field guide
Rotating coordinate frames and the transport theorem
Rotating frames and the transport theorem - the NED-frame conventions and derivative rules behind body-to-world rotation in a flight estimator.
The identity that links inertial and body-frame derivatives β
β is called the transport theorem. Itβs a geometrical fact about rotating coordinate systems, not a physical law. It applies to any vector quantity : position, velocity, angular momentum, a magnetic field vector, whatever lives in 3D space and is measured from a spinning platform.
This note traces it from the concrete picture you already know (body-frame velocity β inertial velocity) back to the general principle.
Start with what you already do in code
In your PID controllerβs simulation step, the thrust vector is in body coordinates. To integrate position, you rotate it to the inertial frame using the rotation matrix . In body coordinates the quad has velocity (from the IMU frame). In inertial coordinates the velocity is . The mapping is:
This is a rotation matrix β a linear algebra operation. Itβs the clean, easily-codeable way to do the transform. But thereβs another way to see it that reveals the deeper structure.
A simpler picture: the spinning room
Imagine youβre standing in a room that rotates at constant rate about a vertical axis (a centrifuge or a merry-go-round).
What the rotating-frame observer sees: youβre standing still at position relative to the centre. Your velocity in the rotating frame is .
What an inertial observer (someone outside, watching from above) sees: youβre not standing still β youβre being carried around in a circle at speed tangent to the circle. Your inertial velocity is .
If you walk in the rotating frame at , the inertial observer sees your walking velocity plus the carrying velocity:
This is the transport theorem for . The term is the βcarrying termβ β the velocity you inherit from the frameβs rotation even if you donβt move within it.
Generalising: the theorem for any vector
A vector expressed in a rotating basis :
Differentiate in the inertial frame (product rule):
The first group is the body derivative β how the components change as seen by someone riding in the rotating frame.
The second group is the contribution from the axes themselves spinning. The fundamental property of angular velocity is that it tells you how a rotating frameβs basis vectors move:
Substitute:
Hence:
Thatβs the whole theorem. Memorise the structure:
Rotating-frame derivative = body derivative + omega cross the vector
The two applications you care about
1. Position () β velocity kinematics
| Term | Meaning | In your code |
|---|---|---|
| inertial velocity | after rotation | |
| body-frame velocity | from IMU | |
| carrying velocity from rotation | what handles in one shot |
If the IMU were at position relative to the quadβs centre of rotation (it is), and the quad is rotating (it is), then the IMU sees a velocity contribution from rotation alone β even if the centre isnβt moving. This is why the rotation matrix is applied after computing body-frame motion.
In practice you use the rotation matrix rather than the cross product for the position case, because handles all three axes at once and is easier to code. But conceptually itβs the same .
2. Angular momentum () β Eulerβs equations
| Term | Meaning | Equation | |
|---|---|---|---|
| torque | Newtonβs second law for rotation | ||
| change in spin, body-frame | |||
| gyroscopic cross-coupling |
So:
This is euler-body-rate-cross-coupling. The cross term is the same physical effect as the carrying term in the position case β the angular momentum vector is being βcarried aroundβ by the bodyβs rotation.
Why the cross term feels different for position vs.Β angular momentum
Same mathematical structure, but:
Position case: vanishes when (origin). At the centre of rotation, no carrying velocity. For your quad, the IMU is off-centre, so there is a contribution, but you absorb it into the rotation matrix.
Angular momentum case: does not vanish even at the centre of rotation, because is non-zero whenever the body is spinning. The gyroscopic term is a self-interaction β the bodyβs own angular momentum interacts with its own rotation, producing torques that affect other axes.
This self-interaction is precession. Hold a spinning bicycle wheel by its axle and try to tilt it β the wheel fights you by turning in a perpendicular direction. That resistance is manifesting in your hands as a real torque.
Applied to your quadcopter simulation
Your current PID code likely does:
// Body torques from motor mixing
float tau_x, tau_y, tau_z;
// Angular acceleration (simplified)
float p_dot = tau_x / Ixx;
float q_dot = tau_y / Iyy;
float r_dot = tau_z / Izz;
// Integrate
p += p_dot * dt;
q += q_dot * dt;
r += r_dot * dt;The transport theorem says this is missing the term . For a near-hover quad with small , the missing term is small. For aggressive manoeuvres itβs not. The full integration is:
float p_dot = tau_x / Ixx + (Iyy - Izz) / Ixx * q * r;
float q_dot = tau_y / Iyy + (Izz - Ixx) / Ixx * p * r;
float r_dot = tau_z / Izz + (Ixx - Iyy) / Izz * p * q;Those extra terms are the transport theorem at work on the angular momentum vector. Nothing more.
This C code belongs in the physics model of a flight simulator β one that currently drops these terms, and this note is the reference for adding them when the flight regime demands it.
Summary
The transport theorem is a coordinate system identity, not physics. It says: inertial derivative = body derivative + Ο Γ vector.
The Ο Γ term exists because the body-frame basis vectors are spinning. If (no rotation), the term vanishes.
Same formula, different vectors:
- Applied to β velocity kinematics (you use the rotation matrix)
- Applied to β Eulerβs equations (you usually drop the term)
In your quad: the cross term in Eulerβs equations is the same mechanism as the carrying velocity in the position kinematics β a geometric consequence of measuring rates from a spinning platform.
See also: euler-body-rate-cross-coupling β when you can drop the cross term and when it bites you.