MsckfVio Estimator/Filter
0.引言
文章只是自己过一遍代码的笔记,大部分参考自网络,尽量都列出出处。
主要参考文章:

ID 是全局ID,通过ID来建立的跟踪关系。
- 后端数据结构:
StateServer:

MapServer:

void MsckfVio::addFeatureObservations(
const CameraMeasurementConstPtr& msg) {
StateIDType state_id = state_server.imu_state.id;
int curr_feature_num = map_server.size();
int tracked_feature_num = 0;
// step 3.1.Add new observations for existing features or new
// features in the map server.
for (const auto& feature : msg->features) {
if (map_server.find(feature.id) == map_server.end()) {
// This is a new feature.
map_server[feature.id] = Feature(feature.id);
map_server[feature.id].observations[state_id] =
Vector4d(feature.u0, feature.v0,
feature.u1, feature.v1);
} else {
// This is an old feature.
map_server[feature.id].observations[state_id] =
Vector4d(feature.u0, feature.v0,
feature.u1, feature.v1);
++tracked_feature_num;
}
}
// step 3.2.计算跟踪成功率
tracking_rate =
static_cast<double>(tracked_feature_num) /
static_cast<double>(curr_feature_num);
return;
}
系统框架:

0.1.符号定义



0.2.EKF回顾

1.三种状态模型

使用误差状态模型对状态模型进行更新,需要做的有三步骤:
- 1.对 nominal-state 进行积分
- 2.对 error-state 进行积分[EKF在这步里计算]
- 3.true-state = nominal-state + error-state
2.nominal-state IMU 状态量预测(Propagation/Prediction)
x t n − 积 分 → x t n + 1 \mathbf{x}_{t_n} - 积分 \rightarrow \mathbf{x}_{t_{n+1}}xtn−积分→xtn+1:离散时间的积分,得到状态递推公式。
nominal-state不同状态量的积分方式选择不同:
2.1.nominal-state 位置、速度的四阶龙格-库塔积分
回顾一下龙格库塔积分法:龙格 - 库塔( Runge-Kutta )方法是解决常微分方程初值问题的高精度单步法,这类方法与泰勒( Taylor )展开有密切联系。参考数值分析:


具有四阶 Taylor展开精度,原理推导见数值分析教材。
回到正题,计算 位置 p \mathbf{p}p, 速度 v \mathbf{v}v 的积分:
位置和速度的微分方程为
p ˙ = v v ˙ = a = R ( a m − a b ) + g \begin{aligned} &\dot{\mathbf{p}}=\mathbf{v} \\ &\dot{\mathbf{v}}=\mathbf{a}=\mathbf{R}\left(\mathbf{a}_{m}-\mathbf{a}_{b}\right)+\mathbf{g} \end{aligned}p˙=vv˙=a=R(am−ab)+g
计算 Runge-Kutta有,
nominal-state中的 a m − a b \mathbf{a}_m - \mathbf{a}_bam−ab 实际计算时直接使用的测量值 a m = a c c \mathbf{a}_m = accam=acc, 疑问: R ( t n + 1 + t n ) / 2 \mathbf{R}_{(t_{n+1} + t_n)/2}R(tn+1+tn)/2 是如何计算的,是对数运算后取一般角度吗?
2.2.nominal-state 四元数积分

2.3.其他微分为 0 的项,显然其值保持不变
3.error-state IMU 误差状态量

3.1.error-state IMU 运动方程

3.2.系统状态协方差预测
一阶微分方程,具有闭式解:
x ˙ = F ( t ) x ( t ) + G ( t ) w ( t ) \begin{aligned} &\dot{\mathbf{x}}=\mathbf{F}(t) \mathbf{x}(t) +\mathbf{G}(t) \mathbf{w}(t) \end{aligned}x˙=F(t)x(t)+G(t)w(t)

