MATLAB实现一个EKF-2D-SLAM(已开源)

1. SLAM问题定义

同时定位与建图(SLAM)的本质是一个估计问题,它要求移动机器人利用传感器信息实时地对外界环境结构进行估计,并且估算出自己在这个环境中的位置,Smith 和Cheeseman在上个世纪首次将EKF估计方法应用到SLAM。

以滤波为主的SLAM模型主要包括三个方程:

1)运动方程:它会增加机器人定位的不确定性

2)根据观测对路标初始化的方程:它根据观测信息,对新的状态量初始化。

3)路标状态对观测的投影方程:根据观测信息,对状态更新,纠正,减小不确定度。

2. EKF-SLAM维护的数据地图

系统状态x是一个很大的向量,它包括机器人的状态和路标点的状态,

x = [ R M ] = [ R L 1 ⋮ L n ] \mathbf{x}=\left[\begin{array}{c} {\mathcal{R}} \\ {\mathcal{M}} \end{array}\right]=\left[\begin{array}{c} {\mathcal{R}} \\ {\mathcal{L}_{1}} \\ {\vdots} \\ {\mathcal{L}_{n}} \end{array}\right]x=[RM]=RL1Ln
其中R {\mathcal{R}}R是机器人状态,M = ( L 1 , … , L n ) {\mathcal{M}} = \left({\mathcal{L}_{1}}, \dots,{\mathcal{L}_{n}}\right)M=(L1Ln)是n个当前已经观测过的路标点状态集合。

在EKF中,x被认为服从高斯分布,所以,EKF-SLAM的地图被建模为x的均值x ‾ \overline{x}x与协方差P \mathbf{P}P,

x ‾ = [ R ‾ M ] = [ R ‾ L ‾ 1 ⋮ L ‾ n ] P = [ P R R P R M P M R P M M ] = [ P R R P R L 1 ⋯ P R L n P L 1 R P L 1 L 1 ⋯ P L n L n ⋮ ⋮ ⋱ ⋮ P L n R P L n L 1 ⋯ P L n L n ] \overline{\mathbf{x}}=\left[\frac{\overline{\mathcal{R}}}{\mathcal{M}}\right]=\left[\begin{array}{c} {\overline{\mathcal{R}}} \\ {\overline{\mathcal{L}}_{1}} \\ {\vdots} \\ {\overline{\mathcal{L}}_{n}} \end{array}\right] \quad \mathbf{P}=\left[\begin{array}{cc} {\mathbf{P}_{\mathcal{R} \mathcal{R}}} & {\mathbf{P}_{\mathcal{R} \mathcal{M}}} \\ {\mathbf{P}_{\mathcal{M R}}} & {\mathbf{P}_{\mathcal{M M}}} \end{array}\right]=\left[\begin{array}{cccc} {\mathbf{P}_{\mathcal{R R}}} & {\mathbf{P}_{\mathcal{R} \mathcal{L}_{1}}} & {\cdots} & {\mathbf{P}_{\mathcal{R} \mathcal{L}_{n}}} \\ {\mathbf{P}_{\mathcal{L}_{1} \mathcal{R}}} & {\mathbf{P}_{\mathcal{L}_{1} \mathcal{L}_{1}}} & {\cdots} & {\mathbf{P}_{\mathcal{L}_{n}} \mathcal{L}_{n}} \\ {\vdots} & {\vdots} & {\ddots} & {\vdots} \\ {\mathbf{P}_{\mathcal{L}_{n} \mathcal{R}}} & {\mathbf{P}_{\mathcal{L}_{n} \mathcal{L}_{1}}} & {\cdots} & {\mathbf{P}_{\mathcal{L}_{n} \mathcal{L}_{n}}} \end{array}\right]x=[MR]=RL1LnP=[PRRPMRPRMPMM]=PRRPL1RPLnRPRL1PL1L1PLnL1PRLnPLnLnPLnLn
因此EKF-SLAM的目标就是根据运动模型和观测模型及时更新地图量{ x ‾ , P } \left\{\overline{\mathbf{x}},\mathbf{P}\right\}{x,P}

3. EKF-SLAM算法实施

