field guide
Roll and pitch from accelerometer
Deriving roll and pitch from the accelerometer out of the rotation matrix, so the formulas - and their signs - are never guesswork.
The formulas roll = atan2(ay, az) and pitch = atan2(-ax, sqrt(ay²+az²)) look like they came out of nowhere. They didn’t — they fall out of a rotation matrix. Deriving them once means you’ll never write the wrong sign.
The setup
When the chip is at rest, the only force on it is gravity. The accelerometer measures the support force (proper acceleration), equal and opposite to gravity. So if gravity in the world frame is (pointing down), the accelerometer reads in the world frame — pointing up.
The chip doesn’t measure in the world frame. It measures in its own frame. When the chip is rotated, the question is: what does the world’s “up” vector look like expressed in the chip’s coordinate system?
That’s a rotation problem. Write the rotation that takes world coordinates to chip coordinates, apply it to , and the result is what the accelerometer reads on its three axes.
Roll only
Roll the chip by around its X-axis. The rotation matrix that takes world → chip is the inverse of the chip→world rotation — i.e., a rotation by around X:
Apply to the world-frame gravity-up vector :
So for pure roll:
Therefore , and .
Pitch only
Pitch the chip by around its Y-axis.
Apply to :
So for pure pitch:
And , so .
This is almost the full formula but only works when roll is zero. For the combined case, we need both rotations.
Roll AND pitch
Apply the rotations in sequence: first roll, then pitch. The combined rotation world → chip is .
Multiplying and applying to :
Now the formulas. For roll:
The cancels — pitch doesn’t enter the roll formula. So works regardless of pitch.
For pitch, the comes from collapsing the roll terms:
Taking the square root (assuming , true for any sensible drone pitch within ):
Then:
And:
The is the magnitude of gravity’s projection onto the chip’s YZ plane. By construction this is regardless of roll, so pitch becomes independent of roll — exactly like roll is independent of pitch.
Why the matters
If you used the pitch-only formula when the chip is also rolled, the denominator would be instead of — the roll angle would corrupt the pitch estimate. The removes the roll dependence.
What it doesn’t give you: yaw
Gravity is along Z. Rotation around Z (yaw) leaves the gravity vector unchanged in the chip’s frame — it’s invariant under yaw. No amount of trig with can recover yaw. That’s why gyro yaw drifts without a magnetometer.
Connection to the complementary filter
These formulas provide the absolute reference for roll and pitch that the complementary filter needs. See complementary-filter for how they’re blended with the gyro integration:
roll_accel = atan2(ay, az)
pitch_accel = atan2(-ax, sqrt(ay*ay + az*az))
The filter feeds the gyro at high frequencies and these accel-derived angles at low frequencies.
Coordinate sign check
These formulas assume NED sensor mount: +x forward, +y right, +z down. If the sensor is rotated relative to the vehicle frame, adjust the sign in the atan2 calls — not in the control code.