00001 import unittest
00002 import math
00003
00004 import rospy
00005 from geometry_msgs.msg import Twist,Vector3
00006 from nav_msgs.msg import Odometry
00007
00008 class E:
00009 def __init__(self,x,y,z):
00010 self.x = x
00011 self.y = y
00012 self.z = z
00013 def shortest_euler_distance(self, e_from, e_to):
00014
00015
00016
00017
00018 phi = e_from.x / 2.0
00019 the = e_from.y / 2.0
00020 psi = e_from.z / 2.0
00021 w1 = math.cos(phi) * math.cos(the) * math.cos(psi) + math.sin(phi) * math.sin(the) * math.sin(psi)
00022 x1 = math.sin(phi) * math.cos(the) * math.cos(psi) - math.cos(phi) * math.sin(the) * math.sin(psi)
00023 y1 = math.cos(phi) * math.sin(the) * math.cos(psi) + math.sin(phi) * math.cos(the) * math.sin(psi)
00024 z1 = math.cos(phi) * math.cos(the) * math.sin(psi) - math.sin(phi) * math.sin(the) * math.cos(psi)
00025
00026
00027 phi = e_to.x / 2.0
00028 the = e_to.y / 2.0
00029 psi = e_to.z / 2.0
00030 w2 = math.cos(phi) * math.cos(the) * math.cos(psi) + math.sin(phi) * math.sin(the) * math.sin(psi)
00031 x2 = -(math.sin(phi) * math.cos(the) * math.cos(psi) - math.cos(phi) * math.sin(the) * math.sin(psi))
00032 y2 = -(math.cos(phi) * math.sin(the) * math.cos(psi) + math.sin(phi) * math.cos(the) * math.sin(psi))
00033 z2 = -(math.cos(phi) * math.cos(the) * math.sin(psi) - math.sin(phi) * math.sin(the) * math.cos(psi))
00034
00035
00036 w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
00037 x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
00038 y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
00039 z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
00040
00041
00042 squ = w * w
00043 sqx = x * x
00044 sqy = y * y
00045 sqz = z * z
00046
00047
00048 self.x = math.atan2(2.0 * (y*z + w*x), squ - sqx - sqy + sqz)
00049
00050
00051 sarg = -2.0 * (x*z - w * y)
00052 if sarg <= -1.0:
00053 self.y = -0.5*math.pi
00054 else:
00055 if sarg >= 1.0:
00056 self.y = 0.5*math.pi
00057 else:
00058 self.y = math.asin(sarg)
00059
00060
00061 self.z = math.atan2(2.0 * (x*y + w*z), squ + sqx - sqy - sqz)
00062
00063
00064 class Q:
00065 def __init__(self,x,y,z,u):
00066 self.x = x
00067 self.y = y
00068 self.z = z
00069 self.u = u
00070 def normalize(self):
00071 s = math.sqrt(self.u * self.u + self.x * self.x + self.y * self.y + self.z * self.z)
00072 self.u /= s
00073 self.x /= s
00074 self.y /= s
00075 self.z /= s
00076 def getEuler(self):
00077 self.normalize()
00078 squ = self.u
00079 sqx = self.x
00080 sqy = self.y
00081 sqz = self.z
00082
00083 vec = E(0,0,0)
00084
00085 vec.x = math.atan2(2 * (self.y*self.z + self.u*self.x), squ - sqx - sqy + sqz);
00086
00087 vec.y = math.asin(-2 * (self.x*self.z - self.u*self.y));
00088
00089 vec.z = math.atan2(2 * (self.x*self.y + self.u*self.z), squ + sqx - sqy - sqz);
00090 return vec
00091
00092 class BaseTest(unittest.TestCase):
00093 def __init__(self, *args):
00094 super(BaseTest, self).__init__(*args)
00095 self.success = False
00096
00097 self.odom_xi = 0;
00098 self.odom_yi = 0;
00099 self.odom_ti = 0;
00100 self.odom_ei = E(0,0,0)
00101 self.odom_initialized = False;
00102
00103 self.odom_x = 0;
00104 self.odom_y = 0;
00105 self.odom_t = 0;
00106 self.odom_e = E(0,0,0)
00107
00108 self.p3d_xi = 0;
00109 self.p3d_yi = 0;
00110 self.p3d_ti = 0;
00111 self.p3d_ei = E(0,0,0)
00112 self.p3d_initialized = False;
00113
00114 self.p3d_x = 0;
00115 self.p3d_y = 0;
00116 self.p3d_t = 0;
00117 self.p3d_e = E(0,0,0)
00118
00119 self.pub = None
00120
00121 def normalize_angle_positive(self, angle):
00122 return math.fmod(math.fmod(angle, 2*math.pi) + 2*math.pi, 2*math.pi)
00123
00124 def normalize_angle(self, angle):
00125 anorm = self.normalize_angle_positive(angle)
00126 if anorm > math.pi:
00127 anorm -= 2*math.pi
00128 return anorm
00129
00130 def shortest_angular_distance(self, angle_from, angle_to):
00131 angle_diff = self.normalize_angle_positive(angle_to) - self.normalize_angle_positive(angle_from)
00132 if angle_diff > math.pi:
00133 angle_diff = -(2*math.pi - angle_diff)
00134 return self.normalize_angle(angle_diff)
00135
00136 def printBaseOdom(self, odom):
00137 orientation = odom.pose.pose.orientation
00138 q = Q(orientation.x, orientation.y, orientation.z, orientation.w)
00139 q.normalize()
00140 print "odom received"
00141 print "odom pos " + "x: " + str(odom.pose.pose.position.x)
00142 print "odom pos " + "y: " + str(odom.pose.pose.position.y)
00143 print "odom pos " + "t: " + str(q.getEuler().z)
00144 print "odom vel " + "x: " + str(odom.twist.twist.linear.x)
00145 print "odom vel " + "y: " + str(odom.twist.twist.linear.y)
00146 print "odom vel " + "t: " + str(odom.twist.twist.angular.z)
00147
00148 def printBaseP3D(self, p3d):
00149 print "base pose ground truth received"
00150 print "P3D pose translan: " + "x: " + str(p3d.pose.pose.position.x)
00151 print " " + "y: " + str(p3d.pose.pose.position.y)
00152 print " " + "z: " + str(p3d.pose.pose.position.z)
00153 print "P3D pose rotation: " + "x: " + str(p3d.pose.pose.orientation.x)
00154 print " " + "y: " + str(p3d.pose.pose.orientation.y)
00155 print " " + "z: " + str(p3d.pose.pose.orientation.z)
00156 print " " + "w: " + str(p3d.pose.pose.orientation.w)
00157 print "P3D rate translan: " + "x: " + str(p3d.twist.twist.linear.x)
00158 print " " + "y: " + str(p3d.twist.twist.linear.y)
00159 print " " + "z: " + str(p3d.twist.twist.linear.z)
00160 print "P3D rate rotation: " + "x: " + str(p3d.twist.twist.angular.vx)
00161 print " " + "y: " + str(p3d.twist.twist.angular.vy)
00162 print " " + "z: " + str(p3d.twist.twist.angular.vz)
00163
00164 def odomInput(self, odom):
00165 self.printBaseOdom(odom)
00166 orientation = odom.pose.pose.orientation
00167 q = Q(orientation.x, orientation.y, orientation.z, orientation.w)
00168 q.normalize()
00169 if self.odom_initialized == False:
00170 self.odom_initialized = True
00171 self.odom_xi = odom.pose.pose.position.x
00172 self.odom_yi = odom.pose.pose.position.y
00173 self.odom_ti = q.getEuler().z
00174 self.odom_ei = q.getEuler()
00175 self.odom_x = odom.pose.pose.position.x - self.odom_xi
00176 self.odom_y = odom.pose.pose.position.y - self.odom_yi
00177 self.odom_t = q.getEuler().z - self.odom_ti
00178 self.odom_e.shortest_euler_distance(self.odom_ei, q.getEuler())
00179
00180 def p3dInput(self, p3d):
00181 q = Q(p3d.pose.pose.orientation.x , p3d.pose.pose.orientation.y , p3d.pose.pose.orientation.z , p3d.pose.pose.orientation.w)
00182 q.normalize()
00183 v = q.getEuler()
00184
00185 if self.p3d_initialized == False:
00186 self.p3d_initialized = True
00187 self.p3d_xi = p3d.pose.pose.position.x
00188 self.p3d_yi = p3d.pose.pose.position.y
00189 self.p3d_ti = v.z
00190 self.p3d_ei = E(v.x,v.y,v.z)
00191
00192 self.p3d_x = p3d.pose.pose.position.x - self.p3d_xi
00193 self.p3d_y = p3d.pose.pose.position.y - self.p3d_yi
00194 self.p3d_t = v.z - self.p3d_ti
00195 self.p3d_e.shortest_euler_distance(self.p3d_ei,E(v.x,v.y,v.z))
00196
00197 def debug_e(self):
00198
00199 print " odom " + " x: " + str(self.odom_e.x) + " y: " + str(self.odom_e.y) + " t: " + str(self.odom_e.t)
00200
00201 print " p3d " + " x: " + str(self.p3d_e.x) + " y: " + str(self.p3d_e.y) + " t: " + str(self.p3d_e.t)
00202
00203 def debug_pos(self):
00204
00205 print " odom " + " x: " + str(self.odom_x) + " y: " + str(self.odom_y) + " t: " + str(self.odom_t)
00206
00207 print " p3d " + " x: " + str(self.p3d_x) + " y: " + str(self.p3d_y) + " t: " + str(self.p3d_t)
00208
00209 def init_ros(self, name):
00210 print "LNK\n"
00211 self.pub = rospy.Publisher("/base_controller/command", Twist)
00212 rospy.Subscriber("/base_pose_ground_truth", Odometry, self.p3dInput)
00213 rospy.Subscriber("/base_odometry/odom", Odometry, self.odomInput)
00214 rospy.init_node(name, anonymous=True)