00001
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
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)
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)
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"]])
00044 map_to_base_odom_homogeneous_matrix = make_homogeneous_matrix(trans, rot)
00045 slam_odom_matrix = map_to_base_odom_homogeneous_matrix.dot(base_odom_homogeneous_matrix)
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
00055
00056
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
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