3.1 地图初始化

显而易见,在机器人开始之前是没有任何路标点的信息的,因此此时地图中只有机器人自己的状态信息,因此n = 0 , x = R {n} = 0,{x} = {\mathcal{R}}n=0,x=R。SLAM中经常把机器人初始位姿认为是地图的原点,其初始协方差可以按实际情况设定,比如:

x ‾ = [ x y θ ] = [ 0 0 0 ] P = [ 0 0 0 0 0 0 0 0 0 ] \overline{\mathbf{x}}=\left[\begin{array}{l} {x} \\ {y} \\ {\theta} \end{array}\right]=\left[\begin{array}{l} {0} \\ {0} \\ {0} \end{array}\right] \quad \mathbf{P}=\left[\begin{array}{lll} {0} & {0} & {0} \\ {0} & {0} & {0} \\ {0} & {0} & {0} \end{array}\right]x=xyθ=000P=000000000

3.2 运动模型

在EKF中如果x是状态量,u是控制输入,n是噪声变量,那么我们可以得到一般的状态更新函数:

x ← f ( x , u , n ) \mathbf{x} \leftarrow f(\mathbf{x}, \mathbf{u}, \mathbf{n})xf(x,u,n)

EKF的预测步骤为:

x ‾ ← f ( x ‾ , u , 0 ) P ← F x P F x ⊤ + F n N F n ⊤ \begin{array}{l} {\overline{\mathbf{x}} \leftarrow f(\overline{\mathbf{x}}, \mathbf{u}, 0)} \\ {\mathbf{P} \leftarrow \mathbf{F}_{\mathbf{x}} \mathbf{P} \mathbf{F}_{\mathbf{x}}^{\top}+\mathbf{F}_{\mathbf{n}} \mathbf{N} \mathbf{F}_{\mathbf{n}}^{\top}} \end{array}xf(x,u,0)PFxPFx+FnNFn

其中雅克比矩阵F x = ∂ f ( x ‾ , u ) ∂ x \mathbf{F}_{\mathbf{x}}=\frac{\partial f(\overline{\mathbf{x}}, \mathbf{u})}{\partial \mathbf{x}}Fx=xf(x,u)F n = ∂ f ( x ‾ , u ) ∂ n \mathbf{F}_{\mathbf{n}}=\frac{\partial f(\overline{\mathbf{x}}, \mathbf{u})}{\partial \mathbf{n}}Fn=nf(x,u)N {\mathbf{N}}N是随机变量n的协方差。

但是在EKF-SLAM中,只有一部分状态R {\mathcal{R}}R是随运动而改变的,其余所有路标状态不改变,所以SLAM的运动方程为:

R ← f R ( R , u , n ) M ← M \begin{array}{l} {\mathcal{R} \leftarrow f_{\mathcal{R}}(\mathcal{R}, \mathbf{u}, \mathbf{n})} \\ {\mathcal{M} \leftarrow \mathcal{M}} \end{array}RfR(R,u,n)MM

因此我们可以得到稀疏的雅克比矩阵:

F x = [ ∂ f R ∂ R 0 0 I ] F n = [ ∂ f R ∂ n 0 ] \mathbf{F}_{\mathbf{x}}=\left[\begin{array}{cc} {\frac{\partial f_{\mathcal{R}}}{\partial \mathcal{R}}} & {0} \\ {0} & {\mathbf{I}} \end{array}\right] \quad \mathbf{F}_{\mathbf{n}}=\left[\begin{array}{c} {\frac{\partial f_{\mathcal{R}}}{\partial \mathbf{n}}} \\ {0} \end{array}\right]Fx=[RfR00I]Fn=[nfR0]

最终我们得到了用于运动模型的EKF稀疏预测公式

R ‾ ← f R ( R ‾ , u , 0 ) \overline{\mathcal{R}} \leftarrow f_{\mathcal{R}}(\overline{\mathcal{R}}, \mathbf{u}, 0)RfR(R,u,0)

