Openvins学习---ov_msckf中的State
StateOptions.h
State.h是 OpenVINS 框架中 MSCKF(多状态约束卡尔曼滤波)算法的核心配置结构体定义,通过StateOptions结构体统一管理滤波参数、校准选项、特征表示等关键配置,同时提供从 YAML 文件读取配置和打印调试信息的功能,是算法模块化与可配置性的核心实现。
1、关键依赖
LandmarkRepresentation.h:定义特征点的表示方式(如全局 3D 坐标、逆深度等)。opencv_yaml_parse.h:提供 YAML 配置文件的解析能力,支持从外部文件加载参数。print.h/sensor_data.h:分别用于调试信息打印和传感器数据处理辅助。
2. 核心配置模块解析
StateOptions结构体的配置项可分为 5 大类,覆盖 MSCKF 算法的核心参数:
(1)滤波基础配置
| 配置项 | 作用 | 默认值 | 
|---|---|---|
| do_fej | 是否启用首次估计雅可比(FEJ),FEJ 可减少线性化误差,提升滤波稳定性 | true | 
| integration_method | IMU 数据的积分方式(离散积分、RK4 四阶龙格 - 库塔、解析积分),RK4 精度更高,适用于大多数场景 | RK4 | 
| max_clone_size | 滑动窗口的最大 “克隆” 数量(即窗口内保留的历史位姿状态数),影响滤波计算量与精度平衡 | 11 | 
(2)传感器校准选项
控制是否对相机与 IMU 的内外参、时间偏移进行在线校准,按需开启可提升系统适应能力(如硬件安装误差较大时):
- do_calib_camera_pose:是否校准相机 - IMU 外参(两者间的位置与姿态关系)。
- do_calib_camera_intrinsics:是否校准相机内参(如焦距、畸变系数)。
- do_calib_camera_timeoffset:是否校准相机与 IMU 的时间偏移(硬件同步误差)。
- do_calib_imu_intrinsics:是否校准IMU 内参(如 gyro/accelerometer 零偏、比例因子)。
- do_calib_imu_g_sensitivity:是否校准IMU 重力敏感度(IMU 输出受重力方向影响的系数)。
(3)IMU 模型配置
定义 IMU 内参的建模方式,匹配不同的 IMU 校准数据格式:
- 枚举ImuModel:支持KALIBR(兼容 Kalibr 校准工具输出)和RPNG(另一种 IMU 误差模型)。
- 默认值为KALIBR,是视觉惯性校准领域的常用格式;若选择calibrated(已校准)模式,则禁止开启 IMU 内参校准(避免逻辑冲突)。
(4)特征点管理配置
控制不同类型特征点(MSCKF 特征、SLAM 特征、ARUCO 标签)的数量与更新规则:
- max_slam_features:SLAM 特征点的最大估计数量(SLAM 特征需长期跟踪,数量影响内存与计算量)。
- max_slam_in_update/- max_msckf_in_update:单次 EKF 更新中允许使用的 SLAM/MSCKF 特征点数量上限,防止单帧特征过多导致计算超时。
- max_aruco_features:ARUCO 标签的最大估计数量(ARUCO 常用于已知尺寸的人工标记,辅助定位)。
- num_cameras:系统使用的相机数量(支持单目、双目等多相机配置)。
(5)特征点表示方式
通过LandmarkRepresentation::Representation枚举,定义不同特征点的坐标表示格式(影响观测模型与计算效率):
- 默认均为GLOBAL_3D(全局坐标系下的 3D 坐标),适用于大多数场景。
- 其他可选类型(未在默认值中体现)包括ANCHORED_MSCKF(锚定在某帧的逆深度)、ANCHORED_INVERSE_DEPTH(逆深度表示,适用于单目初始化)等,需根据相机类型(单目 / 双目)选择。
3、StateOptions配置项与 YAML 文件对应关系表
该表清晰梳理了StateOptions结构体中每个配置项的含义、默认值,以及在 YAML 配置文件中对应的字段名,方便快速查询和修改参数。
| 分类 | StateOptions配置项 | 核心含义 | 默认值 | YAML 文件对应字段 | 备注 | 
|---|---|---|---|---|---|
| 滤波基础 | do_fej | 是否启用首次估计雅可比(FEJ),减少线性化误差 | true | use_fej | 布尔值(true/false),建议默认启用 | 
| integration_method | IMU 数据积分方式 | RK4 | integration | 字符串选项: discrete(离散)、rk4(四阶龙格 - 库塔)、analytical(解析) | |
| max_clone_size | 滑动窗口最大 “克隆” 数(窗口内历史位姿数量) | 11 | max_clones | 整数,需平衡计算量与定位精度,通常设 5-15 | |
| 传感器校准 | do_calib_camera_pose | 是否校准相机 - IMU 外参(位置 + 姿态) | false | calib_cam_extrinsics | 硬件安装误差大时建议启用 | 
| do_calib_camera_intrinsics | 是否校准相机内参(焦距、畸变等) | false | calib_cam_intrinsics | 相机未提前标定或环境温度变化大时启用 | |
| do_calib_camera_timeoffset | 是否校准相机与 IMU 的时间偏移 | false | calib_cam_timeoffset | 硬件未做时间同步时建议启用 | |
| do_calib_imu_intrinsics | 是否校准 IMU 内参(零偏、比例因子等) | false | calib_imu_intrinsics | IMU 精度低或未提前标定时启用 | |
| do_calib_imu_g_sensitivity | 是否校准 IMU 重力敏感度 | false | calib_imu_g_sensitivity | 对重力敏感的 IMU(如低成本 MEMS)建议启用 | |
| IMU 模型 | imu_model | IMU 内参建模格式 | KALIBR | 外层 relative_config_imu下的imu0.model | 字符串选项: kalibr(兼容 Kalibr 工具)、rpng;选calibrated则禁止 IMU 校准 | 
| 特征管理 | max_slam_features | SLAM 特征点最大估计数量 | 25 | max_slam | 整数,数量过多会增加内存占用,建议 20-50 | 
| max_slam_in_update | 单次 EKF 更新允许的 SLAM 特征数上限 | 1000 | max_slam_in_update | 防止单帧特征过多导致计算超时,按需调整 | |
| max_msckf_in_update | 单次 EKF 更新允许的 MSCKF 特征数上限 | 1000 | max_msckf_in_update | 作用同 SLAM 特征上限,通常与 SLAM 上限一致 | |
| max_aruco_features | ARUCO 标签最大估计数量 | 1024 | num_aruco | 整数,ARUCO 标签为人工标记,数量通常较少 | |
| num_cameras | 系统使用的相机数量 | 1 | max_cameras | 支持单目(1)、双目(2)等多相机配置 | |
| 特征表示 | feat_rep_msckf | MSCKF 特征点的坐标表示方式 | GLOBAL_3D | feat_rep_msckf | 字符串选项: global_3d、anchored_msckf(逆深度)等 | 
| feat_rep_slam | SLAM 特征点的坐标表示方式 | GLOBAL_3D | feat_rep_slam | 选项同 MSCKF 特征,单目建议用 anchored_inverse_depth | |
| feat_rep_aruco | ARUCO 标签的坐标表示方式 | 
StateHelper.h
这个文件是 OpenVINS 框架中核心的状态管理工具类头文件,封装了基于扩展卡尔曼滤波(EKF)的状态与协方差操作,是视觉惯性里程计(VIO)实现的关键模块。StateHelper类通过静态方法提供所有操作,无需实例化即可调用。其核心作用是统一管理State对象(存储系统状态,如 IMU 位姿、特征点等)及其协方差矩阵,覆盖 EKF 从初始化、 propagation(预测)、update(更新)到 marginalization(边缘化)的全流程。
1、关键方法分类与作用
根据功能可分为 6 大类,涵盖 EKF 完整生命周期操作:
(1)EKF 核心流程操作
- EKFPropagation:状态协方差预测。在状态均值已完成时间更新后,根据状态转移矩阵- Phi和过程噪声- Q,将协方差矩阵向前传播。
- EKFUpdate:状态协方差更新。利用观测雅克比矩阵- H、观测残差- res和观测噪声- R,执行 EKF 的测量更新步骤,修正状态及协方差。
(2)协方差初始化与获取
- set_initial_covariance:初始化状态协方差。根据指定的变量顺序- order,将输入的协方差矩阵- covariance赋值给- State,并确保交叉协方差正确插入。
- get_marginal_covariance:获取局部协方差。提取指定变量集合(如部分特征点)的边际协方差,用于更新前的卡方检验(无需完整协方差,提升效率)。
- get_full_covariance:获取完整协方差。返回整个系统状态的协方差矩阵副本,仅推荐用于仿真,实际运行中操作完整矩阵效率低。
(3)状态边缘化(Marginalization)
边缘化是 VIO 中控制状态维度、避免计算量爆炸的关键技术,该类提供 3 种边缘化能力:
- marginalize:通用变量边缘化。移除指定变量(如旧 IMU 位姿),并同步调整协方差矩阵维度与剩余变量的 ID,确保后续操作索引正确。
- marginalize_old_clone:旧克隆态边缘化。当系统中 IMU 位姿 “克隆态”(用于多帧视觉约束)数量超过上限时,边缘化最旧的克隆态,维持状态维度稳定。
- marginalize_slam:SLAM 特征点边缘化。移除失效或异常的 SLAM 特征点,清理无效状态变量。
(4)状态克隆(Clone)
- clone:克隆状态变量。将指定变量(如当前 IMU 位姿)复制一份并添加到协方差矩阵末尾,用于构建多帧约束(如 MSCKF 中的关键帧位姿)。
- augment_clone:增强型克隆(IMU-Camera 时间偏移适配)。克隆当前 IMU 位姿时,考虑 IMU 与相机的时间偏移误差,根据角速度- last_w和速度计算偏移对克隆态的影响,确保时间同步精度。
(5)新状态初始化
针对未观测过的新变量(如新增特征点),提供两种初始化方式:
- initialize:通用状态初始化。当观测雅克比- H_L(对新变量的雅克比)非方阵 / 不可逆时,通过 Givens 旋转分离更新与初始化系统,需输入各向同性的观测噪声- R。
- initialize_invertible:可逆雅克比初始化。当- H_L为方阵且可逆时,直接通过观测更新初始化新变量,流程更简洁。
(6) 构造函数(私有)
- StateHelper():私有默认构造函数。强制该类只能通过静态方法调用,无法创建实例,确保状态操作的统一性和安全性。
State.h
这个文件是 OpenVINS 框架中核心的状态容器类State的头文件,它整合了StateOptions配置、所有待估计的系统状态(如 IMU 位姿、特征点、传感器校准参数)及协方差矩阵,是 EKF 滤波流程中状态数据的 “统一存储中心”。
1、核心定位与设计逻辑
State类的核心是 “按配置存储状态”:通过构造函数接收StateOptions对象,根据配置动态初始化需要估计的状态变量(如是否创建 IMU 内参校准变量、是否保留 SLAM 特征点),同时封装协方差矩阵的存储与基础访问接口,确保状态数据的安全性与一致性(通过互斥锁)。
它与StateHelper是 “数据与操作分离” 的设计:State只负责 “存数据”,StateHelper负责 “操作数据”(如协方差预测、边缘化),通过友元类机制允许StateHelper访问State的私有成员(如_Cov协方差矩阵),既保证封装性,又避免冗余代码。
2、关键成员解析(按功能分类)
(1)线程安全与时间戳
| 成员变量 | 类型 | 核心作用 | 
|---|---|---|
| _mutex_state | std::mutex | 状态互斥锁:防止多线程(如 IMU 预测线程、视觉更新线程)同时修改状态,避免数据竞争。 | 
| _timestamp | double | 当前状态时间戳:记录最后一次相机帧更新的时间(相机时钟下),用于时间同步。 | 
(2)配置与基础状态
| 成员变量 | 类型 | 核心作用 | 
|---|---|---|
| _options | StateOptions | 滤波器配置:存储从外部传入的所有配置(如是否校准相机外参、滑动窗口大小),决定状态初始化逻辑。 | 
| _imu | shared_ptr<IMU> | 活跃 IMU 状态:存储当前 IMU 的核心状态 —— 世界到 IMU 的旋转( q_GtoI)、IMU 在世界的位置(p_IinG)、IMU 速度(v_IinG)、gyro 零偏(bg)、accel 零偏(ba)。 | 
(3)滑动窗口与特征点(MSCKF 核心)
| 成员变量 | 类型 | 核心作用 | 
|---|---|---|
| _clones_IMU | map<double, PoseJPL> | IMU 克隆态:按时间戳升序存储历史 IMU 位姿(滑动窗口内),用于 MSCKF 的多帧视觉约束; map自动排序特性可快速获取最旧克隆态(用于边缘化)。 | 
| _features_SLAM | unordered_map<size_t, Landmark> | SLAM 特征点:以特征 ID 为键,存储世界坐标系下的 3D 特征点位置;数量由 _options.max_slam_features限制,超出则边缘化旧特征。 | 
(4)传感器校准参数(可选估计)
这些变量是否初始化,完全由_options中的配置决定(如do_calib_camera_pose=true才会创建_calib_IMUtoCAM):
| 成员变量 | 类型 | 核心作用 | 
|---|---|---|
| _calib_dt_CAMtoIMU | shared_ptr<Vec> | 相机 - IMU 时间偏移:存储 t_imu = t_cam + t_off中的t_off,用于时间同步校准。 | 
| _calib_IMUtoCAM | unordered_map<size_t, PoseJPL> | IMU - 相机外参:按相机 ID 存储每个相机相对于 IMU 的旋转( R_ItoC)和位置(p_IinC)。 | 
| _cam_intrinsics | unordered_map<size_t, Vec> | 相机内参:按相机 ID 存储内参参数(如焦距、畸变系数),支持多相机校准。 | 
| _calib_imu_dw/_da | shared_ptr<Vec> | IMU 内参:分别存储 gyro 和 accel 的尺度误差、轴偏差(6 维向量),用于 IMU 内参校准。 | 
| _calib_imu_tg | shared_ptr<Vec> | gyro 重力敏感度:9 维向量,存储 gyro 对重力变化的响应误差,用于高精度 IMU 校准。 | 
| _calib_imu_GYROtoIMU等 | shared_ptr<JPLQuat> | IMU 轴系校准:针对不同 IMU 模型( KALIBR/RPNG),存储 gyro 与 accel 之间的旋转关系。 | 
(5)协方差与变量列表(私有,仅StateHelper访问)
| 成员变量 | 类型 | 核心作用 | 
|---|---|---|
| _Cov | Eigen::MatrixXd | 状态协方差矩阵:存储所有状态变量的不确定性及交叉相关性,是 EKF 的核心数据;仅允许 StateHelper修改,避免直接操作导致的错误。 | 
| _variables | vector<shared_ptr<Type>> | 状态变量列表:按顺序存储所有状态变量,用于协方差矩阵的索引映射(如变量在列表中的位置对应协方差矩阵的行 / 列),确保 StateHelper能正确定位变量的协方差。 | 
3、关键方法解析
(1)状态管理方法
- margtimestep():获取下一个待边缘化的时间戳。遍历- _clones_IMU(按时间戳排序),返回最旧克隆态的时间戳,是滑动窗口 “淘汰旧状态” 的核心接口。
- max_covariance_size():返回当前协方差矩阵的维度(- _Cov的行数 / 列数),即所有状态变量的总维度,用于- StateHelper操作协方差前的尺寸校验。
(2)IMU 内参矩阵构造方法
- Dm():静态方法,将 6 维 IMU 内参向量(- _calib_imu_dw/- _da)转换为 3x3 内参矩阵。根据- ImuModel(- KALIBR/- RPNG)使用不同的填充方式(下三角 / 上三角),适配两种主流 IMU 内参模型。
- Tg():静态方法,将 9 维重力敏感度向量(- _calib_imu_tg)转换为 3x3 矩阵(按列填充),用于 IMU 重力敏感度校准的计算。
(3)误差状态维度计算
- imu_intrinsic_size():计算 IMU 内参相关的误差状态维度。若开启 IMU 内参校准(- do_calib_imu_intrinsics=true),基础维度为 15(gyro 6 维 + accel 6 维 + 轴系旋转 3 维);若额外开启重力敏感度校准,再加 9 维,用于- StateHelper构造状态转移矩阵时确定维度。
Propagator.h
这个文件是 OpenVINS 框架中核心的 IMU 状态传播类头文件,封装了基于 IMU 数据的状态均值与协方差预测逻辑,支持离散积分、RK4(四阶龙格 - 库塔)、解析积分三种数值方法,是视觉惯性里程计(VIO)中 “预测” 阶段的核心实现。
1、核心功能定位
Propagator类的核心作用是将系统状态从当前时间 “推进” 到目标时间:通过接收 IMU 原始数据(角速度、线加速度),结合 IMU 噪声模型与积分方法,更新State中的 IMU 状态(位姿、速度、零偏)及其协方差;同时支持状态克隆(用于 MSCKF 滑动窗口)和快速状态预测(用于高频位姿输出),是连接 IMU 数据与 EKF 预测步骤的关键模块。
2、关键成员与作用
(1) 数据存储与配置
| 成员变量 | 类型 | 核心作用 | 
|---|---|---|
| _noises | NoiseManager | 存储 IMU 噪声参数(如角速度噪声 sigma_w、零偏随机游走噪声sigma_wb),并预计算噪声平方(提升计算效率)。 | 
| _gravity | Eigen::Vector3d | 重力向量(默认 z 轴方向,大小由构造函数传入,通常为 9.81 m/s²),用于 IMU 线加速度的重力补偿。 | 
| imu_data | vector<ImuData> | 缓存 IMU 原始数据(时间戳、角速度 wm、线加速度am),通过feed_imu方法持续接收,clean_old_imu_measurements清理过期数据。 | 
| imu_data_mtx | std::mutex | IMU 数据缓存的互斥锁,防止多线程(如 IMU 数据接收线程、状态传播线程)并发访问导致数据竞争。 | 
| 缓存相关变量( cache_*) | atomic<bool>/ 矩阵 | 存储快速状态预测的缓存结果(状态估计值、协方差、时间戳), invalidate_cache可强制失效缓存,避免过期数据使用。 | 
2、核心方法分类与解析
根据功能可分为 6 大类,覆盖 IMU 数据处理、状态传播、辅助计算全流程:
(1)IMU 数据管理
- feed_imu:接收 IMU 原始数据并缓存。传入- ImuData(含时间戳、角速度、线加速度)和过期时间- oldest_time,自动清理早于该时间的旧数据,避免缓存溢出。
- clean_old_imu_measurements:主动清理过期 IMU 数据。遍历- imu_data,删除时间戳早于- oldest_time的条目,维持缓存数据的时效性。
- invalidate_cache:失效快速状态预测的缓存。当系统状态发生突变(如视觉更新后),调用此方法标记缓存无效,确保后续快速预测使用最新状态。
(2) 核心状态传播(对外接口)
这两个方法是Propagator的核心对外接口,直接对接 EKF 预测流程:
- propagate_and_clone:状态传播 + 克隆。- 从imu_data中筛选当前状态时间到目标时间(相机时钟)的 IMU 数据;
- 调用内部积分方法(如 RK4)更新State的 IMU 状态均值与协方差;
- 调用StateHelper::augment_clone,将传播后的 IMU 位姿克隆为新的 “克隆态”,加入State::_clones_IMU(用于 MSCKF 多帧约束)。
 
