Euler Angles
The Euler Angles are defined by the following immutable structure:
struct EulerAngles{T}
a1::T
a2::T
a3::T
rot_seq::Symbol
end
in which a1
, a2
, and a3
define the angles and the rot_seq
is a symbol that defines the axes. The valid values for rot_seq
are:
:XYX
,:XYZ
,:XZX
,:XZY
,:YXY
,:YXZ
,:YZX
,:YZY
,:ZXY
,:ZXZ
,:ZYX
, andZYZ
.
The constructor for this structure is:
function EulerAngles(a1::T1, a2::T2, a3::T3, rot_seq::Symbol = :ZYX) where {T1,T2,T3}
in which a EulerAngles
with angles a1
, a2
, and a3
[rad] and rotation sequence rot_seq
will be created. Notice that the type of the returned structure will be selected according to the input types T1
, T2
, and T3
. If rot_seq
is omitted, then it defaults to :ZYX
.
julia> EulerAngles(1, 1, 1)
EulerAngles{Int64}: R(Z) : 1 rad ( 57.2958°) R(Y) : 1 rad ( 57.2958°) R(X) : 1 rad ( 57.2958°)
julia> EulerAngles(1, 1, 1.0f0, :XYZ)
EulerAngles{Float32}: R(X) : 1.0 rad ( 57.2958°) R(Y) : 1.0 rad ( 57.2958°) R(Z) : 1.0 rad ( 57.2958°)
julia> EulerAngles(1., 1, 1, :XYX)
EulerAngles{Float64}: R(X) : 1.0 rad ( 57.2958°) R(Y) : 1.0 rad ( 57.2958°) R(X) : 1.0 rad ( 57.2958°)
Operations
Multiplication
The multiplication of two Euler angles is defined here as the composition of the rotations. Let $\Theta_1$ and $\Theta_2$ be two sequences of Euler angles (instances of the structure EulerAngles
). Thus, the operation:
\[\Theta_{2,1} = \Theta_2 \cdot \Theta_1\]
will return a new set of Euler angles $\Theta_{2,1}$ that represents the composed rotation of $\Theta_1$ followed by $\Theta_2$. Notice that $\Theta_{2,1}$ will be represented using the same rotation sequence as $\Theta_2$.
julia> a1 = EulerAngles(1, 0, 0, :ZYX)
EulerAngles{Int64}: R(Z) : 1 rad ( 57.2958°) R(Y) : 0 rad ( 0.0°) R(X) : 0 rad ( 0.0°)
julia> a2 = EulerAngles(0, -1, 0, :YZY)
EulerAngles{Int64}: R(Y) : 0 rad ( 0.0°) R(Z) : -1 rad (-57.2958°) R(Y) : 0 rad ( 0.0°)
julia> a2 * a1
EulerAngles{Float64}: R(Y) : 0.0 rad ( 0.0°) R(Z) : 0.0 rad ( 0.0°) R(Y) : 0.0 rad ( 0.0°)
julia> a1 = EulerAngles(1, 1, 1, :YZY)
EulerAngles{Int64}: R(Y) : 1 rad ( 57.2958°) R(Z) : 1 rad ( 57.2958°) R(Y) : 1 rad ( 57.2958°)
julia> a2 = EulerAngles(0, 0, -1, :YZY)
EulerAngles{Int64}: R(Y) : 0 rad ( 0.0°) R(Z) : 0 rad ( 0.0°) R(Y) : -1 rad (-57.2958°)
julia> a2 * a1
EulerAngles{Float64}: R(Y) : 1.0 rad ( 57.2958°) R(Z) : 1.0 rad ( 57.2958°) R(Y) : 1.31938e-16 rad ( 7.55951e-15°)
julia> a1 = EulerAngles(1.3, 2.2, 1.4, :XYZ)
EulerAngles{Float64}: R(X) : 1.3 rad ( 74.4845°) R(Y) : 2.2 rad ( 126.051°) R(Z) : 1.4 rad ( 80.2141°)
julia> a2 = EulerAngles(-1.4, -2.2, -1.3, :ZYX)
EulerAngles{Float64}: R(Z) : -1.4 rad (-80.2141°) R(Y) : -2.2 rad (-126.051°) R(X) : -1.3 rad (-74.4845°)
julia> a2 * a1
EulerAngles{Float64}: R(Z) : -8.32667e-17 rad (-4.77083e-15°) R(Y) : 3.33067e-16 rad ( 1.90833e-14°) R(X) : -1.11022e-16 rad (-6.36111e-15°)
Inversion
The inv
function applied to Euler angles will return the inverse rotation. If the Euler angles $\Theta$ represent a rotation through the axes $a_1$, $a_2$, and $a_3$ by angles $\alpha_1$, $\alpha_2$, and $\alpha_3$, then $\Theta^{-1}$ is a rotation through the axes $a_3$, $a_2$, and $a_1$ by angles $-\alpha_3$, $-\alpha_2$, and $-\alpha_1$.
julia> a = EulerAngles(1, 2, 3, :ZYX)
EulerAngles{Int64}: R(Z) : 1 rad ( 57.2958°) R(Y) : 2 rad ( 114.592°) R(X) : 3 rad ( 171.887°)
julia> inv(a)
EulerAngles{Int64}: R(X) : -3 rad (-171.887°) R(Y) : -2 rad (-114.592°) R(Z) : -1 rad (-57.2958°)
julia> a = EulerAngles(1.2, 3.3, 4.6, :XYX)
EulerAngles{Float64}: R(X) : 1.2 rad ( 68.7549°) R(Y) : 3.3 rad ( 189.076°) R(X) : 4.6 rad ( 263.561°)
julia> a * inv(a)
EulerAngles{Float64}: R(X) : -1.92593e-34 rad (-1.10348e-32°) R(Y) : 0.0 rad ( 0.0°) R(X) : 0.0 rad ( 0.0°)
All the operations related to Euler angles first convert them to DCM or Quaternions, and then the result is converted back to Euler angles. Hence, the performance will not be good.