ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于MPC的Carsim与Simulink联合仿真路径跟踪控制实战

基于MPC的Carsim与Simulink联合仿真路径跟踪控制实战

简介:基于MPC的汽车路径跟踪控制资料包,面向智能驾驶与车辆控制方向的开发者、研究生及工程师,解决利用Carsim动力学仿真与Simulink联合搭建MPC轨迹跟踪闭环的典型需求。包内共13个文件,约214KB,涵盖Simulink模型文件、Carsim仿真配置、MATLAB脚本(用于模型线性化与Jacobian计算)、参考轨迹数据、说明文档及备份文件,可支撑从车辆动力学建模、MPC控制器搭建到联合仿真验证的完整流程。资源内容围绕Carsim高精度整车特性复现、Simulink双向数据接口、MPC预测模型与滚动优化、参考轨迹生成、控制器参数整定、实时性保障及可视化输出等关键模块展开,并保留原始备份文件便于版本对照,为理解自动驾驶路径跟踪控制提供可直接运行的示例环境。已有61人学习下载,适合具备一定MATLAB/Simulink基础、希望快速上手MPC联合仿真或需参考控制器架构设计的学习者使用。

1. 基于MPC的汽车路径跟踪控制:为什么联合仿真才是真正能落地的验证方式

拿纯跟踪或者PID做横向控制,在低速、大半径弯道上表现尚可,但一进连续S弯或者高速工况,前视距离和增益调来调去就是压不住轨迹偏差。MPC(模型预测控制)之所以在路径跟踪里被反复提起,是因为它把“未来一段路的跟踪”作为一个带约束的优化问题显式求解,能同时处理跟踪精度、控制量约束和执行器饱和。问题是,MPC控制器写出来之后,总得有一辆车来验证,总不能每次都上实车——Carsim与Simulink联合仿真就是行业里最常见的做法:Carsim提供高精度车辆动力学模型,Simulink跑控制器,两边以固定步长交换信号,闭环跑完还能把过程录成视频。这篇文章面向的是正在做横向控制算法验证的工程师和研究生,目标很明确:把MPC控制器在联合仿真里跑起来,并且搞清楚参数怎么调、坑在哪里、视频怎么出。

2. MPC路径跟踪控制器设计:先想清楚预测模型和控制目标

2.1 路径跟踪问题的本质是带约束的跟踪问题

路径跟踪不是单纯的“追一个点”,而是要让车辆在每一时刻的横向偏差、航向偏差尽可能小,同时保证前轮转角在物理可执行范围内。这里的难点在于:车辆是一个非线性、强耦合的系统,纵向速度和横摆运动互相影响,而且前轮转角不仅影响当前位置的曲率匹配,还影响未来一段时间的状态变化。

工程上最常见的建模方法是把问题拆成横向控制和纵向控制:纵向控制维持参考车速,横向控制输出前轮转角。MPC控制器在前向路径上取一系列参考点,利用车辆动力学模型预测未来N个步长的状态,然后求解一个带约束的二次规划问题,取出当前时刻的最优控制量施加给车辆。滚动时域的意思是,每一步都重新求解,只执行第一个控制量,然后下一个采样时刻再滚动一次。

这里的关键是预测模型。常用的是车辆二自由度单轨模型,状态量取横向偏差 (e_y)、航向偏差 (e_\psi)、侧向速度 (v_y) 和横摆角速度 (r),控制量取前轮转角 (\delta)。离散化之后得到线性状态方程:

[ x(k+1) = A_d x(k) + B_d u(k) ]

其中 (A_d, B_d) 由连续模型离散得到,采样周期一般取 20ms 到 100ms 之间。要注意的是,这个模型做了小角度假设,所以它只在侧向加速度不超过 0.4g 左右的工况下精度可控。超过这个范围,线性的预测模型和Carsim的非线性整车模型之间会出现明显偏差,MPC的预测优势就会被模型失配抵消。