P R R ← ∂ f R ∂ R P R R ∂ f R T ∂ R + ∂ f R ∂ n N ∂ f R T ∂ n \mathbf{P}_{\mathcal{R} \mathcal{R}} \leftarrow \frac{\partial f_{\mathcal{R}}}{\partial \mathcal{R}} \mathbf{P}_{\mathcal{R} \mathcal{R}} \frac{\partial f_{\mathcal{R}}^{T}}{\partial \mathcal{R}}+\frac{\partial f_{\mathcal{R}}}{\partial \mathbf{n}} \mathbf{N} \frac{\partial f_{\mathcal{R}}^{T}}{\partial \mathbf{n}}PRRRfRPRRRfRT+nfRNnfRT

P R M ← ∂ f R ∂ R P R M \mathbf{P}_{\mathcal{R} \mathcal{M}} \leftarrow \frac{\partial f_{\mathcal{R}}}{\partial \mathcal{R}} \mathbf{P}_{\mathcal{R} \mathcal{M}}PRMRfRPRM

P M R ← P R M ⊤ \mathbf{P}_{\mathcal{M} \mathcal{R}} \leftarrow \mathbf{P}_{\mathcal{R} \mathcal{M}}^{\top}PMRPRM

3.3 已经加入地图的状态量观测更新

在EKF中,我们有以下一般的观测方程

y = h ( x ) + v \mathbf{y}=h(\mathbf{x})+\mathbf{v}y=h(x)+v

其中y \mathbf{y}y是测量噪声,x \mathbf{x}x是全状态,h ( ) h()h()是观测函数,v vv是测量噪声。

典型的EKF观测更新为:

z ‾ = y − h ( x ‾ ) \overline{\mathbf{z}}=\mathbf{y}-h(\overline{\mathbf{x}})z=yh(x)

Z = H x P H x ⊤ + R \mathbf{Z}=\mathbf{H}_{\mathbf{x}} \mathbf{P} \mathbf{H}_{\mathbf{x}}^{\top}+\mathbf{R}Z=HxPHx+R

K = P H x ⊤ Z − 1 \mathbf{K}=\mathbf{P} \mathbf{H}_{\mathbf{x}}^{\top} \mathbf{Z}^{-1}K=PHxZ1

x ‾ ← x ‾ + K z ‾ \overline{\mathbf{x}} \leftarrow \overline{\mathbf{x}}+\mathbf{K} \overline{\mathbf{z}}xx+Kz

P ← P − K Z K ⊤ \mathbf{P} \leftarrow \mathbf{P}-\mathbf{K} \mathbf{Z} \mathbf{K}^{\top}PPKZK

雅克比矩阵H x = ∂ h ( x ‾ ) ∂ x \mathbf{H}_{\mathbf{x}}=\frac{\partial h(\overline{\mathbf{x}})}{\partial \mathbf{x}}Hx=xh(x)R \mathbf{R}R是测量噪声的协方差矩阵。

在SLAM中,观测指的是机器人上的传感器观测到某些路标点,并对路标点进行参数化的输出。每次可能对路标点有多个观测值,这里每使用一个观测值,就进行一次状态更新。

观测的结果依赖于机器人的状态R \mathcal{R}R,传感器的状态S \mathcal{S}S和路标点的状态L i \mathcal{L}_{i}Li,并且这里假设,传感器的状态与机器人的状态差了一个固定的坐标变化,其实也就是外参固定。当观测到路标点i ii时,可以得到如下关系:
y i = h i ( R , S , L i ) + v \mathbf{y}_{i}=h_{i}\left(\mathcal{R}, \mathcal{S}, \mathcal{L}_{i}\right)+\mathbf{v}yi=hi(R,S,Li)+v

这就是观测方程,它不依赖于除了L i \mathcal{L}_{i}Li外的任何路标点状态。因此EKF-SLAM的雅克比H x \mathbf{H}_{\mathbf{x}}Hx也是稀疏的:

H x = [ H R 0 ⋯ 0 H L i 0 ⋯ 0 ] \mathbf{H}_{\mathbf{x}}=\left[\begin{array}{lllllllll} {\mathbf{H}_{\mathcal{R}}} & {0} & {\cdots} & {0} & {\mathbf{H}_{\mathcal{L}_{i}}} & {0} & {\cdots} & {0} \end{array}\right]Hx=[HR00HLi00]

