Link Search Menu Expand Document

Initialization & Resets

A VIO estimator is only as trustworthy as its ability to start well and to recover well. voxl-open-vins-server initializes through a structure-from-motion (SfM) pipeline that runs entirely on-board with deterministic, real-time-friendly numerics — no Ceres, no dynamic thread pools — and recovers through a two-tier reset system designed so that a healthy filter is never torn down for a transient hiccup.

Table of contents

  1. Lifecycle
  2. Getting started: gravity and jerk gating
  3. Static initialization
  4. Dynamic initialization — Ceres-free SfM
  5. Resets
    1. Soft reset (warm)
    2. Hard reset (cold)
    3. Auto-reset policy
  6. Related configuration

Lifecycle

Initialization and reset lifecycle


Getting started: gravity and jerk gating

Before any visual initialization, the server’s IMU front-end establishes two facts:

  • Gravity direction — a plausible gravity sample orients the initial frame. By default the server accepts any attitude (the estimator’s SfM initializer is attitude-agnostic); platforms that want a level-start gate can opt in with imu_init_max_gravity_angle_deg.
  • Motion state — a jerk detector watching accelerometer/gyroscope windows distinguishes “sitting on the bench” from “picked up / taking off”, which selects between the static and dynamic initializers and arms zero-velocity updates appropriately.

Static initialization

If the platform is stationary, the filter initializes directly: gravity from the averaged accelerometer, zero velocity, and bias priors from the quiet window. A deliberately tight tilt gate applies here — a pitched platform held in hand must fall through to dynamic initialization rather than receive a confidently wrong level-start seed.

Dynamic initialization — Ceres-free SfM

If the platform is moving (or tilted), the estimator solves a small structure-from-motion problem over a short window (~2 s) of feature tracks and preintegrated IMU segments: recover attitude (including gravity), velocity, biases, and feature depths, jointly, from scratch — at any attitude, mid-motion.

The refinement is a full maximum-likelihood solve, executed by a purpose-built solver — ov_init::zbft_sfm, authored by Joao Leonardo Silva Cotta, PhD — that replaces Ceres on the flight target:

  • Deterministic and RT-friendly — fixed memory, bounded iterations, lock-free bounded parallelism; identical inputs produce identical outputs, run after run.
  • Analytic Jacobians everywhere — closed-form derivatives for the IMU preintegration and reprojection factors (finite differences exist only as test oracles).
  • Well-conditioned gravity handling — gravity is optimized on the unit sphere (S²) with a weak direction prior and a post-solve sanity gate, which is what makes reliable any-attitude initialization possible without flip ambiguities.
  • Fast — full dynamic initialization completes in ~17–20 ms end-to-end on a QRB5165 (the legacy Ceres path took ~65 ms), including aggressive-motion cases with over 170° of rotation across the window.

Warm-start injection. The initializer does not just hand over a single state: the window’s poses and their joint covariance are injected as filter clones, so the filter performs useful updates immediately instead of cold-starting a fresh 2-second window after init.


Resets

Two tiers, one contract: the filter must come back honestly — no stale confidence, no leftover evidence from the previous life.

Soft reset (warm)

Triggered by RESET_VIO_SOFT on the control pipe or autonomously by health monitoring. The EKF state and covariance are rebuilt while everything expensive survives:

  • feature tracks and the IMU history buffer — re-initialization is warm, not a cold restart;
  • calibration values — per-camera time offsets and readout estimates carry over;
  • live bias estimates — the running gyro/accel biases (with age-inflated uncertainty) are handed to the dynamic initializer as priors, dramatically conditioning the re-solve. The priors are gated: implausible magnitudes or uncertainties are rejected, and a divergence-suspected reset inflates them further before use.

What is deliberately purged: per-update bookkeeping keyed to the old timeline (the published feature list, quality smoothing, zero-velocity latches) — sensor time is continuous across a reset, so anything time-keyed would otherwise present pre-reset evidence as current.

Hard reset (cold)

Triggered by RESET_VIO_HARD or by estimator-poisoning error codes. The entire estimator object is destroyed and recreated: queued camera frames are released back to their owners exactly once, error codes are cleared (including those raised by the teardown itself — housekeeping is not a health event), and the system returns to the gravity/jerk gate.

Auto-reset policy

The health monitor (30 Hz) applies a strict severity split (full code table on the Pipe Interface page):

Estimator-health codes (corrupt covariance, sustained low quality, feature starvation, velocity-uncertainty breaches) recommend a reset — the filter itself is suspect. Transport warnings (dropped frame, dropped IMU sample, timestamp glitch) never do: the asynchronous ingest drops frames by design for ordering and staleness, and a single dropped frame once caused a mid-flight reset loop. Warning codes self-clear after 10 quiet seconds.

Additional guards prevent reset loops: quality checks arm only at the initialized rising edge (a re-initializing filter gets its full grace window), quality is capped during initialization so a freshly rebuilt covariance cannot report false confidence, and a reset that begins while a publish is in flight forces that last packet to report INITIALIZING.


Server-side knobs (/etc/modalai/voxl-open-vins-server.conf — see the main page): en_auto_reset, auto_reset_max_velocity, auto_reset_max_v_cov_timeout_s, auto_reset_min_features, auto_reset_min_feature_timeout_s, ok_state_grace_timeout_s, and the quality-hysteresis thresholds.

Estimator-side knobs (estimator_config.yaml, prefix init_): window length and feature budget (init_window_time, init_max_features), dynamic-init MLE controls (init_dyn_mle_max_iter, init_dyn_mle_max_threads, LM damping schedule), gravity gates (init_gravity_max_angle, init_static_gravity_max_angle, init_dyn_grav_prior_sigma, init_dyn_grav_gate_deg), warm start (init_warmstart_inject), and the reset bias priors (init_dyn_reset_prior_use and its acceptance gates).

The shipped platform configurations already encode sensible values for all of these; the knobs exist for bring-up and research. If you are tuning, change one group at a time and validate with voxl-benchmark-vio replays before flying.