function [kr,err] = fcn(x,y,phi,vx,vy,phi_dot,xr,yr,thetar,kappar)
n=length(xr);%先找到规划轨迹的长度,共有多少个规划点
d_min=(x-xr(1))^2+(y-yr(1))^2;%把最短距离设为真实位置与第1个点。可以不用开平方根,减少计算量,因为并不关心距离是多少,只想找到最短点的序号
min=1;%先把最短点的序号设为1
for i=1:n%遍历所有的点
d=(x-xr(i))^2+(y-yr(i))^2;%计算它与真实的位置的之间的距离
if d<d_min%如果能找到比所设置的最短距离还要短
d_min=d;%将值赋为最短距离
min=i;%把序点的序号赋给min
end
end
%遍历一遍后,一定能找到最短的距离规划点的序号,其实就是选择排序法
dmin=min;
tor=[cos(thetar(dmin));sin(thetar(dmin))];
nor=[-sin(thetar(dmin));cos(thetar(dmin))];
d_err=[x-xr(dmin);y-yr(dmin)];
ed=nor'*d_err;
es=tor'*d_err;
%projection_point_thetar=thetar(dmin);%apollo
projection_point_thetar=thetar(dmin)+kappar(dmin)*es;%投影点的航向角
ed_dot=vy*cos(phi-projection_point_thetar)+vx*sin(phi-projection_point_thetar);
%%%%%%%%%
ephi=sin(phi-projection_point_thetar);%因为角度具有多值性,使用sin来消除因为多2pi或者少2pi而导致的算法出错
%%%%%%%%%
s_dot=vx*cos(phi-projection_point_thetar)-vy*sin(phi-projection_point_thetar);
s_dot=s_dot/(1-kappar(dmin)*ed);
ephi_dot=phi_dot-kappar(dmin)*s_dot;
kr=kappar(dmin);
err=[ed;ed_dot;ephi;ephi_dot];
end
plain

,用 From Workspace 模块,从工作区里把变量导入到 Simlink 里必须要工作区里有
注意 : From workspace 只能导行向量,能导列向量、不能导矩阵,也不能导结构体。实际上通过技巧操作可以导矩阵以及列向量,但省事点尽量变成行向量就可以了。
4、AB模块 + LQR模块
本来 LQR 模块应该最难写,也最复杂,但是很幸运 Matlab 自己有 LQR 模块包。用离线LQR,所以 LQR 变成了最好写的模块,而且 LQR 模块和 AB 计算模块是紧密联系的,所以把 AB 计算模块和 LQR 模块合在一起写。
先建立脚本文件,作为LQR离线查表的数据,代码如下:
lqr_offline.m
登录后复制 __
复制代码
cf=-110000;%侧偏刚度根据曲线估算
cr=cf;%严格来说 CR 和 CF 应该不一样,但差别不大,所以近似认为一样
m=1412;%根据Carsim把整车参数输进去
Iz=1536.7;
a=1.015;
b=2.910-1.015;
k=zeros(5000,4);%申请矩阵k,用来存放LQR的k
for i=1:5000
vx=0.01*i;%只有vx是变量,所以每隔0.01米每秒,算一下对应的k。
%这样的话就可涵盖v从 0.01 米每秒到 v 等于 50 米每秒这么大范围内所有的 k
A=[0,1,0,0;
0,(cf+cr)/(m*vx),-(cf+cr)/m,(a*cf-b*cr)/(m*vx);
0,0,0,1;
0,(a*cf-b*cr)/(Iz*vx),-(a*cf-b*cr)/Iz,(a*a*cf+b*b*cr)/(Iz*vx)];
B=[0;
-cf/m;
0;
-a*cf/Iz];
Q=1*eye(4);
R=10;
k(i,:)=lqr(A,B,Q,R);
end
k1=k(:,1)';%建立四个变量,K1、K2、K3、K4,把表记录下来
k2=k(:,2)';%因为Simlink不能传矩阵,只能传行向量,需要做个转置
k3=k(:,3)';
k4=k(:,4)';
plain

秒之外,从
开始到
,再从
到想要的速度,但如果
,代到
矩阵里,
就变成奇异阵了,里面有无穷大。所以在
情况下的
,要进行另外处理,不能用LQR算,后面再讲。
是由
如何查表找和
很有规律,从
一直增大,所以第一行
必然对应
, 第
行对应
,只要让
除以
这样的小数,对应哪个
,用速度除
,除出来是小数而不是整数,那怎么办呢?
秒是非常小的间隔,在两个之间的
以及
五个变量决定,把
输入进去,除以
,做四舍五入,看和表的哪组
对应,就把对应的
离线 LQR 算法程序代码如下:
登录后复制 __
复制代码
function k = fcn(k1,k2,k3,k4,vx)
if abs(vx)<0.01%特殊处理如果 v 的绝对值小于0.01,
k=[0,0,0,0];%直接令 k 就等于0,它是航向量
else
index=round(vx/0.01);%否则的话就用 v x 除001,再用round四舍五入,值就是所要的匹配的序号
k=[k1(index),k2(index),k3(index),k4(index)];
end
end
plain
设置成了单位矩阵,
取
,可以设置不同的
和
,算出
来,再把
导进去。所以 LQR 和规划算法一样,得先跑一遍,让工作区 Workspace 里有
,才能进行下一步的 Simulink 仿真。
LQR中的权重矩阵
和
只要记住两句话即可:
**
控制量
可能会特别大,比如可能算出来
要达到
**
过程比较平缓比较重要,因为要保证平缓、舒适性、安全性。
和
权重的权衡互相矛盾,要具体调合适的
和
,期望达到的效果是能很快跟踪上路径,并且控制量
模块写好之后,用 Simlink 拼起来即可。
5、前馈模块实现
以及投影点的曲率
。
forward_control
登录后复制 __
复制代码
function forword_angle = fcn(vx,a,b,m,cf,cr,k,kr)
forword_angle=kr*(a+b-b*k(3)-(m*vx*vx/(a+b))*((b/cf)+(a/cr)*k(3)-(a/cr)));
end
plain
最后把所有结果整合起来即可。
last_angle
登录后复制 __
复制代码
function angle = fcn(k,err,forword_angle)
angle=-k*err+forword_angle;
end
plain