Working with an Attitude
Attitude — the orientation of one frame relative to another — is deceptively subtle. A single wrong transpose or a swapped multiplication order silently corrupts a whole navigation or bundle-adjustment pipeline. This page builds engineering intuition for the representations (Euler, axis-angle, Rodrigues, quaternion), the group SO(3) with its exp / log maps, the kinematics, and how you carry a covariance for something that doesn't live in a vector space.
Symbols used on this page are defined in the Nomenclature → attitude & rotations.
Derived from the internal lecture "Working with an Attitude!!" (N. V. Adurthi, a commercial space operator) and its MATLAB visualizations, re-implemented here as interactive JS.
Rotations vs coordinate changes (active vs passive)
Two things get called "rotation" and confusing them is the #1 source of bugs:
- Active rotation $R$ — physically rotates a vector within one fixed frame: $\mathbf{v}' = R\,\mathbf{v}$. Natural for physical motion (a camera boresight swinging in inertial space).
- Passive rotation / coordinate change (DCM) $C$ — the vector stays put; you re-express its coordinates in another frame: $\mathbf{v}_B = C\,\mathbf{v}_A$. Needed to write Newton's laws in the body frame.
They are inverses of each other: $C = R^{-1} = R^{\top}$ (rotations are orthogonal). Pick one convention for all your math and code — most confusion is bookkeeping, not physics.
Intrinsic vs extrinsic composition
When you chain two rotations there are two interpretations, and they give different results:
- Extrinsic (global): every rotation is about the original fixed axes. Sequential rotations left-multiply: $R = R_2\,R_1$.
- Intrinsic (local): each subsequent rotation is about the already-rotated (body) axis. Sequential rotations right-multiply: $R = R_1\,R_2$.
So "rotate about z then about x" is $R_x R_z$ extrinsically but $R_z R_x$ intrinsically — completely different final frames. Computer-graphics tools (Blender, Omniverse) use extrinsic; robot joints often enforce intrinsic. Drag the angles and flip the toggle:
The same idea, on real hardware — a rocket rotating intrinsically vs extrinsically:
Intrinsic (rotations about body axes)
Extrinsic (rotations about global axes)
The rotation group SO(3)
Rotation matrices form the special orthogonal group
$$ SO(3) = \{\, R\in\mathbb{R}^{3\times3} : R^\top R = I,\ \det R = +1 \,\}. $$This is a 3-dimensional curved manifold, not a vector space — you cannot simply add two rotation matrices and get a rotation. That single fact drives everything about attitude estimation.
The Lie algebra & the hat map
The tangent space at the identity is $\mathfrak{so}(3)$, the space of $3\times3$ skew-symmetric matrices. A rotation vector $\boldsymbol{\phi}=\phi\,\hat{\mathbf e}\in\mathbb{R}^3$ maps to a matrix by the hat (cross-product) operator:
$$ [\boldsymbol{\phi}]_\times = \begin{bmatrix} 0 & -\phi_3 & \phi_2\\ \phi_3 & 0 & -\phi_1\\ -\phi_2 & \phi_1 & 0\end{bmatrix}, \qquad [\boldsymbol{\phi}]_\times\,\mathbf{v} = \boldsymbol{\phi}\times\mathbf{v}. $$The exponential map (Rodrigues' formula)
The exponential map takes a rotation vector to a rotation matrix. Because $[\hat{\mathbf e}]_\times^3 = -[\hat{\mathbf e}]_\times$, the matrix series collapses to the closed-form Rodrigues formula:
$$ R = \exp\big([\boldsymbol{\phi}]_\times\big) = I + \sin\phi\,[\hat{\mathbf e}]_\times + (1-\cos\phi)\,[\hat{\mathbf e}]_\times^2, \qquad \phi=\lVert\boldsymbol{\phi}\rVert. $$The logarithm map
Its inverse recovers the axis-angle from a rotation matrix:
$$ \phi = \cos^{-1}\!\left(\frac{\operatorname{tr}(R)-1}{2}\right),\qquad [\hat{\mathbf e}]_\times = \frac{1}{2\sin\phi}\big(R - R^\top\big). $$Why this matters: exp/log let you step off the manifold into the flat tangent space $\mathbb{R}^3$, do ordinary vector calculus (add errors, form a Gaussian, take a Jacobian), then map back. This is the mathematical engine behind the Multiplicative EKF below and behind pose-graph optimization and bundle adjustment in vision-based navigation.
Turn the algebra into a picture: set an axis and an angle, and watch exp produce the rotation matrix that carries the body frame there. Push the angle past 180° to see why log is only unique on $(-\pi,\pi]$ — the same rotation has many rotation-vector preimages, which is exactly why filters keep the error small and reset every step:
Attitude representations
One physical rotation, many coordinates. Each has trade-offs:
Euler angles
Three sequential rotations (e.g. yaw–pitch–roll, $Z$–$Y$–$X$). Minimal (3 numbers) and intuitive for actuators, but they suffer gimbal lock — the kinematics become singular when two axes align (pitch $=\pm90^\circ$). Interpreting a covariance in Euler angles is awkward because the mapping is nonlinear and order-dependent.
$$ R_{ZYX}(\psi,\theta,\varphi) = R_z(\psi)\,R_y(\theta)\,R_x(\varphi). $$Principal rotation (axis-angle)
Euler's theorem: any orientation is a single rotation by angle $\Phi$ about a unit axis $\hat{\mathbf e}$ — the principal rotation vector $\boldsymbol{\phi}=\Phi\hat{\mathbf e}$. This is exactly the log of $R$. Singular kinematics at $\Phi=0$ (axis undefined).
Quaternions
The unit quaternion packs axis-angle without singularities:
$$ \mathbf{q} = \begin{bmatrix} q_0\\ \mathbf{q}_v\end{bmatrix} = \begin{bmatrix} \cos(\Phi/2)\\ \hat{\mathbf e}\,\sin(\Phi/2)\end{bmatrix},\qquad \lVert\mathbf{q}\rVert=1. $$They live on the unit 3-sphere $S^3$ in 4-D, double-cover SO(3) ($\mathbf{q}$ and $-\mathbf{q}$ are the same rotation), and compose by Hamilton multiplication. Rotation of a vector and coordinate change:
$$ \mathbf{v}' = \mathbf{q}\otimes\mathbf{v}\otimes\mathbf{q}^{-1}\ (\text{active}),\qquad \mathbf{v}_B = \mathbf{q}^{-1}\otimes\mathbf{v}_A\otimes\mathbf{q}\ (\text{coordinate change}). $$Singularity-free — the standard choice for the mean attitude state.
Classical & Modified Rodrigues Parameters
Two minimal (3-vector) parametrizations obtained by stereographic-type projection of the quaternion:
$$ \underbrace{\mathbf{g} = \hat{\mathbf e}\,\tan\!\frac{\Phi}{2} = \frac{\mathbf{q}_v}{q_0}}_{\text{CRP (Gibbs vector)}}, \qquad \underbrace{\boldsymbol{\sigma} = \hat{\mathbf e}\,\tan\!\frac{\Phi}{4} = \frac{\mathbf{q}_v}{1+q_0}}_{\text{MRP}}. $$- CRP is singular at $\Phi=180^\circ$ (denominator $q_0\to0$).
- MRP pushes the singularity out to $\Phi=360^\circ$; a "shadow set" switch keeps it bounded.
See all five for the same rotation — and watch CRP diverge as $\Phi\to180^\circ$:
Attitude kinematics
An IMU reads body angular rate $\boldsymbol{\omega}$. The orientation evolves as:
Singularity-free; 9 numbers with 6 constraints.
Singularity-free; 4 numbers with 1 constraint.
Euler-angle kinematics involve a matrix that blows up at the gimbal-lock pitch — another reason to integrate quaternions/DCM and read out Euler angles only for display.
Covariance of an attitude — the Multiplicative EKF
A standard Kalman filter assumes the state lives in a vector space where mean and covariance share one flat plane. Attitude does not. The Multiplicative EKF (MEKF) (Markley, 2003) resolves this by splitting the state into a global mean (a quaternion/DCM, kept on the manifold) and a small local error (a rotation vector in the tangent plane, where the covariance lives):
$$ R = \delta R(\boldsymbol{\delta\theta})\;\bar R,\qquad \boldsymbol{\delta\theta}\sim\mathcal N(\mathbf 0, P),\qquad \delta R \approx I + [\boldsymbol{\delta\theta}]_\times. $$The mean $\bar R$ carries the orientation on SO(3); the $3\times3$ covariance $P$ lives in the tangent plane at $\bar R$. After a measurement update the error mean is nonzero, so a reset step folds it back into $\bar R$ and re-centers the tangent plane — the covariance then lives in a slightly different plane.
Covariance propagation & the "constant in inertial frame" insight
With no noise or bias, propagating only initial-condition uncertainty under a constant body rate
$\boldsymbol{\omega}$ gives the coupled flow (exactly the UQ MATLAB app's covP.m):
Watching $P$ in the body frame, its ellipsoid appears to tumble and change shape — which looks alarming, since with no process noise the uncertainty should be conserved. The resolution: the eigenvalues of $P$ are invariant, and $S = \bar R\,P\,\bar R^\top$ is constant — the covariance is stationary in the inertial frame; only its body-frame coordinates rotate. The same is true for an Euler-angle covariance.
This is the MATLAB visualization, re-implemented live — the 3σ ellipsoid rides the unit sphere at the current Euler axis while its eigenvalues stay put:
The original MATLAB-rendered animation of the same idea:
Representing attitude errors — which frame?
To express a small misalignment $\delta R$ you again choose global or local, and they give different frames (and different Jacobians):
$$ R' = \delta R\;R\quad(\text{global / left}),\qquad R' = R\;\delta R\quad(\text{local / right}). $$This is the applying_misalignment MATLAB app — global vs local application side by side:
Jacobians for optimization
In nonlinear least squares over attitude (calibration, pose-graph, bundle adjustment) you perturb the estimate multiplicatively and differentiate w.r.t. the tangent-space error. The Jacobian of a rotated point $R\,\mathbf p$ w.r.t. a right (local) perturbation is
$$ \frac{\partial (R\,\exp([\boldsymbol{\delta\theta}]_\times)\,\mathbf p)}{\partial \boldsymbol{\delta\theta}} \bigg|_{0} = -R\,[\mathbf p]_\times, $$and it is different for a left perturbation. Getting the side wrong is a classic, hard-to-debug optimization error — the whole reason to fix one convention across math and code.
Related: Extended Kalman Filter · Star Tracker (attitude measurement) · IMU (angular rate) · the same $SE(3)$/$SO(3)$ transforms appear in Perception.
Reference: F. L. Markley, "Attitude Error Representations for Kalman Filtering," J. Guidance, Control & Dynamics, 26(2), 2003.