基于动力学的MPC控制器设计盲点解析

文章目录

    • Apollo MPC控制器的设计架构
    • 误差模型和离散化
    • 预测模型推导
    • 目标函数和约束设计
    • 优化求解
    • 优化OSQP求解器
    • 参考文献

Apollo MPC控制器的设计架构

误差模型和离散化

状态变量和控制变量

1、Apollo MPC控制器中状态变量主要有如下6个

  matrix_state_ = Matrix::Zero(basic_state_size_, 1);
  
  // State matrix update;
  matrix_state_(0, 0) = debug->lateral_error();
  matrix_state_(1, 0) = debug->lateral_error_rate();
  matrix_state_(2, 0) = debug->heading_error();
  matrix_state_(3, 0) = debug->heading_error_rate();
  matrix_state_(4, 0) = debug->station_error();
  matrix_state_(5, 0) = debug->speed_error();

状态变量计算:

控制变量有两个:

其中\delta _{_{f}} 为前轮转角,a为加速度补偿

  Eigen::MatrixXd control_matrix(controls_, 1);
  control_matrix << 0, 0;

在代码中控制量的计算和输出

// 解mpc,输出一个vector,control内有10个control_matrix
SolveLinearMPC(matrix_ad_, matrix_bd_, matrix_cd_, matrix_q_updated_,
          matrix_r_updated_, lower_bound, upper_bound, matrix_state_, reference,
          mpc_eps_, mpc_max_iteration_, &control)
// 已知,mpc仅取第一组解为当前时刻最优控制解,即control[0]
// steer_single_direction_max_degree_ --- the maximum turn of steer
// control中第一个矩阵中的第一个值用于计算方向盘转角
double steer_angle_feedback = control[0](0, 0) * 180 / M_PI *
                                steer_transmission_ratio_ /
                                steer_single_direction_max_degree_ * 100;

double steer_angle = steer_angle_feedback + steer_angle_feedforwardterm_updated_ +
                     steer_angle_ff_compensation + steer_angle_feedback_augment;

// control中第一个矩阵中的第二个值control[0](1, 0),用于计算加速度 = 加速度补偿 + 期望加速度 + 坡度加速度补偿
debug->set_acceleration_cmd_closeloop(control[0](1, 0));
double acceleration_cmd = control[0](1, 0) + debug->acceleration_reference() + 
                          control_conf_.enable_slope_offset() * debug->slope_offset_compensation();

动力学误差模型

代码实现:

// 初始化矩阵
Status MPCController::Init(const ControlConf *control_conf) {
  ...
  // Matrix init operations.
  matrix_a_ = Matrix::Zero(basic_state_size_, basic_state_size_);
  matrix_ad_ = Matrix::Zero(basic_state_size_, basic_state_size_);
  ...
  // TODO(QiL): expand the model to accomendate more combined states.

  matrix_a_coeff_ = Matrix::Zero(basic_state_size_, basic_state_size_);
  ...

  matrix_b_ = Matrix::Zero(basic_state_size_, controls_);
  matrix_bd_ = Matrix::Zero(basic_state_size_, controls_);
  ...
  matrix_bd_ = matrix_b_ * ts_;

  matrix_c_ = Matrix::Zero(basic_state_size_, 1);
  ...
  matrix_cd_ = Matrix::Zero(basic_state_size_, 1);
  ...
  }

// 更新矩阵
void MPCController::UpdateMatrix(SimpleMPCDebug *debug) {
  const double v = VehicleStateProvider::instance()->linear_velocity();
  matrix_a_(1, 1) = matrix_a_coeff_(1, 1) / v;
  matrix_a_(1, 3) = matrix_a_coeff_(1, 3) / v;
  matrix_a_(3, 1) = matrix_a_coeff_(3, 1) / v;
  matrix_a_(3, 3) = matrix_a_coeff_(3, 3) / v;

  Matrix matrix_i = Matrix::Identity(matrix_a_.cols(), matrix_a_.cols());
  matrix_ad_ = (matrix_i + ts_ * 0.5 * matrix_a_) *
               (matrix_i - ts_ * 0.5 * matrix_a_).inverse();

  matrix_c_(1, 0) = (lr_ * cr_ - lf_ * cf_) / mass_ / v - v;
  matrix_c_(3, 0) = -(lf_ * lf_ * cf_ + lr_ * lr_ * cr_) / iz_ / v;
  matrix_cd_ = matrix_c_ * debug->heading_error_rate() * ts_;
}

