Skip to the content
FixTheRobot Explore Robotics / UAV / Module 4 / M4-T5

UAV Systems Engineering · Module 4

M4-T5: OpenVINS

OpenVINS keeps features out of the state with a linear-algebra trick: project the residual into the null space of the feature Jacobian.

  • Lesson 5 of 15
  • SLAM and Autonomous Localization
  • Research-level
  • About 5 minutes to read

OpenVINS (Geneva et al., ICRA 2020) is an open research platform built on the multi-state constraint Kalman filter. It is a filter where optimisation-based systems use a window, and its design choices (null-space elimination, first-estimate Jacobians, online calibration) explain its behaviour and its documentation.

Learning objectives

After this lesson, you should be able to:

  • Describe the MSCKF structure: a window of cloned camera poses and features eliminated by null-space projection.
  • Perform the null-space projection and verify that the projected residual is independent of the feature error.
  • Explain first-estimate Jacobians and their role in consistency.
  • List the online calibration options and what the configuration needs.

Conceptual explanation

The OpenVINS documentation (docs.openvins.com) is the authority for its current features and interfaces; the description below follows the paper and the documentation structure.

The multi-state constraint Kalman filter (MSCKF) keeps the IMU state and a sliding window of cloned past camera poses. Tracked features that are no longer seen produce constraints between the cloned poses; the feature position is never put in the filter state, but eliminated by projecting the residual into the left null space of the feature Jacobian. OpenVINS adds optional long-lived SLAM features in the state, first-estimate Jacobians for consistency, and online calibration of camera–IMU extrinsics, time offset and camera intrinsics.

OpenVINS (MSCKF) structureIMU propagation extends the state, a camera clone is added at each image. Feature tracks that end yield residuals that are projected into the null space of the feature Jacobian and used to update the filter, without adding the feature to the state. Old clones are marginalised. Optional SLAM features and calibration states are kept in the state.PropagateIMUClone posewindowNull-space updatefeatures eliminatedMarginaliseold clonesCalibrationextrinsics, tda filter with the efficiency of eliminating features
The MSCKF loop.
Animation of the multi-state constraint Kalman filter. As the camera moves along a path, a window of past camera poses is kept as clones. A feature in the scene is tracked from several clones, and the rays from those poses intersect at the feature; when the feature leaves the view, it is triangulated from all the rays and the geometric constraint updates the clone poses without adding the feature to the state. The oldest clone is then dropped, so the state size stays constant, and the triangulation error is printed.
MSCKF/OpenVINS: the state holds the IMU state plus NN camera-pose clones; features are not in the state. When a track ends, the feature is triangulated from all clones that saw it and the resulting residual (projected away from the feature position) updates the clones. Illustrative planar geometry with 0.5∘0.5^{\circ} bearing noise. (Looping, about 6 seconds; drawn and computed for this course with illustrative values.)

Engineering intuition

A feature seen from several camera poses gives more residual equations than the 3 unknowns of its position. Three combinations of the residuals can be used to solve for the feature; the remaining combinations do not depend on the feature’s position at all: they constrain only the camera poses. Projecting onto those combinations gives clean, feature-independent constraints on the window, at a cost linear in the number of features. That is the MSCKF trick. Consistency then depends on evaluating the Jacobians at the first estimates of the states, which keeps the unobservable directions (global position and yaw) correctly unobservable (lesson M3-T12).

Mathematical formulation

For one feature with nn observations, the stacked linearised residual is:

Null-space projection
r≈Hx δx+Hf δpf+n,Hf∈R2n×3\mathbf r \approx \mathbf H_x\,\delta\mathbf x + \mathbf H_f\,\delta\mathbf p_f + \mathbf n, \qquad \mathbf H_f \in \mathbb R^{2n\times 3}
N=left null space of Hf(N⊤Hf=0)\mathbf N = \text{left null space of } \mathbf H_f \quad(\mathbf N^{\top}\mathbf H_f = \mathbf 0)
The feature error drops out
N⊤r=N⊤Hx δx+N⊤n\mathbf N^{\top}\mathbf r = \mathbf N^{\top}\mathbf H_x\,\delta\mathbf x + \mathbf N^{\top}\mathbf n

The projected residual no longer depends on the feature error δpf\delta p_{f} and gives a measurement update on the state only. The projected noise covariance is N⊤N^{\top}RN. NN has 2n − 3 columns, so a feature seen nn times contributes 2n − 3 independent constraints. First-estimate Jacobians: the linearisation of HxH_{x} uses the first estimate of each state variable rather than the latest, preserving the filter’s unobservable subspace.

HxH_{x}
Jacobian of the residual with respect to the filter state (cloned poses and calibration).
HfH_{f}
Jacobian with respect to the feature position.
NN
basis of the left null space of HfH_{f}.

Architecture and data flow

OpenVINS provides ROS 1 and ROS 2 interfaces and a configuration directory with an estimator YAML, a camera/IMU calibration YAML and an IMU noise YAML. Check the documentation pages “Getting started” and “Configuration” for the current names; the keys that matter are the camera intrinsics and extrinsics, the IMU noise densities and random walks (lesson M3-T7), the options calib_cam_extrinsics, calib_cam_timeoffset and calib_cam_intrinsics, the number of tracked features, the window size (max_clones) and the SLAM feature settings.

