Conversion between quaternions and Euler angles: Difference between revisions
→Definition: scalar->real |
|||
(229 intermediate revisions by more than 100 users not shown) | |||
Line 1: | Line 1: | ||
{{Short description|Mathematical strategy}} |
|||
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". |
|||
{{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== |
==Definition== |
||
There are [[Quaternions_and_spatial_rotation#Alternative_conventions|two representations]] of quaternions. This article uses the more popular Hamilton. |
|||
A unit quaternion can be described as: |
|||
:<math>\mathbf{q} = \begin{bmatrix} q_0 & q_1 & q_2 & q_3 \end{bmatrix}^T</math> |
|||
:<math>|\mathbf{q}|^2 = q_0^2 + q_1^2 + q_2^2 + q_3^2 = 1</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). |
|||
We can associate a quaternion to a rotation around an axis by the following expression |
|||
Defining the [[Quaternion#Conjugation,_the_norm,_and_reciprocal|norm of the quaternion]] as follows: |
|||
:<math>\mathbf{q}_0 = \cos(\alpha/2)</math> |
|||
<math display=block>\lVert q \rVert = \sqrt{\,q_w^2 + q_x^2 + q_y^2 + q_z^2~}</math> |
|||
:<math>\mathbf{q}_2 = \sin(\alpha/2)\cos(\beta_y)</math> |
|||
A ''unit quaternion'' satisfies: |
|||
:<math>\mathbf{q}_3 = \sin(\alpha/2)\cos(\beta_z)</math> |
|||
<math display=block>\lVert q \rVert = 1</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 "[[Unit vector|direction cosines]]" locating the axis of rotation (Euler's Theorem). |
|||
We can associate a [[quaternion]] with a rotation around an axis by the following expression |
|||
:<math>\mathbf{q}_w = \cos(\alpha/2)</math> |
|||
:<math>\mathbf{q}_x = \sin(\alpha/2)\cos(\beta_x)</math> |
|||
:<math>\mathbf{q}_y = \sin(\alpha/2)\cos(\beta_y)</math> |
|||
:<math>\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). |
|||
==Intuition== |
|||
To better understand how "[[direction cosine]]s" work with quaternions: |
|||
:<math>\begin{array}{lcr} \mathbf{q}_w = \cos(\text{rotation angle}/2)\\ |
|||
\mathbf{q}_x = \sin(\text{rotation angle}/2)\cos(\text{angle between axis of rotation and x axis})\\ |
|||
\mathbf{q}_y = \sin(\text{rotation angle}/2)\cos(\text{angle between axis of rotation and y axis})\\ |
|||
\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}_w = \cos(\alpha/2)\\ |
|||
\mathbf{q}_x = \sin(\alpha/2)\cdot1\\ |
|||
\mathbf{q}_y = \sin(\alpha/2)\cdot0\\ |
|||
\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}_w = \cos(\alpha/2)\\ |
|||
\mathbf{q}_x = \sin(\alpha/2)\cdot0\\ |
|||
\mathbf{q}_y = \sin(\alpha/2)\cdot1\\ |
|||
\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}_w = \cos(\alpha/2)\\ |
|||
\mathbf{q}_x = \sin(\alpha/2)\cdot0.707 \ldots\\ |
|||
\mathbf{q}_y = \sin(\alpha/2)\cdot0.707 \ldots\\ |
|||
\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]]): |
|||
* Heading – <math>\psi</math>: rotation about the Z-axis |
|||
* Pitch – <math>\theta</math>: rotation about the new Y-axis |
|||
* Bank – <math>\phi</math>: rotation about the new X-axis |
|||
where the X-axis points forward, Y-axis to the right and Z-axis downward. In the conversion example above the rotation occurs in the order heading, pitch, bank. |
|||
== Rotation matrices == |
== Rotation matrices == |
||
The [[orthogonal matrix]] (post-multiplying a 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_w+iq_x+jq_y+kq_z</math> is given by the [[Quaternions and spatial rotation#Quaternion-derived rotation matrix|inhomogeneous expression]]: |
|||
[[Image:Eulerangles.svg|right|thumb|300px|Euler angles - The xyz (fixed) system is shown in blue, the XYZ (rotated) system is shown in red. The line of nodes, labelled N, is shown in green.]] |
|||
The [[orthogonal matrix]] corresponding to a rotation by the unit quaternion '''q''' is given by{{clarifyme|date=October 2008|reason=Is this matrix supposed to be pre-multiplied by a row vector or post-multiplied by a column vector?}} |
|||
:<math>\begin{bmatrix} |
:<math>R = \begin{bmatrix} |
||
1- 2( |
1- 2(q_y^2 + q_z^2) & 2(q_x q_y - q_w q_z) & 2(q_w q_y + q_x q_z) \\ |
||
2( |
2(q_x q_y + q_w q_z) & 1 - 2(q_x^2 + q_z^2) & 2(q_y q_z - q_w q_x) \\ |
||
2( |
2(q_x q_z - q_w q_y) & 2( q_w q_x + q_y q_z) & 1 - 2(q_x^2 + q_y^2) |
||
\end{bmatrix}</math> |
\end{bmatrix}</math> |
||
or equivalently, by the [[Homogeneous coordinates|homogeneous]] expression: |
|||
The [[orthogonal matrix]] corresponding to a rotation with [[Euler angles]] <math>\phi, \theta, \psi</math>, with '''x-y-z''' convention, is given by{{clarifyme|date=October 2008|reason=Is this matrix supposed to be pre-multiplied by a row vector or post-multiplied by a column vector?}} |
|||
:<math>\begin{bmatrix} |
|||
:<math>R = \begin{bmatrix} |
|||
\cos\theta \cos\psi & -\cos\phi \sin\psi + \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi \sin\theta \cos\psi \\ |
|||
q_w^2 + q_x^2 - q_y^2 - q_z^2 & 2(q_x q_y - q_w q_z) & 2(q_w q_y + q_x q_z) \\ |
|||
\cos\theta \sin\psi & \cos\phi \cos\psi + \sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\ |
|||
2(q_x q_y + q_w q_z) & q_w^2 - q_x^2 + q_y^2 - q_z^2 & 2(q_y q_z - q_w q_x) \\ |
|||
-\sin\theta & \sin\phi \cos\theta & \cos\phi \cos\theta \\ |
|||
2(q_x q_z - q_w q_y) & 2( q_w q_x + q_y q_z) & q_w^2 - q_x^2 - q_y^2 + q_z^2 |
|||
\end{bmatrix}</math> |
\end{bmatrix}</math> |
||
If <math>q_w+iq_x+jq_y+kq_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. |
|||
==== Conversion ==== |
|||
By combing the quaternion representations of the Euler rotations we get |
|||
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> |
|||
:<math>\mathbf{q} = R_z(\psi)R_y(\theta)R_x(\phi) = [\cos (\psi /2) + \mathbf{k}\sin (\psi /2)][\cos (\theta /2) + \mathbf{j}\sin (\theta /2)][\cos (\phi /2) + \mathbf{i}\sin (\phi /2)] |
|||
:<math> |
|||
\begin{align} |
|||
\begin{bmatrix} |
|||
x \\ |
|||
y \\ |
|||
z \\ |
|||
\end{bmatrix} |
|||
& = |
|||
R_z(\psi) R_y(\theta) R_x(\phi) |
|||
\begin{bmatrix} |
|||
X \\ |
|||
Y \\ |
|||
Z \\ |
|||
\end{bmatrix} |
|||
\\ |
|||
& = |
|||
\begin{bmatrix} |
|||
\cos\psi & -\sin\psi & 0 \\ |
|||
\sin\psi & \cos\psi & 0 \\ |
|||
0 & 0 & 1 \\ |
|||
\end{bmatrix} |
|||
\begin{bmatrix} |
|||
\cos\theta & 0 & \sin\theta \\ |
|||
0 & 1 & 0 \\ |
|||
-\sin\theta & 0 & \cos\theta \\ |
|||
\end{bmatrix} |
|||
\begin{bmatrix} |
|||
1 & 0 & 0 \\ |
|||
0 & \cos\phi & -\sin\phi \\ |
|||
0 & \sin\phi & \cos\phi \\ |
|||
\end{bmatrix} |
|||
\begin{bmatrix} |
|||
X \\ |
|||
Y \\ |
|||
Z \\ |
|||
\end{bmatrix} |
|||
\\ |
|||
& = |
|||
\begin{bmatrix} |
|||
\cos\theta \cos\psi & -\cos\phi \sin\psi + \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi \sin\theta \cos\psi \\ |
|||
\cos\theta \sin\psi & \cos\phi \cos\psi + \sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\ |
|||
-\sin\theta & \sin\phi \cos\theta & \cos\phi \cos\theta \\ |
|||
\end{bmatrix} |
|||
\begin{bmatrix} |
|||
X \\ |
|||
Y \\ |
|||
Z \\ |
|||
\end{bmatrix} |
|||
\\ |
|||
\end{align} |
|||
</math> |
</math> |
||
[[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.]] |
|||
:<math> \mathbf{q} = \begin{bmatrix} |
|||
== 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'''): |
|||
:<math> |
|||
\begin{align} |
|||
\mathbf{q_{lB}} & = |
|||
\begin{bmatrix} \cos (\psi /2) \\ 0 \\ 0 \\ \sin (\psi /2) \\ \end{bmatrix} |
|||
\begin{bmatrix} \cos (\theta /2) \\ 0 \\ \sin (\theta /2) \\ 0 \\ \end{bmatrix} |
|||
\begin{bmatrix} \cos (\phi /2) \\ \sin (\phi /2) \\ 0 \\ 0 \\ \end{bmatrix} |
|||
\\ |
|||
& = \begin{bmatrix} |
|||
\cos (\phi /2) \cos (\theta /2) \cos (\psi /2) + \sin (\phi /2) \sin (\theta /2) \sin (\psi /2) \\ |
\cos (\phi /2) \cos (\theta /2) \cos (\psi /2) + \sin (\phi /2) \sin (\theta /2) \sin (\psi /2) \\ |
||
\sin (\phi /2) \cos (\theta /2) \cos (\psi /2) - \cos (\phi /2) \sin (\theta /2) \sin (\psi /2) \\ |
\sin (\phi /2) \cos (\theta /2) \cos (\psi /2) - \cos (\phi /2) \sin (\theta /2) \sin (\psi /2) \\ |
||
\cos (\phi /2) \sin (\theta /2) \cos (\psi /2) + \sin (\phi /2) \cos (\theta /2) \sin (\psi /2) \\ |
\cos (\phi /2) \sin (\theta /2) \cos (\psi /2) + \sin (\phi /2) \cos (\theta /2) \sin (\psi /2) \\ |
||
\cos (\phi /2) \cos (\theta /2) \sin (\psi /2) - \sin (\phi /2) \sin (\theta /2) \cos (\psi /2) \\ |
\cos (\phi /2) \cos (\theta /2) \sin (\psi /2) - \sin (\phi /2) \sin (\theta /2) \cos (\psi /2) \\ |
||
\end{bmatrix} |
\end{bmatrix} \\ |
||
\end{align} |
|||
</math> |
|||
Other rotation sequences use different conventions.<ref name=nasa-rotation /> |
|||
For Euler angles we get: |
|||
=== Source code === |
|||
Below code in C++ illustrates above conversion: |
|||
<syntaxhighlight lang="cpp"> |
|||
struct Quaternion |
|||
{ |
|||
double w, x, y, z; |
|||
}; |
|||
// This is not in game format, it is in mathematical format. |
|||
Quaternion ToQuaternion(double roll, double pitch, double yaw) // roll (x), pitch (y), yaw (z), angles are in radians |
|||
{ |
|||
// Abbreviations for the various angular functions |
|||
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; |
|||
q.w = cr * cp * cy + sr * sp * sy; |
|||
q.x = sr * cp * cy - cr * sp * sy; |
|||
q.y = cr * sp * cy + sr * cp * sy; |
|||
q.z = cr * cp * sy - sr * sp * cy; |
|||
return q; |
|||
} |
|||
</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. |
|||
If the quaternion is properly '''normalized''', the Euler angles can be obtained from the quaternions via the relations: |
|||
:<math>\begin{bmatrix} |
:<math>\begin{bmatrix} |
||
Line 49: | Line 204: | ||
\end{bmatrix} = |
\end{bmatrix} = |
||
\begin{bmatrix} |
\begin{bmatrix} |
||
\mbox{ |
\mbox{atan2} \left(2(q_w q_x + q_y q_z),1 - 2(q_x^2 + q_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{ |
\mbox{atan2} \left(2(q_w q_z + q_x q_y),1 - 2(q_y^2 + q_z^2)\right) |
||
\end{bmatrix} </math> |
\end{bmatrix} </math> |
||
Note 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. Moreover, typical implementations of arctan also might have some numerical disadvantages near zero and one. |
|||
==Relationship with Tait-Bryan angles== |
|||
[[Image:Flight dynamics with text.png|right|thumb]] |
|||
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> |
|||
Similarly for Euler angles, we use the [[Tait-Bryan angles]] (in terms of [[flight dynamics]]): |
|||
:<math> \theta = \mbox{arcsin} (2(q_w q_y - q_x q_z)) </math> |
|||
* Roll - <math>\phi</math>: rotation about the X-axis |
|||
* Pitch - <math>\theta</math>: rotation about the Y-axis |
|||
=== Source code === |
|||
* Yaw - <math>\psi</math>: rotation about the Z-axis |
|||
The following C++ program illustrates conversion above: |
|||
where the X-axis points forward, Y-axis to the right and Z-axis downward and in the example to follow the rotation occurs in the order yaw, pitch, roll (about body-fixed axes). |
|||
Nevertheless, it is not easy to find a matrix expression with Tait-Bryan angles because its final expression depends on how the rotations are applied. |
|||
<syntaxhighlight lang="cpp"> |
|||
#define _USE_MATH_DEFINES |
|||
#include <cmath> |
|||
struct Quaternion { |
|||
double w, x, y, z; |
|||
}; |
|||
struct EulerAngles { |
|||
double roll, pitch, yaw; |
|||
}; |
|||
// this implementation assumes normalized quaternion |
|||
// converts to Euler angles in 3-2-1 sequence |
|||
EulerAngles ToEulerAngles(Quaternion q) { |
|||
EulerAngles angles; |
|||
// roll (x-axis rotation) |
|||
double sinr_cosp = 2 * (q.w * q.x + q.y * q.z); |
|||
double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y); |
|||
angles.roll = std::atan2(sinr_cosp, cosr_cosp); |
|||
// pitch (y-axis rotation) |
|||
double sinp = std::sqrt(1 + 2 * (q.w * q.y - q.x * q.z)); |
|||
double cosp = std::sqrt(1 - 2 * (q.w * q.y - q.x * q.z)); |
|||
angles.pitch = 2 * std::atan2(sinp, cosp) - M_PI / 2; |
|||
// yaw (z-axis rotation) |
|||
double siny_cosp = 2 * (q.w * q.z + q.x * q.y); |
|||
double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z); |
|||
angles.yaw = std::atan2(siny_cosp, cosy_cosp); |
|||
return angles; |
|||
} |
|||
</syntaxhighlight> |
|||
== Singularities == |
== Singularities == |
||
One must be aware of singularities in the Euler angle parametrization when the pitch approaches |
One must be aware of singularities in the Euler angle parametrization when the pitch approaches ±90° (north/south pole). These cases must be handled specially. The common name for this situation is [[gimbal lock]]. |
||
Code to handle the singularities is derived on this site: [http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ www.euclideanspace.com] |
Code to handle the singularities is derived on this site: [http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ www.euclideanspace.com] |
||
== Vector rotation == |
|||
Let us define scalar <math>q_w</math> and vector <math>\vec{q}</math> such that quaternion <math>\mathbf{q} = (q_w,\vec{q})</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{v}^{\,\prime} = \mathbf{qvq}^\ast</math> |
|||
where <math>\mathbf{v} = (0,\vec{v})</math> is a quaternion containing the embedded vector <math>\vec{v}</math>, <math>\mathbf{q}^\ast=(q_w,-\vec{q})</math> is a [[Quaternion#Conjugation, the norm, and reciprocal|conjugate quaternion]], and <math>\mathbf{v}^{\,\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_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 === |
|||
The general rule for quaternion multiplication involving [[Quaternion#Scalar and vector parts|scalar and vector parts]] is given by |
|||
:<math> |
|||
\begin{align} |
|||
\mathbf{p q} & = (p_w,\vec{p})(q_w,\vec{q}) \\ |
|||
& = (p_w q_w - \vec{p} \cdot \vec{q}, p_w \vec{q} + q_w \vec{p} + |
|||
\vec{p} \times \vec{q}) \\ |
|||
\end{align} |
|||
</math> |
|||
Using this relation one finds for <math>\mathbf{v} = (0,\vec{v})</math> that |
|||
:<math> |
|||
\begin{align} |
|||
\mathbf{v q^\ast} & = (0,\vec{v})(q_w,-\vec{q}) \\ |
|||
& = (\vec{v} \cdot \vec{q}, q_w \vec{v} - \vec{v} \times \vec{q}) \\ |
|||
\end{align} |
|||
</math> |
|||
and upon substitution for the triple product |
|||
:<math> |
|||
\begin{align} |
|||
\mathbf{q v q^\ast} & = (q_w,\vec{q})(\vec{v} \cdot \vec{q}, q_w \vec{v} - \vec{v} \times \vec{q}) \\ |
|||
& = (0, q_w^2 \vec{v} + q_w \vec{q} \times \vec{v} + (\vec{v} \cdot \vec{q}) \vec{q} + q_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_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} |
|||
</math> |
|||
one obtains |
|||
:<math> |
|||
\begin{align} |
|||
\mathbf{v}^\prime & = \mathbf{q v q^\ast} = (0, \vec{v} + 2 q_w \vec{q} \times \vec{v} + |
|||
2\vec{q}\times (\vec{q}\times\vec{v} )) \\ |
|||
\end{align} |
|||
</math> |
|||
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_w \vec{t} + \vec{q} \times \vec{t} ). |
|||
</math> |
|||
==See also== |
==See also== |
||
Line 74: | Line 315: | ||
*[[Euler Angles]] |
*[[Euler Angles]] |
||
*[[Rotation matrix]] |
*[[Rotation matrix]] |
||
*[[Rotation formalisms in three dimensions]] |
|||
== References == |
|||
{{Reflist}} |
|||
== External links == |
|||
* [http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q60 Q60. How do I convert Euler rotation angles to a quaternion?] and related questions at The Matrix and Quaternions FAQ |
|||
[[Category: |
[[Category:Rotation in three dimensions]] |
||
[[Category:Euclidean symmetries]] |
[[Category:Euclidean symmetries]] |
||
[[Category:3D computer graphics]] |
[[Category:3D computer graphics]] |
||
[[Category:Quaternions]] |
Latest revision as of 19:39, 13 November 2024
This article may need to be rewritten to comply with Wikipedia's quality standards. (January 2024) |
Spatial rotations in three dimensions can be parametrized using both Euler angles and unit quaternions. This article explains how to convert between the two representations. Actually this simple use of "quaternions" was first presented by Euler some seventy years earlier than Hamilton to solve the problem of magic squares. For this reason the dynamics community commonly refers to quaternions in this application as "Euler parameters".
Definition
[edit]There are two representations of quaternions. This article uses the more popular Hamilton.
A quaternion has 4 real values: qw (the real part or the scalar part) and qx qy qz (the imaginary part).
Defining the norm of the quaternion as follows:
A unit quaternion satisfies:
We can associate a quaternion with a rotation around an axis by the following expression
where α is a simple rotation angle (the value in radians of the angle of rotation) and cos(βx), cos(βy) and cos(βz) are the "direction cosines" of the angles between the three coordinate axes and the axis of rotation. (Euler's Rotation Theorem).
Intuition
[edit]To better understand how "direction cosines" work with quaternions:
If the axis of rotation is the x-axis:
If the axis of rotation is the y-axis:
If the axis of rotation is the z-axis:
If the axis of rotation is a vector located 45° (π/4 radians) between the x and y axes:
Therefore, the x and y axes "share" influence over the new axis of rotation.
Tait–Bryan angles
[edit]Similarly for Euler angles, we use the Tait Bryan angles (in terms of flight dynamics):
- Heading – : rotation about the Z-axis
- Pitch – : rotation about the new Y-axis
- Bank – : rotation about the new X-axis
where the X-axis points forward, Y-axis to the right and Z-axis downward. In the conversion example above the rotation occurs in the order heading, pitch, bank.
Rotation matrices
[edit]The orthogonal matrix (post-multiplying a column vector) corresponding to a clockwise/left-handed (looking along positive axis to origin) rotation by the unit quaternion is given by the inhomogeneous expression:
or equivalently, by the homogeneous expression:
If 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:[1]
Euler angles (in 3-2-1 sequence) to quaternion conversion
[edit]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):
Other rotation sequences use different conventions.[1]
Source code
[edit]Below code in C++ illustrates above conversion:
struct Quaternion
{
double w, x, y, z;
};
// This is not in game format, it is in mathematical format.
Quaternion ToQuaternion(double roll, double pitch, double yaw) // roll (x), pitch (y), yaw (z), angles are in radians
{
// Abbreviations for the various angular functions
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;
q.w = cr * cp * cy + sr * sp * sy;
q.x = sr * cp * cy - cr * sp * sy;
q.y = cr * sp * cy + sr * cp * sy;
q.z = cr * cp * sy - sr * sp * cy;
return q;
}
Quaternion to Euler angles (in 3-2-1 sequence) conversion
[edit]A direct formula for the conversion from a quaternion to Euler angles in any of the 12 possible sequences exists.[2] For the rest of this section, the formula for the sequence Body 3-2-1 will be shown. If the quaternion is properly normalized, the Euler angles can be obtained from the quaternions via the relations:
Note that the arctan functions implemented in computer languages only produce results between −π/2 and π/2, which is why atan2 is used to generate all the correct orientations. Moreover, typical implementations of arctan also might have some numerical disadvantages near zero and one.
Some implementations use the equivalent expression:[3]
Source code
[edit]The following C++ program illustrates conversion above:
#define _USE_MATH_DEFINES
#include <cmath>
struct Quaternion {
double w, x, y, z;
};
struct EulerAngles {
double roll, pitch, yaw;
};
// this implementation assumes normalized quaternion
// converts to Euler angles in 3-2-1 sequence
EulerAngles ToEulerAngles(Quaternion q) {
EulerAngles angles;
// roll (x-axis rotation)
double sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
angles.roll = std::atan2(sinr_cosp, cosr_cosp);
// pitch (y-axis rotation)
double sinp = std::sqrt(1 + 2 * (q.w * q.y - q.x * q.z));
double cosp = std::sqrt(1 - 2 * (q.w * q.y - q.x * q.z));
angles.pitch = 2 * std::atan2(sinp, cosp) - M_PI / 2;
// yaw (z-axis rotation)
double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
angles.yaw = std::atan2(siny_cosp, cosy_cosp);
return angles;
}
Singularities
[edit]One must be aware of singularities in the Euler angle parametrization when the pitch approaches ±90° (north/south pole). These cases must be handled specially. The common name for this situation is gimbal lock.
Code to handle the singularities is derived on this site: www.euclideanspace.com
Vector rotation
[edit]Let us define scalar and vector such that quaternion .
Note that the canonical way to rotate a three-dimensional vector by a quaternion defining an Euler rotation is via the formula
where is a quaternion containing the embedded vector , is a conjugate quaternion, and is the rotated vector . In computational implementations this requires two quaternion multiplications. An alternative approach is to apply the pair of relations
where 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% [4] faster than the original for vector rotation.
Proof
[edit]The general rule for quaternion multiplication involving scalar and vector parts is given by
Using this relation one finds for that
and upon substitution for the triple product
where anti-commutivity of cross product and has been applied. By next exploiting the property that is a unit quaternion so that , along with the standard vector identity
one obtains
which upon defining can be written in terms of scalar and vector parts as
See also
[edit]- Rotation operator (vector space)
- Quaternions and spatial rotation
- Euler Angles
- Rotation matrix
- Rotation formalisms in three dimensions
References
[edit]- ^ a b NASA Mission Planning and Analysis Division (July 1977). "Euler Angles, Quaternions, and Transformation Matrices". NASA. Retrieved 24 May 2021.
- ^ Bernardes, Evandro; Viollet, Stéphane (10 November 2022). "Quaternion to Euler angles conversion: A direct, general and computationally efficient method". PLOS ONE. 17 (11): e0276302. Bibcode:2022PLoSO..1776302B. doi:10.1371/journal.pone.0276302. ISSN 1932-6203. PMC 9648712. PMID 36355707.
- ^ Blanco, Jose-Luis (2010). "A tutorial on se (3) transformation parameterizations and on-manifold optimization". University of Malaga, Tech. Rep. CiteSeerX 10.1.1.468.5407.
- ^ Janota, A; Šimák, V; Nemec, D; Hrbček, J (2015). "Improving the Precision and Speed of Euler Angles Computation from Low-Cost Rotation Sensor Data". Sensors. 15 (3): 7016–7039. Bibcode:2015Senso..15.7016J. doi:10.3390/s150307016. PMC 4435132. PMID 25806874.
External links
[edit]- Q60. How do I convert Euler rotation angles to a quaternion? and related questions at The Matrix and Quaternions FAQ