基于动力学模型的无人驾驶车辆MPC轨迹跟踪算法及carsim+matlab联合仿真学习笔记

news2024/11/26 10:30:03

目录

1 模型推导及算法分析

1.1 模型推导

1.1.1 车辆动力学模型

1.1.2 线性时变预测模型推导

1.2 模型预测控制器设计

1.2.1 目标函数设计

1.2.2 约束设计

2 代码解析

2.1 模板框架

2.1.1 S-Function

2.1.2 mdlInitializeSizes函数

2.1.3 mdlUpdates()函数

2.1.4 mdlOutputs()函数

2.2 MPC 算法主体

雅可比矩阵 a  b 求解

E 矩阵

参考轨迹 Y ref

H 矩阵

f 矩阵

约束矩阵

quadprog 求解器

3. carsim、simulink联合仿真

3.1 Carsim 设置

3.1.1 车辆参数设置

3.1.2 仿真工况设置

3.1.3 输入输出设置

3.1.4 仿真结果:图形曲线

3.1.5 仿真结果:动画效果

3.2 simulink 仿真

3.2.1 carsim 路径添加

3.2.2 Simulink 搭建

3.2.3 仿真结果

4 不同工况下仿真结果

4.1 控制系统对路面附着条件的鲁棒性

4.2 控制算法对速度的鲁棒性

4.3 不同设计参数对控制器的影响


1 模型推导及算法分析

包括车辆非线性横摆动力学模型、线性时变预测模型推导,以及MPC控制器设计

1.1 模型推导

动力学模型+线性时变预测模型

1.1.1 车辆动力学模型

 公式(2.38)是考虑轮胎侧向、纵向滑移的非线性动力学方程,成立的条件是假设前轮偏角 δf 较小,且轮胎模型工作在线性区域。

轨迹跟踪属于横向控制,控制量为小车前轮转角δf。这里默认纵向速度Vx恒定,轨迹跟踪的目的就是使车辆的横摆角 φ 和横向位置 Y 逼近参考轨迹的 φ_ref 和 Y_ref。

选取状态量ξ = [ y_dot, x_dot, φ, φ_dot, Y, X ] ,输出量 η = [ φ ; Y ],于是得到非线性模型:

97011ab307606b8d5ee26a7af81651d1.png

1.1.2 线性时变预测模型推导

1、离散化:采用前向欧拉法,将非线性公式(2.29)在 k 时刻离散化 

 2、 线性化

线性化方法泰勒展开首先需要选择一个起始参照点,参照点的选择有参考系统方法,及针对状态轨迹的线性化方法(参照第一版教材3.3.2节,第二版教材这部分内容缺失)。

a. 参考系统方法是指提前得到了每个时刻的参考控制量 Uref,和状态量 ξref 。即在期望轨迹上已经完全通过。这种设计目的是为了消除当前车辆状态和参考系统状态的偏差,本质上不是直接和期望路径进行偏差比对,而是和参考值进行比对。这种方法缺点在于需要提前获取到一个参考系统。本章节的期望轨迹只有 X_predict、Y_ref 及 φ_ref,不包含全部状态,因此无法提前得到一组参考系统,所以采用状态轨迹法。

b. 状态轨迹法:在 t 时刻工作点,对系统施加持续不变的控制量 ut ,得到一条状态轨迹 ξt,并在该 t 时刻做线性化。

难点:这里所谓对系统施加的持续不变的控制量 ut 就是后面用到的恒定量 u(k-1),是在轨迹跟随控制前就已经施加到系统上的控制量,并且这个初始控制量在整个轨迹跟踪过程中都会恒定不变地施加在系统上,不会随着系统状态及控制量的变化而消失,每次求解得到的最优 Δu(k) 只是在上一时刻的 u(k-1) 的基础上补偿的一个增量,这个增量对原本施加在系统上的 ut 即 u(k-1) 没有任何影响,通俗的理解就是 u(k+Np)=u(k-1) + Δu(k) + Δu(k+2) + ... + Δu(k+Np-1) + Δu(k+Np), 即每次求解得到的Δu(k)对控制量的增益改变都会叠加到下一时刻。

难点2:这里的u(k-1)其实就是车辆在没有被施加控制增量时候已经被施加了的控制量,也就意味着是上一时刻的控制量在当前时刻的体现,因为还没有施加控制增量,所以自然可以表示上一时刻的控制量。

先在 t=0 时刻的工作点(ξ0,u0)进行泰勒展开,忽略高阶项:

 (11-a)ξ(k + 1)表达式就是线性时变预测模型。 Ak,t 、Bk,t 及 dk,t 表示这是一个时变系统 LTV,需要在线求解系数。这种模型缺点在于表达式中不包含控制量的增量 Δu(k),从而无法使其受到 ΔUmin 和 ΔUmax 的约束,如果在驾驶过程中方向盘的转动幅度过大,会给乘车人带来不好的体验,所以现在需要构造新的形式以便包含对Δu(k)的约束:

