ADR 0021: A GoPro is steered by its own attitude
Status: accepted (2026-10-20); its attitude source and clock superseded by ADR 0023
Context
ADR 0016 integrates the gyro and levels it by the accelerometer. A GoPro MAX or MAX2 also writes its own fused attitude, CORI, with a gravity direction, GRAV, one of each per frame (FORMAT-gopro.md). The camera fuses its sensors at their full rate, before they are decimated into the file, so its attitude is at least as good as one integrated from the stored gyro. What the file does not state is how its quaternions map onto the cube, which way they turn, how its clock meets the picture's, and whether GRAV is a true vertical.
Decision
CameraRecording.reportedAttitudecarries a camera's own attitude (attitude, body to world) and the up direction in its body frame (up), sample by sample.rendition/attitude.tsprefers it to integrating the gyro.CORIis read as storedw, x, y, zand conjugated: the camera writes the world's turn to the body. Its frame is x right, y down, z forward;imuToCameraturns it into the cube's frame (front+x, up+z) by{ w: 0.5, x: -0.5, y: 0.5, z: -0.5 }. Found on MAX2 footage by steering a fast-turning view with each of the 24 axis-aligned rotations and measuring how still the world held between frames a third of a second apart: 6.54 against 4.76 for the next.GRAVnegated is the up direction, in the same body frame asCORI(the levelled vertical scattered least with it, 0.12 against 0.49 for any other alignment).levelAttitudelevels the attitude by it over the same four-second window as ADR 0016, every reading counted alike (trust: 'every-reading'):GRAVis a unit vector, so there is no magnitude to doubt.- The telemetry runs 30 ms behind the picture. The same stillness measure peaks smoothly at a 30 ms offset (6.88 against 6.54 at none, falling either side), so the reader sets
captureClockto 30 ms. IORIis not applied. Composing it, either way round, did not change how level or still the stabilized picture is; the stored picture is the camera's unturned cube.
Consequences
- Stabilized MAX2 stills are level at the moments checked, a canopy turn and a spiral included. An apparent dome there was the developer harness rendering without the correction, not
GRAV. - Longer levelling windows scored worse, and weighting
GRAVby the accelerometer's magnitude changed nothing, so neither is used. - The alignment, offset and up source are measured on the MAX2 only; the original MAX uses them as provisional values until its footage is measured.
stitch/goproPreview.test.tsholds the searches a new body is measured with (WEB360_GOPRO_SEARCH,_OFFSETS,_HORIZON) and renders a stabilized still withWEB360_GOPRO_STAB.