# estimator config excerpt (key names as in the OpenVINS documentation; verify for your version)
use_fej: true                 # first-estimate Jacobians
calib_cam_extrinsics: true    # estimate camera-IMU extrinsics online
calib_cam_timeoffset: true    # estimate camera-IMU time offset online
max_clones: 11                # size of the sliding window of camera poses
num_pts: 200                  # tracked features per frame
max_slam: 50                  # long-lived SLAM features kept in the state
Names and defaults vary between releases: use the documentation for your version.

Real-world UAV applications

  • Filter-based VIO for Capstone 1 and a comparison with optimisation-based systems.
  • Online calibration of camera-IMU extrinsics and time offset.
  • Embedded platforms where a filter’s predictable cost matters.
  • Teaching consistency and observability.

Implementation example

This runs as shown: for a feature seen from 5 poses, the left null space of its Jacobian is computed; the projected residual has 2n−3=72n-3=7 independent components and is unchanged when the feature position error changes.

import numpy as np
rng = np.random.default_rng(2)
n = 5                                                               # the feature is observed from n camera poses
Hf = rng.standard_normal((2 * n, 3))                                # feature Jacobian (2n x 3): stands for dproj/dp_f
Hx = rng.standard_normal((2 * n, 12))                               # Jacobian wrt 2 cloned poses worth of states (illustrative size)

U, s, Vt = np.linalg.svd(Hf, full_matrices=True)
N = U[:, 3:]                                                        # left null space of Hf: 2n x (2n - 3)
assert N.shape == (2 * n, 2 * n - 3) and np.allclose(N.T @ Hf, 0, atol=1e-12)

dx = rng.standard_normal(12) * 0.01; dpf_a = rng.standard_normal(3) * 0.2; dpf_b = rng.standard_normal(3) * 0.2     # two different feature position errors
r = lambda dpf: Hx @ dx + Hf @ dpf
proj_a, proj_b = N.T @ r(dpf_a), N.T @ r(dpf_b)
print("projected residual dimension:", len(proj_a), "(2n - 3 =", 2 * n - 3, ")  difference between two feature errors:", np.abs(proj_a - proj_b).max())
assert np.allclose(proj_a, proj_b, atol=1e-12) and not np.allclose(r(dpf_a), r(dpf_b))      # the feature error disappears only after projection

R = 0.5 ** 2 * np.eye(2 * n); Rp = N.T @ R @ N                                           # projected noise stays white for white input
assert np.allclose(Rp, 0.25 * np.eye(2 * n - 3), atol=1e-12)
MSCKF null-space projection: feature-independent constraints on the poses.

Common engineering mistakes

Disabling first-estimate Jacobians without understanding the effect

The filter gains false information about yaw and becomes overconfident.

Online calibration without excitation

Extrinsics and time offset do not converge, or converge wrongly.

Using default noise parameters from an example

Weights depend on your IMU (lesson M3-T7).

Too small a window for the motion

Features lose their baseline and the update weakens.

Assuming a filter and an optimiser behave identically

Their consistency and cost characteristics differ.

Failure modes

Failure modes, symptoms and causes
Failure modeHow it shows upLikely cause
Overconfident yawYaw covariance shrinks with no heading sourceFEJ off or a bug in the Jacobians
Calibration divergenceExtrinsics wanderPoor initial guess, no excitation
Initialisation failureEstimate absentStationary start or low texture
High CPUFrame dropsToo many features or SLAM features for the platform

Debugging approach

  1. Run with ground truth and NEES (lesson M3-T15) to check consistency.
  2. Plot estimated calibration states over time.
  3. Check feature counts and tracking quality.
  4. Profile CPU against num_pts and max_slam.

Practical exercises

  1. Show that 2n − 3 constraints result from nn observations.
  2. Compute the null-space projection for n=3n=3 and verify the dimension.
  3. Run OpenVINS on EuRoC with and without online time-offset calibration and compare.
  4. Read the OpenVINS documentation page on FEJ and summarise it in three sentences.

Interview questions

Write an answer in your own words, then reveal the model answer. Nothing is sent anywhere.

Question 1

What is the MSCKF trick?

Model answer

Project the feature residual into the left null space of the feature Jacobian so the update constrains only the camera poses and the feature never enters the state.

Question 2

Why first-estimate Jacobians?

Model answer

Linearising at the first estimate keeps the filter’s unobservable subspace (global position and yaw) intact, avoiding spurious information and inconsistency.

Question 3

What can OpenVINS calibrate online?

Model answer

Camera–IMU extrinsics, time offset and camera intrinsics, given enough excitation and a reasonable initial guess.

References and further reading

Primary papers, official documentation and standards. Each claim above that is specific to a tool or version points here.

What’s next

Mark this lesson

Saved in this browser and synced to your account when you are signed in.

Next lesson

M4-T6: LiDAR SLAM

Compare feature-based and direct LiDAR SLAM methods and the sensors and scenes each suits.