2.2 线性时变MPC:工程上最常见的落地形式

纯线性MPC的问题在于它把车速当成定值,但实际仿真中车速会波动,尤其是在转向时纵向速度会被横摆耦合影响。所以工程上普遍采用线性时变MPC(LTV-MPC):在每个采样时刻,根据当前纵向速度重新计算离散化的状态方程,然后在此基础上做预测和优化。这样做的好处是,模型参数随工况更新,而优化问题的规模不变,实时性可控。

具体实现上,预测时域 (N_p) 内,从当前状态出发,用离散状态方程递推得到未来一系列状态:

[ X = \Phi x(k) + \Theta U ]

其中 (X) 是所有预测状态的堆叠,(U) 是控制时域 (N_c) 内的控制量序列。优化目标写成二次型:

[ J = (X - X_{ref})^T Q (X - X_{ref}) + U^T R U + \Delta U^T S \Delta U ]

这里的 (X_{ref}) 是对应于每个预测步的参考状态。约束条件包括前轮转角幅值约束、转角增量约束,必要时还会限制横摆角速度,避免激烈转向导致车辆失稳。

LTV-MPC的另外一层含义是:参考轨迹本身也需要在每个时刻重新生成。路径跟踪中,参考轨迹通常由规划层给出,是一组离散点序列;控制器需要根据当前车辆位置找出最近的参考点,然后沿路径方向截取一段作为预测参考。这个“找最近点”的操作如果做不好,MPC的优化问题就会在路径曲率变化处出现跳变,导致控制量抖振。

2.3 MPC控制器参数:预测时域、控制时域、权重矩阵

参数设计是MPC落地中最耗时的一步。预测时域 (N_p) 决定了控制器“看得多远”。(N_p) 太小,控制器只看眼前,路径跟踪在弯道处会滞后;(N_p) 太大,远方的参考点对当前控制量影响变小,而且优化变量增多,求解实时性下降,还可能因为模型偏差累积导致预测不可靠。我一般会以“车辆在预测时域内行驶的距离”为基准来选:车速 36km/h、采样周期 50ms、(N_p=20),对应前视距离约10米,在城市道路工况基本够用;高速工况要适当增大预测时域或者提高采样频率。

控制时域 (N_c) 一般取 (N_p) 的四分之一到三分之一。(N_c=5) 到 (N_c=8) 是常见的设置范围。权重矩阵 (Q) 中最重要的是横向偏差对应的权重。横向偏差权重设太低,车辆会“飘”在轨迹附近,弯道内侧偏移明显;设太高,控制器会很“神经质”,轻微噪声就引发剧烈转向。(R) 是控制量权重,它抑制转向指令的幅值。(S) 是控制量变化率权重,它决定转向指令的平滑程度,(S) 太小时方向盘看起来像在抖动,太大会让弯道响应变慢。

参数调整的顺序一般是:先固定预测时域和控制时域,调 (Q) 保证跟踪精度,再调 (R) 和 (S) 控制执行器输出质量。下面这个表格列出我常用的初始值范围:

参数符号初始范围调整依据
预测时域(N_p)15 ~ 25车速越高、道路曲率半径越大,取值越大
控制时域(N_c)3 ~ 8约 (N_p) 的 1/4 到 1/3
采样周期(T_s)0.02 ~ 0.1s越小控制越平滑,但求解负担增大
横向偏差权重(Q_{ey})10 ~ 100跟踪精度不足时增大,但注意引发转向抖振
航向偏差权重(Q_{epsi})1 ~ 10弯道入口处横摆响应慢时增大
转角权重(R)0.1 ~ 1转向幅值过大时增大
转角增量权重(S)1 ~ 10转向抖振时增大,通常在 5 附近起步

这些参数的初始值不是为了直接跑出最优结果,而是为了让系统在第一个仿真循环里稳定,之后再根据仿真录像和曲线微调。

