机器人运动估计——IMU运动方程与ESKF原理介绍(下)

Hello! 欢迎来到我的博客
今天的内容关于机器人中常用的传感器IMU,我们用它来实现机器人姿态、速度、位置的估计。
今天将会介绍使用低成本IMU进行机器人运动估计的一个常用方法——ESKF。

3 Error State Kalman Filter(ESKF介绍)

3.1 动机与流程

使用IMU的初衷是为了求解载体的位置、速度、姿态等系统状态,然而由于IMU测量数据(包括加速度计和陀螺仪的测量数据)都带有大量噪声,直接利用IMU运动方程进行积分会随着时间发生显著的漂移。因此,为了避免漂移我们需要融合其他传感器的信息(如GPS、视觉),对IMU运动积分的结果进行修正。

Error-state Kalman Filter(ESKF)就是一种传感器融合的算法,它的基础仍然是卡尔曼滤波。它的核心思想是把系统的状态分为三类:

  • true state:实际状态,系统实际的运行状态
  • nominal state:名义状态,描述了运动状态的主要趋势,主导成分。(large-signal,非线性)
  • error state:误差状态,实际状态与名义状态之间的差值(small-signal,近似线性,适合线性高斯滤波)

基于以上状态分类,我们可以将关心的true-state,分为两部分,分别进行估计,即nominal state和error state,然后再进行二者叠加。

ESKF的全过程可以描述为如下步骤:

  • 对高频率的IMU数据 u m \mathbf{u}_m um进行积分,获得nomimal state x \mathbf{x} x。(注意:nominal state里面不考虑噪声,因此势必会累积误差。这部分误差可依据error state进行修正)
  • 利用Kalman Filter估计error state,这里同样也包括时间更新和量测更新两部分。(注意:这个过程考虑了噪声,并且由于误差状态方程是近似线性的,所以可以直接用卡尔曼滤波)
  • 利用error state修正nominal state,获取true state
  • 重置error state

使用ESKF的优势:

  1. error state 中的参数数量与运动自由度是相等的,避免了过参数化(over-parameterization or redundancy)引起的协方差矩阵奇异的风险。
  2. error state 总是接近于0,Kalman Filter工作在原点附近。因此,远离奇异值、万向节锁,并且保证了线性化的合理性和有效性。
  3. error state 总是很小,因此二阶项都可以忽略,因此雅可比矩阵的计算会很简单,很迅速。
  4. error state 的变化平缓,因此KF修正的频率不需要太高。

3.2 状态定义

所有在ESKF中用到的变量定义如下:
在这里插入图片描述
图片中定义了所以状态,包括true state,nominal state以及error state。以及error state和nominal state组合获得true state的方式。
另外,图中的各个运算符在上一篇文章中均已有了定义。除了一个叉乘矩阵的符号,其定义如下:

[ a ] × ≜ [ 0 − a z a y a z 0 − a x − a y a x 0 ] [\mathbf{a}]_{\times} \triangleq\left[\begin{array}{ccc} 0 & -a_{z} & a_{y} \\ a_{z} & 0 & -a_{x} \\ -a_{y} & a_{x} & 0 \end{array}\right] [a]×0azayaz0axayax0

图片来自于参考文献[1]的P31。

3.3 Nominal State 积分更新(每个时间步都要执行)

3.3.1 Nominal state 方程(连续时间):

p ˙ = v v ˙ = R ( a m − a b ) + g q ˙ = 1 2 q ⊗ ( ω m − ω b ) a ˙ b = 0 ω ˙ b = 0 g ˙ = 0 \begin{aligned} \dot{\mathbf{p}} &=\mathbf{v} \\ \dot{\mathbf{v}} &=\mathbf{R}\left(\mathbf{a}_{m}-\mathbf{a}_{b}\right)+\mathbf{g} \\ \dot{\mathbf{q}} &=\frac{1}{2} \mathbf{q} \otimes\left(\bm\omega_{m}-\bm\omega_{b}\right) \\ \dot{\mathbf{a}}_{b} &=0 \\ \dot{\bm\omega}_{b} &=0 \\ \dot{\mathbf{g}} &=0 \end{aligned} p˙v˙q˙a˙bω˙bg˙=v=R(amab)+g=21q(ωmωb)=0=0=0

