22from typing import List , Union , Tuple
33
44import numpy as np
5- import quaternion
6- from quaternion import quaternion as quat
75
86from ..datatypes .pose import PoseData
97from ..datatypes .laserscan import LaserScanData
@@ -81,21 +79,41 @@ def probability_of_collision(
8179 return prop_col
8280
8381
84- def _rotate_vector_by_quaternion ( q : quaternion . quaternion , v : List ) -> List :
82+ def _np_quaternion_multiply ( q1 : np . ndarray , q2 : np . ndarray ) -> np . ndarray :
8583 """
86- rotate a vector v by a rotation quaternion q
84+ Multiplies two quaternions q1 * q2
85+ Each quaternion is an array [w, x, y, z]
86+ """
87+ w0 , x0 , y0 , z0 = q1
88+ w1 , x1 , y1 , z1 = q2
89+ return np .array ([
90+ w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1 ,
91+ w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1 ,
92+ w0 * y1 - x0 * z1 + y0 * w1 + z0 * x1 ,
93+ w0 * z1 + x0 * y1 - y0 * x1 + z0 * w1 ,
94+ ])
95+
96+
97+ def _np_quaternion_conjugate (q : np .ndarray ) -> np .ndarray :
98+ """
99+ Returns the conjugate of a quaternion
100+ """
101+ w , x , y , z = q
102+ return np .array ([w , - x , - y , - z ])
103+
87104
88- :param q: the rotation to perform
89- :type q: quaternion.quaternion
90- :param v: the vector to be rotated
91- :type v: List
105+ def _rotate_vector_by_quaternion (q : np .ndarray , v : List [float ]) -> List [float ]:
106+ """
107+ Rotate a 3D vector v by a quaternion q.
92108
93- :return: the rotated position of the vector
94- :rtype: List
109+ :param q: quaternion [w, x, y, z]
110+ :param v: vector [x, y, z]
111+ :return: rotated vector
95112 """
96- vq = quat (0 , 0 , 0 , 0 )
97- vq .imag = v
98- return (q * vq * q .inverse ()).imag
113+ vq = np .array ([0.0 , * v ])
114+ q_conj = _np_quaternion_conjugate (q )
115+ rotated_vq = _np_quaternion_multiply (_np_quaternion_multiply (q , vq ), q_conj )
116+ return rotated_vq [1 :].tolist ()
99117
100118
101119def get_pose_target_in_reference_frame (
@@ -119,21 +137,24 @@ def get_pose_target_in_reference_frame(
119137 reference_position = reference_pose .get_position ()
120138 reference_rotation = reference_pose .get_orientation ()
121139
122- orientation_target_in_ref = reference_rotation .inverse () * orientation_target
140+ orientation_target_in_ref = (
141+ _np_quaternion_conjugate (reference_rotation ) * orientation_target
142+ )
123143
124144 position_target_in_ref = _rotate_vector_by_quaternion (
125- reference_rotation .inverse (), (position_target - reference_position ).tolist ()
145+ _np_quaternion_conjugate (reference_rotation ),
146+ (position_target - reference_position ).tolist (),
126147 )
127148
128149 target_pose_in_ref = PoseData ()
129150 target_pose_in_ref .set_pose (
130151 x = position_target_in_ref [0 ],
131152 y = position_target_in_ref [1 ],
132153 z = position_target_in_ref [2 ],
133- qw = orientation_target_in_ref . w ,
134- qx = orientation_target_in_ref . x ,
135- qy = orientation_target_in_ref . y ,
136- qz = orientation_target_in_ref . z ,
154+ qw = orientation_target_in_ref [ 0 ] ,
155+ qx = orientation_target_in_ref [ 1 ] ,
156+ qy = orientation_target_in_ref [ 2 ] ,
157+ qz = orientation_target_in_ref [ 3 ] ,
137158 )
138159
139160 return target_pose_in_ref
@@ -209,7 +230,7 @@ def from_2d_to_PoseData(x: float, y: float, heading: float) -> PoseData:
209230 :rtype: PoseData
210231 """
211232 pose_data = PoseData ()
212- quat_data : quat = from_euler_to_quaternion (heading , 0.0 , 0.0 )
233+ quat_data : np . ndarray = from_euler_to_quaternion (heading , 0.0 , 0.0 )
213234 pose_data .set_position (x , y , 0.0 )
214235 pose_data .set_orientation (
215236 qw = quat_data [0 ], qx = quat_data [1 ], qy = quat_data [2 ], qz = quat_data [3 ]
0 commit comments