3. Carsim与Simulink联合仿真环境搭建:从车辆模型到信号接口

3.1 Carsim车辆模型配置:车型、道路、车速三个关键设置

Carsim的优势在于它提供了经过大量实车验证的车辆动力学模型,不需要自己推导轮胎魔术公式和悬架动力学。但它的模型参数不是拿来就能直接用的,配置不当会导致联合仿真出来的车辆行为莫名其妙。

第一步是选车型。Carsim自带多种车型,包括轿车、SUV、轻型卡车等。做路径跟踪控制验证,建议选一个参数成熟的B级轿车或者C级轿车,不要一开始就上运动型车辆模型。运动型车辆的响应更快,MPC参数没调好时,系统更容易发散,排错时很难分清是控制器问题还是车辆模型问题。

第二步是道路设置。Carsim里需要建立一条参考路径,路径可以用道路中心线的离散点定义,也可以用曲率半径连续变化的道路段拼接。常见的做法是用一组 XY 坐标点定义路径中心线,然后让车辆初始位置对准路径起点。这里有一个容易被忽视的点:路径的坐标系是Carsim的全局坐标系,而MPC控制器预测用的参考轨迹是从这条全局路径上截取的。联合仿真的信号接口里,需要把Carsim输出的车辆全局坐标和航向角传回Simulink,然后控制器再根据车辆当前位置从全局路径中提取局部参考点。

第三步是车速设置。Carsim模型既可以由Simulink控制油门刹车,也可以设置定速巡航模式。联合仿真的初期阶段,强烈建议先用Carsim的定速模式把纵向车速固定,专注验证横向控制。等到MPC横向控制器在固定车速下稳定了,再切换到Simulink控制油门刹车的模式,把纵向控制加进来。这样把变量一个一个引入,调试效率高得多。

3.2 Simulink S-Function接口:信号定义与控制方式

Carsim与Simulink的联合仿真,核心是Carsim提供的一个Simulink模型,这里面包含一个Carsim S-Function模块。该模块接收Simulink侧的控制指令(转向角、油门、制动),输出车辆状态(位置、速度、横摆角速度、侧向速度等)。

接口的配置要在Carsim的图形界面里完成:选定输入输出变量后,点生成Simulink模型按钮,Carsim会自动生成一个包含S-Function的Simulink文件。这里需要特别留意输入输出的单位。Carsim的转向角接口冲量单位是度(deg),而MPC控制器内部计算用的是弧度(rad),所以Simulink模型里需要加一个增益模块做单位换算。油门和制动的接口通常是0到1的归一化值,而MPC的纵向控制如果有的话,输出的是加速度需求,需要再做一层映射才能接到油门刹车上。这些单位问题如果不统一,第一个仿真结果出来之后会发现车辆根本不动,或者转向角小得看不到效果。

3.3 仿真步长设置:固定步长与数据对齐

联合仿真的步长设置直接影响MPC控制器的性能。Simulink的求解器要设置为定步长,推荐步长取MPC控制器采样周期的一致值或者整数因子。例如MPC的采样周期是0.05秒,Simulink的定步长可以设成0.05秒,也可以设成0.01秒然后让MPC模块每5个步长执行一次。后者能让Carsim的车辆动力学积分更精确,但数据量变大,仿真速度变慢。

Carsim的解算步长一般在它自身的配置界面里设置。常见做法是把Carsim的内部步长设成与Simulink步长一致。如果不一致,S-Function需要做插值,插值在高速转向工况下会引入额外的延迟和噪声。这里的一个血泪经验是:先确认两边步长,再开始联调,否则后期排查控制量抖振时会多花很多时间。

