00001
00002
00003 import rospy
00004 import numpy
00005 from nav_msgs.msg import Odometry
00006 from geometry_msgs.msg import Point, Quaternion, Twist, Vector3, TwistWithCovariance
00007 from std_msgs.msg import Float64, Empty
00008 import tf
00009 import time
00010 import threading
00011 import copy
00012 from jsk_robot_startup.odometry_utils import broadcast_transform, make_homogeneous_matrix
00013
00014 class CameraToBaseOffset(object):
00015 def __init__(self):
00016 rospy.init_node("CameraToBaseOffset", anonymous=True)
00017
00018 self.rate = float(rospy.get_param("~rate", 100))
00019
00020 self.publish_tf = rospy.get_param("~publish_tf", True)
00021 if self.publish_tf:
00022 self.invert_tf = rospy.get_param("~invert_tf", True)
00023 self.broadcast = tf.TransformBroadcaster()
00024 self.base_link_frame = rospy.get_param("~base_link_frame", "BODY")
00025 self.camera_frame = rospy.get_param("~camera_frame", "left_camera_optical_frame")
00026 self.odom_frame = rospy.get_param("~odom_frame", "viso_odom")
00027 self.tf_duration = rospy.get_param("~tf_duration", 1)
00028 self.listener = tf.TransformListener(True, rospy.Duration(10))
00029 self.r = rospy.Rate(self.rate)
00030 self.initial_matrix = None
00031 self.lock = threading.Lock()
00032 self.source_odom_sub = rospy.Subscriber("~source_odom", Odometry, self.source_odom_callback)
00033 self.init_signal_sub = rospy.Subscriber("~init_signal", Empty, self.init_signal_callback)
00034 self.pub = rospy.Publisher("~output", Odometry, queue_size = 1)
00035
00036 def execute(self):
00037 while not rospy.is_shutdown():
00038 self.r.sleep()
00039
00040 def init_signal_callback(self, msg):
00041 time.sleep(1)
00042 with self.lock:
00043 self.initial_matrix = None
00044
00045 def source_odom_callback(self, msg):
00046 with self.lock:
00047
00048 current_camera_to_base = self.calculate_camera_to_base_transform(msg.header.stamp)
00049 if current_camera_to_base == None:
00050 return
00051
00052 if self.initial_matrix == None:
00053 self.initial_matrix = numpy.linalg.inv(current_camera_to_base)
00054
00055 camera_relative_base_transformation = numpy.dot(self.initial_matrix, current_camera_to_base)
00056
00057
00058 source_odom_matrix = make_homogeneous_matrix([msg.pose.pose.position.x, msg.pose.pose.position.y, msg.pose.pose.position.z],
00059 [msg.pose.pose.orientation.x, msg.pose.pose.orientation.y,
00060 msg.pose.pose.orientation.z, msg.pose.pose.orientation.w])
00061 new_odom_matrix = camera_relative_base_transformation.dot(source_odom_matrix)
00062
00063
00064 new_odom = copy.deepcopy(msg)
00065 new_odom.header.frame_id = self.odom_frame
00066 new_odom.child_frame_id = self.base_link_frame
00067 new_odom.pose.pose.position = Point(*list(new_odom_matrix[:3, 3]))
00068 new_odom.pose.pose.orientation = Quaternion(*list(tf.transformations.quaternion_from_matrix(new_odom_matrix)))
00069 new_pose_cov_matrix = numpy.matrix(new_odom.pose.covariance).reshape(6, 6)
00070 rotation_matrix = camera_relative_base_transformation[:3, :3]
00071 new_pose_cov_matrix[:3, :3] = (rotation_matrix.T).dot(new_pose_cov_matrix[:3, :3].dot(rotation_matrix))
00072 new_pose_cov_matrix[3:6, 3:6] = (rotation_matrix.T).dot(new_pose_cov_matrix[3:6, 3:6].dot(rotation_matrix))
00073 new_odom.pose.covariance = numpy.array(new_pose_cov_matrix).reshape(-1,).tolist()
00074
00075
00076 self.pub.publish(new_odom)
00077 if self.publish_tf:
00078 broadcast_transform(self.broadcast, new_odom, self.invert_tf)
00079
00080 def calculate_camera_to_base_transform(self, stamp):
00081 try:
00082 (trans,rot) = self.listener.lookupTransform(self.camera_frame, self.base_link_frame, stamp)
00083 except:
00084 try:
00085 rospy.logwarn("[%s] failed to solve camera_to_base tf in %f. Use rospy.Time(0): %s to %s", rospy.get_name(), stamp.to_sec(), self.camera_frame, self.base_link_frame)
00086 (trans,rot) = self.listener.lookupTransform(self.camera_frame, self.base_link_frame, rospy.Time(0))
00087 except:
00088 rospy.logwarn("[%s] failed to solve camera_to_base tf: %s to %s", rospy.get_name(), self.camera_frame, self.base_link_frame)
00089 return None
00090 camera_to_base_link = make_homogeneous_matrix(trans, rot)
00091 return camera_to_base_link
00092
00093 if __name__ == '__main__':
00094 try:
00095 node = CameraToBaseOffset()
00096 node.execute()
00097 except rospy.ROSInterruptException: pass
00098