其中, R = R { q } \mathbf{R}=\mathbf{R}\{\mathbf{q}\} R=R{q}是基于 q \mathbf{q} q生成的旋转矩阵,表示从IMU系到惯性系的旋转。
注意到,这组方程完全没有考虑噪声。这组方程的推导是显而意见的,只需要在IMU运动方程的基础上,假设噪声项全部为0即可。

3.3.2 Nominal state 方程(离散时间,用于写程序):

p ← p + v Δ t + 1 2 ( R ( a m − a b ) + g ) Δ t 2 v ← v + ( R ( a m − a b ) + g ) Δ t q ← q ⊗ q { ( ω m − ω b ) Δ t } a b ← a b ω b ← ω b g ← g \begin{array}{l} \mathbf{p} \leftarrow \mathbf{p}+\mathbf{v} \Delta t+\frac{1}{2}\left(\mathbf{R}\left(\mathbf{a}_{m}-\mathbf{a}_{b}\right)+\mathbf{g}\right) \Delta t^{2} \\ \mathbf{v} \leftarrow \mathbf{v}+\left(\mathbf{R}\left(\mathbf{a}_{m}-\mathbf{a}_{b}\right)+\mathbf{g}\right) \Delta t \\ \mathbf{q} \leftarrow \mathbf{q} \otimes \mathbf{q}\left\{\left(\bm\omega_{m}-\bm\omega_{b}\right) \Delta t\right\} \\ \mathbf{a}_{b} \leftarrow \mathbf{a}_{b} \\ \bm\omega_{b} \leftarrow \bm\omega_{b} \\ \mathbf{g} \leftarrow \mathbf{g} \end{array} pp+vΔt+21(R(amab)+g)Δt2vv+(R(amab)+g)Δtqqq{(ωmωb)Δt}ababωbωbgg
其中,定义 q { v } = e v / 2 \mathbf{q}\left\{\mathbf{v}\right\}=e^{\mathbf{v} / 2} q{v}=ev/2,所以:
q { ( ω m − ω b ) Δ t } = e ( ω m − ω b ) Δ t / 2 = e u θ / 2 = [ cos ⁡ ( θ / 2 ) u sin ⁡ ( θ / 2 ) ] \mathbf{q}\left\{\left(\bm\omega_{m}-\bm\omega_{b}\right) \Delta t\right\}=e^{\mathbf{\left(\bm\omega_{m}-\bm\omega_{b}\right) \Delta t} / 2}=e^{\mathbf{u}\theta/ 2}= \left[\begin{array}{c} \cos (\theta/ 2) \\ \mathbf{u} \sin (\theta/ 2) \end{array}\right] q{(ωmωb)Δt}=e(ωmωb)Δt/2=euθ/2=[cos(θ/2)usin(θ/2)]
其中, θ = ∣ ∣ ( ω m − ω b ) Δ t ∣ ∣ , u = ( ω m − ω b ) Δ t θ \theta=||\left(\bm\omega_{m}-\bm\omega_{b}\right) \Delta t||,\mathbf{u}=\frac{\left(\bm\omega_{m}-\bm\omega_{b}\right) \Delta t}{\theta} θ=(ωmωb)Δt,u=θ(ωmωb)Δt

实际上,上面这个操作就是把角度增量改造成单位四元数,两个单位四元数相乘仍然是单位四元数,这样才能保证 q \mathbf{q} q始终为单位四元数,保证迭代是收敛的。

3.4 Error State 时间更新(每个时间步都要执行)

3.4.1 Error state 方程(连续时间):

