@@ -2464,6 +2464,75 @@ def conj(self) -> np.ndarray:
24642464 """
24652465 return self .conjugate ()
24662466
2467+ def from_rpy (self , Angles : np .ndarray ) -> np .ndarray :
2468+ """
2469+ Quaternion Array from given RPY angles.
2470+
2471+ The quaternion can be constructed from the Aerospace cardanian angle
2472+ sequence that follows the order :math:`\\ phi\\ to\\ theta\\ to\\ psi`,
2473+ where :math:`\\ phi` is the **roll** (or *bank*) angle, :math:`\\ theta`
2474+ is the **pitch** (or *elevation*) angle, and :math:`\\ psi` is the
2475+ **yaw** (or *heading*) angle.
2476+
2477+ The composing quaternions are:
2478+
2479+ .. math::
2480+ \\ begin{array}{rcl}
2481+ \\ mathbf{q}_X &=& \\ begin{pmatrix}\\ cos\\ frac{\\ phi}{2} & \\ sin\\ frac{\\ phi}{2} & 0 & 0\\ end{pmatrix} \\ \\ && \\ \\
2482+ \\ mathbf{q}_Y &=& \\ begin{pmatrix}\\ cos\\ frac{\\ theta}{2} & 0 & \\ sin\\ frac{\\ theta}{2} & 0\\ end{pmatrix} \\ \\ && \\ \\
2483+ \\ mathbf{q}_Z &=& \\ begin{pmatrix}\\ cos\\ frac{\\ psi}{2} & 0 & 0 & \\ sin\\ frac{\\ psi}{2}\\ end{pmatrix}
2484+ \\ end{array}
2485+
2486+ The elements of the final quaternion
2487+ :math:`\\ mathbf{q}=\\ mathbf{q}_Z\\ mathbf{q}_Y\\ mathbf{q}_X = q_w+q_xi+q_yj+q_zk`
2488+ are obtained as:
2489+
2490+ .. math::
2491+ \\ begin{array}{rcl}
2492+ q_w &=& \\ cos\\ frac{\\ psi}{2}\\ cos\\ frac{\\ theta}{2}\\ cos\\ frac{\\ phi}{2} + \\ sin\\ frac{\\ psi}{2}\\ sin\\ frac{\\ theta}{2}\\ sin\\ frac{\\ phi}{2} \\ \\ && \\ \\
2493+ q_x &=& \\ cos\\ frac{\\ psi}{2}\\ cos\\ frac{\\ theta}{2}\\ sin\\ frac{\\ phi}{2} - \\ sin\\ frac{\\ psi}{2}\\ sin\\ frac{\\ theta}{2}\\ cos\\ frac{\\ phi}{2} \\ \\ && \\ \\
2494+ q_y &=& \\ cos\\ frac{\\ psi}{2}\\ sin\\ frac{\\ theta}{2}\\ cos\\ frac{\\ phi}{2} + \\ sin\\ frac{\\ psi}{2}\\ cos\\ frac{\\ theta}{2}\\ sin\\ frac{\\ phi}{2} \\ \\ && \\ \\
2495+ q_z &=& \\ sin\\ frac{\\ psi}{2}\\ cos\\ frac{\\ theta}{2}\\ cos\\ frac{\\ phi}{2} - \\ cos\\ frac{\\ psi}{2}\\ sin\\ frac{\\ theta}{2}\\ sin\\ frac{\\ phi}{2}
2496+ \\ end{array}
2497+
2498+ .. warning::
2499+ The Aerospace sequence :math:`\\ phi\\ to\\ theta\\ to\\ psi` is only
2500+ one of the `twelve possible rotation sequences
2501+ <https://en.wikipedia.org/wiki/Euler_angles#Tait.E2.80.93Bryan_angles>`_
2502+ around the main axes. Other sequences might be more suitable for
2503+ other applications, but this one is the most common in practice.
2504+
2505+ Parameters
2506+ ----------
2507+ Angles : numpy.ndarray
2508+ N-by-3 cardanian angles, in radians, following the order: roll -> pitch -> yaw.
2509+
2510+ Returns
2511+ -------
2512+ Q : numpy.ndarray
2513+ Quaternion Array from roll-pitch-yaw angles.
2514+
2515+ """
2516+ _assert_iterables (Angles , 'Roll-Pitch-Yaw angles' )
2517+ Angles = np .copy (Angles )
2518+ if Angles .ndim != 2 or Angles .shape [- 1 ] != 3 :
2519+ raise ValueError (f"Expected `angles` must have shape (N, 3), got { Angles .shape } ." )
2520+ if not all (- 2.0 * np .pi <= angle <= 2.0 * np .pi for angle in Angles .flatten ()):
2521+ raise ValueError (f"Expected `angles` must be in [-2*pi, 2*pi]" )
2522+ # RPY to Quaternion
2523+ cy = np .cos (0.5 * Angles [:, 2 ])
2524+ sy = np .sin (0.5 * Angles [:, 2 ])
2525+ cp = np .cos (0.5 * Angles [:, 1 ])
2526+ sp = np .sin (0.5 * Angles [:, 1 ])
2527+ cr = np .cos (0.5 * Angles [:, 0 ])
2528+ sr = np .sin (0.5 * Angles [:, 0 ])
2529+ Q = np .zeros ((Angles .shape [0 ], 4 ))
2530+ Q [:, 0 ] = cy * cp * cr + sy * sp * sr
2531+ Q [:, 1 ] = cy * cp * sr - sy * sp * cr
2532+ Q [:, 2 ] = sy * cp * sr + cy * sp * cr
2533+ Q [:, 3 ] = sy * cp * cr - cy * sp * sr
2534+ return Q / np .linalg .norm (Q , axis = 1 )[:, None ]
2535+
24672536 def to_angles (self ) -> np .ndarray :
24682537 """
24692538 Return corresponding roll-pitch-yaw angles of quaternion.
0 commit comments