2 from dynamic_graph.sot.tools.se3
import SO3
3 from numpy
import linalg
11 A quaternion has a scalar part and a vector part. 12 In this class the quaternion is represented as an array of 4 elements : 13 - the first element is the scalar part 14 - the next 3 elements represents the vector part 16 One can acces to the array directly with the attribute "array" 17 e.g. q1=Quaternion(1,0,0,0) --> q1.array 19 A quaternion can be instanciated with 1, 2 or 4 elements 20 (see : __init__() for more information). 22 It can also return a rotation vector, a rotation matrix, or a SO3 23 (see the methods : to...() for more information). 28 Instanciation of the quaternion with 1, 2 or 4 arguments : 29 ----------------------------------------------------------- 30 This creates a 4-sized array (self.array) representing the quaternion 31 with the first element representing the scalar part 32 and the 3 others the vector part. 36 - the first one is used as the scalar part, 37 the other three as the vector part. 41 - the 1-sized argument is used as the scalar part, 42 the 3-sized argument is used as the vector part. 46 - if it is a quaternion it will create a copy of this quaternion. 47 - if it is a scalar, the scalar will be used as the scalar part 48 and the vector part will be set at (0,0,0). 49 - if it is an array, matrix, tuple or list of 4 elements, 50 the first element is used as the scalar part 51 and the rest as the vector part. 52 - if it is an array, matrix, tuple or list of 3 elements, 53 the 3 elements are interpreted as a rotation vector, 54 this creates a quaternion representing the same rotation. 55 - if it is a to 2 dimension array convertible array, matrix, tuple 56 or list with at least (3*3) elements, 57 the upper left (3*3) elements are interpreted as a rotation matrix, 58 this creates a quaternion representing the same rotation. 62 If no argument is given, than the quaternion will be set by default 63 to with the scalar part set to 1 and the vector part to (0,0,0). 64 (this is the neutral element for multiplication in quaternion space) 66 To create a quaternion from Roll, Pitch, Yaw angles : 67 ----------------------------------------------------- 68 first instanciate a quaternion and than use the method fromRPY() 69 to change the values of it to the dezired ones. 70 e.g. : quat().fromRPY(R,P,Y) 75 self.
array = np.array([1.0, 0.0, 0.0, 0.0])
77 if np.array(args).size == 4:
78 self.
array = np.double(np.array(args))
82 if type(args[0]) == Quaternion:
83 self.
array = args[0].array.copy()
84 elif np.array(args[0]).size == 1:
87 self.
array = np.double(
88 np.hstack([np.array(args[0]), np.array([0, 0, 0])])
90 elif np.array(args[0]).size == 4
and max(np.array(args[0]).shape) == 4:
92 self.
array = np.double(np.array(args[0])).reshape(
95 elif np.array(args[0]).size == 3
and max(np.array(args[0]).shape) == 3:
98 rV = np.double(np.array(args[0])).reshape(
101 alpha = np.double(linalg.norm(rV))
106 self.
array = np.hstack([np.cos(alpha / 2.0), np.sin(alpha / 2.0) * e])
108 len(np.array(args[0]).shape) == 2
109 and np.array(args[0]).shape[0] >= 3
110 and np.array(args[0]).shape[1] >= 3
114 rM = np.double(np.array(args[0])[:3, :3])
116 selec[0] = 1 + rM[0, 0] + rM[1, 1] + rM[2, 2]
117 selec[1] = 1 + rM[0, 0] - rM[1, 1] - rM[2, 2]
118 selec[2] = 1 - rM[0, 0] + rM[1, 1] - rM[2, 2]
119 selec[3] = 1 - rM[0, 0] - rM[1, 1] + rM[2, 2]
120 param = selec.argmax()
124 q[0] = np.sqrt(selec[param])
125 q[1] = (rM[2, 1] - rM[1, 2]) / q[0]
126 q[2] = (rM[0, 2] - rM[2, 0]) / q[0]
127 q[3] = (rM[1, 0] - rM[0, 1]) / q[0]
131 q[1] = np.sqrt(selec[param])
132 q[0] = (rM[2, 1] - rM[1, 2]) / q[1]
133 q[2] = (rM[1, 0] + rM[0, 1]) / q[1]
134 q[3] = (rM[0, 2] + rM[2, 0]) / q[1]
138 q[2] = np.sqrt(selec[param])
139 q[0] = (rM[0, 2] - rM[2, 0]) / q[2]
140 q[1] = (rM[1, 0] + rM[0, 1]) / q[2]
141 q[3] = (rM[2, 1] + rM[1, 2]) / q[2]
145 q[3] = np.sqrt(selec[param])
146 q[0] = (rM[1, 0] - rM[0, 1]) / q[3]
147 q[1] = (rM[0, 2] + rM[2, 0]) / q[3]
148 q[2] = (rM[2, 1] + rM[1, 2]) / q[3]
158 arg0 = np.double(np.array(args[0]))
159 arg1 = np.double(np.array(args[1]))
160 if arg0.size == 1
and arg1.size == 3:
161 self.
array = np.zeros(4)
163 self.
array[1:4] = arg1[:]
164 elif arg0.size == 3
and arg1.size == 1:
165 self.
array = np.zeros(4)
167 self.
array[1:4] = arg0[:]
174 if not error
and self.
array.shape != (4,):
179 "Impossible to instanciate the Quaternion object " 180 "with the given arguments" 185 String representation of the quaternion. 188 aff += str(self.
array[0]) +
" + " 189 aff += str(self.
array[1]) +
" i + " 190 aff += str(self.
array[2]) +
" j + " 191 aff += str(self.
array[3]) +
" k ]" 196 Returns a quaternion which elements are the opposite of the original, 197 (this opposite quaternion represents the same rotation). 203 If other is not a quaternion it is casted to a quaternion, 204 the elements are added one to one. 206 if type(other) != Quaternion:
214 If other is not a quaternion it is casted to a quaternion, 215 the elements are substracted one to one. 217 if type(other) != Quaternion:
225 If other is not a quaternion it is casted to a quaternion, 226 the result of the quaternion multiplication is returned. 228 if type(other) != Quaternion:
233 qr[0] = self.
array[0] * q2.array[0] - np.vdot(self.
array[1:], q2.array[1:])
235 np.cross(self.
array[1:4], q2.array[1:4])
236 + self.
array[0] * q2.array[1:4]
237 + q2.array[0] * self.
array[1:4]
243 other is casted to a quaternion, 244 the result of the quaternion multiplication is returned. 250 Returns the norm of the quaternion. 252 return np.double(linalg.norm(self.
array))
256 Returns the conjugate of the quaternion. 262 Returns the inverse of the quaternion. 268 If other is not a quaternion it is casted to a quaternion, 269 the result of the quaternion multiplication with the inverse of other 272 if type(other) != Quaternion:
276 return self * q2.inv()
280 Returns quaternion**n with quaternion**0 = Quaternion(1,0,0,0). 289 Changes the values of the quaternion to make it a unit quaternion 290 representing the same rotation as the original one 291 and returns the updated version. 293 self.
array /= abs(self)
298 Returns the unit quaternion representation of the quaternion 299 without changing the original. 307 Returns the corresponding SO3. 313 Returns a (3*3) array (rotation matrix) 314 representing the same rotation as the (normalized) quaternion. 317 rm = np.zeros((3, 3))
318 rm[0, 0] = 1 - 2 * (q[2] ** 2 + q[3] ** 2)
319 rm[0, 1] = 2 * q[1] * q[2] - 2 * q[0] * q[3]
320 rm[0, 2] = 2 * q[1] * q[3] + 2 * q[0] * q[2]
321 rm[1, 0] = 2 * q[1] * q[2] + 2 * q[0] * q[3]
322 rm[1, 1] = 1 - 2 * (q[1] ** 2 + q[3] ** 2)
323 rm[1, 2] = 2 * q[2] * q[3] - 2 * q[0] * q[1]
324 rm[2, 0] = 2 * q[1] * q[3] - 2 * q[0] * q[2]
325 rm[2, 1] = 2 * q[2] * q[3] + 2 * q[0] * q[1]
326 rm[2, 2] = 1 - 2 * (q[1] ** 2 + q[2] ** 2)
331 Returns a 3-sized array (rotation vector) 332 representing the same rotation as the (normalized) quaternion. 336 alpha = 2 * np.arccos(q[0])
337 if linalg.norm(q[1:4]) != 0:
338 rV = alpha * q[1:4] / linalg.norm(q[1:4])
343 Returns a copy of the quaternion. 349 Returns a 3-sized array with representing the same rotation 350 as the (normalized) quaternion. With : 351 - the first element representing the Roll, 352 - the second the Pitch 354 Where Roll Pitch and Yaw are the angles so that the rotation 355 with the quaternion represents the same rotation as : 356 - A rotation of R (Roll) about the original x-axis, 357 followed by a rotation of P (Pitch) about the original y-axis, 358 followed by a rotation of Y (Yaw) about the original z-axis. 359 - Or otherwise a rotation of Y about the original z-axis, 360 followed by a rotation of P about the new y-axis, 361 followed by a rotation of R about the new x-axis. 364 r = np.arctan2(2 * (q[0] * q[1] + q[2] * q[3]), 1 - 2 * (q[1] ** 2 + q[2] ** 2))
366 2 * (q[0] * q[2] - q[3] * q[1]),
368 (2 * (q[0] * q[1] + q[2] * q[3])) ** 2
369 + (1 - 2 * (q[1] ** 2 + q[2] ** 2)) ** 2
372 y = np.arctan2(2 * (q[0] * q[3] + q[1] * q[2]), 1 - 2 * (q[2] ** 2 + q[3] ** 2))
373 return np.array([r, p, y])
377 Set the values of the quaternion to the values of a unit quaternion 378 representing the same rotation as the one performed by Roll Pitch Yaw : 379 - A rotation of R (Roll) about the original x-axis, 380 followed by a rotation of P (Pitch) about the original y-axis, 381 followed by a rotation of Y (Yaw) about the original z-axis. 382 - Or otherwise a rotation of Y about the original z-axis, 383 followed by a rotation of P about the new y-axis, 384 followed by a rotation of R about the new x-axis. 389 self.
array[0] = np.cos(r) * np.cos(p) * np.cos(y) + np.sin(r) * np.sin(
392 self.
array[1] = np.sin(r) * np.cos(p) * np.cos(y) - np.cos(r) * np.sin(
395 self.
array[2] = np.cos(r) * np.sin(p) * np.cos(y) + np.sin(r) * np.cos(
398 self.
array[3] = np.cos(r) * np.cos(p) * np.sin(y) - np.sin(r) * np.sin(
def __rmul__(self, other)
def toRotationVector(self)
def toRotationMatrix(self)
def fromRPY(self, R, P, Y)