δ p ˙ = δ v δ v ˙ = − R [ a m − a b ] × δ θ − R δ a b + δ g − R a n δ θ ˙ = − [ ω m − ω b ] × δ θ − δ ω b − ω n δ a ˙ b = a w δ ω ˙ b = ω w δ g ˙ = 0 \begin{aligned} \delta \dot\mathbf{p} &=\delta \mathbf{v} \\ \dot{\delta \mathbf{v}} &=-\mathbf{R}\left[\mathbf{a}_{m}-\mathbf{a}_{b}\right]_{\times} \delta \boldsymbol{\theta}-\mathbf{R} \delta \mathbf{a}_{b}+\delta \mathbf{g}-\mathbf{R} \mathbf{a}_{n} \\ {\delta} \dot\boldsymbol{\theta} &=-\left[\boldsymbol{\omega}_{m}-\boldsymbol{\omega}_{b}\right]_{\times} \delta \boldsymbol{\theta}-\delta \boldsymbol{\omega}_{b}-\boldsymbol{\omega}_{n} \\ \delta\dot \mathbf{a}_{b} &=\mathbf{a}_{w} \\ \delta \dot{\boldsymbol{\omega}}_{b} &=\boldsymbol{\omega}_{w} \\ \dot{\delta \mathbf{g}} &=0 \end{aligned} δp˙δv˙δθ˙δa˙bδω˙bδg˙=δv=R[amab]×δθRδab+δgRan=[ωmωb]×δθδωbωn=aw=ωw=0
这个误差方程,考虑了噪声等不确定性。其形式看起来似乎不太直观,但实际上推导也很简单。
比如,以位置为例:
δ p = p t − p \delta \mathbf{p}=\mathbf{p}_t-\mathbf{p} δp=ptp
所以其导数为:
δ p ˙ = p ˙ t − p ˙ = v t − v = δ v \delta \dot\mathbf{p}=\dot\mathbf{p}_t-\dot\mathbf{p}=\mathbf{v}_t-\mathbf{v}=\delta \mathbf{v} δp˙=p˙tp˙=vtv=δv
再比如以速度为例:
δ v = v t − v \delta \mathbf{v}=\mathbf{v}_t-\mathbf{v} δv=vtv
所以其导数为:
δ v ˙ = v ˙ t − v ˙ = R t ( a m − a b t − a n ) + g t − ( R ( a m − a b ) + g ) = ( R δ R − R ) ( a m − a b ) − R δ R ( δ a b + a m ) + ( g t − g ) ≈ [ R ( I + [ δ θ ] × ) − R ] ( a m − a b ) − R ( I + [ δ θ ] × ) ( δ a b + a m ) + δ g ≈ R [ δ θ ] × ( a m − a b ) − R ( δ a b + a m ) + δ g = − R [ a m − a b ] × δ θ − R δ a b + δ g − R a n \begin{aligned} \delta \dot\mathbf{v}&=\dot\mathbf{v}_t-\dot\mathbf{v}\\ &=\mathbf{R}_{t}\left(\mathbf{a}_{m}-\mathbf{a}_{b t}-\mathbf{a}_{n}\right)+\mathbf{g}_{t}-(\mathbf{R}\left(\mathbf{a}_{m}-\mathbf{a}_b\right)+\mathbf{g})\\ &=(\mathbf{R}\delta\mathbf{R}-\mathbf{R})(\mathbf{a}_{m}-\mathbf{a}_{b})-\mathbf{R}\delta\mathbf{R}(\delta\mathbf{a}_b+\mathbf{a}_m)+(\mathbf{g}_t-\mathbf{g})\\ &\approx[\mathbf{R}(\mathbf{I}+[\delta\bm{\theta}]_\times)-\mathbf{R}](\mathbf{a}_{m}-\mathbf{a}_{b})-\mathbf{R}(\mathbf{I}+[\delta\bm{\theta}]_\times)(\delta\mathbf{a}_b+\mathbf{a}_m)+\delta\mathbf{g}\\ &\approx\mathbf{R}[\delta\bm{\theta}]_\times(\mathbf{a}_{m}-\mathbf{a}_{b})-\mathbf{R}(\delta\mathbf{a}_b+\mathbf{a}_m)+\delta\mathbf{g}\\ &=-\mathbf{R}\left[\mathbf{a}_{m}-\mathbf{a}_{b}\right]_{\times} \delta \boldsymbol{\theta}-\mathbf{R} \delta \mathbf{a}_{b}+\delta \mathbf{g}-\mathbf{R} \mathbf{a}_{n} \\ \end{aligned} δv˙=v˙tv˙=Rt(amabtan)+gt(R(amab)+g)=(RδRR)(amab)RδR(δab+am)+(gtg)[R(I+[δθ]×)R](amab)R(I+[δθ]×)(δab+am)+δgR[δθ]×(amab)R(δab+am)+δg=R[amab]×δθRδab+δgRan
其中,用到了 δ R = e [ δ θ ] × ≈ I + [ δ θ ] × \delta\mathbf{R}=e^{[\delta\bm{\theta}]_\times} \approx \mathbf{I}+[\delta\bm{\theta}]_\times δR=e[δθ]×I+[δθ]×。此外,还用到了两个小量相乘可以忽略的假设。

