Skip to content Link Search Menu Expand Document
ModalAI DOCS
Store

VOXL Open-VINS Server

voxl-open-vins-server is a multi-camera visual-inertial odometry (VIO) service for the VOXL 2 platform. It uses an MSCKF-based estimator derived from OpenVINS to fuse data from up to 3 cameras and an IMU, producing real-time pose and velocity estimates that are forwarded to the autopilot as odometry data. Cameras may be hardware-synchronized or fully unsynchronized, global-shutter or rolling-shutter (including mixed rigs such as a rolling-shutter hires camera paired with a global-shutter tracking camera) — see Asynchronous & Mixed-Shutter Cameras. Initialization and recovery run a deterministic on-board SfM pipeline — see Initialization & Resets.

The server is built around three modular subsystems: VoxlCore (configuration, housekeeping, publishing), VoxlCam (camera management and feature tracking via OpenCL), and VoxlIMU (IMU data acquisition and frame transformation). Data flows through ModalAI’s MPA pipe architecture, which decouples sensor producers from VIO consumers and downstream clients.

Table of contents

  1. Architecture
    1. System Overview
    2. Data Flow
    3. Module Dependencies
    4. Camera Class Hierarchy
    5. Initialization Flow
  2. Prerequisites
  3. Installation and Setup
    1. Install
    2. Disable qvio
    3. Generate Configuration
    4. Start the Service
  4. Configuration Files
    1. extrinsics.conf
    2. vio_cams.conf
    3. voxl-open-vins-server.conf
      1. Auto-Reset Parameters
      2. State Machine and Spin Monitoring
      3. OpenVINS and Camera Mode
      4. Takeoff and Occlusion
      5. In-Flight Calibration (SDK 1.8.0+)
      6. Frame Settings
      7. Quality Hysteresis
  5. MPA Pipes
    1. Output Pipes
    2. Publisher Pipeline
    3. Input Pipes
    4. Control Pipe
  6. Command-Line Options
    1. In-Flight Calibration Options (SDK 1.8.0+)
  7. Client Tools
    1. voxl-reset-vins
    2. voxl-inspect-vins
    3. voxl-vins-autoconf
    4. voxl-vins-lab
    5. voxl-zcalib
    6. voxl-calib-to-extrinsics
    7. voxl-calib-commit-chains
    8. voxl-benchmark-vio
  8. Testing
    1. Hand Testing
      1. Steps
    2. Flight Testing
  9. Troubleshooting
    1. No config file
    2. Server fails to start
    3. VIO quality is poor or resets frequently
    4. IMU body frame errors
  10. Legacy Parameter Notes
  11. API Reference

Architecture

System Overview

Architecture Diagram

The server follows an IMU-driven pattern: camera frames are staged lock-free as they arrive, and each IMU batch advances the filter and releases whatever frames are ready.

  1. IMU data arrives via MPA pipe and is handled by VoxlIMU on an RT-priority thread. The FrameTransform module detects gravity direction and jerk events for initialization gating.
  2. Camera frames arrive through per-camera MPA pipes. CameraManager dispatches frames to one MonoCamera instance per camera (stereo pairs are matched in the estimator when use_stereo is set), which push them directly into the estimator’s lock-free per-camera ingest — there is no fusion thread and no frame pairing; camera callbacks never block.
  3. Each IMU callback feeds the batch to the OpenVINS VioManager, which releases staged camera frames in global timestamp order (each frame only once inertial data covers it) and runs tracking plus the MSCKF update per released frame. Synchronized rigs produce same-timestamp frames that are bundled automatically; with epoch_mode: true (the fpvhires and zmono profiles), unsynchronized rigs flow through epoch-anchored cloning.
  4. Publisher formats the resulting state (pose, velocity, quality, error codes) with coordinate frame transformation (OpenVINS → FRD) and writes to output pipes — on the same VIO thread, immediately after each update.
  5. HealthCheck runs at 30 Hz, monitoring connectivity, triaging error codes by severity, and driving auto-reset.

Data Flow

Data Flow

Per-sample data flow: camera callbacks stage frames into lock-free per-camera rings; each _imu_data_handler_cb invocation feeds the IMU batch to the VioManager, which releases staged frames in global timestamp order, runs the MSCKF update, and publishes through Publisher::publish() on the same thread. Dropped frames (late, ring-full, bogus timestamp) are returned to their owner exactly once and are counted, never fatal.

