Euler Angles
Euler angles parameterize a rotation as three successive elemental rotations about coordinate axes. Each elemental rotation is a special case of Rodrigues’ Formula with equal to a standard basis vector.
For the Z-X-Z convention (proper Euler angles), a rotation is decomposed as:
For the Z-Y-X convention (Tait-Bryan / yaw-pitch-roll), used in aerospace:
where the elemental rotation matrices are:
There are 12 valid conventions: 6 proper Euler (repeat one axis: XYX, XZX, YXY, YZY, ZXZ, ZYZ) and 6 Tait-Bryan (all distinct axes: XYZ, XZY, YXZ, YZX, ZXY, ZYX). All suffer from gimbal lock — a singularity where two axes align and one degree of freedom is lost.
Intuition
Euler angles decompose one complicated rotation into three simple ones that a human (or a gimbal mechanism) can execute sequentially. Each elemental rotation moves within a single coordinate plane — the complexity is in how those planes chain together.
Intrinsic vs. extrinsic. The same three angles can be interpreted two ways:
| Convention | Reading order | Frame interpretation |
|---|---|---|
| Intrinsic (body-frame) | Multiply left to right: | Each rotation is about the current (body) frame axis |
| Extrinsic (fixed-frame) | Multiply right to left: same product | Each rotation is about the fixed (spatial) frame axis |
A Z-X-Z intrinsic rotation is algebraically identical to a Z-X-Z extrinsic rotation with the angles applied in reverse order. This follows from associativity of matrix multiplication — the algebra doesn’t care which interpretation you prefer.
Why gimbal lock happens. Each Euler angle controls one axis. When the middle rotation aligns two axes (e.g., pitch hits in yaw-pitch-roll), the first and third rotations produce the same physical effect. Two parameters now control one DOF, and one DOF becomes uncontrollable. The mapping from angles to drops rank from 3 to 2.
This is topological, not a convention problem: no 3-parameter representation of can be singularity-free everywhere, because and you cannot smoothly parameterize it with .
Properties
Gimbal lock singularities by convention
| Convention | Singularity condition | What aligns |
|---|---|---|
| Z-X-Z (proper) | or | First and third -axes coincide |
| Z-Y-X (yaw-pitch-roll) | Yaw and roll axes coincide |
At the singularity, (or ) can take any value as long as their sum is fixed — infinitely many angle triples map to the same rotation.
Angle extraction: Z-Y-X (yaw-pitch-roll)
Given , solve for using atan2 for quadrant-correctness:
Valid when (i.e. ). At the singularity, one can only determine or , and by convention one angle is set to zero.
Representation comparison
| Property | Euler angles | Exponential coords | Quaternions | Rotation matrix |
|---|---|---|---|---|
| Parameters | 3 | 3 () | 4 (unit) | 9 (6 constraints) |
| Singularity? | Yes (gimbal lock) | Yes () | No | No |
| Composition | Painful (recompute) | Not additive in general | Hamilton product | Matrix multiply |
| Interpolation | Poor (artifacts near lock) | Okay (via SLERP in ball) | SLERP (optimal) | Wasteful |
| Human readability | Excellent | Moderate | Poor | Poor |
Connection to manipulator singularities
Gimbal lock previews a broader phenomenon: kinematic singularities in robot arms. In both cases, a parameter-space-to-configuration-space map loses rank, a Jacobian becomes singular, and the system loses controllability in some direction. The mathematical structure is identical — a rank-deficient derivative of a smooth map. This is covered further in 5.3. Singularities and Manipulability.
Examples
Example 1: Z-Y-X extraction from
Extract: . Then , .
Result: . A pure yaw of 90° — correct.
Example 2: Gimbal lock in yaw-pitch-roll
Set (nose straight up):
Only the difference appears — the system has collapsed from 3 DOF to 2. Physically, when pitch is , yawing the aircraft produces the same motion as rolling it. This is gimbal lock.
Implementation
import numpy as np
def euler_zyx_to_matrix(psi, theta, phi):
"""Yaw-pitch-roll (Z-Y-X intrinsic) to rotation matrix."""
Rz = rodrigues(np.array([0,0,1]), psi)
Ry = rodrigues(np.array([0,1,0]), theta)
Rx = rodrigues(np.array([1,0,0]), phi)
return Rz @ Ry @ Rx
def matrix_to_euler_zyx(R):
"""Rotation matrix to yaw-pitch-roll (Z-Y-X). Assumes cos(theta) != 0."""
theta = -np.arcsin(np.clip(R[2,0], -1, 1))
psi = np.arctan2(R[1,0], R[0,0])
phi = np.arctan2(R[2,1], R[2,2])
return psi, theta, phiNote rodrigues() is defined in Rodrigues’ Formula. For production code, prefer scipy.spatial.transform.Rotation which handles all 12 conventions and singularity edge cases.