为了看懂后端代码,我先看了下《Quaternion kinematics for the error-state Kalman filter》这篇参考文献,写了两篇总结文档
学习MSCKF笔记——四元数基础
学习MSCKF笔记——真实状态、标称状态、误差状态
MSCKF的后端内容还是很多的,Stereo-MSCKF的代码也写得很好,通过读代码将MSCKF后端流程图总结如下:
下面我将后端中几个关键的知识点相关的理论推导和代码进行总结分析。
首先我们要清楚的一点是,在MSCKF中维护的状态变量是由两部分组成,分别是IMU误差状态 x I = [ δ θ i 2 w T , δ b g T , δ w v T , δ b a T , δ w p i T , δ θ i 2 c T , δ t i 2 c T ] T \mathbf{x}_{I}=\left[\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{w}}^{T}, \delta \mathbf{b}_{g}^{T}, \delta^{\mathrm{w}} \mathbf{v}^{T}, \delta \mathbf{b}_{a}^{T}, \delta^{\mathrm{w}} \mathbf{p}_{i}^{T}, \delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{c}}^{T}, \delta \mathbf{t}_{\mathrm{i} 2 \mathrm{c}}^{T}\right]^{T} xI=[δθi2wT,δbgT,δwvT,δbaT,δwpiT,δθi2cT,δti2cT]T和相机误差状态 x c = [ δ θ w 2 c T , δ w p c T ] T \mathbf{x}_{c_{}}=\left[\delta \boldsymbol{\theta}_{w 2 c_{}}^{T}, \delta^{\mathrm{w}} \mathbf{p}_{c_{}}^{T}\right]^{T} xc=[δθw2cT,δwpcT]T,在状态预测过程中,只是对IMU的标称状态和IMU的误差状态进行预测,预测的过程中会改变IMU误差状态的协方差以及IMU误差状态相对相机误差状态的协方差。而相机相关的状态只会在观测更新时改变。
在学习MSCKF笔记——误差状态卡尔曼滤波中,我们讨论了IMU的标称状态和误差状态分别的定义和推导,下面我们就可以具体看看,在MSCKF中是如何实际应用这两种状态变量的,对于标称状态,与上一篇博文中不同的是,MSCKF中IMU的标称状态采用的是四阶龙格库塔积分,而不是欧拉积分,精度会更高,四阶龙格库塔不展开进行讨论,我们着重讨论下IMU误差状态的实际应用。
在上一篇博客我们对IMU的误差状态的连续时间系统进行了推导,并进行了近似离散化(精确离散化方法的一阶泰勒展开),这里我们首先给出IMU误差状态连续时间系统方程(这里省略下标 I I I) x ˙ ( t ) = F ( t ) x ( t ) + G ( t ) w ( t ) \dot{\mathbf{x}}(t)=\mathbf{F}(t) \mathbf{x}(t)+\mathbf{G}(t) \mathbf{w}(t) x˙(t)=F(t)x(t)+G(t)w(t)其中状态变量为 x = [ δ θ i 2 w T , δ b g T , δ w v T , δ b a T , δ w p i T , δ θ i 2 c T , δ t i 2 c T ] T \mathbf{x}=\left[\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{w}}^{T}, \delta \mathbf{b}_{g}^{T}, \delta^{\mathrm{w}} \mathbf{v}^{T}, \delta \mathbf{b}_{a}^{T}, \delta^{\mathrm{w}} \mathbf{p}_{i}^{T}, \delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{c}}^{T}, \delta \mathbf{t}_{\mathrm{i} 2 \mathrm{c}}^{T}\right]^{T} x=[δθi2wT,δbgT,δwvT,δbaT,δwpiT,δθi2cT,δti2cT]T,噪声项为 w = [ ω n T , ω ω T , a n T , a ω T ] T \mathbf{w}=\left[\begin{array}{lll}\boldsymbol{\omega}_{n}^{T}, \boldsymbol{\omega}_{\omega}^{T}, \mathbf{a}_{n}^{T}, \mathbf{a}_{\omega}^{T}\end{array}\right]^{T} w=[ωnT,ωωT,anT,aωT]T其中噪声项的均值和方差分别为 E [ n ( t ) ] = 0 , E [ n ( t ) T n ( τ ) ] = q δ ( t − τ ) E[\mathbf{n}(t)]=0, E\left[\mathbf{n}(t)^{T} \mathbf{n}(\tau)\right]=\mathbf{q} \delta(t-\tau) E[n(t)]=0,E[n(t)Tn(τ)]=qδ(t−τ) F ( 21 × 21 ) = [ − [ ω m − ω b ] × − I 0 0 0 0 0 0 0 0 0 0 0 0 − R i 2 w [ a m − a b ] × 0 0 − R i 2 w 0 0 0 0 0 0 0 0 0 0 0 0 I 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] \underset{(21 \times 21)}{\mathbf{F}}=\left[\begin{array}{ccccccc} -\left[\omega_{m}-\omega_{b}\right]_{\times} & -\mathbf{I} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ -\mathbf{R}_{\mathrm{i} 2 \mathrm{w}}\left[\mathbf{a}_{m}-\mathbf{a}_{b}\right]_{\times} & \mathbf{0} & \mathbf{0} & -\mathbf{R}_{\mathrm{i} 2 \mathrm{w}} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{I} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \end{array}\right] (21×21)F=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡−[ωm−ωb]×0−Ri2w[am−ab]×0000−I0000000000I0000−Ri2w0000000000000000000000000⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤ G ( 21 × 12 ) = [ − I 0 0 0 0 I 0 0 0 0 − R i 2 w 0 0 0 0 I 0 0 0 0 0 0 0 0 0 0 0 0 ] \underset{(21 \times 12)}{\mathbf{G}}=\left[\begin{array}{cccc} -\mathbf{I} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{I} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & -\mathbf{R}_{\mathrm{i} 2 \mathrm{w}} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{I} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \end{array}\right] (21×12)G=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡−I0000000I0000000−Ri2w0000000I000⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤由于上一篇博客中对IMU的误差状态的连续时间系统进行了推导,唯一不同的是在MSCKF的误差状态中考虑相机和IMU之间的旋转 δ θ i 2 c T \delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{c}}^{T} δθi2cT和平移 δ t i 2 c T \delta \mathbf{t}_{\mathrm{i} 2 \mathrm{c}}^{T} δti2cT,对应的代码部分如下:
// Compute discrete transition and noise covariance matrix
Matrix<double, 21, 21> F = Matrix<double, 21, 21>::Zero();
Matrix<double, 21, 12> G = Matrix<double, 21, 12>::Zero();
F.block<3, 3>(0, 0) = -skewSymmetric(gyro);
F.block<3, 3>(0, 3) = -Matrix3d::Identity();
F.block<3, 3>(6, 0) = -quaternionToRotation(
imu_state.orientation).transpose()*skewSymmetric(acc);
F.block<3, 3>(6, 9) = -quaternionToRotation(
imu_state.orientation).transpose();
F.block<3, 3>(12, 6) = Matrix3d::Identity();
G.block<3, 3>(0, 0) = -Matrix3d::Identity();
G.block<3, 3>(3, 3) = Matrix3d::Identity();
G.block<3, 3>(6, 6) = -quaternionToRotation(
imu_state.orientation).transpose();
G.block<3, 3>(9, 9) = Matrix3d::Identity();
获得误差状态的连续时间系统推导公式后,我们对其进行离散化,根据线性系统理论,连续时间系统离散化形式为: x ( t k + 1 ) = Φ ( t k + 1 , t k ) x ( t k ) + ∫ t k t t + 1 Φ ( t k + 1 , τ ) G ( τ ) w ( τ ) d τ \mathbf{x}\left(\mathrm{t}_{k+1}\right)=\mathbf{\Phi}\left(t_{k+1}, t_{k}\right) \mathbf{x}\left(\mathrm{t}_{k}\right)+\int_{t_{k}}^{t_{t+1}} \mathbf{\Phi}\left(t_{k+1}, \tau\right) \mathbf{G}(\tau) \mathbf{w}(\tau) d \tau x(tk+1)=Φ(tk+1,tk)x(tk)+∫tktt+1Φ(tk+1,τ)G(τ)w(τ)dτ我们将短间隔时间内的 F ( t ) \mathbf{F}(t) F(t)矩阵作为常阵 F k \mathbf{F}_{k} Fk处理并对精确离散化公式进行三次泰勒展开,获得 Φ ( t k + 1 , t k ) = e F Δ t = I + F Δ t + 1 2 ( F Δ t ) 2 + 1 3 ! ( F Δ t ) 3 + O ( ∥ F Δ t ∥ 4 ) \boldsymbol{\Phi}\left(t_{k+1}, t_{k}\right)=\mathrm{e}^{\mathrm{F} \Delta t}=\mathbf{I}+\mathbf{F} \Delta t+\frac{1}{2}(\mathbf{F} \Delta t)^{2}+\frac{1}{3 !}(\mathbf{F} \Delta t)^{3}+O\left(\|\mathbf{F} \Delta t\|^{4}\right) Φ(tk+1,tk)=eFΔt=I+FΔt+21(FΔt)2+3!1(FΔt)3+O(∥FΔt∥4)同时,我们令 W k = ∫ t k t t + 1 Φ ( t k + 1 , τ ) G ( τ ) w ( τ ) d τ \mathbf{W}_{k}=\int_{t_{k}}^{t_{t+1}} \boldsymbol{\Phi}\left(t_{k+1}, \tau\right) \mathbf{G}(\tau) \mathbf{w}(\tau) d \tau Wk=∫tktt+1Φ(tk+1,τ)G(τ)w(τ)dτ则离散化后即获得运动方程为 x k + 1 = Φ k + 1 ∣ k x k + W k \mathbf{x}_{k+1}=\boldsymbol{\Phi}_{k+1 \mid k} \mathbf{x}_{k}+\mathbf{W}_{k} xk+1=Φk+1∣kxk+Wk我们计算噪声项 W k \mathbf{W}_{k} Wk的均值和方差分别为 E [ W k ] = 0 , E [ W k W k T ] = Q k δ ( t − τ ) E\left[\mathbf{W}_{k}\right]=0, E\left[\mathbf{W}_{k} \mathbf{W}_{k}^{T}\right]=\mathbf{Q}_{k} \delta(t-\tau) E[Wk]=0,E[WkWkT]=Qkδ(t−τ),其中 Q k = ∫ t k t k + 1 Φ ( t k + 1 , t ) G ( t ) q G ( t ) T Φ T ( t k + 1 , t ) d t \mathbf{Q}_{k}=\int_{t_{k}}^{t_{k+1}} \mathbf{\Phi}\left(t_{k+1}, t\right) \mathbf{G}(t) \mathbf{q} \mathbf{G}(t)^{T} \mathbf{\Phi}^{T}\left(t_{k+1}, t\right) d t Qk=∫tktk+1Φ(tk+1,t)G(t)qG(t)TΦT(tk+1,t)dt
这一部分代码对应为:
Matrix<double, 21, 21> Fdt = F * dtime;
Matrix<double, 21, 21> Fdt_square = Fdt * Fdt;
Matrix<double, 21, 21> Fdt_cube = Fdt_square * Fdt;
Matrix<double, 21, 21> Phi = Matrix<double, 21, 21>::Identity() +
Fdt + 0.5*Fdt_square + (1.0/6.0)*Fdt_cube;
Matrix<double, 21, 21> Q = Phi*G*state_server.continuous_noise_cov*
G.transpose()*Phi.transpose()*dtime;
我们求得运动方程的的噪声项方差的主要目的是进行卡尔曼滤波的运动学推导,我们可以不管误差状态的均值,因为误差状态是噪声驱动的,噪声项的均值为零,在运动方程的迭代下均值始终为零,而误差状态的方差则会收到噪声方差影响: P I I k + 1 ∣ k = Φ k + 1 ∣ k P I I k ∣ k Φ k + 1 ∣ k T + Q k \mathbf{P}_{I I_{k+1 \mid k}}=\boldsymbol{\Phi}_{k+1 \mid k} \mathbf{P}_{I I_{k\mid k}}\boldsymbol{\Phi}_{k+1 \mid k}^{T}+\mathbf{Q}_{k} PIIk+1∣k=Φk+1∣kPIIk∣kΦk+1∣kT+Qk同时,如果有相机状态存在时,由于IMU的误差状态发生了改变,那么相机误差状态相对于IMU误差状态的协方差也会发生改变,对应的代码如下:
state_server.state_cov.block<21, 21>(0, 0) =
Phi*state_server.state_cov.block<21, 21>(0, 0)*Phi.transpose() + Q;
if (state_server.cam_states.size() > 0) {
state_server.state_cov.block(
0, 21, 21, state_server.state_cov.cols()-21) =
Phi * state_server.state_cov.block(
0, 21, 21, state_server.state_cov.cols()-21);
state_server.state_cov.block(
21, 0, state_server.state_cov.rows()-21, 21) =
state_server.state_cov.block(
21, 0, state_server.state_cov.rows()-21, 21) * Phi.transpose();
}
注意到后端的流程是,当接收到一个图像帧之后会将当前帧与上一帧之间的所有IMU数据拿出来进行状态预测,在完成所有IMU数据的状态预测后,紧接着就是状态扩增,对于标称状态,直接将当前帧时刻IMU状态的标称状态拿来当做当前帧相机的标称状态,对应代码如下:
Matrix3d R_w_i = quaternionToRotation(
state_server.imu_state.orientation);
Matrix3d R_w_c = R_i_c * R_w_i;
Vector3d t_c_w = state_server.imu_state.position +
R_w_i.transpose()*t_c_i;
state_server.cam_states[state_server.imu_state.id] =
CAMState(state_server.imu_state.id);
CAMState& cam_state = state_server.cam_states[
state_server.imu_state.id];
cam_state.time = time;
cam_state.orientation = rotationToQuaternion(R_w_c);
cam_state.position = t_c_w;
对于误差状态,均值没啥好扩增的,因为在观测发生前,所有误差状态的均值都为零,我们最为关心的应该是误差状态的协方差矩阵扩增,这里借用吴博在深蓝学院课程上将的概念,矩阵扩增分为理解为克隆和修正两步,第一步克隆如下: [ x i ] ⟶ [ x i x i ] \left[\mathbf{x}_{i}\right] \longrightarrow\left[\begin{array}{l} \mathbf{x}_{i} \\ \mathbf{x}_{i} \end{array}\right] [xi]⟶[xixi] [ P i ] ⟶ [ P i i P i i P i i P i i ] \left[\mathbf{P}_{i}\right] \longrightarrow\left[\begin{array}{cc} \mathbf{P}_{i i} & \mathbf{P}_{i i} \\ \mathbf{P}_{i i} & \mathbf{P}_{i i} \end{array}\right] [Pi]⟶[PiiPiiPiiPii]第二步修正如下: [ x i ] ⟶ [ x i x j ] \left[\mathbf{x}_{i}\right] \longrightarrow\left[\begin{array}{l} \mathbf{x}_{i} \\ \mathbf{x}_{j} \end{array}\right] [xi]⟶[xixj] x j = J j i x i \mathbf{x}_{j}=\mathbf{J}_{j i} \mathbf{x}_{i} xj=Jjixi [ P i i P i i P i i P i i ] ⟶ [ P i i P j i P i j P j j ] \left[\begin{array}{ll} \mathbf{P}_{i i} & \mathbf{P}_{i i} \\ \mathbf{P}_{i i} & \mathbf{P}_{i i} \end{array}\right] \longrightarrow\left[\begin{array}{ll} \mathbf{P}_{i i} & \mathbf{P}_{j i} \\ \mathbf{P}_{i j} & \mathbf{P}_{j j} \end{array}\right] [PiiPiiPiiPii]⟶[PiiPijPjiPjj] P i j = J j i P i i \mathbf{P}_{i j}=\mathbf{J}_{j i}\mathbf{P}_{i i} Pij=JjiPii P j j = J j i P i i J j i T \mathbf{P}_{j j}=\mathbf{J}_{j i} \mathbf{P}_{i i} \mathbf{J}_{j i}^{T} Pjj=JjiPiiJjiT其中 J j i \mathbf{J}_{j i} Jji为新增状态变量 x j \mathbf{x}_{j} xj相对 x i \mathbf{x}_{i} xi的雅克比矩阵,那么在MSCKF中,新增误差相机状态对当前误差状态的雅克比为 J ( 6 , 21 + 6 N ) = [ ( ∂ x c ∂ x I T ) T , ( ∂ x c ∂ x c T ) T ] T \mathbf{J}_{(6,21+6 \mathrm{N})}=\left[\left(\frac{\partial \mathbf{x}_{c}}{\partial \mathbf{x}_{I}^{T}}\right)^{T},\left(\frac{\partial \mathbf{x}_{c}}{\partial \mathbf{x}_{c}^{T}}\right)^{T}\right]^{T} J(6,21+6N)=[(∂xIT∂xc)T,(∂xcT∂xc)T]T其中第二项是当前相机误差状态变量相对其他误差相机状态变量的的雅克比,为零矩阵,第一项为新增相机误差状态变量相对IMU误差状态变量的雅克比,结果如下(这一部分是参考吴博深蓝课程上的推导,我感觉推导过程中还有些问题和代码对应也不是完全一致,这里后续修改): ∂ x c ∂ x I T = [ ∂ δ θ c 2 w ∂ δ θ i 2 w 0 3 × 9 0 3 × 3 ∂ δ θ c 2 w ∂ δ θ i 2 c 0 3 × 3 ∂ δ w p c ∂ δ θ i 2 w 0 3 × 9 ∂ δ w p c δ w p i 0 3 × 3 ∂ δ w p c δ t i 2 c ] \frac{\partial \mathbf{x}_{c}}{\partial \mathbf{x}_{I}^{T}}=\left[\begin{array}{ccccc} \frac{\partial\delta \boldsymbol{\theta}_{c 2 w_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{w}}} & \mathbf{0}_{3\times9} & \mathbf{0}_{3\times3} & \frac{\partial\delta \boldsymbol{\theta}_{c 2 w_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{c}}} & \mathbf{0}_{3\times3} \\ \frac{\partial \delta^{\mathrm{w}} \mathbf{p}_{c_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{w}}} & \mathbf{0}_{3\times9} &\frac {\partial\delta^{\mathrm{w}} \mathbf{p}_{c_{}}}{\delta^{\mathrm{w}} \mathbf{p}_{i_{}}} & \mathbf{0}_{3\times3} & \frac{\partial\delta^{\mathrm{w}} \mathbf{p}_{c_{}}}{\delta \mathbf{t}_{\mathrm{i} 2 \mathrm{c}}} \end{array}\right] ∂xIT∂xc=[∂δθi2w∂δθc2w∂δθi2w∂δwpc03×903×903×3δwpi∂δwpc∂δθi2c∂δθc2w03×303×3δti2c∂δwpc]
我们已知: { w p c = R i 2 w i p c + w p i R w 2 c = R i 2 c R w 2 i \left\{\begin{array}{l} {}^w \mathbf{p}_{c}=\mathbf{R}_{i 2 w}{}^{i} \mathbf{p}_{c}+{ }^{w} \mathbf{p}_{i} \\ \mathbf{R}_{w 2 c}=\mathbf{R}_{i 2 c} \mathbf{R}_{w 2 i} \end{array}\right. {wpc=Ri2wipc+wpiRw2c=Ri2cRw2i
对于 ∂ δ θ c 2 w ∂ δ θ i 2 w \frac{\partial\delta \boldsymbol{\theta}_{c 2 w_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{w}}} ∂δθi2w∂δθc2w: R c 2 w T = R i 2 c R i 2 w T ⇒ ( R c 2 w Exp ( δ θ c 2 w ) ) T = R i 2 c ( R i 2 w Exp ( δ θ i 2 w ) ) T ⇒ Exp ( − δ θ c 2 w ) R w 2 c = R i 2 c Exp ( − δ θ i 2 w ) R w 2 i ⇒ Exp ( − δ θ c 2 w ) R w 2 c = Exp ( Adj R i 2 c ( − δ θ i 2 w ) ) R i 2 c R w 2 i ⇒ Exp ( − δ θ c 2 w ) = Exp ( Adj R i 2 c ( − δ θ i 2 w ) ) ⇒ δ θ c 2 w = R i 2 c δ θ i 2 w \begin{array}{l} \mathbf{R}_{c 2 w}^{T}=\mathbf{R}_{i 2 c} \mathbf{R}_{i 2 w}^{T} \\ \Rightarrow\left(\mathbf{R}_{c 2 w} \operatorname{Exp}\left(\delta \boldsymbol{\theta}_{c2w}\right)\right)^{T}=\mathbf{R}_{i 2 c}\left(\mathbf{R}_{i 2 w} \operatorname{Exp}\left(\delta \boldsymbol{\theta}_{i2w}\right)\right)^{T} \\ \Rightarrow \operatorname{Exp}\left(-\delta \boldsymbol{\theta}_{c 2 w}\right) \mathbf{R}_{w 2 c}=\mathbf{R}_{i 2 c} \operatorname{Exp}\left(-\delta \boldsymbol{\theta}_{i 2 w}\right) \mathbf{R}_{w 2 i} \\ \Rightarrow \operatorname{Exp}\left(-\delta \boldsymbol{\theta}_{c 2 w}\right) \mathbf{R}_{w 2 c}=\operatorname{Exp}\left(\operatorname{Adj}_{\mathbf{R}_{i2c}}\left(-\delta \boldsymbol{\theta}_{i 2 w}\right)\right) \mathbf{R}_{i 2 c} \mathbf{R}_{w2i} \\ \Rightarrow \operatorname{Exp}\left(-\delta \boldsymbol{\theta}_{c 2 w}\right)=\operatorname{Exp}\left(\operatorname{Adj}_{\mathbf{R}_{i2c}}\left(-\delta \boldsymbol{\theta}_{i 2 w}\right)\right) \\ \Rightarrow \delta \boldsymbol{\theta}_{c 2 w}=\mathbf{R}_{i 2 c} \delta \boldsymbol{\theta}_{i 2 w} \end{array} Rc2wT=Ri2cRi2wT⇒(Rc2wExp(δθc2w))T=Ri2c(Ri2wExp(δθi2w))T⇒Exp(−δθc2w)Rw2c=Ri2cExp(−δθi2w)Rw2i⇒Exp(−δθc2w)Rw2c=Exp(AdjRi2c(−δθi2w))Ri2cRw2i⇒Exp(−δθc2w)=Exp(AdjRi2c(−δθi2w))⇒δθc2w=Ri2cδθi2w ∂ δ θ c 2 w ∂ δ θ i 2 w = R i 2 c \frac{\partial\delta \boldsymbol{\theta}_{c 2 w_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{w}}}=\mathbf{R}_{i 2 c} ∂δθi2w∂δθc2w=Ri2c对于 ∂ δ θ c 2 w ∂ δ θ i 2 c \frac{\partial\delta \boldsymbol{\theta}_{c 2 w_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{c}}} ∂δθi2c∂δθc2w: R w 2 c = R i 2 c R w 2 i ⇒ ( R c 2 w Exp ( δ θ c 2 w ) ) T = ( R c 2 i Exp ( δ θ c 2 i ) ) T R w 2 i ⇒ Exp ( − δ θ c 2 w ) R w 2 c = Exp ( − δ θ c 2 i ) R i 2 c R w 2 i ⇒ δ θ c 2 w = δ θ c 2 i \begin{array}{l} \mathbf{R}_{w 2 c}=\mathbf{R}_{i 2 c} \mathbf{R}_{w 2 i} \\ \Rightarrow\left(\mathbf{R}_{c 2 w} \operatorname{Exp}\left(\delta\boldsymbol{\theta}_{c 2 w}\right)\right)^{T}=\left(\mathbf{R}_{c 2 i} \operatorname{Exp}\left(\delta\boldsymbol{\theta}_{c 2 i}\right)\right)^{T} \mathbf{R}_{w 2 i} \\ \Rightarrow \operatorname{Exp}\left(-\delta\boldsymbol{\theta}_{c 2 w}\right) \mathbf{R}_{w 2 c}=\operatorname{Exp}\left(-\delta\boldsymbol{\theta}_{c 2 i}\right) \mathbf{R}_{i 2 c} \mathbf{R}_{w 2 i} \\ \Rightarrow \delta\boldsymbol{\theta}_{c 2 w}=\delta\boldsymbol{\theta}_{c 2 i} \end{array} Rw2c=Ri2cRw2i⇒(Rc2wExp(δθc2w))T=(Rc2iExp(δθc2i))TRw2i⇒Exp(−δθc2w)Rw2c=Exp(−δθc2i)Ri2cRw2i⇒δθc2w=δθc2i ∂ δ θ c 2 w ∂ δ θ i 2 c = I \frac{\partial\delta \boldsymbol{\theta}_{c 2 w_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{c}}}=\mathbf{I} ∂δθi2c∂δθc2w=I对于 ∂ δ w p c ∂ δ θ i 2 w \frac{\partial \delta^{\mathrm{w}} \mathbf{p}_{c_{}}}{\partial\delta \boldsymbol{\theta}_{\mathrm{i} 2 \mathrm{w}}} ∂δθi2w∂δwpc: ∂ w p c ∂ δ θ i 2 w = lim δ θ → 0 ( R i 2 w Exp ( δ θ ) i p c + w p i ) − ( R i 2 w i p c + w p i ) δ θ = lim δ θ → 0 ( R i 2 w ( I + [ δ θ ] × ) i p c + w p i ) − ( R i 2 w p c + w p i ) δ θ = lim δ θ → 0 R i 2 w [ δ θ ] × i p c δ θ = − R i 2 w [ i p c ] × \begin{aligned} \frac{\partial^{w} \mathbf{p}_{c}}{\partial \delta \boldsymbol{\theta}_{i 2 w}} &=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{\left(\mathbf{R}_{i 2 w} \operatorname{Exp}(\delta \boldsymbol{\theta})^{i} \mathbf{p}_{c}+{ }^{w} \mathbf{p}_{i}\right)-\left(\mathbf{R}_{i 2 w}^{i} \mathbf{p}_{c}+{ }^{w} \mathbf{p}_{i}\right)}{\delta \boldsymbol{\theta}}\\ &=\lim _{\delta \theta \rightarrow 0} \frac{\left(\mathbf{R}_{i 2 w}\left(\mathbf{I}+[\delta \boldsymbol{\theta}]_{\times}\right)^{i} \mathbf{p}_{c}+{ }^{w} \mathbf{p}_{i}\right)-\left(\mathbf{R}_{i 2 w}{\mathbf{p}}_{c}+{ }^{w} \mathbf{p}_{i}\right)}{\delta \boldsymbol{\theta}}\\ &=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{\mathbf{R}_{i 2 w}[\delta \boldsymbol{\theta}]_{\times}^{i} \mathbf{p}_{c}}{\delta \boldsymbol{\theta}}=-\mathbf{R}_{i 2 w}\left[{ }^{i} \mathbf{p}_{c}\right]_{\times} \end{aligned} ∂δθi2w∂wpc=δθ→0limδθ(Ri2wExp(δθ)ipc+wpi)−(Ri2wipc+wpi)=δθ→0limδθ(Ri2w(I+[δθ]×)ipc+wpi)−(Ri2wpc+wpi)=δθ→0limδθRi2w[δθ]×ipc=−Ri2w[ipc]×对于 ∂ δ w p c δ w p i \frac {\partial\delta^{{w}} \mathbf{p}_{c_{}}}{\delta^{{w}} \mathbf{p}_{i_{}}} δwpi∂δwpc: ∂ δ w p c δ w p i = lim δ ′ p ϵ → 0 ( R i 2 w ( i p c + δ i p c ) + w p i ) − ( R i p c + w p i ) δ θ = lim δ θ → 0 R i 2 w δ i p c δ i p c = R i 2 w \begin{aligned}\frac {\partial\delta^{{w}} \mathbf{p}_{c_{}}}{\delta^{{w}} \mathbf{p}_{i_{}}}&=\lim _{\delta^{\prime} \mathbf{p}_{\epsilon} \rightarrow 0} \frac{\left(\mathbf{R}_{i 2 w}\left({ }^{i} \mathbf{p}_{c}+\delta^{i} \mathbf{p}_{c}\right)+{ }^{w} \mathbf{p}_{i}\right)-\left(\mathbf{R}^{i} \mathbf{p}_{c}+{ }^{w} \mathbf{p}_{i}\right)}{\delta \mathbf{\theta}}\\&=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{\mathbf{R}_{i 2 w} \delta^{i} \mathbf{p}_{c}}{\delta^{i} \mathbf{p}_{c}}=\mathbf{R}_{i 2 w}\end{aligned} δwpi∂δwpc=δ′pϵ→0limδθ(Ri2w(ipc+δipc)+wpi)−(Ripc+wpi)=δθ→0limδipcRi2wδipc=Ri2w对于 ∂ δ w p c δ t i 2 c \frac{\partial\delta^{\mathrm{w}} \mathbf{p}_{c_{}}}{\delta \mathbf{t}_{\mathrm{i} 2 \mathrm{c}}} δti2c∂δwpc: ∂ w p c ∂ δ w p i = I \frac{\partial^{w} \mathbf{p}_{c}}{\partial \delta^{w} \mathbf{p}_{i}}=\mathbf{I} ∂δwpi∂wpc=I
这里直接对应部分的代码:
Matrix<double, 6, 21> J = Matrix<double, 6, 21>::Zero();
J.block<3, 3>(0, 0) = R_i_c;
J.block<3, 3>(0, 15) = Matrix3d::Identity();
J.block<3, 3>(3, 0) = skewSymmetric(R_w_i.transpose()*t_c_i);
J.block<3, 3>(3, 12) = Matrix3d::Identity();
J.block<3, 3>(3, 18) = Matrix3d::Identity();
获得雅克比之后就可以按照上面状态扩增的步骤就可以求得扩增后的协方差矩阵,对应的代码如下:
// Rename some matrix blocks for convenience.
const Matrix<double, 21, 21>& P11 =
state_server.state_cov.block<21, 21>(0, 0);
const MatrixXd& P12 =
state_server.state_cov.block(0, 21, 21, old_cols-21);
// Fill in the augmented state covariance.
state_server.state_cov.block(old_rows, 0, 6, old_cols) << J*P11, J*P12;
state_server.state_cov.block(0, old_cols, old_rows, 6) =
state_server.state_cov.block(old_rows, 0, 6, old_cols).transpose();
state_server.state_cov.block<6, 6>(old_rows, old_cols) =
J * P11 * J.transpose();
状态扩增后就开始构建观测并对误差状态进行更新,也就是执行卡尔曼滤波中的后三步,状态更新的前提以及三角化等操作这里就不赘述了,直接看前面的流程图就很容易搞清楚,这其中重要的步骤就是状态观测如何构建,构建的过程其实也比较简单,这一部分推导主要参考吴博在深蓝学院课程上的讲解,通过重投影误差构建观测残差: r j = z j − z ^ j \mathbf{r}^{j}=\mathbf{z}^{j}-\widehat{\mathbf{z}}^{j} rj=zj−z j其中 j j j代表第 j j j个特征点,然后将残差对状态变量进行线性化,也就是求残差对状态变量的雅克比,因为观测残差和特征点还有关系,因此我们还要求残差对特征点的雅克比: r j ≃ H j x + H f j w p j + n j \mathbf{r}^{j} \simeq \mathbf{H}^{j} {\mathbf{x}}+\mathbf{H}^{f_{j} w} {\mathbf{p}}_{j}+\mathbf{n}^{j} rj≃Hjx+Hfjwpj+nj但是由于我们的状态变量中没有特征点的部分,因此最后我们还需要将残差 r j \mathbf{r}^{j} rj和状态变量雅克比 H j \mathbf{H}^{j} Hj投影到特征点雅克比的零空间中去,其实也就是消元掉观测方程中特征点相关的部分: r o j = V T ( z j − z ^ j ) ≃ V T H j x + V T H f j p j + V T n j = V T H j x + V T n j = H o j x + n o j \begin{array}{l} \mathbf{r}_{o}^{j}=\mathbf{V}^{T}\left(\mathbf{z}^{j}-\hat{\mathbf{z}}^{j}\right) \\ \simeq \mathbf{V}^{T} \mathbf{H}^{j}{\mathbf{x}}+\mathbf{V}^{T} \mathbf{H}^{f_j} {\mathbf{p}}_{j}+\mathbf{V}^{T} \mathbf{n}^{j} \\ =\mathbf{V}^{T} \mathbf{H}^{j}{\mathbf{x}}+\mathbf{V}^{T} \mathbf{n}^{j} \\ =\mathbf{H}_{o}^{j} {\mathbf{x}}+\mathbf{n}_{o}^{j} \end{array} roj=VT(zj−z^j)≃VTHjx+VTHfjpj+VTnj=VTHjx+VTnj=Hojx+noj关于这中间的细节,我们首先看下雅克比是怎么求的。首先我们考虑世界坐标系下的第 j j j个3D点 w p f j = [ x , y , z ] T { }^{w} \mathbf{p}_{f_{j}}=[x, y, z]^{T} wpfj=[x,y,z]T,该3D点被世界坐标系下的第 i i i个双目 w p c i 1 , w p c i 2 { }^{w} \mathbf{p}_{c_{i 1}},{ }^{w} \mathbf{p}_{c_{i 2}} wpci1,wpci2观测到,对应到归一化平面上的坐标为 z i j = [ u , v ] T \mathbf{z}_{i }^j=[u, v]^{T} zij=[u,v]T,那么 z i j = [ u v ] = [ x z y z ] \mathbf{z}_{i}^{j}=\left[\begin{array}{l} u \\ v \end{array}\right]=\left[\begin{array}{l} \frac{x}{z} \\ \frac{y}{z} \end{array}\right] zij=[uv]=[zxzy]第 j j j个特征点与第 i i i个相机构成的残差为: r i j = z i j − z ^ i j \mathbf{r}_{i}^{j}=\mathbf{z}_{i}^{j}-\widehat{\mathbf{z}}_{i}^{j} rij=zij−z ij因为我们在MSCKF中使用的是双目,因此会有 r i 1 j \mathbf{r}_{i1}^{j} ri1j和 r i 2 j \mathbf{r}_{i2}^{j} ri2j两个残差,而在双目状态中我们以左目状态为准,那么残差对特征点的雅克比为 H c i f j 4 × 3 = [ ∂ r i 1 j ∂ w p c i 1 ∂ r i 2 j ∂ w p c i 1 ] = [ ∂ r i 1 j ∂ c i 1 p f j ∂ c i 1 p f j ∂ w p f j ∂ r i 2 j ∂ c i 2 p f j ∂ c i 2 p f j ∂ w p f j ] \begin{array}{c} \mathbf{H}_{c_i}^{f_{j}} \\ 4 \times 3 \end{array}=\left[\begin{array}{c} \frac{\partial \mathbf{r}_{i 1}^{j}}{\partial^{w} \mathbf{p}_{c_{i 1}}} \\ \frac{\partial \mathbf{r}_{i 2}^{j}}{\partial^{w} \mathbf{p}_{c_{i 1}}} \end{array}\right]=\left[\begin{array}{c} \frac{\partial \mathbf{r}_{i 1}^{j}}{\partial^{c_{i 1}} \mathbf{p}_{f_{j}}} \frac{\partial^{c_{i 1}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{f_{j}}} \\ \frac{\partial \mathbf{r}_{i 2}^{j}}{\partial^{c_{i 2}} \mathbf{p}_{f_{j}}} \frac{\partial^{c_{i 2}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{f_{j}}} \end{array}\right] Hcifj4×3=⎣⎡∂wpci1∂ri1j∂wpci1∂ri2j⎦⎤=⎣⎡∂ci1pfj∂ri1j∂wpfj∂ci1pfj∂ci2pfj∂ri2j∂wpfj∂ci2pfj⎦⎤残差对相机状态的雅克比为: H c i j 4 × 6 = [ ∂ r i 1 j ∂ R w 2 c i 1 , ∂ r i 1 j ∂ w p c i 1 ∂ r i 2 j ∂ R w 2 c i 1 , ∂ r i 1 j ∂ w p c i 1 ] = [ ∂ r i 1 j ∂ c i 1 p f j ∂ c i 1 p f j ∂ R w 2 c i 1 , ∂ r i 1 j ∂ c i 1 p f j ∂ c i 1 p f j ∂ w p c i 1 ∂ r i 2 j ∂ c i 2 p f j ∂ c i 2 p f j ∂ R w 2 c i 1 , ∂ r i 2 j ∂ c i 2 p f j ∂ c i 2 p f j ∂ w p c i 1 ] \begin{array}{c} \mathbf{H}_{c_{i}}^{j} \\ 4 \times 6 \end{array}=\left[\begin{array}{cc} \frac{\partial \mathbf{r}_{i 1}^{j}}{\partial \mathbf{R}_{w 2 c_{i 1}}}, & \frac{\partial \mathbf{r}_{i 1}^{j}}{\partial^{w} \mathbf{p}_{c_{i 1}}} \\ \frac{\partial \mathbf{r}_{i 2}^{j}}{\partial \mathbf{R}_{w 2 c_{i 1}}}, & \frac{\partial \mathbf{r}_{i 1}^{j}}{\partial^{w} \mathbf{p}_{c_{i 1}}} \end{array}\right]=\left[\begin{array}{c} \frac{\partial \mathbf{r}_{i 1}^{j}}{\partial^{c_{i 1}} \mathbf{p}_{f_{j}}} \frac{\partial^{c_{i 1}} \mathbf{p}_{f_{j}}}{\partial \mathbf{R}_{w 2 c_{i 1}}}, \frac{\partial \mathbf{r}_{i 1}^{j}}{\partial^{c_{i 1}} \mathbf{p}_{f_{j}}} \frac{\partial^{c_{i 1}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{c_{i 1}}} \\ \frac{\partial \mathbf{r}_{i 2}^{j}}{\partial^{c_{i 2}} \mathbf{p}_{f_{j}}} \frac{\partial^{c_{i 2}} \mathbf{p}_{f_{j}}}{\partial \mathbf{R}_{w 2 c_{i 1}}}, \frac{\partial \mathbf{r}_{i 2}^{j}}{\partial^{c_{i 2}} \mathbf{p}_{f_{j}}} \frac{\partial^{c_{i 2}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{c_{i 1}}} \end{array}\right] Hcij4×6=⎣⎡∂Rw2ci1∂ri1j,∂Rw2ci1∂ri2j,∂wpci1∂ri1j∂wpci1∂ri1j⎦⎤=⎣⎡∂ci1pfj∂ri1j∂Rw2ci1∂ci1pfj,∂ci1pfj∂ri1j∂wpci1∂ci1pfj∂ci2pfj∂ri2j∂Rw2ci1∂ci2pfj,∂ci2pfj∂ri2j∂wpci1∂ci2pfj⎦⎤我们知道双目的投影方程 { left : c i 1 p f j = R w 2 c i 1 ( w p f j − w p c i 1 ) right: c i 2 p f j = R c i 1 2 c i 2 ( R w 2 c i 1 ( w p f j − w p c i 1 ) ) + t c i 1 2 c i 2 \left\{\begin{array}{l} \operatorname{left}:^{c_{i1}} \mathbf{p}_{f_{j}}=\mathbf{R}_{w 2 c_{i1}}\left({ }^{w} \mathbf{p}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right) \\ \text { right: }{ }^{c_{i2}} \mathbf{p}_{f_{j}}=\mathbf{R}_{c_{i1} 2 c_{i2}}\left(\mathbf{R}_{w 2 c_{i1}}\left({}^{w}{\mathbf{p}}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right)\right)+\mathbf{t}_{c_{i 1} 2 c_{i 2}} \end{array}\right. {left:ci1pfj=Rw2ci1(wpfj−wpci1) right: ci2pfj=Rci12ci2(Rw2ci1(wpfj−wpci1))+tci12ci2然后根据这个投影方程求解雅克比 ∂ r i j ∂ c p f j = [ ∂ u ∂ x = 1 z , ∂ u ∂ y = 0 , ∂ u ∂ z = − x z 2 ∂ u ∂ x = 0 , ∂ u ∂ y = 1 z , ∂ u ∂ z = − y z 2 ] \frac{\partial \mathbf{r}_{i}^{j}}{\partial^{c} \mathbf{p}_{f_{j}}}=\left[\begin{array}{ll} \frac{\partial u}{\partial x}=\frac{1}{z}, & \frac{\partial u}{\partial y}=0, & \frac{\partial u}{\partial z}=-\frac{x}{z^{2}} \\ \frac{\partial u}{\partial x}=0, & \frac{\partial u}{\partial y}=\frac{1}{z}, & \frac{\partial u}{\partial z}=-\frac{y}{z^{2}} \end{array}\right] ∂cpfj∂rij=[∂x∂u=z1,∂x∂u=0,∂y∂u=0,∂y∂u=z1,∂z∂u=−z2x∂z∂u=−z2y] ∂ c i 1 p f j ∂ w p f j = R w 2 c i 1 ∂ c i 2 p f j ∂ w p f j = R w 2 c i 2 \frac{\partial^{c_{i1}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{f_{j}}}=\mathbf{R}_{w 2 c_{i1}} \quad \frac{\partial^{c_{i2}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{f_{j}}}=\mathbf{R}_{w 2 c_{i2}} ∂wpfj∂ci1pfj=Rw2ci1∂wpfj∂ci2pfj=Rw2ci2 ∂ c i 1 p f j ∂ w p c i 1 = − R w 2 c i 1 ∂ c i 2 p f j ∂ w p c i 1 = − R w 2 c i 2 \frac{\partial^{c_{i 1}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{c_{i 1}}}=-\mathbf{R}_{w 2 c_{i 1}} \quad \frac{\partial^{c_{i 2}} \mathbf{p}_{f_{j}}}{\partial^{w} \mathbf{p}_{c_{i 1}}}=-\mathbf{R}_{w 2 c_{i 2}} ∂wpci1∂ci1pfj=−Rw2ci1∂wpci1∂ci2pfj=−Rw2ci2 ∂ c i 1 p f j ∂ R w 2 c i 1 = lim δ θ → 0 ( R c i 1 2 w Exp ( δ θ ) ) T ( w p f j − w p c i 1 ) − R w 2 c i 1 ( w p f j − w p c i 1 ) δ θ = lim δ θ → 0 ( I − [ δ θ ] x ) R w 2 c i 1 ( w p f j − w p c i 1 ) − R w 2 c i 1 ( w p f j − w p c i 1 ) δ θ = lim δ θ → 0 − [ δ θ ] × R w 2 c i 1 ( w p f j − w p c i 1 ) δ θ = [ R w 2 c i 1 ( w p f j − w p c i 1 ) ] × = [ c i 1 p f j ] × \begin{aligned} \frac{\partial^{c_{i1}} \mathbf{p}_{f_{j}}}{\partial \mathbf{R}_{w 2 c_{i1}}}&=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{\left(\mathbf{R}_{c_{i1} 2 w} \operatorname{Exp}(\delta \boldsymbol{\theta})\right)^{T}\left({}^w \mathbf{p}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right)-\mathbf{R}_{w 2 c_{i1}}\left({}^w \mathbf{p}_{f_{j}}-{}^w \mathbf{p}_{c_{i1}}\right)}{\delta \mathbf{\theta}}\\ &=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{\left(\mathbf{I}-[\delta \boldsymbol{\theta}]_{x}\right) \mathbf{R}_{w 2 c_{i1}}\left({ }^{w} \mathbf{p}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right)-\mathbf{R}_{w 2 c_{i1}}\left({ }^{w} \mathbf{p}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right)}{\delta \mathbf{\theta}}\\ &=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{-[\delta \boldsymbol{\theta}]_{\times} \mathbf{R}_{w 2 c_{i1}}\left({ }^{w} \mathbf{p}_{f_{j}}-{{}^w\mathbf{p}}_{c_{i1}}\right)}{\delta \boldsymbol{\theta}}\\ &=\left[\mathbf{R}_{w 2 c_{i 1}}\left({ }^{w} \mathbf{p}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right)\right]_{\times}=\left[{ }^{c_{i1}} \mathbf{p}_{f_{j}}\right]_{\times} \end{aligned} ∂Rw2ci1∂ci1pfj=δθ→0limδθ(Rci12wExp(δθ))T(wpfj−wpci1)−Rw2ci1(wpfj−wpci1)=δθ→0limδθ(I−[δθ]x)Rw2ci1(wpfj−wpci1)−Rw2ci1(wpfj−wpci1)=δθ→0limδθ−[δθ]×Rw2ci1(wpfj−wpci1)=[Rw2ci1(wpfj−wpci1)]×=[ci1pfj]× ∂ c i 2 p f j ∂ R w 2 c i 1 = lim δ θ → 0 ( R c i 1 2 w Exp ( δ θ ) R c i 2 2 c i 1 ) T ( w p f j − w p c i 1 ) − R c i 1 2 c i 2 R w 2 c i 1 ( w p f j − w p c i 1 ) δ θ = lim δ θ → 0 R c i 1 2 c i 2 ( I − [ δ θ ] × ) R w 2 c i 1 ( w p f j − w p c i 1 ) − R c 11 2 c i 2 R w 2 c i 1 ( w p f j − w p c i 1 ) δ θ = R c i 1 2 c i 2 [ R w 2 c 1 ( w p f j − w p c i 1 ) ] × = R c i 1 2 c i 2 [ c i 1 p f j ] × \begin{aligned} \frac{\partial^{c_{i2}} \mathbf{p}_{f_{j}}}{\partial \mathbf{R}_{w 2 c_{i1}}}&=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{\left(\mathbf{R}_{c_{i1} 2 w} \operatorname{Exp}(\delta \boldsymbol{\theta}) \mathbf{R}_{c_{i2} 2 c_{i1}}\right)^{T}\left({ }^{w} \mathbf{p}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right)-\mathbf{R}_{c_{i1} 2 c_{i2}} \mathbf{R}_{w 2 c_{i1}}\left({}^w \mathbf{p}_{f_{j}}-{}^w{\mathbf{p}_{c_{i1}}}\right)}{\delta \boldsymbol{\theta}}\\ &=\lim _{\delta \boldsymbol{\theta} \rightarrow 0} \frac{\mathbf{R}_{c_{i 1} 2 c_{i 2}}\left(\mathbf{I}-[\delta \boldsymbol{\theta}]_{\times}\right) \mathbf{R}_{w 2 c_{i1}}\left({ }^{w} \mathbf{p}_{f_{j}}-{ }^{w} \mathbf{p}_{c_{i1}}\right)-\mathbf{R}_{c_{11} 2 c_{i 2}} \mathbf{R}_{w 2 c_{i1}}\left(w_{\mathbf{p}_{f_{j}}}-w_{\mathbf{p}_{c_{i1}}}\right)}{\delta \boldsymbol{\theta}}\\ &=\mathbf{R}_{c_{i_{1}} 2 c_{i_{2}}}\left[\mathbf{R}_{{}w 2 c_{1}}\left({}^w{\mathbf{p}_{f_{j}}}-{}^w{\mathbf{p}_{c_{i1}}}\right)\right]_{\times}=\mathbf{R}_{c_{i1} 2 c_{i2}}\left[{}^{c_{i1}} \mathbf{p}_{f_{j}}\right]_{\times} \end{aligned} ∂Rw2ci1∂ci2pfj=δθ→0limδθ(Rci12wExp(δθ)Rci22ci1)T(wpfj−wpci1)−Rci12ci2Rw2ci1(wpfj−wpci1)=δθ→0limδθRci12ci2(I−[δθ]×)Rw2ci1(wpfj−wpci1)−Rc112ci2Rw2ci1(wpfj−wpci1)=Rci12ci2[Rw2c1(wpfj−wpci1)]×=Rci12ci2[ci1pfj]×
这一部分代码对应为:
// 3d feature position in the world frame.
// And its observation with the stereo cameras.
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.
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.
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));
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);
dpc0_dxc.rightCols(3) = -R_w_c0;
Matrix<double, 3, 6> dpc1_dxc = Matrix<double, 3, 6>::Zero();
dpc1_dxc.leftCols(3) = R_c0_c1 * skewSymmetric(p_c0);
dpc1_dxc.rightCols(3) = -R_w_c1;
Matrix3d dpc0_dpg = R_w_c0;
Matrix3d dpc1_dpg = R_w_c1;
H_x = dz_dpc0*dpc0_dxc + dz_dpc1*dpc1_dxc;
H_f = dz_dpc0*dpc0_dpg + dz_dpc1*dpc1_dpg;
残差的计算为:
// Compute the residual.
r = z - Vector4d(p_c0(0)/p_c0(2), p_c0(1)/p_c0(2),
p_c1(0)/p_c1(2), p_c1(1)/p_c1(2));
上面求得的是第 j j j个特征点对第 i i i个相机的残差对特征点 H c i f j \mathbf{H}_{c_{i}}^{f_j} Hcifj以及相机状态的雅克比 H c i j \mathbf{H}_{c_{i}}^{j} Hcij,然后我们将上述雅克比和残差堆叠成第 j j j个特征点相关的雅克比矩阵 H f j \mathbf{H}^{f_j} Hfj和 H j \mathbf{H}^{j} Hj:
// Project the residual and Jacobians onto the nullspace
// of H_fj.
H_xj.block<4, 6>(stack_cntr, 21+6*cam_state_cntr) = H_xi;
H_fj.block<4, 3>(stack_cntr, 0) = H_fi;
r_j.segment<4>(stack_cntr) = r_i;
stack_cntr += 4;
从代码看,这里的堆叠顺序是纵向堆叠,紧接着对 H f j \mathbf{H}^{f_j} Hfj进行QR分解求得其左零空间,QR分解的原理如下 H = Q R = [ Q 1 , Q 2 ] [ R 1 0 ] ⇒ Q T H = [ Q 1 T H Q 2 T H ] = [ R 1 0 ] ⇒ Q 2 T H = 0 ⇒ V T = Q 2 T \begin{array}{l} \mathbf{H}=\mathbf{Q} \mathbf{R}=\left[\begin{array}{cc} \mathbf{Q}_{1}, & \mathbf{Q}_{2} \end{array}\right]\left[\begin{array}{c} \mathbf{R}_{1} \\ \mathbf{0} \\ \end{array}\right] \\ \Rightarrow \mathbf{Q}^{T} \mathbf{H}=\left[\begin{array}{l} \mathbf{Q}_{1}^{T} \mathbf{H} \\ \mathbf{Q}_{2}^{T} \mathbf{H} \end{array}\right]=\left[\begin{array}{c} \mathbf{R}_{1} \\ \mathbf{0} \end{array}\right] \\ \Rightarrow \mathbf{Q}_{2}^{T} \mathbf{H}=\mathbf{0} \Rightarrow \mathbf{V}^{T}=\mathbf{Q}_{2}^{T} \end{array} H=QR=[Q1,Q2][R10]⇒QTH=[Q1THQ2TH]=[R10]⇒Q2TH=0⇒VT=Q2T其中 H \mathbf{H} H的尺寸为 m × n m \times n m×n,那么 Q 1 \mathbf{Q}_1 Q1的尺寸为 m × n m \times n m×n, Q 2 \mathbf{Q}_2 Q2的尺寸为 m × ( m − n ) m \times (m-n) m×(m−n),假设观测到特征点 j j j的相机数量为 M M M,那么 H f j \mathbf{H}^{f_j} Hfj的尺寸就为 4 M × 3 4M \times 3 4M×3,那么 V T \mathbf{V}^T VT的尺寸就为 4 M × ( 4 M − 3 ) 4M \times (4M-3) 4M×(4M−3),那么投影到 H f j \mathbf{H}^{f_j} Hfj左零空间的 H o j \mathbf{H}^{j}_o Hoj矩阵尺寸为 ( 4 M − 3 ) × ( 21 + 6 C ) (4M-3) \times (21+6C) (4M−3)×(21+6C)其中 C C C是状态向量中相机的数量,代码对应为:
// Project the residual and Jacobians onto the nullspace
// of H_fj.
JacobiSVD<MatrixXd> svd_helper(H_fj, ComputeFullU | ComputeThinV);
MatrixXd A = svd_helper.matrixU().rightCols(
jacobian_row_size - 3);
H_x = A.transpose() * H_xj;
r = A.transpose() * r_j;
在求得每一个特征点相关的雅克比矩阵 H o j \mathbf{H}^{j}_o Hoj和残差向量 r j \mathbf{r}_j rj后同样是纵向堆叠成最终的观测矩阵 H o \mathbf{H}o Ho和残差 r \mathbf{r} r,代码如下:
H_x.block(stack_cntr, 0, H_xj.rows(), H_xj.cols()) = H_xj;
r.segment(stack_cntr, r_j.rows()) = r_j;
stack_cntr += H_xj.rows();
可以看出来,这样堆叠出来的观测矩阵如果特征点多的话将是一个可长可长的矩阵,因此在进行观测更新之前我们通过QR分解对观测矩阵进一步压缩: H o = [ Q 1 Q 2 ] [ R H 0 ] ⇒ r o = [ Q 1 Q 2 ] [ R H 0 ] x + n o ⇒ [ Q 1 T r o Q 2 T r o ] = [ T H 0 ] x + [ Q 1 T n o Q 2 T n o ] \mathbf{H}_{o}=\left[\begin{array}{cc} \mathbf{Q}_{1} & \mathbf{Q}_{2} \end{array}\right]\left[\begin{array}{c} \mathbf{R}_{H} \\ \mathbf{0} \end{array}\right] \Rightarrow \mathbf{r}_{o}=\left[\begin{array}{cc} \mathbf{Q}_{1} & \mathbf{Q}_{2} \end{array}\right]\left[\begin{array}{c} \mathbf{R}_{H} \\ \mathbf{0} \end{array}\right] {\mathbf{x}}+\mathbf{n}_{o} \Rightarrow\left[\begin{array}{c} \mathbf{Q}_{1}^{T} \mathbf{r}_{o} \\ \mathbf{Q}_{2}^{T} \mathbf{r}_{o} \end{array}\right]=\left[\begin{array}{c} \mathbf{T}_{H} \\ \mathbf{0} \end{array}\right] {\mathbf{x}}+\left[\begin{array}{c} \mathbf{Q}_{1}^{T} \mathbf{n}_{o} \\ \mathbf{Q}_{2}^{T} \mathbf{n}_{o} \end{array}\right] Ho=[Q1Q2][RH0]⇒ro=[Q1Q2][RH0]x+no⇒[Q1TroQ2Tro]=[TH0]x+[Q1TnoQ2Tno] ⇒ r n = Q 1 T r o = T H x + Q 1 T n o = R H x + n n \Rightarrow \mathbf{r}_{n}=\mathbf{Q}_{1}^{T} \mathbf{r}_{o}=\mathbf{T}_{H} {\mathbf{x}}+\mathbf{Q}_{1}^{T} \mathbf{n}_{o}=\mathbf{R}_{H}{\mathbf{x}}+\mathbf{n}_{n} ⇒rn=Q1Tro=THx+Q1Tno=RHx+nn对应代码为:
// Convert H to a sparse matrix.
SparseMatrix<double> H_sparse = H.sparseView();
// Perform QR decompostion on H_sparse.
SPQR<SparseMatrix<double> > spqr_helper;
spqr_helper.setSPQROrdering(SPQR_ORDERING_NATURAL);
spqr_helper.compute(H_sparse);
MatrixXd H_temp;
VectorXd r_temp;
(spqr_helper.matrixQ().transpose() * H).evalTo(H_temp);
(spqr_helper.matrixQ().transpose() * r).evalTo(r_temp);
H_thin = H_temp.topRows(21+state_server.cam_states.size()*6);
r_thin = r_temp.head(21+state_server.cam_states.size()*6);
接下来就是状态正常的卡尔曼更新了,代码如下所示:
// Compute the Kalman gain.
const MatrixXd& P = state_server.state_cov;
MatrixXd S = H_thin*P*H_thin.transpose() +
Feature::observation_noise