其中H R = ∂ h i ( R ‾ , S , L ‾ i ) ∂ R \mathbf{H}_{\mathcal{R}}=\frac{\partial h_{i}\left(\overline{\mathcal{R}}, \mathcal{S}, \overline{\mathcal{L}}_{i}\right)}{\partial \mathcal{R}}HR=Rhi(R,S,Li)H L i = ∂ h i ( R ‾ , S , L ‾ i ) ∂ L i \mathbf{H}_{\mathcal{L}_{i}}=\frac{\partial h_{i}\left(\overline{\mathcal{R}}, \mathcal{S}, \overline{\mathcal{L}}_{i}\right)}{\partial \mathcal{L}_{i}}HLi=Lihi(R,S,Li)。由于这里的稀疏性,EKF-SLAM的观测更新变成:

z ‾ = y i − h i ( R ‾ , S , L ‾ i ) \overline{\mathbf{z}}=\mathbf{y}_{i}-h_{i}\left(\overline{\mathcal{R}}, \mathcal{S}, \overline{\mathcal{L}}_{i}\right)z=yihi(R,S,Li)

Z = [ H R H L i ] [ P R R P R L i P L i R P L i L i ] [ H R ⊤ H L i ⊤ ] + R \mathbf{Z}=\left[\begin{matrix}\mathbf{H}_{\mathcal{R}} &\mathbf{H}_{\mathcal{L}_{i}}\end{matrix}\right]\left[\begin{array}{cc} {\mathbf{P}_{\mathcal{R} \mathcal{R}}} & {\mathbf{P}_{\mathcal{R} \mathcal{L}_{i}}} \\ {\mathbf{P}_{\mathcal{L}_{i} \mathcal{R}}} & {\mathbf{P}_{\mathcal{L}_{i} \mathcal{L}_{i}}} \end{array}\right]\left[\begin{array}{c} {\mathbf{H}_{\mathcal{R}}^{\top}} \\ {\mathbf{H}_{\mathcal{L}_{i}}^{\top}} \end{array}\right]+\mathbf{R}Z=[HRHLi][PRRPLiRPRLiPLiLi][HRHLi]+R

K = [ P R R P R L i P M R P M L i ] [ H R ⊤ H L i ⊤ ] Z − 1 \mathbf{K}=\left[\begin{array}{ll} {\mathbf{P}_{\mathcal{R} \mathcal{R}}} & {\mathbf{P}_{\mathcal{R} \mathcal{L}_{i}}} \\ {\mathbf{P}_{\mathcal{M} \mathcal{R}}} & {\mathbf{P}_{\mathcal{M} \mathcal{L}_{i}}} \end{array}\right]\left[\begin{array}{l} {\mathbf{H}_{\mathcal{R}}^{\top}} \\ {\mathbf{H}_{\mathcal{L}_{i}}^{\top}} \end{array}\right] \mathbf{Z}^{-1}K=[PRRPMRPRLiPMLi][HRHLi]Z1

x ‾ ← x ‾ + K z ‾ \overline{\mathbf{x}} \leftarrow \overline{\mathbf{x}}+\mathbf{K} \overline{\mathbf{z}}xx+Kz

P ← P − K Z K ⊤ \mathbf{P} \leftarrow \mathbf{P}-\mathbf{K} \mathbf{Z} \mathbf{K}^{\top}PPKZK

3.4 观测方程可逆时的状态增广

这里的状态增广指的是新发现的路标点的初始化。当机器人发现了曾经未观测到的路标点时,会利用观测方程将新的路标状态加入地图,这一步操作会增大总状态向量的大小。可以看到EKF-SLAM中的滤波器大小动态变化的。

当传感器信息可以提供新发现路标点的所有自由度,也就是观测方程是双射时,只需要根据观测方程h ( ) h()h()的逆运算,即可以得到机器人状态R \mathcal{R}R,传感器状态S \mathcal{S}S,观测量y n + 1 \mathbf{y}_{n+1}yn+1,观测噪声v vv,它们与新路标点状态的关系:

