【Carsim Simulink自动驾驶仿真】基于MPC的轨迹跟踪控制
时间:2022-09-10 17:00:00
如果对Carsim不了解基本用途,可参考:【Carsim Simulink基于自动驾驶模拟MPC的速度控制
如果对MPC算法原理不清楚,可以参考:如何理解MPC模型预测控制理论
项目介绍:
教程是北京理工大学无人驾驶车辆模型预测控制的第二版。使用的模拟软件是Carsim2020.0和MatlabR2021a。使用MPC控制思想跟踪和控制车辆轨迹,并给出模拟结果。
整整两天,踩了无数坑,所以篇幅比较大。如有其他问题,请一起讨论。
从网上下载的代码无法运行,因此本文的代码被修改和调试。
基于MPC轨迹跟踪控制
- 效果图
-
- 直线跟踪
-
- 3m/s
- 5m/s
- 10m/s
- 圆跟踪
-
- 3m/s
- 5m/s
- 10m/s
- MATLAB框架搭建
- 数学遗漏问题及代码修改
-
- 运动模型很少L
- 目标函数线性项少系数改写后
- 讨论代码中的其他问题
-
- 输入维度不匹配
- 超出数组范围的索引
-
- 1.变量范围
- 2.换个求解器
- 3.所有初始值均为0
- 4.对于kesi(4)和kesi(5)的赋值 (这是我的问题)
-
- 一些理解
- 参数的选取
- 速度问题
- 附录:全代码(修改后)
效果图
因为参数已经调整好了,效果和书不一样。
直线跟踪
图像为:路径,速度,误差和前轮偏角
前轮偏角局部放大图为:
3m/s
5m/s
10m/s
速度的具体图像如下:
圆跟踪
图为:路径、速度和前轮偏差(误差不知道Carsim中怎么画,知道的大佬请私信,呜呜呜):
放大轨迹后:
前轮偏角为:
放大前轮偏角后:
3m/s
速度为:
5m/s
速度为:
10m/s
速度为:
MATLAB框架搭建
书中给出的MATLAB框架如下:
因为对于这种方法输出需要再另外处理。所以我这里直接将速度乘3.6,角度也在程序中直接处理了。对应的框架图为:
代码的数学遗漏问题与修改
书中的代码和下载下来的代码不一样,所以还是检查一下这两个地方,
运动学模型少L
在书中,推导运动学模型的时候,最后一个数字分母是有一个l的:
但是在代码中,这个地方少了,需要加上。
改写之后的目标函数线性项少系数
这里的2在书中没有少,但是下载下来的代码中没有这个系数。如果没有的可以加一下。
代码中的其他问题及讨论
输入维度不匹配的情况
看一下S-Function
的输入是3个还是5个,输出是2个还是直接给出5个,对应的代码中也应该和其一样。具体在S-Function
中是初始化的第一个函数中的:
sizes.NumOutputs =5;%[speed,steering]
sizes.NumInputs =3;
索引超出数组范围
这个是我的主要问题,之所以报错,是因为求解器求解不出来优化问题,方法的话我找了一些,然后自己也试了一些:
1.变量的范围
这里有两种情况:
- 第一种情况是检查变量范围
delta_umin=[-0.05;-0.0082;];
如果当中的-0.05是0.05,将其加一个负号。 - 第二种情况其实扩大变量的范围可以求解,但是这里不建议,如果你在扩大范围之后可以求解,那么建议还是将其变回原来的数,更改其他值。
2.换一个求解器
使用interior-point-convex
,而不是active-set
%options = optimset('Algorithm','active-set');
options = optimset('Algorithm','interior-point-convex');
3.初始值全部设为0
检查初始化函数mdlInitializeSizes
中的x0
和U
是否都为零。注意,这里的U表示的就是控制量与参考控制的差值。
function [sys,x0,str,ts] = mdlInitializeSizes
%找到以下两个值
x0 = [0;0;0];
U=[0;0];
4.对于kesi(4)和kesi(5)的赋值 (这个是我的问题)
这个我认为争议比较大,但是改了之后确实没有报错了。
先说一下,按照理论:
kesi(4)和kesi(5)就是这里的控制变量 u ~ \tilde{u} u~。而这个 u ~ \tilde{u} u~根据定义是:
是当前速度与参考速度的插值,所以这里我们应该将Carsim中的5个变量全部输入到S-Funciton
中,然后进行如下操作:
U(1) = u(4)/3.6 - vd1;
steer_SW = u(5)*pi/180;
steering_angle = steer_SW/18;
U(2) = steering_angle - vd2;
kesi(4)=U(1); % vel-vel_ref
kesi(5)=U(2); % steer_angle - steering_ref
之前我从来没有怀疑过这里,直到我看到书中的代码和网上下载的不一样的时候,我就尝试了一下书上的代码,即将前四行全部注释掉:
% U(1) = u(4)/3.6 - vd1;
% steer_SW = u(5)*pi/180;
% steering_angle = steer_SW/18;
% U(2) = steering_angle - vd2;
kesi(4)=U(1); % vel-vel_ref
kesi(5)=U(2); % steer_angle - steering_ref
这样改之后我的代码就不会出现问题了。
一些理解
首先我们要清楚,kesi(4,5)
是控制减去参考控制
,求解器解出来的X
是前后两次的控制差值
。
我们先看能跑对的程序,大致过程可以简化成设置值,求解,给出输出
三步:
U = [0,0]
for 循环:
#第一步:设置kesi
kesi(4)=U(1); % vel-vel_ref
kesi(5)=U(2); % steer_angle - steering_ref
#第二步:求解
[X,~,~]=quadprog(H,f,A_cons,b_cons,[],[],lb,ub,[],options);
#第三步:给出输出
u_dot(1)=X(1);
u_dot(2)=X(2);
U(1)=kesi(4)+u_dot(1);%用于存储上一个时刻的控制量
U(2)=kesi(5)+u_dot(2);
u_real(1) = U(1) + vd1;
u_real(2) = U(2) + vd2;
这里列一个表格:
时间 | 求解之前的U,也就是上一步的U | kesi | u_dot | 求解之后的U | 输出 |
---|---|---|---|---|---|
k-1 | u k − 1 − u k − 1 r e f u_{k-1}-u_{k-1}^{ref} uk−1−uk−1ref | u k − 1 − u k − 1 r e f u_{k-1}-u_{k-1}^{ref} uk−1−uk−1ref | u k − u k r e f − u k − 1 + u k − 1 r e f u_k-u_{k}^{ref}-u_{k-1}+u_{k-1}^{ref} uk−ukref−uk−1+uk−1ref | u k − 1 − u k − 1 r e f + u k − u k r e f − u k − 1 + u k − 1 r e f = u k − u k r e f u_{k-1}-u_{k-1}^{ref}+u_k-u_{k}^{ref}-u_{k-1}+u_{k-1}^{ref}=u_k-u_{k}^{ref} uk−1−uk−1ref+uk−ukref−uk−1+uk−1ref=uk−ukref | u_k |
之后就可以征程循环。注意这里的初始值设置为[0,0]是合理的。 |
我出错的程序:
U = [0,0]
for 循环:
#第一步:设置kesi
U(1) = u(4)/3.6 - vd1;
steer_SW = u(5)*pi/180;
steering_angle = steer_SW/18;
U(2) = steering_angle - vd2;
kesi(4)=U(1); % vel-vel_ref
kesi(5)=U(2); % steer_angle - steering_ref
#第二步:求解
[X,~,~]=quadprog(H,f,A_cons,b_cons,[],[],lb,ub,[],options);
#第三步:给出输出
u_dot(1)=X(1);
u_dot(2)=X(2);
U(1)=kesi(4)+u_dot(1);%用于存储上一个时刻的控制量
U(2)=kesi(5)+u_dot(2);
u_real(1) = U(1) + vd1;
u_real(2) = U(2) + vd2;
建立同样的表格,这里唯一不一样的是,之前的输入其实是记忆到了程序里面,这里的输入变成了从程序中获取:
时间 | 求解之前的U,也就是上一步的U | kesi | u_dot | 求解之后的U | 输出 |
---|---|---|---|---|---|
k-1 | u k − 1 i n p u t − u k − 1 r e f u_{k-1}^{input}-u_{k-1}^{ref} uk−1input−uk−1ref | u k − 1 i n p u t − u k − 1 r e f u_{k-1}^{input}-u_{k-1}^{ref} uk−1input−uk−1ref | u k − u k r e f − u k − 1 i n p u t + u k − 1 r e f u_k-u_{k}^{ref}-u_{k-1}^{input}+u_{k-1}^{ref} uk−ukref−uk−1input+uk−1ref | u k − u k r e f u_k-u_{k}^{ref} uk−ukref | u_k |
k | u k i n p u t − u k r e f u_{k}^{input}-u_{k}^{ref} ukinput−ukref | ||||
但是按照道理来说,这个和上一个表格是一样的,这里不一样的是速度输入之后需要进行变换,输出的时候也要进行变换,这变换之后会存在的误差比较大。还有一种可能,这里其实输入进来的是速度和方向盘转角,这个方向盘转角和轮胎转角之间有一个系数,这个系数这里设置的18,但是具体设置多少,也没有具体的深究。 | |||||
总之我个人感觉可能是上一时刻的输出 u k u_k uk和这一时刻的输入 u k i n p u t u_k^{input} ukinp相关文章
|