- IMU 的状态,在
2.nominal-state IMU 状态量预测(Propagation/Prediction)新小节进行更新 - 在误差状态系统里,状态是由噪声驱动,状态的均值为0,只需更新协方差,对于IMU的协方差矩阵, 还是需要先求取状态转移矩阵和离散的运动噪声协方差矩阵,如下:
Φ k = Φ ( t k + 1 , t k ) = exp ( ∫ t k t k + 1 F ( τ ) d τ ) Q k = ∫ t k t k + 1 Φ ( t k + 1 , τ ) GQG Φ ( t k + 1 , τ ) T d τ \Phi_{k}=\Phi(t_{k+1},t_{k})=\textbf{exp}(\int_{t_{k}}^{t_{k+1}} \textbf{F}(\tau)d\tau) \\ \textbf{Q}_{k}=\int_{t_{k}}^{t_{k+1}}\Phi({t_{k+1},\tau})\textbf{GQG}\Phi({t_{k+1},\tau})^{T}d\tauΦk=Φ(tk+1,tk)=exp(∫tktk+1F(τ)dτ)Qk=∫tktk+1Φ(tk+1,τ)GQGΦ(tk+1,τ)Tdτ

整个状态(IMU+Camera)的covariance传播过程如图所示:

那么对于左上角 IMU 的 corvariance 的传播,则为此小节误差状态求得的协方差矩阵:
P I I k + 1 ∣ k = Φ k P I I k ∣ k Φ k ⊤ + Q k \mathbf{P}_{I I_{k+1 \mid k}}=\boldsymbol{\Phi}_{k} \mathbf{P}_{I I_{k \mid k}} \boldsymbol{\Phi}_{k}^{\top}+\mathbf{Q}_{k}PIIk+1∣k=ΦkPIIk∣kΦk⊤+Qk
其中Camera的covariance暂时还没有变化是因为这个时间段图像还没有到来,只有IMU的影响,但是会影响到IMU与Camera协方差,即上图灰色矩形块:

4.状态增广 State Augmentation
4.1.绝对观测模型与相对观测模型
MSCKF 相比EKF-SLAM特殊之处在于:
- 1.状态量中不维护3D路标点(状态量就会少很多,也会降低计算量)
- 2.利用零空间投影边缘化3D路标点建立相机之间的相对观测约束
- 3.通过状态增广的方式维护多个历史相机位姿状态

4.2.增广相机状态向
对 error-state 进行状态量增广。
- 根据 IMU 位姿求取 Camera 位姿:

- 对误差状态向量增广相机状态向量:δ θ w 2 c T , δ w p c T \delta \boldsymbol{\theta}_{w 2 c}^{T}, \delta^{\mathrm{w}} \mathbf{p}_{c}^{T}δθw2cT,δwpcT
4.3.状态协方差扩增
误差状态由噪声驱动,误差状态的协方差矩阵就是系统的协方差矩阵?
当图像到来时,需要对当前相机姿态做增广,这个时刻的相机姿态是由上一时刻的IMU propagate的结果结合外参得到的:
δ θ w 2 c T , δ w p c T \delta \boldsymbol{\theta}_{w 2 c}^{T}, \delta^{\mathrm{w}} \mathbf{p}_{c}^{T}δθw2cT,δwpcT XX ,从代码看这里增广类似于 nominal-state 状态量添加的是 R w 2 c , t c 2 w ( w p c ) R_{w2c}, t_{c2w }(^w p_c)Rw2c,tc2w(wpc)
外参用到了 T w 2 i \mathbf{T}_{w2i}Tw2i, T i 2 c \mathbf{T}_{i2c}Ti2c.
假设上一时刻共有 N 个相机姿态在状态向量中,那么当新一帧图像到来时,这个时候整个滤波器的状态变成了 21+6(N+1) 的向量, 那么它对应的 covariance 维度变为 ( 21 + 6 ( N + 1 ) ) × ( 21 + 6 ( N + 1 ) ) (21+6(N+1))\times(21+6(N+1))(21+6(N+1))×(21+6(N+1)) .其数学表达式为:
P k ∣ k = ( I 21 + 6 N J ) P k ∣ k ( I 21 + 6 N J ) T \textbf{P}_{k|k}=\begin{pmatrix} \textbf{I}_{21+6N}\\ \textbf{J} \end{pmatrix}\textbf{P}_{k|k}\begin{pmatrix} \textbf{I}_{21+6N}\\ \textbf{J} \end{pmatrix}^{T}Pk∣k=(I21+6NJ)Pk∣k(I21+6NJ)T