// 求解MPC
// discrete linear predictive control solver, with control format
// x(i + 1) = A * x(i) + B * u (i) + C
bool SolveLinearMPC(const Matrix &matrix_a, const Matrix &matrix_b,
                    const Matrix &matrix_c, const Matrix &matrix_q,
                    const Matrix &matrix_r, const Matrix &matrix_lower,
                    const Matrix &matrix_upper,
                    const Matrix &matrix_initial_state,
                    const std::vector<Matrix> &reference, const double eps,
                    const int max_iter, std::vector<Matrix> *control) 

apollo使用的是双线性变换离散法的方法:

  matrix_ad_ = (matrix_i + ts_ * 0.5 * matrix_a_) *
               (matrix_i - ts_ * 0.5 * matrix_a_).inverse();
               
  matrix_bd_ = matrix_b_ * ts_;
 
  matrix_cd_ = matrix_c_ * debug->heading_error_rate() * ts_;

补充:

Apollo采用的中点欧拉法和向前欧拉法的结合:

预测模型推导

为什么不用上述推导出的离散化的状态空间方程来推导我们的预测模型,以此来设计MPC控制器?

主要考虑在设计目标函数的时候,想将我们的控制增量设计到我们的目标函数中去,而非直接使用控制量,控制增量为代价,能有效改善控制的平滑性

此处我们需要注意的是:

  • 控制步长为Nc,因此当预测步长为k+Nc+1时,此时预测状态y(k+Nc+1)的最后一项也只写到k+Nc-1。因为到k+Nc时刻及以后的控制量有两种处理策略第一种就是控制步长Nc之后的预测控制量保持不变;第二种就是Nc之后的预测控制量全部置零。我们此处达到控制步长之后的控制量全置零;
  • 最终推导出的系统的预测模型Y, 其可以根据系统当前的状态量,以及施加一个未来一段时间Nc序列的控制增量,我们就可以知道系统未来(Np步)的表现是什么样子的(系统输出),即y(k+1)~y(k+Np);

目标函数和约束设计

设计目标:

  • 希望我们的路径跟踪误差在预测时域内尽可能趋于0,也即希望目标函数的第一项的几个状态量尽可能趋于0,这样我们的车辆才能更好的跟随规划路径;
  • 其次,我们希望目标函数的第二项控制增量的代价越小越好,也即希望前后两帧的控制量变化越小越好,这样控制的效果越平滑,对应前轮转角和加速度变化越平滑;
  • 目标函数最后一项引入松弛因子(在程序中是一个具体的数值),其主要作用就是改善优化问题的可行解,提高求解效率;

在MPC控制规律中,将控制序列中的第一个参数作为控制量,输入给被控系统。

对于车辆控制来说,就是找到一组合适的控制量,如u = [\delta _{f},a]其中\delta _{_{f}} 为前轮转角,a为刹车/油门系数,使车辆沿参考轨迹行驶,且误差最小、控制最平稳、舒适度最高等。因此在设计目标函数的时候可以考虑以下几点:

1、设计代价函数时候,一般设计为二次型的样式,为的是避免在预测时域内,误差忽正忽负,导致误差相互抵消;

2、考虑的代价主要有如下:

  • 横向误差:指实际轨迹点与参考轨迹点间的距离;
  • 航向误差:车辆当前航向与参考轨迹点航向的偏差;
  • 速度误差:车辆当前速度与规划轨期望车速的偏差;
  • 刹车/油门调节量:目的是为了保证刹车/油门变化的平稳性;

3、约束条件:

  • 最大前轮转角
  • 最大前轮转角变化量
  • 最大刹车/油门调节量
  • 最大方向盘转角
  • 最大车速
  • 最大加速度等