联合仿真的数据流大概是这样的:

  1. Simulink中的MPC控制器根据当前车辆状态和参考轨迹,计算出前轮转角指令。
  2. 转角指令经单位换算后送入Carsim S-Function的输入端口。
  3. Carsim根据车辆动力学模型积分一步,更新车辆状态。
  4. 车辆状态经S-Function输出端口返回Simulink。
  5. Simulink将状态送入MPC控制器,同时记录数据用于后续分析和视频生成。

4. 在Simulink里实现MPC路径跟踪控制器:可复现的MATLAB Function方案

4.1 用MATLAB Function实现LTV-MPC核心逻辑

MPC控制器在Simulink里的实现方式有几种:用Model Predictive Control Toolbox的现成模块、用C MEX S-Function、或者用MATLAB Function(Interpreted MATLAB Function)。前两种方案的效率更高,但在控制器结构需要频繁调整时不太灵活。MATLAB Function写成的MPC控制器是初版验证阶段最实用的方案,原因很简单:你可以随时改预测模型矩阵、改权重、加约束,不需要重新编译。

下面给出一个基于离散状态方程的LTV-MPC核心代码。这个函数接收当前车辆状态、参考轨迹点、以及由Simulink传来的车速信息,输出前轮转角指令。

function delta = ltv_mpc_controller(x, y, psi, vx, ref_traj, Np, Nc, Ts, Q, R, S, delta_prev) % LTV-MPC控制器核心函数 % 输入: % x, y: 车辆全局坐标 (m) % psi: 车辆横摆角 (rad) % vx: 纵向速度 (m/s) % ref_traj: 参考轨迹矩阵,每行为 [x_ref, y_ref, psi_ref] % Np, Nc: 预测时域与控制时域 % Ts: 采样周期 (s) % Q, R, S: 权重矩阵 % delta_prev: 上一时刻前轮转角 (rad) % 输出: % delta: 当前时刻前轮转角指令 (rad) % 搭建车辆线性模型(二自由度单轨模型参数) lf = 1.1; lr = 1.6; m = 1500; Cf = 80000; Cr = 80000; Iz = 2500; % 状态量: [ey, epsi, vy, r],参考值为0(误差模型) % 连续时间状态矩阵 A_c, B_c A_c = [0, vx, 1, 0; 0, 0, 0, 1; 0, -(Cf+Cr)/(m*vx), -(Cf+Cr)/m, (lf*Cf-lr*Cr)/(m*vx); 0, -(lf*Cf-lr*Cr)/(Iz*vx), -(lf*Cf-lr*Cr)/Iz, -(lf^2*Cf+lr^2*Cr)/(Iz*vx)]; B_c = [0; 0; Cf/m; lf*Cf/Iz]; % 离散化(零阶保持) [A_d, B_d] = c2d(A_c, B_c, Ts); % 将参考轨迹转换为误差模型下的参考状态序列 % 先找最近参考点 dist = sqrt((ref_traj(:,1)-x).^2 + (ref_traj(:,2)-y).^2); [~, idx] = min(dist); % 截取预测窗口内的参考点 idx_end = min(idx + Np - 1, size(ref_traj,1)); ref_window = ref_traj(idx:idx_end, :); % 如果预测窗口超出轨迹末尾,用最后一点填充 if size(ref_window,1) < Np pad = repmat(ref_window(end,:), Np-size(ref_window,1), 1); ref_window = [ref_window; pad]; end % 计算误差模型下的参考状态 ey_ref = zeros(Np,1); epsi_ref = zeros(Np,1); for k = 1:Np % 车辆坐标投影到参考轨迹局部坐标系 dx = ref_window(k,1) - x; dy = ref_window(k,2) - y; dx_local = dx*cos(psi) + dy*sin(psi); dy_local = -dx*sin(psi) + dy*cos(psi); ey_ref(k) = dy_local; % 横向偏差 epsi_ref(k) = atan2(ref_window(k,3)-psi); % 航向偏差 end % 构建预测矩阵 Phi 和 Theta % 预测状态序列 X = Phi*x0 + Theta*U Phi = zeros(4*Np, 4); Theta = zeros(4*Np, Nc); for k = 1:Np Ak = A_d^k; Phi(4*(k-1)+1:4*k, :) = Ak; for j = 1:min(k, Nc) Theta(4*(k-1)+1:4*k, j) = Ak^(k-j) * B_d; end end % 构建二次规划问题 % 目标函数: min 0.5*U'*H*U + f'*U Q_block = kron(eye(Np), Q); R_block = kron(eye(Nc), R); % 预测误差 = Phi*x0 + Theta*U - Xref % 先把 Xref 算出来 Xref = zeros(4*Np, 1); for k = 1:Np Xref(4*(k-1)+1) = ey_ref(k); Xref(4*(k-1)+2) = epsi_ref(k); Xref(4*(k-1)+3) = 0; % vy的参考值为0 Xref(4*(k-1)+4) = 0; % r的参考值为0 end E = Phi * [0; 0; 0; 0] - Xref; % 当前状态初始化为误差模型的原点 H = Theta' * Q_block * Theta + R_block; f = Theta' * Q_block * E; % 约束:前轮转角幅值和变化率 % |U_i| <= 0.42 rad (约24度) % |U_i - U_{i-1}| <= 0.35 rad lb = -0.42 * ones(Nc,1); ub = 0.42 * ones(Nc,1); Aineq = zeros(Nc-1, Nc); bineq = zeros(Nc-1, 1); for i = 1:Nc-1 Aineq(i, i) = 1; Aineq(i, i+1) = -1; bineq(i) = 0.35; end % 处理第一项与控制时域内的delta_prev的关系 Aineq_extra = zeros(1, Nc); Aineq_extra(1) = 1; bineq_extra = delta_prev + 0.35; % 求解二次规划 options = optimoptions('quadprog', 'Display', 'off', 'Algorithm', 'active-set'); U_opt = quadprog(H, f, [Aineq; Aineq_extra], [bineq; bineq_extra], [], [], lb, ub, [], options); % 取第一个控制量 delta = U_opt(1); end

