SlamMapTfToOdometry.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 import rospy
00003 from geometry_msgs.msg import TwistWithCovariance, Twist, Vector3, Point, Quaternion
00004 from nav_msgs.msg import OccupancyGrid, Odometry
00005 import tf
00006 import numpy
00007 from jsk_robot_startup.odometry_utils import make_homogeneous_matrix 
00008 import threading
00009 
00010 class SlamMapTfToOdometry:
00011     def __init__(self):
00012         rospy.init_node("SlamMapTfToOdometry", anonymous=True)
00013         self.pub = rospy.Publisher("~output", Odometry, queue_size=10)
00014         self.map_frame = rospy.get_param("~map_frame", "map")
00015         # self.base_frame = rospy.get_param("~base_frame", "BODY")
00016         self.rate = rospy.get_param("~rate", 10)
00017         self.pub_only_map_updated = rospy.get_param("~pub_only_map_updated", True)
00018         self.listener = tf.TransformListener()
00019         self.r = rospy.Rate(self.rate) # 10hz
00020         self.is_new_map = False
00021         self.slam_odom = None
00022         self.lock = threading.Lock()
00023         self.map_sub = rospy.Subscriber("~map", OccupancyGrid, self.map_callback, queue_size = 10)
00024         self.base_odom_sub = rospy.Subscriber("~base_odom", Odometry, self.base_odom_callback, queue_size = 10)
00025 
00026     def execute(self):
00027         while not rospy.is_shutdown():
00028             self.r.sleep()
00029 
00030     def map_callback(self, msg):
00031         if self.pub_only_map_updated and self.slam_odom != None:
00032             with self.lock:
00033                 self.pub.publish(self.slam_odom)
00034 
00035     def base_odom_callback(self, msg):
00036         with self.lock:
00037             try:
00038                 self.listener.waitForTransform(self.map_frame, msg.header.frame_id, msg.header.stamp, rospy.Duration(3))
00039                 (trans,rot) = self.listener.lookupTransform(self.map_frame, msg.header.frame_id, msg.header.stamp) # current map->base_odom transform
00040             except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
00041                 return
00042             base_odom_homogeneous_matrix = make_homogeneous_matrix([getattr(msg.pose.pose.position, attr) for attr in ["x", "y", "z"]],
00043                                                                    [getattr(msg.pose.pose.orientation, attr) for attr in ["x", "y", "z", "w"]]) # base_odom -> body
00044             map_to_base_odom_homogeneous_matrix = make_homogeneous_matrix(trans, rot) # map -> base_odom
00045             slam_odom_matrix = map_to_base_odom_homogeneous_matrix.dot(base_odom_homogeneous_matrix) # map -> body
00046 
00047             self.slam_odom = Odometry()
00048             self.slam_odom.pose.pose.position = Point(*list(slam_odom_matrix[:3, 3]))
00049             self.slam_odom.pose.pose.orientation = Quaternion(*list(tf.transformations.quaternion_from_matrix(slam_odom_matrix)))
00050             self.slam_odom.header.stamp = msg.header.stamp
00051             self.slam_odom.header.frame_id = self.map_frame
00052             self.slam_odom.child_frame_id = msg.child_frame_id        
00053 
00054             # calculate covariance
00055             # use covariance of base_odom.pose and only transform it to new coords from tf
00056             # TODO: calc covariance in correct way, but what is that ...?
00057             rotation_matrix = map_to_base_odom_homogeneous_matrix[:3, :3]
00058             original_pose_cov_matrix = numpy.matrix(msg.pose.covariance).reshape(6, 6)
00059             pose_cov_matrix = numpy.zeros((6, 6))
00060             pose_cov_matrix[:3, :3] = (rotation_matrix.T).dot(original_pose_cov_matrix[:3, :3].dot(rotation_matrix))
00061             pose_cov_matrix[3:6, 3:6] = (rotation_matrix.T).dot(original_pose_cov_matrix[3:6, 3:6].dot(rotation_matrix))
00062             self.slam_odom.pose.covariance = numpy.array(pose_cov_matrix).reshape(-1,).tolist()
00063 
00064             # twist is local and transform same as covariance
00065             new_velocity = numpy.dot(rotation_matrix, numpy.array([[msg.twist.twist.linear.x],
00066                                                                    [msg.twist.twist.linear.y],
00067                                                                    [msg.twist.twist.linear.z]]))
00068             new_omega = numpy.dot(rotation_matrix, numpy.array([[msg.twist.twist.angular.x],
00069                                                                 [msg.twist.twist.angular.y],
00070                                                                 [msg.twist.twist.angular.z]]))
00071             original_twist_cov_matrix = numpy.matrix(msg.twist.covariance).reshape(6, 6)
00072             twist_cov_matrix = numpy.zeros((6, 6))
00073             twist_cov_matrix[:3, :3] = (rotation_matrix.T).dot(original_twist_cov_matrix[:3, :3].dot(rotation_matrix))
00074             twist_cov_matrix[3:6, 3:6] = (rotation_matrix.T).dot(original_twist_cov_matrix[3:6, 3:6].dot(rotation_matrix))
00075             self.slam_odom.twist = TwistWithCovariance(Twist(Vector3(*new_velocity[:, 0]), Vector3(*new_omega[:, 0])), twist_cov_matrix.reshape(-1,).tolist())
00076             
00077             if not self.pub_only_map_updated:
00078                 self.pub.publish(self.slam_odom)
00079 
00080 if __name__ == '__main__':
00081     try:
00082         node = SlamMapTfToOdometry()
00083         node.execute()
00084     except rospy.ROSInterruptException: pass


jsk_robot_startup
Author(s):
autogenerated on Sat Jul 1 2017 02:42:18