☰
Carsim与Simulink联合仿真实现弯道变道MPC轨迹跟踪控制
2026/10/16 9:36:03 网站建设 项目流程

我一直觉得,弯道变道是智能车辆轨迹跟踪控制里最有代表性的工况。直线变道时,横向和纵向基本解耦,控制器调好一组PID就能跑得像模像样;但到了弯道上,曲率本身在变化,侧向加速度又和车速耦合在一起,之前那套参数基本就直接“原形毕露”。之前做某自动驾驶仿真验证项目时,我第一版Carsim与Simulink联合仿真模型在直线段一切正常,一进弯道前轮转角就开始高频小幅抖动,车辆慢慢朝弯道外侧滑出去,方向盘完全失去对轨迹的掌控。来回折腾了两三天,最后发现根因不在MPC的权重矩阵,而在参考路径里的航向角序列。

这篇文章就把Carsim与Simulink联合仿真实现弯道变道的完整链路拆开聊一聊:从仿真环境怎么搭、I/O接口怎么配,到弯道变道参考路径怎么生成、MPC轨迹跟踪控制器怎么设计,再到联合仿真调试时那些文档里不会写的坑。适合正在做自动驾驶控制仿真验证、或者在搞智能车辆轨迹跟踪课题的工程师和学生参考,思路可以直接照搬。

1. 为什么要用Carsim和Simulink做弯道变道仿真

1.1 弯道变道这个工况,为什么值得单独拿出来说

弯道变道和直道变道最大的区别在于:车辆状态方程里多了一个随时间变化的道路曲率项,而且这个曲率直接影响侧向加速度需求。直道上换道,横向位移跟着一个平滑多项式走就行,纵向速度基本可以用恒定值;弯道上换道,车辆本身就有一个朝向弯道内侧的横摆角速度,换道轨迹需要在这个基础横摆运动之上再叠加一次横向偏移,跟踪控制器必须同时处理好“跟随弯道”和“完成变道”两个任务。

从动力学角度看,弯道变道要求侧向加速度限制不能超出轮胎附着能力,车速越高、弯道半径越小,这个限制就越紧。仿真相比实车场地测试的优势非常明显:同一套控制器可以批量扫不同半径、不同车速、不同换道长度的工况,而且可以安全地试错。实测中如果在某组参数下车辆失控,后果可能是车损甚至是安全问题,但在仿真里最多是波形发散、数据异常,重跑一次就恢复,这是弯道变道控制研发放在仿真阶段进行的重要原因。

1.2 Carsim和Simulink在整个仿真链路里各自扮演什么角色

Carsim负责车辆动力学求解部分——包含悬架、轮胎、转向系统、制动系统、空气阻力等子模型,输出车辆在空间中的位置、速度、横摆角、横摆角速度、质心侧偏角等状态。Simulink则部署路径规划、速度规划、MPC控制器或者PID控制器等算法逻辑。两者的数据交互通过Carsim生成的S-Function完成,每个仿真步长内Simulink调用一次Carsim求解器,读取车辆状态并写回转向角、油门、制动等控制量。

这种分工非常自然:车辆动力学如果自己建模,模型标定非常浪费时间,而Carsim是成熟软件,改个参数、换辆车只需要在界面上操作;控制算法则需要频繁调整甚至换结构,放在Simulink里修改起来更方便。我之前也对比过几个平台,简单列一下:

工具动力学精度与Simulink接口便利性开放程度最适合场景
Carsim高,百万级参数覆盖多种车型高,直接生成S-Function较高,车辆参数开放控制算法验证、硬件在环、整车级工况仿真
CarMaker较高,场景管理强中等,需要中间层脚本中等测试场景批量化、ADAS功能验证
PreScan偏向传感器与场景中等中低感知算法验证、V2X场景
ADAMS极高,多体动力学低,配置复杂高底盘悬架精细化分析,不适合控制快速迭代

控制算法验证这个环节,Carsim和Simulink组合在实用性和便利性之间平衡得最好,这也是它成为行业里做轨迹跟踪联合仿真首选方案的原因。

2. 联合仿真环境搭建:接口配置中最容易卡住的几个环节

2.1 版本兼容性和安装细节,先说最容易踩的坑

Carsim各版本与MATLAB/Simulink版本之间有明确的兼容关系,如果版本差异过大,生成S-Function之后在Simulink里会报编译错误,而且报错信息通常很隐晦。建议在项目开始前就确定好版本组合,并且整套环境只用这一组版本,避免多人协作时工程文件互相不兼容。