其它方程的推导,就不在此说明了,可以参考文献[1]的P33页。

3.4.2 Error state 方程(离散时间,用于写程序):

定义状态向量:
x = [ p v q a b ω b g ] ∈ R 19 × 1 , δ x = [ δ p δ v δ θ δ a b δ ω b δ g ] ∈ R 18 × 1 , u m = [ a m ω m ] ∈ R 6 × 1 , i = [ v i θ i a i ω i ] ∈ R 12 × 1 \mathbf{x}=\left[\begin{array}{l} \mathbf{p} \\ \mathbf{v} \\ \mathbf{q} \\ \mathbf{a}_{b} \\ \boldsymbol{\omega}_{b} \\ \mathbf{g} \end{array}\right] \in \mathbb{R}_{19\times 1}, \quad \delta \mathbf{x}=\left[\begin{array}{c} \delta \mathbf{p} \\ \delta \mathbf{v} \\ \delta \boldsymbol{\theta} \\ \delta \mathbf{a}_{b} \\ \delta \boldsymbol{\omega}_{b} \\ \delta \mathbf{g} \end{array}\right] \in \mathbb{R}_{18\times 1}\quad, \quad \mathbf{u}_{m}=\left[\begin{array}{c} \mathbf{a}_{m} \\ \boldsymbol{\omega}_{m} \end{array}\right] \in \mathbb{R}_{6\times 1}, \quad \mathbf{i}=\left[\begin{array}{c} \mathbf{v}_{\mathbf{i}} \\ \boldsymbol{\theta}_{\mathbf{i}} \\ \mathbf{a}_{\mathbf{i}} \\ \boldsymbol{\omega}_{\mathbf{i}} \end{array}\right] \in \mathbb{R}_{12\times 1} x=pvqabωbgR19×1,δx=δpδvδθδabδωbδgR18×1,um=[amωm]R6×1,i=viθiaiωiR12×1
于是误差状态方程可以写作:
δ x ← f ( x , δ x , u m , i ) = F x ( x , u m ) ⋅ δ x + F i ⋅ i \delta \mathbf{x} \leftarrow f\left(\mathbf{x}, \delta \mathbf{x}, \mathbf{u}_{m}, \mathbf{i}\right)=\mathbf{F}_{\mathbf{x}}\left(\mathbf{x}, \mathbf{u}_{m}\right) \cdot \delta \mathbf{x}+\mathbf{F}_{\mathbf{i}} \cdot \mathbf{i} δxf(x,δx,um,i)=Fx(x,um)δx+Fii
其中:
F x = ∂ f ∂ δ x ∣ x , u m = [ I I Δ t 0 0 0 0 0 I − R [ a m − a b ] × Δ t − R Δ t 0 I Δ t 0 0 R ⊤ { ( ω m − ω b ) Δ t } 0 − I Δ t 0 0 0 0 I 0 0 0 0 0 0 I 0 0 0 0 0 0 I ] ∈ R 18 × 18 \mathbf{F}_{\mathbf{x}}=\left.\frac{\partial f}{\partial \delta \mathbf{x}}\right|_{\mathbf{x}, \mathbf{u}_{m}}=\left[\begin{array}{cccccc} \mathbf{I} & \mathbf{I} \Delta t & 0 & 0 & 0 & 0 \\ 0 & \mathbf{I} & -\mathbf{R}\left[\mathbf{a}_{m}-\mathbf{a}_{b}\right]_{\times} \Delta t & -\mathbf{R} \Delta t & 0 & \mathbf{I} \Delta t \\ 0 & 0 & \mathbf{R}^{\top}\left\{\left(\omega_{m}-\omega_{b}\right) \Delta t\right\} & 0 & -\mathbf{I} \Delta t & 0 \\ 0 & 0 & 0 & \mathbf{I} & 0 & 0 \\ 0 & 0 & 0 & 0 & \mathbf{I} & 0 \\ 0 & 0 & 0 & 0 & 0 & \mathbf{I} \end{array}\right] \in \mathbb{R}_{18\times 18} Fx=δxfx,um=I00000IΔtI00000R[amab]×ΔtR{(ωmωb)Δt}0000RΔt0I0000IΔt0I00IΔt000IR18×18

