Skip to main content

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.

OpenVINS uses a 6-axis IMU as the backbone of its Extended Kalman Filter (EKF), propagating a 15-dimensional inertial state forward between camera frames. Each incoming IMU reading — a raw angular rate and a raw linear acceleration — is de-biased and integrated to evolve the orientation, position, velocity, and sensor biases in time. Two integration strategies are supported: a straightforward discrete model that is easy to understand and implement, and a full continuous-time analytical model that additionally accommodates IMU intrinsic calibration parameters such as scale factors, axis misalignments, and gyroscope gravity sensitivity.

IMU Measurement Model

A 6-axis MEMS IMU reports measurements of the local angular rate Iωm{}^I\boldsymbol{\omega}_m and local linear acceleration Iam{}^I\mathbf{a}_m in the IMU body frame {I}\{I\}. Both channels are corrupted by an additive slowly-drifting bias and white Gaussian noise: Iωm(t)=Iω(t)+bg(t)+ng(t){}^I\boldsymbol{\omega}_m(t) = {}^I\boldsymbol{\omega}(t) + \mathbf{b}_{g}(t) + \mathbf{n}_{g}(t) Iam(t)=Ia(t)+GIR(t)Gg+ba(t)+na(t){}^I\mathbf{a}_m(t) = {}^I\mathbf{a}(t) + {}^I_G\mathbf{R}(t)\,{}^G\mathbf{g} + \mathbf{b}_{a}(t) + \mathbf{n}_{a}(t) where Iω{}^I\boldsymbol{\omega} and Ia{}^I\mathbf{a} are the true angular velocity and linear acceleration, bg\mathbf{b}_g and ba\mathbf{b}_a are the gyroscope and accelerometer biases, ng\mathbf{n}_g and na\mathbf{n}_a are zero-mean white Gaussian noise processes, Gg=[0 0 9.81]{}^G\mathbf{g} = [0\ 0\ 9.81]^\top is gravity expressed in the global frame {G}\{G\}, and GIR{}^I_G\mathbf{R} rotates vectors from the global frame into the IMU frame. For IMUs with significant scale/axis imperfections (MEMS models in particular), OpenVINS also supports an extended intrinsic model that introduces separate gyroscope and accelerometer sensor frames {w}\{w\} and {a}\{a\}: wωm(t)=TwIwRIω(t)+TgIa(t)+bg(t)+ng(t){}^w\boldsymbol{\omega}_{m}(t) = \mathbf{T}_{w}\,{}^w_I\mathbf{R}\,{}^I\boldsymbol{\omega}(t) + \mathbf{T}_{g}\,{}^I\mathbf{a}(t) + \mathbf{b}_g(t) + \mathbf{n}_g(t) aam(t)=TaIaR(Ia(t)+GIR(t)Gg)+ba(t)+na(t){}^a\mathbf{a}_{m}(t) = \mathbf{T}_a\,{}^a_I\mathbf{R}\bigl({}^I\mathbf{a}(t) + {}^I_G\mathbf{R}(t)\,{}^G\mathbf{g}\bigr) + \mathbf{b}_a(t) + \mathbf{n}_a(t) Here Tw\mathbf{T}_w and Ta\mathbf{T}_a are invertible 3×33\times3 scale/misalignment matrices, and Tg\mathbf{T}_g models the gravity sensitivity of the gyroscope (its response to linear acceleration due to inherent inertia).
Calibrating IMU intrinsics introduces many additional degrees of freedom and requires trajectories with sufficient excitation (e.g. dynamic handheld motion). Planar, single-axis, or constant-measurement trajectories can lead to degenerate calibrations. OpenVINS recommends performing intrinsic calibration offline unless your platform is guaranteed to have rich, multi-axis motion.

Inertial State Vector

The inertial navigation state xI\mathbf{x}_I at time tt is a 16-dimensional vector (parameterized as a 15-dimensional error state): xI(t)=[GIqˉ(t)GpI(t)GvI(t)bg(t)ba(t)]\mathbf{x}_I(t) = \begin{bmatrix} {}^I_G\bar{q}(t) \\ {}^G\mathbf{p}_I(t) \\ {}^G\mathbf{v}_I(t) \\ \mathbf{b}_{g}(t) \\ \mathbf{b}_{a}(t) \end{bmatrix}
SymbolDimensionMeaning
GIqˉ{}^I_G\bar{q}4 (unit quaternion)Rotation from global frame {G}\{G\} to IMU frame {I}\{I\} (JPL convention)
GpI{}^G\mathbf{p}_I3Position of IMU origin in the global frame
GvI{}^G\mathbf{v}_I3Velocity of IMU in the global frame
bg\mathbf{b}_g3Gyroscope bias
ba\mathbf{b}_a3Accelerometer bias
OpenVINS uses the JPL quaternion convention with a left multiplicative quaternion error: GIqˉ=δqˉGIqˉ^,δqˉ[12θ~1]{}^I_G\bar{q} = \delta\bar{q} \otimes {}^I_G\hat{\bar{q}}, \qquad \delta\bar{q} \simeq \begin{bmatrix}\frac{1}{2}\tilde{\boldsymbol{\theta}} \\ 1\end{bmatrix} where θ~R3\tilde{\boldsymbol{\theta}} \in \mathbb{R}^3 is the small-angle orientation error vector. All other states use standard additive error. This yields a 15-dimensional error state x~I\tilde{\mathbf{x}}_I despite the 16-element quaternion parameterization.

