1. 第20期合集为什么要把话题从"模块"拉回"系统"
做这个系列的合集做到第20期,我自己有一个明显的心态变化:前十几期的时候,我最喜欢拆的是单个模块——怎么把点云喂进检测网络、怎么把一条参考线拟合得平滑、怎么让横向控制不画龙。这类内容写起来爽,读者看着也爽,因为每一篇都有立竿见影的正反馈:改个参数,曲线就直了。但做到十几期之后就发现一个问题,单个模块在电脑上跑得像模像样,一放到车上就各种别扭,而这个别扭往往跟那个模块本身没关系。
自动驾驶这四个字,在工程上从来不是"感知很强"、"规划很聪明"、"控制很丝滑"的简单相加。它是一个典型的木桶系统,而且这个木桶的板子之间是互相插着榫卯的:感知的时间戳抖一下,规划出来的轨迹就会抖;定位的协方差没传下去,规划就会自信地贴着一辆大卡车切过去。所以第20期我不打算再拆零件了,而是把前面十九期讲过的那些散件摊开,聊一个更实在的话题——从"能跑"到"敢在真实道路上连续跑"之间,到底隔着什么。
这篇内容适合三类人看。第一类是刚进这个方向、手里已经能跑通一个开源方案、但搞不清楚"为什么Demo很稳、实车很慌"的同学;第二类是已经在做某个垂直模块、想弄清楚自己那块在整个链条里到底被谁卡脖子的工程师;第三类是纯粹对这套系统好奇、想搞明白里面到底有多少工程细节的技术读者。我会尽量把每个参数的来龙去脉、每个取舍背后的账算给你看,能直接抄的部分我会写清楚怎么抄,不能抄的部分我会说清楚为什么不能抄。
2. 整体收敛思路:先划边界,再谈性能
2.1 前十九期攒下的三类硬骨头
把之前写的东西归类一下,问题其实就三类,而且这三类的解法完全是反着来的。
第一类是精度问题,比如检测框抖动、加塞车辆漏检、路口远处目标分辨率不够。这类问题的直觉解法是"加大模型、加传感器、加分辨率",短期有效,但很快会撞到算力和成本的墙。
第二类是一致性问题,比如同一段路今天过得很顺、明天就犹豫甚至急刹。这类问题加算力没用,因为根子往往在时间同步、坐标系约定、状态机边界条件上,属于"设计债"。
第三类是可维护性问题,比如换了个城市的道路标线风格,标定参数就开始飘;换了个车型,控制的增益全部要重调。这类问题的解法不是优化,而是抽象——把跟场景、跟车体强耦合的东西抽出来,做成可配置的层。
我实测下来一个很反直觉的结论:大部分"优化不掉"的性能问题,其实是一致性问题伪装出来的。你看到的是检测帧率不够,实际是两路传感器的数据差了半个周期;你看到的是控制震荡,实际是规划输出的曲率本身在跳变。
2.2 一个被低估的事实:瓶颈通常不在算法
我自己做过一次很土的统计,把一段时间里团队解决的实车问题归因,粗略地分成算法类、集成类、标定类、数据类四堆。结果算法类只占三成左右,剩下七成里,集成和标定加起来超过一半。
这个分布很好理解。算法层面的东西,文献里、公开课程里都有大量成熟结论可以借鉴;而集成和标定是强依赖具体车体、具体传感器安装位置、具体线束和时钟的东西,没人能替你做完。比如相机相对车体坐标系的旋转外参差 0.5 度,在 50 米外就是大约 0.44 米的横向偏差,这个数字足以让一辆车在窄路里压线。
所以这一节的核心观点是:先把系统的骨架和约定定死,再往里面填算法。骨架包括坐标系定义、时间基准、数据接口、降级策略、指标口径。这五件事只要有一件含糊,后面所有的优化都是在流沙上盖楼。
2.3 收敛的基本动作:划边界、定指标、留降级
落到具体操作上,我一般按三步走。
第一步划边界。把系统能力显式地写成一张表:最高设计车速、最大可处理曲率、可识别的最小目标高度、允许的最大定位误差、允许的最长感知失效时间。这张表不是为了好看,是为了后续所有模块的接口都拿它当契约。比如写明"定位误差 3σ 不超过 0.3 米",那规划在生成轨迹时就必须按 0.3 米的不确定性去留安全余量,而不是假设自己永远在 1 厘米精度上。
第二步定指标。指标一定要可测量、可复现。我见过太多"这个版本感觉更顺了"的评审,这种结论没法做回归。可用的指标比如:每千公里人工接管次数、每百公里急刹(纵向减速度超过阈值)次数、轨迹曲率变化率的均方根、横向跟踪误差的 95 分位数。这些数字写进日志,才能做版本间的对比。
第三步留降级。任何一个模块都必须回答一个问题:你失效了之后,系统怎么活。感知失效 100 毫秒,可以靠短时预测撑过去;定位失效 5 秒,就得降速靠边;通信中断,必须能靠本地状态完成停车。降级不是补丁,是设计阶段就要写进状态机的东西,我在第 3 节还会细说。
注意:降级策略一定要在仿真和封闭场地里真的触发过一遍。没被验证过的降级逻辑,在关键时刻大概率不生效,因为它平时从来没被执行过,里面藏着的空指针和未初始化状态没人发现。
3. 感知单元:传感器不是越多越好
3.1 选型先算三笔账
传感器配置这件事,新人最容易犯的错是"加法思维"——多一路相机就多一份冗余,多一颗激光雷达就多一份安心。实际不是这样,每加一个传感器,你同时加了三样成本。
第一笔是算力账。以图像为例,8 路 1920×1080 的彩色图,单帧原始数据是 1920×1080×3 字节,约 6.2 MB。30 fps 下,8 路一秒的数据量是 6.2 MB × 8 × 30 ≈ 1.5 GB/s。就算在采集端做了压缩,解码、缩放、推理这一整套走下来,对带宽和算力的占用都是实打实的。激光雷达同理:64 线、10 Hz,单帧大约 12 万点,每点按 xyz 加反射强度共 16 字节算,单帧约 2 MB,一秒 20 MB。这类数据一旦要送到多个下游模块,内存拷贝的开销比计算本身还大。
第二笔是标定账。传感器越多,需要维护的外参组合越多。n 个传感器两两之间就有 n(n-1)/2 对关系,虽然有车体坐标系做中转会好一些,但每一路相对车体的外参都得定期复核。我接手过一个配置了 11 路传感器的车,光外参文件就有好几个版本在不同分支里飘,最后排查一个横向偏移花了整整两天,发现是某一路的俯仰角用了旧值。
第三笔是失效账。传感器越多,失效模式越多,而且会互相干扰。摄像头被泥水糊住会输出一张"很干净"的灰图,检测网络照样给你一堆置信度不低的框;激光雷达被雨雾衰减后,远处点云变稀疏,聚类出来的目标尺寸偏小。这些失效不像断电那样干脆,是"软失效",最难处理。
我个人倾向的配置思路是:主传感器求性能,备份传感器求异构。主传感器把性能拉满,备份的不追求精度,只追求物理原理不同、失效模式不同。摄像头怕逆光和眩光,激光雷达不怕;激光雷达怕雨雾和脏污,毫米波雷达不怕。这种异构组合的冗余价值,远大于同构的两颗摄像头。
3.2 前融合与后融合,差的不只是精度
融合层级这个话题争论了很多年,我自己的结论是:没有普适答案,但选的时候必须清楚自己付出了什么。
后融合(决策级融合)是各路传感器各自跑检测,输出目标列表,再在目标层做关联和加权。优点是模块解耦、可解释、单路坏了不影响其他路。缺点是信息在各自检测这一步就被压缩了——一个被部分遮挡的目标,摄像头可能只给出 0.3 的置信度,激光雷达因为点数少也可能给低分,后融合拿到的就是两个低分,很可能直接滤掉;但实际上两路信息合起来看,这个目标是真实存在的。
前融合(数据级或特征级)是把原始数据或中间特征在早期就合并,让网络自己去学互补关系。优点是理论上信息损失最小,对遮挡、弱光这类场景提升明显。代价是标定精度要求陡增、训练数据难配、调试时几乎没法归因——出了问题你只能说"这个融合网络不行",说不出是哪一路的问题。
我实际用下来比较稳的折中是特征级融合 + 保留各路的独立检测头作为监督。训练时每路都有自己的检测损失,推理时用融合特征出最终结果。这样既有前融合的信息互补优势,训练时又能通过单路损失快速定位是哪一路的标定或数据出了问题。这个做法不算新,但在工程上确实省了很多排查时间。
3.3 时间同步:一个10毫秒的账
时间同步这件事,我在前面几期反复提,但这期还是得再说一遍,因为它是最容易被"看起来没问题"掩盖的坑。
先算一笔最简单的账。车速 20 m/s,也就是 72 km/h,如果两路传感器的时间戳差了 10 ms,那它们在空间上描述的根本不是同一个时刻的世界,偏差是 20 × 0.01 = 0.2 米。这个 0.2 米在目标跟踪里会被理解成目标在动,从而给速度估计引入虚假分量;在融合时会被理解成两路数据对不上,从而降低关联置信度。
如果车速到 30 m/s,同样的 10 ms 就是 0.3 米。这已经超过了很多场景下安全余量的量级。
时间同步我一般分三层做。硬件层用统一的触发源给相机和激光雷达发同步信号,让曝光时刻和雷达扫描起始时刻对齐到同一个时间基准。驱动层给每一帧数据打上采集时间戳,注意这里要用硬件时间而不是软件收包时间,因为从传感器到主机中间有传输和排队延迟,软件时间戳会引入几十毫秒的抖动。算法层做运动补偿,也就是拿着自车的位姿变化把不同时刻的点云变换到同一个参考时刻。这一步很多人省掉了,觉得同步做好了就不需要补偿。但即使同步做到 1 ms,在高速下也有 3 厘米的偏差,点云拼接时会表现为地面轻微"重影",进而影响地面分割和障碍物高度估计。
提示:判断时间同步是否真的对齐,有个很土但好用的方法——找一个垂直的杆子,让车以恒定速度经过,然后把不同时刻的激光点云都变换到同一参考系里,看杆子的边缘是否锐利。如果是糊的,同步或者运动补偿一定有问题。
3.4 标定的日常维护
标定分为产线标定和在线标定。产线标定解决出厂状态,在线标定解决随时间漂移。这两件事都要,但优先级不同。
产线标定的关键是把标定条件控制住:标定场地要有足够的目标点、温度要稳定、车要空载、胎压要标准。这些条件听起来啰嗦,实际影响很大——悬挂高度变化 1 厘米,相机俯仰角就会变一点点,在 50 米外可能就带来十几厘米的投影偏差。
在线标定我用得比较多的判断手段是场景自检:车在笔直且标线清晰的路段行驶时,用车道线检测结果反推相机的俯仰和横摆角,和产线值比对。如果偏差超过阈值,就报警或者自动补偿。这个方法的优点是数据唾手可得,不需要专门的标定场;缺点是依赖车道线检测本身正确,所以只能作为趋势监控,不能作为绝对基准。
另外我要强调一个容易被忽略的点:标定参数要有版本和校验。参数文件应该带哈希值,启动时校验,加载失败就直接拒绝进入自动驾驶模式。我见过一次因为参数文件被覆盖成空文件、系统用默认值跑起来的事故,表现形式是车一直在往左偏,非常危险。
4. 定位与建图:误差会挑最坏的时机暴露
4.1 权重怎么分
多源定位的本质是一个加权问题:卫星定位、惯性导航、轮速、视觉里程计、激光匹配,每一路都有自己的置信度,融合算法要根据置信度动态分配权重。
我用得比较顺手的做法是给每一路维护一个"健康度"分数,而不是直接用原始的协方差。这个健康度综合了几个方面:原始观测的质量(比如卫星的可见星数和几何精度因子)、和上一时刻预测的一致性、以及历史表现。健康度高就多信一点,健康度低就少信,完全失效就直接权重归零并且触发降级。
这里有个实践中的坑:不要把权重调得太平滑。有些融合算法为了输出好看,把权重变化做了很长的低通滤波,结果就是在卫星信号从好变坏的那几秒里,系统还沉浸在"卫星很准"的惯性判断里,输出的位置一路飘出去,等反应过来已经偏了一米多。我的做法是让降权快、升权慢——出问题立刻不信,恢复信任要观察一段时间。这个不对称设计在很多状态估计里都适用。
4.2 误差累积的量化估算
航位推算的误差增长,新人往往只有一个模糊的"会漂"的印象。实际可以算得很清楚,算过一遍你就知道为什么必须定期用绝对观测纠偏。
假设横摆角的估计有 1 度的偏差,车辆直行 100 米后,横向位置误差大约是 100 × tan(1°) ≈ 1.75 米。如果速度估计有 1% 的尺度误差,每走 1 公里就会积累 10 米的纵向误差。这两个数字说明一件事:靠纯惯性推算,几百米内就必须有绝对观测来兜底,否则误差是指数级扩大的。
再算一个更贴近实际的:假设卫星定位在进入隧道瞬间可用,平面精度 0.3 米(这是比较保守的城区估计),隧道长 800 米,平均车速 60 km/h,也就是 16.7 m/s,通过需要约 48 秒。这段时间里只靠惯性导航推算,按中等性能的器件估算,横摆角误差可能累积到 0.5 到 1 度,对应出口处的横向误差在 7 到 14 米之间——这已经不是一个车道的问题了。
所以我给这类场景的建议是:进隧道之前必须把定位的协方差状态"冻结"并且开始膨胀,让下游的规划知道"我现在不太确定我在哪",从而主动拉开与邻车的距离、降低车速。如果下游拿到的是一个假装很准的位置,那才是最危险的。
4.3 降级链条的设计
降级不是二元的"能用/不能用",应该是分级的。我给一个我们实际用过的分级思路:
| 级别 | 触发条件 | 系统行为 | 恢复条件 |
|---|---|---|---|
| 正常 | 定位误差 3σ ≤ 0.3 m | 全功能运行 | — |
| 一级降级 | 误差 0.3 到 1.0 m | 限速降低 20%,跟车时距加大 | 误差回到 0.3 m 内持续 5 秒 |
| 二级降级 | 误差 1.0 到 3.0 m | 禁止变道,沿当前车道低速行驶 | 误差回到 1.0 m 内持续 10 秒 |
| 三级降级 | 误差 > 3.0 m 或定位模块失效 | 请求人工接管,无响应则减速靠边停车 | 需人工重置 |
这张表的价值在于,它把"定位不好"这件模糊的事,翻译成了下游能执行的具体动作。而且每一级的恢复条件都带了持续时间要求,避免在阈值附近反复横跳。
注意:降级的恢复一定要比触发更保守。我见过一个系统因为恢复条件太宽松,定位在临界值附近来回切换状态,导致车速一会儿正常一会儿限速,体感极差,后车还以为你在故意别它。
5. 预测、规划与控制:把"像人开车"翻译成数字
5.1 预测的三条路
预测模块的三条主流路线,我的看法比较直接:规则打底、学习提精度、不确定性兜底。
规则方法基于运动学和车道几何,比如恒定速度模型、恒定转弯率模型、以及"沿着当前车道线继续走"的车道跟随模型。优点是算得快、可解释、不会出现离谱输出。缺点是遇到复杂交互就失效,比如路口里两辆车互相试探谁先走,规则写不出来。
学习方法用大量真实轨迹训练,能学到一些交互模式。优点是在见过的场景里表现好,缺点是对未见场景的泛化没保证,而且输出的多模态轨迹之间需要一致性约束,否则会出现"一条往左一条往右一条直行"的组合,下游没法用。
第三条是不确定性建模。我越来越觉得这是最实用的一条——不追求预测得对,追求知道自己可能不对。输出不是一个点,而是一个随时间膨胀的概率分布,规划模块拿这个分布去做保守决策。车速越高、视野越差、目标的行为越反常,分布就膨胀得越快。
实际工程里这三条通常一起用:规则模型给出物理上合理的基准轨迹,学习模型给出交互倾向的概率修正,最后统一到一套不确定性表示上交给规划。
5.2 规划的分层结构
规划我一般拆成三层,各层的更新频率和目标完全不同。
全局层负责从起点到终点的路线,秒级甚至分钟级更新一次,用的是地图上的路网信息,输出是一串路径点。
行为层负责决策,比如"前方 200 米有慢车,是否变道"、"路口右转是等还是抢"。这一层用状态机或者有限状态集合来实现,更新频率几赫兹。这一层最容易出问题,因为它涉及大量边界条件:变道时机、让行判断、匝道汇入的抢让博弈。
局部层负责轨迹生成,十赫兹到几十赫兹,输出一条带时间信息的轨迹,包含位置、速度、加速度、曲率。这一层的约束最多:车辆动力学约束、舒适性约束、避障约束、交通规则约束。
分层的意义在于把不确定性隔离开。行为层的决策一旦定了,局部层就只管把这个决策执行得平滑;局部层如果发现执行不了,要向上反馈,让行为层重新决策。很多系统之所以"犹豫",就是因为局部层发现执行不了却不敢向上反馈,只能硬着头皮规划出一条别扭的轨迹,然后控制跟着别扭。
5.3 控制参数整定实操
控制这块我把横向和纵向分开说,因为它们的调参逻辑差别很大。
横向控制主流是纯跟踪、Stanley 或者模型预测控制。我用纯跟踪举例子,因为它参数少、好理解。核心参数是前视距离 L,经验公式是 L = k × v,其中 v 是车速,k 一般取 0.5 到 1.2 之间的系数。车速 10 m/s、k 取 0.8,前视距离就是 8 米。前视距离太小,车会左右画龙;太大,弯道会切内道。我实测下来的调法是从小往大试:一开始取 k=0.5 保证跟踪紧,然后逐步加大到刚好不震荡为止,通常落在 0.7 到 1.0 之间。
纵向控制就是一个带前馈的 PID。核心不是调 PID 三个参数,而是把前馈项做对。车辆的纵向动力学近似是 a = 驱动/制动 − 阻力项,阻力项包括滚阻、风阻、坡度。如果前馈只按目标加速度给,上坡时就会持续掉速,然后积分项慢慢补上来,表现为"上坡先慢半拍再追"。正确的做法是把坡度估计和滚阻风阻都放进前馈,PID 只负责消除残差。这样积分增益可以取很小,避免积分饱和导致的下坡超速或者停车时的"点头"。
我给一组实际能用的起始参数:纵向 PID 的 Kp = 0.8,Ki = 0.15,Kd = 0.02,采样周期 50 ms,前馈项包含坡度补偿和滚阻补偿。这组参数在 1.5 吨左右的小型车上表现不错,换车型需要重调,因为质量和制动响应特性变了。
5.4 舒适性指标要把数字写死
"舒适"这个事必须量化,否则没法评审。我用的参考值是这样的:
| 指标 | 舒适区间 | 可接受上限 | 备注 |
|---|---|---|---|
| 纵向加速度 | −1.5 ~ 1.5 m/s² | ±2.5 m/s² | 急刹会明显超过 |
| 纵向 jerk | ≤ 2.5 m/s³ | 5 m/s³ | 顿挫感主要来自这个 |
| 横向加速度 | ≤ 1.5 m/s² | 3 m/s² | 超过 3 乘客会明显被甩 |
| 曲率变化率 | ≤ 0.01 1/m/s | 0.02 1/m/s | 方向盘抖动的主因 |
跟车距离我用时距模型:期望距离 = 时距 × 车速 + 最小静止距离。时距取 1.5 秒,最小距离取 5 米。车速 20 m/s 时期望距离就是 1.5 × 20 + 5 = 35 米。这个时距在通畅路况下偏保守,但保守的代价主要是被加塞,激进的代价是追尾,这个权衡我永远选保守。
6. 数据闭环与仿真验证:量产前的最后一道闸
6.1 数据回流的触发条件要设计,不能靠人工
数据闭环最怕的是"人工挑数据"——谁觉得哪段路有意思就上传哪段。这种方式在项目早期还行,规模一上来就完全失控,因为你永远在补最近一次事故的洞,而不是在系统性地提升覆盖。
我的做法是把触发条件写死在车端,分三类。第一类是系统异常触发:接管、急刹、规划失败、降级、时延超阈值。第二类是不确定性触发:感知置信度低、定位协方差大、预测分布宽。第三类是场景触发:按地图上的特定区域(复杂路口、隧道、匝道)或者按场景分类器识别的结果自动打标。
第二类最容易被忽略,但价值极高。因为系统自己觉得"我不确定"的那些时刻,恰恰是数据分布里最缺的样本。比起人工去翻几千公里的日志,这种自动筛选效率高一个数量级。
上传策略我也做了分级:异常触发的完整上传原始数据,不确定性触发的只上传压缩后的特征和关键帧,场景触发的按时段切片上传。这样能控制流量成本——全量原始数据一秒一个多 G,谁都传不起。
6.2 场景库要分层,别一锅炖
场景库我按三个维度分层。按功能维度:跟车、变道、路口通行、匝道汇入、避让、泊车。按难度维度:典型、边界、极端。典型场景占大多数但价值最低,边界场景是真正拉开差距的地方,极端场景用来验证不崩溃。按来源维度:实车采集、仿真生成、人工构造。
三层的组合里,我投入产出比最高的是"边界场景 × 实车采集"这一格。因为它既真实又稀缺,而仿真生成的边界场景往往会因为物理模型简化而失真。
覆盖率怎么衡量,我给一个实操的口径:不要追求"跑过的里程数",要追求"触发过的不确定性类型数"。里程是线性增长的,不确定性类型是有限的,后者更容易收敛,也更能说明问题。
6.3 仿真和实车的置信度怎么对齐
仿真最大的问题不是不够真实,而是你不知道它哪里不真实。所以我一般不追求把仿真做得越来越像,而是做"相关性校准"。
具体做法是:挑几十个实车能复现的场景,在仿真里跑同样的场景,对比关键指标——刹车触发点、最大减速度、轨迹偏离量。如果仿真里的刹车点比实车晚 5 米,那就说明仿真的感知时延建模偏乐观,需要加上这段时间。校准完一轮之后,仿真结果才有参考价值。
我个人的经验是,仿真适合验证逻辑正确性(状态机跳转对不对、降级链条通不通、边界条件有没有漏),实车适合验证体验和稳定性(顿挫、犹豫、长时漂移)。这两件事不要互相替代,我见过用仿真数据去证明"体感舒适"的,这就有点自欺欺人了。
7. 常见问题与排查实录
7.1 一份可以直接用的速查表
| 现象 | 大概率的根因 | 快速验证方法 |
|---|---|---|
| 车辆沿车道轻微画龙 | 横向控制前视距离过小,或规划曲率不连续 | 打印规划输出的曲率序列,看是否阶梯跳变 |
| 直线行驶出现规律性横向偏移 | 相机外参横摆角偏差,或轮速标定尺度误差 | 用清晰标线路段反推相机角度与标称值比对 |
| 加塞车辆识别滞后 | 时间同步偏差,或跟踪器关联门限过紧 | 查时间戳差值,检查新目标初始化帧数 |
| 上坡掉速后突然追速 | 纵向控制前馈缺坡度补偿,积分饱和 | 看前馈项是否包含坡度,看积分项是否打满 |
| 定位在隧道出口大幅偏出 | 惯性推算误差累积,协方差未膨胀 | 回放隧道数据,看协方差曲线是否单调增 |
| 同一路口有时犹豫有时果断 | 行为层状态机边界条件重叠,决策无优先级 | 打日志看同一输入是否产生不同决策 |
| 雨天远处点云突然消失 | 激光衰减,聚类尺寸偏小后被动滤除 | 对比干湿路面同距离点云数量 |
| 停车瞬间前后点头 | 纵向控制末端增益过大,缺末端减速度规划 | 看最后 2 米的目标减速度曲线 |
7.2 几个说不出但很气的坑
第一个坑是坐标系约定不统一。车体坐标系到底是 x 向前还是 y 向前、角度是顺时针还是逆时针、单位是度还是弧度,这几个问题在每个跨模块的接口上都可能出现分歧。我们曾经因为一个模块把航向角当成逆时针、另一个当成顺时针,导致车在环岛里往反方向打了一把方向。最后是靠强制所有接口必须带单位后缀(比如 yaw_rad、yaw_deg)才根治的。这个规范土,但真的有用。
第二个坑是日志不够定位问题。早期我们的日志只记录模块输出,出了问题只能猜。后来改成关键中间量全记:时间戳、输入输出、置信度、降级状态、决策理由。日志量大了不少,但排查效率提升得更多。我的判断标准是:任何一个线上问题,如果不能在半小时内从日志里定位到具体模块,那就是日志设计有问题。
第三个坑是**"偶发"被当成"不重要"**。有个横向偏移的问题,一千公里出现两三次,一直被排到低优先级。后来发现触发条件是某个特定角度下的逆光加上一段特殊曲率的弯道,概率低但一旦触发偏移量接近半米。偶发不等于轻微,概率和严重度要分开评估。
第四个坑是参数没有单一可信源。同一组控制参数在三个地方各存了一份,改了一处另外两处没改,实车表现和仿真完全对不上。后来我们把所有可调参数集中到一个配置仓库,带版本号和变更记录,任何一次实车测试都必须记录所用的参数版本。这件事做完之后,"这个版本为什么变差了"这类扯皮基本消失。
第五个坑是过度依赖单一指标。有一段时间我们只盯接管次数,结果为了降低接管次数,系统变得越来越保守,最后变成了"能不动就不动",接管次数确实降了,但通行效率低到没人愿意用。指标一定要成对设计:效率配安全,舒适配通行,单指标优化必然跑偏。
我个人在这个方向做了这么久,最深的体会是:这套系统的难点从来不在某个算法有多精妙,而在于你能不能把几十个模块的时钟、坐标、单位、边界条件、失效路径全部对齐成一套自洽的约定。前面十九期我讲了很多单点的技巧,到这一期才敢说,真正让一辆车从"演示"走到"可用"的,是这些看起来最不性感的东西——一份写清楚的接口契约、一张量化过的降级表、一套能复现的日志。谁把这些做扎实了,谁的系统就更抗造。