A depth camera's IMU is a dependable heading sensor until you bolt it down: in hand it reads yaw, roll and pitch sensibly, and on the robot the yaw is wrong by a constant nobody expected. The cause is almost always one fixed rotation between the camera's own axes and the robot's axes, and the fix is to apply that rotation once, in code. Here you get the sign convention, the quarter-turn correction table, a measured calibration for mounts that are not square, a drift test that separates bias from geometry, and a five-minute acceptance ladder for the shop floor. It is written for anyone putting a depth camera with a built-in IMU onto a mobile robot or an arm, before or after the first bad reading.
Why does yaw read correctly in hand but wrong on the robot?
Because the IMU reports orientation in the camera's own axes, and once it is bolted down those axes point wherever the mount aims them: every reading is right for the camera and wrong for the robot by one constant rotation.
Hand-held, you keep the sensor level and facing roughly the way you face, so camera axes and expectations coincide. On the deck, the printed triplet is still the robot's attitude, expressed in a frame rotated by the mount angle: the numbers respond correctly to every turn, they are just written in the wrong frame. Turning the robot 90°, 180° or a full circle cannot repair a frame error; only a rotation applied to the data can. The frame vocabulary behind this is set out in depth camera orientation relative to a fixed frame.
Rank the causes most likely first and test in this order:
- Mount rotation between camera frame and robot frame. The dominant cause by far. Command a 90° clockwise turn: a reading that changes by exactly 90° but sits offset by a constant is this fault.
- Sign-convention mismatch. Many libraries report counter-clockwise positive; robot headings often run clockwise-positive. Read the sign of the change on a clockwise 90° turn.
- Yaw integrated from gyro rate with no heading reference. It creeps even at standstill. Park for two minutes and watch the number.
- Compass heading in a distorted magnetic field. Steel chassis, drive motors and cable trays bend magnetic yaw. Translate the robot one metre: absolute yaw that jumps a degree or more marks a bad field.
- Flex in the deck or bracket. The rare one, and the only case where mounting position matters at all. Re-measure the mount offset after a hard drive; a shift means stiffness, not placement.
Does moving the camera closer to the robot's rotation centre fix yaw?
No — orientation is a property of the whole rigid body, so a stiffly mounted camera reads the same attitude anywhere on the deck, the yaw error is the mount rotation rather than the lever arm, and distance matters only if the deck or bracket flexes while turning.
Every point of a rigid body shares one angular velocity. A camera 0.4 m ahead of the pivot sweeps an arc of radius 0.4 m, yet its orientation changes exactly as much per turn as a sensor bolted at the pivot itself. Moving the camera inward trades field of view for nothing: the offset is geometric, and the geometry did not change.
Distance does enter when the platform is not rigid. Skid-steer decks twist as the wheels fight each other, an unsupported bracket resonates at every start and stop, and a sensor on a long overhang rides that flex more than one near the centre. If the offset re-measured after a full-speed drive differs from the static value by more than about a degree, stiffen the bracket. Do not move the camera for the IMU's sake: the field of view chose its place.
Which rotation do I apply for a 90° camera mount?
For a mount that is a whole number of quarter-turns about the vertical axis, corrected yaw equals raw yaw minus φ: a camera facing left of the nose carries φ = +90°, facing right φ = -90°, backwards φ = 180°, with roll and pitch unchanged.
φ is the mount yaw: the angle of the camera's forward axis measured from the robot's nose, positive counter-clockwise viewed from above. The IMU sees robot yaw plus φ, so subtracting φ once recovers the robot's heading, with wrap handled so that a reading of -170° under φ = 180° lands at +10°, not -350°.
| Camera's forward axis relative to the robot's nose | φ | Corrected yaw | Roll and pitch |
|---|---|---|---|
| Forward, level | 0° | unchanged | unchanged |
| 90° left (counter-clockwise from above) | +90° | raw yaw - 90° | unchanged |
| 90° right (clockwise from above) | -90° | raw yaw + 90° | unchanged |
| Backwards, level | 180° | raw yaw - 180° | unchanged |
| Upside down | not a yaw offset | matrix method, below | signs flip |
A pure yaw mount leaves roll and pitch untouched, which is why the table needs no roll correction. Upside down, nothing in the table applies: roll and pitch signs flip, and a single yaw subtraction no longer describes the mount.
How do I correct a mount that is not square to the robot?
Measure the offset once and subtract it: square the robot's base frame to a straight wall or tape line, read the raw yaw there, and that reading is the offset φ for every later sample. The offset is only as good as your square-up.
- Square the base frame to a reference: a taped line, a wall edge, a machine bed. A 3 m line held straight to about 1 cm squares the nose to roughly 0.2°, because 0.01 m ÷ 3 m ≈ 0.0033 rad ≈ 0.2°.
- Park with drives disabled and read the raw yaw. That number is φ, wrapped into the -180° to +180° range.
- Subtract φ from every later reading and wrap the result, in exactly one code path.
- Log φ with a dated photo of the mount, and re-measure after any bracket change, remount or collision.
A tilted mount breaks the one-angle shortcut, because pitch couples into yaw as the tilt grows: compose the rotations instead, R_robot = R_mount × R_imu, then extract the Euler angles in the order your controller expects. Before trusting any table or constant, confirm which way the IMU's own axes point: the IMU optical frame check shows the two-rotation test, and camera tilt from IMU data as Euler angles covers the reading side.
Euler extraction is order-sensitive: the same rotation matrix produces different roll-pitch-yaw numbers under a ZYX sequence than under another, so match the robot's convention. The ZYX roll-pitch-yaw rotation convention explained page walks the ordering. As pitch approaches ±90°, yaw degenerates in any Euler set; the frame-offset fix for Euler gimbal lock shows the standard workaround, and the cheaper answer is to keep mount and operating pitch away from vertical.
Why does yaw still drift after the offset is right?
Because gravity pins roll and pitch but nothing in the accelerometer pins yaw: a fused orientation that is perfect in pitch and roll still integrates gyro rate for heading, and residual gyro bias creeps yaw slowly, so a correct offset does not stop the walk.
The accelerometer's only absolute reference is the gravity vector, and it points down: it pins roll and pitch completely and tells the fusion nothing about heading, because spinning about the vertical leaves gravity unchanged in the sensor frame. Yaw therefore comes from gyro integration alone. Raw-rate integration on a consumer MEMS gyro typically creeps a fraction of a degree to a couple of degrees per minute at standstill; fusion trims that, never to zero.
Two tests separate drift from geometry. A wrong heading that survives a full 360° turn and lands back where it started is offset error — return to the calibration line. A heading that creeps while parked is gyro bias. The fixes, in order of payoff:
- Re-zero at standstill. Detect the parked state, gyro magnitude a fraction of a degree per second and accelerometer variance low, and reset the yaw bias there. For a stop-and-go robot this removes most of the creep.
- Bound yaw with odometry. Wheel odometry drifts differently; disagreement beyond a few degrees over a run flags the source that is lying.
- Magnetometer only after a field test. Compass yaw is absolute, which tempts everyone. Indoor steel and high-current cables bend it by several degrees, tens within a metre of large steel, so calibrate in place, mounted. If absolute yaw jumps while the robot translates one metre, that patch of floor is unusable for compass heading: stay with gyro-relative yaw plus the fixed offset.
How do I check the fix before the robot runs a real job?
Run a quarter-turn ladder: rotate the robot 90°, 180°, 270° and 360° clockwise, then 90° counter-clockwise, and require corrected yaw to track the commanded angle within 2° per step and to land back at start. A sign error shows up instantly as +90° where you expect -90°.
| Commanded turn | True robot yaw | Corrected yaw must read |
|---|---|---|
| 90° clockwise | -90° | -90° ± 2° |
| 180° clockwise | -180° | -180° ± 2° |
| 270° clockwise | +90° after wrap | +90° ± 2° |
| 360° clockwise | 0° | 0° ± 2° |
| 90° counter-clockwise | +90° | +90° ± 2° |
The 2° gate has one justification: consumer-grade IMUs resolve a rigid quarter-turn to about a degree once the offset is removed, so anything larger is a fault, not noise. Read the failures like this:
- The same constant error at every step: φ is wrong or a wrap is missing.
- Signs mirrored: convention flip; change the sign where you subtract φ, nowhere else.
- Correct at first, then growing: gyro drift entering the test; shorten the ladder or re-zero between steps.
- Jitter beyond a degree: loose bracket or vibration; torque the fasteners and re-measure φ.
Should I remap axes in code or move the camera?
Never move the camera to please the IMU: the field of view dictates placement, and a rigid mount at any angle is corrected by one rotation applied in exactly one place, with corrected angles read everywhere else.
Placement serves the lens; the IMU rides along and gets corrected in software. One fix to refuse is the scale factor: multiplying yaw by 0.9 to shave a supposed 10% error compresses a full 360° turn into 324°, which the ladder's return-to-start step fails immediately. A rotated frame needs a rotation, never a gain.
Give the offset one owner: a configuration constant applied where the IMU reading enters your code, or a static transform in a URDF-style tree, which is exactly where a camera hung upside down belongs too — vertically mounted depth camera: put the rotation in the URDF joint shows that pattern. No local patches in the control loop, the logger and the viewer.
The same R_mount is the camera-to-robot extrinsic you need anyway: once it exists, detections, points and heading share one transform, and the axis naming stops being a guess. Camera coordinate frame vs point cloud x y z covers the naming, and convert a camera point between robot workobjects covers the hand-off to the controller.
Prevention, in one list:
- Log φ with a dated mount photo at every calibration.
- One code path owns the offset, and the ladder script reads through that same path.
- Re-run the quarter-turn ladder after remounts, bracket swaps, collisions and any update that touches the IMU stream.
- Keep the bracket stiff: an offset that moves more than a degree after a full-speed drive is a structural fault, not a calibration one.
When you are specifying the depth camera for the robot as well as fixing its mount, these are the 3D sensors to configure it from:
- Type
- Depth / ToF camera
- Type
- Stereo / structured light
- Type
- Stereo / structured light
The camera finder filters this line by type and resolution, and the system configurator assembles camera, mount and cabling into one build. Free expert support comes with every order; questions about a specific mount geometry go through the contact page, and the sensor-side guides sit on the 3D topic page.
Questions
Does a mounting yaw offset affect roll and pitch too?
Not for a pure yaw mount: rotating the camera about the vertical axis changes only yaw, so roll and pitch pass through unchanged. An upside-down or strongly tilted mount changes all three Euler angles, which is why those mounts need the full rotation matrix and re-extracted angles instead of one subtracted constant.
How accurate can corrected yaw be in practice?
With a stiff mount and a carefully measured offset, quarter-turn repeatability of about 1° is realistic on a consumer-grade depth-camera IMU. The largest residual usually comes from the square-up when you measure the offset, so use a long straight reference and re-measure after any bracket change.
My corrected yaw increases when the robot turns clockwise — is that wrong?
Only if your controller expects the opposite sign. Many IMU libraries report counter-clockwise positive, while robot headings often run clockwise-positive; both are self-consistent. Pick one convention, flip the sign at the same single place where you subtract the mount offset, and record it next to the offset value.
Can two cameras on the same robot share one yaw offset?
Only if their brackets hold the same angle, which is rarely true to within a degree. Each IMU carries its own mounting rotation: measure one offset per camera, store them separately, and re-run the quarter-turn check on both after any remount or collision.


