A zero-velocity update (ZUPT) allows OpenVINS to exploit knowledge that the sensor platform is momentarily stationary. Rather than attempting to triangulate features or track visual motion during a standstill — which is unreliable in monocular systems and vulnerable to dynamic objects — the system instead inserts a synthetic measurement that asserts zero acceleration and zero angular velocity. This soft constraint corrects bias estimates, prevents velocity drift, and keeps the filter consistent during periods where visual odometry would otherwise degrade.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/rpng/open_vins/llms.txt
Use this file to discover all available pages before exploring further.
What ZUPT Is and When It Applies
A ZUPT does not rigidly enforce zero velocity. Instead, it creates a synthetic observation of zero true acceleration and zero true angular rate, and updates the filter with that observation weighted by the expected measurement uncertainty. The result is a probabilistic constraint: if the IMU readings are consistent with being stationary, the filter is nudged toward zero velocity; if the readings are noisy or the threshold is not met, no update occurs. ZUPT is especially valuable in two scenarios:Monocular VIO at Stop Lights
A wheeled vehicle stopped at a traffic light cannot triangulate features (no baseline change). Dynamic objects crossing the intersection corrupt feature tracks. ZUPT suppresses feature updates entirely and maintains state quality using only the inertial zero-velocity constraint.
Initialization Phases
During the first few seconds of operation, when the sliding window has too few clones for reliable triangulation, ZUPT can stabilize the IMU bias estimates and prevent early divergence.
The ZUPT Measurement Model
The synthetic measurement asserts that the true linear acceleration and angular velocity are zero: Relating these to the IMU readings via the sensor model: The measurement residual is formed by subtracting the expected measurement from the synthetic “observation” of zero: The measurement Jacobians with respect to the relevant state variables are: The residual and its Jacobians are then used in a standard EKF update, directly constraining the orientation (through the gravity rotation term), accelerometer bias, and gyroscope bias.Stationary Detection
Two complementary detection methods determine whether a ZUPT update should be applied at each timestep.Disparity-Based Detection
Given two consecutive images, if the average pixel displacement of tracked feature points is below a threshold , the scene is assumed stationary: This is fast and simple, but fails in dynamic environments where background features are static while other objects move (e.g., a car at a stop light with pedestrians crossing). The parameterzupt_max_disparity controls .
IMU-Based Detection
The ZUPT residual itself is used as a test statistic. The normalized squared residual follows a distribution under the zero-velocity hypothesis: where is the noise inflation multiplier (zupt_noise_multiplier). In practice, the IMU noise matrix must be inflated by a factor of for reliable detection. This large multiplier reflects either over-optimistic noise specifications in the IMU datasheet or additional vibrations (motor noise, road vibration) that are not captured by the nominal noise model.
Configuration Parameters
ZUPT is configured in the OpenVINS YAML parameter file. The relevant parameters are:| Parameter | Type | Description |
|---|---|---|
try_zupt | bool | Enable or disable the zero-velocity update. Set to true to activate ZUPT. |
zupt_max_velocity | double (m/s) | Maximum velocity magnitude below which a ZUPT is considered. Prevents false detections at constant velocity. Typical value: 0.1–1.0 m/s. |
zupt_noise_multiplier | double | Multiplier applied to the IMU noise matrix in the test. Typical range: 50–100. |
zupt_max_disparity | double (pixels) | Maximum average feature disparity (in pixels) for the visual detection check. Typical value: 0.5–2.0 px. |
zupt_only_at_beginning | bool | If true, ZUPT is only applied during the first few seconds after initialization. Useful for recovering stable biases at startup without interfering with normal operation. |
Example YAML Configuration
The UpdaterZeroVelocity Class
UpdaterZeroVelocity (ov_msckf/src/update/UpdaterZeroVelocity.h) implements the full detection and update pipeline.
try_update() proceeds as follows:
- Velocity check: if the current velocity estimate exceeds
zupt_max_velocity, returnfalseimmediately. - Disparity check: compute the average feature disparity from the feature database; if it exceeds
zupt_max_disparity, returnfalse. - Build residual: form and from the most recent IMU readings.
- Chi-squared test: evaluate the normalized residual; reject if above the 95th-percentile threshold.
- EKF update: apply the standard Kalman update with the ZUPT residual and Jacobians.
- Return
trueto signal that a ZUPT was applied (the caller can skip feature-based update for this frame).
When
try_update() returns true, the main VIO pipeline in VioManager skips the normal MSCKF feature update for that timestamp. This prevents stale or dynamic-object-corrupted feature tracks from fighting against the zero-velocity constraint.