
先说点实在的。ACC和CACC这套东西名字看着高大上说白了就是让车自己跟着前车走、跟着车队走的控制问题。ACC叫自适应巡航控制现在十几万的家用车已经标配了CACC叫协同自适应巡航控制多了一个车与车之间通信的能力属于自动驾驶和车路协同领域的核心研究方向。用MATLAB和Simulink来建这套系统是我认为目前最适合入门的路径没有之一。原因很简单你要验证控制算法好坏最怕的就是在实车上反复试错而Simulink可以在几分钟内搭出一条完整车队让算法在仿真里先跑几百上千公里把逻辑漏洞、参数毛病全暴露出来再上实车就从容得多。这篇内容写给三类人正在做车辆工程、控制工程相关课题的学生做ADAS功能开发的工程师以及想搞懂ACC/CACC原理、打算自己动手复现一个仿真模型的爱好者。看完你能得到一套可以直接搭建的模型框架知道每一步为什么这么做也会清楚我自己实测时踩过的坑。1. 项目框架与核心思路1.1 ACC和CACC的本质区别ACC的核心逻辑是“感知-决策-执行”这条闭环毫米波雷达或摄像头测出前车的距离和相对速度控制器算出一个合理的期望加速度然后发动机或制动系统去执行这个加速度。整个过程只有本车与前车的互动车上不依赖任何外部信息。CACC则在这个基础上引入了V2V通信也就是车与车之间的数据交换。前车不仅把自己当前的加速度、速度告诉后车有的拓扑结构里还会把前前车的信息也一并传过来。后车不再是被动地“看着前车动我才动”而是提前知道前车要刹车了、要加速了提前做出反应。这个区别带来的核心指标是弦稳定性英文叫String Stability。什么意思想象一条车队头车轻轻点了下刹车如果控制不好越往后的车反应越大像波浪一样被放大最后面的车可能直接急刹甚至追尾。ACC因为信息滞后一个车距理论上很难保证整个车队的弦稳定性CACC因为有了通信前车的加速度信息可以直接传给后车车队就能像火车车厢一样整体联动波动在传递中逐渐衰减而不是放大。所以我做这个项目的核心思路就是先搭一个完整的ACC单车主模型验证它自己能稳定跟车然后在这个基础上加入通信链路改造成CACC多车队列做对比分析。这个从简到繁、从单车到车队的路线也是业内最标准的做法。1.2 分层控制架构为什么Simulink适合做这件事ACC/CACC控制器的工程实现几乎都采用分层架构这个分层方式本身就是在Simulink里建模的地图。上层叫策略层也叫运动控制层负责根据相对距离、相对速度、本车速度计算出期望加速度。这里做的事是“决定车应该以多大的加速度往前走”。下层叫执行层负责把期望加速度转换成具体的油门开度或制动压力。这里涉及车辆逆动力学模型要回答的问题是“给出这个加速度发动机和刹车该怎么配合”。通信层是CACC特有的负责接收前车广播的加速度、速度、位置信息并把这些信息融合进控制算法。在Simulink里这三层天然对应三个子系统。你可以把上层控制器封装成一个模块把下层车辆模型又封装成一个模块然后用信号线把它们连起来。改控制算法时只需要动上层那个子系统内部车辆模型不用碰。这种模块化解耦的思维方式对我的调试效率提升不是一点半点。另外Simulink有自带的一体化环境状态流模块用来描述逻辑切换比如ACC和定速巡航之间的模式切换Simscape或者Vehicle Dynamics Blockset可以直接提供车辆动力学模型Simulink Real-Time和Embedded Coder支持生成C代码。这意味着你在仿真里验证过的模型可以经过代码生成直接部署到快速控制原型设备上仿真和实车的差距被压缩到最小。2. 模型搭建前的准备车辆模型与参数设定2.1 车辆纵向动力学模型别一上来就用Carsim那种高精度车辆模型除非你做的就是底盘动力学研究。做ACC/CACC算法验证重点在控制策略本身车辆模型精度做到“合理可信”就够了。我常用的车辆纵向动力学模型是基于牛顿第二定律的简化形式[ a \frac{F_{traction} - F_{resistance}}{m} ]其中驱动力 (F_{traction}) 与油门/制动指令相关阻力项 (F_{resistance}) 包括滚动阻力、空气阻力和坡道阻力。为了更贴近实际可以加一阶惯性环节模拟发动机和制动系统的响应滞后[ \dot{a}{actual} -\frac{1}{\tau} a{actual} \frac{1}{\tau} a_{desired} ]其中 (\tau) 是动力总成时间常数一般汽油车取0.3到0.5秒电动车更快一些可以取0.2秒左右。这个时间常数直接影响控制器的稳定性边界我调试时发现如果 (\tau) 设得过大上限PID参数无论怎么调都会出现振荡因为被控对象的相位裕度已经不够了。这里我一般直接使用Simulink自带的车辆动力学模块或者自己用传递函数搭建。自己搭的话至少要包含车体纵向运动方程输出速度和位置一阶惯性环节代表执行器响应油门/制动切换逻辑避免同时踩油门和刹车2.2 传感器与通信模型传感器这块ACC通常用毫米波雷达模型里我用的是“距离 相对速度”输出。雷达模型不需要太复杂加上一个高斯白噪声和一个量测延迟就够了。噪声方差和延迟时间这两个参数非常重要直接影响上层控制器的带宽上限。CACC通信模型则是另一套逻辑。V2V通信不是零延迟的理想信道实际工程中V2X通信延迟在10到100毫秒之间还会出现丢包。我在模型里用Simulink的Transport Delay模块模拟通信延迟又用伯努利随机数生成器模拟丢包事件把通信的不完美性直接暴露给控制器。这个做法比较贴近真实工程场景后面做鲁棒性分析时用得上。关键参数我列个表方便对照设置参数符号取值说明整车质量m1500 kg中型轿车典型值滚动阻力系数f0.015常规沥青路面空气阻力系数×迎风面积Cd×A0.6 m²轿车典型值动力总成时间常数τ0.4 s汽油车典型值雷达量测噪声标准差σ_d0.1 m相对距离噪声相对速度噪声标准差σ_v0.05 m/s相对速度噪声通信延迟τ_comm20 ms典型V2V延迟期望车头时距h1.2 s常用设定值2.3 工具箱准备如果要用MATLAB/Simulink完整跑通这套系统需要的工具箱包括Simulink、Stateflow、Simulink Control Design、Simulink 3D Animation可以用来做可视化Vehicle Dynamics Blockset是锦上添花。搞CACC的话可能还要用到Instrument Control Toolbox用来对接硬件通信。版本方面我现在用的是2024a版本太老的版本缺少一些V2X相关的示例模型但核心功能差异不大不用迷信新版。3. ACC控制器建模从间距策略到油门刹车3.1 间距策略恒定车头时距与恒定间距ACC控制器的第一步是确定期望间距。间距定得太近不安全乘客心理压力也大间距定得太远容易被加塞道路通行效率低。现在主流方案是恒定车头时距CTH[ d_{des} d_0 h \cdot v_{ego} ]其中 (d_0) 是最小安全间距一般取2到5米(h) 是车头时距一般取0.8到2秒(v_{ego}) 是本车速度。这个策略的思路是车速越快间距线性拉大保证有足够的反应时间。另外一种策略是恒定间距CSC也就是不管车速多少间距都固定不变。这种策略在理论分析中很常用因为传递函数简单便于做稳定性分析但在现实中很难落地速度一快就变成危险驾驶了。我把两种策略都做进了模型里通过一个常数模块切换。实测下来CSC在低速园区工况下表现还算稳定但在高速场景下突遇前车急刹时CSC的响应明显更激进舒适性很差。所以主推还是CTH。3.2 上层控制器设计PID与MPC对比期望间距算出来了下一步就是把这个间距误差变成期望加速度。最常见的做法是PID控制器[ a_{des} k_p (d_{rel} - d_{des}) k_d (v_{rel} - h \cdot a_{est}) k_{acc} \cdot a_{lead} ]注意第三项 (a_{lead}) 是前车加速度在ACC中不知道所以这一项为零在CACC中通过通信获得就是后面要讲的重点。PID实现简单、参数含义直观适合快速验证整个模型链路是否通畅。但PID有三个毛病第一参数整定依赖经验不同工况可能要换不同套参数第二无法显式处理加速度和加加速度约束第三对前车加速度信息利用不充分导致跟车响应偏慢。所以我后来又把上层控制器升级成了MPC也就是模型预测控制。MPC的核心思想是在当前时刻预测未来N步的系统状态然后求解一个带约束的优化问题得到最优控制序列只执行第一步下一时刻重新滚动优化。这个思路很直观像你开车时不是只看眼前一米的距离而是会预判未来几秒的距离变化趋势。MPC在Simulink里的实现可以用MPC Toolbox也可以手写YALMIP产线或直接用quadprog求解器。MPC对间距误差的控制效果与PID相比超调量可以减小一半以上加速度变化也更加平滑。我在实际项目中做了一次对比实验工况是前车从30 m/s急减速到10 m/s。PID控制器的最大间距误差约4.2米加速度最大变化率约6 m/s³MPC的最大间距误差约2.5米加速度变化率也控制在2 m/s³以内。差距很直观。3.3 下层逆动力学模型与油门刹车切换上层算出的期望加速度是正负任意值但车辆执行器并没有“负油门”这种东西需要把加速度映射到油门/刹车上。这部分就是下层控制的功能。我的做法是把期望加速度分三种情况期望加速度大于某个阈值比如0.2 m/s²控制节气门开度制动压力为零期望加速度小于某个阈值比如-0.2 m/s²控制制动压力节气门关闭介于两者之间保持当前状态避免频繁切换这里有个关键细节油门和制动的切换要加滞回区间。如果阈值设置没有滞回车辆会在这个区间内来回抖动油门刹车快速交替不仅舒适性极差还会让Simulink的步长求解器因为频繁的事件触发而变慢。我用Stateflow实现了这个切换逻辑状态图里三个状态之间用滞回条件迁移实际效果非常平稳。油门开度与加速度之间的关系并不线性一般用查表方式建模。转速为2500 rpm每分钟两千五百转、挡位处于中低挡时油门每增加一个单位加速度增量可能很大但在高挡高速工况油门响应明显变钝。所以查表数据一定要覆盖你仿真所涉及的速度区间否则高速跟车场景会出现控制器输出饱和的问题。4. CACC协同控制通信拓扑与控制律4.1 V2V通信拓扑与车队稳定性CACC相比ACC多出来的核心就是通信拓扑。业内常见的几种拓扑包括前车跟随型英文缩写PF只接收紧邻前车信息领航车-前车跟随型缩写PLF同时接收头车和紧邻前车信息多前车跟随型缩写MPF接收前几辆车的信息不同拓扑对车队稳定性的影响差异显著。理论分析通常通过传递函数来做把间距误差定义为本车实际间距与期望间距之差然后推导相邻两车误差之间的传递函数关系再分析这个传递函数的H∞范数是否小于等于1代表扰动在队列中不会被放大。在PF拓扑下由于本车只能感知前车运动状态整个车队相当于一串首尾相扣的弹簧间距误差容易向队尾传播放大。PLF拓扑多了一个领航车信息的提前作用相当于让每个后车都知道队列的目标运动意图稳定性条件明显放宽。MPF则更进一层但代价是通信带宽和拓扑复杂度上升。所以我在建模时选了PLF拓扑作为主要研究方案既有足够的协同性又不至于把通信模型搞得太复杂。每个后车接收的数据是前车的加速度、速度、实际位置以及领航车的加速度。数据通过Simulink的总线信号统一封装便于扩展。4.2 CACC控制律推导与实现CACC的控制律可以看作在ACC基础上用通信获得的前车加速度做前馈补偿。经典的控制律形式为[ a_{des} k_p (d_{rel} - d_{des}) k_d (v_{rel} - h \cdot a_{prev}) k_f \cdot a_{prev} ]其中 (a_{prev}) 是紧邻前车的加速度。通过通信获得后把这一项用前馈方式叠加到控制输出中。为什么前馈有效因为前车尚未产生明显相对位移变化时后车已经从通信中感知到前车的加速意图可以在物理相对距离改变之前就调整自己的加速度。这相当于你在排队时身后的人通过无线电告诉你前面的人突然停了你可以提前刹车而不是等看到前面的人停下才知道。在Simulink中实现这个控制律非常直观前车加速度信号通过通信延迟模块进入控制器的前馈通道乘以一个前馈增益之后与PID反馈项叠加。需要注意的是前馈通道必须加一个低通滤波器因为通信信号中混杂着高频噪声原样导入会让执行器高频抖动。我实际测试的PLF拓扑CACC控制律代码核心逻辑在MATLAB Function模块中实现伪代码如下function a_des CACC_controller(d_rel, v_rel, v_ego, a_prev, a_lead) d0 2.0; h 1.2; d_des d0 h * v_ego; kp 0.8; kd 0.6; kf 0.9; a_feedback kp * (d_rel - d_des) kd * (v_rel - h * a_prev); a_feedforward kf * a_prev; a_des a_feedback a_feedforward; end4.3 通信时延与丢包的应对通信链路不是理想的。我前面提到用Transport Delay模块模拟通信延迟用伯努利随机数模拟丢包这两个模块加进去之后原来的CACC性能明显恶化车队尾部开始出现振荡甚至在某些丢包率下后车的加速度出现了类似刹车点头的现象。应对策略有几个层面。第一控制器参数要针对通信延迟做鲁棒性设计。延迟变大时前馈增益 (k_f) 必须适当降低。我的经验是把 (k_f) 设置成通信延迟的函数延迟越大前馈作用越弱让系统回归到以反馈为主的模式。第二丢包处理常用直接丢弃旧数据本周期若没收到新数据就用上一周期的数据相当于零阶保持。这种方式最简单但在连续丢包时效果不好。我加了一个模型预测模块当丢包发生时用车辆运动学模型对前车未来位置做预测填充直至通信恢复。实测下来这个改进让车队在5%丢包率下依然保持稳定的差距水平零阶保持方案在3%丢包时就开始出现明显超调。第三在CACC设计中加入控制器的增益调度也很重要。不同车速、不同通信质量下使用不同组别的控制参数是工程化落地的基础。这个增益调度表我就直接放在Simulink的Lookup Table模块里简单直观。5. 场景仿真与调参实战5.1 多车队列场景搭建我搭建的仿真场景是一个五辆车组成的车队头车编号0后面跟着编号1到4。车辆的初始位置按间距设定均匀分布初始速度都设为20 m/s。整个模型的顶层布局分三大块左侧是领航车的驾驶行为信号源我叫它Scenario Generator负责切换不同驾驶工况中间是五辆车的子系统每辆车内都包含感知、上层控制、下层控制、车辆动力学四个子模块右侧是监视显示系统包括实时曲线显示和车队行驶动画空间。领航车工况我用一个信号发生器搭建默认设计了几段典型工况匀速巡航、正弦加减速、紧急制动、阶梯提速方便把整个控制器的响应特性都压测一遍。五辆车之间通过信号线连接时我踩过一个坑如果直接用Goto、From模块跨层引用信号模型可以跑但逻辑清晰度很差信号源判断容易混乱。建议把所有车辆间的通信信号统一整理成总线对象在基础工作区定义Simulink.Bus然后在模型里用总线端口连线。这样查线、查信号、做代码生成都方便很多。5.2 典型工况测试与结果分析我重点测试了三个工况结果都很有代表性。第一个是头车紧急制动头车从20 m/s以最大制动减速度大概7 m/s²刹到停车。纯ACC车队中由于每辆车都是看到前车减速才减速间距误差在车队中逐渐累积第4辆车的最小间距缩小到不足2.5米濒临碰撞风险。CACC车队中头车的制动意图通过V2V通信几乎同步传递给后方车辆第4辆车的最小间距仍保持在5米以上刹车强度曲线也远没有ACC车队那么陡舒适性改善明显。第二个是头车正弦加减速这个工况用来观察车队在持续扰动下的弦稳定性。ACC车队中正弦扰动向后传递时间距误差逐渐放大从第1辆到第4辆误差振幅几乎翻倍CACC车队中误差振幅是递减的正体现了弦稳定性的效果。第三个是头车阶梯提速头车从20 m/s提速到30 m/s保持一段时间再回到20 m/s。这个工况下两套系统的稳态跟车误差相差不大但在提速初期CACC的响应速度明显快于ACC车队的车速同步性更好。5.3 参数整定心得参数整定是整个项目中最花时间的一步。我先说最核心的原则先内部后外部先单车后车队。具体来说先把车辆动力学模型单独验证看看开环响应是否合理再闭合ACC反馈环只调单车PID参数让它在阶跃工况下能够无静差跟车。单车存在问题调好的参数不要动再引入通信链路调CACC的前馈增益和滤波器参数。PID参数怎么快速定一个初始值我的经验是用临界比例度法。先把积分项和微分项设为0只保留比例项从小到大增加比例增益直到系统输出出现等幅振荡记下此时的临界增益 (K_c) 和振荡周期 (T_c)。然后按照经验公式计算初始PID参数[ K_p 0.6 K_c, \quad K_i \frac{K_p}{0.5 T_c}, \quad K_d K_p \cdot 0.125 T_c ]算出来的参数通常就能跑了再在此基础上细调。注意这个初始参数可能会偏激进因为车辆模型含有时间常数实车场景还要再降一些增益我习惯把仿真调好参数乘以0.7到0.8再试验。前馈增益 (k_f) 的设定相对固定理论上接近1就能实现完美的前馈补偿但考虑到通信延迟和执行器滞后我一般设置在0.8到0.95之间配合低通滤波器使用。滤波截止频率设在2 Hz左右比较合适既能滤掉通信噪声又不会明显削弱控制信号的上升沿。6. 常见问题与排查技巧实录6.1 常见仿真问题与排查方法我自己在搭建和调试过程中遇到过不少问题挑几个最典型的列在下面你可以直接对照排查。问题现象可能原因解决方案仿真起动很慢计算步长很小模型中存在高频振荡或代数环检查油门/制动切换是否频繁加入滞回用低通滤波器消除高频分量车辆间距出现负值初始间距设置过小或控制器发散增大初始间距到100米以上先手动降PID增益让系统稳定车队尾部出现“蛇形摆动”通信延迟过大且前馈增益偏高降低前馈增益到0.7或增大低通滤波器的滤波强度突然出现NAN无效数值查表模块的输入超出了表头取值范围检查油门/制动查表模块的边界值对控制器输出做Saturation限幅仿真结果与理论分析有出入离散控制器的采样时间不一致让所有控制器的采样时间统一避免多速率采样导致的混叠效应代码生成失败模型层级不规范或Bus对象未定义统一使用Bus对象传递总线信号确保Simulink代码生成模块没有歧义6.2 从仿真到落地部署的一条路最后说一点扩展思路。这套模型的价值远不止停留在仿真层面我后续做的是把控制器部分抽离出来通过Simulink的Embedded Coder生成C代码部署到NI控制器或快速控制原型设备上做硬件在环测试。注意在模型准备做代码生成之前提前养成几个习惯能省很多功夫第一所有控制器模块用离散时间更新别用连续时间因为目标硬件是周期性任务执行第二饱和模块、限幅模块显式添加到每个输出端口防止溢出第三不要在控制器通路里放Simulink示波器模块它对代码生成不友好用信号记录模块代替。还有一个小技巧在Simulink中做ACC/CACC时给每辆车内部的控制模块加上后缀编号比如Ctrl_Car1、Ctrl_Car2这样生成代码后函数名清晰可辨排查问题会非常方便。这套项目做完之后我的整体感受是ACC是基础功CACC才是真正体现协同价值的进阶玩法。如果你正在做相关方向建议先花一周时间把单车的ACC模型搭熟然后再去碰通信和控制律的协同设计进度反而会比直接从CACC入手更快。有条件的话把仿真参数和算法固化下来再做一版硬件在环的测试你会对整个V2X控制链路有更深的理解。