阅读代码:https://github.com/quyinsong/USV-path-following
运行效果:
这段代码实现了一个用于直线路径跟踪的视线引导(Line of Sight, LOS)控制算法,使用了PID控制器。
仿真循环:每个状态更新步骤使用欧拉积分 (euler2) 来更新状态。
需要实现或导入 USV 和 euler2 函数,即USV.m 和 euler2.m文件。
这段 MATLAB 代码实现了一种基于 视线引导法(Line-of-Sight, LOS) 的路径跟随控制算法,适用于自主水面艇(USV)的直线路径跟随。整个代码由 USV 的运动学和动力学模型构成,使用了 PID 控制器来调节航向。下面逐步解释代码的主要部分:
USV 的运动学和动力学参数初始化:m11
, m22
, m33
等是质量矩阵的相关元素,描述了 USV 的动力学特性。Xu
, Yv
, Nv
等是水动力系数,表示不同方向上的阻力和力矩的影响。
xk
, yk
:定义了直线路径的两个点。afak
计算了路径的方向角,基于起点和终点的坐标,通过 atan2
函数得到。
ts
:仿真时间步长,tfinal
:仿真总时间,Ns
:仿真步骤数量。初始状态 x=[0.1, 0.1, 0, 5, 5, 0]
对应了初始的速度、位置和航向角。在这个循环中,代码执行以下操作:
Kp1
是 LOS 控制器的增益。ye
是横向偏差,表示 USV 在当前时刻相对于目标路径的偏离量。beta
是当前 USV 的航向角。psaid
计算出期望航向角,基于 LOS 规则。ek
表示当前航向误差,Kd
和 Kp2
是控制器的参数,分别用于调整控制器对误差的响应。M
是 USV 的质量矩阵,Crb
是与科氏力和离心力相关的刚体力矩矩阵。Nvr
是与水动力相关的阻尼矩阵,表示水流对 USV 的影响。fr
是摩擦力模型。tpid
是 PID 控制器的输出力矩,用于控制 USV 的航向。tao
是控制输入向量,包含横向力、纵向力和航向力矩。euler2
函数进行欧拉法数值积分,更新 USV 的状态。xdot = USV(x,tao,[0 0]',[0,0]',d)
通过调用 USV
函数计算 USV 的状态导数,d
是随机噪声,模拟环境干扰。modelplot
函数用于在仿真过程中绘制 USV 的路径。在仿真过程中,Kp2
和 Kd
这两个参数根据不同的航向误差动态调整,以增强系统的响应速度和稳定性。PID 控制器根据航向误差和其导数生成控制信号来调整 USV 的航向。
这个代码实现了 USV 在水面上跟随指定直线路径的仿真,并且展示了控制器的设计和性能。
以下是代码的详细解释:
% line of sight guidence used in straight line path following
% control law use PID
clc
clear all
% USV parameters
m11 = 25.8; m22 = 33.8; m33 = 2.76; m23 = 1.095; m32 =1.095;
Xu=0.72253; Yv=-0.88965; Nv=0.0313;
Xuu=-1.32742; Yr=-7.25; Nr=-1.9;
Yvv=-36.47297; Nvv=3.95645;
Yrv=-0.805; Nrv=0.13;
Yvr=-0.845; Nvr=0.08;
Yrr=-3.45; Nrr=-0.75;
% generate two points
xk =[5 5]';yk =[300 150]';
afak=atan2(yk(2)-xk(2),yk(1)-xk(1));
%initial
ts =0.01;
tfinal=50;
Ns=tfinal/ts;
x=[0.1 0.1 0 5 5 0]';x0=x;
ek_1=1; Ek(1)=ek_1;
psaid_1 = 0.1; psaid_2 = 0.05;
% simulation
disp('Simulation ...');
for k=1:1:Ns
time(k)=(k-1)*ts;
% LOS law
Kp1=0.1;
ye=-(x(4)-xk(1))*sin(afak)+(x(5)-xk(2))*cos(afak);
YE(k)=ye;
beta=atan2(x(2),x(1));
psaid=afak+atan2(-Kp1*ye,1)-beta;
% control law
u = x(1);v=x(2);r= x(3);
ek=x(6)-psaid;
if k*ts<=0.5, Kd=0.8; else ,Kd=10;end
if ek<=0.05, Kp2=3;else,Kp2=1;end
% matrix
n11=-Xu-Xuu*abs(u);
n22=-Yv-Yvv*abs(v)-Yrv*abs(r);
n23=-Yr-Yvr*abs(v)-Yrr*abs(r);
n32=-Nv-Nvv*abs(v)-Nrv*abs(r);
n33=-Nr-Nvr*abs(v)-Nrr*abs(r);
M=[m11 0 0;
0 m22 m23;
0 m32 m33];
Crb=[0 0 -m22*v-m23*r;
0 0 m11*u;
m22*v+m23*r -m11*u 0 ];
% Nvr=[n11 0 0;
% 0 n22 n23;
% 0 n32 n33 ];
c13=Crb(1,3);
c23=Crb(2,3);
c31=-c13;c32=-c23;
m0 = m22*m33-m23*m32;
fr = (m32*(c23*r+n22*v+n23*r)+m22*(c13*u+c23*v-n32*v-n33*r))/m0;
psaidd = (psaid-2*psaid_1+psaid_2)/ts^2;
psaid_2=psaid_1; psaid_1 = psaid;
tpid=-Kp2*ek-Kd*(ek-ek_1)/ts-fr*m0/m22+psaidd;
ek_1=ek;
tao=[20 0 tpid]';
Ttao(k,:)=tao';
Ek(k)=ek;
% USV
d = [1*randn(1,1) 2*randn(1,1) 2*randn(1,1)]';
xdot=USV(x,tao,[0 0]',[0,0]',d);
% state update
x=euler2(xdot,x,ts);
% store time series
xout(1,:)=x0;
xout(k,:)=x';
end
u=xout(:,1);
v=xout(:,2);
r=xout(:,3);
N=xout(:,4);
E=xout(:,5);
psai=xout(:,6);
% plot
disp('Plot ...');
for k=1:1:Ns
pos =[N(k) E(k)]';
if k==1
modelplot(pos,psai(k));
end
if rem(k*ts,5)==0
modelplot(pos,psai(k));
end
end
plot(E,N,'r','linewidth',2)
plot([xk(2) yk(2)],[xk(1) yk(1)],'b',E,N,'r--','linewidth',2)
hold off;
figure(2);
plot([xk(2) yk(2)],[xk(1) yk(1)],'b',E,N,'r--','linewidth',2)
xlabel('E');ylabel('N');
figure(3);
plot(time,psai*180/pi,'r','linewidth',2);
xlabel('time/s');ylabel('psai/deg');
figure(4);
plot(time,u,'r','linewidth',2)
xlabel('time/s');ylabel('u (m/s)');
figure(5);
plot(time,Ttao(:,1),'r',time,Ttao(:,3),'b','linewidth',2)
legend('surge force','yaw torch');
figure(6);
plot(time,YE,'r','linewidth',2)
xlabel('time/s');ylabel('YE (m)');
hello,我是 。如果你喜欢我的文章,欢迎三连给我鼓励和支持:?点赞 ? 关注 ?评论,我会给大家带来更多有用有趣的文章。
原文链接 ? ,⚡️更新更及时。
欢迎大家添加好友交流。