- 从
- fast_state_propagate:快速状态预测(不修改原始状态)。基于当前- State克隆一个临时 IMU 状态,传播到目标时间(IMU 时钟)并返回预测的状态(13 维:4 维四元数 + 3 维位置 + 3 维速度 + 3 维角速度)与协方差(12 维误差状态),用于高频位姿输出(如视觉更新间隔内的实时显示),不影响原始- State数据。
(3)IMU 数据筛选与插值
- select_imu_readings(静态):筛选目标时间区间的 IMU 数据。根据起始时间- time0和结束时间- time1,从输入的 IMU 数据中提取覆盖该区间的条目;若区间边界未对齐 IMU 数据时间戳,调用- interpolate_data进行线性插值,生成 “截断” 后的 IMU 数据,确保积分区间精确。
- interpolate_data(静态):IMU 数据线性插值。对两个相邻 IMU 数据(- imu_1、- imu_2),按目标时间戳- timestamp的比例(- lambda),线性插值角速度和线加速度,解决 “相机帧时间与 IMU 帧时间不重合” 的时间同步问题。
(4)状态均值积分(三种方法)
根据StateOptions::integration_method配置,选择对应的积分方式更新 IMU 状态均值(位姿new_q、速度new_v、位置new_p):
- predict_mean_discrete:离散积分。适用于 IMU 频率较高的场景,假设短时间内角速度和线加速度恒定,直接用 “噪声均值 × 时间” 更新状态,计算速度快但精度较低。
- predict_mean_rk4:RK4 积分。四阶龙格 - 库塔积分,通过 4 次中间采样(- k1-- k4)逼近连续系统的状态变化,精度高于离散积分,是 OpenVINS 的默认积分方式。
- predict_mean_analytic:解析积分。基于 ACI²(Analytical Continuous-Time Integration)方法,通过解析公式计算状态变化,避免数值离散误差,精度最高但推导复杂,适用于对精度要求极高的场景。
(5)协方差与状态转移矩阵计算
协方差预测需要状态转移矩阵F(描述误差状态的传播规律)和噪声协方差Qd(描述 IMU 噪声对误差的影响),对应两种计算逻辑:
- predict_and_compute:整合协方差预测流程。输入起始与结束时刻的 IMU 数据,根据配置的积分方法,调用- compute_F_and_G_discrete或- compute_F_and_G_analytic计算- F和噪声雅可比- G,再通过- G×Q×G^T计算离散噪声协方差- Qd。
- compute_F_and_G_discrete:离散型- F和- G计算。基于离散积分假设,推导误差状态的转移矩阵- F(如位置误差受速度误差、旋转误差影响的系数)和噪声雅可比- G(如 IMU 噪声对速度误差的贡献系数)。
- compute_F_and_G_analytic:解析型- F和- G计算。基于解析积分的连续时间模型,通过推导的解析公式计算- F和- G,精度更高,需配合- compute_Xi_sum生成的积分中间变量(如- Xi_1-- Xi_4,描述旋转与加速度的耦合关系)。
(6)辅助计算(IMU 内参雅可比)
当开启 IMU 内参校准时(do_calib_imu_intrinsics=true),需要计算内参误差对状态的影响,对应三个静态方法:
- compute_H_Dw:计算 IMU gyro 内参矩阵- Dw的雅可比。根据- ImuModel(KALIBR/RPNG),生成内参误差(如尺度误差)对 gyro 测量值的影响矩阵,用于协方差预测中内参误差的传播。
- compute_H_Da:计算 IMU accel 内参矩阵- Da的雅可比。与- compute_H_Dw逻辑类似,生成内参误差对 accel 测量值的影响矩阵。
- compute_H_Tg:计算 gyro 重力敏感度矩阵- Tg的雅可比。生成重力敏感度误差对 gyro 测量值的影响矩阵,用于重力敏感度校准场景的协方差传播。
