ACC自适应巡航进阶:目标选择与纵向控制的工程实战解析
发布时间:2026/10/20 5:07:15 锦皓数字建站

上一讲我们把ACC自适应巡航的系统基础讲完了毫米波雷达怎么测距测速、前车目标怎么映射到自车车道、恒速与跟车巡航的模式切换、还有最基础的PID速度控制怎么跑通一个直道跟车Demo。那次算入门这一讲我想做点更实际的东西——目标到底该跟谁、切入切出时怎么给油收油、弯道里为什么容易跟丢、纵向控制用PID还是MPC、雷达和摄像头数据对不上时听谁的以及低速拥堵和功能降级这些真正决定ACC好不好用的细节。如果你刚接手ADAS算法模块或者正在做ACC相关的毕业设计这篇文章应该能帮你少踩几个坑。1. 总体思路从“能动”到“能看懂路况”1.1 “二”到底补了什么第一讲的核心是“把速度跟住”。给一个前车目标算出一个期望加速度让自车在直道上老老实实地跟着走。那一套在封闭场地和高速公路直道上确实够用了但一上真实道路就会露馅前面有好几辆车雷达一下丢出十几个目标ACC要自己判断哪一个才是“该跟的车”前车忽然变道出去你还没来得及反应系统就猛加速往前冲路过弯道时明明隔壁车道的车也在前方系统却把它误当成主目标一脚刹车。这一讲把视角从“单车控制”抬到“整车场景策略”。简单说就是ACC不再只关心怎么踩油门刹车而是先回答几个问题当前车道里谁是我的目标、这个目标可不可靠、我现在应该处于定速还是跟车、如果传感器坏了该怎么办。这里的核心不是某一层算法有多花哨而是每一层的职责边界要清楚层与层之间的接口要稳定。只有这样换传感器、换车型、换控制器的时候算法框架才不用推倒重来。1.2 模块化链路让问题可拆解我习惯把整个ACC系统拆成下面这条链路感知融合层、目标管理层、场景决策层、纵向控制层、执行器接口层。感知融合层输出的是目标列表每个目标带距离、相对速度、横向位置、存活时间、类型车辆/行人/自行车等信息目标管理层从这些目标里挑出唯一一个“主目标”也叫TOITarget of Interest场景决策层根据主目标存在与否、车速、距离、驾驶员操作决定当前处于定速巡航模式、跟车巡航模式还是停车保持模式纵向控制层负责把模式转换成具体的加速度请求发给发动机和制动系统。这个结构最直接的好处是每个模块都能单独拿出来测试。目标选择有没有问题灌一段录制好的雷达和摄像头数据就能验证控制逻辑有没有问题用一台仿真车接上同样的目标曲线也能验证。彼此可以并行迭代不用每次都在实车上做全链路验证。别把接口设计得太复杂。我见过不少项目状态机里塞了几十个标志位模块之间互相读私有数据最后出了bug查起来非常痛苦。好的接口设计就是每个模块输出一个明确的结构体各层之间靠这个结构体通信内部怎么实现是自由。你可以替换一个更强的目标跟踪算法只要输出格式不变下游完全不受影响。这就像餐厅的流水线接单、备菜、炒菜、传菜各司其职换掉某个环节其他环节不用跟着改。2. 目标级联与场景划分ACC的每一步都在回答“跟谁、怎么跟”2.1 主目标选择的工程化流程主目标选的准不准直接决定ACC的体验。选错了轻则莫名其妙加速减速重则把护栏当车踩一脚刹。一个工程上可落地的筛选流程大概是这样候选目标先过滤把本车后方、横向距离过大的目标剔除。雷达原始目标里可能有高速路旁的护栏、路牌、隔离带反射点这些点通常横向距离大、横向速度小、类型标签为静态首先就要过滤掉。然后算“同车道概率”。这一步不能只看目标当前在哪里还要往前看一步。因为车辆是在动的本车前方是一条弯道时直线上看起来在邻道的车进入弯道后可能正好就在本车轨迹上。所以工程上会先做本车道中心线外推方法是根据本车横摆角速度、车速和车道线曲率把未来一段距离内的车道中心轨迹算出来然后计算目标的横向坐标到这个轨迹的偏移量。简单示意一下def select_target(candidates, ego_v, lane_curvature, dt, n_points): future_path generate_ego_trajectory(ego_v, lane_curvature, dt, n_points) valid [] for obj in candidates: lateral_off estimate_lateral_offset_from_path(obj, future_path) if abs(lateral_off) LANE_WIDTH * 0.5: valid.append(obj) if not valid: return None return min(valid, keylambda o: o.longitudinal_distance)这里有两个参数需要标定一个是车道宽度假设一般取3.5米左右一个是横向偏移阈值通常取半个车道宽。别小看这个阈值设大了会把邻道车算进来设小了在弯道里又会把真实主目标漏掉。实车上一般会根据车道线质量做动态调整车道线置信度高时用0.4个车道宽置信度低时放宽到0.6。2.2 切入切出不能突然冲刺也不能犹犹豫豫真实道路上的主目标不是一直不变的。邻道车辆突然并入本车道或者主目标变道离开这是ACC调参里最容易出现投诉的两个场景。切入场景的核心是“早识别、缓介入”。判断切入不能只看某一帧的横向位置要看横向位置的变化趋势。比如一个目标在当前帧横向偏移是1.2米看起来还在邻道但它的横向速度是1.5米/秒且方向指向本车道中心那在0.5秒内它就会进入本车道。如果算法等到它完全进入车道才反应留给制动的时间就不多了。正确做法是预测切入提前开始温和减速。减速度不需要一次给满可以按一个斜坡增加到目标减速度。比如目标本身要求的减速度是2.5米/秒²可以先在200毫秒内从0.5线性爬到2.0再保持到距离误差收敛。这样驾驶员和乘客的体感是“系统预料到了”而不是“系统被吓到了”。切出场景则要反着来主目标切出后自车不应该立刻踩油门追向前方空位。原因很简单驾驶员会本能地害怕谁知道前方会不会突然又出现一个目标。工程上普遍的做法是设置一个延迟窗口比如1.5到2秒窗口内保持当前速度窗口结束后再以限制好的加速度斜率恢复加速。2.3 弯道里跟丢了多半是坐标投影的问题弯道可以说是ACC最容易露怯的场景。直道上一切正常一个弯道过来就开始误判。原因在于坐标投影。ACC传感器输出的目标经纬度坐标是以雷达安装位置为原点的笛卡尔坐标但控制逻辑需要的是“相对本车行驶轨迹的纵向和横向距离”。在弯道上本车有一个横摆角传感器的坐标系其实一直在转如果不做轨迹投影补偿一个小弯道都会让某个邻道车辆看起来“跑”到了本车前方。工程上一般有两种解法。一种是基于曲率的前方轨迹投影根据自车速和横摆角速度积分出前方路径再把目标点投影到这条路径上求弧长和横向偏差。另一种是基于车道线地图把目标点匹配到车道中心线上。前者对车道线质量不敏感适合纯雷达方案后者精度更高依赖摄像头车道线输出两者可以融合使用。弯道里还有一个容易被忽略的问题目标被遮挡。一辆车在弯道里被路边树木或大型车辆遮挡几秒后重新出现在视野里如果目标跟踪模块没有保留它的历史状态它会被当成一个新目标主目标ID瞬间变化自车会以为前车忽然消失又出现产生一次明显的顿挫感。处理办法是给目标一个“保留期”比如500毫秒内即使没有关联到测量值也用模型预测位置继续输出。3. 纵向控制进阶从串级PID到模型预测控制3.1 串级PID先讲明白第一讲提到PID实际工程里单环PID根本不够用。ACC的纵向控制普遍是串级结构外层是距离环输入是期望跟车距离与实际距离的误差输出是期望速度内层是速度环输入是期望速度和实际速度的误差输出是加速度请求。为什么分成两层因为纯位置控制直接输出加速度的话内环对速度波动的响应太慢前车稍微加个速自车就容易追过或拉开过大。串级结构的好处是内环先把速度稳定住外环只负责距离修正各干各的事调参也容易定位问题。期望跟车距离一般用时间间隙策略计算d_des v_ego * t_gap d0v_ego是自车速度t_gap是时间间隙通常取1.5秒d0是停车时的最小安全间距一般取2到5米。为什么用时间间隙而不是固定距离道理很简单车速120公里/小时时固定距离20米是致命的同样20米在60公里/小时下又太保守会被后车频繁加塞。模式切换也要设计滞回区间。比如定速巡航模式和跟车模式之间不能以0.1米为阈值来回切换否则驾驶员会感觉到油门和刹车在抖动。工程上一般做一个两档阈值比如距离小于35米且相对速度为负时进入跟车模式距离大于45米时才切回定速模式。3.2 为什么需要MPC串级PID可以在直线跟车场景下做得很好但实际驾驶里它的短板很明显反应永远慢半拍。因为PID是“看到误差才反应”。前车急刹车距离误差已经变大系统才开始降速前车急加速相对距离已经拉大了系统才给油门。而且执行器有延迟发动机扭矩响应需要几百毫秒ESP制动系统建立压力也要时间。PID在延迟面前很容易产生振荡。MPC模型预测控制思路从根本上不一样它不是等误差出现再去纠正而是用一个模型预测未来一段时间内自车和前车的状态按照一个包含安全距离、速度、加速度、舒适性的目标函数找出一段最优的控制序列然后只执行第一步下个周期重新算。我常用一个类比解释MPCPID是盯着当前误差踩刹车的老司机MPC是看前车尾灯提前松油门的熟练司机。后者不慌因为它在脑子里预演了未来几秒。ACC这个场景用MPC特别合适因为它本身就是一个带约束的最优控制问题加速度有限制不是你想刹到5米/秒²就立刻能办到舒适性有限制人受不了太快的加速度变化率安全性有限制相对距离不能小于某个阈值。3.3 一个可落地的代价函数与简化求解我把一个工程上能跑的ACC-MPC代价函数拆给你看。预测模型采用一阶积分模型采样周期100毫秒预测时域取50步也就是往后看5秒。状态量取距离误差e_d、相对速度e_v、自车速度v控制量取期望加速度a前车的未来加速度a_lead当作已知扰动输入。代价函数可以写成J Σ( w_d * e_d² w_v * e_v² w_a * a² w_j * jerk² )其中jerk是加速度的变化率也就是(a[k] - a[k-1]) / dt。w_d、w_v、w_a、w_j是权重决定系统在安全和舒适之间怎么取舍。约束条件是加速度下限和上限、jerk的下限和上限a_min ≤ a ≤ a_maxjerk_min ≤ jerk ≤ jerk_max一个简化求解示意是这样的def solve_mpc(e_d0, e_v0, v0, a_lead_seq, dt, N): best_cost float(inf) best_a_seq None # 在可行域内枚举加速度序列实际工程用QP求解器 for a_seq in enumerate_feasible_sequences(a_min, a_max, jerk_limit, N): e_d, e_v e_d0, e_v0 v v0 cost 0 for k in range(N): a a_seq[k] e_d e_d e_v * dt e_v e_v (a_lead_seq[k] - a) * dt v v a * dt jerk (a - a_seq[k-1]) / dt if k 0 else 0 cost w_d * e_d**2 w_v * e_v**2 w_a * a**2 w_j * jerk**2 if cost best_cost: best_cost cost best_a_seq a_seq return best_a_seq[0]实际工程不会用枚举效率太低一般用二次规划QP求解器或者基于动力学模型推导的简化求解器。但代价函数的形状就是上面这个思路。调参顺序建议先调好权重再调约束。先把加速度约束放宽让系统在自由环境下动作观察距离误差收敛情况再逐步收紧jerk约束确认舒适性。直接一上来就把jerk限得很死系统会表现出“一直在磨磨蹭蹭”的感觉很憋屈。3.4 舒适性加速度斜率比峰值更重要乘客抱怨ACC“急”“晕”往往不是加速度峰值太大而是加速度变化太快。学术上叫jerk也就是加速度的导数。经验值方面正常驾驶时舒适性较好的jerk上限在2到3米/秒³附近。紧急制动时目标减速度可以达到4到5米/秒²但如果jerk超过5米/秒³乘客会有明显的点头感。所以控制策略里一定要给加速度请求做斜率限制不能直接要求从0加到3米/秒²。实现上可以做一个一阶惯性环节让加速度请求按时间常数平滑过渡也可以用MPC的jerk约束直接限制。4. 传感器融合与状态估计别让ACC变成“近视眼”4.1 单传感器各自“偏科”融合才是正解只用毫米波雷达做ACC最核心的痛点是横向精度差。雷达的多普勒测速很准纵向距离也不错但横向位置误差经常超过0.5米而且对静止目标容易产生虚假回波匝道护栏、路沿反光、隧道墙壁都会报出假目标。只用摄像头做ACC痛点反过来。摄像头横向位置识别准确车道线检测能力强但单目测距本质上依赖地面假设和先验尺寸纵向距离误差在小目标上很容易达到10%以上夜间和逆光时性能还会进一步下降。融合的目的不是简单取平均而是充分利用各自优势雷达负责纵向距离和相对速度摄像头负责横向位置和目标类型识别两者经过时间同步和空间对齐后生成一个同时具备稳定纵向和横向精度的目标。4.2 目标跟踪与滤波的工程要点目标从传感器进入系统后不能直接用原始测量值驱动控制必须经过跟踪滤波。ACC里常用的状态模型是CA模型也就是恒加速度模型状态向量包含距离、速度、加速度三个量。卡尔曼滤波在这里的作用是把测量值里的噪声滤掉并在目标短暂遮挡时用模型预测位置顶住。但工程上有几个坑滤波器状态更新周期和目标上报周期不匹配时协方差矩阵容易“飘”导致滤波输出抖动。解决方法是严格按照传感器时间戳做预测更新而不是在每个算法周期里假设数据新鲜。目标ID切换时状态会突变。一个目标丢失又重新关联如果把它当成新目标卡尔曼滤波器要从初始状态重新收敛收敛期间输出的距离、速度往往不可信。工程上会给每个目标一个连续存活时间和关联计数只有连续关联多帧后滤波器输出才允许进入控制环。前车加速度估计也是一个关键点。MPC需要预测前车的未来加速度但这个量没法直接测量只能通过对前车位置和速度的差分结合滤波来估计。估计误差大的时候优化出来的轨迹会过于乐观或过于悲观。实际操作中我会对前车加速度估计结果做一个可信度标签可信度低时把MPC里的前车扰动项置零避免错误预测引发误刹车。4.3 时间同步与数据关联雷达和摄像头的输出周期不一样时间戳也不同融合前必须做时间对齐。一个常见做法是把所有传感器数据先缓冲到统一时间基准上然后按融合周期取每个传感器最近的有效帧用其时间戳做插值补偿。补偿精度直接影响目标位置因为50毫秒的时间差在高速公路上就对应1米多的位置差。数据关联解决的是“哪几个传感器目标其实是同一个物体”的问题。简单场景用最近邻匹配就够了但目标密集时最近邻容易串。稍微复杂一点就用全局最近关联即把雷达目标和视觉目标的匹配看成一个指派问题最小化总的关联代价。代价矩阵里的距离度量用马氏距离比欧氏距离好因为它考虑了不同维度上的不确定性差异。关联时必须设置门限匹配代价超过门限的目标就是新目标不能强行关联。我见过一个案例门限设大了一个雷达点和一个视觉目标明明是不同物体却被硬拼在一起融合目标一会儿跳前一会儿跳后导致ACC全程在抖。5. 低速拥堵场景与安全降级该停就停该退就退5.1 自动跟停与起步的策略ACC在高速上表现好一到城市低速拥堵路况就容易暴露出设计缺陷。这时候车辆经常要在走走停停中反复起步和刹停对算法和标定都是严峻考验。自动跟停的核心难点不是“刹住”而是“怎么刹住”。前车停车时如果系统按常规跟车策略一直收敛到目标距离才停程序就会用一个比较大的减速度突然刹停乘客身体前倾明显。所以工程上会在预计停车前一段距离比如10米左右就开始提前降速用爬行减速的方式慢慢凑近前车。目标停车距离不再是固定值而是和速度、前车加速度趋势绑定前车减速得快自车就早减速。停车之后的起步策略需要设计确认机制。很多量产ACC在停车超过3到5秒后不会自动起步必须驾驶员轻点油门或者拨一下按键才恢复。原因不在于算法做不到而在于安全逻辑长期停车后前车状况未知驾驶员可能正打算开门下车此刻自动起步容易出事故。起步前还得重新做一次目标选择因为停车期间主目标很可能已经换道了。低速场景下还有一个参数要特殊处理时间间隙。低速时如果沿用1.5秒时间间隙期望距离会小于停车间距逻辑混乱。所以低速域要切换成固定间距策略比如车速低于5米/秒时期望距离直接取一个定值带一个小的速度修正项。5.2 传感器失效时的降级链路ACC做得好不好失效场景下的表现比正常场景更能说明问题。毫米波雷达和摄像头都有自己的健康状态监测。雷达会有自检故障码摄像头会有遮挡、标定漂移、供电异常等诊断信息。算法层除了看故障码还要监测数据帧的连续性和合理性比如连续200毫秒没有收到雷达目标数据那就是异常。失效后的降级策略分三层第一层是传感器部分失效比如摄像头被泥水遮挡但雷达正常。此时系统可以降级为“纯雷达ACC”但必须同时限制最高速度和工作场景比如车速只能到80公里/小时且不提供跟停功能。第二层是核心传感器完全失效比如雷达故障。这时候ACC无法可靠检测前方目标系统应立即发出接管请求同时保持当前加速度不超过一个安全值。这个阶段的目标不是继续ACC而是安全退出。第三层是系统无法确保安全但又不能立刻停车时比如在高速中间刹车减速到安全速率打开危险报警灯保持车辆缓慢行驶并持续提示驾驶员接管。这种设计叫fail-safe核心原则是ACC可以在任何时刻退出但不能在退出时制造危险。5.3 数据回放与问题复现调ACC最怕的是问题无法复现。实车上偶发一次误刹车可能好几周都碰不到第二次这时候数据回放就是救命稻草。我建议所有ACC相关的输入输出都做完整录包包括雷达原始目标、摄像头输出、本车速、横摆角速度、方向盘转角、油门刹车指令、ACC状态机状态。字段要带上毫秒级时间戳同时记录一个GPS时间基准方便后续多路数据对齐。回放时用离线工具把同一份数据灌进算法看输出可以在几秒钟内复现实车上的行为。这样调整参数后可以立刻看到同一场景下的算法行为变化不用再冒着风险上路试。6. 实测中遇到的几个典型问题与调参思路6.1 目标抖动导致加减速频繁现象高速巡航时前车明明在匀速行驶自车却隔几秒就轻微加减速。排查方向首先要看主目标ID是否稳定。如果雷达目标在几帧内反复切换ID系统就会认为前车速度在跳变。解决办法通常是给目标关联计数加滞回连续3帧关联同一个目标后才允许它成为主目标丢失目标后保留一段时间。其次要看滤波参数是否太激进。卡尔曼滤波的测量噪声矩阵设得太小滤波输出会跟随测量值的抖动设得太大又会出现“跟不住”的滞后感。一般先根据传感器厂商给的噪声标定初值再在回放数据上做离线仿真调参。6.2 误触发刹车对护栏和路沿的响应现象左侧是护栏的弯道处系统突然减速屏幕上主目标显示在左侧护栏上。这是毫米波雷达的经典问题弯道护栏会产生很强的镜面反射雷达会输出一个和真实目标距离很接近的虚假点。如果这个点恰好落在本车道外推轨迹附近就会被选成主目标。处理思路有三步。第一步给目标打类型标签静态目标候选需要更严格的同车道判定条件。第二步融合摄像头车道线信息用车道线曲率修正本车道外推轨迹让护栏点的横向偏移计算更准确。第三步引入目标横向运动趋势一致性检验一个横向位置和横向速度都稳定在同一点的目标才可能是真实交通参与者剧烈跳变的目标可信度要打折扣。6.3 舒适性和安全性怎么平衡这是所有ACC项目中讨论最多的话题。安全性要求跟车距离近一点这样反应时间更长舒适性要求加速度和jerk都小一点这样动作更柔和。这两个目标天然冲突。我的经验是把安全性拆成硬约束和软约束两级。硬约束是绝对不能突破的边界比如紧急制动时最大减速度不超过5米/秒²跟车距离不小于5米。软约束是MPC代价函数里的权重项正常工况下系统会在安全边界内尽量舒适。这样在紧急情况下系统可以突破舒适性软约束来保证安全而平时则保持柔和。调参时间线大概是先确定硬约束边界再调MPC的权重让正常跟车时动作温和最后拉一个紧急场景库验证硬约束场景下系统能否触发保护性制动。这个流程比一上来就追求极端舒适性要稳妥得多。还有一个实际操作中的细节值得单独说每次修改参数后不要只跑一个场景要至少在仿真环境里过一遍标准场景集包括前车突然切入、前车急刹、相邻车道车辆并行、隧道入口、雨天传感器降级等。我见过太多人把某个场景调顺了另一个场景又出现新问题原因就是缺乏标准回归测试。建一个场景用例库每次改动后全量回归哪怕多花半天时间也比实车出险情划算。我个人调ACC这几年最大的感受是控制算法本身的学习成本并不高难的是对“目标管理”的理解。PID也好MPC也好它们都是在解决“怎么动”的问题目标选择、切入切出、弯道投影、传感器融合解决的是“动谁”的问题。后者没做好前者再精细也白搭。很多刚开始做ACC的同学会把大量精力放在调MPC权重上上车之后被安全员吐槽问题往往出在目标选择上而不是控制上。最后再补一个小技巧录数据时别只录正常场景遇到误动作、急刹、目标丢失的时候手动打一个标记回办公室后优先分析这些标记段。这些“坏数据”比一百公里正常路跑的数据都有价值。ACC这个功能看似简单实际上牵涉传感器、融合、决策、控制、安全降级和人机共驾多个层面每一步都有大量工程细节。这篇文章抛出的是我在实践中验证过的思路和参数范围真到具体车型上还需要根据传感器配置、制动系统响应特性和整车标定反复打磨。希望这些经验能帮你绕开我走过的弯路。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。