Conversion between quaternions and Euler angles: Difference between revisions

Content deleted Content added
Miki88 (talk | contribs)
Link suggestions feature: 3 links added.
 
(48 intermediate revisions by 23 users not shown)
Line 1:
{{Short description|Mathematical strategy}}
{{cleanup rewrite|date=January 2024}}
[[Rotation formalisms in three dimensions|Spatial rotations in three dimensions]] can be [[Coordinate system|parametrized]] using both [[Euler angles]] and [[Quaternions and spatial rotation|unit quaternions]]. This article explains how to convert between the two representations. Actually this simple use of "quaternions" was first presented by [[Leonhard Euler|Euler]] some seventy years earlier than [[William Rowan Hamilton|Hamilton]] to solve the problem of [[magic square]]s. For this reason the dynamics community commonly refers to quaternions in this application as "Euler parameters".
 
==Definition==
There are [[Quaternions_and_spatial_rotation#Alternative_conventions|two representations]] of quaternions. This article uses the more popular Hamilton.
For the rest of this article, the [[JPL]] [[quaternion]] convention<ref>W. G. Breckenridge, "Quaternions proposed standard conventions," NASA Jet Propulsion Laboratory, Technical Report, Oct. 1979.</ref> shall be used. A unit [[quaternion]] can be described as:
 
:<math>\mathbf{q} = \begin{bmatrix} q_0 & q_1 & q_2 & q_3 \end{bmatrix}^T = \begin{bmatrix} q_w & q_x & q_y & q_z \end{bmatrix}^T</math>
A quaternion has 4 real values: {{mvar|q<sub>w</sub>}} (the real part or the scalar part) and {{mvar|q<sub>x</sub> q<sub>y</sub> q<sub>z</sub>}} (the imaginary part).
:<math>|\mathbf{q}|^2 = q_0^2 + q_1^2 + q_2^2 + q_3^2 = q_w^2 + q_x^2 + q_y^2 + q_z^2 = 1</math>
 
Defining the [[Quaternion#Conjugation,_the_norm,_and_reciprocal|norm of the quaternion]] as follows:
:<math display=block>|\mathbf{lVert q}|^2 = q_0^2 + q_1^2 + q_2^2 + q_3^2\rVert = \sqrt{\,q_w^2 + q_x^2 + q_y^2 + q_z^2 = 1~}</math>
 
A ''unit quaternion'' satisfies:
<math display=block>\lVert q \rVert = 1</math>
 
We can associate a [[quaternion]] with a rotation around an axis by the following expression
 
:<math>\mathbf{q}_0 = \mathbf{q}_w = \cos(\alpha/2)</math>
:<math>\mathbf{q}_1 = \mathbf{q}_x = \sin(\alpha/2)\cos(\beta_x)</math>
:<math>\mathbf{q}_2 = \mathbf{q}_y = \sin(\alpha/2)\cos(\beta_y)</math>
:<math>\mathbf{q}_3 = \mathbf{q}_z = \sin(\alpha/2)\cos(\beta_z)</math>
where α is a simple rotation angle (the value in radians of the [[angle of rotation]]) and cos(β<sub>''x''</sub>), cos(β<sub>''y''</sub>) and cos(β<sub>''z''</sub>) are the "[[direction cosine]]s" of the angles between the three coordinate axes and the axis of rotation. ([[Euler's rotation theorem|Euler's Rotation Theorem]]).
 
==Intuition==
To better understand how "[[direction cosine]]s" work with quaternions:
 
:<math>\begin{array}{lcr} \mathbf{q}_0 = \mathbf{q}_w = \cos(\text{rotation angle}/2)\\
\mathbf{q}_1 = \mathbf{q}_x = \sin(\text{rotation angle}/2)\cos(\text{angle between axis of rotation and x axis})\\
\mathbf{q}_2 = \mathbf{q}_y = \sin(\text{rotation angle}/2)\cos(\text{angle between axis of rotation and y axis})\\
\mathbf{q}_3 = \mathbf{q}_z = \sin(\text{rotation angle}/2)\cos(\text{angle between axis of rotation and z axis})\end{array}</math>
 
If the [[axis of rotation]] is the ''x''-axis:
 
:<math>\begin{array}{lcr} \mathbf{q}_0 = \mathbf{q}_w = \cos(\alpha/2)\\
\mathbf{q}_1 = \mathbf{q}_x = \sin(\alpha/2)\cdot1\\
\mathbf{q}_2 = \mathbf{q}_y = \sin(\alpha/2)\cdot0\\
\mathbf{q}_3 = \mathbf{q}_z = \sin(\alpha/2)\cdot0\end{array}</math>
 
If the [[axis of rotation]] is the ''y''-axis:
 
:<math>\begin{array}{lcr} \mathbf{q}_0 = \mathbf{q}_w = \cos(\alpha/2)\\
\mathbf{q}_1 = \mathbf{q}_x = \sin(\alpha/2)\cdot0\\
\mathbf{q}_2 = \mathbf{q}_y = \sin(\alpha/2)\cdot1\\
\mathbf{q}_3 = \mathbf{q}_z = \sin(\alpha/2)\cdot0\end{array}</math>
 
If the [[axis of rotation]] is the ''z''-axis:
 
:<math>\begin{array}{lcr} \mathbf{q}_w = \cos(\alpha/2)\\
\mathbf{q}_x = \sin(\alpha/2)\cdot0\\
\mathbf{q}_y = \sin(\alpha/2)\cdot0\\
\mathbf{q}_z = \sin(\alpha/2)\cdot1\end{array}</math>
 
If the [[axis of rotation]] is a [[Vector_(mathematics_and_physics)|vector]] located 45° ({{sfrac|{{pi}}|4}} radians) between the ''x'' and ''y'' axes:
 
:<math>\begin{array}{lcr} \mathbf{q}_0 = \mathbf{q}_w = \cos(\alpha/2)\\
\mathbf{q}_1 = \mathbf{q}_x = \sin(\alpha/2)\cdot0.707 \ldots\\
\mathbf{q}_2 = \mathbf{q}_y = \sin(\alpha/2)\cdot0.707 \ldots\\
\mathbf{q}_3 = \mathbf{q}_z = \sin(\alpha/2)\cdot0\end{array}</math>
 
Therefore, the ''x'' and ''y'' axes "share" influence over the new [[axis of rotation]].
 
===Tait–Bryan angles===
[[Image:taitbrianzyx.svg|thumb|right|200px|Tait–Bryan angles. ''z-y′-x″'' sequence (intrinsic rotations; ''N'' coincides with ''y’''). The angle rotation sequence is ''ψ'', ''θ'', ''Фφ''. Note that in this case ''ψ > 90°'' and ''θ'' is a negative angle.]]
 
Similarly for Euler angles, we use the [[Euler angles#Tait–Bryan_angles|Tait Bryan angles]] (in terms of [[flight dynamics]]):
Line 55 ⟶ 70:
 
== Rotation matrices ==
The [[orthogonal matrix]] (post-multiplying a [[Row and column vectors|column vector]]) corresponding to a clockwise/[[Right-hand rule|left-handed]] (looking along positive axis to origin) rotation by the unit [[quaternion]] <math>q=q_0q_w+iq_1iq_x+jq_2jq_y+kq_3kq_z</math> is given by the [[Quaternions and spatial rotation#Quaternion-derived rotation matrix|inhomogeneous expression]]:
 
:<math>R = \begin{bmatrix}
1- 2(q_2q_y^2 + q_3q_z^2) & 2(q_1q_x q_2q_y - q_0q_w q_3q_z) & 2(q_0q_w q_2q_y + q_1q_x q_3q_z) \\
2(q_1q_x q_2q_y + q_0q_w q_3q_z) & 1 - 2(q_1q_x^2 + q_3q_z^2) & 2(q_2q_y q_3q_z - q_0q_w q_1q_x) \\
2(q_1q_x q_3q_z - q_0q_w q_2q_y) & 2( q_0q_w q_1q_x + q_2q_y q_3q_z) & 1 - 2(q_1q_x^2 + q_2q_y^2)
\end{bmatrix}</math>
 
Line 66 ⟶ 81:
 
:<math>R = \begin{bmatrix}
q_0q_w^2 + q_1q_x^2 - q_2q_y^2 - q_3q_z^2 & 2(q_1q_x q_2q_y - q_0q_w q_3q_z) & 2(q_0q_w q_2q_y + q_1q_x q_3q_z) \\
2(q_1q_x q_2q_y + q_0q_w q_3q_z) & q_0q_w^2 - q_1q_x^2 + q_2q_y^2 - q_3q_z^2 & 2(q_2q_y q_3q_z - q_0q_w q_1q_x) \\
2(q_1q_x q_3q_z - q_0q_w q_2q_y) & 2( q_0q_w q_1q_x + q_2q_y q_3q_z) & q_0q_w^2 - q_1q_x^2 - q_2q_y^2 + q_3q_z^2
\end{bmatrix}</math>
 
If <math>q_0q_w+iq_1iq_x+jq_2jq_y+kq_3kq_z</math> is not a unit quaternion then the homogeneous form is still a scalar multiple of a rotation matrix, while the inhomogeneous form is in general no longer an orthogonal matrix. This is why in numerical work the homogeneous form is to be preferred if distortion is to be avoided.
 
The direction cosine matrix (from the rotated Body XYZ coordinates to the original Lab xyz coordinates for a clockwise/lefthand rotation) corresponding to a post-multiply '''Body 3-2-1''' sequence with [[Euler angles]] (ψ, θ, φ) is given by:<ref name=nasa-rotation>{{cite web|last=NASA Mission Planning and Analysis Division|title=Euler Angles, Quaternions, and Transformation Matrices|date=July 1977 |url=https://ntrs.nasa.gov/archivecitations/nasa/casi.ntrs.nasa.gov/19770024290_1977024290.pdf19770024290|publisher=[[NASA]]|accessdate=1224 January 2013}}{{dead link|date=AprilMay 2021}}</ref>
:<math>
\begin{align}
Line 128 ⟶ 143:
[[Image:Eulerangles.svg|right|thumb|150px|Euler angles for Body 3-1-3 Sequence – The xyz (original fixed Lab) system is shown in blue, the XYZ (rotated final Body) system is shown in red. The line of nodes, labelled N and shown in green, is the intermediate Body X-axis around which the second rotation occurs.]]
 
== Euler angles (in 3-2-1 sequence) to quaternion conversion ==
By combining the quaternion representations of the Euler rotations we get for the '''Body 3-2-1''' sequence, where the airplane first does yaw (Body-Z) turn during taxiing onto the runway, then pitches (Body-Y) during take-off, and finally rolls (Body-X) in the air. The resulting orientation of Body 3-2-1 sequence (around the capitalized axis in the illustration of Tait–Bryan angles) is equivalent to that of lab 1-2-3 sequence (around the lower-cased axis), where the airplane is rolled first (lab-x axis), and then nosed up around the horizontal lab-y axis, and finally rotated around the vertical lab-z axis ('''lB''' = '''lab2Body'''):
 
Line 158 ⟶ 173:
};
 
// This is not in game format, it is in mathematical format.
Quaternion ToQuaternion(double yawroll, double pitch, double rollyaw) // yawroll (Zx), pitch (Yy), rollyaw (Xz), angles are in radians
{
// Abbreviations for the various angular functions
 
double cy = cos(yaw * 0.5);
double sy = sin(yaw * 0.5);
double cp = cos(pitch * 0.5);
double sp = sin(pitch * 0.5);
double cr = cos(roll * 0.5);
double sr = sin(roll * 0.5);
double cp = cos(pitch * 0.5);
double sp = sin(pitch * 0.5);
double cy = cos(yaw * 0.5);
double sy = sin(yaw * 0.5);
 
Quaternion q;
Line 178 ⟶ 195:
</syntaxhighlight>
 
== Quaternion to Euler angles (in 3-2-1 sequence) conversion ==
 
A direct formula for the conversion from a quaternion to Euler angles in any of the 12 possible sequences exists.<ref>{{cite journal |last1=Bernardes |first1=Evandro |last2=Viollet |first2=Stéphane |title=Quaternion to Euler angles conversion: A direct, general and computationally efficient method |journal=PLOS ONE |date=10 November 2022 |volume=17 |issue=11 |pages=e0276302 |doi=10.1371/journal.pone.0276302 |pmid=36355707 |pmc=9648712 |bibcode=2022PLoSO..1776302B |language=en |issn=1932-6203|doi-access=free }}</ref> For the rest of this section, the formula for the sequence '''Body 3-2-1''' will be shown.
The Euler angles can be obtained from the quaternions via the relations:<ref>{{cite journal|last1=Blanco|first1=Jose-Luis|title=A tutorial on se (3) transformation parameterizations and on-manifold optimization|journal=University of Malaga, Tech. Rep|date=2010|citeseerx=10.1.1.468.5407}}</ref>
If the quaternion is properly '''normalized''', the Euler angles can be obtained from the quaternions via the relations:
 
:<math>\begin{bmatrix}
Line 186 ⟶ 204:
\end{bmatrix} =
\begin{bmatrix}
\mbox{arctanatan2} \frac {\left(2(q_0q_w q_1q_x + q_2q_y q_3q_z)} {,1 - 2(q_1q_x^2 + q_2q_y^2)}\right) \\
- \pi/2 + 2 \, \mbox{atan2} \left(\sqrt{1 + 2(q_w q_y - q_x q_z)}, \sqrt{1 - 2(q_w q_y - q_x q_z)}\right) \\
\mbox{arcsin} (2(q_0 q_2 - q_3 q_1)) \\
\mbox{arctanatan2} \frac {\left(2(q_0q_w q_3q_z + q_1q_x q_2q_y)} {,1 - 2(q_2q_y^2 + q_3q_z^2)}\right)
\end{bmatrix} </math>
 
Note, however, that the [[arctan]] and [[arcsin]] functions implemented in computer languages only produce results between −π/2 and [[right angle|π/2]], andwhich foris threewhy rotations[[atan2]] betweenis −π/2used andto π/2generate oneall does not obtain allthe possiblecorrect orientations. ToMoreover, generatetypical allimplementations theof orientationsarctan onealso needsmight tohave replacesome thenumerical arctandisadvantages functionsnear inzero computerand codeone. by [[atan2]]:
 
TheSome Eulerimplementations angles can be obtained fromuse the quaternions via theequivalent relationsexpression:<ref>{{cite journal|last1=Blanco|first1=Jose-Luis|title=A tutorial on se (3) transformation parameterizations and on-manifold optimization|journal=University of Malaga, Tech. Rep|date=2010|citeseerx=10.1.1.468.5407}}</ref>
:<math>\begin{bmatrix}
:<math> \theta = \mbox{arcsin} (2(q_0q_w q_2q_y - q_3q_x q_1q_z)) \\</math>
\phi \\ \theta \\ \psi
\end{bmatrix} =
\begin{bmatrix}
\mbox{atan2} (2(q_0 q_1 + q_2 q_3),1 - 2(q_1^2 + q_2^2)) \\
\mbox{asin} (2(q_0 q_2 - q_3 q_1)) \\
\mbox{atan2} (2(q_0 q_3 + q_1 q_2),1 - 2(q_2^2 + q_3^2))
\end{bmatrix} </math>
 
=== Source code ===
Line 217 ⟶ 229:
};
 
// this implementation assumes normalized quaternion
// converts to Euler angles in 3-2-1 sequence
EulerAngles ToEulerAngles(Quaternion q) {
EulerAngles angles;
Line 226 ⟶ 240:
 
// pitch (y-axis rotation)
double sinp = std::sqrt(1 + 2 * (q.w * q.y - q.zx * q.xz));
ifdouble cosp = (std::abssqrt(sinp)1 >=- 12 * (q.w * q.y - q.x * q.z));
angles.pitch = 2 * std::copysignatan2(M_PI / 2sinp, sinpcosp); //- useM_PI 90/ degrees if out of range2;
else
angles.pitch = std::asin(sinp);
 
// yaw (z-axis rotation)
Line 248 ⟶ 260:
== Vector rotation ==
 
Let us define scalar <math>q_0q_w</math> and vector <math>\vec{q}</math> such that quaternion <math>\mathbf{q} = (q_0q_w,\vec{q}) = q_0+iq_1+jq_2+kq_3</math>.
 
Note that the canonical way to rotate a three-dimensional vector <math>\vec{v}</math> by a quaternion <math>q</math> defining an [[Conversion between quaternions and Euler angles#Conversion|Euler rotation]] is via the formula
:<math>\mathbf{pv}^{\,\prime} = \mathbf{qpqqvq}^\ast</math>
where <math>\mathbf{pv} = (0,\vec{v}) = 0+iv_1+jv_2+kv_3</math> is a quaternion containing the embedded vector <math>\vec{v}</math>, <math>\mathbf{q}^\ast=(q_0q_w,-\vec{q})</math> is a [[Quaternion#Conjugation.2C, the norm.2C, and reciprocal|conjugate quaternion]], and <math>\mathbf{pv}^{\,\prime} = (0,\vec{v}^{\,\prime})</math> is the rotated vector <math>\vec{v}^{\,\prime}</math>. In computational implementations this requires two quaternion multiplications. An alternative approach is to apply the pair of relations
:<math>\vec{t} = 2\vec{q} \times \vec{v}</math>
:<math>\vec{v}^{\,\prime} = \vec{v} + q_0q_w \vec{t} + \vec{q} \times \vec{t}</math>
where <math>\times</math> indicates a three-dimensional vector [[cross product]]. This involves fewer multiplications and is therefore computationally faster. Numerical tests indicate this latter approach may be up to 30% <ref>{{cite journal |pmc=4435132|year=2015|last1=Janota|first1=A|title=Improving the Precision and Speed of Euler Angles Computation from Low-Cost Rotation Sensor Data|journal=Sensors|volume=15|issue=3|pages=7016–7039|last2=Šimák|first2=V|last3=Nemec|first3=D|last4=Hrbček|first4=J|doi=10.3390/s150307016|pmid=25806874|bibcode=2015Senso..15.7016J |doi-access=free}}</ref> faster than the original for vector rotation.
 
=== Proof ===
Line 261 ⟶ 273:
:<math>
\begin{align}
\mathbf{q_1q_2p q} & = (r_1p_w,\vec{vp}_1)(r_2q_w,\vec{vq}_2) \\
& = (r_1p_w r_2q_w - \vec{vp}_1 \cdot \vec{vq}_2, r_1p_w \vec{vq}_2 + r_2q_w \vec{vp}_1 +
\vec{vp}_1 \times \vec{vq}_2) \\
\end{align}
</math>
Using this relation one finds for <math>\mathbf{pv} = (0,\vec{v})</math> that
:<math>
\begin{align}
\mathbf{pv q^\ast} & = (0,\vec{v})(q_0q_w,-\vec{q}) \\
& = (\vec{v} \cdot \vec{q}, q_0q_w \vec{v} - \vec{v} \times \vec{q}) \\
\end{align}
</math>
Line 276 ⟶ 288:
:<math>
\begin{align}
\mathbf{q pv q^\ast} & = (q_0q_w,\vec{q})(\vec{v} \cdot \vec{q}, q_0q_w \vec{v} - \vec{v} \times \vec{q}) \\
& = (0, q_0q_w^2 \vec{v} + q_0q_w \vec{q} \times \vec{v} + (\vec{v} \cdot \vec{q}) \vec{q} + q_0q_w \vec{q} \times \vec{v} +
\vec{q}\times(\vec{q}\times\vec{v} )) \\
\end{align}
</math>
where anti-commutivity of cross product and <math>\vec{q}\cdot \vec{v} \times \vec{q} = 0</math> has been applied. By next exploiting the property that <math>\mathbf{q}</math> is a [[Conversion between quaternions and Euler angles#Definition|unit quaternion]] so that <math>q_0q_w^2 = 1 - \vec{q}\cdot\vec{q}</math>, along with the standard vector identity
:<math>
\vec{q}\times(\vec{q}\times\vec{v}) = (\vec{q}\cdot\vec{v})\vec{q} - (\vec{q}\cdot\vec{q})\vec{v}
Line 288 ⟶ 300:
:<math>
\begin{align}
\mathbf{pv}^\prime & = \mathbf{q pv q^\ast} = (0, \vec{v} + 2 q_0q_w \vec{q} \times \vec{v} +
2\vec{q}\times (\vec{q}\times\vec{v} )) \\
\end{align}
Line 294 ⟶ 306:
which upon defining <math>\vec{t} = 2\vec{q} \times \vec{v}</math> can be written in terms of scalar and vector parts as
:<math>
(0, \vec{v}^{\,\prime}) = (0, \vec{v} + q_0q_w \vec{t} + \vec{q} \times \vec{t} ).
</math>