当前位置: 首页 > article >正文

深蓝学院自主泊车第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=xk1+vkcos(θk1)Δt=yk1+vksin(θk1)Δt=θk1+ω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(xk1,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(xk1,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=AkPk1AkT+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= 100010vksinθk1Δtvkcosθk1Δ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θk1Δtsinθk1Δ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(zkxk,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=(IKk)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展示,

在这里插入图片描述


http://www.kler.cn/a/548748.html

相关文章:

  • Vue 4.0发布!JSX vs 模板语法:谁才是前端的未来?
  • 线性表之顺序表
  • 【2025最新计算机毕业设计】基于SpringBoot+Vue高校社团管理系统 【提供源码+答辩PPT+文档+项目部署】
  • DeepSeek专题:以专业角度详细讲讲Deepseek-R1的高质量数据合成过程⌛
  • 机试刷题_字符串的排列【python】
  • 容器运行常见数据库
  • python电影数据分析及可视化系统建设
  • 深入学习Linux命令行中的各种替换操作(命令替换、参数替换、进程替换)
  • MySQL常见错误码及解决方法(1130、1461、2003、1040、2000、1049、1062、1129、2002、1690等)
  • (萌新入门)如何从起步阶段开始学习STM32 ——2 我应该学习HAL库还是寄存器库?
  • 【自学笔记】计算机视觉基础知识点总览-持续更新
  • 使用JavaScript实现深浅拷贝
  • 单链表的概念,结构和优缺点
  • openharmony系统移植之显示驱动框架从framebuffer升级为drm(linux-5.10)
  • 【JVM系列】谈一谈JVM调优
  • 【Leetcode】解锁二分查找:突破解题瓶颈的关键技巧
  • Java和JavaScript当中的json对象和json字符串分别讲解
  • 栈的深度解析:从基础实现到高级算法应用——C++实现与实战指南
  • 清华大学×DeepSeek 使用手册 2.0:《DeepSeek如何赋能职场应用?》(文末附下载链接)
  • DeepSeek-R1论文阅读及蒸馏模型部署