这段代码的逻辑不难拆解:先是根据当前纵向速度 (v_x) 在线计算离散状态矩阵 (A_d, B_d),这是LTV的体现;然后做全局路径到车辆局部坐标系的投影,得到未来 (N_p) 步的横向偏差和航向偏差参考;再构建预测矩阵 (\Phi) 和 (\Theta),最终把MPC优化问题转成标准的二次规划问题,用quadprog求解。

需要注意几个参数细节。第一,状态向量用的是误差模型,不是绝对状态,所以初始状态在原点,参考状态由路径投影得到。这种做法的好处是权重矩阵的物理意义更清晰:横向偏差的权重大小直接对应跟踪精度。第二,c2d函数用的是零阶保持离散化,这在采样周期不大于快速模式时间常数的十分之一时精度足够。第三,约束里用了两个不等式来处理控制量增量约束,第一项描述控制时域内部的增量限制,第二项描述第一个控制量相对于上一时刻输出的增量限制。

4.2 在Simulink模型里配置控制器模块与数据记录

把上面的函数封装成Simulink的MATLAB Function模块后,输入端需要接:车辆状态(来自Carsim S-Function)、参考轨迹(来自工作空间或者From Workspace模块)、车速(来自Carsim输出)。输出端接一个单位换算模块,把弧度换算成度,再送到Carsim S-Function的转向角输入端口。

参考轨迹的传入方式,常见做法是用一个Constant模块或者From Workspace模块,把预先规划好的路径点矩阵读入。路径点矩阵在MATLAB工作空间里定义,例如:

% 定义参考轨迹:一条带弯道的路径 s = linspace(0, 200, 2000)'; x_ref = s; y_ref = 20 * sin(0.05 * s); psi_ref = atan2(cos(0.05*s)*0.05*20, 1); ref_traj = [x_ref, y_ref, psi_ref];

