Skip to content Link Search Menu Expand Document
ModalAI DOCS
Store

VINS Calibration

Targetless camera-IMU calibration from natural motion with voxl-open-vins-server and voxl-portal.

Table of contents

  1. Overview
  2. Run from the Command Line
  3. Motion
  4. Outputs and Exit Codes
  5. voxl-portal VINS Calibration Page
    1. Calibrate
    2. Results
    3. Configure
  6. Commit the Results
    1. Write the configuration files
    2. Hot start
  7. Calibrator Profile
  8. Offline Replay with voxl-vins-lab

VINS calibration requires SDK 1.8.0 or newer (voxl-open-vins-server 0.7.8, voxl-portal 0.9.16). The voxl-open-vins-server 0.6.x releases in SDK 1.6 do not include it.

Overview

VINS calibration estimates the camera-IMU calibration from natural motion, with no calibration target. It uses the same camera drivers and frame gating as VIO. A session estimates these blocks:

  • camera-IMU extrinsics (R_ItoC, p_IinC)
  • the camera-IMU time offset (td)
  • IMU intrinsics (Dw, Da, R_AtoI, and the gyro g-sensitivity Tg)
  • optionally, camera intrinsics

Each block either commits a new value or abstains and keeps its seed. A block that abstains is normal: it means the motion in that session did not make the block observable enough to trust.

Use it when the camera-IMU extrinsics or time offset are uncertain, for example after a camera is remounted or replaced, or when VIO drifts on a vehicle whose camera intrinsics are already good. Camera intrinsics still come from Camera Calibration.

By default every configured camera that has intrinsics joins one joint solve, and the first global-shutter camera anchors it.

Run from the Command Line

The calibrate mode of voxl-open-vins-server needs exclusive use of the cameras and IMU, so stop the VIO service first:

systemctl stop voxl-open-vins-server
voxl-open-vins-server --calibrate --calib-flight

--calibrate requires rs_convention: center in the estimator configuration. Otherwise it exits with ERROR: --calibrate requires rs_convention: center.

During the session the server requests the performance CPU governor. A board that is already in performance mode is not changed.

OptionDescription
--calibrate, -kRun a calibration session instead of VIO
--calib-flightUse the flight profile
--calib-cam <name>Calibrate only this camera. By default every camera with intrinsics joins, and the first global-shutter camera anchors the solve
--calib-out <yaml>Result file (default /data/ov_calib/ov_calib_result.yaml)
--calib-config <yaml>Calibrator profile (default /etc/modalai/ov_calib.yaml)
--calib-max-sec <s>Cap on the collection time
--calib-budget <s>Solve time budget
--calib-min-eig <x>Excitation threshold that ends collection early (default 5.0, 0 uses the full budget)
--calib-no-perf-modeDo not request the performance governor
--no-calib-hotstartDo not apply a committed snapshot at startup

Motion

The solve can only commit what the motion makes observable.

  • Good: figure-8s with speed changes, yaw sweeps at varying rates while translating, and vertical bobs.
  • Avoid: hover, constant-velocity straight lines, and pure yaw in place.
  • The session prompts for the direction that is currently weakest.

A hover-only session that refuses to commit extrinsics is behaving correctly.

Outputs and Exit Codes

Results are written to /data/ov_calib/:

FileContents
ov_calib_result.yamlCommitted and seed values for each block, written atomically. This is the snapshot used for hot start
ov_calib_result.yaml.report.jsonSession report (committed blocks, gates, verification)
ov_calib_result.yaml.session.binSession record for offline replay, written when record_session is true in the profile

The calibrate mode exits with:

CodeMeaning
0Session completed and the result was committed
2Session aborted or the result was refused
255Setup failed before the session started, for example the rs_convention check

voxl-portal VINS Calibration Page

voxl-portal 0.9.12 and newer (0.9.16 in SDK 1.8.0) has Debug > VINS Calibration. The page runs the standalone voxl-zcalib calibrator, which can run with VIO stopped or alongside VIO. When VIO is running, voxl-zcalib shares its pipes, does not stop VIO, does not change the CPU governor, and writes no configuration. Only one session runs at a time.

The page has three tabs: Calibrate, Results, and Configure.

Calibrate

  1. Cameras: pick from the declared cameras, or choose Any pipe and give the pipe, an intrinsics file, a label, the shutter type (Global, or Rolling with a readout time), and whether rescaling is allowed.
  2. Session: choose the source.
    • Live: calibrate from the cameras and IMU now.
    • Session record: replay a .session.bin from /data/ov_calib or from a voxl-vins-lab tracker-only run. A typed path overrides the list.
    • voxl-logger capture: see the warning below.
  3. Profile: Flight, or Bench (full 70-clone solve that takes minutes). Collection cap in seconds, where 0 uses the profile budget.

In SDK 1.8.0 the voxl-logger capture source fails, because voxl-zcalib 0.7.8 does not accept --log. Convert the log first with voxl-vins-lab -l <dir> --tracker-only, then pick <dir>/vins-lab/run_*/tracker_session.bin under Session record.

The live panel shows the stages (Settle, Bootstrap, Collect, Solve, Verify, Commit), tiles for windows, tracked rate and features per camera, and drops, and the calibrator log.

  • Solve now ends collection and starts the solve.
  • Extend +30 s adds 30 seconds of recording time. The solve budget does not change.
  • Abort finalizes the session through the control pipe and then stops the calibrator.

Solve now and Extend +30 s are only enabled during live collection. They are disabled for recorded sources.