Module Dependencies

ModuleKey ClassesResponsibility
VoxlCorePublisher, HealthCheck, VoxlConfigureMain loop, configuration, publishing, quality metric, health monitoring
VoxlCamCameraManager, CameraBase, MonoCameraCamera pipe subscription, image preprocessing, direct push into the estimator ingest
VoxlIMUFrameTransform, _imu_data_handler_cbIMU pipe subscription, frame transformation, jerk detection
ov_msckf (library)VioManager, AsyncCameraBuffer, State, updatersLock-free ingest, epoch-anchored MSCKF estimation, per-camera temporal/rolling-shutter states
ov_init (library)DynamicInitializer, zbft_sfm solverCeres-free SfM initialization, any-attitude init/reset, warm start

Camera Class Hierarchy

Camera Hierarchy

CameraBase is the abstract base class. MonoCamera handles each camera pipe; the older concatenated-frame StereoCamera was removed, and stereo pairs are matched in the estimator. Cameras push frames directly into the estimator’s lock-free per-camera ingest from the pipe callback — no intermediate fusion queue.

Initialization Flow

Init Flow

main() call graph: reads config, syncs camera calibration, starts Publisher (which starts HealthCheck), then enters the event loop.


Prerequisites

  • VOXL 2 or QCS6490-based hardware
  • VOXL SDK 1.4.0 or later. This page describes voxl-open-vins-server 0.7.8 as shipped in SDK 1.8.0; features marked SDK 1.8.0+ (presets, in-flight calibration, the calibration tools) are not in the 0.6.x server that ships with SDK 1.6
  • All tracking cameras calibrated (intrinsics files present in /data/modalai/)
  • Extrinsics configured in /etc/modalai/extrinsics.conf (see Configure Extrinsics)
  • Camera feeds verified in voxl-portal before enabling VIO

Installation and Setup

Install

If you are working on a non-development drone, back up configuration and intrinsic files first:

/etc/modalai
/data/modalai

Disable qvio

Only one VIO source should be active at a time. Disable qvio before starting voxl-open-vins-server:

voxl-configure-qvio disable

Generate Configuration

Run the configuration tool to write /etc/modalai/voxl-open-vins-server.conf:

voxl-configure-open-vins <camera_configuration>

Available configurations:

ArgumentRigCameras
starling2_2camStarling 2front + down tracking (forced camera sync)
fpvVOXL 2 FPVduo AR0144 tracking, hardware-synchronized
fpvhiresVOXL 2 FPV, hires VIOIMX664 hires (rolling shutter, 60 fps) + AR0144 tracking (global shutter, 30 fps), unsynchronized — see Async & Mixed-Shutter Cameras
factory_enablegenericdefault config for synced AR0144 cameras
fpvmVOXL 2 FPV on M0197 (QCS6490, BMI270 IMU)duo AR0144 tracking, hardware-synchronized (SDK 1.8.0+)
fpvhiresmsingle hires cameraIMX664 hires only (rolling shutter), mono (SDK 1.8.0+)
starling2mStarling 2, single cameraone tracking camera, mono, unsynchronized ingest (SDK 1.8.0+)
starling2bmiStarling 2 with BMI270 IMUtwo tracking cameras, unsynchronized ingest (SDK 1.8.0+)
zmonosingle hires cameraIMX664 hires (rolling shutter, 60 fps), mono: the fpvhires rig without the tracking camera (SDK 1.8.0+)

For example, voxl-configure-open-vins starling2_2cam configures a two-camera setup using front and down tracking cameras. The result should be in agreement with the three configuration files in /etc/modalai/:

  • voxl-open-vins-server.conf
  • vio_cams.conf
  • extrinsics.conf (if not already present)

On SDK 1.8.0 and later, check that the server conf and the profile YAMLs it points at are consistent before starting the service. voxl-vins-autoconf validates the set and reports problems (dry run); --apply fixes what it reports:

voxl-vins-autoconf
voxl-vins-autoconf --apply

Start the Service

systemctl restart voxl-open-vins-server

Configuration Files

Three files in /etc/modalai/ control the server:

extrinsics.conf

Defines the geometric relationship between sensors (cameras, IMU) and the body frame. See the extrinsics configuration page for details.

When imu_body_frame_mode is enabled (default), the server also reads the body -> imu_apps extrinsic to transform VIO output into the body frame.

vio_cams.conf

