IMU预积分类 —IntegrationBase
IMU预积分的理论推导
为了便于代码分析,这里先给出VINS-Mono中IMU预积分的理论推导。
IMU噪声与零偏模型
IMU的量测模型可表示为:
{
a
^
b
=
a
b
+
b
a
+
R
w
b
g
w
+
n
a
ω
^
b
=
ω
b
+
b
ω
+
n
ω
(1)
\left\{ \begin{aligned} &\hat{\bm{a}}^b=\bm{a}^b+\bm{b}_a+\bm{R}_w^b\bm{g}^w+\bm{n}_a\\ &\hat{\bm{\omega}}^b=\bm{\omega}^b+\bm{b}_\omega+\bm{n}_\omega \end{aligned} \right. \tag{1}
{a^b=ab+ba+Rwbgw+naω^b=ωb+bω+nω(1)
式中,
a
^
b
\hat{\bm{a}}^b
a^b和
ω
^
b
\hat{\bm{\omega}}^b
ω^b分别表示IMU的加速度和角速度测量信息;
a
b
\bm{a}^b
ab和
ω
b
\bm{\omega}^b
ωb分别为载体真实的加速度和角速度;
b
a
\bm{b}_a
ba和
b
ω
\bm{b}_\omega
bω分别为加速度计和陀螺仪零偏,建模为随机游走过程:
{
n
b
a
∼
N
(
0
,
σ
b
a
2
)
,
n
b
ω
∼
N
(
0
,
σ
b
ω
2
)
b
a
˙
=
n
b
a
,
b
ω
˙
=
n
b
ω
(2)
\left\{ \begin{aligned} &\bm{n}_{\bm{b}_a}\sim\mathcal{N}\left(\bm{0},\bm{\sigma}_{b_a}^2\right),\bm{n}_{\bm{b}_\omega}\sim\mathcal{N}\left(\bm{0},\bm{\sigma}_{b_\omega}^2\right)\\ &\dot{\bm{b}_a}=\bm{n}_{\bm{b}_a},\dot{\bm{b}_\omega}=\bm{n}_{\bm{b}_\omega} \end{aligned} \right. \tag{2}
{nba∼N(0,σba2),nbω∼N(0,σbω2)ba˙=nba,bω˙=nbω(2)
R
w
b
\bm{R}_w^b
Rwb为世界坐标系到本体坐标系的坐标旋转矩阵;
g
w
\bm{g}^w
gw为世界坐标系下的重力加速度矢量;
n
a
∼
N
(
0
,
σ
a
2
)
\bm{n}_a\sim\mathcal{N}\left(\bm{0},\bm{\sigma}_a^2\right)
na∼N(0,σa2)和
n
ω
∼
(
0
,
σ
ω
2
)
\bm{n}_\omega\sim\left(\bm{0},\bm{\sigma}_\omega^2\right)
nω∼(0,σω2)为器件的高斯白噪声。
IMU预积分状态传播方程
连续时间形式
载体的位置、速度和姿态四元数在时间区间
[
t
k
,
t
k
+
1
]
\left[t_k,t_{k+1}\right]
[tk,tk+1]内的传播方程为:
{
p
k
+
1
w
=
p
k
w
+
v
k
w
Δ
t
k
+
∬
t
i
∈
[
t
k
,
t
k
+
1
]
(
R
b
t
i
w
(
a
^
t
i
−
b
a
−
n
a
)
−
g
w
)
d
t
2
v
k
+
1
w
=
v
k
w
+
∫
t
i
∈
[
t
k
,
t
k
+
1
]
(
R
b
t
i
w
(
a
^
t
i
−
b
a
−
n
a
)
−
g
w
)
d
t
q
w
b
k
+
1
=
q
w
b
k
⊗
∫
t
i
∈
[
t
k
,
t
k
+
1
]
1
2
Ω
(
ω
^
w
b
w
−
b
ω
−
n
ω
)
q
k
w
d
t
(3)
\left\{ \begin{aligned} &\bm{p}_{k+1}^w=\bm{p}_k^w+\bm{v}_k^w\Delta t_k+\iint_{t_i\in\left[t_k,t_{k+1}\right]}\left(\bm{R}_{b_{t_i}}^w\left(\hat{\bm{a}}_{t_i}-\bm{b}_a-\bm{n}_a\right)-\bm{g}^w\right)dt^2\\ &\bm{v}_{k+1}^w=\bm{v}_k^w+\int_{t_i\in\left[t_k,t_{k+1}\right]}\left(\bm{R}_{b_{t_i}}^w\left(\hat{\bm{a}}_{t_i}-\bm{b}_a-\bm{n}_a\right)-\bm{g}^w\right)dt\\ &\bm{q}_w^{b_{k+1}}=\bm{q}_w^{b_{k}}\otimes\int_{t_i\in\left[t_k,t_{k+1}\right]}\frac{1}{2}\bm{\Omega}\left(\hat{\bm{\omega}}_{wb}^w-\bm{b}_\omega-\bm{n}_\omega\right)\bm{q}_k^wdt \end{aligned} \right. \tag{3}
⎩⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎧pk+1w=pkw+vkwΔtk+∬ti∈[tk,tk+1](Rbtiw(a^ti−ba−na)−gw)dt2vk+1w=vkw+∫ti∈[tk,tk+1](Rbtiw(a^ti−ba−na)−gw)dtqwbk+1=qwbk⊗∫ti∈[tk,tk+1]21Ω(ω^wbw−bω−nω)qkwdt(3)
式中
q
w
b
k
+
1
{\bm{q}_w^{b_{k+1}}}
qwbk+1为世界坐标系到本体坐标系的旋转四元数,
⊗
\otimes
⊗表示四元数乘法,
Ω
(
ω
)
\bm{\Omega}\left(\bm{\omega}\right)
Ω(ω)为上一小节中由
ω
\bm{\omega}
ω组成的齐次矩阵,
b
k
\bm{b}_k
bk和
b
k
+
1
\bm{b}_{k+1}
bk+1分别为第
k
k
k帧和第
k
+
1
k+1
k+1帧对应的体坐标系,
b
t
i
\bm{b}_{t_i}
bti为
t
i
t_i
ti时刻的体坐标系。
可以看出,IMU的由第
k
k
k帧向第
k
+
1
k+1
k+1帧的状态传播需要第
k
k
k帧的旋转、位置和速度信息,这使得后端优化时,每当
k
k
k帧位姿优化完后均需要重新计算
k
+
1
k+1
k+1的相关变量;而若将式(3)中右侧的积分项表示在
k
k
k帧对应的本体系下,则该项不包含任何需要后端优化的位姿变量而只依赖于IMU的量测信息,更加便于后端优化处理。因此,增量形式的IMU状态传播方程为:
{
R
w
b
k
p
k
+
1
w
=
R
w
b
k
(
p
k
w
+
v
k
w
Δ
t
k
−
1
2
g
w
Δ
t
k
2
)
+
α
^
k
+
1
b
k
R
w
b
k
v
k
+
1
w
=
R
w
b
k
(
v
k
w
−
g
w
Δ
t
k
)
+
β
^
k
+
1
b
k
q
b
k
w
⊗
q
w
b
k
+
1
=
γ
^
k
+
1
b
k
(4)
\left\{ \begin{aligned} &\bm{R}_w^{b_k}\bm{p}_{k+1}^w=\bm{R}_w^{b_k}\left(\bm{p}_k^w+\bm{v}_k^w\Delta t_k-\frac{1}{2}\bm{g}^w\Delta t_k^2\right)+\hat{\bm{\alpha}}_{k+1}^{b_k}\\ &\bm{R}_w^{b_k}\bm{v}_{k+1}^w=\bm{R}_w^{b_k}\left(\bm{v}_k^w-\bm{g}^w\Delta t_k\right)+\hat{\bm{\beta}}_{k+1}^{b_k}\\ &\bm{q}_{b_{k}}^w\otimes\bm{q}_w^{b_{k+1}}=\hat{\bm{\gamma}}_{k+1}^{b_k} \end{aligned} \right. \tag{4}
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧Rwbkpk+1w=Rwbk(pkw+vkwΔtk−21gwΔtk2)+α^k+1bkRwbkvk+1w=Rwbk(vkw−gwΔtk)+β^k+1bkqbkw⊗qwbk+1=γ^k+1bk(4)
式中,
α
k
+
1
b
k
\bm{\alpha}_{k+1}^{b_k}
αk+1bk、
β
k
+
1
b
k
\bm{\beta}_{k+1}^{b_k}
βk+1bk和
γ
k
+
1
b
k
\bm{\gamma_{k+1}^{b_k}}
γk+1bk分别为
b
k
b_k
bk坐标系下第
k
k
k和
k
+
1
k+1
k+1帧之间IMU的预积分项:
{
α
^
k
+
1
b
k
=
∬
t
i
∈
[
t
k
,
t
k
+
1
]
(
R
b
t
i
b
k
(
a
^
t
i
−
b
a
−
n
a
)
)
d
t
2
β
^
k
+
1
b
k
=
∫
t
i
∈
[
t
k
,
t
k
+
1
]
(
R
b
t
i
b
k
(
a
^
t
i
−
b
a
−
n
a
)
)
d
t
γ
^
k
+
1
b
k
=
∫
t
i
∈
[
t
k
,
t
k
+
1
]
1
2
Ω
(
ω
^
w
b
w
−
b
ω
−
n
ω
)
γ
b
k
t
i
d
t
(5)
\left\{ \begin{aligned} &\hat{\bm{\alpha}}_{k+1}^{b_k}=\iint_{t_i\in\left[t_k,t_{k+1}\right]}\left(\bm{R}_{b_{t_i}}^{b_k}\left(\hat{\bm{a}}_{t_i}-\bm{b}_a-\bm{n}_a\right)\right)dt^2\\ &\hat{\bm{\beta}}_{k+1}^{b_k}=\int_{t_i\in\left[t_k,t_{k+1}\right]}\left(\bm{R}_{b_{t_i}}^{b_k}\left(\hat{\bm{a}}_{t_i}-\bm{b}_a-\bm{n}_a\right)\right)dt\\ &\hat{\bm{\gamma}}_{k+1}^{b_k}=\int_{t_i\in\left[t_k,t_{k+1}\right]}\frac{1}{2}\bm{\Omega}\left(\hat{\bm{\omega}}_{wb}^w-\bm{b}_\omega-\bm{n}_\omega\right)\bm{\gamma}_{b_k}^{t_i}dt \end{aligned} \right. \tag{5}
⎩⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎧α^k+1bk=∬ti∈[tk,tk+1](Rbtibk(a^ti−ba−na))dt2β^k+1bk=∫ti∈[tk,tk+1](Rbtibk(a^ti−ba−na))dtγ^k+1bk=∫ti∈[tk,tk+1]21Ω(ω^wbw−bω−nω)γbktidt(5)
可以看出,(5)中的IMU预积分项只和实际IMU期间量测以及IMU零偏有关。当后端优化的IMU零偏变化时,若变化较小,则使用IMU预积分项关于零偏的一阶近似更新预积分项;否则,则按照式(5)重新积分IMU得到预积分项。IMU预积分关于零偏的线性化更新表达式可以表示为:
{
α
^
k
k
+
1
≈
α
^
k
k
+
1
+
J
b
a
α
δ
b
a
+
J
b
ω
α
δ
b
ω
β
^
k
k
+
1
≈
β
^
k
k
+
1
+
J
b
a
β
δ
b
a
+
J
b
ω
β
δ
b
ω
γ
^
k
k
+
1
=
γ
^
k
k
+
1
⊗
J
b
ω
γ
δ
b
ω
(6)
\left\{ \begin{aligned} &\hat{\bm{\alpha}}_k^{k+1}\approx\hat{\bm{\alpha}}_k^{k+1}+\bm{J}^{\bm{\alpha}}_{\bm{b}_a}\delta\bm{b}_a+\bm{J}^{\bm{\alpha}}_{\bm{b}_\omega}\delta\bm{b}_\omega\\ &\hat{\bm{\beta}}_k^{k+1}\approx\hat{\bm{\beta}}_k^{k+1}+\bm{J}^{\bm{\beta}}_{\bm{b}_a}\delta\bm{b}_a+\bm{J}^{\bm{\beta}}_{\bm{b}_\omega}\delta\bm{b}_\omega\\ &\hat{\bm{\gamma}}_k^{k+1}=\hat{\bm{\gamma}}_k^{k+1}\otimes\bm{J}^{\bm{\gamma}}_{\bm{b}_\omega}\delta\bm{b}_\omega \end{aligned} \right. \tag{6}
⎩⎪⎪⎨⎪⎪⎧α^kk+1≈α^kk+1+Jbaαδba+Jbωαδbωβ^kk+1≈β^kk+1+Jbaβδba+Jbωβδbωγ^kk+1=γ^kk+1⊗Jbωγδbω(6)
这里公式的第三行与原文不同的原因是,原文中虽然偏导数写的是
J
b
ω
γ
\bm{J}^{\bm{\gamma}}_{\bm{b}_\omega}
Jbωγ,但为了与后续误差动力学方程对应,实际采用的偏导数是
J
b
ω
θ
\bm{J}^{\bm{\theta}}_{\bm{b}_\omega}
Jbωθ,即:
J
b
ω
γ
δ
b
ω
=
[
1
1
2
J
b
ω
θ
δ
b
ω
]
(7)
\bm{J}^{\bm{\gamma}}_{\bm{b}_\omega}\delta\bm{b}_\omega=\left[\begin{array}{c}1\\\frac{1}{2}\bm{J}^{\bm{\theta}}_{\bm{b}_\omega}\delta\bm{b}_\omega\end{array}\right] \tag{7}
Jbωγδbω=[121Jbωθδbω](7)
离散时间形式
为了与程序中对应,需要对连续形式的IMU传播方程进行离散化,由于程序中使用的是中值积分,这里也仅给出中值积分的IMU预积分离散传播方程为:
{
p
i
+
1
w
=
p
i
w
+
v
i
w
Δ
t
i
+
1
2
a
‾
t
i
δ
t
2
v
i
+
1
w
=
v
i
w
+
a
‾
t
i
δ
t
q
w
b
i
+
1
=
q
w
b
i
⊗
[
1
1
2
ω
‾
t
i
δ
t
]
(8)
\left\{ \begin{aligned} &\bm{p}_{i+1}^w=\bm{p}_i^w+\bm{v}_i^w\Delta t_i+\frac{1}{2}\overline{\bm{a}}_{t_i}\delta t^2\\ &\bm{v}_{i+1}^w=\bm{v}_i^w+\overline{\bm{a}}_{t_i}\delta t\\ &\bm{q}_w^{b_{i+1}}=\bm{q}_w^{b_{i}}\otimes\left[\begin{array}{c}1\\\frac{1}{2}\overline{\bm{\omega}}_{t_i}\delta t \end{array}\right] \end{aligned} \right. \tag{8}
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧pi+1w=piw+viwΔti+21atiδt2vi+1w=viw+atiδtqwbi+1=qwbi⊗[121ωtiδt](8)
其中:
{
a
‾
t
i
=
1
2
[
R
b
t
i
w
(
a
^
t
i
−
b
a
)
+
R
b
t
i
+
1
w
(
a
^
t
i
+
1
−
b
a
)
]
−
g
w
ω
‾
t
i
=
1
2
(
ω
^
t
i
+
ω
^
t
i
+
1
)
−
b
ω
(9)
\left\{ \begin{aligned} &\overline{\bm{a}}_{t_i}=\frac{1}{2}\left[\bm{R}_{b_{t_i}}^w\left(\hat{\bm{a}}_{t_i}-\bm{b}_a\right)+\bm{R}_{b_{t_{i+1}}}^w\left(\hat{\bm{a}}_{t_{i+1}}-\bm{b}_a\right)\right]-\bm{g}^w\\ &\overline{\bm{\omega}}_{t_i}=\frac{1}{2}\left(\hat{\bm{\omega}}_{t_i}+\hat{\bm{\omega}}_{t_{i+1}}\right)-\bm{b}_\omega \end{aligned} \right. \tag{9}
⎩⎪⎨⎪⎧ati=21[Rbtiw(a^ti−ba)+Rbti+1w(a^ti+1−ba)]−gwωti=21(ω^ti+ω^ti+1)−bω(9)
IMU预积分误差动力学方程
连续时间形式
在VINS的优化中,由于采用马氏距离构建二乘函数,需要对状态的协方差矩阵进行更新,而协方差矩阵的一步预测依赖于状态的误差动力学方程,因此这里我们首先就IMU预积分项的误差动力学方程进行推导。涉及的状态量包括位置增量 α k + 1 b k \bm{\alpha}_{k+1}^{b_k} αk+1bk、速度增量 β k + 1 b k \bm{\beta}_{k+1}^{b_k} βk+1bk、姿态增量 θ k + 1 b k \bm{\theta}_{k+1}^{b_k} θk+1bk、加速度计零偏 b a \bm{b}_a ba和陀螺仪零偏 b ω \bm{b_\omega} bω,其中由于陀螺器件测量为角增量,这里使用角增量 θ k + 1 b k \bm{\theta}_{k+1}^{b_k} θk+1bk代替四元数增量 γ k + 1 b k \bm{\gamma}_{k+1}^{b_k} γk+1bk。
由于我们需要求解的是上述各增量的误差动力学方程,因此系统状态空间矢量可记为:
δ
x
=
[
δ
α
t
b
k
δ
β
t
b
k
δ
θ
t
b
k
δ
b
a
δ
b
ω
n
a
n
ω
n
b
a
n
b
ω
]
(10)
\delta\bm{x}=\left[\begin{array}{ccccccccc} \delta\bm{\alpha}_t^{b_k} & \delta\bm{\beta}_t^{b_k} & \delta\bm{\theta}_t^{b_k} & \delta\bm{b}_a & \delta\bm{b}_\omega & \bm{n}_a & \bm{n}_\omega & \bm{n}_{\bm{b}_a} & \bm{n}_{\bm{b}_\omega} \end{array}\right] \tag{10}
δx=[δαtbkδβtbkδθtbkδbaδbωnanωnbanbω](10)
由于增量表示的是
k
+
1
k+1
k+1和
k
k
k之间的相对值,这里为了书写方便,下标使用
k
k
k而非前面
k
+
1
k+1
k+1,同时改用下标
t
t
t表示IMU测量时刻,以区别图像帧时刻
k
k
k,但两者本质上是同一个量。同时,由于导数运算的顺序可以交换,即
δ
a
˙
=
δ
a
˙
\delta\dot{\bm{a}}=\dot{\delta\bm{a}}
δa˙=δa˙,我们可以先求当前变量的时间导数,再求其对各状态量的偏导数。
- 位置增量误差
δ
α
t
b
k
\delta\bm{\alpha}_t^{b_k}
δαtbk
位置增量的时间导数为 α ˙ t b k = β t b k \dot{\bm{\alpha}}_t^{b_k}=\bm{\beta}_t^{b_k} α˙tbk=βtbk,显然,除了偏导数 δ α ˙ t b k / δ β t b k = I \delta\dot{\bm{\alpha}}_t^{b_k}/\delta\bm{\beta}_t^{b_k}=\bm{I} δα˙tbk/δβtbk=I外,位置增量的导数对其余状态增量的导数为零,即其余状态增量的变化对位置增量误差的导数没有贡献. - 速度增量误差
δ
β
t
b
k
\delta\bm{\beta}_t^{b_k}
δβtbk
速度增量的时间导数为 β ˙ t b k = R b t b k ( a ^ t − b a − n a ) \dot{\bm{\beta}}_t^{b_k}=\bm{R}_{b_t}^{b_k}\left(\hat{\bm{a}}_t-\bm{b}_a-\bm{n}_a\right) β˙tbk=Rbtbk(a^t−ba−na),可以看出非零偏导数共有三项,分别为:
δ β t b k δ θ k b k = − R b t b k ( a ^ t − b a − n a ) ≈ − R b t b k ( a ^ t − b a ) δ β t b k b a = − R b t b k δ β t b k n a = − R b t b k (11) \begin{aligned} \frac{\delta\bm{\beta}_t^{b_k}}{\delta\bm{\theta}_k^{b_k}}&=-\bm{R}_{b_t}^{b_k}\left(\hat{\bm{a}}_t-\bm{b}_a-\bm{n}_a\right)\\ &\approx-\bm{R}_{b_t}^{b_k}\left(\hat{\bm{a}}_t-\bm{b}_a\right)\\ \frac{\delta\bm{\beta}_t^{b_k}}{\bm{b}_a}&=-\bm{R}_{b_t}^{b_k}\\ \frac{\delta\bm{\beta}_t^{b_k}}{\bm{n}_a}&=-\bm{R}_{b_t}^{b_k} \end{aligned} \tag{11} δθkbkδβtbkbaδβtbknaδβtbk=−Rbtbk(a^t−ba−na)≈−Rbtbk(a^t−ba)=−Rbtbk=−Rbtbk(11)
其中,由于状态递推的本质是随机变量均值的传播,而 n a \bm{n}_a na是零均值的高斯白噪声,可作为零值处理。 - 角增量误差
δ
θ
t
b
k
\delta\bm{\theta}_t^{b_k}
δθtbk
由于角增量的运算中涉及四元数的乘法,使用导数微分定义求解会比较复杂,这里我们换一种思路,假设无任何偏差的四元数时间导数和带各项扰动的四元数时间导数分别为 q ˙ n \dot{\bm{q}}_n q˙n和 q ˙ t \dot{\bm{q}}_t q˙t,则:
q ˙ t = 1 2 q ⊗ δ q ⏟ δ θ ⊗ [ 0 ω ^ − b ω − n ω − δ b ω ] q ˙ n = 1 2 q ⊗ [ 0 ω ^ − b ω ] (12) \begin{aligned} \dot{\bm{q}}_t&=\frac{1}{2}\underbrace{\bm{q}\otimes\delta\bm{q}}_{\delta\bm{\theta}}\otimes\left[\begin{array}{c} 0\\\hat{\bm{\omega}}-\bm{b}_\omega-\bm{n}_\omega-\delta\bm{b}_\omega \end{array}\right]\\ \dot{\bm{q}}_n&=\frac{1}{2}\bm{q}\otimes\left[\begin{array}{c} 0\\\hat{\bm{\omega}}-\bm{b}_\omega \end{array}\right] \end{aligned} \tag{12} q˙tq˙n=21δθ q⊗δq⊗[0ω^−bω−nω−δbω]=21q⊗[0ω^−bω](12)
同时, q ˙ t \dot{\bm{q}}_t q˙t又可表示为:
q ˙ t = ∂ ( q ⊗ δ q ) ∂ t = q ˙ ⊗ δ q + q ⊗ δ q ˙ = 1 2 q ⊗ [ 0 ω − b ω ] ⊗ δ q + q ⊗ δ q ˙ (13) \begin{aligned} \dot{\bm{q}}_t&=\frac{\partial\left(\bm{q}\otimes\delta\bm{q}\right)}{\partial t}=\dot{\bm{q}}\otimes\delta\bm{q}+\bm{q}\otimes\dot{\delta\bm{q}}\\ &=\frac{1}{2}\bm{q}\otimes\left[\begin{array}{c} 0\\\bm{\omega}-\bm{b}_\omega \end{array}\right]\otimes\delta\bm{q}+\bm{q}\otimes\dot{\delta\bm{q}} \end{aligned} \tag{13} q˙t=∂t∂(q⊗δq)=q˙⊗δq+q⊗δq˙=21q⊗[0ω−bω]⊗δq+q⊗δq˙(13)
令上述两式相等可得到:
1 2 q ⊗ δ q ⊗ [ 0 ω ^ − b ω − n ω − δ b ω ] = 1 2 q ⊗ [ 0 ω − b ω ] ⊗ δ q + q ⊗ δ q ˙ ⇒ 1 2 δ q ⊗ [ 0 ω ^ − b ω − n ω − δ b ω ] = 1 2 [ 0 ω − b ω ] ⊗ δ q + δ q ˙ ⇒ 2 δ ˙ q = δ q ⊗ [ 0 ω ^ − b ω − n ω − δ b ω ] − [ 0 ω − b ω ] ⊗ δ q ⇒ 2 δ q ˙ = R ( [ 0 ω ^ − b ω − n ω − δ b ω ] ) δ q − L ( [ 0 n ω + δ b ω ] ) δ q ⇒ 2 δ q ˙ = [ 0 ( n ω + δ b ω ) T − ( n ω − δ b ω ) − ( 2 ω ^ − 2 b ω − n ω − δ b ω ) ∧ ] [ 1 δ θ 2 ] (14) \begin{aligned} &\frac{1}{2}\bm{q}\otimes\delta\bm{q}\otimes\left[\begin{array}{c} 0\\\hat{\bm{\omega}}-\bm{b}_\omega-\bm{n}_\omega-\delta\bm{b}_\omega \end{array}\right]=\frac{1}{2}\bm{q}\otimes\left[\begin{array}{c} 0\\\bm{\omega}-\bm{b}_\omega \end{array}\right]\otimes\delta\bm{q}+\bm{q}\otimes\dot{\delta\bm{q}}\\ \Rightarrow&\frac{1}{2}\delta\bm{q}\otimes\left[\begin{array}{c} 0\\\hat{\bm{\omega}}-\bm{b}_\omega-\bm{n}_\omega-\delta\bm{b}_\omega \end{array}\right]=\frac{1}{2}\left[\begin{array}{c} 0\\\bm{\omega}-\bm{b}_\omega \end{array}\right]\otimes\delta\bm{q}+\dot{\delta\bm{q}}\\ \Rightarrow&2\dot{\delta}\bm{q}=\delta\bm{q}\otimes\left[\begin{array}{c} 0\\\hat{\bm{\omega}}-\bm{b}_\omega-\bm{n}_\omega-\delta\bm{b}_\omega \end{array}\right]-\left[\begin{array}{c} 0\\\bm{\omega}-\bm{b}_\omega \end{array}\right]\otimes\delta\bm{q}\\ \Rightarrow&2\dot{\delta\bm{q}}=\mathcal{R}\left(\left[\begin{array}{c} 0\\\hat{\bm{\omega}}-\bm{b}_\omega-\bm{n}_\omega-\delta\bm{b}_\omega \end{array}\right]\right)\delta\bm{q}-\mathcal{L}\left(\left[\begin{array}{c} 0\\\bm{n}_\omega+\delta\bm{b}_\omega \end{array}\right]\right)\delta\bm{q}\\ \Rightarrow&2\dot{\delta\bm{q}}=\left[\begin{matrix} 0 & \left(\bm{n}_\omega+\delta\bm{b}_\omega\right)^T\\ -\left(\bm{n}_\omega-\delta\bm{b}_\omega\right) & -\left(2\hat{\bm{\omega}}-2\bm{b}_\omega-\bm{n}_\omega-\delta\bm{b}_\omega\right)^\wedge\\ \end{matrix}\right]\left[\begin{array}{c} 1\\\frac{\delta\bm{\theta}}{2} \end{array}\right]\\ \end{aligned} \tag{14} ⇒⇒⇒⇒21q⊗δq⊗[0ω^−bω−nω−δbω]=21q⊗[0ω−bω]⊗δq+q⊗δq˙21δq⊗[0ω^−bω−nω−δbω]=21[0ω−bω]⊗δq+δq˙2δ˙q=δq⊗[0ω^−bω−nω−δbω]−[0ω−bω]⊗δq2δq˙=R([0ω^−bω−nω−δbω])δq−L([0nω+δbω])δq2δq˙=[0−(nω−δbω)(nω+δbω)T−(2ω^−2bω−nω−δbω)∧][12δθ](14)
将 δ q ˙ = [ 0 1 2 δ θ ˙ ] \dot{\delta\bm{q}}=\left[\begin{array}{c} 0\\\frac{1}{2}\dot{\delta\bm{\theta}} \end{array}\right] δq˙=[021δθ˙]带入上式可以并忽略零均值项 n ω \bm{n}_\omega nω以及二阶小量 δ b ω δ θ \delta\bm{b}_\omega\delta\bm{\theta} δbωδθ可以得到:
[ 0 δ θ ˙ ] = [ 0 ( n ω + δ b ω ) T − ( n ω − δ b ω ) − ( 2 ω ^ − 2 b ω − n ω − δ b ω ) ∧ ] [ 1 δ θ 2 ] ⇒ δ θ ˙ ≈ − ( ω ^ − b ω ) ∧ δ θ − n ω − δ b ω (15) \begin{aligned} \left[\begin{array}{c} 0\\\dot{\delta\bm{\theta}}\end{array}\right]&=\left[\begin{matrix} 0 & \left(\bm{n}_\omega+\delta\bm{b}_\omega\right)^T\\ -\left(\bm{n}_\omega-\delta\bm{b}_\omega\right) & -\left(2\hat{\bm{\omega}}-2\bm{b}_\omega-\bm{n}_\omega-\delta\bm{b}_\omega\right)^\wedge\\ \end{matrix}\right]\left[\begin{array}{c} 1\\\frac{\delta\bm{\theta}}{2} \end{array}\right]\\ \Rightarrow\dot{\delta\bm{\theta}}&\approx-\left(\hat{\bm{\omega}}-\bm{b}_\omega\right)^\wedge\delta\bm{\theta}-\bm{n}_\omega-\delta\bm{b}_\omega \end{aligned} \tag{15} [0δθ˙]⇒δθ˙=[0−(nω−δbω)(nω+δbω)T−(2ω^−2bω−nω−δbω)∧][12δθ]≈−(ω^−bω)∧δθ−nω−δbω(15) - 加速度计零偏误差 δ b a \delta\bm{b}_a δba:根据IMU的器件模型有 δ b ˙ a = n b a \delta\dot{\bm{b}}_a=\bm{n}_{\bm{b}_a} δb˙a=nba。
- 陀螺零偏误差 δ b ω \delta\bm{b}_\omega δbω:同样根据IMU的器件模型有 δ b ˙ ω = n b ω \delta\dot{\bm{b}}_\omega=\bm{n}_{\bm{b}_\omega} δb˙ω=nbω。
至此,我们已经获得了所有非零均值状态量动力学方程,写成矩阵形式为:
[
δ
α
˙
t
b
k
δ
β
˙
t
b
k
δ
θ
˙
t
b
k
δ
b
a
˙
δ
b
ω
˙
]
=
[
0
I
0
0
0
0
0
−
R
b
t
b
k
(
a
^
t
−
b
a
)
∧
−
R
b
t
b
k
0
0
0
−
(
ω
^
t
−
b
ω
)
∧
0
−
I
0
0
0
0
0
0
0
0
0
0
]
[
δ
α
t
b
k
δ
β
t
b
k
δ
θ
t
b
k
δ
b
a
δ
b
ω
]
+
[
0
0
0
0
−
R
b
t
b
k
0
0
0
0
−
I
0
0
0
0
I
0
0
0
0
I
]
[
n
a
n
ω
n
b
a
n
b
ω
]
⇒
δ
x
˙
t
=
f
t
δ
x
t
+
v
t
n
t
(16)
\begin{aligned} \left[\begin{array}{c} \delta\dot{\bm{\alpha}}_t^{b_k}\\\delta\dot{\bm{\beta}}_t^{b_k}\\\delta\dot{\bm{\theta}}_t^{b_k}\\ \delta\dot{\bm{b}_a}\\\delta\dot{\bm{b}_\omega} \end{array}\right]&=\left[\begin{matrix} 0 & \bm{I} & 0 & 0 & 0\\ 0 & 0 & -\bm{R}_{b_t}^{b_k}\left(\hat{\bm{a}}_t-\bm{b}_a\right)^\wedge & -\bm{R}_{b_t}^{b_k} & 0\\ 0 & 0 & -\left(\hat{\bm{\omega}}_t-\bm{b}_\omega\right)^\wedge & 0 & -\bm{I}\\ 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 & 0 \end{matrix}\right]\left[\begin{array}{c} \delta\bm{\alpha}_t^{b_k}\\\delta\bm{\beta}_t^{b_k}\\\delta\bm{\theta}_t^{b_k}\\ \delta\bm{b}_a\\\delta\bm{b}_\omega \end{array}\right]\\ &+\left[\begin{matrix} 0 & 0 & 0 & 0\\ -\bm{R}_{b_t}^{b_k} & 0 & 0 & 0\\ 0 & -\bm{I} & 0 & 0\\ 0 & 0 & \bm{I} & 0\\ 0 & 0 & 0 & \bm{I} \end{matrix}\right]\left[\begin{array}{c} \bm{n}_a\\\bm{n}_\omega\\\bm{n}_{\bm{b}_a}\\\bm{n}_{\bm{b}_\omega} \end{array}\right]\\ \Rightarrow\dot{\delta\bm{x}}_t&=\bm{f}_t\delta\bm{x}_t+\bm{v}_t\bm{n}_t \end{aligned} \tag{16}
⎣⎢⎢⎢⎢⎢⎡δα˙tbkδβ˙tbkδθ˙tbkδba˙δbω˙⎦⎥⎥⎥⎥⎥⎤⇒δx˙t=⎣⎢⎢⎢⎢⎡00000I00000−Rbtbk(a^t−ba)∧−(ω^t−bω)∧000−Rbtbk00000−I00⎦⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎡δαtbkδβtbkδθtbkδbaδbω⎦⎥⎥⎥⎥⎤+⎣⎢⎢⎢⎢⎡0−Rbtbk00000−I00000I00000I⎦⎥⎥⎥⎥⎤⎣⎢⎢⎡nanωnbanbω⎦⎥⎥⎤=ftδxt+vtnt(16)
根据导数的定义,可以将上式改写为递推形式:
δ
x
t
+
1
−
δ
x
t
δ
t
=
f
t
δ
x
t
+
v
t
n
t
δ
x
t
+
1
=
δ
x
t
+
f
t
δ
x
t
δ
t
+
v
t
n
t
δ
t
=
(
I
+
f
t
δ
t
)
⏟
F
t
δ
x
t
+
v
t
δ
t
⏟
V
t
n
t
(17)
\begin{aligned} \frac{\delta\bm{x}_{t+1}-\delta\bm{x}_t}{\delta t}&=\bm{f}_t\delta\bm{x}_t+\bm{v}_t\bm{n}_t\\ \delta\bm{x}_{t+1}&=\delta\bm{x}_t+\bm{f}_t\delta\bm{x}_t\delta t + \bm{v}_t\bm{n}_t\delta t\\ &=\underbrace{\left(\bm{I}+\bm{f}_t\delta t\right)}_{\bm{F}_t}\delta\bm{x}_t+\underbrace{\bm{v}_t\delta t}_{\bm{V}_t}\bm{n}_t \end{aligned} \tag{17}
δtδxt+1−δxtδxt+1=ftδxt+vtnt=δxt+ftδxtδt+vtntδt=Ft
(I+ftδt)δxt+Vt
vtδtnt(17)
可以看出,上式是一个标准的状态空间模型,给出了随机变量均值的传播方程;同样,我们可以直接写出随机变量方差的传播方程:
P
t
+
1
=
F
t
P
t
F
t
T
+
V
t
Q
t
V
t
T
P
0
=
0
Q
0
=
[
σ
a
2
0
0
0
0
σ
ω
2
0
0
0
0
σ
b
a
2
0
0
0
0
σ
b
ω
2
]
(18)
\begin{aligned} \bm{P}_{t+1}&=\bm{F}_t\bm{P}_t\bm{F}_t^T+\bm{V}_t\bm{Q}_t\bm{V}_t^T\\ \bm{P}_0&=\bm{0}\\ \bm{Q}_0&=\left[\begin{matrix} \sigma_a^2 & 0 & 0 & 0\\ 0 & \sigma_\omega^2 & 0 & 0\\ 0 & 0 & \sigma_{\bm{b}_a}^2 & 0\\ 0 & 0 & 0 & \sigma_{\bm{b}_\omega}^2 \end{matrix}\right] \end{aligned} \tag{18}
Pt+1P0Q0=FtPtFtT+VtQtVtT=0=⎣⎢⎢⎡σa20000σω20000σba20000σbω2⎦⎥⎥⎤(18)
误差雅克比矩阵的更新为:
J
k
+
1
=
∏
t
∈
[
k
,
k
+
1
]
F
t
J
k
J
k
=
I
(19)
\begin{aligned} \bm{J}_{k+1}&=\prod\limits_{t\in\left[k,k+1\right]}\bm{F}_t\bm{J}_k\\ \bm{J}_k&=\bm{I} \end{aligned} \tag{19}
Jk+1Jk=t∈[k,k+1]∏FtJk=I(19)
注意这里的下标为图像帧
k
k
k而非IMU量测
t
t
t。
离散时间形式
同样,这里采用中值积分对式(16)进行离散化,由于离散化推导过程较为繁杂,这里直接给出结论,详细过程参见github链接。
[
δ
α
t
+
1
δ
θ
t
+
1
δ
β
t
+
1
δ
b
a
t
+
1
δ
b
ω
t
+
1
]
=
[
I
f
01
δ
t
I
f
03
f
04
0
f
11
0
0
−
δ
t
I
0
f
21
I
f
23
f
24
0
0
0
I
0
0
0
0
0
I
]
[
δ
α
t
δ
θ
t
δ
β
t
δ
b
a
t
δ
b
ω
t
]
+
[
v
00
v
01
v
02
v
03
0
0
0
−
δ
t
2
I
0
−
δ
t
2
I
0
0
−
R
b
t
b
k
δ
t
2
v
21
−
R
b
t
+
1
b
k
δ
t
2
v
23
0
0
0
0
0
0
δ
t
I
0
0
0
0
0
0
δ
t
I
]
[
n
a
t
n
ω
t
n
a
t
+
1
n
ω
t
+
1
n
b
a
n
b
ω
]
(20)
\begin{aligned} \left[\begin{array}{c} \delta\bm{\alpha}_{t+1}\\\delta\bm{\theta}_{t+1}\\\delta\bm{\beta}_{t+1}\\ \delta{\bm{b}_a}_{t+1}\\\delta{\bm{b}_\omega}_{t+1} \end{array}\right]&= \left[\begin{matrix} \bm{I} & f_{01} & \delta t\bm{I} & f_{03} & f_{04}\\ 0 & f_{11} & 0 & 0 & -\delta t\bm{I}\\ 0 & f_{21} & \bm{I} & f_{23} & f_{24} \\ 0 & 0 & 0 & \bm{I} & 0 \\ 0 & 0 & 0 & 0 & \bm{I} \end{matrix}\right]\left[\begin{array}{c} \delta\bm{\alpha}_t\\\delta\bm{\theta}_t\\\delta\bm{\beta}_t\\ \delta{\bm{b}_a}_t\\\delta{\bm{b}_\omega}_t \end{array}\right]\\ &+\left[\begin{matrix} v_{00} & v_{01} & v_{02} & v_{03} & 0 & 0\\ 0 & -\frac{\delta t}{2}\bm{I} & 0 & -\frac{\delta t}{2}\bm{I} & 0 & 0\\ -\frac{\bm{R}_{b_t}^{b_k}\delta t}{2} & v_{21} & -\frac{\bm{R}_{b_{t+1}}^{b_k}\delta t}{2} & v_{23} & 0 & 0\\ 0 & 0 & 0 & 0 & \delta t\bm{I} & 0\\ 0 & 0 & 0 & 0 & 0 & \delta t\bm{I} \end{matrix}\right]\left[\begin{array}{c} {\bm{n}_a}_t\\{\bm{n}_\omega}_t\\{\bm{n}_a}_{t+1}\\{\bm{n}_\omega}_{t+1}\\ \bm{n}_{\bm{b}_a}\\\bm{n}_{\bm{b}_\omega} \end{array}\right] \end{aligned} \tag{20}
⎣⎢⎢⎢⎢⎡δαt+1δθt+1δβt+1δbat+1δbωt+1⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡I0000f01f11f2100δtI0I00f030f23I0f04−δtIf240I⎦⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎡δαtδθtδβtδbatδbωt⎦⎥⎥⎥⎥⎤+⎣⎢⎢⎢⎢⎢⎡v000−2Rbtbkδt00v01−2δtIv2100v020−2Rbt+1bkδt00v03−2δtIv2300000δtI00000δtI⎦⎥⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎢⎢⎡natnωtnat+1nωt+1nbanbω⎦⎥⎥⎥⎥⎥⎥⎤(20)
F
\bm{F}
F矩阵中对应元素具体表达式如下:
f
01
=
{
−
1
4
R
b
t
b
k
(
a
^
t
−
b
a
)
∧
δ
t
2
−
1
4
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
[
I
−
(
ω
^
t
+
ω
^
t
+
1
2
−
b
ω
)
∧
δ
t
]
δ
t
2
}
f
03
=
−
1
4
(
R
b
t
b
k
+
R
b
t
+
1
b
k
)
δ
t
2
f
04
=
1
4
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
δ
t
3
f
11
=
[
I
−
(
ω
^
t
+
ω
^
t
+
1
2
−
b
ω
)
∧
δ
t
]
f
21
=
{
−
1
2
R
b
t
b
k
(
a
^
t
−
b
a
)
∧
−
1
2
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
[
I
−
(
ω
^
t
+
ω
^
t
+
1
2
−
b
ω
)
∧
δ
t
]
}
δ
t
f
23
=
−
1
2
(
R
b
t
b
k
+
R
b
t
+
1
b
k
)
δ
t
f
24
=
1
2
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
δ
t
2
(21)
\begin{aligned} f_{01}&=\left\{-\frac{1}{4}\bm{R}_{b_t}^{b_k}\left(\hat{\bm{a}}_t-\bm{b}_a\right)^\wedge\delta t^2-\frac{1}{4}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\left[\bm{I}-\left(\frac{\hat{\bm{\omega}}_t+\hat{\bm{\omega}}_{t+1}}{2}-\bm{b}_\omega\right)^\wedge\delta t\right]\delta t^2\right\}\\ f_{03}&=-\frac{1}{4}\left(\bm{R}_{b_t}^{b_k}+\bm{R}_{b_{t+1}}^{b_k}\right)\delta t^2\\ f_{04}&=\frac{1}{4}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\delta t^3\\ f_{11}&=\left[\bm{I}-\left(\frac{\hat{\bm{\omega}}_t+\hat{\bm{\omega}}_{t+1}}{2}-\bm{b}_\omega\right)^\wedge\delta t\right]\\ f_{21}&=\left\{-\frac{1}{2}\bm{R}_{b_t}^{b_k}\left(\hat{\bm{a}}_t-\bm{b}_a\right)^\wedge-\frac{1}{2}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\left[\bm{I}-\left(\frac{\hat{\bm{\omega}}_t+\hat{\bm{\omega}}_{t+1}}{2}-\bm{b}_\omega\right)^\wedge\delta t\right]\right\}\delta t\\ f_{23}&=-\frac{1}{2}\left(\bm{R}_{b_t}^{b_k}+\bm{R}_{b_{t+1}}^{b_k}\right)\delta t\\ f_{24}&=\frac{1}{2}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\delta t^2 \end{aligned} \tag{21}
f01f03f04f11f21f23f24={−41Rbtbk(a^t−ba)∧δt2−41Rbt+1bk(a^t+1−ba)∧[I−(2ω^t+ω^t+1−bω)∧δt]δt2}=−41(Rbtbk+Rbt+1bk)δt2=41Rbt+1bk(a^t+1−ba)∧δt3=[I−(2ω^t+ω^t+1−bω)∧δt]={−21Rbtbk(a^t−ba)∧−21Rbt+1bk(a^t+1−ba)∧[I−(2ω^t+ω^t+1−bω)∧δt]}δt=−21(Rbtbk+Rbt+1bk)δt=21Rbt+1bk(a^t+1−ba)∧δt2(21)
V
\bm{V}
V矩阵中对应元素具体表达式如下:
v
00
=
−
1
4
R
b
t
b
k
δ
t
2
v
01
=
1
8
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
δ
t
3
v
02
=
−
1
4
R
b
t
+
1
b
k
δ
t
2
v
03
=
1
8
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
δ
t
3
v
21
=
1
4
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
δ
t
2
v
23
=
1
4
R
b
t
+
1
b
k
(
a
^
t
+
1
−
b
a
)
∧
δ
t
2
(22)
\begin{aligned} v_{00}&=-\frac{1}{4}\bm{R}_{b_t}^{b_k}\delta t^2\\ v_{01}&=\frac{1}{8}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\delta t^3\\ v_{02}&=-\frac{1}{4}\bm{R}_{b_{t+1}}^{b_k}\delta t^2\\ v_{03}&=\frac{1}{8}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\delta t^3\\ v_{21}&=\frac{1}{4}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\delta t^2\\ v_{23}&=\frac{1}{4}\bm{R}_{b_{t+1}}^{b_k}\left(\hat{\bm{a}}_{t+1}-\bm{b}_a\right)^\wedge\delta t^2 \end{aligned} \tag{22}
v00v01v02v03v21v23=−41Rbtbkδt2=81Rbt+1bk(a^t+1−ba)∧δt3=−41Rbt+1bkδt2=81Rbt+1bk(a^t+1−ba)∧δt3=41Rbt+1bk(a^t+1−ba)∧δt2=41Rbt+1bk(a^t+1−ba)∧δt2(22)
IntegrationBase类详解
成员变量
IntegrationBase
类是VINS-Mono中用于处理IMU预积分相关功能的类,位于vins_estimator/src/factor/integration_base.h头文件中,包含的成员变量如下:
double dt; // 每次预积分的时间周期长度
Eigen::Vector3d acc_0, gyr_0; // t时刻对应的IMU测量值
Eigen::Vector3d acc_1, gyr_1; // t+1时刻对应的IMU测量值
const Eigen::Vector3d linearized_acc, linearized_gyr; // k帧图像时刻对应的IMU测量值
Eigen::Vector3d linearized_ba, linearized_bg; // 加速度计和陀螺仪零偏,在[k,k+1]区间上视为不变
Eigen::Matrix<double, 15, 15> jacobian, covariance; // 预积分误差的雅克比矩阵
Eigen::Matrix<double, 18, 18> noise; //系统噪声矩阵
double sum_dt; //所有IMU预积分区间的总时长,由于量测的不同步性,不一定有sum_dt = (k+1)-k
Eigen::Vector3d delta_p; // 位置预积分
Eigen::Quaterniond delta_q; // 旋转四元数预积分
Eigen::Vector3d delta_v; // 速度预积分
std::vector<double> dt_buf; // 用于存储每次预积分时间dt的寄存器
std::vector<Eigen::Vector3d> acc_buf; // 用于存储每次预积分加速度量测的寄存器
std::vector<Eigen::Vector3d> gyr_buf; // 用于存储每次预积分角速度量测的寄存器
成员函数
构造函数(IntegrationBase)
VINS-Mono要求预积分中的参数必须进行初始化,因此移除了默认构造函数,仅允许使用如下所示的唯一构造函数:
IntegrationBase(const Eigen::Vector3d &_acc_0, const Eigen::Vector3d &_gyr_0,
const Eigen::Vector3d &_linearized_ba, const Eigen::Vector3d &_linearized_bg)
: acc_0{_acc_0}, gyr_0{_gyr_0}, linearized_acc{_acc_0}, linearized_gyr{_gyr_0},
linearized_ba{_linearized_ba}, linearized_bg{_linearized_bg},
jacobian{Eigen::Matrix<double, 15, 15>::Identity()}, covariance{Eigen::Matrix<double, 15, 15>::Zero()},
sum_dt{0.0}, delta_p{Eigen::Vector3d::Zero()}, delta_q{Eigen::Quaterniond::Identity()}, delta_v{Eigen::Vector3d::Zero()}
{
// 噪声矩阵
// ACC_N, GYR_N: 加速度计和陀螺白噪声均值
// ACC_W, GYR_W: 加速度计和陀螺随机游走
noise = Eigen::Matrix<double, 18, 18>::Zero();
noise.block<3, 3>(0, 0) = (ACC_N * ACC_N) * Eigen::Matrix3d::Identity();
noise.block<3, 3>(3, 3) = (GYR_N * GYR_N) * Eigen::Matrix3d::Identity();
noise.block<3, 3>(6, 6) = (ACC_N * ACC_N) * Eigen::Matrix3d::Identity();
noise.block<3, 3>(9, 9) = (GYR_N * GYR_N) * Eigen::Matrix3d::Identity();
noise.block<3, 3>(12, 12) = (ACC_W * ACC_W) * Eigen::Matrix3d::Identity();
noise.block<3, 3>(15, 15) = (GYR_W * GYR_W) * Eigen::Matrix3d::Identity();
}
该构造函数接收第k帧时刻对应的加速度、角速度、加速度计零偏和陀螺仪零偏,并完成各成员变量的初始化,初始化中的各成员变量含义上一节已说明,此处不再赘述。
中值积分函数(midPointIntegration)
该函数用于求解IMU的预积分状态递推和更新对应的Jacobian矩阵,函数原型如下:
void midPointIntegration(double _dt,
const Eigen::Vector3d &_acc_0, const Eigen::Vector3d &_gyr_0,
const Eigen::Vector3d &_acc_1, const Eigen::Vector3d &_gyr_1,
const Eigen::Vector3d &delta_p, const Eigen::Quaterniond &delta_q, const Eigen::Vector3d &delta_v,
const Eigen::Vector3d &linearized_ba, const Eigen::Vector3d &linearized_bg,
Eigen::Vector3d &result_delta_p, Eigen::Quaterniond &result_delta_q, Eigen::Vector3d &result_delta_v,
Eigen::Vector3d &result_linearized_ba, Eigen::Vector3d &result_linearized_bg, bool update_jacobian)
函数接口参数分别为:
- t时刻的IMU量测:_acc_0, _gyr_0
- t时刻的位置、姿态、速度预积分估计值:delta_p, delta_q, delta_v
- t+1时刻的IMU量测:_acc_1, _gyr_1
- t+1时刻的位置、姿态、速度预积分估计值:result_delta_p, result_delta_q, result_delta_v
- t和t+1时刻加速度计和陀螺仪零偏估计值:result_linearized_ba, result_linearized_ba, result_linearized_ba, result_linearized_bg
- Jacobian矩阵更新选项:update_jacobian
和论文中推导采用欧拉积分法不同,代码中实际采用的是中值积分法,且认为在整个 [ k , k + 1 ] [k,k+1] [k,k+1]过程中,加速度计和陀螺仪零偏保持不变。函数主要分为两部分:
- 预积分估计值的一步递推
由于代码内容和上述理论推倒完全一致,这里不做过多说明。
Vector3d un_acc_0 = delta_q * (_acc_0 - linearized_ba);
Vector3d un_gyr = 0.5 * (_gyr_0 + _gyr_1) - linearized_bg; /// average angular rate
result_delta_q = delta_q * Quaterniond(1, un_gyr(0) * _dt / 2, un_gyr(1) * _dt / 2, un_gyr(2) * _dt / 2);
Vector3d un_acc_1 = result_delta_q * (_acc_1 - linearized_ba);
Vector3d un_acc = 0.5 * (un_acc_0 + un_acc_1); /// average acceleration
result_delta_p = delta_p + delta_v * _dt + 0.5 * un_acc * _dt * _dt;
result_delta_v = delta_v + un_acc * _dt;
result_linearized_ba = linearized_ba;
result_linearized_bg = linearized_bg;
- Jacobian矩阵更新
该部分代码内容与前文的理论推倒基本一致,但噪声传播矩阵V
的前四行与理论推导正负相反,具体原因目前尚不明确,待分析完后续代码补充。
Vector3d w_x = 0.5 * (_gyr_0 + _gyr_1) - linearized_bg;
Vector3d a_0_x = _acc_0 - linearized_ba;
Vector3d a_1_x = _acc_1 - linearized_ba;
Matrix3d R_w_x, R_a_0_x, R_a_1_x;
// symmetric matrix
/// angular velocity symmetric
R_w_x<<0, -w_x(2), w_x(1),
w_x(2), 0, -w_x(0),
-w_x(1), w_x(0), 0;
/// a_0_x symmetric
R_a_0_x<<0, -a_0_x(2), a_0_x(1),
a_0_x(2), 0, -a_0_x(0),
-a_0_x(1), a_0_x(0), 0;
/// a_1_x symmetric
R_a_1_x<<0, -a_1_x(2), a_1_x(1),
a_1_x(2), 0, -a_1_x(0),
-a_1_x(1), a_1_x(0), 0;
MatrixXd F = MatrixXd::Zero(15, 15);
F.block<3, 3>(0, 0) = Matrix3d::Identity(); /// f_00
F.block<3, 3>(0, 3) = -0.25 * delta_q.toRotationMatrix() * R_a_0_x * _dt * _dt +
-0.25 * result_delta_q.toRotationMatrix() * R_a_1_x * (Matrix3d::Identity() - R_w_x * _dt) * _dt * _dt; /// f_01
F.block<3, 3>(0, 6) = MatrixXd::Identity(3,3) * _dt; /// f_02
F.block<3, 3>(0, 9) = -0.25 * (delta_q.toRotationMatrix() + result_delta_q.toRotationMatrix()) * _dt * _dt; /// f_03
F.block<3, 3>(0, 12) = 0.25 * result_delta_q.toRotationMatrix() * R_a_1_x * _dt * _dt * _dt; /// f_04
F.block<3, 3>(3, 3) = Matrix3d::Identity() - R_w_x * _dt; /// f_11
F.block<3, 3>(3, 12) = -1.0 * MatrixXd::Identity(3,3) * _dt; /// f_14
F.block<3, 3>(6, 3) = -0.5 * delta_q.toRotationMatrix() * R_a_0_x * _dt +
-0.5 * result_delta_q.toRotationMatrix() * R_a_1_x * (Matrix3d::Identity() - R_w_x * _dt) * _dt; /// f_21
F.block<3, 3>(6, 6) = Matrix3d::Identity(); /// f_22
F.block<3, 3>(6, 9) = -0.5 * (delta_q.toRotationMatrix() + result_delta_q.toRotationMatrix()) * _dt; /// f_23
F.block<3, 3>(6, 12) = 0.5 * result_delta_q.toRotationMatrix() * R_a_1_x * _dt * _dt; /// f_24
F.block<3, 3>(9, 9) = Matrix3d::Identity(); /// f_33
F.block<3, 3>(12, 12) = Matrix3d::Identity(); /// f_44
MatrixXd V = MatrixXd::Zero(15,18);
V.block<3, 3>(0, 0) = 0.25 * delta_q.toRotationMatrix() * _dt * _dt; /// v_00 (opposite to equation)
V.block<3, 3>(0, 3) = 0.25 * -result_delta_q.toRotationMatrix() * R_a_1_x * _dt * _dt * 0.5 * _dt; /// v_01 (opposite to equation)
V.block<3, 3>(0, 6) = 0.25 * result_delta_q.toRotationMatrix() * _dt * _dt; /// v_02 (opposite to equation)
V.block<3, 3>(0, 9) = V.block<3, 3>(0, 3); /// v_03
V.block<3, 3>(3, 3) = 0.5 * MatrixXd::Identity(3,3) * _dt; /// v_11 (opposite to equation)
V.block<3, 3>(3, 9) = 0.5 * MatrixXd::Identity(3,3) * _dt; /// v_13 (opposite to equation)
V.block<3, 3>(6, 0) = 0.5 * delta_q.toRotationMatrix() * _dt; /// v_20 (opposite to equation)
V.block<3, 3>(6, 3) = 0.5 * -result_delta_q.toRotationMatrix() * R_a_1_x * _dt * 0.5 * _dt; /// v_21 (opposite to equation)
V.block<3, 3>(6, 6) = 0.5 * result_delta_q.toRotationMatrix() * _dt; /// v_22 (opposite to equation)
V.block<3, 3>(6, 9) = V.block<3, 3>(6, 3); /// v_23
V.block<3, 3>(9, 12) = MatrixXd::Identity(3,3) * _dt; /// v_34
V.block<3, 3>(12, 15) = MatrixXd::Identity(3,3) * _dt; /// v_45
jacobian = F * jacobian;
covariance = F * covariance * F.transpose() + V * noise * V.transpose()
状态传播函数(propagate)
该函数的内核为上述中值积分函数,主要用于实现IMU预积分的递推,函数原型如下:
void propagate(double _dt, const Eigen::Vector3d &_acc_1, const Eigen::Vector3d &_gyr_1)
函数的入口参数分别为IMU预积分的时间间隔_dt
和当前IMU量测_acc_1
、_gyr_1
。propagate
函数首先调用midPointIntegration
计算IMU预积分的一步递推,随后对IMU预积分初值进行重置(注意每次递推需要对四元数进行归一化),用于下一步递推,详细代码如下:
// 获取输入参数
dt = _dt;
acc_1 = _acc_1;
gyr_1 = _gyr_1;
Vector3d result_delta_p;
Quaterniond result_delta_q;
Vector3d result_delta_v;
Vector3d result_linearized_ba;
Vector3d result_linearized_bg;
// 调用中值积分进行IMU预积分一步递推
midPointIntegration(_dt, acc_0, gyr_0, _acc_1, _gyr_1, delta_p, delta_q, delta_v,
linearized_ba, linearized_bg,
result_delta_p, result_delta_q, result_delta_v,
result_linearized_ba, result_linearized_bg, 1);
// 重置状态量用于下一步递推
delta_p = result_delta_p;
delta_q = result_delta_q;
delta_v = result_delta_v;
linearized_ba = result_linearized_ba;
linearized_bg = result_linearized_bg;
delta_q.normalize(); // 对四元数进行归一化
sum_dt += dt;
acc_0 = acc_1;
gyr_0 = gyr_1;
状态重传播函数(reprogate)
该函数在后端完成优化,给出加速度计和陀螺仪零偏新的最优估计值后,基于新的估计值对已有的IMU预积分进行重递推,函数入口参数为优化后的零偏值_linearized_ba
和_linearized_bg
。
void repropagate(const Eigen::Vector3d &_linearized_ba, const Eigen::Vector3d &_linearized_bg)
{
// 重置各状态量
sum_dt = 0.0;
acc_0 = linearized_acc;
gyr_0 = linearized_gyr;
delta_p.setZero();
delta_q.setIdentity();
delta_v.setZero();
linearized_ba = _linearized_ba;
linearized_bg = _linearized_bg;
jacobian.setIdentity();
covariance.setZero();
// 调用propagate函数进行重递推
for (int i = 0; i < static_cast<int>(dt_buf.size()); i++)
propagate(dt_buf[i], acc_buf[i], gyr_buf[i]);
}
变量存储函数(push_back)
该函数向IntegrationBase中的数据寄存器存入每一个IMU量测的时间间隔dt
、加速度计量测值acc
和陀螺仪量测值gyr
,并基于量测值对IMU预积分项进行一步递推,函数原型如下:
void push_back(double dt, const Eigen::Vector3d &acc, const Eigen::Vector3d &gyr)
{
dt_buf.push_back(dt);
acc_buf.push_back(acc);
gyr_buf.push_back(gyr);
propagate(dt, acc, gyr);
}
残差评估函数(evaluate)
该函数用于在后端非线性优化中每一次优化后评估IMU预积分的残差,函数入口参数分别为:
- 优化后的第k帧预积分状态变
Pi
、Qi
、Vi
、Bai
、Bgi
- 优化后的第k+1帧预积分状态量
Pj
、Qj
、Vj
、Baj
、Bgj
函数返回值为k和k+1之间IMU预积分状态与非线性优化状态之间的残差,用于构建后端的非线性优化误差函数(理想状态下残差应该为零,实际情况下残差应该逐渐收敛于一个小值附近)。
Eigen::Matrix<double, 15, 1> evaluate(const Eigen::Vector3d &Pi, const Eigen::Quaterniond &Qi, const Eigen::Vector3d &Vi, const Eigen::Vector3d &Bai, const Eigen::Vector3d &Bgi,
const Eigen::Vector3d &Pj, const Eigen::Quaterniond &Qj, const Eigen::Vector3d &Vj, const Eigen::Vector3d &Baj, const Eigen::Vector3d &Bgj)
{
Eigen::Matrix<double, 15, 1> residuals;
Eigen::Matrix3d dp_dba = jacobian.block<3, 3>(O_P, O_BA);
Eigen::Matrix3d dp_dbg = jacobian.block<3, 3>(O_P, O_BG);
Eigen::Matrix3d dq_dbg = jacobian.block<3, 3>(O_R, O_BG);
Eigen::Matrix3d dv_dba = jacobian.block<3, 3>(O_V, O_BA);
Eigen::Matrix3d dv_dbg = jacobian.block<3, 3>(O_V, O_BG);
Eigen::Vector3d dba = Bai - linearized_ba;
Eigen::Vector3d dbg = Bgi - linearized_bg;
Eigen::Quaterniond corrected_delta_q = delta_q * Utility::deltaQ(dq_dbg * dbg);
Eigen::Vector3d corrected_delta_v = delta_v + dv_dba * dba + dv_dbg * dbg;
Eigen::Vector3d corrected_delta_p = delta_p + dp_dba * dba + dp_dbg * dbg;
// 计算优化残差
residuals.block<3, 1>(O_P, 0) = Qi.inverse() * (0.5 * G * sum_dt * sum_dt + Pj - Pi - Vi * sum_dt) - corrected_delta_p;
residuals.block<3, 1>(O_R, 0) = 2 * (corrected_delta_q.inverse() * (Qi.inverse() * Qj)).vec();
residuals.block<3, 1>(O_V, 0) = Qi.inverse() * (G * sum_dt + Vj - Vi) - corrected_delta_v;
residuals.block<3, 1>(O_BA, 0) = Baj - Bai;
residuals.block<3, 1>(O_BG, 0) = Bgj - Bgi;
return residuals;
}