此处关于控制增量的约束,比如说,我们的前轮转角打30°需要2s,则1s需要打15°,然而我们的控制周期T=0.05s,则控制周期我们需要下发的转角最大为0.75°,也即我们下发转角的最大速率不超过0.75°/T。

关于软约束,也即代价函数,使其值越小越好。

优化求解

滚动优化求解的目的是为了求最优控制解,是一种在线优化,它每一时刻都会针对当前误差重新计算控制量,通过使某一或某些性能指标达到最优来实现控制作用。因此,滚动优化可能不会得到全局最优解,但是却能对每一时刻的状态进行最及时的响应,达到局部最优。

第一步:目标函数如何转化为标准二次型

注意:

目标函数化简后的每一项其实都是一个具体的数,第三项表示具体数的转置等于其自身。因此合并第二项和第三项,二者实质相等。其次化成二次型后,G属于已知项,且Q也是已知项,故二次型的最后一项其实不影响最终的优化求解最小值问题,因此放在最后一项,且求解过程可以忽略

第二步:约束的转化

u(k)^{*}作为此时的控制量输入给系统,直到下一个控制时刻,系统根据新的状态信息预测下一时段内的输出,然后通过优化得到一组新的控制序列。如此反复,直至完成整个控制过程。

OSQP求解器

带参构造函数MpcOsqp 求解

输入矩阵Ad,Bd,Q,R,初始状态阵X0,控制量上下边界,状态量上下边界,参考状态(0矩阵),最大迭代次数mpc_max_iteration_,预测时域周期数horizon_,求解精度mpc_eps_,用输入参数去初始化类对象的数据成员

MpcOsqp::MpcOsqp(const Eigen::MatrixXd &matrix_a,
                 const Eigen::MatrixXd &matrix_b,
                 const Eigen::MatrixXd &matrix_q,
                 const Eigen::MatrixXd &matrix_r,
                 const Eigen::MatrixXd &matrix_initial_x,
                 const Eigen::MatrixXd &matrix_u_lower,
                 const Eigen::MatrixXd &matrix_u_upper,
                 const Eigen::MatrixXd &matrix_x_lower,
                 const Eigen::MatrixXd &matrix_x_upper,
                 const Eigen::MatrixXd &matrix_x_ref, const int max_iter,
                 const int horizon, const double eps_abs)
    : matrix_a_(matrix_a),
      matrix_b_(matrix_b),
      matrix_q_(matrix_q),
      matrix_r_(matrix_r),
      matrix_initial_x_(matrix_initial_x),
      matrix_u_lower_(matrix_u_lower),
      matrix_u_upper_(matrix_u_upper),
      matrix_x_lower_(matrix_x_lower),
      matrix_x_upper_(matrix_x_upper),
      matrix_x_ref_(matrix_x_ref),
      max_iteration_(max_iter),
      horizon_(horizon),
      eps_abs_(eps_abs) {
  state_dim_ = matrix_b.rows();
  control_dim_ = matrix_b.cols();
  ADEBUG << "state_dim" << state_dim_;
  ADEBUG << "control_dim_" << control_dim_;
  num_param_ = state_dim_ * (horizon_ + 1) + control_dim_ * horizon_;
}

OSQP求解结果输出:

 std::vector<double> control_cmd(controls_, 0);

  apollo::common::math::MpcOsqp mpc_osqp(
      matrix_ad_, matrix_bd_, matrix_q_updated_, matrix_r_updated_,
      matrix_state_, lower_bound, upper_bound, lower_state_bound,
      upper_state_bound, reference_state, mpc_max_iteration_, horizon_,
      mpc_eps_);
//取控制序列的第一个作为输出的控制量
  if (!mpc_osqp.Solve(&control_cmd)) {
    AERROR << "MPC OSQP solver failed";
  } else {
    ADEBUG << "MPC OSQP problem solved! ";
    control[0](0, 0) = control_cmd.at(0);
    control[0](1, 0) = control_cmd.at(1);
  }

  //第一个元素前轮反馈转角
  steer_angle_feedback = Wheel2SteerPct(control[0](0, 0));

  //第二个元素加速度补偿
  acc_feedback = control[0](1, 0);

参考文献