Defines which camera pipes to subscribe to and how each camera participates in VIO. Example for a two-camera setup:

{
    "cams": [{
            "enable":               true,
            "name":                 "tracking_front",
            "pipe_for_preview":     "tracking_front",
            "pipe_for_tracking":    "tracking_front",
            "is_occluded_on_ground": false,
            "imu":                  "imu_apps",
            "cal_file":             "opencv_tracking_front_intrinsics.yml"
        },{
            "enable":               true,
            "name":                 "tracking_down",
            "pipe_for_preview":     "tracking_down",
            "pipe_for_tracking":    "tracking_down",
            "is_occluded_on_ground": true,
            "imu":                  "imu_apps",
            "cal_file":             "opencv_tracking_down_intrinsics.yml"
        },{
            "enable":               false,
            "name":                 "tracking_rear",
            "pipe_for_preview":     "tracking_rear",
            "pipe_for_tracking":    "tracking_rear",
            "is_occluded_on_ground": false,
            "imu":                  "imu_apps",
            "cal_file":             "opencv_tracking_rear_intrinsics.yml"
        }]
}
FieldDescription
enableWhether this camera is active in the VIO pipeline
nameCamera identifier used in logs and overlays
pipe_for_trackingMPA pipe name to subscribe to for feature tracking frames. Can differ from the preview pipe (e.g. tracking_front_misp_norm or tracking_front_misp_grey) depending on which image processing yields the best features for your application
pipe_for_previewMPA pipe name used for overlay visualization
is_occluded_on_groundIf true, this camera’s view is obstructed while landed (e.g. a downward camera on the ground). The server will not use features from this camera until the drone reaches takeoff_alt_threshold altitude
imuIMU pipe name. All cameras must reference the same IMU
cal_fileOpenCV intrinsics calibration file in /data/modalai/

To enable a third camera, set its enable field to true.

voxl-open-vins-server.conf

Main server configuration file. The server creates this file with default values if it does not exist. All parameters are read by read_server_config() in VoxlConfigure.cpp.

Auto-Reset Parameters

ParameterTypeDefaultDescription
en_auto_resetbooltrueEnable automatic VIO reset when divergence or low feature count is detected
auto_reset_max_velocityfloat20.0Velocity magnitude threshold (m/s) above which the system considers the estimate divergent
auto_reset_max_v_cov_timeout_sfloat0.5Duration (s) that quality must remain below threshold before an auto-reset is recommended
auto_reset_min_featuresint1Minimum number of tracked features required to avoid a reset
auto_reset_min_feature_timeout_sfloat10.0Duration (s) that the feature count must stay below the minimum before triggering a reset

State Machine and Spin Monitoring

ParameterTypeDefaultDescription
ok_state_grace_timeout_sfloat2.0Grace period (s) after entering OK state during which quality is held low to avoid false confidence from bad initialization
fast_yaw_threshfloat5.0Yaw rate (rad/s) above which spinning-in-place detection engages
fast_yaw_timeout_sfloat1.75Duration (s) of sustained spinning-in-place before an auto-reset is recommended

OpenVINS and Camera Mode

ParameterTypeDefaultDescription
yaml_folderstring/usr/share/modalai/voxl-open-vins/VoxlConfig/starling2Path to the folder containing OpenVINS YAML configuration files (estimator_config.yaml, kalibr_imucam_chain.yaml)
using_stereoint0When sync_config is true, overrides use_stereo in the estimator YAML (1 on, 0 off). Ignored when sync_config is false
stereo_z_minfloat0.30Minimum depth (m) accepted by the stereo matcher (SDK 1.8.0+)
stereo_z_maxfloat100.0Maximum depth (m) accepted by the stereo matcher (SDK 1.8.0+)
stereo_calibrationstring""Optional path to a voxl_stereo_calibration.yml from an offline stereo calibration. Blank leaves the stereo matcher on the left-to-right extrinsic composed from the camera chain (SDK 1.8.0+)
sync_configbooltrueCalibration synchronization at startup — this flag does not affect frame ingest or timing. true: the server regenerates the OpenVINS YAMLs from system calibration — camera intrinsics/distortion are refreshed from /data/modalai, the cam-to-cam extrinsic is composed from the per-camera cam → imu extrinsics, and the estimator/camchain YAMLs are rewritten. false: the calibration files shipped in yaml_folder are authoritative and are not regenerated (e.g. starling2_2cam); an active calibration hot start still writes the camera chain