安装层面有几个细节容易被忽略:

  • 安装路径绝对不能包含中文和空格,否则编译生成的VS工程文件路径不正确,S-Function加载会失败;
  • Carsim生成的S-Function依赖C编译器,需要先确保MATLAB里能正常执行mex -setup,否则联合仿真模型无法编译;
  • 打开Carsim模型时,注意选择与Simulink联合仿真对应的模式,而不是完全独立的Carsim试算模式,否则模型类型不对,无法生成正确的DLL。

提示:如果第一次运行联合仿真时Simulink报“Cannot find S-Function”或者加载dll失败,不要急着查Simulink模型里的问题,先回到Carsim工程里确认是否点过“Build/Generate”生成对应的动态库,再排查MATLAB工作区变量是否正确加载。

2.2 Carsim模型生成Simulink模型的操作流程

Carsim主界面中配置好车辆模型参数后,进入Simulink联合仿真配置页面,这里需要做三件事:配置输入通道、配置输出通道、生成模型。输入通道是Simulink写给Carsim的控制量,输出通道是Carsim反馈给Simulink的车辆状态。常见的通道配置我列成表:

类型通道名含义与单位
输入IMP_STEER_L1前轮转向角,通常用rad
输入IMP_THROTTLE_ENGINE_0节气门开度或驱动扭矩
输入IMP_BRAKE_MASTER_CYLINDER主缸制动压力
输入IMP_VX可选的外部纵向速度输入
输出Vx纵向车速,m/s
输出Vy侧向车速,m/s
输出YawRate横摆角速度,rad/s
输出Yaw横摆角,rad
输出Xo, Zo, Yo惯性系坐标,m
输出Beta质心侧偏角,rad
输出Steer_L1当前前轮转角反馈,rad

通道配置好之后,点击“Send to Simulink”或者“Create Simulink Model”,Carsim会调用MATLAB生成或更新主模型文件,同时运行一个初始化脚本,把车辆参数写入MATLAB工作区。之后在Simulink中打开主模型,你会看到模型里有一个S-Function模块,里面是Carsim的接口封装,输入输出端口和刚才配置的通道一一对应。

初次拿到这个模型,我建议先不改动任何逻辑,直接双击S-Function模块,确认它的参数中包含车辆型号信息和初始化脚本路径。若路径错误或者脚本没运行,后面所有信号都会是空的。

2.3 仿真步长、信号记录和联调前的基本自检

联合仿真建议在Simulink求解器设置里选固定步长,常见做法是0.001s,控制周期的逻辑可以放在独立的子系统里用0.02s或0.05s的采样时间,通过Rate Transition模块连接。为什么强调固定步长?因为变步长求解器会在响应剧烈时自动缩小步长,但Carsim的S-Function通道在每个主步长内只同步一次,结果就是控制指令写入的时间点错乱,控制器性能会被莫名其妙的时序问题拖垮。

信号记录方面,用To Workspace模块把Vx、Vy、Yaw、Xo、Yo以及控制器的输出保存下来,变量命名建议带上前缀,例如veh.Vx、ref.X,这样在MATLAB工作区里不用纠结变量来源。数据记录至关重要,后期调参全靠这批数据复盘。

还有一个小技巧:接入正经控制器之前,先在Simulink里用常数输入模块给前轮转角一个固定值,比如0.02rad,跑1秒钟,看Carsim车辆有没有产生合理的横摆角速度响应。如果这步都不正常,说明接口通道方向或者单位有问题,此时去查MPC参数毫无意义。

3. 弯道变道参考路径生成:五次多项式与速度规划的配合

3.1 弯道场景定义与基础中心线

先定义一个可复现的场景:弯道半径取R=120m,车道宽度取3.5m,车辆初始在右侧车道中心线行驶,目标换入左侧车道中心线。弯道中心线可以用圆弧近似,曲率κ_ref=1/R,换道起点车辆航向角与弯道切向角一致。

为什么可以用圆弧近似而不需要做回旋线?因为验证控制算法时,道路曲率在换道段内基本保持不变,用圆弧做参考可以让控制器集中应对“变道轨迹叠加”这个核心难度。如果以后要测更真实的公路几何,再把中心线替换成回旋线,控制器部分不需要大改,变道叠加的逻辑是通用的。

