CameraToBaseOffset.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
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         # execute rate
00018         self.rate = float(rospy.get_param("~rate", 100))
00019         # tf parameters
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) # wait to update odom_init frame
00042         with self.lock:
00043             self.initial_matrix = None
00044             
00045     def source_odom_callback(self, msg):
00046         with self.lock:
00047             # calculate camera transform
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) # base_link transformation in camera coords
00056             
00057             # calculate offseted odometry
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             # make odometry msg. twist is copied from source_odom
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             # publish
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) # camera -> base_link
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         


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