
提到车队纵向控制很多做智能网联汽车仿真的同行第一反应就是搭个PID觉得能跟上车就行。我最早也是这么干的结果在真实工况里连续翻了两次车一次是前车急加速时跟车间距被拉得过大另一次是车队在中途突然切入一辆车导致后车速度振荡到让人头晕。后来我把控制器换成了滑模控制在Matlab里写算法、用CarSim出车辆模型做了联合仿真才把跟车误差和稳定性同时压住。这篇就完整记录一下我当时是如何从PID切换到滑模并在Matlab与CarSim里把整个纵向控制器跑通的。这篇文章适合正在做编队行驶、AEB、ACC相关课题的学生和工程师也适合想从PID类方法往鲁棒控制方向转的人。你会看到完整的滑模控制律推导、Simulink模块搭建方式、CarSim联合仿真的接口配置以及最让人头疼的抖振问题怎么一步步处理掉。1. 为什么车队纵向控制要换滑模——PID的两次“翻车”先说个背景。车队纵向控制的核心说白了就一句话让后车根据前车的状态调整自己的油门和刹车始终保持一个安全且合理的间距同时整个车队的车速要平稳不能出现“前后摆动”或者“越来越紧”的失稳现象。听起来简单但真做起来控制器要面对的车辆系统并不听话。1.1 车队跟车真正难在哪一个小型乘用车的纵向动力学可以用简化模型描述m·a F_drive - F_res其中F_res是滚动阻力、空气阻力、坡度阻力的总和。问题是m会随载重变化空气阻力系数和路面坡度也不固定发动机到车轮之间还有一阶惯性和传动延迟。真正写控制律时你倾面的是一个带有不确定性的非线性系统而不是教科书里那个干干净净的二阶积分器。我遇到的第一次“翻车”就是在一次载重变化测试中。同一辆车空载和满载之间质量能差出20%~30%PID参数在空载下调得很好满载后跟随响应迟滞前车一个中等强度的制动后车就把安全间距压到了接近零。还有一次是在坡道上。PID控制器把坡度带来的重力分力当作系统扰动比例项拼命加控制量去补偿结果车速出现明显的低频振荡车内乘客体感很不好。1.2 参数不确定性和外部干扰才是滑模的用武之地这个时候我意识到车队跟随问题真正的难点不是“跟踪一个参考速度”而是“在系统存在不可测扰动和参数偏移时仍能保持良好的跟踪性能”。这正好是滑模控制的强项。滑模控制的核心思想是设计一个滑模面并强行把系统状态“拉”到这个面上再让状态沿着这个面滑动到平衡点。因为滑模面一旦建立系统的动态行为就由滑模面方程决定而不是由原系统的精确模型决定。这带来一个非常实用的性质对匹配的不确定性具有不变性通俗讲就是只要扰动和参数偏差都在系统输入通道里控制器可以无视它们依然维持设计好的动态品质。这就是我决定切换方案的原因。PID是线性调节器面对非线性扰动时本质上是“被动补偿”滑模则是“主动切换”用不连续控制项把不确定性直接拍下去。当然它也有代价比如抖振但那个我们可以用工程手段缓解后面细说。2. 滑模面与趋近律先把控制律推明白再写代码做控制最忌讳模型没理清就上手调参。我建议先把滑模控制律在纸面上完整推一遍再进Simulink搭模块。这里的推导用到的是车队纵向控制的经典框架你也可以直接拿去做编队扩展。2.1 车距策略选型固定车距还是恒定车头时距车距策略决定了误差定义必须最先定下来。固定车间距策略要求相邻两车始终保持一个常数距离稳态很简单但车速越高这种策略对通信时延和制动能力越敏感稍有不慎就会追尾。恒定车头时距策略则把期望车距设置为d_des h·v_i d0其中h是车头时距秒d0是最小静止间距米。车速越快期望间距越大这更符合真实驾驶习惯。我的项目里选的是CTH策略参数取h0.5sd04m。这个策略的另一个好处是能推导出便于滑模设计的线性误差方程。2.2 滑模面设计误差不仅要小还得平滑收敛对第i辆车定义它与前车的实际间距误差e_i x_{i-1} - x_i - d_des其中x是纵向位置。一次求导得到e_dot_i v_{i-1} - v_i - h·a_i这里用了CTH策略的导数关系注意a_i是后车加速度是从CarSim里读出来的信号。我的滑模面取为s_i e_dot_i λ·e_iλ是滑模面系数。这个面设计成“误差的导数加上误差的比例”物理意义是让间距误差和间距误差变化率同时趋于零。λ越大收敛越快但放进实际系统里会放大高频噪声所以后面整定时要从0.2左右开始慢慢试。2.3 趋近律选取与控制增益的底线有了滑模面下一步是让s_i在有限时间内到达并保持在零。这里我用指数趋近律s_dot_i -ε·sgn(s_i) - k·s_iε决定到达滑模面的速度k决定沿滑模面趋近的速度。把s_i并入车辆动力学模型求解控制输入时会得到一个类似这样的控制律u_i a_{i-1} λ·(v_{i-1} - v_i - h·a_i) k·s_i ε·sgn(s_i)其中u_i是期望加速度作为下层执行器的目标值。工程上还会加一个输出限幅比如把u_i限制在[-3, 2] m/s²之间避免大油门大刹车导致执行器饱和。这里有一个非常关键的选型逻辑ε不能拍脑袋定。从趋近律条件s·s_dot 0出发ε必须大于系统不确定性的上界。换句话说坡度造成的重力扰动、风阻变化、质量偏移折算到加速度量纲后是多少ε就要比这个大一点留出余量。实测下来整车质量变化20%对应的加速度扰动上界大概在0.5~0.8 m/s²左右我一开始ε取1.0效果不错。3. Simulink里的控制器实现离散化与抗噪处理数学推导完成之后接下来就是把控制律变成能跑的模型。我不建议用纯Simulink积木方式搭控制律因为滑模里面有符号函数、限幅、条件判断用MATLAB Function写更清晰剖面也更贴近以后做嵌入式移植的方式。3.1 控制器模块结构与输入信号组织控制器子系统的输入我预留了五个信号前车位置、前车速度、前车加速度、本车位置、本车速度。CarSim输出的本车加速度也可以直接引来但注意先做滤波因为CarSim输出的加速度噪声在联合仿真里是不均匀的。模型结构建议这样组织最外层是CarSim的车辆模型接口车辆模型输出运动学信号进入控制器子系统控制器经算法计算后输出期望加速度再经过一个驱动/制动逆模型模块转换成驱动力矩和制动力矩送回CarSim。驱动/制动逆模型是容易被忽略的一环。CarSim需要的输入是各轮的驱动力矩和制动压力而控制器输出的是加速度。两者之间需要一个转换关系简单做法是用稳态映射驱动力矩 期望加速度 × 等效质量 × 车轮半径再除以传动效率。虽然粗糙但在纵向控制仿真里足够用。3.2 MATLAB Function里的核心代码与限幅下面这段代码是我在Simulink的MATLAB Function里实际用的简化版本你可以直接参考function a_des smc_ctrl(x_prev, v_prev, a_prev, x_i, v_i, a_i, p) h p.h; d0 p.d0; lambda p.lambda; eps p.eps; k p.k; phi p.phi; d_des h * v_i d0; e1 x_prev - x_i - d_des; e2 v_prev - v_i - h * a_i; s e2 lambda * e1; % 饱和函数替代符号函数防抖振 sat_s min(max(s / phi, -1), 1); a_des a_prev lambda * e2 k * s eps * sat_s; % 执行器限幅 a_lim 3.0; a_des max(-a_lim, min(a_des, a_lim)); end注意我在最终版本里用饱和函数sat(s/φ)替代了符号函数sgn(s)这是为了后面的抖振问题预留的处理手段。参数p通过Simulink的Parameter结构传入我习惯把整定参数集中放在模型工作空间里不用每次改代码。3.3 离散化坑点采样时间与数值微分滑模控制本质上是连续时间设计但仿真和执行都是离散的。采样时间如果太大滑模的“切换”会变成严重的高频跳跃误差会比预期大得多。我的经验是纵向控制回路采样时间至少设到10ms最好5ms。CarSim的求解步长和Simulink的模型步长要保持一致或者倍数关系否则数据传递时会有虚假的高频成分。还有数值微分问题。滑模面里需要用到e的导数我一开始直接对位置信号做差分结果高频噪声被放大了好几倍控制量抖得像锯齿。后来我改用从CarSim直接输出速度信号来计算e2只有v和a是直接测量量完全避开了差分求导。能直接测的量千万不要自己算这是联合仿真的基本教训。4. CarSim与Simulink联合仿真接口配置和车辆模型准备CarSim是个老牌的车辆动力学软件它内部已经有了非常细致的底盘、轮胎、悬架模型你的控制器只负责“发号施令”车辆怎么响应交给CarSim去算。联合仿真就是把CarSim当成被控对象把Simulink当成控制器两边通过接口总线通信。4.1 先把车辆模型和驾驶场景设置好进入CarSim之前我用的是它的内置B级车模型改了一下整车质量和质心位置模拟满载工况。道路场景我选用平直双向两车道并在中间段设置了一个坡度段和一个低附着系数段用来测试控制器在真实路况下的鲁棒性。CarSim的驾驶脚本里我给前车设置了完整的速度曲线先匀速再以1.5 m/s²加速度加速到80km/h稳定行驶后做一次急减速到40km/h最后再加速。这组工况涵盖了正常跟车、急加速、急刹车三种情况基本能把控制器的优缺点暴露干净。4.2 输入输出通道的正确接法联合仿真接口的配置是最容易把人卡住的地方。以CarSim 2019之后的版本为例在CarSim主界面选Simulink接口后你会看到一个通道配置面板里面分Import和Export两组。Export组是CarSim输出给Simulink的量我选择了车辆纵向位置X、纵向速度Vx、纵向加速度Ax、横摆角速度备用。Import组是Simulink输出给CarSim的量我选择了左侧驱动轮和右侧驱动轮的驱动力矩以及四个车轮的制动压力。注意CarSim的力矩单位是N·m制动压力单位是MPa转换错一个数量级整车就乱跳。接好线之后在Simulink里会自动生成一个CarSim主模块模块上方是ImportChannels下方是ExportChannels。必须把总线命名和CarSim里的变量名一一对应少一个都不行。我建议把两组信号拉成总线对象方便后续扩展。4.3 联合仿真易错点与检查顺序我整理了三条最容易踩的坑。第一仿真开始前要在CarSim里点一次“Send to Simulink”把车辆参数和模型文件输出到当前工作目录。如果提示找不到模型文件原因是路径里有中文或空格CarSim有时候不认把工程放到纯英文路径下就解决了。第二Simulink求解器类型设成定步长这也是必须的。CarSim的底层模型是变步长的但联合仿真接口按定步长交换数据比较稳定我设的是固定步长1ms仿真速度可以接受。第三不要同时从CarSim和MATLAB内存里读取车辆状态。有一次我为了省事在MATLAB Function里写了一个全局变量用来缓存位置结果CarSim输出的位置和内存缓存不一致两个信号打架跟车误差一度摇摆不定。后来统一以CarSim输出通道为唯一数据源问题立刻消失。5. 抖振处理从sign到sat再到参数试出来的经验滑模控制最出名的问题就是抖振。理论上符号函数在高频切换能维持理想的滑动模态但真实系统里执行器有延迟、传感器有噪声、模型是离散的符号函数的切换频率会被推到极限导致控制输出持续震颤。这次联合仿真里我用的是tanh和饱和函数相结合的方式效果可以量化对比。5.1 抖振的根因和它为什么在离散系统里更严重抖振的根源在于控制律里的不连续项。当状态一旦跨过滑模面符号函数立刻翻转控制量方向理论上这发生在无穷小的时间内。但实际系统里采样间隔限制了状态检测频率执行器延迟削弱了翻转后的响应结果状态不会精确停在滑模面上而是在面附近来回穿越形成自持振荡。离散化之后情况更糟。连续系统里抖振频率理论上可以无限高幅度由趋近律参数决定离散系统里每个采样周期才做一次决策等价的“开关频率”就是采样频率的一半。如果采样步长10ms抖振频率最高50Hz这个频率落在车辆纵向悬挂的敏感区间里乘客体感会非常不舒服。5.2 边界层法效果立竿见影但要会取舍解决方案是在滑模面附近设定一个边界层用饱和函数代替符号函数sgn(s) → sat(s/φ)当|s|≤φ时输出s/φ当|s|φ时输出sgn(s)通俗讲就是在滑模面附近把“开关”换成了“比例调节”。好处是控制量连续了抖振明显缓解代价是滑模的鲁棒性会打折扣因为边界层内的控制等效成了一个高增益线性控制器对外部扰动的抑制能力不如纯不连续项强。φ的大小就是一个典型的取舍问题。φ太小抖振压不住φ太大边界层变成厚厚一条“软带”系统误差会变大。我第一次试φ0.1控制量振幅降到原来一半但误差偏大后来调到φ1.5抖振基本消失误差也还在可接受范围内。5.3 一组实测对比数据与取舍逻辑我在CarSim里用同一工况对比了几组参数记录了一下稳定跟车段的平均车距误差和控制量变化率给你做个参考控制形式边界层厚度φ平均车距误差(m)控制量标准差(m/s²)体感评价纯符号函数sgn无0.120.86明显抖振加速度冲击频繁饱和函数sat0.50.150.41轻微抖振可接受饱和函数sat1.50.210.28平滑误差略增大饱和函数sat4.00.350.17平滑但稳态误差偏大从表里能看出纯符号函数误差最小但控制量质量最差φ从0.5到1.5之间是比较好的折中。我最后选的φ1.2另外还加了一个低通滤波把控制量做了截止频率20Hz的平滑。这一步之后CarSim输出的车辆加速度曲线已经非常干净了。6. 参数整定顺序与结果分析从能跑到跑好的过程滑模控制器参数不多但耦合性强。调稳到调好我花了大半天时间。这里分享一下我的整定顺序和一个完整工况下的数据结论。6.1 整定的顺序和判断指标我的整定顺序是先定车距策略参数h和d0再定滑模面系数λ接着定趋近律增益k和ε最后处理边界层厚度φ和滤波截止频率。这个顺序的逻辑是先保证误差定义合理再保证收敛性然后保证鲁棒性最后改善控制品质。判断指标我主要看三个一是在前车急加速和急减速时车距误差是否超限二是速度收敛过程是否有超调和振荡三是控制加速度曲线是否有高频分量也就是抖振。还有一个容易被忽略的指标是加速度的一阶导数jerk它直接关系乘坐舒适性。滑模控制因为切换特性jerk会比PID大我会把jerk限制在2.5 m/s³以内超过就适当增大φ。6.2 一组仿真结果与故障排查最终确定的参数是h0.5sd04mλ0.4k0.8ε1.0φ1.2。工况就是前面说的“匀速—加速—急减速—再加速”标准循环车队一共6辆车我重点观察第5辆车的跟随表现因为队列越靠后误差累积越明显。实测下来稳定跟车段的车距误差控制在0.15m以内急加速段的误差峰值不超过0.3m急减速段的误差峰值大概是0.25m全程没有出现速度振荡或车距收敛的迹象。而在同样的工况下之前PID控制器的误差峰值接近0.8m并且减速完成后有一次明显的回摆。调试中印象最深的一次问题是控制器在中途坡度路段出现了一小段误差增大我一度以为是ε取小了把ε从1.0加到1.5结果误差改善不明显控制量反而开始抖。后来检查发现是CarSim的坡度输出信号在联合仿真接口里出现了短暂跳变滤波器没覆盖到。我在坡度信号入口加了一个一阶惯性滤波问题立刻消失。这件事之后我学乖了仿真里异常先怀疑信号入口不要一上来就怀疑控制参数。6.3 让鲁棒性检验更真实的几个建议仿真跑通之后我建议你做几组额外的压力测试而不是只看标准工况。第一把车辆质量按50%载荷增加到满载观察ε是否需要增大第二把前车的急减速强度提高到接近刹车极限观察车距误差是否会突破安全阈值第三在有坡道的路面测试控制器的力矩补偿是否及时。这些测试我都做过最终ε从1.0调到了1.2λ从0.4降到了0.35原因是在满载和坡度叠加时0.4的λ会让车距误差收敛过快刹车稍微急一点就触发执行器饱和。另外简单提一个关于CarSim道路模型的细节CarSim默认输出给Simulink的是车辆在大地坐标系下的位置和速度如果你的控制器使用跟车距离误差要注意两车的位置必须在同一坐标系下最好都选择大地坐标的绝对位置再在控制器里做差。如果有人用传感器相对距离信号自定义变量导出坐标基准不一致会导致跟车距离计算完全错误我一开始就在这个问题上多花了两个小时排查。最后分享一个我后来一直在用的经验滑模控制器的参数整定过程一定要留一份“标准工况录波”的模板数据。每次改参数前先跑一遍标准工况保存车距误差曲线和控制量曲线的截图改完再跑一遍对比两张图。参数试过几十组之后你会形成一种直觉知道哪里该动λ、哪里该动ε。这种手感比任何理论分析都值钱。如果你接下来打算把车队规模从6辆扩展到12辆或者更多滑模控制器本身不需要大改但要关注通信拓扑和时延。带有时延的队列滑模面里最好引入前车加速度前馈和通信时延补偿否则队列尾部会出现明显的“鞭梢效应”。这个扩展我当时也做了后面有机会整理成另一篇再聊。