Takeoff and Occlusion

ParameterTypeDefaultDescription
takeoff_alt_thresholdfloat0.5Altitude (m) above which cameras marked is_occluded_on_ground become active

In-Flight Calibration (SDK 1.8.0+)

These keys connect VIO to the targetless calibrator (see Command-Line Options and VINS Calibration). All default to false. 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.

ParameterTypeDefaultDescription
en_calib_hotstartboolfalseAt boot, apply the values of the committed blocks in the calibration snapshot (/data/ov_calib/ov_calib_result.yaml) to the estimator configuration. Filter noise and prior sigmas are not changed. --no-calib-hotstart forces it off for one run
calibrate_firstboolfalseA boot with no committed snapshot runs a calibration session first, then starts VIO in the same process with the new values. Delete the snapshot to recalibrate. Retries are bounded. Requires en_calib_hotstart: true; otherwise it is ignored
calib_restore_governorboolfalseRestore the automatic CPU governor after a calibration session. A board already in performance mode is never changed
calib_hotstart_on_resetboolfalseA hard reset normally reverts to the on-disk configuration from before calibration. true re-applies the snapshot on the rebuilt filter

Frame Settings

ParameterTypeDefaultDescription
imu_body_frame_modebooltrueWhen enabled, the server reads the body -> imu extrinsic and outputs VIO in the body frame. The IMU pipe is subscribed as imu_apps_body instead of imu_apps
imu_init_max_gravity_angle_degfloat-1.0Level-start gate for IMU initialization, in degrees: if set >= 0, IMU data is held back from the estimator until the measured gravity angle is within this many degrees of level. The default -1.0 disables the gate so (re)initialization can happen at any attitude

Quality Hysteresis

The server uses a state machine with hysteresis to classify VIO quality: INITIAL, GOOD, and BAD. The thresholds and transition counts below control state transitions.

ParameterTypeDefaultDescription
quality_low_thresh_initialint15Quality score threshold below which degradation is detected in INITIAL state
quality_low_thresh_goodint14Quality score threshold below which degradation is detected in GOOD state
quality_high_threshint35Quality score threshold above which recovery is detected (used for INITIAL->GOOD and BAD->GOOD transitions)
quality_initial_to_bad_countint20Consecutive low-quality samples required to transition from INITIAL to BAD
quality_initial_to_good_countint50Consecutive high-quality samples required to transition from INITIAL to GOOD
quality_bad_to_good_countint60Consecutive high-quality samples required to transition from BAD to GOOD
quality_good_to_bad_countint45Consecutive low-quality samples required to transition from GOOD to BAD

MPA Pipes

MPA pipe map

The tables below summarize the interface; the complete communications reference — packet fields, states, quality semantics, and the full error-code table with severities — is on the dedicated Pipe Interface page.

Output Pipes

PipeTypeDescription
ov_extendedext_vio_data_tFull VIO state including covariance matrices, feature counts, quality, and error codes
ovvio_data_tSimplified VIO data with pose and velocity for basic consumers
ov_statusov_status_tSystem status, health information, and operational state

Publisher Pipeline

Publisher Pipeline

Publisher::publish() call graph: calculates quality score, computes angular velocity via dirty quaternion differentiation, applies OpenVINS→FRD coordinate transform, and checks auto-reset conditions before writing to output pipes.

Input Pipes

PipeSourceDescription
imu_apps (or imu_apps_body)voxl-imu-serverIMU data (accelerometer and gyroscope). The _body variant is used when imu_body_frame_mode is enabled
Camera pipes (dynamic)voxl-camera-serverOne pipe per camera defined in vio_cams.conf (e.g. tracking_front, tracking_down)

Control Pipe

The server exposes a control pipe at /run/mpa/ov/control that accepts the following commands:

CommandDescription
RESET_VIO_SOFTSoft reset: reinitializes the VIO state without recreating the VioManager
RESET_VIO_HARDHard reset: destroys and recreates the VioManager from scratch

Control pipes are available on both the ov_extended and ov server channels.


Command-Line Options

Usage: voxl-open-vins-server [OPTIONS]

Options:
  -d, --debug     Enable debug output and detailed logging
  -v, --verbose   Enable verbose output and status information
  -c, --config    Configuration only mode (load and validate config, then exit)
  -i, --imu-body  Enable IMU body measurements (overrides conf file)
  -k, --calibrate Run the targetless calibrator instead of VIO (SDK 1.8.0+)
  -h, --help      Display help message