IMU Kinematic Equations

The continuous-time differential equations governing IMU state evolution are: GIqˉ˙(t)=12Ω(Iω(t))GItqˉ{}^I_G\dot{\bar{q}}(t) = \frac{1}{2}\boldsymbol{\Omega}({}^I\boldsymbol{\omega}(t))\,{}^{I_t}_G\bar{q} Gp˙I(t)=GvI(t){}^G\dot{\mathbf{p}}_I(t) = {}^G\mathbf{v}_I(t) Gv˙I(t)=GItRIa(t){}^G\dot{\mathbf{v}}_I(t) = {}^{I_t}_G\mathbf{R}^\top\,{}^I\mathbf{a}(t) b˙g(t)=nwg(t),b˙a(t)=nwa(t)\dot{\mathbf{b}}_g(t) = \mathbf{n}_{wg}(t), \qquad \dot{\mathbf{b}}_a(t) = \mathbf{n}_{wa}(t) where Ω(ω)=[ω×ωω0]\boldsymbol{\Omega}(\boldsymbol{\omega}) = \begin{bmatrix} -\lfloor\boldsymbol{\omega}\times\rfloor & \boldsymbol{\omega} \\ -\boldsymbol{\omega}^\top & 0\end{bmatrix} is the quaternion rate matrix, and the biases evolve as random walks driven by white Gaussian process noises nwg\mathbf{n}_{wg} and nwa\mathbf{n}_{wa}.

Integration Strategies

Given the kinematic equations above, the state mean must be numerically integrated between IMU timestamps. OpenVINS provides two integration approaches. Both compute the state transition matrix Φ(tk+1,tk)\boldsymbol{\Phi}(t_{k+1},t_k) and noise Jacobian Gk\mathbf{G}_k, then propagate the covariance as: Pk+1k=Φ(tk+1,tk)PkkΦ(tk+1,tk)+GkQdGk\mathbf{P}_{k+1|k} = \boldsymbol{\Phi}(t_{k+1},t_k)\,\mathbf{P}_{k|k}\,\boldsymbol{\Phi}(t_{k+1},t_k)^\top + \mathbf{G}_k\,\mathbf{Q}_d\,\mathbf{G}_k^\top
The discrete model assumes each IMU measurement is constant over its sampling interval Δtk=tk+1tk\Delta t_k = t_{k+1} - t_k. This is a zero-order hold (ZOH) approximation.Quaternion propagation uses the matrix-exponential form of the constant-rate assumption:GIk+1qˉ^=exp ⁣(12Ω(ω^k)Δtk)GIkqˉ^{}^{I_{k+1}}_G\hat{\bar{q}} = \exp\!\Bigl(\tfrac{1}{2}\boldsymbol{\Omega}(\hat{\boldsymbol{\omega}}_k)\Delta t_k\Bigr)\,{}^{I_k}_G\hat{\bar{q}}where ω^k=ωm,kb^g,k\hat{\boldsymbol{\omega}}_k = \boldsymbol{\omega}_{m,k} - \hat{\mathbf{b}}_{g,k} is the bias-corrected angular rate.Position and velocity are updated assuming constant acceleration in the current body frame:Gp^Ik+1=Gp^Ik+Gv^IkΔtk12GgΔtk2+12GIkR^a^kΔtk2{}^G\hat{\mathbf{p}}_{I_{k+1}} = {}^G\hat{\mathbf{p}}_{I_k} + {}^G\hat{\mathbf{v}}_{I_k}\Delta t_k - \tfrac{1}{2}{}^G\mathbf{g}\Delta t_k^2 + \tfrac{1}{2}{}^{I_k}_G\hat{\mathbf{R}}^\top\hat{\mathbf{a}}_k\Delta t_k^2Gv^k+1=Gv^IkGgΔtk+GIkR^a^kΔtk{}^G\hat{\mathbf{v}}_{k+1} = {}^G\hat{\mathbf{v}}_{I_k} - {}^G\mathbf{g}\Delta t_k + {}^{I_k}_G\hat{\mathbf{R}}^\top\hat{\mathbf{a}}_k\Delta t_kBiases propagate as pure random walks:b^g,k+1=b^g,k,b^a,k+1=b^a,k\hat{\mathbf{b}}_{g,k+1} = \hat{\mathbf{b}}_{g,k}, \qquad \hat{\mathbf{b}}_{a,k+1} = \hat{\mathbf{b}}_{a,k}The discrete noise covariance is converted from the continuous-time noise spectral density:Qmeas=[σgc2ΔtI300σac2ΔtI3],Qbias=[Δtσwgc2I300Δtσwac2I3]\mathbf{Q}_{meas} = \begin{bmatrix} \frac{\sigma_{g_c}^2}{\Delta t}\mathbf{I}_3 & \mathbf{0} \\ \mathbf{0} & \frac{\sigma_{a_c}^2}{\Delta t}\mathbf{I}_3\end{bmatrix}, \quad \mathbf{Q}_{bias} = \begin{bmatrix} \Delta t\,\sigma_{wg_c}^2\mathbf{I}_3 & \mathbf{0} \\ \mathbf{0} & \Delta t\,\sigma_{wa_c}^2\mathbf{I}_3\end{bmatrix}The 15×15 state transition matrix Φ\boldsymbol{\Phi} is constructed by perturbing each state variable and collecting first-order terms. It captures how orientation error propagates into position and velocity errors through the estimated acceleration.
The discrete model is simpler to implement and is the right starting point for understanding OpenVINS propagation. It does not include IMU intrinsic calibration parameters.