本文针对运动学MPC控制器进行回顾总结,详细可以参考下述文献。

1、【基础】自动驾驶控制算法第五讲 连续方程的离散化与离散LQR原理_哔哩哔哩_bilibili

2、基于MPC轨迹跟踪~理论篇上_哔哩哔哩_bilibili

3、Apollo代码学习(六)—模型预测控制(MPC)_apollo mpc-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947261.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DC-DC 降压转换器设计提示和技巧

基本 DC-DC 降压转换器电路 在开始之前&#xff0c;我们先回顾一下DC-DC降压转换器的电路&#xff1a; 为了帮助您&#xff0c;我开发了降压设计中“什么影响什么”的矩阵&#xff1a; 主要的权衡是电感&#xff08;与 k 因子成反比&#xff0c;即峰峰值与平均电感电流之比&a…

Unity3D仿星露谷物语开发9之创建农场Scene

1、目标 绘制农场的场景。通过不同Sorting Layer控制物体的显示优先级&#xff0c;绘制Tilemap地图&#xff0c;添加Tilemap Collider碰撞器&#xff0c;同时添加Composite Collider碰撞器优化性能。 ps&#xff1a;绘制Tilemap的技巧&#xff1a;通过"Shift [" 可…

Linux 定时任务:轻松创建与精准执行

Linux 定时任务&#xff1a;轻松创建与精准执行 在 Linux 系统的运维与自动化管理领域&#xff0c;定时任务扮演着举足轻重的角色。它能够让系统在预设的时间点或周期性时段&#xff0c;自动执行特定的脚本、命令&#xff0c;极大地减轻了管理员的工作负担&#xff0c;提升工作…

Linux驱动开发:深入理解I2C时序(二)

在Linux驱动开发中,I2C时序的理解和正确处理是保证I2C设备正常工作和通信的关键。I2C协议的时序特性决定了数据的有效传输和设备间的协作。因此,掌握I2C的时序细节,以及如何在Linux内核中进行时序处理,能够让开发者更好地处理设备通信问题。 本文将继续深入探讨I2C通信协议…

国产编辑器EverEdit - 常用资源汇总

1 国产编辑器EverEdit-常用资源汇总 EverEdit是一款国产文本编辑器&#xff0c;历经超过15年的更新和维护&#xff0c;拥有不输业界顶级商业文本编辑器(EmEditor、UltraEdit)的实力&#xff0c;甚至在某些方面的功能更强(当然&#xff0c;各有千秋)&#xff0c;开发者对文本编辑…

解决uniapp H5页面限制输入框只能输数字问题

工作记录 最最近在做 uniapp 开发的移动端 H5 页面&#xff0c;有个需求是金额输入框只能输入数字&#xff0c;不能输入小数点和其他字符&#xff0c;经过各种尝试&#xff0c;发现其他字符可以通过正则过滤掉&#xff0c;但是输入小数点的话&#xff0c;因为没有触发 input 和…

面试准备备备备

职业技能 放到简历的黄金位置&#xff08;HR刷选简历的重要参考&#xff09; 基本准则&#xff1a;写在简历上的必须能聊&#xff0c;不然就别写 参考公式&#xff1a;职业技能 必要技术 其他技术 针对性的引导面试官&#xff08;让他问一些你想让他问的&#xff09; 寻找合…

npm install --global windows-build-tools --save 失败

注意以下点 为啥下载windows-build-tools&#xff0c;是因为node-sass4.14.1 一直下载不成功&#xff0c;提示python2 没有安装&#xff0c;最终要安装这个&#xff0c;但是安装这个又失败&#xff0c;主要有以下几个要注意的 1、node 版本 14.21.3 不能太高 2、管理员运行 …

Jenkins 中自动化部署 Spring Boot 项目

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的全栈工程师 欢迎分享 / 收藏 / 赞 / 在看…

【DSP/matlab】fftshift 是什么意思?在信号处理中有什么作用?

文章目录 前言一、定义什么是 fftshift&#xff1f;fftshift 在信号处理中的作用&#xff1a; 前言 dsp_paper 一、定义 fftshift 是一个在信号处理和数字信号处理中常用的函数&#xff0c;特别是在使用快速傅里叶变换&#xff08;FFT&#xff09;时。这个函数的主要作用是将…