Examples:

voxl-open-vins-server              # Run with default settings
voxl-open-vins-server -d           # Run with debug output
voxl-open-vins-server -v -c        # Validate configuration only

In 0.7.8 -i has no effect: the server reads imu_body_frame_mode from the conf file after parsing options, so the conf value wins.

In-Flight Calibration Options (SDK 1.8.0+)

-k / --calibrate runs a targetless camera-IMU calibration session instead of VIO. The session uses the same IMU and camera pipes and frame gating as VIO, solves, writes its result, and exits; the exit code is the session verdict (0 = completed and committed). Stop the service first, because this mode takes over the server’s process name and pipes. For the full procedure see VINS Calibration.

systemctl stop voxl-open-vins-server
voxl-open-vins-server --calibrate --calib-flight
OptionDescription
-k, --calibrateRun the calibrator instead of VIO
--calib-cam <name>Calibrate only this vio_cams.conf camera. By default every configured camera is calibrated in one joint solve, and the first global-shutter camera anchors the report. Name a rolling-shutter camera explicitly to calibrate it alone
--calib-out <yaml>Result path. Default /data/ov_calib/ov_calib_result.yaml
--calib-flightApply the flight profile shape: a short session, 60 s class, suitable for an in-flight or quick bench run. The bench profile in ov_calib.yaml is the longer, full-shape solve
--calib-max-sec <s>Absolute collection cap, in stream seconds
--calib-budget <s>Solver wall-time budget override
--calib-config <yaml>Calibrator profile. Default /etc/modalai/ov_calib.yaml (separate from the estimator config)
--calib-no-perf-modeLeave the CPU governor alone. By default the session requests the performance governor
--calib-min-eig <x>Stop collecting once the weakest calibration direction reaches x. Default 5.0; 0 collects the full budget
--no-calib-hotstartDo not apply a committed calibration snapshot for this run, regardless of en_calib_hotstart

Client Tools

voxl-reset-vins

Sends a reset command to the running server through the control pipe.

voxl-reset-vins          # Send a hard reset
voxl-reset-vins -s       # Send a soft reset

voxl-inspect-vins

Real-time terminal display of VIO data from the ov pipe. Shows position, rotation, velocity, features, quality, state, and error codes.

voxl-inspect-vins              # Default view (position, rotation, features, quality, state, errors)
voxl-inspect-vins -v           # Include velocity
voxl-inspect-vins -b           # Display values in body frame (reads body->imu extrinsic)
voxl-inspect-vins -z           # Print all fields
voxl-inspect-vins -n           # Print each sample on a new line (useful for logging)
FlagDescription
-aPrint IMU angular velocity
-bPrint values in body frame
-gPrint gravity vector
-mPrint camera-to-IMU extrinsics
-nPrint each sample on a new line
-tPrint timestamp in nanoseconds
-vPrint velocity
-zPrint all fields

voxl-vins-autoconf

SDK 1.8.0+. Inspects and validates voxl-open-vins-server.conf together with the profile YAML folder it points at (estimator config and kalibr chains): YAML syntax the server’s parser would reject, shutter/readout/fps declarations, max_cameras against the chain, the calibration key group, and hot-start snapshot presence. Dry run by default; --apply fixes what it reports, writes atomically, and keeps a one-time .bak. Exit code 0 = consistent, 1 = findings, 2 = hard error.

voxl-vins-autoconf                          # inspect + validate (no writes)
voxl-vins-autoconf --apply                  # fix what it reports
voxl-vins-autoconf --profile fpvhiresM      # point yaml_folder at a shipped profile
voxl-vins-autoconf --enable-zcal            # set en_calib_hotstart
voxl-vins-autoconf --log <log_dir>          # validate a voxl-logger capture's config tree

voxl-vins-lab

SDK 1.8.0+. Offline replay harness: feeds a voxl-logger capture directly into an in-process estimator through the same sensor conversion code as the live server, and writes per-frame CSV and a summary. It runs on the VOXL (the tracker needs the device’s OpenCL) and does not modify /etc/modalai or /data/modalai. It replaces voxl-log-vins and voxl-evaluate-vins, which were removed in SDK 1.8.0.