3.2 用五次多项式生成横向偏移曲线

换道段的横向偏移d(s)是沿道路纵向距离s的函数。换道开始时偏移量为0,末端偏移量为3.5m;同时为了保证轨迹连续且曲率连续,两端的一阶导数和二阶导数也需要为0。一个三次多项式只能约束位置和斜率,端点上曲率会突变,车辆跟踪时转向角会出现跳变;解决这个问题的经典做法是用五次多项式。

归一化后的五次多项式只需一行公式,在工程里非常实用:

d(s) = d_final * [10 * (s / S)^3 - 15 * (s / S)^4 + 6 * (s / S)^5]

其中d_final是最终横向偏移距离,S是换道纵向长度。这个式子的好处是两端二阶导均为0,曲率连续,生成的轨迹让MPC控制器的工作难度显著降低。S的取值和车速强相关,低速小S,高速大S;工程上可以先按S = 0.6*v取,再根据实际仿真中的侧向加速度峰值调整。

MATLAB生成参考轨迹的代码可以这样写:

R = 120; % 弯道半径 v = 16.67; % 期望纵向车速 60km/h d_final = 3.5; % 换道横向偏移 S = 0.6 * v; % 换道纵向距离 s_vec = 0:0.1:2*pi*R/4; % 整个弯道行程 % 换道段的横向偏移曲线 s_lane = s_vec(s_vec <= S); d = d_final * (10*(s_lane/S).^3 - 15*(s_lane/S).^4 + 6*(s_lane/S).^5); % 弯道中心线坐标 theta = s_vec / R; xc = R * sin(theta); yc = R * (1 - cos(theta)); % 叠加换道偏移:法向方向是 (-sin(theta), cos(theta)) nlane = zeros(1, length(s_lane)); for i = 1:length(s_lane) t = s_lane(i) / R; nlane(i) = d(i); % 在弯道坐标系下,直接沿法向加偏移 end x_ref = xc(1:length(s_lane)) - nlane .* sin(s_lane/R); y_ref = yc(1:length(s_lane)) + nlane .* cos(s_lane/R);

严格来说,弯道上的偏移叠加需要考虑几何失真,但在R≥80m的场景下,这种近似带来的位置误差远小于控制器跟踪误差,工程上可以直接用。生成后务必画出参考轨迹,肉眼检查曲线是否平滑。

3.3 速度规划:弯道上不能全程匀速

弯道变道过程中车速不能一直恒定,因为弯道本身需要向心加速度。如果侧向加速度限制为3m/s²,那么弯道半径120m对应的最大车速约为 sqrt(3 * 120) ≈ 18.97m/s,约68km/h。设计期望速度时,要先按整条参考轨迹的最大曲率计算允许车速,再在换道前后做梯形或者S形过渡。

速度规划最简单的实现方式:把整个轨迹按曲率分段,每段给一个限制速度,然后用平滑插值连接。参考代码片段如下:

kappa_ref = 1 / R; ay_lim = 3.0; % 侧向加速度限值 v_max_curve = sqrt(ay_lim / kappa_ref); v_target = min(v, v_max_curve); % 简单梯形速度曲线 t_total = S / v_target + 2.0; t = 0:0.01:t_total; v_profile = min(v_target, v * ones(size(t))); % 实际项目中可进一步加加速度限制,生成S形过渡