这段代码生成一条在直线方向上叠加正弦弯道的参考路径。路径的航向角用解析求导得到。这里有个需要注意的点:如果路径规划层给的是离散点序列,航向角需要用相邻点计算斜率并做角度归一化(wrapToPi),否则航向角在 ±π 边界附近会跳变,MPC的参考状态会突然变化,控制量就会出现尖峰。

在Simulink里还需要添加一个数据记录模块,把车辆状态、参考轨迹、控制量记录到工作空间,用于后续的视频生成和性能分析。用To Workspace模块记录x, y, psi, delta, ey这些变量。记录的数据要有时间戳,视频生成时按时间戳同步帧。

4.3 仿真运行流程与参数初始化脚本

把整个仿真模型跑起来之前,我建议先写一个初始化脚本,把所有参数集中管理。这样每次改参数不需要去Simulink模块里翻,直接在脚本里改,然后重跑仿真即可。

% 联合仿真参数初始化脚本 Ts = 0.05; % 采样周期 50ms Np = 20; % 预测时域 Nc = 5; % 控制时域 Q = diag([50, 10, 1, 1]); % 状态权重 R = 0.5; % 控制量权重 S = 5; % 控制量增量权重(已并入H矩阵) % 参考轨迹 s = linspace(0, 300, 3000)'; x_ref = s; y_ref = 30 * sin(0.03 * s); psi_ref = atan2(30*0.03*cos(0.03*s), 1); ref_traj = [x_ref, y_ref, psi_ref]; % Carsim模型参数(供S-Function使用) Carsim_speed = 36/3.6; % 定速 36km/h 换算成 m/s % 仿真时长 sim_time = 40; % 秒 % 运行Simulink模型 sim('carsim_mpc_simulink.slx');

这段脚本里的Q = diag([50, 10, 1, 1])是性能调优的起点。横向偏差权重 50、航向偏差权重 10、侧向速度和横摆角速度权重各为 1。如果仿真结果里横向偏差过大,优先增大第一个权重;如果转向指令出现高频抖动,增大S或者在离散化时加一个一阶惯性滤波器,让参考输入更平滑。

运行仿真后,第一件事是检查变量logsout或者simout里的横向偏差曲线。如果曲线在弯道入口处出现尖峰,峰值远超0.5米,大概率是预测时域不足;如果曲线振荡不收敛,先检查单位换算是否正确,再检查约束是否被激活得太频繁,转角饱和会导致控制器行为退化成bang-bang控制,也就是方向盘来回打到极限位置。

5. 联合仿真高频踩坑与排查:现象、原因、解决办法

5.1 Carsim生成的Simulink模型在MATLAB里打不开报错

现象:在Carsim界面点击生成Simulink模型后,生成的.slx文件在MATLAB中打开时提示版本不兼容或者缺少模块库。

原因:Carsim与MATLAB的版本匹配问题。Carsim每代版本支持的MATLAB版本范围有限,如果MATLAB版本过高或者过低,Carsim自带的S-Function模块无法被正确加载。另一个常见原因是路径中含中文或空格,Carsim生成的模型文件引用了带中文路径的资源文件,Simulink无法解析。

解决:先确认Carsim安装目录下自带的文档里标注的MATLAB兼容版本列表,把MATLAB版本调整到兼容范围。这一步没有捷径,兼容性列表在Carsim安装目录的Docs文件夹里有明确说明。路径问题解决方法是把整个工程放在纯英文路径下,例如D:\MPC_Project\,避免中文目录和空格。检查系统的环境变量,确认Carsim运行时所需的库路径已正确添加到PATH中。

5.2 仿真结果发散,车辆状态在几个仿真步内超出合理范围

现象:仿真开始后,车辆位置和横摆角以肉眼可见的速度失控,横向偏差直接飞到几十米,或者转角输出持续在饱和值上震荡。