F i = ∂ f ∂ i ∣ x , u m = [ 0 0 0 0 I 0 0 0 0 I 0 0 0 0 I 0 0 0 0 I 0 0 0 0 ] ∈ R 18 × 12 , Q i = [ V i 0 0 0 0 Θ i 0 0 0 0 A i 0 0 0 0 Ω i ] ∈ R 12 × 12 \mathbf{F}_{\mathbf{i}}=\left.\frac{\partial f}{\partial \mathbf{i}}\right|_{\mathbf{x}, \mathbf{u}_{m}}=\left[\begin{array}{cccc} 0 & 0 & 0 & 0 \\ \mathbf{I} & 0 & 0 & 0 \\ 0 & \mathbf{I} & 0 & 0 \\ 0 & 0 & \mathbf{I} & 0 \\ 0 & 0 & 0 & \mathbf{I} \\ 0 & 0 & 0 & 0 \end{array}\right] \quad \in \mathbb{R}_{18\times 12}, \quad \mathbf{Q}_{\mathbf{i}}=\left[\begin{array}{cccc} \mathbf{V}_{\mathbf{i}} & 0 & 0 & 0 \\ 0 & \mathbf{\Theta}_{\mathbf{i}} & 0 & 0 \\ 0 & 0 & \mathbf{A}_{\mathbf{i}} & 0 \\ 0 & 0 & 0 & \mathbf{\Omega}_{\mathbf{i}} \end{array}\right] \in \mathbb{R}_{12\times 12} Fi=ifx,um=0I000000I000000I000000I0R18×12,Qi=Vi0000Θi0000Ai0000ΩiR12×12

其中, v i , θ i , a i , ω i \mathbf{v}_{\mathbf{i}},\boldsymbol{\theta}_{\mathbf{i}},\mathbf{a}_{\mathbf{i}},\boldsymbol{\omega}_{\mathbf{i}} vi,θi,ai,ωi代表随机脉冲,他们的均值为0,协方差矩阵为对角阵。
另外,定义:
R ⊤ { ( ω m − ω b ) Δ t } = e − [ ω m − ω b ] × Δ t = I − [ ω m − ω b ] × Δ t + 1 2 [ ω m − ω b ] × 2 Δ t 2 − . . . \mathbf{R}^{\top}\left\{\left(\boldsymbol{\omega}_{m}-\boldsymbol{\omega}_{b}\right) \Delta t\right\}=e^{-[\boldsymbol{\omega}_{m}-\boldsymbol{\omega}_{b}]_\times \Delta t}=\mathbf{I}-[\boldsymbol{\omega}_{m}-\boldsymbol{\omega}_{b}]_\times \Delta t+\frac{1}{2}[\boldsymbol{\omega}_{m}-\boldsymbol{\omega}_{b}]_\times^2 \Delta t^2-... R{(ωmωb)Δt}=e[ωmωb]×Δt=I[ωmωb]×Δt+21[ωmωb]×2Δt2...
这是一个微分方程的闭合解,利用这个解进行递推会更精确。当然,也可以只取前面两项。

3.4.3 对于Error state的卡尔曼滤波器的时间更新(用于写程序)

误差状态更新
δ x ^ ← F x ( x , u m ) ⋅ δ x ^ \hat{\delta \mathbf{x}} \leftarrow \mathbf{F}_{\mathbf{x}}\left(\mathbf{x}, \mathbf{u}_{m}\right) \cdot \hat{\delta \mathbf{x}} δx^Fx(x,um)δx^
协方差矩阵更新
P ← F x P F x ⊤ + F i Q i F i ⊤ \mathbf{P} \leftarrow \mathbf{F}_{\mathbf{x}} \mathbf{P} \mathbf{F}_{\mathbf{x}}^{\top}+\mathbf{F}_{\mathbf{i}} \mathbf{Q}_{\mathbf{i}} \mathbf{F}_{\mathbf{i}}^{\top} PFxPFx+FiQiFi
这个就是很基础的卡尔曼滤波方程了,不了解的可以移步我的博客:
机器人运动估计系列(番外篇)——从贝叶斯滤波到卡尔曼(上)

3.5 Error State 量测更新(只有测量值到来的时间步需要执行)

由于IMU的数据中夹带了大量噪声,我们需要利用更多的传感器的信息,来对状态进行修正。

而这些传感器中常用的组合包括:GPS+IMU,单目视觉+IMU,双目视觉+IMU等。

3.5.1 量测方程