有一点必须强调:参考轨迹的航向角序列不能只包含五次多项式的一阶导数,还必须叠加上弯道本身的切线角。也就是说,期望航向角psi_ref = atan2(dy_center, dx_center) + atan(d'(s))的近似。很多初学者生成参考轨迹时,换道终点航向角直接填0,车辆在弯道末端必定跑偏,这个问题我在调试时遇到不止一次。

4. 轨迹跟踪控制器设计:MPC横向控制与速度调节的配合

4.1 为什么选MPC,而不是纯跟踪或者PID

弯道变道控制里,纯跟踪算法的问题在于预瞄距离难调:预瞄太短,车辆振荡;预瞄太长,过弯时走线太靠内。PID横向控制则很难权衡超调量和稳态误差,而且很难显式处理转向角限位约束。MPC的价值在于把“未来一段轨迹的信息”和“当前状态偏差”统一放进一个优化问题里,同时能硬约束转向角范围和控制增量范围。弯道变道这个场景,曲率变化和横向偏差耦合明显,MPC的预测能力对抑制过弯时的超调非常关键。

4.2 简化车辆模型与离散化

工程上先用运动学自行车模型就足够把控制器逻辑调通,模型如下:

状态定义为横向偏差e_y、横向偏差变化率e_y_dot、航向偏差e_psi、航向偏差变化率e_psi_dot。连续状态方程可以写成:

e_y_dot = v_x * e_psi e_psi_dot = v_x / L * tan(delta) - v_x * kappa_ref

其中L是轴距,delta是前轮转角,kappa_ref是参考曲率。把状态空间离散化,采样时间取0.05s,得到离散状态方程x(k+1) = A_d * x(k) + B_d * u(k),控制量u建议选前轮转角变化率而不是转角本身,这样可以在优化里同时惩罚转角幅值和转角变化率,防止控制量剧烈抖动。

4.3 MPC代价函数、约束与初始参数

MPC每一帧求解一个有限时域优化问题,代价函数写成:

J = sum(k=1..Np) x(k)^T Q x(k) + sum(k=1..Nc) u(k)^T R u(k)

其中Q是对角矩阵,对应四个状态分量的惩罚权重;R是控制增量的惩罚权重。约束条件包括:|delta| <= δ_max,|Δdelta| <= Δδ_max,|e_y| <= 1.5m。

初始参数我建议这样设:

参数初始值说明
采样时间 dt0.05s与Carsim主步长解耦,控制器单独周期
预测时域 Np20约1秒预测长度,弯道场景足够
控制时域 Nc8控制自由度太多会导致求解慢且动作碎
Q_ey30横向偏差权重,偏大则跟踪更紧
Q_edot10横向偏差变化率权重
Q_epsi20航向偏差权重
Q_edotpsi5航向偏差变化率权重
R10控制增量权重,偏大则动作更平缓

调参顺序建议:先固定Q矩阵,从R=100开始往下减,直到转向角不再抖动;如果横向误差峰值偏大,再逐步增大Q_ey。不要一开始就把所有权重都调到很大,那样控制器会像神经质一样疯狂输出,仿真一定发散。

4.4 Simulink中的MPC实现骨架

在Simulink里实现MPC可以走两条路:用MPC Toolbox提供的模块,或者手写一个MATLAB Function做QP求解。Toolbox方便但不够灵活,手写框架则方便后面接入不同的求解器。下面是简化版MPC控制器的函数骨架,核心逻辑是每一帧构造QP问题后调用quadprog求解:

function u_out = mpc_controller(x_ref, y_ref, psi_ref, vx, state, params) % 简化的弯道变道MPC控制器 % 输入:参考轨迹、当前车速、当前状态、控制器参数 % 输出:前轮转角 delta Np = params.Np; dt = params.dt; L = params.L; R_q = params.R; Q = params.Q; % 计算参考曲率(由本次采样点估计) kappa_ref = curvatrue_from_trajectory(x_ref, y_ref); % 构造离散状态空间矩阵 A_d, B_d(简化运动学模型) [A_d, B_d] = vehicle_model_discrete(vx, L, kappa_ref, dt); % 构造QP问题: min 0.5*z'*H*z + f'*z % z = [u0, u1, ..., u_{Nc-1}] [H, f] = build_qp_matrix(Q, R_q, A_d, B_d, Np, Nc, state); % 线性不等式约束:转向角限位、控制增量限位 [Aineq, bineq] = build_qp_constraints(params.delta_max, params.ddelta_max, L, Nc); % 求解 z = quadprog(H, f, Aineq, bineq, [], [], [], [], [], optimoptions('quadprog','Display','off')); % 取第一个控制增量,累加到当前转向角 u_out = state.delta + z(1); end

具体实现中还有很多细节,比如参考曲率要从最近参考点处计算、当前偏差点要从惯性系坐标投影到参考轨迹坐标系里、预测时域内曲率要按对应参考点更新而不是一直用当前点。这些地方是决定MPC实际表现的关键,用Toolbox模块时可以少操心一部分,手写时则要逐一确认。

速度控制与MPC配合,通常做法是在Simulink里用一个简单PID把期望速度转成油门/制动指令,输出给Carsim的油门和制动通道。建议把速度PID和MPC横向控制放在同一个子系统内,共用同一个采样步长,避免时间不同步产生额外问题。

5. 联合仿真调试实录:从发散到收敛的参数整定过程

5.1 第一次跑不通时的完整排查链路

我在实际项目中遇到过最典型的失败过程:参考轨迹看着平滑,MPC权重也调过很多轮,但一接上Carsim就横向误差越来越大,最后车辆冲出道路。排查链路值得记录一下,给后来者参考。

第一步先排除接口问题。在Simulink里给前轮转角一个很小的正弦激励,比如0.01rad、0.5Hz,观察Carsim输出的横摆角速度是否同频响应,如果响应方向反了或者没有响应,检查前轮转角输入通道的极性和单位。第二步检查参考轨迹生成脚本,把参考航向角ps_ref和实测航向角画在同一张图里,如果有固定偏差,大概率是航向角叠加逻辑写错了。第三步检查MPC求解结果,把每一步的期望转向角和实际输出转向角打印出来,如果两者差值一直很大,说明约束条件或者控制增量累加方式有问题。

这个流程走完,基本能把“接口问题”“参考轨迹问题”“控制器实现问题”三大类原因分开。直接改权重矩阵调试,很容易绕进死胡同。

5.2 常见故障现象与解决方法汇总

现象可能的根因处理方向
进入弯道后横向误差持续增大,方向盘小幅高频抖动参考航向角未叠加弯道切线角;R权重太小修正参考航向角生成逻辑;增大R,降低控制增量灵敏度
仿真开始车辆立刻冲出去,纵向速度瞬间飙到数百km/h油门或制动通道极性反了;初始速度状态与Carsim不一致检查IMP_THROTTLE和IMP_BRAKE极性;确认车辆初始纵向速度设置
车辆对转向指令完全没有反应IMP_STEER_L1单位错误,比如给了rad但Carsim按deg解释检查单位转换系数,统一使用弧度
跟踪效果还行但变道完成后车速过低速度规划中曲率限速过于保守;ay_lim设置太小适当提高侧向加速度限值,或改为变道末端平滑恢复目标车速
仿真卡顿导致波形不连续固定步长设置过大或控制器步长和主步长比率不合理主步长降到0.001s,控制器周期维持在0.02~0.05s之间

5.3 数据后处理:用什么指标判断调参是否到位

我习惯用三张曲线图判断联合仿真的质量:第一张是XY平面内参考轨迹与实车轨迹的叠加图,直观看整体贴合程度;第二张是横向误差随时间的变化曲线,重点看峰值的出现位置和稳态收敛时间;第三张是前轮转角时间曲线,观察是否出现明显的高频抖振。

工程上可以给自己定几个可量化的验收值:横向误差峰值不超过0.15m,变道完成后稳态误差不超过0.05m,前轮转角曲线没有持续的高频小幅振荡,侧向加速度峰值不超过3m/s²。达到这些指标之后,基本可以认为这一组参数在仿真工况内是有效的。此时再把参数表记录下来,后续扫不同半径和车速工况时,只需要按固定规律微调Q和R,不用从头开始试。

绘图脚本很简单,核心逻辑是从workspace拿数据画图:

figure; plot(ref_x, ref_y, 'b--', 'LineWidth', 1.5); hold on; plot(veh.Xo, veh.Yo, 'r-', 'LineWidth', 1.2); legend('参考轨迹', '实车轨迹'); xlabel('X/m'); ylabel('Y/m'); grid on; figure; plot(t_out, ey_array, 'k-'); xlabel('t/s'); ylabel('横向误差/m'); grid on;

写在最后的经验

这个项目折腾下来,我最大的感触是:弯道变道联合仿真最花时间的往往不是控制器算法本身,而是参考轨迹的正确性和接口信号的一致性。控制器权重可以靠调试经验快速收敛,但一个没叠加弯道切线角的参考路径会让人怀疑整个MPC框架,最终发现是上游数据的问题,非常浪费时间。建议所有做联合仿真的朋友,第一步先画参考轨迹的图像检查,第二步做开环激励验证接口,第三步再接控制器闭环。顺序不要反,反过来就是没日没夜地加班。

另外一个小技巧:排查问题前先在纯Simulink里用简化车辆模型闭环跑一遍控制器,确认控制逻辑本身没问题,再切到Carsim联合仿真。这样几乎能把控制器实现问题全部提前消除。最后,无论用什么算法,先统一坐标系定义和角度单位,能帮你避开一半的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询