Conversion between quaternions and Euler angles: Difference between revisions

Content deleted Content added
Citation bot (talk | contribs)
Add: doi-access, bibcode, pmc, pmid. Removed proxy/dead URL that duplicated identifier. | Use this bot. Report bugs. | Suggested by Headbomb | Linked from Wikipedia:WikiProject_Academic_Journals/Journals_cited_by_Wikipedia/Sandbox | #UCB_webform_linked 55/230
Link suggestions feature: 3 links added.
 
(23 intermediate revisions by 12 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 "passive" [[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}_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)\cdot0\\
\mathbf{q}_3 = \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]].
Line 62 ⟶ 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 73 ⟶ 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/citations/19770024290|publisher=[[NASA]]|accessdate=24 May 2021}}</ref>
Line 165 ⟶ 173:
};
 
// This is not in game format, it is in mathematical format.
Quaternion ToQuaternion(double roll, double pitch, double yaw) // roll (x), pitch (Yy), yaw (z), angles are in radians
{
// Abbreviations for the various angular functions
Line 195 ⟶ 204:
\end{bmatrix} =
\begin{bmatrix}
\mbox{arctanatan2} \left(\dfrac {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{arctanatan2} \left(\sqrt{\dfrac {1 + 2(q_0q_w q_2q_y - q_1q_x q_3q_z)}, \sqrt{1 - 2(q_0q_w q_2q_y - q_1q_x q_3q_z)}}\right) \\
\mbox{arctanatan2} \left(\dfrac {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>
 
HoweverNote that the [[arctan]] functions implemented in computer languages only produce results between −π/2 and [[right angle|π/2]], which is why [[atan2]] is used to generate all the correct orientations. oneMoreover, needstypical toimplementations replace theof arctan functionsalso inmight computerhave codesome bynumerical disadvantages near zero and one. [[atan2]]:
 
:<math>\begin{bmatrix}
\phi \\ \theta \\ \psi
\end{bmatrix} =
\begin{bmatrix}
\mbox{atan2} \left(2(q_0 q_1 + q_2 q_3),1 - 2(q_1^2 + q_2^2)\right) \\
- \pi/2 + 2 \, \mbox{atan2} \left(\sqrt{1 + 2(q_0 q_2 - q_1 q_3)}, \sqrt{1 - 2(q_0 q_2 - q_1 q_3)}\right) \\
\mbox{atan2} \left(2(q_0 q_3 + q_1 q_2),1 - 2(q_2^2 + q_3^2)\right)
\end{bmatrix} </math>
 
Moreover, typical implementations of arctan also might have some numerical disadvantages near zero and one. Some implementations use the equivalent expression:<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> \theta = \mbox{arcsin} (2(q_0q_w q_2q_y - q_1q_x q_3q_z)) </math>
 
=== Source code ===
Line 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|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, the norm, 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 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 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 [[#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 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 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>