L n + 1 = g ( R , S , y n + 1 , v ) \mathcal{L}_{n+1}=g\left(\mathcal{R}, \mathcal{S}, \mathbf{y}_{n+1},v\right)Ln+1=g(R,S,yn+1,v)

上式是单个路标点的逆观测模型。

路标点的均值和雅克比:

L ‾ n + 1 = g ( R ‾ , S , y n + 1 , 0 ) \overline{\mathcal{L}}_{n+1}=g\left(\overline{\mathcal{R}}, \mathcal{S}, \mathbf{y}_{n+1},0\right)Ln+1=g(R,S,yn+1,0)

G R = ∂ g ( R ‾ , S , y n + 1 , 0 ) ∂ R \mathbf{G}_{\mathcal{R}}=\frac{\partial g\left(\overline{\mathcal{R}}, \mathcal{S}, \mathbf{y}_{n+1},0\right)}{\partial \mathcal{R}}GR=Rg(R,S,yn+1,0)

G v = ∂ g ( R ‾ , S , y n + 1 , 0 ) ∂ v \mathbf{G}_{\mathbf v}=\frac{\partial g\left(\overline{\mathcal{R}}, \mathcal{S}, \mathbf{y}_{n+1},0\right)}{\partial \mathbf{v}}Gv=vg(R,S,yn+1,0)

显然,新加路标点状态的协方差P L L \mathbf{P}_{\mathcal{L} \mathcal{L}}PLL,以及该状态与地图其它状态的互协方差为:

P L L = G R P R R G R ⊤ + G v R G v ⊤ \mathbf{P}_{\mathcal{L} \mathcal{L}}=\mathbf{G}_{\mathcal{R}} \mathbf{P}_{\mathcal{R} \mathcal{R}} \mathbf{G}_{\mathcal{R}}^{\top}+\mathbf{G}_{\mathbf v} \mathbf{R} \mathbf{G}_{\mathbf v}^{\top}PLL=GRPRRGR+GvRGv

P L x = G R P R x = G R [ P R R P R M ] \mathbf{P}_{\mathcal{L} \mathbf{x}}=\mathbf{G}_{\mathcal{R}} \mathbf{P}_{\mathcal{R} \mathbf{x}}=\mathbf{G}_{\mathcal{R}}\left[\begin{matrix}\mathbf{P}_{\mathcal{R} \mathcal{R}} &\mathbf{P}_{\mathcal{R} \mathcal{M}}\end{matrix}\right]PLx=GRPRx=GR[PRRPRM]

然后将这些结果加入到地图中,可以得到总状态的均值与协方差矩阵:
x ‾ ← [ x ‾ L ‾ n + 1 ] \overline{\mathbf{x}} \leftarrow \left[\begin{array}{c} {\overline{\mathbf{x}}} \\ {\overline{\mathcal{L}}_{n+1}} \end{array}\right]x[xLn+1]

P ← [ P P L x ⊤ P L x P L L ] \mathbf{P} \leftarrow\left[\begin{array}{cc} {\mathbf{P}} & {\mathbf{P}_{\mathcal{L} \mathbf{x}}^{\top}} \\ {\mathbf{P}_{\mathcal{L}\mathbf{x}}} & {\mathbf{P}_{\mathcal{L}\mathcal{L}}} \end{array}\right]P[PPLxPLxPLL]

4. 仿真实验

4.1 模型设置

4.1.1 传感器模型

传感器是一个360度的雷达,可以探测发现周围一定范围内的路标点及其类型,其探测半径为r,其观测值为(ξ \xiξ,s)。ξ \xiξ为在当前雷达坐标系中路标点与x轴的的夹角,s为路标点与当前雷达坐标系原点的距离。

4.1.2 运动模型

将当前时刻雷达局部坐标系中的(u 1 {u}_{1}u1,0)点作为下一时刻雷达的位置,所以运动方程可以设为:

