00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 import numpy as np
00034 import copy
00035
00036 import roslib; roslib.load_manifest('hrl_geom')
00037 import rospy
00038 from std_msgs.msg import Header
00039 from geometry_msgs.msg import PoseStamped, Pose, Point, Quaternion, PointStamped
00040 from geometry_msgs.msg import Transform, TransformStamped, Vector3
00041 from geometry_msgs.msg import Twist, TwistStamped
00042 import hrl_geom.transformations as trans
00043
00044 def rot_mat_to_axis_angle(R):
00045 ang = np.arccos((np.trace(R) - 1.0)/2.0)
00046 axis = np.array([R[2,1]-R[1,2], R[0,2]-R[2,0], R[1,0]-R[0,1]])
00047 axis = axis / np.linalg.norm(axis)
00048 return (axis, ang)
00049
00050 def axis_angle_to_rot_mat(axis, ang):
00051 axis = axis / np.linalg.norm(axis)
00052 K = np.mat([[0.0, -axis[2], axis[1]],
00053 [axis[2], 0.0, -axis[0]],
00054 [-axis[1], axis[0], 0.0]])
00055 I = np.mat(np.eye(3))
00056 return I + np.sin(ang)*K + (1.0 - np.cos(ang))*K*K
00057
00058
00059
00060
00061 class PoseConv(object):
00062 POSE_TYPES = [
00063 'pose_msg',
00064 'pose_stamped_msg',
00065 'point_msg',
00066 'point_stamped_msg',
00067 'tf_msg',
00068 'tf_stamped_msg',
00069 'twist_msg',
00070 'twist_stamped_msg',
00071 'homo_mat',
00072 'pos_rot',
00073 'pos_quat',
00074 'pos_euler',
00075 'pos_axis_angle']
00076
00077
00078
00079
00080 @staticmethod
00081 def get_type(*args):
00082 try:
00083 if type(args[0]) is str:
00084 return PoseConv.get_type(*args[1:])
00085 if len(args) == 1:
00086 if type(args[0]) is Pose:
00087 return 'pose_msg'
00088 elif type(args[0]) is PoseStamped:
00089 return 'pose_stamped_msg'
00090 elif type(args[0]) is Transform:
00091 return 'tf_msg'
00092 elif type(args[0]) is TransformStamped:
00093 return 'tf_stamped_msg'
00094 elif type(args[0]) is Twist:
00095 return 'twist_msg'
00096 elif type(args[0]) is TwistStamped:
00097 return 'twist_stamped_msg'
00098 elif type(args[0]) is Point:
00099 return 'point_msg'
00100 elif type(args[0]) is PointStamped:
00101 return 'point_stamped_msg'
00102 elif isinstance(args[0], (np.matrix, np.ndarray)) and np.shape(args[0]) == (4, 4):
00103 return 'homo_mat'
00104 elif isinstance(args[0], (tuple, list)) and len(args[0]) == 2:
00105 pos_arg = np.mat(args[0][0])
00106 if pos_arg.shape != (1, 3) and pos_arg.shape != (3, 1):
00107 return None
00108 if isinstance(args[0][1], (tuple, list)) and len(args[0][1]) == 2:
00109 if len(args[0][1][0]) == 3 and np.array(args[0][1][1]).size == 1:
00110 return 'pos_axis_angle'
00111 else:
00112 return None
00113 rot_arg = np.mat(args[0][1])
00114 if rot_arg.shape == (3, 3):
00115 return 'pos_rot'
00116 if 1 not in rot_arg.shape:
00117 return None
00118 rot_arg = rot_arg.tolist()[0]
00119 if len(rot_arg) == 3:
00120 return 'pos_euler'
00121 elif len(rot_arg) == 4:
00122 return 'pos_quat'
00123 else:
00124 return None
00125 elif len(args) == 2:
00126 return PoseConv.get_type(((args[0], args[1]),))
00127 except:
00128 pass
00129 return None
00130
00131
00132
00133 @staticmethod
00134 def to_pose_msg(*args):
00135 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00136 if homo_mat is None:
00137 rospy.logwarn("[pose_converter] Unknown pose type.")
00138 return None
00139 else:
00140 return Pose(Point(*homo_mat[:3,3].T.A[0]), Quaternion(*quat_rot))
00141
00142
00143
00144 @staticmethod
00145 def to_pose_stamped_msg(*args):
00146 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00147 if homo_mat is None:
00148 rospy.logwarn("[pose_converter] Unknown pose type.")
00149 return None
00150 ps = PoseStamped()
00151 if header is None:
00152 ps.header.stamp = rospy.Time.now()
00153 else:
00154 ps.header.seq = header[0]
00155 ps.header.stamp = header[1]
00156 ps.header.frame_id = header[2]
00157 ps.pose = Pose(Point(*homo_mat[:3,3].T.A[0]), Quaternion(*quat_rot))
00158 return ps
00159
00160
00161
00162 @staticmethod
00163 def to_point_msg(*args):
00164 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00165 if homo_mat is None:
00166 rospy.logwarn("[pose_converter] Unknown pose type.")
00167 return None
00168 return Point(*homo_mat[:3,3].T.A[0])
00169
00170
00171
00172 @staticmethod
00173 def to_point_stamped_msg(*args):
00174 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00175 if homo_mat is None:
00176 rospy.logwarn("[pose_converter] Unknown pose type.")
00177 return None
00178 ps = PointStamped()
00179 if header is None:
00180 ps.header.stamp = rospy.Time.now()
00181 else:
00182 ps.header.seq = header[0]
00183 ps.header.stamp = header[1]
00184 ps.header.frame_id = header[2]
00185 ps.point = Point(*homo_mat[:3,3].T.A[0])
00186 return ps
00187
00188
00189
00190 @staticmethod
00191 def to_tf_msg(*args):
00192 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00193 if homo_mat is None:
00194 rospy.logwarn("[pose_converter] Unknown pose type.")
00195 return None
00196 else:
00197 return Transform(Vector3(*homo_mat[:3,3].T.A[0]), Quaternion(*quat_rot))
00198
00199
00200
00201 @staticmethod
00202 def to_tf_stamped_msg(*args):
00203 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00204 if homo_mat is None:
00205 rospy.logwarn("[pose_converter] Unknown pose type.")
00206 return None
00207 tf_stamped = TransformStamped()
00208 if header is None:
00209 tf_stamped.header.stamp = rospy.Time.now()
00210 else:
00211 tf_stamped.header.seq = header[0]
00212 tf_stamped.header.stamp = header[1]
00213 tf_stamped.header.frame_id = header[2]
00214 tf_stamped.transform = Transform(Vector3(*homo_mat[:3,3].T.A[0]), Quaternion(*quat_rot))
00215 return tf_stamped
00216
00217
00218
00219 @staticmethod
00220 def to_twist_msg(*args):
00221 _, homo_mat, _, euler_rot = PoseConv._make_generic(args)
00222 if homo_mat is None:
00223 rospy.logwarn("[pose_converter] Unknown pose type.")
00224 return None
00225 else:
00226 return Twist(Vector3(*homo_mat[:3,3].T.A[0]), Vector3(*euler_rot))
00227
00228
00229
00230 @staticmethod
00231 def to_twist_stamped_msg(*args):
00232 header, homo_mat, _, euler_rot = PoseConv._make_generic(args)
00233 if homo_mat is None:
00234 rospy.logwarn("[pose_converter] Unknown pose type.")
00235 return None
00236 twist_stamped = TwistStamped()
00237 header_msg = Header()
00238 if header is None:
00239 header_msg.stamp = rospy.Time.now()
00240 else:
00241 header_msg.seq = header[0]
00242 header_msg.stamp = header[1]
00243 header_msg.frame_id = header[2]
00244 return TwistStamped(header_msg, Twist(Vector3(*homo_mat[:3,3].T.A[0]), Vector3(*euler_rot)))
00245
00246
00247
00248 @staticmethod
00249 def to_homo_mat(*args):
00250 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00251 if homo_mat is None:
00252 rospy.logwarn("[pose_converter] Unknown pose type.")
00253 return None
00254 else:
00255 return homo_mat.copy()
00256
00257
00258
00259 @staticmethod
00260 def to_pos_rot(*args):
00261 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00262 if homo_mat is None:
00263 rospy.logwarn("[pose_converter] Unknown pose type.")
00264 return None, None
00265 else:
00266 return homo_mat[:3,3].copy(), homo_mat[:3,:3].copy()
00267
00268
00269
00270 @staticmethod
00271 def to_pos_quat(*args):
00272 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00273 if homo_mat is None:
00274 rospy.logwarn("[pose_converter] Unknown pose type.")
00275 return None, None
00276 else:
00277 return copy.copy(list(homo_mat[:3,3].T.A[0])), copy.copy(quat_rot)
00278
00279
00280
00281 @staticmethod
00282 def to_pos_euler(*args):
00283 header, homo_mat, quat_rot, euler_rot = PoseConv._make_generic(args)
00284 if homo_mat is None:
00285 rospy.logwarn("[pose_converter] Unknown pose type.")
00286 return None, None
00287 else:
00288 return copy.copy(list(homo_mat[:3,3].T.A[0])), copy.copy(euler_rot)
00289
00290
00291
00292 @staticmethod
00293 def to_pos_axis_angle(*args):
00294 header, homo_mat, quat_rot, _ = PoseConv._make_generic(args)
00295 if homo_mat is None:
00296 rospy.logwarn("[pose_converter] Unknown pose type.")
00297 return None, None
00298 else:
00299 return copy.copy(list(homo_mat[:3,3].T.A[0])), rot_mat_to_axis_angle(homo_mat[:3,:3])
00300
00301 @staticmethod
00302 def _make_generic(args):
00303 try:
00304 if type(args[0]) == str:
00305 frame_id = args[0]
00306 header, homo_mat, rot_quat, rot_euler = PoseConv._make_generic(args[1:])
00307 if homo_mat is None:
00308 return None, None, None, None
00309 if header is None:
00310 header = [0, rospy.Time.now(), '']
00311 header[2] = frame_id
00312 return header, homo_mat, rot_quat, rot_euler
00313
00314 if len(args) == 2:
00315 return PoseConv._make_generic(((args[0], args[1]),))
00316 elif len(args) == 1:
00317 pose_type = PoseConv.get_type(*args)
00318 if pose_type is None:
00319 return None, None, None, None
00320 if pose_type == 'pose_msg':
00321 homo_mat, rot_quat, rot_euler = PoseConv._extract_pose_msg(args[0])
00322 return None, homo_mat, rot_quat, rot_euler
00323 elif pose_type == 'pose_stamped_msg':
00324 homo_mat, rot_quat, rot_euler = PoseConv._extract_pose_msg(args[0].pose)
00325 seq = args[0].header.seq
00326 stamp = args[0].header.stamp
00327 frame_id = args[0].header.frame_id
00328 return [seq, stamp, frame_id], homo_mat, rot_quat, rot_euler
00329 elif pose_type == 'tf_msg':
00330 homo_mat, rot_quat, rot_euler = PoseConv._extract_tf_msg(args[0])
00331 return None, homo_mat, rot_quat, rot_euler
00332 elif pose_type == 'tf_stamped_msg':
00333 homo_mat, rot_quat, rot_euler = PoseConv._extract_tf_msg(args[0].transform)
00334 seq = args[0].header.seq
00335 stamp = args[0].header.stamp
00336 frame_id = args[0].header.frame_id
00337 return [seq, stamp, frame_id], homo_mat, rot_quat, rot_euler
00338 elif pose_type == 'point_msg':
00339 homo_mat, rot_quat, rot_euler = PoseConv._extract_point_msg(args[0])
00340 return None, homo_mat, rot_quat, rot_euler
00341 elif pose_type == 'point_stamped_msg':
00342 homo_mat, rot_quat, rot_euler = PoseConv._extract_point_msg(args[0].point)
00343 seq = args[0].header.seq
00344 stamp = args[0].header.stamp
00345 frame_id = args[0].header.frame_id
00346 return [seq, stamp, frame_id], homo_mat, rot_quat, rot_euler
00347 elif pose_type == 'twist_msg':
00348 homo_mat, rot_quat, rot_euler = PoseConv._extract_twist_msg(args[0])
00349 return None, homo_mat, rot_quat, rot_euler
00350 elif pose_type == 'twist_stamped_msg':
00351 homo_mat, rot_quat, rot_euler = PoseConv._extract_twist_msg(args[0].twist)
00352 seq = args[0].header.seq
00353 stamp = args[0].header.stamp
00354 frame_id = args[0].header.frame_id
00355 return [seq, stamp, frame_id], homo_mat, rot_quat, rot_euler
00356 elif pose_type == 'homo_mat':
00357 return (None, np.mat(args[0]), trans.quaternion_from_matrix(args[0]).tolist(),
00358 trans.euler_from_matrix(args[0]))
00359 elif pose_type in ['pos_rot', 'pos_euler', 'pos_quat', 'pos_axis_angle']:
00360 pos_arg = np.mat(args[0][0])
00361 if pos_arg.shape == (1, 3):
00362
00363 pos = pos_arg.T
00364 elif pos_arg.shape == (3, 1):
00365 pos = pos_arg
00366
00367 if pose_type == 'pos_axis_angle':
00368 homo_mat = np.mat(np.eye(4))
00369 homo_mat[:3,:3] = axis_angle_to_rot_mat(args[0][1][0], args[0][1][1])
00370 quat = trans.quaternion_from_matrix(homo_mat)
00371 rot_euler = trans.euler_from_matrix(homo_mat)
00372 elif pose_type == 'pos_rot':
00373
00374 homo_mat = np.mat(np.eye(4))
00375 homo_mat[:3,:3] = np.mat(args[0][1])
00376 quat = trans.quaternion_from_matrix(homo_mat)
00377 rot_euler = trans.euler_from_matrix(homo_mat)
00378 else:
00379 rot_arg = np.mat(args[0][1])
00380 if rot_arg.shape[1] == 1:
00381 rot_arg = rot_arg.T
00382 rot_list = rot_arg.tolist()[0]
00383 if pose_type == 'pos_euler':
00384
00385 homo_mat = np.mat(trans.euler_matrix(*rot_list))
00386 quat = trans.quaternion_from_euler(*rot_list)
00387 rot_euler = rot_list
00388 elif pose_type == 'pos_quat':
00389
00390 homo_mat = np.mat(trans.quaternion_matrix(rot_list))
00391 quat = rot_list
00392 rot_euler = trans.euler_from_quaternion(quat)
00393
00394 homo_mat[:3, 3] = pos
00395 return None, homo_mat, np.array(quat), rot_euler
00396 except:
00397 pass
00398
00399 return None, None, None, None
00400
00401 @staticmethod
00402 def _extract_pose_msg(pose):
00403 px = pose.position.x; py = pose.position.y; pz = pose.position.z
00404 ox = pose.orientation.x; oy = pose.orientation.y
00405 oz = pose.orientation.z; ow = pose.orientation.w
00406 quat = [ox, oy, oz, ow]
00407 rot_euler = trans.euler_from_quaternion(quat)
00408 homo_mat = np.mat(trans.quaternion_matrix(quat))
00409 homo_mat[:3,3] = np.mat([[px, py, pz]]).T
00410 return homo_mat, quat, rot_euler
00411
00412 @staticmethod
00413 def _extract_tf_msg(tf_msg):
00414 px = tf_msg.translation.x; py = tf_msg.translation.y; pz = tf_msg.translation.z
00415 ox = tf_msg.rotation.x; oy = tf_msg.rotation.y
00416 oz = tf_msg.rotation.z; ow = tf_msg.rotation.w
00417 quat = [ox, oy, oz, ow]
00418 rot_euler = trans.euler_from_quaternion(quat)
00419 homo_mat = np.mat(trans.quaternion_matrix(quat))
00420 homo_mat[:3,3] = np.mat([[px, py, pz]]).T
00421 return homo_mat, quat, rot_euler
00422
00423 @staticmethod
00424 def _extract_twist_msg(twist_msg):
00425 pos = [twist_msg.linear.x, twist_msg.linear.y, twist_msg.linear.z]
00426 rot_euler = [twist_msg.angular.x, twist_msg.angular.y, twist_msg.angular.z]
00427 quat = trans.quaternion_from_euler(*rot_euler, axes='sxyz')
00428 homo_mat = np.mat(trans.euler_matrix(*rot_euler))
00429 homo_mat[:3,3] = np.mat([pos]).T
00430 return homo_mat, quat, rot_euler
00431
00432 @staticmethod
00433 def _extract_point_msg(point_msg):
00434 pos = [point_msg.x, point_msg.y, point_msg.z]
00435 homo_mat = np.mat(np.eye(4))
00436 homo_mat[:3,3] = np.mat([pos]).T
00437 return homo_mat, [0., 0., 0., 1.], [0., 0., 0.]
00438
00439
00440 def main():
00441 rospy.init_node("pose_converter")
00442 pose = ([0.1, -0.5, 1.0], [0.04842544, 0.01236504, 0.24709477, 0.96770153])
00443 errors = 0
00444 for type_from in PoseConv.POSE_TYPES:
00445 for type_to in PoseConv.POSE_TYPES:
00446 print
00447 print "Types: FROM %s, TO %s" % (type_from, type_to)
00448 exec("from_pose = PoseConv.to_%s(pose)" % type_from)
00449 if from_pose is None or (type(from_pose) is tuple and from_pose[0] is None):
00450 print "from_pose ERROR\n" * 5
00451 errors += 1
00452 continue
00453 exec("to_pose = PoseConv.to_%s('base_link', from_pose)" % type_to)
00454 if to_pose is None or (type(to_pose) is tuple and to_pose[0] is None):
00455 print "to_pose ERROR\n" * 5
00456 errors += 1
00457 continue
00458 exec("back_pose = PoseConv.to_%s(to_pose)" % type_from)
00459 if back_pose is None or (type(back_pose) is tuple and back_pose[0] is None):
00460 print "back_pose ERROR\n" * 5
00461 errors += 1
00462 continue
00463 exec("orig_pose = PoseConv.to_pos_quat(back_pose)")
00464 if orig_pose is None or (type(orig_pose) is tuple and orig_pose[0] is None):
00465 print "orig_pose ERROR\n" * 5
00466 print pose
00467 print orig_pose
00468 errors += 1
00469 continue
00470 if not np.allclose(orig_pose[0], pose[0]):
00471 print "orig_pose pos ERROR\n" * 5
00472 print pose
00473 print orig_pose
00474 errors += 1
00475 continue
00476 if 'point' not in type_to + type_from and not np.allclose(orig_pose[1], pose[1]):
00477 print "orig_pose rot ERROR\n" * 5
00478 print pose
00479 print orig_pose
00480 errors += 1
00481 continue
00482 print "-" * 50
00483 if type_from != PoseConv.get_type(from_pose) or type_to != PoseConv.get_type(to_pose):
00484 print "get_type ERROR\n" * 5
00485 errors += 1
00486 continue
00487 print from_pose
00488 print "-" * 20
00489 print to_pose
00490 print "\n\nErrors: %d" % errors
00491
00492 if __name__ == "__main__":
00493 main()