From a shell, a live voxl-zcalib session can also be solved early through its control pipe:

echo solve > /run/mpa/vins_calib/control

Results

The Results tab lists completed sessions. For each one it shows the committed blocks, the time offset, prior and posterior values, coupling, held-out verification, solve stages, bootstrap, the committed values, and the gates.

Write to extrinsics.conf runs voxl-calib-to-extrinsics. It shows a preview first, maps each camera to its entry in /etc/modalai/extrinsics.conf, and keeps a .bak copy. It is refused while voxl-open-vins-server is running.

Configure

The Configure tab edits three files:

  • /etc/modalai/voxl-open-vins-server.conf
  • estimator_config.yaml in the configured yaml_folder. A file without the %YAML:1.0 header, or with a : inside a trailing comment, is rejected
  • /etc/modalai/ov_calib.yaml

Saves are refused while voxl-open-vins-server is running. Each save keeps a .bak copy and replaces the file atomically.

Commit the Results

A committed result can be used two ways: hot start, which overlays it at boot without editing the estimator files, or a permanent write into the configuration files.

Write the configuration files

voxl-calib-commit-chains writes the committed blocks into kalibr_imu_chain.yaml and kalibr_imucam_chain.yaml, keeping .bak copies:

systemctl stop voxl-open-vins-server
voxl-calib-commit-chains --dry-run
voxl-calib-commit-chains -e
systemctl start voxl-open-vins-server
OptionDescription
--resultResult yaml to read (default /data/ov_calib/ov_calib_result.yaml)
--confvoxl-open-vins-server conf (default /etc/modalai/voxl-open-vins-server.conf)
--extrinsics-confextrinsics.conf to update with -e (default /etc/modalai/extrinsics.conf)
--chain-dirOverride the conf’s yaml_folder
--cam IDX=CHILDMap a camera to its extrinsics.conf entry (repeatable)
--dry-runPrint the changes without writing
--forceCommit despite a resolution mismatch
-e, --write-extrinsicsAlso write extrinsics.conf
--keep-hotstartLeave the hot-start keys on
--keep-sync-configLeave sync_config unchanged

By default it turns off calibrate_first, en_calib_hotstart, and calib_hotstart_on_reset, because the values now live in the chain files. It also sets sync_config to false (adding the key if absent) so the chain files are not regenerated over the result. The IMU chain is only written when the result commits the full Dw, Da, R_AtoI set.

To update only /etc/modalai/extrinsics.conf, use voxl-calib-to-extrinsics:

voxl-calib-to-extrinsics
voxl-calib-to-extrinsics --in-place

Without --in-place it writes <conf>.calibrated (by default /etc/modalai/extrinsics.conf.calibrated). --in-place replaces the file and keeps a .bak. Only committed extrinsic blocks are changed, and the old and new values are printed. Other options are --result, --conf, --out, --cam IDX=CHILD, --imu-frame, and --imu-child (default imu_apps).

Hot start

These keys in /etc/modalai/voxl-open-vins-server.conf all default to false:

KeyDescription
en_calib_hotstartAt boot, overlay the committed values from /data/ov_calib/ov_calib_result.yaml onto the estimator configuration. Seed values and filter noise settings are never applied
calibrate_firstA boot with no committed snapshot runs a calibration session first, then starts VIO. Requires en_calib_hotstart. Retries are bounded to 3 attempts, counted in /data/ov_calib/.calibrate_first_attempts
calib_hotstart_on_resetA hard reset normally reverts to the on-disk configuration. When true, the snapshot is applied again
calib_restore_governorRestore the automatic CPU governor after a calibration session

voxl-vins-autoconf --enable-zcal sets en_calib_hotstart. --disable-zcal clears en_calib_hotstart, calibrate_first, and calib_hotstart_on_reset. Neither changes calib_restore_governor:

voxl-vins-autoconf --enable-zcal
voxl-vins-autoconf --disable-zcal

To recalibrate with calibrate_first, delete /data/ov_calib/ov_calib_result.yaml and reboot.

Calibrator Profile

The profile is /etc/modalai/ov_calib.yaml. The package default is installed at /usr/share/modalai/voxl-open-vins/ov_calib.yaml and copied to /etc/modalai/ only when no copy exists there, so deleting the /etc/modalai/ copy resets it. The shipped profile uses the flight profile with a 30 s collection budget, a 120 s solve budget, collect_min_eig 5.0, and record_session true. The seed_* keys choose which blocks start from the current configuration; intrinsics are seeded, extrinsics and time offset are not.

The file is validated strictly. Keep comments on their own line: a : inside a trailing comment silently makes that key keep its default.

Offline Replay with voxl-vins-lab

voxl-vins-lab replays recorded data through the same code:

voxl-vins-lab -l <log_dir>
voxl-vins-lab -l <log_dir> --tracker-only
voxl-vins-lab --session <session.bin>
voxl-vins-lab -l <log_dir> --calib /data/ov_calib/ov_calib_result.yaml
  • -l <log_dir> runs the full system on a voxl-logger capture.
  • --tracker-only writes <log_dir>/vins-lab/run_*/tracker_session.bin, which voxl-zcalib and the portal can replay.
  • --session <bin> runs the filter only on a session record.
  • --calib <yaml> replays the log under a committed calibration, for an A/B comparison against the original run.

Every run writes a calibration.json. voxl-vins-autoconf --log <dir> prints the replay command for a given log. For repeatable accuracy comparisons across many logs, see voxl-benchmark-vio.