通常,量测方程的基本形式如下:
y = h ( x t ) + v \mathbf{y}=h\left(\mathbf{x}_{t}\right)+v y=h(xt)+v
其中 h ( ) h() h()是量测函数,与传感器有关。 v v v是高斯白噪声,为 v ∼ N { 0 , V } v \sim \mathcal{N}\{0, \mathbf{V}\} vN{0,V}

为了实现量测更新,我们需要求 h h h δ x \delta \mathbf{x} δx的导数,所以有:

H ≡ ∂ h ∂ δ x ∣ x = ∂ h ∂ x t ∣ x ∂ x t ∂ δ x ∣ x = H x X δ x \left.\mathbf{H} \equiv \frac{\partial h}{\partial \delta \mathbf{x}}\right|_{\mathbf{x}}=\left.\left.\frac{\partial h}{\partial \mathbf{x}_{t}}\right|_{\mathbf{x}} \frac{\partial \mathbf{x}_{t}}{\partial \delta \mathbf{x}}\right|_{\mathbf{x}}=\mathbf{H}_{\mathbf{x}} \mathbf{X}_{\delta \mathbf{x}} Hδxhx=xthxδxxtx=HxXδx
其中 H x ≜ ∂ h ∂ x t ∣ x \left.\mathbf{H}_{\mathbf{x}} \triangleq \frac{\partial h}{\partial \mathbf{x}_{t}}\right|_{\mathbf{x}} Hxxthx是量测函数的雅可比矩阵,根据传感器的不同而具有不同形式。

X δ x ≜ ∂ x t ∂ δ x ∣ x \left.\mathbf{X}_{\delta \mathbf{x}} \triangleq \frac{\partial \mathbf{x}_{t}}{\partial \delta \mathbf{x}}\right|_{\mathbf{x}} Xδxδxxtx则可以表示为:
X δ x ≜ ∂ x t ∂ δ x ∣ x = [ I 6 0 0 0 Q δ θ 0 0 0 I 9 ] , Q δ θ = 1 2 [ − q x − q y − q z q w − q z q y q z q w − q x − q y q x q w ] \left.\mathbf{X}_{\delta \mathbf{x}} \triangleq \frac{\partial \mathbf{x}_{t}}{\partial \delta \mathbf{x}}\right|_{\mathbf{x}}=\left[\begin{array}{ccc} \mathbf{I}_{6} & 0 & 0 \\ 0 & \mathbf{Q}_{\delta \boldsymbol{\theta}} & 0 \\ 0 & 0 & \mathbf{I}_{9} \end{array}\right], \mathbf{Q}_{\delta \boldsymbol{\theta}}=\frac{1}{2}\left[\begin{array}{ccc} -q_{x} & -q_{y} & -q_{z} \\ q_{w} & -q_{z} & q_{y} \\ q_{z} & q_{w} & -q_{x} \\ -q_{y} & q_{x} & q_{w} \end{array}\right] Xδxδxxtx=I6000Qδθ000I9,Qδθ=21qxqwqzqyqyqzqwqxqzqyqxqw

关于上式的详细推导,可以参考文献[1]的P39页。

3.5.2 对于Error state的卡尔曼滤波器的量测更新(用于写程序)

卡尔曼增益的计算
K = P H ⊤ ( H P H ⊤ + V ) − 1 \mathbf{K}=\mathbf{P} \mathbf{H}^{\top}\left(\mathbf{H} \mathbf{P} \mathbf{H}^{\top}+\mathbf{V}\right)^{-1} K=PH(HPH+V)1
误差状态量测更新
δ ^ x ← K ( y − h ( x ^ t ) ) \hat{\delta} \mathbf{x} \leftarrow \mathbf{K}\left(\mathbf{y}-h\left(\hat{\mathbf{x}}_{t}\right)\right) δ^xK(yh(x^t))
协方差矩阵更新
P ← ( I − K H ) P \mathbf{P} \leftarrow(\mathbf{I}-\mathbf{K} \mathbf{H}) \mathbf{P} P(IKH)P
这是卡尔曼滤波的基础方程,就不做介绍了。

3.6 状态合并以及Error State 重置(在量测更新过后执行)

3.6.1 状态合并

这一步是要把error state与nominal state合并,即修正nominal state随时间的漂移。