x j = J j i x i \mathbf{x}_j = \mathbf{J}_{ji} \mathbf{x}_ixj=Jjixi 这个式子怎么来的 ?
高斯分布线性变换的协方差矩阵性质:
假设有高斯随机变量: x ∈ R N ∼ N ( μ x , Σ x x ) \boldsymbol{x} \in \mathbb{R}^{N} \sim \mathcal{N}\left(\boldsymbol{\mu}_{x}, \boldsymbol{\Sigma}_{x x}\right)x∈RN∼N(μx,Σxx), 以及另一个与 x \boldsymbol{x}x 线性相关的随机变量 y ∈ R M \boldsymbol{y} \in \mathbb{R}^{M}y∈RM :
y = G x \boldsymbol{y}=\boldsymbol{G} \boldsymbol{x}y=Gx
其中 G ∈ R M × N \boldsymbol{G} \in \mathbb{R}^{M \times N}G∈RM×N 是一个常量矩阵。我们的目标是研究 y \boldsymbol{y}y 的统计特性。一个简单的方法是直接计算期望和方差:
μ y = E [ y ] = E [ G x ] = G E [ x ] = G μ x Σ y y = E [ ( y − μ y ) ( y − μ y ) T ] = G E [ ( x − μ x ) ( x − μ x ) T ] G T = G Σ x x G T \begin{aligned} \boldsymbol{\mu}_{y} &=E[\boldsymbol{y}]=E[\boldsymbol{G} \boldsymbol{x}]=\boldsymbol{G} E[\boldsymbol{x}]=\boldsymbol{G} \boldsymbol{\mu}_{x} \\ \boldsymbol{\Sigma}_{y y} &=E\left[\left(\boldsymbol{y}-\boldsymbol{\mu}_{y}\right)\left(\boldsymbol{y}-\boldsymbol{\mu}_{y}\right)^{\mathrm{T}}\right] \\ &=\boldsymbol{G} E\left[\left(\boldsymbol{x}-\boldsymbol{\mu}_{x}\right)\left(\boldsymbol{x}-\boldsymbol{\mu}_{x}\right)^{\mathrm{T}}\right] \boldsymbol{G}^{\mathrm{T}}=\boldsymbol{G} \boldsymbol{\Sigma}_{x x} \boldsymbol{G}^{\mathrm{T}} \end{aligned}μyΣyy=E[y]=E[Gx]=GE[x]=Gμx=E[(y−μy)(y−μy)T]=GE[(x−μx)(x−μx)T]GT=GΣxxGT那么, 我们就得到 y ∼ N ( μ y , Σ y y ) = N ( G μ x , G Σ x x G T ) \boldsymbol{y} \sim \mathcal{N}\left(\boldsymbol{\mu}_{y}, \boldsymbol{\Sigma}_{y y}\right)=\mathcal{N}\left(\boldsymbol{G} \boldsymbol{\mu}_{x}, \boldsymbol{G} \boldsymbol{\Sigma}_{x x} \boldsymbol{G}^{\mathrm{T}}\right)y∼N(μy,Σyy)=N(Gμx,GΣxxGT) 。
因此,对状态量协方差矩阵的增广就可以通过 J ( 6 , 21 + 6 N ) = [ ( ∂ x c ∂ x i m u T ) T , ( ∂ x c ∂ x c T ) T ] T \begin{aligned} \underset{(6,21+6 \mathrm{~N})}{\mathbf{J}}=& {\left[\left(\frac{\partial \mathbf{x}_{c}}{\partial \mathbf{x}_{i m u}^{T}}\right)^{T},\left(\frac{\partial \mathbf{x}_{c}}{\partial \mathbf{x}_{c}^{T}}\right)^{T}\right]^{T} } \\ \end{aligned}(6,21+6 N)J=[(∂ximuT∂xc)T,(∂xcT∂xc)T]T 计算得出,如PPT所示。重点就转为求 ( ∂ x c ∂ x i m u T ) T \left(\frac{\partial \mathbf{x}_{c}}{\partial \mathbf{x}_{i m u}^{T}}\right)^{T}(∂ximuT∂xc)T:


