Skip to content

Phase 3 — Visual-Inertial Odometry

Status: complete (2026-05-26). Epic E3 (#33) closed; all 16 sub-issues merged.

Phase 3 delivered a complete MSCKF visual-inertial odometry pipeline. See the VIO Overview for the architecture; this page is the phase record.

Each row is one merged PR, through the full gate (ready PR → CodeRabbit review → gcc+clang+CI green → merge):

IssueComponentPage
#34VioBackend interfaceMSCKF Backend
#48Image container + PGM/PNG I/OFront End
#49Gaussian image pyramidFront End
#39Camera models (pinhole/fisheye/unified)Cameras
#37FAST corner detectorFront End
#38Pyramidal KLT trackerFront End
#40IMU preintegrationIMU
#41Feature representations + null-space typesCamera Updaters
#43State + Propagator + StateHelperMSCKF State
#42IMU initialization (static + dynamic)IMU
#44Camera updaters (null-space MSCKF)Camera Updaters
#35MSCKF backendMSCKF Backend
#45Top-level VioEstimatorVioEstimator
#36Sliding-window backend skeletonMSCKF Backend
#46EuRoC replay harness + ATE/RPEAccuracy
#47Per-frame latency budgetLatency
  • Filter stability — covariance stays PD/PSD and the innovation well-conditioned over 1000 consecutive camera updates; trace monotonically non-increasing.
  • Initialization — gravity recovered within 0.5° (static); gravity, velocities, and gyro bias recovered exactly on synthetic trajectories (dynamic).
  • Accuracy — ATE/RPE via the EuRoC harness; V1_01_easy gate < 0.50 m (dataset-gated).
  • Latency — per-frame feed_image budget, ~38 ms median at -O2 on 752×480 (details).
  • Jacobi over power iteration for ATE’s Horn alignment — the 4×4 profile matrix’s top two eigenvalues are near-degenerate, so power iteration silently returned wrong rotations.
  • Dataset / optimized-build gating so CI stays green without the EuRoC sequence and without an optimized build.
  • Square-root covariance backend#187, split out rather than shipping a static_assert-only template knob.

Next: Phase 4 — SLAM.