x ← x ⊕ δ x ^ \mathbf{x} \leftarrow \mathbf{x} \oplus \hat{\delta \mathbf{x}} xxδx^
即:
p ← p + δ p ^ v ← v + δ v ^ q ← q ⊗ q { δ θ ^ } a b ← a b + δ a ^ b ω b ← ω b + δ ω ^ b g ← g + δ g ^ \begin{aligned} &\begin{array}{l} \mathbf{p} \leftarrow \mathbf{p}+\hat{\delta \mathbf{p}} \\ \mathbf{v} \leftarrow \mathbf{v}+\hat{\delta \mathbf{v}} \end{array}\\ &\mathbf{q} \leftarrow \mathbf{q} \otimes \mathbf{q}\{\hat{\delta \boldsymbol{\theta}}\}\\ &\mathbf{a}_{b} \leftarrow \mathbf{a}_{b}+\delta \hat{\mathbf{a}}_{b}\\ &\bm\omega_{b} \leftarrow \bm\omega_{b}+\delta \hat{\bm\omega}_{b}\\ &\mathbf{g} \leftarrow \mathbf{g}+\hat{\delta \mathbf{g}} \end{aligned} pp+δp^vv+δv^qqq{δθ^}abab+δa^bωbωb+δω^bgg+δg^

3.6.2 Error state 重置

由于nominal state的误差已经修正了,所以error state要置零,同时协方差矩阵也要相应的修改。

通常来说,重置的方法如下:
δ x ^ ← 0 P ← G P G ⊤ \begin{aligned} &\hat{\delta \mathbf{x}} \leftarrow 0\\ &\mathbf{P} \leftarrow \mathbf{G} \mathbf{P} \mathbf{G}^{\top} \end{aligned} δx^0PGPG
其中: G = I 18 \mathbf{G}= \mathbf{I}_{18} G=I18

4 Matlab代码

https://github.com/CASIA-RoboticFish/FBUS-EKF

参考文献