1.2 模型预测控制器设计

有了对 Δu(k) 的约束后,就可以开始设计MPC,首先进行目标函数的设计。

1.2.1 目标函数设计

鉴于车辆动力学模型的复杂度较高,加上更多的约束条件,因此控制器在执行过程中,很有可能出现规定时间内求不出最优解的情况,这时车辆方向盘处于失控的危险状态。为了规避这种情况,在目标函数中加入松弛因子ρ。

注意:这里 ρ 越大意味着求解的条件越宽松,但 ρ过大也意味着跟踪效果不理想。

公式(13-a)的 Y(t) 表达式包含了未来 Np 个预测时域内的 ξ(k+i),将 Y(t) 代入目标函数。

公式(13-c)是标准的二次规划形式,其中待求解 X 已经由一维的 Δδf 扩增为包含 ε 的二维增广矩阵,接下来是约束条件的设计。

1.2.2 约束设计

控制量 u(k) 约束及输出量 φ(k) 和 Y(k) 的约束:

控制增量 Δu 的约束:

公式(14-a)是结合了控制量和输出量的综合形式,公式(14-b)是控制增量和松弛因子的约束。到目前为止已经完成轨迹跟踪的线性时变预测模型,接下来的工作是结合代码分析,并结合carsim联合仿真,查看轨迹跟踪效果。

2 代码解析

2.1 模板框架

2.1.1 S-Function

function [sys,x0,str,ts] = chapter5_2_2(t,x,u,flag) % u表示来自carsim的输入
switch flag,
 case 0
  [sys,x0,str,ts] = mdlInitializeSizes; % 初始化系统参数的一些基本的维度
 case 2
  sys = mdlUpdates(t,x,u); % 没有用到
 case 3
  sys = mdlOutputs(t,x,u); % 实现控制算法的主要模块
 case {1,4,9}
  sys = [];
 otherwise
  error(['unhandled flag = ',num2str(flag)]);
end

2.1.2 mdlInitializeSizes函数

function [sys,x0,str,ts] = mdlInitializeSizes
sizes = simsizes;
sizes.NumContStates  = 0; % 连续状态量个数为 0 
sizes.NumDiscStates  = 6; % 离散状态量个数为 6
sizes.NumOutputs     = 1; % 输出个数为 1,delta_f 作为输出
sizes.NumInputs      = 8; % 输入个数为 8,来自 carsim,还包括2个滑移率
sizes.DirFeedthrough = 1; % mdlOutputs函数模块中直接调用了u的数据,所以为1
sizes.NumSampleTimes = 1; 
sys = simsizes(sizes); 
x0 =[0.001;0.0001;0.0001;0.00001;0.00001;0.00001]; % 6个状态量的初始值
global U; % 1维控制量,前轮转角输出 delta_f
U=[0]; % delta_f(0)=0,起步时前轮转角为 0°
str = [];
ts  = [0.05 0]; % 仿真间隔是0.05秒,第二项为0表示从0秒开始立即仿真

2.1.3 mdlUpdates()函数

function sys = mdlUpdates(t,x,u) % 这部分没有用到
sys = x;

2.1.4 mdlOutputs()函数

u 表示来自carsim的 8 个状态输入,

function sys = mdlOutputs(t,x,u)
    tic % 开始计时
    fprintf('Update start, t=%6.3f\n',t) % 日志记录当前时刻控制动作的开始
    Nx=6;
    Nu=1;
    Ny=2;
    Np =20;
    Nc=5;
    T=0.05; % 采样时间

2.2 MPC 算法主体

tic 含义:

下面这部分是车体的参数,目的是为了求解雅可比矩阵 a 和 b

%% a b 常量参数:车体
    Sf=0.2; Sr=0.2;
    lf=1.232;lr=1.468;
    Ccf=66900;Ccr=62700;
    Clf=66900;Clr=62700;
    m=1723;g=9.8;I=4175;
%% a b 变量参数,carsim 实时采集
    y_dot=u(1)/3.6; % Km/h => m/s
    x_dot=u(2)/3.6+0.0001; % 防止分母为0
    phi=u(3)*3.141592654/180; % degree => rad
    phi_dot=u(4)*3.141592654/180;
    Y=u(5);
    X=u(6);
    Y_dot=u(7); % 前轮纵向滑移率
    X_dot=u(8); % 后轮纵向滑移率
    global U; % 控制量
    delta_f=U(1); 
    fprintf('Update start, u(1)=%4.2f\n',U(1)) % 日志记录每个控制周期的控制量 

雅可比矩阵 a  b 求解