论文中的结果:

5.特征点三角化
计算获取世界坐标系下的 3D 特征点,代码在 Feature::initializePosition
5.1. 对极几何计算初始深度
据对极几何原理,三角化计算初始深度,得到初始三维点坐标:

5.2.LM优化3D点
• 通过 L-M 算法迭代优化得到更加精确的世界系三维点


迭代优化求解:

5.3. 投影世界系三维点到相机系**
position = T_c0_w.linear()*final_position + T_c0_w.translation();
6.系统测量更新
使用相机测量进行系统进行校正。
6.1. 线性化测量模型
使用相机进行更新,使用 测量的 error-state ?
线性化测量模型怎么推导出来的?–>【挖坑】OC-EKF
这里 H HH 为啥是两部分:一部分为 error-state 状态量【对IMU的 H HH 也全为0,只有与相机相关的部分有值】,一部分为 相机3D点,但状态量中没有,所以需要进行左零空间投影。
视觉测量残差可近似表示为

r rr 为重投影误差。
// 3D点世界坐标系 wP_{f_i} = [x,y,z]^T
const Vector3d& p_w = feature.position;
const Vector4d& z = feature.observations.find(cam_state_id)->second;
// Convert the feature position from the world frame to
// the cam0 and cam1 frame.
// 3D点世界坐标系下左右目相机观测
Vector3d p_c0 = R_w_c0 * (p_w-t_c0_w);
Vector3d p_c1 = R_w_c1 * (p_w-t_c1_w);
// Compute the Jacobians.
// 式(1)
Matrix<double, 4, 3> dz_dpc0 = Matrix<double, 4, 3>::Zero();
dz_dpc0(0, 0) = 1 / p_c0(2);
dz_dpc0(1, 1) = 1 / p_c0(2);
dz_dpc0(0, 2) = -p_c0(0) / (p_c0(2)*p_c0(2));
dz_dpc0(1, 2) = -p_c0(1) / (p_c0(2)*p_c0(2));
// 式(1)
Matrix<double, 4, 3> dz_dpc1 = Matrix<double, 4, 3>::Zero();
dz_dpc1(2, 0) = 1 / p_c1(2);
dz_dpc1(3, 1) = 1 / p_c1(2);
dz_dpc1(2, 2) = -p_c1(0) / (p_c1(2)*p_c1(2));
dz_dpc1(3, 2) = -p_c1(1) / (p_c1(2)*p_c1(2));
Matrix<double, 3, 6> dpc0_dxc = Matrix<double, 3, 6>::Zero();
dpc0_dxc.leftCols(3) = skewSymmetric(p_c0); // 式(2)
dpc0_dxc.rightCols(3) = -R_w_c0; // 式(3)
Matrix<double, 3, 6> dpc1_dxc = Matrix<double, 3, 6>::Zero();
dpc1_dxc.leftCols(3) = R_c0_c1 * skewSymmetric(p_c0); // 式(4)
dpc1_dxc.rightCols(3) = -R_w_c1; // 式(5)
Matrix3d dpc0_dpg = R_w_c0; // 式(6)
Matrix3d dpc1_dpg = R_w_c1; // 式(7)
H_x = dz_dpc0*dpc0_dxc + dz_dpc1*dpc1_dxc;
H_f = dz_dpc0*dpc0_dpg + dz_dpc1*dpc1_dpg;

6.2.边缘化移除H中的3D点

进行相机状态边缘化后,继续对方程进行QR分解,将误差状态量中关于多帧相机的状态量进行压缩:

6.4.EKF Update

7.TODO
阅读参考文献:
本文论文:
- A Multi-State Constraint Kalman Filter for Vision-aided Inertial Navigation
- Robust Stereo Visual Inertial Odometry for Fast Autonomous Flight
基础知识:
- Quaternion kinematics for the error-state KF
- Indirect Kalman Filter for 3D Attitude Estimation-A Tutorial for Quaternion Algebra
能观测性分析 OC-EKF 相关:
- Consistency Analysis and IMprovement of Vision-aided Inertial Navigation
- On the Consistency of Vision-Aided Inertial Navigation
其他参考博客: