Skip to content

Commit 9e02c5d

Browse files
committed
Add method from_rpy to class QuaternionArray
1 parent 0368775 commit 9e02c5d

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

ahrs/common/quaternion.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)