接下来就是雅可比矩阵 a 和 b 的矩阵表达式,这里只写出了结果:

%% a b
    global a b;
    a=[                 1 - (259200*T)/(1723*x_dot),                                                         -T*(phi_dot + (2*((460218*phi_dot)/5 - 62700*y_dot))/(1723*x_dot^2) - (133800*((154*phi_dot)/125 + y_dot))/(1723*x_dot^2)),                                    0,                     -T*(x_dot - 96228/(8615*x_dot)), 0, 0
        T*(phi_dot - (133800*delta_f)/(1723*x_dot)),                                                                                                                  (133800*T*delta_f*((154*phi_dot)/125 + y_dot))/(1723*x_dot^2) + 1,                                    0,           T*(y_dot - (824208*delta_f)/(8615*x_dot)), 0, 0
                                                  0,                                                                                                                                                                                  0,                                    1,                                                   T, 0, 0
            (33063689036759*T)/(7172595384320*x_dot), T*(((2321344006605451863*phi_dot)/8589934592000 - (6325188028897689*y_dot)/34359738368)/(4175*x_dot^2) + (5663914248162509*((154*phi_dot)/125 + y_dot))/(143451907686400*x_dot^2)),                                   0, 1 - (813165919007900927*T)/(7172595384320000*x_dot), 0, 0
                                          T*cos(phi),                                                                                                                                                                         T*sin(phi),  T*(x_dot*cos(phi) - y_dot*sin(phi)),                                                   0, 1, 0
                                         -T*sin(phi),                                                                                                                                                                         T*cos(phi), -T*(y_dot*cos(phi) + x_dot*sin(phi)),                                                   0, 0, 1];
   

    b=[                                                               133800*T/1723
       T*((267600*delta_f)/1723 - (133800*((154*phi_dot)/125 + y_dot))/(1723*x_dot))
                                                                                 0
                                                5663914248162509*T/143451907686400
                                                                                 0
                                                                                 0];  

定义雅可比矩阵 a 和 b 的目的,是为了求解 A 和 B 矩阵:

代码实现:

    %%  A B C 
    A_cell=cell(2,2);
    A_cell{1,1}=a;
    A_cell{1,2}=b;
    A_cell{2,1}=zeros(Nu,Nx);
    A_cell{2,2}=eye(Nu);
    A=cell2mat(A_cell);
    
    B_cell=cell(2,1);
    B_cell{1,1}=b;
    B_cell{2,1}=eye(Nu);
    B=cell2mat(B_cell);
    
    C=[0 0 1 0 0 0 0; 
       0 0 0 0 1 0 0;];

这里 得到的A 和 B 矩阵的目的是为了得到 ψ θ Γ Φ 矩阵,参考公式(13-a):

 由于 θ 同时被矩阵E H f 调用,所以这里可以首先实现 θ:

    %% THETA (被 E H f 调用)
    THETA_cell=cell(Np,Nc);
    for j=1:1:Np
        for k=1:1:Nc
            if k<=j
                THETA_cell{j,k}=C*A^(j-k)*B;
            else 
                THETA_cell{j,k}=zeros(Ny,Nu);
            end
        end
    end
    THETA=cell2mat(THETA_cell);

我们的最终目标是定义 E H f 矩阵,以便构造二次规划标准型矩阵,下面我们按顺序依次实现 E H 和 f 矩阵,结合公式按顺序定义矩阵可以使代码段更加直观。

E 矩阵

第一项便是参考轨迹,这里可以用外部文件生成,也可以直接定义。