【PCIe 总线及设备入门学习专栏 4.2 -- PCI 总线的三种传输模式 】

文章目录 OverviewProgrammed I/O&#xff08;PIO&#xff09;Direct Memory Access (DMA)Peer-to-Peer 本文转自&#xff1a;https://blog.chinaaet.com/justlxy/p/5100053095 Overview 本文来简单地介绍一下PCI Spec规定的三种数据传输模型&#xff1a;Programmed I/O&…

SpringBoot_第二天

SpringBoot_第二天 学习目标 Mybatis整合&数据访问 使用SpringBoot开发企业项目时&#xff0c;持久层数据访问是前端页面数据展示的基础&#xff0c;SpringBoot支持市面上常见的关系库产品(Oracle,Mysql,SqlServer,DB2等)对应的相关持久层框架&#xff0c;当然除了对于关系…

分类模型评估利器-混淆矩阵

相关文章 地理时空动态模拟工具介绍&#xff08;上&#xff09; 地理时空动态模拟工具介绍&#xff08;下&#xff09;地理时空动态模拟工具的使用方法 前言 混淆矩阵&#xff08;Confusion Matrix&#xff09;是机器学习领域中用于评估分类模型性能的一种工具。它通过矩阵的…

【SpringMVC】拦截器

拦截器&#xff08;Interceptor&#xff09;是一种用于动态拦截方法调用的机制。在 Spring MVC 中&#xff0c;拦截器能够动态地拦截控制器方法的执行过程。以下是请求发送与接收的基本流程&#xff1a; 当浏览器发出请求时&#xff0c;请求首先到达 Tomcat 服务器。Tomcat 根…

el-table 实现纵向多级表头

为了实现上图效果&#xff0c;最开始打算用el-row、el-col去实现&#xff0c;但发现把表头和数据分成两大列时&#xff0c;数据太多时会导致所在格高度变高。但由于每一格数据肯定不一样&#xff0c;为保持高度样式一致&#xff0c;就需要我们手动去获取最高格的高度之后再设置…

[paddle] 非线性拟合问题的训练

利用paddlepaddle建立神经网络&#xff0c;模拟有限个数据的非线性拟合 本文仍然考虑 f ( x ) sin ⁡ ( x ) x f(x)\frac{\sin(x)}{x} f(x)xsin(x)​ 函数在区间 [-10,10] 上固定数据的拟合。 import paddle import paddle.nn as nn import numpy as np import matplotlib.…

深入理解Python中的常用数据格式(如csv、json、pickle、npz、h5等):存储机制与性能解析

在数据科学与工程领域&#xff0c;数据的存储与读取是日常工作中不可或缺的一部分。选择合适的数据格式不仅影响数据处理的效率&#xff0c;还关系到存储空间的利用与后续分析的便捷性。本文将以通俗易懂的方式&#xff0c;深入探讨Python中几种常用的数据读写格式&#xff08;…

算法 class 005 (对数器C语言实现)

对数器的概念&#xff1a; 用来测试你的算法是否正确。 怎么做呢&#xff1f; 1&#xff1a;比如&#xff0c;写个冒泡排序&#xff0c;作为对比的对象 2&#xff1a;生成一个随机数 数组&#xff0c;用来测试 3&#xff1a;用冒泡排序和你想要验证的那个排序算法&#xff0c;同…

基于AT89C51单片机的可暂停八路抢答器设计

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/90196607?spm1001.2014.3001.5503 C15 部分参考设计如下&#xff1a; 摘要 随着社会进步和科技发展&#xff0c;电子设备在各类活动中的应用日益普遍&#xff0c…

IoC设计模式详解:控制反转的核心思想

前言&#xff1a;在软件开发中&#xff0c;设计模式是一种经过验证的、在特定场景下能有效解决问题的解决方案。控制反转&#xff08;Inversion of Control&#xff0c;IoC&#xff09; 作为一种设计模式&#xff0c;通过让程序的控制流和对象管理反转&#xff0c;从而使得代码…