[ x n y n ] = [ c o s θ n − 1 − s i n θ n − 1 s i n θ n − 1 c o s θ n − 1 ] [ u 1 0 ] + [ x n − 1 y n − 1 ] + [ n 1 0 ] \left[\begin{array}{cc} {x_{n}} \\ {y_{n}} \end{array} \right] = \left[\begin{array}{cc} cos\theta_{n-1} & -sin\theta_{n-1} \\ sin\theta_{n-1} & cos\theta_{n-1} \end{array}\right] \left[\begin{array}{cc} {u}_{1} \\ 0 \end{array}\right] + \left[\begin{array}{cc} {x_{n-1}} \\ {y_{n-1}} \end{array} \right] + \left[\begin{array}{cc} {n}_{1} \\ 0 \end{array} \right][xnyn]=[cosθn1sinθn1sinθn1cosθn1][u10]+[xn1yn1]+[n10]

其方位每次增加固定的u 2 u_2u2:

θ n + 1 = θ n + u 2 + n 2 {\theta_{n+1}} = {\theta_n} + {u}_{2} + {n}_{2}θn+1=θn+u2+n2

其中n 1 , n 2 n_1,n_2n1,n2为系统噪声。

4.1.3 观测模型

设路标点i ii的状态为x L i = x_{L_i}=xLi=(m 1 m_1m1m 2 {m}_{2}m2),则其在当前雷达坐标系的坐标为:

[ l a d a r 1 l a d a r 2 ] = [ c o s θ n − s i n θ n s i n θ n c o s θ n ] − 1 [ m 1 m 2 ] − [ x n y n ] \left[\begin{array}{cc} {{{ladar}_{1}}} \\ {{{ladar}_{2}}} \end{array} \right] = {\left[\begin{array}{cc} cos\theta_n & -sin\theta_n \\ sin\theta_n & cos\theta_n \end{array}\right]}^{-1} \left[\begin{array}{cc} {{{m}_{1}}} \\ {{{m}_{2}}} \end{array} \right] - \left[\begin{array}{cc} {x_n} \\ {y_n} \end{array} \right][ladar1ladar2]=[cosθnsinθnsinθncosθn]1[m1m2][xnyn]
则观测量为:

ξ = a t a n 2 ( l a d a r 2 , l a d a r 1 ) + v 1 \xi = atan2\left({{{ladar}_{2}}},{{{ladar}_{1}}}\right) + {v}_{1}ξ=atan2(ladar2,ladar1)+v1

s = ( l a d a r 1 ) 2 + ( l a d a r 2 ) 2 + v 2 s = \sqrt{{\left({{{ladar}_{1}}}\right)}^{2} + {\left({{{ladar}_{2}}}\right)}^{2}} + {v}_{2}s=(ladar1)2+(ladar2)2+v2

其中v 1 , v 2 v_1,v_2v1,v2为测量噪声。

4.2 实验结果

使用MATLAB编写程序进行仿真。

代码地址:https://github.com/liuzhenboo/EKF-2D-SLAM

4.2.1 第一次状态增广

其中左图黑色的点表示滤波器新加入的路标点状态均值,绿色椭圆表征路标状态的协方差,其椭圆方程为:

( x − x ‾ ) ⊤ P − 1 ( x − x ‾ ) =  const  (\mathbf{x}-\overline{\mathbf{x}})^{\top} \mathbf{P}^{-1}(\mathbf{x}-\overline{\mathbf{x}})=\text { const }(xx)P1(xx)= const 

其中x为路标状态,P为路标的协方差。

程序中是对P进行SVD分解,得到椭圆的方向R以及半轴到的长度,进行绘图。

4.2.2 状态增广,观测更新

如上图,黑色椭圆对应的路标点表示雷达曾经观测过它,但是当前时刻没有观测到;红色椭圆对应的路标点表示雷达曾经观测过它,并且当前时刻也观测到了;蓝色代表当前刚刚初始化的新路标点。

注意:由于数值计算的原因,图中几何元素的位置关系可能和实际有些许差别;比如有的路标点明明不在雷达范围内,却开始初始化(绿色),这是因为计算过程中matlab四舍五入导致的结果。

4.2.3 状态不再增广,只有观测更新

如上图,不再存在蓝色的协方差椭圆,代表状态增广停止,滤波器的大小不再改变。


版权声明:本文为liu2015302026原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。