参考轨迹 Y ref

   %% Y_ref 
    % phi_ref Y-ref 
    shape=2.4;%参数名称,用于参考轨迹生成
    dx1=25;dx2=21.95;%没有任何实际意义,只是参数名称
    dy1=4.05;dy2=5.7;%没有任何实际意义,只是参数名称
    Xs1=27.19;Xs2=56.46;%参数名称,以上参数是为了生成我们的双移线
    X_predict= zeros(Np,1);%用于保存预测时域内的纵向位置信息,这是计算期望轨迹的基础
    phi_ref  = zeros(Np,1);%用于保存预测时域内的参考横摆角信息
    Y_ref    = zeros(Np,1);%用于保存预测时域内的参考横向位置信息
    % Yita_ref
    Yita_ref_cell=cell(Np,1); % ===========这里命名应该是Y_out_ref_cell,因为η的维度是2,不是 Np,但因为输出量Y和横向坐标命名冲突================
    T_all=20; % 总的仿真时间,防止计算期望轨迹越界
    for p=1:1:Np % 超出仿真时长,
        if t+p*T>T_all 
            X_DOT=x_dot*cos(phi)-y_dot*sin(phi);
            X_predict(Np,1)=X+X_DOT*Np*T;
            z1=shape/dx1*(X_predict(Np,1)-Xs1)-shape/2;
            z2=shape/dx2*(X_predict(Np,1)-Xs2)-shape/2;
            Y_ref(p,1)=dy1/2*(1+tanh(z1))-dy2/2*(1+tanh(z2));
            phi_ref(p,1)=atan(dy1*(1/cosh(z1))^2*(1.2/dx1)-dy2*(1/cosh(z2))^2*(1.2/dx2));
            Yita_ref_cell{p,1}=[phi_ref(p,1);Y_ref(p,1)];
        else % 在仿真时长内(正常执行部分)
            X_DOT=x_dot*cos(phi)-y_dot*sin(phi); % X的斜率,由非线性动力学公式(2.29给出)
            X_predict(p,1)=X+X_DOT*p*T; % X是由carsim输出的车辆当前纵向坐标,X_predict(p,1)表示下一时刻的纵坐标
            z1=shape/dx1*(X_predict(p,1)-Xs1)-shape/2; 
            z2=shape/dx2*(X_predict(p,1)-Xs2)-shape/2;
            Y_ref(p,1)=dy1/2*(1+tanh(z1))-dy2/2*(1+tanh(z2)); % 下一时刻的横坐标参考值
            phi_ref(p,1)=atan(dy1*(1/cosh(z1))^2*(1.2/dx1)-dy2*(1/cosh(z2))^2*(1.2/dx2)); % 下一时刻的横摆角参考值
            Yita_ref_cell{p,1}=[phi_ref(p,1);Y_ref(p,1)]; % [phi_rel; Y_ref]
        end
    end
    Yita_ref=cell2mat(Yita_ref_cell); % Y_ref 矩阵规范化

接下来实现 ψ

    %% ψ  PSI 
    PSI_cell=cell(Np,1);
    for j=1:1:Np
        PSI_cell{j,1}=C*A^j; 
    end
    PSI=cell2mat(PSI_cell);

然后是 ξ,这里 ξ 是经过重构的增广矩阵:

    %% ξ  kesi 
    kesi=zeros(Nx+Nu,1); % ξnew(k)=[ξ(k); u(k-1)]
    kesi(1)=y_dot;
    kesi(2)=x_dot;
    kesi(3)=phi; 
    kesi(4)=phi_dot;
    kesi(5)=Y;
    kesi(6)=X; 
    kesi(7)=U(1); % u(k-1)

GAMMA

    %% Γ  GAMMA
    GAMMA_cell=cell(Np,Np); % 维度 20*20
    for p=1:1:Np;
        for q=1:1:Np; 
            if q<=p;  % 下三角矩阵
                GAMMA_cell{p,q}=C*A^(p-q); 
            else 
                GAMMA_cell{p,q}=zeros(Ny,Nx+Nu);
            end 
        end
    end 
    GAMMA=cell2mat(GAMMA_cell);

最后是 Φ 的实现比较复杂,首先来看表达式,

dk,t 表达式:

 ξt_hat(k+1):这里需要理解:

    %% φ   PHI
    % ξt_hat_(k+1) 为求解 PHI 做准备
    state_k1=zeros(Nx,1);% 下面开始公式(10-a1)即k+1时刻的值 = k时刻的初始值 + T * k时刻的斜率(公式2.38)
    state_k1(1,1)=y_dot+T*(-x_dot*phi_dot+2*(Ccf*(delta_f-(y_dot+lf*phi_dot)/x_dot)+Ccr*(lr*phi_dot-y_dot)/x_dot)/m);
    state_k1(2,1)=x_dot+T*(y_dot*phi_dot+2*(Clf*Sf+Clr*Sr+Ccf*delta_f*(delta_f-(y_dot+phi_dot*lf)/x_dot))/m);
    state_k1(3,1)=phi+T*phi_dot;
    state_k1(4,1)=phi_dot+T*((2*lf*Ccf*(delta_f-(y_dot+lf*phi_dot)/x_dot)-2*lr*Ccr*(lr*phi_dot-y_dot)/x_dot)/I);
    state_k1(5,1)=Y+T*(x_dot*sin(phi)+y_dot*cos(phi));
    state_k1(6,1)=X+T*(x_dot*cos(phi)-y_dot*sin(phi));

 因为前面已经定义了雅可比矩阵 a 和 b,现在可以直接写出 dk,t 矩阵形式:

% dk 为求解 PHI 做准备
    d_k=zeros(Nx,1); % (6,1)
    d_k=state_k1-a*kesi(1:6,1)-b*kesi(7,1); % 公式(11-b)d_k=ξt_hat_(k+1)-Ak,t * ξt_hat_(k) -Bk,t * u(k-1)

这里还需要重构 d_piao_k:

% d_piao_k 为求解 PHI 做准备
    d_piao_k=zeros(Nx+Nu,1) % (7,1)
    d_piao_k(1:6,1)=d_k; % d_piao_k=[dk; 0],见公式(12-a)
    d_piao_k(7,1)=0;

最终可以求 Φ 矩阵:

    % PHI 最终求解
    PHI_cell=cell(Np,1); % φ(20*7,1)
    for p=1:1:Np;
        PHI_cell{p,1}=d_piao_k; 
    end
    PHI=cell2mat(PHI_cell);

接下来可以实现 E 矩阵

%% E 最终求解
    E=zeros(Ny*Np,1);% 源代码名为 error_1
    E=Yita_ref-PSI*kesi-GAMMA*PHI; % E=Yref-phi*ξ-Γφ,这里Yita_ref就是Yref

H 矩阵

% Q 
    Q_cell=cell(Np,Np);
    for i=1:1:Np; 
        for j=1:1:Np;
            if i==j
                Q_cell{i,j}=[2000 0;0 10000;]; % 分别为横摆角权重、横向位置权重
            else 
                Q_cell{i,j}=zeros(Ny,Ny); % Ny = 2
            end
        end 
    end 
    Q=cell2mat(Q_cell);
% R  
    R=5*10^5*eye(Nu*Nc);