[1] Joan Sol`a. Quaternion kinematics for the error-state KF. Sep 12, 2016.

关于<IMU运动方程与ESKF原理介绍>的上下两篇文章主要内容出自上面这篇参考文献,我只是进行了翻译和重新梳理逻辑顺序的工作。因此,大家如果使用到本博客内容,也烦请引用上述参考文献。谢谢~

很抱歉,我是一个AI语言模型,无法提供代码编写服务。但我可以提供一个ESKF融合imu与odom数据的Python示例代码供参考: ```python import numpy as np # ESKF参数设置 class ESKF_Params(): def __init__(self): self.gravity = 9.81 self.gyro_noise = 0.0015 # rad/s self.acc_noise = 0.05 # m/s^2 self.gyro_bias = 0.001 # rad/s self.acc_bias = 0.1 # m/s^2 self.P_matrix = np.identity(15) # 初始协方差矩阵 self.Q_matrix = np.identity(12) # 状态转移噪声矩阵 self.R_matrix = np.identity(6) # 观测噪声矩阵 self.alpha = 1e-4 # 残差的比例因子 self.beta = 2 # 残差的方差因子 # ESKF状态存储 class ESKF_State(): def __init__(self): self.Rotation = np.eye(3) self.Position = np.zeros((3,1)) self.Velocity = np.zeros((3,1)) self.AccBias = np.zeros((3,1)) self.GyroBias = np.zeros((3,1)) self.P_matrix = np.identity(15) # 进行状态预测 def ESKF_Prediction(u, dt, S, params): accData = u[:3].reshape((3,1)) gyroData = u[3:].reshape((3,1)) accData -= S.AccBias gyroData -= S.GyroBias Cn = S.Rotation.T gravity = np.array([0, 0, -params.gravity]).reshape((3,1)) linearVel = S.Velocity + (dt * (accData - (Cn @ gravity))) linearPos = S.Position + (dt * S.Velocity) + (0.5 * (dt ** 2) * (accData - (Cn @ gravity))) gyroBias = S.GyroBias accBias = S.AccBias F_mtx = np.identity(15) F_mtx[:3, 3:6] = np.eye(3) * dt F_mtx[:3, 6:9] = (-Cn @ dt) F_mtx[3:6, 9:12] = np.eye(3) * (-dt) G_mtx = np.zeros((15, 12)) G_mtx[6:9, :3] = -Cn * dt G_mtx[9:12, 3:] = np.eye(3) * dt Q = np.zeros((12, 12)) Q[:3, :3] = (params.acc_noise ** 2) * np.eye(3) Q[3:6, 3:6] = (params.gyro_noise ** 2) * np.eye(3) Q[6:9, 6:9] = (params.acc_bias ** 2) * np.eye(3) Q[9:, 9:] = (params.gyro_bias ** 2) * np.eye(3) F_mtx *= (-1 * params.alpha * dt) G_mtx *= (-1 * params.alpha) Q *= params.beta Q_mtx = np.dot(np.dot(G_mtx, Q), G_mtx.T) + np.dot(np.dot(F_mtx, S.P_matrix), F_mtx.T) X = np.concatenate((linearPos, linearVel, accBias, gyroBias), axis=0) S.Position = linearPos S.Velocity = linearVel S.GyroBias = gyroBias S.AccBias = accBias S.P_matrix = np.dot(np.dot(F_mtx, S.P_matrix), F_mtx.T) + Q_mtx return S, X # 进行状态更新 def ESKF_Update(z, S, X, params): Cn = S.Rotation.T accData = z[:3].reshape((3,1)) posData = z[3:].reshape((3,1)) posData = posData / np.linalg.norm(posData) gravity = np.array([0, 0, -params.gravity]).reshape((3,1)) predPos = S.Position + (S.Velocity * (z[-1] - X[-1])) predVel = S.Velocity predAccBias = S.AccBias predGyroBias = S.GyroBias Cn = Cn @ np.array([[1., gyroData[0]*dt/2., gyroData[1]*dt/2], [-gyroData[0]*dt/2., 1., gyroData[2]*dt/2.], [-gyroData[1]*dt/2., -gyroData[2]*dt/2., 1.]]) H_mtx = np.zeros((6, 15)) H_mtx[:3, 3:6] = np.eye(3) H_mtx[3:6, :3] = (2 * (np.dot(np.dot(np.linalg.inv(Cn), gravity), posData)) * (np.dot(np.dot(np.linalg.inv(Cn), gravity), posData)).T) - (np.dot(np.linalg.inv(Cn), gravity)).T H_mtx[3:6, 6:9] = np.dot(np.dot(np.linalg.inv(Cn), gravity), posData) * np.dot(np.dot(np.linalg.inv(Cn), np.array([[0, -S.Position[2], S.Position[1]], [S.Position[2], 0, -S.Position[0]], [-S.Position[1], S.Position[0], 0]])), (Cn @ dt)) R_mtx = np.diag([(params.acc_noise ** 2) * np.eye(3), (params.acc_bias ** 2) * np.eye(3)]) K_mtx = np.dot(np.dot(S.P_matrix, H_mtx.T), np.linalg.inv(np.dot(np.dot(H_mtx, S.P_matrix), H_mtx.T) + R_mtx)) delta_x = np.dot(K_mtx, (z - np.concatenate((np.dot(Cn, gravity), S.Position), axis=0))) X += np.dot(K_mtx, (z - np.concatenate((np.dot(Cn, gravity), S.Position), axis=0))) predPos += delta_x[:3] predVel += delta_x[3:6] predAccBias += delta_x[6:9] predGyroBias += delta_x[9:] S.Position = predPos S.Velocity = predVel S.AccBias = predAccBias S.GyroBias = predGyroBias S.P_matrix -= np.dot(np.dot(K_mtx, H_mtx), S.P_matrix) S.P_matrix = (S.P_matrix + S.P_matrix.T) * 0.5 return S, X # ESKF滤波器函数 def ESKF_Filter(imuData, odomData, params, omega_init=None): S = ESKF_State() X = np.zeros(15) for i in range(imuData.shape[1] - 1): dt = imuData[0, i+1] - imuData[0, i] if omega_init is None: omega_init = np.zeros((3,1)) u = np.concatenate((imuData[1:, i].reshape((-1,1)), omega_init), axis=0) S, X = ESKF_Prediction(u, dt, S, params) if np.any(np.abs(odomData[0, :] - imuData[0, i]) < 1e-5): idx = np.argmin(np.abs(odomData[0, :] - imuData[0, i])) z = np.concatenate((odomData[1:4, idx].reshape((-1,1)), odomData[4:7, idx].reshape((-1,1)), np.array([odomData[0, idx]]).reshape((-1,1))), axis=0) S, X = ESKF_Update(z, S, X, params) return S, X ```
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值