00001 
00002 
00003 import rospy
00004 import tf
00005 import numpy
00006 import scipy.stats
00007 import math
00008 from geometry_msgs.msg import PoseWithCovariance, TwistWithCovariance, Twist, Pose, Point, Quaternion, Vector3
00009 
00010 
00011 def transform_local_twist_to_global(pose, local_twist):
00012     trans = [pose.position.x, pose.position.y, pose.position.z]
00013     rot = [pose.orientation.x, pose.orientation.y,
00014            pose.orientation.z, pose.orientation.w]
00015     rotation_matrix = tf.transformations.quaternion_matrix(rot)[:3, :3]
00016     global_velocity = numpy.dot(rotation_matrix, numpy.array([[local_twist.linear.x],
00017                                                               [local_twist.linear.y],
00018                                                               [local_twist.linear.z]]))
00019     global_omega = numpy.dot(rotation_matrix, numpy.array([[local_twist.angular.x],
00020                                                            [local_twist.angular.y],
00021                                                            [local_twist.angular.z]]))
00022     return Twist(Vector3(*global_velocity[:, 0]), Vector3(*global_omega[:, 0]))
00023 
00024 def transform_local_twist_covariance_to_global(pose, local_twist_with_covariance):
00025     trans = [pose.position.x, pose.position.y, pose.position.z]
00026     rot = [pose.orientation.x, pose.orientation.y,
00027            pose.orientation.z, pose.orientation.w]
00028     rotation_matrix = tf.transformations.quaternion_matrix(rot)[:3, :3]
00029     twist_cov_matrix = numpy.matrix(local_twist_with_covariance).reshape(6, 6)
00030     global_twist_cov_matrix = numpy.zeros((6, 6))
00031     global_twist_cov_matrix[:3, :3] = (rotation_matrix.T).dot(twist_cov_matrix[:3, :3].dot(rotation_matrix))
00032     global_twist_cov_matrix[3:6, 3:6] = (rotation_matrix.T).dot(twist_cov_matrix[3:6, 3:6].dot(rotation_matrix))
00033     return global_twist_cov_matrix.reshape(-1,).tolist()
00034 
00035 
00036 def update_pose(pose, global_twist, dt):
00037     ret_pose = Pose()
00038     
00039     ret_pose.position.x = pose.position.x + global_twist.linear.x * dt
00040     ret_pose.position.y = pose.position.y + global_twist.linear.y * dt
00041     ret_pose.position.z = pose.position.z + global_twist.linear.z * dt
00042     ret_pose.orientation = update_quaternion(pose.orientation, global_twist.angular, dt)
00043     return ret_pose
00044 
00045 def update_quaternion(orientation, angular, dt): 
00046     
00047     quat_vec = numpy.array([[orientation.x],
00048                             [orientation.y],
00049                             [orientation.z],
00050                             [orientation.w]])
00051     skew_omega = numpy.matrix([[0, -angular.z, angular.y, angular.x],
00052                                [angular.z, 0, -angular.x, angular.y],
00053                                [-angular.y, angular.x, 0, angular.z],
00054                                [-angular.x, -angular.y, -angular.z, 0]])
00055     new_quat_vec = quat_vec + 0.5 * numpy.dot(skew_omega, quat_vec) * dt
00056     norm = numpy.linalg.norm(new_quat_vec)
00057     if norm == 0:
00058         rospy.logwarn("norm of quaternion is zero")
00059     else:
00060         new_quat_vec = new_quat_vec / norm 
00061     return Quaternion(*numpy.array(new_quat_vec).reshape(-1,).tolist())
00062 
00063 
00064 def update_twist_covariance(twist, v_sigma, min_sigma = 1e-3): 
00065     twist_list = [twist.twist.linear.x, twist.twist.linear.y, twist.twist.linear.z, twist.twist.angular.x, twist.twist.angular.y, twist.twist.angular.z]
00066     if all([abs(x) < 1e-6 for x in twist_list]):
00067         current_sigma = [min_sigma] * 6 
00068     else:
00069         current_sigma = v_sigma
00070     return numpy.diag([max(x ** 2, min_sigma ** 2) for x in current_sigma]).reshape(-1,).tolist() 
00071 
00072 def update_pose_covariance(pose_cov, global_twist_cov, dt):
00073     ret_pose_cov = []
00074     
00075     prev_pose_cov_matrix = numpy.matrix(pose_cov).reshape(6, 6)
00076     global_twist_cov_matrix = numpy.matrix(global_twist_cov).reshape(6, 6)
00077     
00078     
00079     jacobi_pose = numpy.diag([1.0] * 6)
00080     jacobi_twist = numpy.diag([dt] * 6)
00081     
00082     pose_cov_matrix = jacobi_pose.dot(prev_pose_cov_matrix.dot(jacobi_pose.T)) + jacobi_twist.dot(global_twist_cov_matrix.dot(jacobi_twist.T))
00083     
00084     ret_pose_cov = numpy.array(pose_cov_matrix).reshape(-1,).tolist()
00085     return ret_pose_cov
00086 
00087 
00088 def broadcast_transform(broadcast, odom, invert_tf):
00089     if not odom or not broadcast:
00090         return
00091     position = [odom.pose.pose.position.x, odom.pose.pose.position.y, odom.pose.pose.position.z]
00092     orientation = [odom.pose.pose.orientation.x, odom.pose.pose.orientation.y, odom.pose.pose.orientation.z, odom.pose.pose.orientation.w]
00093     if invert_tf:
00094         homogeneous_matrix = make_homogeneous_matrix(position, orientation)
00095         homogeneous_matrix_inv = numpy.linalg.inv(homogeneous_matrix)
00096         position = list(homogeneous_matrix_inv[:3, 3])
00097         orientation = list(tf.transformations.quaternion_from_matrix(homogeneous_matrix_inv))
00098         parent_frame = odom.child_frame_id
00099         target_frame = odom.header.frame_id
00100     else:
00101         parent_frame = odom.header.frame_id
00102         target_frame = odom.child_frame_id
00103     broadcast.sendTransform(position, orientation, odom.header.stamp, target_frame, parent_frame)
00104 
00105 
00106 def make_homogeneous_matrix(trans, rot):
00107     homogeneous_matrix = tf.transformations.quaternion_matrix(rot)
00108     homogeneous_matrix[:3, 3] = numpy.array(trans).reshape(1, 3)
00109     return homogeneous_matrix
00110     
00111 
00112 
00113 
00114 def norm_pdf_multivariate(x, mean, cov_inv):
00115     size = len(x)
00116     if size == len(mean) and (size, size) == cov_inv.shape:
00117         inv_det = numpy.linalg.det(cov_inv)
00118         if not inv_det > 0:
00119             rospy.logwarn("Determinant of inverse cov matrix {0} is equal or smaller than zero".format(inv_det))
00120             return 0.0
00121         norm_const = math.pow((2 * numpy.pi), float(size) / 2) * math.pow(1 / inv_det, 1.0 / 2) 
00122         if not norm_const > 0 :
00123             rospy.logwarn("Norm const {0} is equal or smaller than zero".format(norm_const))
00124             return 0.0
00125         x_mean = numpy.matrix(x - mean)
00126         exponent = -0.5 * (x_mean * cov_inv * x_mean.T)
00127         if exponent > 0:
00128             rospy.logwarn("Exponent {0} is larger than zero".format(exponent))
00129             exponent = 0
00130         result = math.pow(math.e, exponent)
00131         return result / norm_const
00132     else:
00133         rospy.logwarn("The dimensions of the input don't match")
00134         return 0.0
00135 
00136 
00137 
00138 
00139 def transform_quaternion_to_euler(quat, prev_euler = None):
00140     
00141     sin_half_pitch = quat[3] * quat[1] - quat[2] * quat[0]
00142     if abs(sin_half_pitch) > 0.499:
00143         
00144         ret_euler = list(tf.transformations.euler_from_quaternion(quat))
00145     else:
00146         
00147         zero_thre = numpy.finfo(float).eps * 4.0 
00148         roll_numerator = 2 * (quat[3] * quat[0] + quat[1] * quat[2])
00149         if abs(roll_numerator) < zero_thre:
00150             roll_numerator = numpy.sign(roll_numerator) * 0.0
00151         yaw_numerator = 2 * (quat[3] * quat[2] + quat[0] * quat[1])
00152         if abs(yaw_numerator) < zero_thre:
00153             yaw_numerator = numpy.sign(yaw_numerator) * 0.0
00154         ret_euler = [numpy.arctan2(roll_numerator, 1 - 2 * (quat[0] ** 2 + quat[1] ** 2)),
00155                      numpy.arcsin(2 * sin_half_pitch),
00156                      numpy.arctan2(yaw_numerator, 1 - 2 * (quat[1] ** 2 + quat[2] ** 2))]
00157     
00158     
00159     if prev_euler != None:
00160         
00161         for i in range(3):
00162             while abs(prev_euler[i] - ret_euler[i]) > numpy.pi:
00163                 ret_euler[i] += numpy.sign(prev_euler[i] - ret_euler[i]) * 2 * numpy.pi
00164     return ret_euler