First-Estimate Jacobians (FEJ) for Consistency

A standard EKF linearizes about the current (post-update) state estimate at each step. Because a visual-inertial system has 4 unobservable degrees of freedom — absolute yaw and 3D global translation — linearizing about an ever-changing estimate causes the observability matrix to gain spurious rank along the yaw direction, leading to filter over-confidence (estimated uncertainty smaller than true uncertainty) and degraded accuracy. First-Estimate Jacobians (FEJ) resolve this by evaluating all Jacobians at a fixed, per-state linearization point:
  • Propagation: The state transition matrix Φ(tk+1,tk)\boldsymbol{\Phi}(t_{k+1},t_k) is evaluated using the pre-update (predicted) state rather than the post-update state. This preserves the semi-group property Φ(tk+1,tk1)=Φ(tk+1,tk)Φ(tk,tk1)\boldsymbol{\Phi}(t_{k+1},t_{k-1}) = \boldsymbol{\Phi}(t_{k+1},t_k)\boldsymbol{\Phi}(t_k,t_{k-1}).
  • Update: The measurement Jacobian Hk\mathbf{H}_k for a feature is computed at the feature’s initial triangulated estimate (not its current estimate) for all subsequent updates.
In the analytical model, applying FEJ means replacing the integrated increments with expressions computed from the current and previous state estimates: ΔR^k=GIk+1R^(GIkR^)\Delta\hat{\mathbf{R}}_k = {}^{I_{k+1}}_G\hat{\mathbf{R}}\,({}^{I_k}_G\hat{\mathbf{R}})^\top Δp^k=GIkR^(Gp^Ik+1Gp^IkGv^IkΔtk+12GgΔtk2)\Delta\hat{\mathbf{p}}_k = {}^{I_k}_G\hat{\mathbf{R}}\Bigl({}^G\hat{\mathbf{p}}_{I_{k+1}} - {}^G\hat{\mathbf{p}}_{I_k} - {}^G\hat{\mathbf{v}}_{I_k}\Delta t_k + \tfrac{1}{2}{}^G\mathbf{g}\Delta t_k^2\Bigr) This guarantees the correct 4-dimensional unobservable nullspace and prevents the filter from falsely gaining information along the global yaw direction.

The Propagator Class

The Propagator class (ov_msckf/src/state/Propagator.h) implements the IMU propagation pipeline. Inputs:
  • A stream of ImuData messages (timestamp, angular rate ωm\boldsymbol{\omega}_m, linear acceleration am\mathbf{a}_m) fed via feed_imu().
  • A NoiseManager struct holding the continuous-time noise spectral densities (σg\sigma_g, σa\sigma_a, σwg\sigma_{wg}, σab\sigma_{ab}).
  • A gravity magnitude scalar (normally 9.81 m/s²).
Key methods:
MethodDescription
feed_imu(message, oldest_time)Appends a new IMU reading to the internal buffer and trims measurements older than oldest_time.
propagate_and_clone(state, timestamp)Collects all IMU readings since the last state time, integrates the mean and covariance step-by-step, then clones the current IMU pose into the sliding window.
fast_state_propagate(state, timestamp, state_plus, cov)Propagates a copy of the IMU state to an arbitrary future timestamp without modifying the filter state — used to provide high-frequency pose outputs between camera updates.
select_imu_readings(...)Static helper that extracts and (linearly) interpolates IMU readings in a given time window.
Propagator maintains a cache that is invalidated after each EKF update. Subsequent calls to fast_state_propagate re-use a cached propagated state when possible to minimize redundant computation.

Build docs developers (and LLMs) love