原因:MPC预测模型里的参数与Carsim车辆模型参数不一致,导致优化解在实际车辆上表现不符合预测。更常见的诱因是单位错误——MPC内部用弧度计算,而Carsim输入接口单位是度,差了一个57.3倍的系数,直接让小角度控制指令变成大幅摆动。还有一种可能是初始参考点搜索出错,车辆位置和路径起点距离过远,MPC找到最近点后生成了不合理的参考序列,优化出大力转向指令。

解决:第一步先检查Simulink模型里的单位换算增益,这是所有问题里成本最低的一个。建议在Carsim输入端口前加一个显示模块,监控实际送入S-Function的转角值。第二步是确保车辆初始位置与路径起点对齐,在Carsim里设置车辆坐标时,误差不要超过0.5米、航向角误差不要超过3度。第三步是降低MPC的权重比例,把横向偏差权重从50降到20,同时把控制量增量权重提高到10,让初始阶段的转向指令更温和。

5.3 仿真速度极慢,一个40秒的工况要跑十几分钟

现象:Simulink仿真进度条几乎不动,查看CPU占用率发现MATLAB单核满载。

原因:首先是定步长设得太小。Carsim的模型包含复杂的轮胎和悬架动力学,如果步长设为1微秒,计算量巨大,但车辆动态响应并没有因此变得更准确。其次是MATLAB Function里用了quadprog,每次MPC调用都要做优化问题求解,当预测时域很大时,优化求解耗时占比显著。还有一个隐蔽的原因是Simulink里可能有连续模块导致变步长求解器被禁用,连PCM(过零检测)被频繁触发。

解决:把Simulink定步长设置成MPC采样周期的整数倍,比如MPCTs=0.05,就用0.05的定步长,不要更细。若Carsim模型内部要求更小步长,在Carsim配置界面单独设置内部步长,让它与Simulink步长脱钩,通过S-Function的插值处理数据对接。对于quadprog的耗时问题,在optimoptions里把OptimalityTolerance放宽到 1e-3,把ConstraintTolerance放宽到 1e-3,求解速度可以提升两倍以上,控制精度损失在毫米级,完全可接受。

5.4 车辆航向角在±π边界跳变,导致控制器输出尖峰

现象:车辆沿直线行驶,但MPC输出的转向指令每隔几秒出现一个陡峭的尖峰,车辆在路径上画出一条明显的小蛇形轨迹。

原因:这是参考航向角和车辆航向角在角度归一化时处理不当导致的典型问题。当路径方向从179度变化到-179度时,数值上看起来变化了358度,但实际物理意义只差了2度。MPC的误差模型里epsi_ref没有做角度回绕处理,导致参考状态突然出现一个3弧度以上的虚假偏差,控制器疯狂打方向去追这个不存在的偏差。

解决:在计算epsi_ref时调用wrapToPi函数,把所有角度差值归一化到[-pi, pi]区间。在MATLAB Function里加这样的判断:

d_psi = ref_window(k,3) - psi; d_psi = atan2(sin(d_psi), cos(d_psi)); % 角度回绕处理 epsi_ref(k) = d_psi;

这样修改之后,角度跳变引起的控制尖峰会被彻底消除。需要注意的是,即使加了回绕处理,如果路径本身有很尖锐的发夹弯(曲率半径小于5米),线性MPC在这种位置还会因为模型线性化失准而表现不佳,此时要么增加控制时域和预测时域,要么在路径预处理时对曲率做平滑。

5.5 视频录制帧率与实际仿真时间对不上,录出来的动画忽快忽慢

现象:利用Carsim自带的Animator录制视频后,播放时发现车在弯道处加速,在直道上减速,与实际设定的车速曲线完全不符。