voxl-vins-lab -l /data/voxl-logger-auto/log0005 -o /data/vinslab/base
voxl-vins-lab -l <log_dir> --speed 1 --publish      # real-time replay, publish ov/ov_extended
voxl-vins-lab -l <log_dir> --calib /data/ov_calib/ov_calib_result.yaml   # replay under a calibration

--interactive adds play/pause/step/seek with filter snapshots, --tracker-only runs only the tracking front-end and writes a session record, and --session <bin> drives the filter alone from a recorded session. Run voxl-vins-lab -h for the full option list.

voxl-zcalib

SDK 1.8.0+. Standalone targetless camera-IMU calibration. Unlike voxl-open-vins-server --calibrate, it runs alongside a running VIO process without taking over its pipes or rewriting its calibration chain, and it can calibrate cameras that are not enabled for VIO (--cam-pipe with --cam-intrinsics). Exit code 0 = committed, 2 = aborted or refused, 1 = usage or I/O error.

voxl-zcalib --list-cams                     # list declared and live cameras
voxl-zcalib --live --cam tracking_front --flight

voxl-calib-to-extrinsics

SDK 1.8.0+. Writes the committed camera extrinsics from a calibration result (default /data/ov_calib/ov_calib_result.yaml) into extrinsics.conf. Only committed blocks are written, and rotation and translation pass plausibility checks first. The default output is <conf>.calibrated; --in-place writes the conf itself after saving <conf>.bak.

voxl-calib-to-extrinsics                    # writes /etc/modalai/extrinsics.conf.calibrated
voxl-calib-to-extrinsics --in-place

voxl-calib-commit-chains

SDK 1.8.0+. Makes a committed calibration permanent: writes it into the active kalibr_imu_chain.yaml and kalibr_imucam_chain.yaml, then turns the hot-start keys off in the server conf. It sets sync_config to false by default so the next boot does not regenerate the chains from extrinsics.conf (--keep-sync-config keeps it). -e also writes the committed extrinsics into extrinsics.conf. --dry-run shows the changes without writing.

voxl-calib-commit-chains --dry-run
voxl-calib-commit-chains -e

voxl-benchmark-vio

Utility for benchmarking VIO performance on VOXL.

voxl-benchmark-vio orchestrates repeatable, automated replay-based benchmarking of voxl-open-vins-server (or voxl-open-sqrtvins2-server) over one or more recorded logs. Given an input definition JSON, for each listed log it stages the appropriate camera/VIO config, spawns the VIO server alongside an analyzer that listens to its outputs, and runs voxl-replay to feed the log data through the pipeline. Per-run metrics (pose, CPU usage, etc.) are written to per-log JSONs and merged into a single summary JSON.

Typical use cases:

  • Comparing the impact of a config change (e.g. GPU vs CPU tracking, OpenVINS vs SqrtVINS) across a fixed set of logs.
  • Regression-testing VIO accuracy and CPU cost across SDK releases.
  • Monte-Carlo runs of the same suite to measure run-to-run variance.

For full details on the input JSON schema, expected log layout, CLI flags, and output format, see the dedicated page:

voxl-benchmark-vio →


Testing

Hand Testing

Hand testing verifies that extrinsics are correct and the VIO pipeline is functioning before flight. This is the recommended starting point.

Steps

  1. SSH or ADB shell into the VOXL 2.
  2. Make sure voxl-camera-server is running (it provides the camera pipes that VIO subscribes to), then start the VIO service:
    systemctl status voxl-camera-server     # confirm it is active/running
    systemctl restart voxl-open-vins-server
    
  3. Open voxl-portal and navigate to the VIO tab. Optionally toggle Raw Feed: ON to confirm the tracking camera feed(s) currently being consumed by VIO are live.

    vio_tab_raw_feed.png

  4. Lift the drone with a small jerk motion (simulating takeoff). Features should start populating on the overlay. Then perform translational motion — move the drone left-right and front-back — and watch the XYZ position values update in the VIO tab.

    vio_tab_features.png

  5. Check roll, pitch, and yaw by selecting ov_extended or vvhub_wrt_local in the VIO tab.
  6. Move the drone around in 3D space, verifying distance readings are accurate.

    Position and orientation can also be viewed directly in the terminal with voxl-inspect-vins:

    voxl2:/$ voxl-inspect-vins
    
     dt(ms) |    T_imu_wrt_vio (m)   |Roll Pitch Yaw (deg)|features|quality| state| error_codes 
       33.3 |    0.05   -0.03    0.12|   4.1   -2.6    0.6|    45  |   95% | OKAY | 
    
  7. Verify in QGroundControl that the drone shows “Ready to Fly” in Position mode.

    QGC_image.png

  8. If tracking looks correct, proceed to flight testing. If not, double-check your extrinsics.conf. You can isolate cameras by disabling them one at a time in vio_cams.conf.

