2 from unittest
import TestCase
3 from dual_quaternions
import DualQuaternion
5 from pyquaternion
import Quaternion
12 self.
random_dq = DualQuaternion.from_quat_pose_array(np.array([1,2,3,4,5,6,7]))
13 self.
other_random_dq = DualQuaternion.from_quat_pose_array(np.array([0.2,0.1,0.3,0.07,1.2,0.9,0.2]))
18 dql = np.array([0.7071067811, 0.7071067811, 0, 0, -3.535533905, 3.535533905, 1.767766952, -1.767766952])
19 dq1 = DualQuaternion.from_dq_array(dql)
20 dq2 = DualQuaternion.from_dq_array(dql)
21 self.assertEqual(dq1, dq2)
23 dq3 = DualQuaternion.from_quat_pose_array(np.array([1, 2, 3, 4, 5, 6, 7]))
24 dq4 = DualQuaternion.from_quat_pose_array([1, 2, 3, 4, 5, 6, 7])
25 self.assertEqual(dq3, dq4)
27 T = np.array([[1, 0, 0, 2], [0, 1, 0, 3], [0, 0, 1, 1], [0, 0, 0, 1]])
28 dq7 = DualQuaternion.from_homogeneous_matrix(T)
29 self.assertEqual(dq7.q_r, Quaternion())
30 self.assertEqual(dq7.translation(), [2, 3, 1])
32 np.testing.assert_array_almost_equal(dq7.homogeneous_matrix(), T)
33 except AssertionError
as e:
36 dq8 = DualQuaternion.from_translation_vector([4, 6, 8])
37 self.assertEqual(dq8.translation(), [4, 6, 8])
40 q_r_unit = Quaternion(1, 0, 0, 0)
41 q_d_zero = Quaternion(0, 0, 0, 0)
42 unit_dq = DualQuaternion(q_r_unit, q_d_zero)
48 dq1 = DualQuaternion.from_translation_vector([4, 6, 8])
49 dq2 = DualQuaternion.from_translation_vector([1, 2, 3])
51 self.assertEqual(sum.q_d, Quaternion(0., 2.5, 4., 5.5))
55 theta1 = np.pi / 180 * 20
56 T_pure_rot = np.array([[1., 0., 0., 0.],
57 [0., np.cos(theta1), -np.sin(theta1), 0.],
58 [0., np.sin(theta1), np.cos(theta1), 0.],
60 dq_pure_rot = DualQuaternion.from_homogeneous_matrix(T_pure_rot)
61 T_pure_trans = np.array([[1., 0., 0., 1.],
65 dq_pure_trans = DualQuaternion.from_homogeneous_matrix(T_pure_trans)
67 T_double_rot = np.dot(T_pure_rot, T_pure_rot)
68 dq_double_rot = dq_pure_rot * dq_pure_rot
70 np.testing.assert_array_almost_equal(T_double_rot, dq_double_rot.homogeneous_matrix())
71 except AssertionError
as e:
74 T_double_trans = np.dot(T_pure_trans, T_pure_trans)
75 dq_double_trans = dq_pure_trans * dq_pure_trans
77 np.testing.assert_array_almost_equal(T_double_trans, dq_double_trans.homogeneous_matrix())
78 except AssertionError
as e:
82 T_composed = np.dot(T_pure_rot, T_pure_trans)
83 dq_composed = dq_pure_rot * dq_pure_trans
84 dq_composed = dq_pure_rot * dq_pure_trans
86 np.testing.assert_array_almost_equal(T_composed, dq_composed.homogeneous_matrix())
87 except AssertionError
as e:
93 self.identity_dq.dq_array())
95 self.random_dq.dq_array())
96 except AssertionError
as e:
101 T_1_2 = np.array([[0, 1, 0, 2], [-1, 0, 0, 4], [0, 0, 1, 6], [0, 0, 0, 1]])
102 T_2_1 = np.array([[0, -1, 0, 4], [1, 0, 0, -2], [0, 0, 1, -6], [0, 0, 0, 1]])
103 dq_1_2 = DualQuaternion.from_homogeneous_matrix(T_1_2)
104 dq_2_1 = DualQuaternion.from_homogeneous_matrix(T_2_1)
107 np.testing.assert_array_almost_equal(dq_2_1.homogeneous_matrix(), dq_1_2.inverse().homogeneous_matrix())
108 except AssertionError
as e:
112 self.assertEqual(self.
identity_dq, DualQuaternion.identity())
113 self.assertEqual(self.
identity_dq, DualQuaternion(-Quaternion(1, 0, 0, 0), -Quaternion(0, 0, 0, 0)))
114 self.assertFalse(self.
identity_dq == DualQuaternion(Quaternion(1, 0, 0, 1), -Quaternion(0, 0, 0, 0)))
115 theta1 = np.pi / 180 * 20
116 T_pure_rot = np.array([[1., 0., 0., 0.],
117 [0., np.cos(theta1), -np.sin(theta1), 0.],
118 [0., np.sin(theta1), np.cos(theta1), 0.],
120 dq_pure_rot = DualQuaternion.from_homogeneous_matrix(T_pure_rot)
122 dq_pure_rot.q_r = - dq_pure_rot.q_r
123 dq_pure_rot.q_d = - dq_pure_rot.q_d
125 np.testing.assert_array_almost_equal(dq_pure_rot.homogeneous_matrix(), T_pure_rot)
126 except AssertionError
as e:
128 dq_pure_rot.q_d = - dq_pure_rot.q_d
130 np.testing.assert_array_almost_equal(dq_pure_rot.homogeneous_matrix(), T_pure_rot)
131 except AssertionError
as e:
133 dq_pure_rot.q_r = - dq_pure_rot.q_r
135 np.testing.assert_array_almost_equal(dq_pure_rot.homogeneous_matrix(), T_pure_rot)
136 except AssertionError
as e:
141 self.assertTrue(isinstance(repr(self.
identity_dq), str))
142 self.assertTrue(isinstance(self.identity_dq.__str__(), str))
145 dq = self.
normalized_dq * self.normalized_dq.quaternion_conjugate()
147 self.assertEqual(dq, DualQuaternion.identity())
150 matr = self.normalized_dq.homogeneous_matrix()
151 inv = np.linalg.inv(matr)
152 self.assertEqual(DualQuaternion.from_homogeneous_matrix(inv), self.normalized_dq.quaternion_conjugate())
156 res2 = self.other_random_dq.quaternion_conjugate() * self.random_dq.quaternion_conjugate()
157 self.assertEqual(res1, res2)
162 trans = [10., 5., 0.]
163 H1 = np.array([[1., 0., 0., trans[0]],
164 [0., np.cos(theta1), -np.sin(theta1), trans[1]],
165 [0., np.sin(theta1), np.cos(theta1), trans[2]],
168 double_conv1 = DualQuaternion.from_homogeneous_matrix(H1).homogeneous_matrix()
170 np.testing.assert_array_almost_equal(H1, double_conv1)
171 except AssertionError
as e:
174 dq1 = DualQuaternion.from_homogeneous_matrix(H1)
175 dq_double1 = DualQuaternion.from_homogeneous_matrix(double_conv1)
176 self.assertEqual(dq1, dq_double1)
179 dq_trans = DualQuaternion.from_translation_vector([10, 5, 0])
180 dq_rot = DualQuaternion.from_dq_array([np.cos(theta1 / 2), np.sin(theta1 / 2), 0, 0, 0, 0, 0, 0])
181 dq2 = dq_trans * dq_rot
183 self.assertEqual(dq2, dq1)
185 double_conv2 = DualQuaternion.from_homogeneous_matrix(dq2.homogeneous_matrix())
186 self.assertEqual(dq2, double_conv2)
192 res2 = self.random_dq.dual_number_conjugate() * self.other_random_dq.dual_number_conjugate()
193 self.assertEqual(res1, res2)
196 dq = self.
normalized_dq * self.normalized_dq.combined_conjugate()
198 self.assertAlmostEqual(dq.q_r, Quaternion())
201 res2 = self.other_random_dq.combined_conjugate() * self.random_dq.combined_conjugate()
202 self.assertEqual(res1, res2)
205 self.assertTrue(self.identity_dq.is_normalized())
206 self.assertEqual(self.identity_dq.normalized(), self.
identity_dq)
207 unnormalized_dq = DualQuaternion.from_quat_pose_array([1, 2, 3, 4, 5, 6, 7])
208 unnormalized_dq.normalize()
209 self.assertTrue(unnormalized_dq.is_normalized())
214 self.assertEqual(self.identity_dq.transform_point(point_f2), point_f2)
217 T_f1_f2 = np.array([[1, 0, 0, 2],
218 [0, 0.54028748, -0.8414805, 3],
219 [0, 0.8414805, 0.54028748, 1],
221 dq_f1_f2 = DualQuaternion.from_homogeneous_matrix(T_f1_f2)
224 point_f1_matrix = np.dot(T_f1_f2, np.expand_dims(np.array(point_f2 + [1]), 1))
225 point_f1_dq = np.array(dq_f1_f2.transform_point(point_f2))
227 np.testing.assert_array_almost_equal(point_f1_matrix[:3].T.flatten(), point_f1_dq.flatten(), decimal=3)
228 except AssertionError
as e:
233 l, m, theta, d = self.identity_dq.screw()
234 self.assertEqual(d, 0)
235 self.assertEqual(theta, 0)
239 dq_trans = DualQuaternion.from_translation_vector(trans)
240 l, m, theta, d = dq_trans.screw()
241 self.assertAlmostEqual(d, np.linalg.norm(trans), 2)
242 self.assertAlmostEqual(theta, 0)
246 dq_rot = DualQuaternion.from_dq_array([np.cos(theta1 / 2), np.sin(theta1 / 2), 0, 0, 0, 0, 0, 0])
247 l, m, theta, d = dq_rot.screw()
248 self.assertAlmostEqual(theta, theta1)
253 dq_rot2 = DualQuaternion.from_dq_array([np.cos(theta2 / 2), 0, 0, np.sin(theta2 / 2), 0, 0, 0, 0])
256 dq_trans = DualQuaternion.from_translation_vector([dist_axis*np.sin(theta2), dist_axis*(1.-np.cos(theta2)),
258 dq_comb = dq_trans * dq_rot2
259 l, m, theta, d = dq_comb.screw()
262 np.testing.assert_array_almost_equal(l, np.array([0, 0, 1]), decimal=3)
264 np.testing.assert_array_almost_equal(np.cross(np.array([[0, dist_axis, 0]]), l).flatten(), m)
265 except AssertionError
as e:
267 self.assertAlmostEqual(d, displacement_z)
268 self.assertAlmostEqual(theta, theta2)
272 l = np.array([0, 0, 1])
274 p = np.array([-1, 0, 0])
281 desired_dq_rot = DualQuaternion.from_quat_pose_array([np.cos(theta/2), 0, 0, np.sin(theta/2), 0, 0, 0])
282 desired_dq_trans = DualQuaternion.from_translation_vector([-1, 1, d])
283 desired_dq = desired_dq_trans * desired_dq_rot
284 dq = DualQuaternion.from_screw(l, m, theta, d)
285 self.assertEqual(dq, desired_dq)
289 dq = DualQuaternion.from_quat_pose_array([0.5, 0.3, 0.1, 0.4, 2, 5, -2])
290 lr, mr, thetar, dr = dq.screw()
291 dq_reconstructed = DualQuaternion.from_screw(lr, mr, thetar, dr)
292 self.assertEqual(dq, dq_reconstructed)
295 l1 = np.array([0.4, 0.2, 0.5])
296 l1 /= np.linalg.norm(l1)
298 p1 = np.array([2.3, 0.9, 1.1])
299 m1 = np.cross(p1, l1)
302 dq1 = DualQuaternion.from_screw(l1, m1, theta1, d1)
303 l2, m2, theta2, d2 = dq1.screw()
305 np.testing.assert_array_almost_equal(l1, l2, decimal=3)
306 np.testing.assert_array_almost_equal(l1, l2, decimal=3)
307 except AssertionError
as e:
309 self.assertAlmostEqual(theta1, theta2)
310 self.assertAlmostEqual(d1, d2)
315 self.identity_dq.save(dir +
'/identity.json')
317 loaded_unit = DualQuaternion.from_file(dir +
'/identity.json')
320 os.remove(dir +
'/identity.json')
323 self.assertRaises(IOError, DualQuaternion.from_file,
'boguspath')
326 """test Screw Linear Interpolation for diff position, same orientation""" 327 dq1 = DualQuaternion.from_translation_vector([2, 2, 2])
328 dq2 = DualQuaternion.from_translation_vector([3, 4, -2])
329 interpolated1 = DualQuaternion.sclerp(dq1, dq2, 0.5)
330 expected1 = DualQuaternion.from_translation_vector([2.5, 3, 0])
331 self.assertEqual(interpolated1, expected1)
332 interpolated2 = DualQuaternion.sclerp(dq1, dq2, 0.1)
333 expected2 = DualQuaternion.from_translation_vector([2.1, 2.2, 1.6])
334 self.assertEqual(interpolated2, expected2)
337 """test Screw Linear Interpolation for diff orientation, same position""" 338 T_id = DualQuaternion.identity().homogeneous_matrix()
339 T_id[0:2, 0:2] = np.array([[0, -1], [1, 0]])
340 dq2 = DualQuaternion.from_homogeneous_matrix(T_id)
341 interpolated1 = DualQuaternion.sclerp(self.
identity_dq, dq2, 0.5)
342 T_exp = DualQuaternion.identity().homogeneous_matrix()
344 T_exp[0:2, 0:2] = np.array([[sq22, -sq22], [sq22, sq22]])
345 expected1 = DualQuaternion.from_homogeneous_matrix(T_exp)
346 self.assertEqual(interpolated1, expected1)
347 interpolated2 = DualQuaternion.sclerp(self.
identity_dq, dq2, 0)
348 interpolated3 = DualQuaternion.sclerp(self.
identity_dq, dq2, 1)
350 self.assertEqual(interpolated3, dq2)
353 """Interpolating with ScLERP should yield same result as interpolating with screw parameters 354 ScLERP is a screw motion interpolation with constant rotation and translation speeds. We can 355 simply interpolate screw parameters theta and d and we should get the same result. 357 taus = [0., 0.23, 0.6, 1.0]
358 l, m, theta, d = self.normalized_dq.screw()
363 interpolated_dq_screw = DualQuaternion.from_screw(l, m, tau*theta, tau*d)
364 self.assertEqual(interpolated_dq, interpolated_dq_screw)
368 received_result = self.normalized_dq.pow(2)
369 self.assertEqual(received_result, expected_result)
372 received_result = self.random_dq.pow(2)
373 self.assertEqual(received_result, expected_result)
def test_from_screw(self)
def test_from_screw_and_back(self)
def test_quaternion_conjugate(self)
def test_sclerp_orientation(self)
def test_sclerp_position(self)
def test_combined_conjugate(self)
def test_dual_number_conjugate(self)
def test_saving_loading(self)
def test_sclerp_screw(self)
def test_homogeneous_conversion(self)
def test_str_repr_is_string(self)
def test_loading_illegal(self)