深蓝学院自主泊车第2次作业-EKF
目录
- 1 题目
- 2 求解
1 题目
给定二维小车,其状态定义为 x = ( x , y , θ ) \boldsymbol{x} = (x, y, \theta) x=(x,y,θ), x x x表示二维运动中的横坐标值, y y y表示二维运行中的纵坐标值, θ \theta θ表示运行的方向,也叫作航向。控制输入定义为 u = ( v , ω ) \boldsymbol{u}=(v, \omega) u=(v,ω),其中 v v v表示小车的速度,它是一个标量,它的标准差为 σ v \sigma_v σv; ω \omega ω是小车的角速度,它也是一个标量,它的标准差为 σ ω \sigma_{\omega} σω。那么小车的运动方程可写为,
x
k
=
x
k
−
1
+
v
k
⋅
c
o
s
(
θ
k
−
1
)
⋅
Δ
t
y
k
=
y
k
−
1
+
v
k
⋅
s
i
n
(
θ
k
−
1
)
⋅
Δ
t
θ
k
=
θ
k
−
1
+
ω
k
⋅
Δ
t
(1)
\begin{align} x_k &= x_{k-1} + v_k \cdot cos(\theta_{k-1}) \cdot \Delta t \\ y_k &= y_{k-1} + v_k \cdot sin(\theta_{k-1}) \cdot \Delta t \\ \theta_{k} &= \theta_{k-1} + \omega_k \cdot \Delta t \end{align} \tag{1}
xkykθk=xk−1+vk⋅cos(θk−1)⋅Δt=yk−1+vk⋅sin(θk−1)⋅Δt=θk−1+ωk⋅Δt(1)
整体可写为,
x
k
=
f
(
x
k
−
1
,
u
k
)
+
w
k
\boldsymbol{x}_k = \boldsymbol{f}(\boldsymbol{x}_{k-1}, \boldsymbol{u}_k) + \boldsymbol{w}_k
xk=f(xk−1,uk)+wk,显然
f
(
⋅
)
\boldsymbol{f}(\cdot)
f(⋅)是一个非线性函数。
同样的,小车的测量方程为,
z
k
=
h
(
x
k
)
+
v
k
=
x
k
+
v
k
(2)
\boldsymbol{z}_k = \boldsymbol{h}(\boldsymbol{x}_k) + \boldsymbol{v}_k = \boldsymbol{x}_k + \boldsymbol{v}_k \tag{2}
zk=h(xk)+vk=xk+vk(2)
它是一个线性函数。
v
k
\boldsymbol{v}_k
vk是一个
3
×
1
3\times1
3×1维的向量,分别表示
x
,
y
,
θ
x,y,\theta
x,y,θ上的噪声,它们的标准差分别为
σ
x
,
σ
y
,
σ
θ
\sigma_x,\sigma_y,\sigma_{\theta}
σx,σy,σθ。
( v , ω ) (v,\omega) (v,ω)的数据频率为100Hz,且 σ v , σ ω \sigma_v,\sigma_{\omega} σv,σω已知。 z \boldsymbol{z} z的数据频率为10Hz,且 σ x , σ y , σ θ \sigma_x,\sigma_y,\sigma_{\theta} σx,σy,σθ已知。使用扩展卡尔曼滤波器估计小车的状态 ( x , y , θ ) (x,y,\theta) (x,y,θ)。
2 求解
依据扩展卡尔曼的那5个公式,可以得到如下公式,
预测部分:
x
k
=
f
(
x
k
−
1
,
u
k
)
(3)
\boldsymbol{x}_k = \boldsymbol{f}(\boldsymbol{x}_{k-1}, \boldsymbol{u}_k) \tag{3}
xk=f(xk−1,uk)(3)
P
k
=
A
k
P
k
−
1
A
k
T
+
B
k
R
k
B
k
T
(4)
\boldsymbol{P}_k = \boldsymbol{A}_k \boldsymbol{P}_{k-1} \boldsymbol{A}_k^T+\boldsymbol{B}_k \boldsymbol{R}_k \boldsymbol{B}_k^T \tag{4}
Pk=AkPk−1AkT+BkRkBkT(4)
其中,
A
k
=
[
1
0
−
v
k
⋅
s
i
n
θ
k
−
1
⋅
Δ
t
0
1
v
k
⋅
c
o
s
θ
k
−
1
⋅
Δ
t
0
0
1
]
(5)
\boldsymbol{A}_k = \begin{bmatrix} 1 & 0 & -v_k\cdot sin\theta_{k-1} \cdot \Delta t \\ 0 & 1 & v_k \cdot cos\theta_{k-1} \cdot \Delta t \\ 0 & 0 & 1 \end{bmatrix} \tag{5}
Ak=
100010−vk⋅sinθk−1⋅Δtvk⋅cosθk−1⋅Δt1
(5)
B
k
=
[
c
o
s
θ
k
−
1
⋅
Δ
t
0
s
i
n
θ
k
−
1
⋅
Δ
t
0
0
Δ
t
]
(6)
\boldsymbol{B}_k = \begin{bmatrix} cos\theta_{k-1} \cdot \Delta t & 0 \\ sin \theta_{k-1} \cdot \Delta t & 0 \\ 0 && \Delta t \end{bmatrix} \tag{6}
Bk=
cosθk−1⋅Δtsinθk−1⋅Δt000Δt
(6)
R
k
=
[
σ
v
2
σ
ω
2
]
(7)
\boldsymbol{R}_k = \begin{bmatrix} \sigma_v^2 \\ \sigma_{\omega}^2 \end{bmatrix} \tag{7}
Rk=[σv2σω2](7)
更新部分:
K
k
=
P
k
,
p
r
e
d
(
P
k
,
p
r
e
d
+
Q
k
)
−
1
(8)
\boldsymbol{K}_k = \boldsymbol{P}_{k,pred} (\boldsymbol{P}_{k,pred} + \boldsymbol{Q}_k)^{-1} \tag{8}
Kk=Pk,pred(Pk,pred+Qk)−1(8)
x
k
=
x
k
,
p
r
e
d
+
K
k
(
z
k
−
x
k
,
p
r
e
d
)
(9)
\boldsymbol{x}_k = \boldsymbol{x}_{k,pred} + \boldsymbol{K}_k(\boldsymbol{z}_k - \boldsymbol{x}_{k,pred}) \tag{9}
xk=xk,pred+Kk(zk−xk,pred)(9)
P k = ( I − K k ) P k , p r e d (10) \boldsymbol{P}_k = (\boldsymbol{I} - \boldsymbol{K}_k) \boldsymbol{P}_{k,pred} \tag{10} Pk=(I−Kk)Pk,pred(10)
修改部分代码如下,
void EkfPredict(State& state, const double &time, const double &velocity, const double &yaw_rate) {
// printf("time %lf, velocity %lf, yaw_rate %lf \n", time, velocity, yaw_rate);
// YOUR_CODE_HERE
// todo: implement the EkfPredict function
std::cout << "================start predict...================" << std::endl;
State pred;
pred.time = time;
double delta_t = 0.01;
//均值部分
pred.x = state.x + velocity * std::cos(state.yaw) * delta_t;
pred.y = state.y + velocity * std::sin(state.yaw) * delta_t;
pred.yaw = state.yaw + yaw_rate * delta_t;
if (pred.yaw > M_PI) { //把pred.yaw限制在[-pi,pi]
pred.yaw -= 2 * M_PI;
} else if (pred.yaw < -M_PI) {
pred.yaw += 2 * M_PI;
}
std::cout << "x = " << pred.x << ", y = " << pred.y << ", yaw = " << pred.yaw << std::endl;
//方差部分
Eigen::Matrix3d A_k;
A_k << 1.0, 0.0, -velocity * std::sin(state.yaw) * delta_t,
0.0, 1.0, velocity * std::cos(state.yaw) * delta_t,
0.0, 0.0, 1.0;
Eigen::Matrix<double, 3, 2> B_k;
B_k << std::cos(state.yaw) * delta_t, 0.0,
std::sin(state.yaw) * delta_t, 0.0,
0.0, delta_t;
pred.P = A_k * state.P * A_k.transpose() + B_k * Qn * B_k.transpose();
std::cout << "A_k: \n" << A_k << std::endl;
std::cout << "B_k: \n" << B_k << std::endl;
std::cout << "Qn: \n" << Qn << std::endl;
std::cout << "P: \n" << pred.P << std::endl;
state.time = pred.time;
state.x = pred.x;
state.y = pred.y;
state.yaw = pred.yaw;
state.P = pred.P;
std::cout << "================end predict...================" << std::endl;
return;
// printf("after predict x: %lf, y: %lf, yaw: %lf \n", state.x, state.y, state.yaw);
}
void EkfUpdate(State& state, const double &m_x, const double &m_y, const double &m_yaw) {
// printf("time :%lf \n", state.time);
// printf("before update x: %lf, y: %lf, yaw: %lf \n", state.x, state.y, state.yaw);
// printf("measure x: %lf, y: %lf, yaw: %lf \n", m_x, m_y, m_yaw);
// YOUR_CODE_HERE
// todo: implement the EkfUpdate function
std::cout << "================start update ...================" << std::endl;
State update;
//计算卡尔曼增益
Eigen::Matrix3d K_k = state.P * (state.P + Rn).inverse();
std::cout << "K_k:\n" << K_k << std::endl;
//计算均值部分
Eigen::Vector3d z_k(m_x, m_y, m_yaw);
Eigen::Vector3d x_k_pred(state.x, state.y, state.yaw);
Eigen::Vector3d innovation = z_k - x_k_pred;
if (innovation[2] > M_PI) { //将yaw之间的差异转换到[-pi,pi]之间
innovation[2] -= 2.0 * M_PI;
} else if (innovation[2] < -M_PI) {
innovation[2] += 2.0 * M_PI;
}
Eigen::Vector3d x_k = x_k_pred + K_k * innovation;
update.x = x_k[0];
update.y = x_k[1];
update.yaw = x_k[2];
// if (update.yaw > M_PI) {
// update.yaw -= 2 * M_PI;
// } else if (update.yaw < -M_PI) {
// update.yaw += 2 * M_PI;
// }
std::cout << "x = " << update.x << ", y = " << update.y << ", yaw = " << update.yaw << std::endl;
//计算方差部分
update.P = (Eigen::Matrix3d::Identity() - K_k) * state.P;
std::cout << "P: \n" << update.P << std::endl;
state.x = update.x;
state.y = update.y;
state.yaw = update.yaw;
state.P = update.P;
std::cout << "================end update...================" << std::endl;
return;
// printf("after update x: %lf, y: %lf, yaw: %lf \n", state.x, state.y, state.yaw);
}
打开4个终端,依次分别输入,
catkin_make
roscore
bash devel/setup.bash
rosrun vehicle_state_estimation vehicle_state_estimation
bash devel/setup.bash
rosrun rviz rviz -d src/state_estimation.rviz
rviz展示,