% 松弛因子ρ
    Row=1000;
 % H 最终求解
    H_cell=cell(2,2);
    H_cell{1,1}=THETA'*Q*THETA+R; % H = θ'* Q * θ + R
    H_cell{1,2}=zeros(Nu*Nc,1);
    H_cell{2,1}=zeros(1,Nu*Nc);
    H_cell{2,2}=Row;
    H=cell2mat(H_cell); 
    H=(H+H')/2; % 保证 H 矩阵是严格的对称阵

f 矩阵

    f_cell=cell(1,2);
    f_cell{1,1}=2 * E' * Q * THETA;
    f_cell{1,2}=0;
    f=-cell2mat(f_cell);

到目前为止已经实现了全部要素矩阵 H f,接下俩可以开始定义约束矩阵。

约束矩阵

%% 控制量u(k)的约束,
    A_t=zeros(Nc,Nc);
    for p=1:1:Nc
        for q=1:1:Nc
            if q<=p
                A_t(p,q)=1;
            else 
                A_t(p,q)=0;
            end
        end 
    end 
    A_I=kron(A_t,eye(Nu)); % 这里A_I就是A_t,因为 Nu=1
    Ut=kron(ones(Nc,1),U(1)); Ut = u(k -1)
    umin=-0.1744; % 前轮偏角的上约束
    umax=0.1744; % 前轮偏角的下约束
    Umin=kron(ones(Nc,1),umin);
    Umax=kron(ones(Nc,1),umax);

输出量 Y(k) 的约束形式:

%% 输出量约束
    ycmax=[0.21; 5]; % 横摆角和纵向位置的约束
    ycmin=[-0.3;-3];
    Ycmax=kron(ones(Np,1),ycmax);
    Ycmin=kron(ones(Np,1),ycmin);

u(k) 和 Y(k) 约束的增广混合形式:

% 结合控制量约束和输出量约束
    A_cons_cell={A_I zeros(Nu*Nc,1);-A_I zeros(Nu*Nc,1);THETA zeros(Ny*Np,1);-THETA zeros(Ny*Np,1)};
    b_cons_cell={Umax-Ut;-Umin+Ut;Ycmax-PSI*kesi-GAMMA*PHI;-Ycmin+PSI*kesi+GAMMA*PHI};
    A_cons=cell2mat(A_cons_cell);%(求解方程)状态量不等式约束增益矩阵,转换为绝对值的取值范围
    b_cons=cell2mat(b_cons_cell);%(求解方程)状态量不等式约束的取值

Δu(k) 的约束,也就是QP求解方程的标准状态量X的约束:

%% 控制增量约束
    delta_umin=-0.0148*0.4; % 前轮偏角变化量的下约束
    delta_umax= 0.0148*0.4; % 前轮偏角变化量的上约束
    delta_Umin=kron(ones(Nc,1),delta_umin);
    delta_Umax=kron(ones(Nc,1),delta_umax); 
    M=10; % ε的上界 
    lb=[delta_Umin;0]; % [Δu(k);ε]的增广下界约束 lb
    ub=[delta_Umax;M]; % [Δu(k);ε]的增广上界约束 ub

quadprog 求解器

调用 matlab 自带的二次规划求解器 quadprog 进行求解,这部分是求解器的核心

%% quadprog求解器
options = optimset('Algorithm','interior-point-convex');% 选用内点法求解
x_start=zeros(Nc+1,1); % [Δu(k);ε]的初始值为 0
[X,fval,exitflag]=quadprog(H,f,A_cons,b_cons,[],[],lb,ub,x_start,options);
% [Δu(k);ε]的解存放在变量 X 中,包含未来Nc个时间点的Δu(k+i)

结果处理,将计算结果 u(k) 输出到carsim中:

%% 计算输出
u_piao=X(1); % 从Nc个未来时刻的Δu(k+i)中提取第一个时刻的Δu(k)作为当前时刻的最优解
U(1)=kesi(7,1)+u_piao; % 这里kesi(7,1)是u(k-1),加上Δu(k),则为当前时刻实际输出u(k)
sys= U; % 这里的 U 作为simulink的输出量,直接复制给carsim,进行前轮转角控制
toc % 一个完整的控制周期计时结束

现在已经实现了matlab全部的代码,下一节将进行联合仿真。

3. carsim、simulink联合仿真

本节主要以实例讲解通过搭建 simulink/carsim联合仿真平台,对设计的MPC控制器进行验证。下图是基于动力学模型的MPC轨迹跟踪控制器进行carsim与simulink联合仿真的实例。carsim版本是8.02,matlab版本是2018a

3.1 Carsim 设置

包括车辆参数设置、仿真工况设置、输入输出接口设置、仿真结果查看。

3.1.1 车辆参数设置

接下来就是车辆参数的具体设置,包括车辆尺寸信息和轮胎信息。

返回车辆参数设定界面,选择悬架和轮胎型号。

3.1.2 仿真工况设置

3.1.3 输入输出设置

由于本章的轨迹跟随为横向控制,只对前轮转角进行控制,所以carsim的输入端口选择车辆的四个轮胎的转角。其中2个前轮的转角由控制器提供,2个后轮的转角固定为0.0°,输出端口包括动力学系统的6个状态量和2个前轮的滑移率,共8个输出量。

 

这时就实现了下图所示的 carsim 和 simulink 之间的数据流传输:

3.1.4 仿真结果:图形曲线

新建数据集:

添加车辆质心的横向位置 Y 关于 X 的图像:

 添加横摆角 φ 关于 纵向位置 X 的图像:

点击 Plot 开始绘图

carsim 图形曲线与 simulink 采集的数据对比,结果完全一致:

3.1.5 仿真结果:动画效果

回到主界面,在下拉列表中选择视角,或者新建自定义数据集:

进入视角设定界面,为了展示双移线的跟踪效果,这里选择拖影效果,即 Ghost Trail Images ,选择拖影数量、时间间隔,将观测视角设定成车身起始点后方的固定视角:

跟踪动画效果如下,可以观察到车辆实际的双移线运动轨迹:

3.2 simulink 仿真

3.2.1 carsim 路径添加

 重启计算机后可在 MATLAB 的 Simulink Library Brower 中找到 Carsim 模块。

3.2.2 Simulink 搭建

首先确保matlab 安装了自动驾驶工具包

部分 matlab 版本不能直接显示,这里要点 Fix

 然后选第二项

这时就可以添加 carsim s-function 模块 

下面是搭建完成的 simulink 完整模块

在 s-function中编辑m文件

3.2.3 仿真结果

基于动力学模型的模型预测控制器主要用于较高速下的轨迹跟踪。在这种情况下对于控制器的评价不仅仅是跟踪精度,还需要重点考虑跟踪过程中的稳定性。在普通车轮形式稳定性的测试中,双移线工况是常用的测试路段。双移线参考轨迹如下图所示,由参考横向位置Yref和参考横摆角φre成,两者都为总关于纵向位置Y 的非线性函数:

在车速为30 km/h,道路摩擦系数为1的工况下,小车轨迹跟踪的仿真结果如下图,可以看出实际运行轨迹与双移线轨迹基本一致:

这里可以看到控制量被约束在限制范围内

4 不同工况下仿真结果

所设计的主动转向跟踪控制器以车辆前轮偏角作为控制器的输入,控制目标是通过不断减少与参考轨迹的偏差,跟踪参考轨迹。

4.1 控制系统对路面附着条件的鲁棒性

无人驾驶车辆在不同附着条件的道路上(如:干燥路面、湿滑路面)行驶时,车辆自身动力学参数,如轮胎侧偏刚度等将会发生变化,同时也会出现地面提供的侧向力不足的情况。这给控制器的性能带来一定的挑战。

若附着条件较差,地面不能提供足够的侧向力,车辆转向时横摆角会出现较大的偏差,轨迹跟踪控制器能够及时修正偏差,最终将偏差收敛为0。且跟踪过程中车辆的控制量及控制增量都处于约束范围内。软约束的加入能够保证系统在给定时间内得到可行解,所以控制系统能够在不同附着条件下较好地跟踪期望轨迹,且具备良好的稳定性。

Carsim 路面附着系数修改指导:

选择附着系数,通常干燥路面附着系数为0.7 ~ 1,湿滑路面附着系数为0.4左右

4.2 控制算法对速度的鲁棒性

很多控制器往往需要针对不同的行驶速度确定不同的控制参数,而模型预测控制器能够根据建立的车辆模型预测系统未来的输出,对车速的变化具有很强的鲁棒性。

主动转向系统仿真实验分别在10m/s 20m/s 和 30m/s的速度下行驶,道路附着条件良好,附着系数为0.8,控制器所采用的参数为T=0.05, Np=15,Nc=10。

从结果可以看出,速度越高,控制量的增量就越大,但不超过约束范围。各动力学约束保持在区间范围内,质心侧偏角则远低于极限范围,表明车辆行驶非常平稳,车速增加并不会导致车辆稳定性下降。 

4.3 不同设计参数对控制器的影响

不同参数对于控制器性能的影响有所差异。对于模型预测控制器来说,最重要的设计参数就是预测时域和控制时域。采用较小的预测时域和控制时域会导致跟踪偏差较大,但对于提升控制系统的实时性效果明显。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习中的数学原理——分类的正则化

通过这篇博客&#xff0c;你将清晰的明白什么是分类的正则化。这个专栏名为白话机器学习中数学学习笔记&#xff0c;主要是用来分享一下我在 机器学习中的学习笔记及一些感悟&#xff0c;也希望对你的学习有帮助哦&#xff01;感兴趣的小伙伴欢迎私信或者评论区留言&#xff01…

Go异步任务解决方案 Asynq

今天为大家介绍一个Go处理异步任务的解决方案&#xff1a;Asynq&#xff0c;是一个 Go 库&#xff0c;用于排队任务并与 worker 异步处理它们。它由Redis提供支持&#xff0c;旨在实现可扩展且易于上手。 一、概述 Asynq 是一个 Go 库&#xff0c;用于对任务进行排队并与工作人…

Python爬虫学习-简单爬取网页数据

疫情宅家无事&#xff0c;就随便写一些随笔吧QwQ… 这是一篇介绍如何用Python实现简单爬取网页数据并导入MySQL中的数据库的文章。主要用到BeautifulSoup requests 和 pymysql。 以网页https://jbk.39.net/mxyy/jbzs/为例&#xff0c;假设我们要爬取的部分数据如下图所示&#…

【板栗糖GIS】——如何下载哔哩哔哩的视频CC字幕为不带时间节点的纯文字

【板栗糖GIS】——如何下载哔哩哔哩的视频CC字幕为不带时间节点的纯文字 目录 1. 打开edge浏览器或谷歌浏览器 2. 安装油猴插件 3. 安装字幕插件 4. 打开哔哩哔哩视频播放页面&#xff0c;点击字幕 首先在想要下载之前需要先判定视频是否有云字幕&#xff0c;如果有才可以…

xxl-job详解

什么是xxl-job&#xff1f; ​ xxl-job是一个分布式的任务调度平台&#xff0c;其核心设计目标是&#xff1a;学习简单、开发迅速、轻量级、易扩展&#xff0c;现在已经开放源代码并接入多家公司的线上产品线&#xff0c;开箱即用。xxl是xxl-job的开发者大众点评的许雪里名称的…

SpringBoot+vue 实现监控视频rtsp播放(java+Nginx+ffmpeg+flv.js)

其实原理就是: 将监控通过FFMPEG,推送给Nginx,前端通过Nginx地址拉取视频&#xff0c;就可以播放了。 1:安装FFMPEG. 2:下载并且配置nginx. 3:使用java代码实现调用cmd或者linux窗口,并且运行操作FFMPEG的命令&#xff0c;进行监控视频rtsp格式的推送&#xff0c;推送给nginx. …

模板方法设计模式的学习和使用

1、模板方法设计模式的学习 当涉及到一系列具有相似行为的算法或操作时,模板方法设计模式是一种有效的设计模式。它允许你定义一个算法的骨架,同时将某些步骤的实现细节交给子类来实现。   模板方法模式基于以下两个核心原则&#xff1a; 抽象类定义模板方法骨架&#xff1a…

chatgpt赋能python:Python将一张图片分割成多张:从理论到实践

Python将一张图片分割成多张&#xff1a;从理论到实践 简介 随着Internet的爆炸式增长&#xff0c;图片已经成为了我们生活中不可或缺的一部分。具有高质量、高清晰度的图片可以提升网站的美观程度&#xff0c;帮助网站吸引更多的用户。但是&#xff0c;有时候大型的图片并不…

chatgpt赋能python:Python并不是一门简单的编程语言

Python 并不是一门简单的编程语言 Python 是一门直观且易学的编程语言&#xff0c;这一点没有错&#xff0c;但是要说它是简单的&#xff0c;那其实是不准确的。Python 有着广泛的应用领域&#xff0c;包括人工智能、大数据分析、Web开发、自动化测试等。尽管初学者可以迅速上…

MySQL中BETWEEN AND(范围查询)

0 写在前面 MySQL 提供了 BETWEEN AND 关键字&#xff0c;用来判断字段的数值是否在指定范围内。 BETWEEN AND 需要两个参数&#xff0c;即范围的起始值和终止值。如果字段值在指定的范围内&#xff0c;则这些记录被返回。如果不在指定范围内&#xff0c;则不会被返回。 最近…

JS 装饰器

JS 装饰器 JavaScript 装饰器是一种以 符号开头的特殊语法&#xff0c;放在目标代码的前面用于包装或扩展代码功能。JavaScript 的装饰器语法目前仍处于提案阶段&#xff0c;现阶段使用的话需要通过 bable 等方式进行编译之后&#xff0c;才能在浏览器正常运行。装饰器分为两…

chatgpt赋能python:Python将空值替换成0

Python 将空值替换成 0 在数据分析和处理过程中&#xff0c;清洗数据往往是非常重要的一个环节。而在清洗数据过程中&#xff0c;经常会遇到空值&#xff08;Missing Values&#xff09;的问题。空值是指在数据集中出现的缺失值&#xff0c;它可能是由于数据输入错误、数据采集…

chatgpt赋能python:Python定义数据框:介绍和基础操作

Python定义数据框&#xff1a;介绍和基础操作 数据框是一种非常方便的数据结构&#xff0c;用于在Python中存储和处理表格数据。数据框可以看作是围绕Series对象构建的2D数据结构&#xff0c;Series是一种存储单个列的一维标记数组。在本文中&#xff0c;我们将介绍如何使用Py…

基于树莓派4B的车牌号识别

目录 0. 前言1. Raspbian系统烧录2. 更换清华源1. 查看树莓派系统版本2. 更换清华国内源3. Raspi镜像修改4. 系统源更新5. 错误排查 3. opencv安装4. 安装 hyperlprpip安装编译安装 5. 验证项目可行性 0. 前言 基于树莓派4B的车牌号识别系统 操作系统&#xff1a;Raspbian PC…

QT实例2(QTableWidget表格中增删数据)

案例介绍 本案例仅简单介绍QTableWidget部分使用方法&#xff0c;如在表格中插入或删除一行数据以及清空表格数据等。在添加数据时&#xff0c;设置了条件判断如正则表达式&#xff0c;若用户输入的数据不合法&#xff0c;则添加失败并提示用户错误的地方&#xff0c;便于用户…

IPsec的NAT穿越详解

问题场景 左边的支部&#xff0c;它的防火墙上联路由器&#xff0c;由于防火墙内部的接口使用的是私网地址&#xff0c;这就导致其无无法在公网上与对端防火墙进行IPsec的隧道建立 。所以必须在AR5上面不是NAT地址转换&#xff0c;由于一般使用的是NAPT&#xff0c;isakmp协议因…

ChatGPT评测

总结&#xff1a;ChatGPT很强大&#xff0c;用作学术方面的问答或者软件行业的辅助工具是有一定的作用&#xff0c;但是有些回答设置了限制&#xff0c;并且中文回答方面总是回答一半&#xff0c;需要一直让他继续说&#xff0c;篇幅不是很长&#xff0c;但是往往能说道精髓&am…

最新加装ChatGPT的New Bing申请流程(含出错解决办法)

两天获得New Bing测试资格流程记录 前言一、Microsoft Edge Dev浏览器下载二、Microsoft账号注册与登陆三、浏览器插件下载与添加四、加入候补名单五、写封信给Bing团队 前言 2023.03.08&#xff0c;下午收到了Microsoft Bing公司的邮件&#xff0c;提示测试资格申请成功&…

Qt Xlsx的基本使用

前言 在很多时候 &#xff0c;我们需要将数据导出&#xff0c;之前我是将数据表导出为CSV格式&#xff0c;CSV文件虽然可以用Excel打开&#xff0c;但相对于真正的Xlsx文件&#xff0c;还是有许多不足的。偶然之间&#xff0c;发现了QtXlsx这个第三方库。 1、QtXlsx官网对QtX…

makefile工具的使用,编写一个或多个文件!(简单易上手)

一、make 和 makefile 是什么 1. make 是一个 命令。 2. makefile 是一个 文件&#xff0c;可以自动化的构建项目。 3. 编写 makefile 需要&#xff1a; &#xff08;1&#xff09;依赖关系 &#xff08;2&#xff09;依赖方法 二、什么是依赖关系、什么是依赖方法 下面我简单…