Flight Testing

You must complete hand testing before flight to avoid fly-aways from bad extrinsics or incorrect parameters.

  1. SSH or ADB shell into the VOXL 2.
  2. Start the service:
    systemctl restart voxl-open-vins-server
    
  3. Open QGroundControl and connect to the VOXL 2.
  4. Verify QGC shows “Ready to Fly”.
  5. Ensure the drone is in Position flight mode and begin flying.
  6. Test roll, pitch, yaw maneuvers and hover in place for several seconds to verify tracking stability.
  7. If everything is stable, continue normal flight operations with OpenVINS.

Troubleshooting

For general service debugging — logs, restarts, running in the foreground — see Debugging Services.

No config file

If voxl-open-vins-server.conf does not exist, run:

voxl-configure-open-vins <camera_configuration>

Server fails to start

  • Check that voxl-camera-server and voxl-imu-server are running and providing data.
  • Verify camera intrinsics files exist in /data/modalai/.
  • Verify extrinsics are configured: cat /etc/modalai/extrinsics.conf.
  • Check the journal for error details: journalctl -u voxl-open-vins-server -n 50.

VIO quality is poor or resets frequently

  • Increase auto_reset_min_feature_timeout_s to allow more time before feature-count resets.
  • Verify cameras have clear field of view with sufficient texture.
  • Check for vibration issues. Excessive IMU vibration degrades the estimator.
  • If using occluded cameras, verify takeoff_alt_threshold matches your takeoff environment.
  • Tune quality hysteresis thresholds if transitions between GOOD and BAD are too sensitive.

IMU body frame errors

If you see Failed to fetch body->imu_apps extrinsic, add the body -> imu_apps relationship to your extrinsics.conf.


Legacy Parameter Notes

The following parameters from older versions of voxl-open-vins-server.conf have been removed. They are either handled internally, moved to OpenVINS YAML configs, or no longer applicable:

Removed ParameterNotes
en_vio_always_onVIO now initializes via jerk detection and does not require arming. No longer needed
en_ext_feature_trackerExternal feature tracker support removed; tracking is handled internally via OpenCL
en_gpu_for_trackingGPU/DSP tracking replaced by OpenCL-based tracking in all configurations
histogram_methodMoved to OpenVINS estimator_config.yaml
use_maskMasking configuration moved to OpenVINS YAML configs
en_force_initInitialization is now handled by the jerk detection system in FrameTransform
max_slam_featuresMoved to OpenVINS estimator_config.yaml as max_slam
max_slam_in_updateMoved to OpenVINS estimator_config.yaml
max_msckf_in_updateMoved to OpenVINS estimator_config.yaml
en_force_ned_2_fluReplaced by imu_body_frame_mode and extrinsic-based frame transformation
takeoff_occlude_stereo_leftNo longer read. Use is_occluded_on_ground in vio_cams.conf with takeoff_alt_threshold
takeoff_occlude_stereo_rightNo longer read. Use is_occluded_on_ground in vio_cams.conf with takeoff_alt_threshold
takeoff_camTakeoff camera is now automatically determined from is_occluded_on_ground in vio_cams.conf
takeoff_thresholdRenamed to takeoff_alt_threshold
auto_reset_max_v_cov, auto_reset_max_v_cov_instantRemoved. Velocity-uncertainty auto-reset is driven by the sustained-quality timeout (auto_reset_max_v_cov_timeout_s); the instantaneous check depended on an arming signal that was never wired
auto_fallback_timeout_s, auto_fallback_min_vRemoved. Fallback-mode logic was never implemented; the parameters had no effect
en_cont_yaw_checksRemoved. Spinning-in-place detection is always on, tuned by fast_yaw_thresh / fast_yaw_timeout_s
fusion_rate_dt_msRemoved. There is no fusion loop anymore — cameras feed the estimator’s lock-free ingest directly and publishing follows each estimator update

API Reference

For detailed C++ API documentation including class hierarchies, call graphs, and source code reference, see the Doxygen API Documentation.