原因:Carsim Animator的视频录制帧率是固定的(通常为60fps或30fps),但联合仿真里Simulink的仿真速度不是实时的。当仿真在一个时间段内计算量特别大时,帧生成速度变慢,Carsim地图里记录的车辆位置间隔和真实时间对不上,录制出来的视频就会出现变速效果。更常见的情况是视频本身录制正常,但播放器用固定帧率播放,而Carsim生成的视频带的是可变时间戳,导入剪辑软件后时间轴错乱。

解决:不要在Carsim的Animator里直接录视频,改用Simulink的仿真数据来生成视频:把车辆位置数据以固定时间间隔导出,用MATLAB的VideoWriter以固定帧率合成视频,这样时间和帧的对应关系完全由数据控制。具体做法在下一章展开。

6. 用MATLAB生成仿真视频:数据驱动的视频合成方案与进阶验证

这个方案的思路是绕开Carsim的Animator录制功能,完全用Simulink仿真记录的数据在MATLAB里绘制每一帧画面,再合成为视频。优点是帧率和仿真时间严格对应,而且可以自由叠加数据曲线和控制量曲线,一帧画面里同时展示车辆轨迹和状态信息。

% 生成路径跟踪仿真视频 video_writer = VideoWriter('mpc_path_tracking.avi', 'Motion JPEG AVI'); video_writer.FrameRate = 20; % 20fps,与仿真数据步长对应 open(video_writer); figure('Position', [100, 100, 1200, 600]); for i = 1:length(t_out) % 左侧子图:俯视图轨迹 subplot(1, 2, 1); plot(x_ref, y_ref, 'b--', 'LineWidth', 1.5); hold on; plot(x_out(1:i), y_out(1:i), 'r-', 'LineWidth', 2); plot(x_out(i), y_out(i), 'ro', 'MarkerSize', 8, 'MarkerFaceColor', 'r'); % 画车辆朝向 quiver(x_out(i), y_out(i), 2*cos(psi_out(i)), 2*sin(psi_out(i)), 'r'); hold off; axis equal; grid on; legend('参考路径', '实际轨迹', '当前位置'); xlabel('X (m)'); ylabel('Y (m)'); title(sprintf('t = %.1f s', t_out(i))); % 右侧子图:横向偏差曲线 subplot(1, 2, 2); plot(t_out(1:i), ey_out(1:i), 'k-', 'LineWidth', 2); yline(0.2, 'r--'); yline(-0.2, 'r--'); ylim([-0.5, 0.5]); grid on; xlabel('时间 (s)'); ylabel('横向偏差 (m)'); title('横向偏差'); frame = getframe(gcf); writeVideo(video_writer, frame); end close(video_writer);

这段代码生成的视频是双栏布局,左边是车辆轨迹俯视图,右边是横向偏差实时曲线。t_out是仿真时间序列,x_out, y_out, psi_out, ey_out是从To Workspace记录的数据。FrameRate设置为20fps,对应50ms采样间隔,播放出来就是实时速度的仿真过程。

进阶验证方面,我常用的三个测试工况是:双移线工况(模拟紧急变道)、连续正弦工况(模拟长弯道道路)和带坡道的曲率变化工况。双移线工况用来检验MPC的瞬态响应,连续正弦工况用来检验稳态跟踪精度。每个工况跑完,记录最大横向偏差、平均横向偏差和控制量变化率的均值,形成一个性能对比表。如果最大横向偏差超过0.3米,通常需要调大 (Q_{ey});如果控制量变化率均值过大,说明 (S) 还不够。

做这套联合仿真的血泪经验是:MPC的参数不能一套打天下,车速一变、路径曲率一变,预测时域和前视距离就要跟着调整。我习惯先跑一组低速大曲率的工况把权重定下来,再做高速工况的针对性修改。仿真数据永远比感觉可靠——每次改完参数,先把横向偏差曲线打印出来贴在看板上,对比着调,而不是一次动三个参数。希望这份实战梳理能帮你把MPC路径跟踪联合仿真这块硬骨头啃下来。

本文还有配套的精品资源,点击获取

返回列表