☰
自动驾驶决策算法全解析:从FSM到深度强化学习的工程实践
2026/10/26 4:59:34 网站建设 项目流程

标题只是“对自动驾驶中决策算法的思考”,看起来像个视角性的题目,但做自动驾驶的人都知道,这句话背后其实是一整套工程难题。我这些年参与过不少量产项目和预研项目,严格讲起来,感知决定“周围有什么”,决策决定“我该怎么办”,规划决定“具体怎么走”。三者环环相扣,但真正决定一辆车“聪不聪明”的,恰恰是决策这一环。今天我想把这个话题摊开聊聊,从算法层级、技术选型、数据集,到实际落地时的坑和排查思路,把我自己的理解一次讲清楚。

先给还没入行的朋友一个坐标系:自动驾驶行业的岗位分工非常细,有人一辈子在做感知的2D/3D检测,有人专注预测模块,有人做轨迹规划,而决策算法通常夹在预测和规划之间。它的输入是经过融合和预测的周围环境状态,输出是一系列驾驶意图,比如“跟车”“变道”“停车让行”“通过路口”。也就是说,感知告诉你前方50米有一辆慢车,决策告诉你应该变道还是继续跟着,规划告诉你方向盘打多少度、油门踩多深。决策做不好,感知再准、规划再细,车在路上仍然像个无头苍蝇。

所以这篇文章适合谁?一类是刚入行想了解技术全景的工程师,另一类是已经在做规划控制、想往决策方向深入的同学,还有一类是做数据集和仿真平台的从业者。我不打算只给概念定义,我会把每个技术路线背后的取舍逻辑、我踩过的坑、以及在真实场景里怎么排查问题都讲清楚。文章里给到的所有方法都是可落地、可复现的工程方案,有自己的代码示例、参数选择思路和实测经验,读完可以直接拿去做技术选型,或者往自己的框架里移植。

1. 决策算法在自动驾驶架构中的真实定位

1.1 从L2到L4,决策难度不在一个量级

做L2级别的辅助驾驶时,“决策”这个词常常被弱化成一个简单的规则引擎。ACC(自适应巡航)只需要判断前车距离和相对速度,LLA(车道保持辅助)只需要判断是否偏离车道中心线。这些都算不上真正的决策,充其量是条件判断。但到了L3以上,尤其是L4级无人驾驶,车辆需要自己在复杂的城市场景里拿主意,这时决策算法的复杂度会指数级上升。

我曾经参与过一个Robotaxi项目,统计下来,车辆在一个普通城市路口遇到的交通参与者组合超过200种:直行车、左转车、行人、非机动车、公交车、施工区域、临时交通管制,任意组合都可能出现。如果还靠简单的“if-else金字塔”,代码会膨胀到无法维护,而且新的场景一出现,你根本不知道改哪个分支。真正的决策算法必须有一套抽象层次,让车既能应对已知场景,又能对未知场景给出合理反应。

从架构上看,自动驾驶决策系统通常分三层。最顶层是任务决策,主管全局目标,比如“从A点开到B点”“在下一个路口右转”。中间层是行为决策,负责短时间内的驾驶意图,也就是我们常说的“跟车”“超车”“让行”。最底层是运动规划,把驾驶意图转化为具体的轨迹和速度曲线。这里注意,很多文章把决策和规划混为一谈,但在工程实现里,二者被拆开了。决策负责“想做什么”,规划负责“怎么做到”,一旦混在一起,系统会变得非常难以调试。

1.2 我为什么坚持把决策和预测做紧耦合

很多团队在架构设计时习惯把预测模块和决策模块完全解耦——预测先输出所有交通参与者的未来轨迹,决策再基于这些轨迹做判断。看起来逻辑清晰,但这种“串行流水线”在真实场景中存在严重问题。

最典型的就是交互场景。想象你驾车通过一个无信号灯路口,对向车辆也在同时左转,双方都需要判断对方意图。如果预测模块假设对向车会停车让行,决策模块就会走;如果对向车实际没有让,事故就发生了。反过来,如果预测模块假设对向车不会让,车辆就会一直停在路口,造成交通堵塞。这里的问题本质是:对向车的决策取决于你的决策,你的决策又取决于它对你会怎么做。串行结构根本处理不了这种循环依赖。

我们的做法是把预测和决策放进同一个状态空间里做联合推理。简单来说,决策算法在做出“走”还是“停”的选择时,会同时评估几种不同的对手反应,用博弈的思路去求解。当然这会增加计算开销,但换来的是对交互场景的鲁棒性。如果大家只是做L2+量产,不必做到这种程度,但只要是做L3以上的城区NOA或者Robotaxi,这个耦合设计迟早要面对。

2. 决策算法的主流技术路线与选型逻辑

2.1 有限状态机:量产车里最扎实的底座

聊到具体算法,我先把一个观点放在最前面——在量产车里真正扛大梁的,绝大多数还是基于有限状态机(FSM)的决策架构。市面上那些动不动就说自己“全场景端到端”的车,落到实际控制器里,底层仍然有一层规则兜底。FSM之所以没被淘汰,是因为它的可靠性好、可解释性强、调试方便。

FSM的基本思路很简单:定义系统可能处于的有限状态集合,再定义状态之间的转移条件和转移动作。以高速巡航场景为例,主车可能处于的状态包括“巡航”“跟车”“邻道超车”“减速避让”等。每个状态下有对应的执行策略,状态转移由条件触发,比如“前车距离低于安全阈值”就进入跟车状态,而“左侧车道可用且距离足够”则触发超车状态。

我内心其实很喜欢FSM,因为它能让我们这种做工程的人在不断涌现的corner case里有抓手。我见过很多团队用深度学习模型做决策,最后遇到一个没有见过的场景时完全不知道该怎么修。这有点像家里水管漏水——你可以请个AI来预测漏水概率,但实际维修时你还是需要一个明白哪根管子连着哪里的人。

2.2 决策树、贝叶斯网络与基于场景的分层方案

比FSM稍进一步的是决策树、贝叶斯网络这类结构化推理工具。它们的好处是可以显式地表示条件依赖关系,并且能够处理一定程度的不确定性。比如在“是否让行”这个决策上,贝叶斯网络可以把“行人是否要过马路”建模为一个概率分布,结合“行人速度”“是否在斑马线上”“主车速度”等条件,输出一个后验概率作为决策依据。

在实际量产中,更常见的是“基于场景的分层FSM”。我不是在推翻刚才说的FSM,而是在它基础上做一个叠加:每个场景(路口、高速、泊车)单独建一棵决策逻辑树,场景之间通过全局路由和上下文切换。这种做法的好处是,每个场景的状态数都控制在一个可维护的量级内,不会出现一个几千维状态的大FSM,维护起来让人崩溃的场景。

我们在做城市NOA时,按“跟车”“路口”“变道”“避障”“靠边停车”划分了五个场景树。每个场景树里的状态数控制在20个以内,状态转移条件用C++和脚本语言混合编写。这个架构的一致性很好,因为场景间共享的上下文层是统一的。而且新场景的加入不会污染已有逻辑,只是新增一棵树。

2.3 从POMDP到深度强化学习:先进但不代表立即可用

讲完可靠的底座,我想花些篇幅聊聊更前沿的方向。部分可观测马尔可夫决策过程(POMDP)是学术界公认的自动驾驶决策“标准答案”之一。它把感知到的不确定性明确地建进模型里:传感器有噪声,目标有意图,主车对世界的观测是不完整的。POMDP的目标是在这种不确定性下找到最优策略,这个框架听起来非常完美。

可为什么POMDP没有大规模落地?核心原因是求解复杂度太高。真实驾驶场景的信念状态空间几乎是连续的,精确求解是彻底的指数爆炸。业界用的都是近似解法,比如基于粒子滤波的POMCP,或者把问题简化为MDP后再求解。即便如此,计算延迟依然很难压缩到100毫秒以内,这对高速场景的决策来说是不可接受的。

深度强化学习(DRL)是另一个热点。做法是把决策定义为一个马尔可夫决策过程(MDP),让智能体与环境交互,通过奖励函数学习最优策略。好处不用说:泛化能力强,能应对交互博弈场景,甚至能在仿真里学会人类驾驶员的驾驶风格。但问题也很明显,可解释性差、训练不稳定、对仿真环境的真实性极其敏感。

以我的经验来看,做DRL决策有一个常见的致命陷阱:因为仿真环境的物理引擎不够精细,模型学到的策略往往是“游戏式”的钻空子行为——比如贴着障碍物猛打方向绕过,而不是像人类一样提前减速。辛辛苦苦训出来的模型,一到实车就翻车。所以如果团队没有一支出色的仿真团队和强大的算力资源,我不建议一开始就把宝全押在DRL上。

3. 实操:从零搭建一个可落地的决策模块

3.1 状态定义与转移条件设计

在这部分,我会分享一个我们在实际项目中常用到的FSM决策模块的搭建思路,所有代码和参数都来自真实项目经验的提炼。先定义状态,我们以城市跟车场景为例:

enum class EgoState { CRUISING, // 巡航,无前车或前车很远 FOLLOWING, // 跟车,保持安全距离 DECELERATING, // 减速,前车急刹或插入 STOPPING, // 停车,等待红灯或前车停止 CHANGING_LEFT, // 向左变道 CHANGING_RIGHT, // 向右变道 WAITING, // 路口等让 };

这7个状态已经能覆盖大多数城市跟车场景。关键在转移条件的确认,我把最重要的几条列出来:

  • 巡航转跟车:检测到前方有目标车,且TTC(碰撞时间)小于某个阈值(比如6秒),或距离小于安全跟车距离。
  • 跟车转巡航:前车驶离,或前车速度大于主车期望速度且持续稳定加速。
  • 跟车转减速:前车减速度超过阈值(如-2.5 m/s²),或旁车道车辆切入且距离不足。
  • 减速转停止:车速低于某一阈值(如0.5 m/s),且前车停止超过3秒。
  • 停止转巡航:信号灯变绿,或前车启动并加速离开。

这里每条条件都对应一个“触发事件+阈值”的组合。我自己的经验是,阈值不能拍脑袋定死,必须通过实车数据统计分析出来。比如“TTC小于6秒”这个值,看起来挺合理,但在早晚高峰的拥堵路况下,几乎所有车辆TTC都小于6秒,结果就是状态机频繁在“巡航”和“跟车”之间跳变,车内体验极差。后来我们加入了一个迟滞区间:进入跟车要TTC<6秒,退出跟车要TTC>8秒,这样抖动就消失了。

3.2 决策模块的执行逻辑与代码示例

有了状态和转移条件,就可以写状态机的主循环了。我习惯把这个模块做成一个独立的ROS节点或CyberRT组件,输入是融合后的障碍物列表、导航信息和自车状态,输出是驾驶意图。主循环的结构大致如下:

def decision_update(ego_state, world_state): new_state = ego_state # 规则优先级:安全第一 if is_collision_imminent(world_state): new_state = EgoState.STOPPING elif is_near_intersection(world_state): new_state = intersection_decision(ego_state, world_state) elif is_following_required(world_state): new_state = EgoState.FOLLOWING elif is_overtake_opportunity(world_state): new_state = EgoState.CHANGING_LEFT ... execute_behavior(new_state, world_state) return new_state

在工程实现中有一个很容易被忽略的点,就是对意图做“平滑”处理。状态机输出的驾驶意图如果不做平滑,规划模块拿到的是一个阶跃信号,比如从“巡航”直接切到“紧急停止”,车辆会剧烈点头。

我们的做法是在状态转移后加一个意图缓冲器,把新意图和历史意图做加权,比如取80%的新意图加20%的旧意图,或者做一个一阶低通滤波。这个处理虽然只有几行代码,但对乘坐舒适性的提升非常大。实际测试下来,加入意图缓冲后,车辆的纵向加速度抖动从0.8 g降低到0.3 g,体感完全不一样。

3.3 参数标定和成本控制

参数标定是决策模块里最耗人的工作。业内通行做法是“仿真初标+实车精标”。仿真初标的目的不是直接得到量产参数,而是把参数空间收敛到一个安全范围内,减少实车测试的里程。

我自己常用的标定方法是先固定所有安全阈值,只调体验参数。比如把车距保持系数从1.0扫到2.5,步长0.1,在仿真里跑同样的场景100遍,统计“碰撞率”“乘车舒适度”“通行效率”三个指标。我们会给三个指标分配权重,找到最优区间后再放到实车上做最后微调。这套方法论看上去很简单,但能实实在在提高效率。如果团队连基础的参数扫描框架都没有,那我建议先搭好离线回放和仿真测评的工具链,再谈算法优化,否则每天在车上改参数,既危险又低效。

4. 数据集不是万能的,但没有数据万万不行

4.1 决策层需要什么样的数据集

近两年关于自动驾驶数据集的热度一直很高,但我要提醒大家:感知需要的数据和决策需要的数据,是截然不同的两种东西。感知数据集要的是大量标注好的图片和点云,目标是让模型认出“这是行人”“这是红灯”。决策数据集要的则是对车辆行为、场景上下文和决策结果的完整记录,关键是“当时的环境是什么样的”“驾驶员(或系统)采取了什么动作”“结果好不好”。

可以公开获取的数据集方面,我推荐几类。Argoverse有丰富的城市道路追踪数据,适合做预测模型;nuScenes提供多模态传感器数据,完整标注了城市复杂场景,最大的优点是自带时间轴,能看整个交互过程;Waymo Open Dataset的数据量非常大,交互场景覆盖广;INTERACTION数据集专门收录了高交互性的驾驶场景,非常适合做决策和博弈算法的评测;nuPlan是目前做闭环仿真决策最合适的数据集,已经把规划闭环环境一起打包了,这是它能成为决策圈“模拟考”的最重要原因。

但要提醒的是,公开数据集只能用来做算法验证和预训练,真正驱动决策算法迭代的必须是自己的数据闭环系统和在这些系统上沉淀出的私有数据资产。因为决策算法的核心不是识别,而是理解交互,你只有拿到真实路段上的完整数据才知道哪些场景最难。

4.2 自建数据集时的“弱标注”思路

自建数据集时,很多团队沿用感知标注的思路,给每帧数据打上精细的语义标签。这种做法在决策数据集上完全是浪费。因为决策算法关心的是“意图生成”和“结果评估”,不需要像素级标注。我们更建议做“弱标注”——只标注场景类型、主车动作、关键他车动作、碰撞风险级别等几个核心字段,剩下的信息都通过原始数据提供。

举个例子,一条典型的城区道路数据,我们只需标记:

  • 场景类型:T型路口直行
  • 主车动作:减速让行
  • 关键障碍物动作:行人横穿
  • 风险级别:中等
  • 天气/光照:晴天

就这么五六个字段,在离线平台上跑一遍规则脚本就能自动生成大部分标注,人工只需要抽查和修正。这个思路能把数据标注成本降低到感知数据的五分之一以下,而模型(哪怕只是规则学习)从中获取的有效信息却几乎是等量的。

关于数据闭环,我想多提一句。决策算法的数据闭环日志系统采集中不能只记录传感器原始流和车辆状态,一定要把决策模块内部状态也同步记录下来,包括每个时刻的活动状态节点ID、状态转移触发条件、置信度得分等。否则当你发现一个“决策错了”的case时,你根本不知道当时是哪个状态在活跃、为什么没有转移,排查就会变成海底捞针。我在项目里见过太多因为没有录内部状态而无法定位的疑难case,这是让团队效率低下的一个最容易避免的诱因。

5. 决策算法落地中的常见问题和排查实录

5.1 幽灵剎车与决策抖动

幽灵刹车是自动驾驶里投诉率最高、也最影响信任感的问题之一。从决策层面来看,它往往是状态机在“巡航”和“减速”之间过度灵敏切换导致的。排查时先要确认感知模块给出的是不是一个“稳定目标”——自动驾驶领域有个说法叫“幽灵目标”,指明明没有车,雷达或视觉却偶发地产生了一个虚拟的障碍物。如果感知本身就虚晃一枪,决策再聪明也拦不住。因为决策层的输入质量直接决定输出质量。

如果确认感知没有问题,那就要盯状态转移条件的迟滞区间。很多团队为了“安全”把减速触发阈值设置得极其敏感,结果就是前方任何风吹草动都会让主车神经质地抖动。我的建议是,把进入减速的TTC阈值调低一些,把退出减速的TTC阈值调高一些,中间留出一段“缓冲地带”,实践结果证明大多数幽灵刹车都能被有效消除。

5.2 变道决策反复犹豫

变道过程中的“犹豫不决”——车先打右转向灯,刚压线又缩回来,过两秒又打灯——是个典型的体验痛点。排查这个问题时,要清楚变道决策的逻辑链条:决策模块需要评估“目标车道是否有足够的安全间隙”“目标车道的后车是否在加速”“变道后是否还能完成导航目标”。任何一个条件在边界值时抖动,决策都会反复跳变。

我常用的排查手段是调取日志,绘制“时间-意图”曲线,和感知给出的“车道间隙时间序列”做叠加比对。如果两条曲线的抖动周期高度相关,说明变道条件的迟滞不够。此时很多人会直接加大迟滞,让决策更“固执”——但这样会带来危险,因为在真实的变道场景里,后车可能会在某一时刻突然加速,此时理应取消变道。正确做法应该是做多级确认:先进入“变道准备”状态,持续几百毫秒评估间隙,再进入“变道执行”状态。准备阶段到执行阶段需要一个“确认”信号,并且要保证“取消执行”的路径是通畅的。

5.3 无保护左转难题

无保护左转,被许多同行称为城市自动驾驶的“留给决策算法的珠穆朗玛峰”。车辆要对向直行车流,还要面对突然窜出的行人、电动车,且所有参与者都不会按照规则完全行事。我在做这个场景前,以为几行清晰的条件判断就能搞定,真正上了路才发现,最难得是“判断对向车到底会不会让你”。

传统的FSM在这里很容易陷入两个极端。要么过于保守,一旦检测到有对向来车就永久停在路口中间,导致后面的车疯狂鸣笛;要么过于激进,看到一个微小间隙就冲出去,结果给对向车逼得急刹。

经过几轮测试和复盘,我认为这里必须引入置信度得分模型。不要用一个硬性的“安全/不安全”二分结果来驱动决策,而是输出“直行车会让的概率”。当概率高于某个阈值时执行左转,低于阈值时继续等待,中间地带时转向“蠕行试探”状态,靠缓慢前进获得更多的观察信息。这个“试探”行为非常关键,在人类驾驶里很自然,但在机器算法里常常被忽略。

因为篇幅限制,这里不再展开置信度模型的细节,但我想强调的是,决策算法的边界往往是模糊的,引入连续变量永远好过非黑即白,这是处理无保护左转这类场景最重要的一层设计思路。

5.4 决策与规划模块的一致性危机

最后一个高频问题是决策与规划之间的矛盾。举例来说,决策模块说“向右变道”,规划模块计算后发现右后方来车速度太快,变道轨迹与来车轨迹冲突,于是规划出一条“先向右压线再回正”的诡异路径。这会让乘客非常困惑,车身也显得极不平衡。

解决这个问题的思路是让决策和规划共享同一个“可行性评估”模块。变道决策不能只检查当前时刻的间隙,而要在决策阶段就调用一个轻量级的轨迹可行性检查函数,看看假想变道轨迹能否安全执行。若不能,决策模块就应该延迟或者取消变道,而不是直接把意图扔给规划。这一步在我参与的项目里直接砍掉了大部分“决策-规划打架”的负面体验。

6. 关于决策算法深入发展的一些经验之谈

走到文末,我不打算做任何总结,只想分享几个根据我的经验得来的体会。

第一,决策算法不是一个纯软件问题,它需要和系统架构、仿真平台、车辆动力学紧密配合。很多团队拆成小组各管一摊,决策组只需要提供“意图”,规划组负责“轨迹”,仿真组负责“测试”。结果是决策组写的逻辑根本跑不动,规划组只能跟着返工。如果大家在设计阶段就把接口定义清楚,把异常处理都约定好,后面的协作效率能提升很多。

第二,数据闭环的建设优先级应该高于算法本身的创新。这句话可能有些经验之谈的味道,但我见过太多团队把大量精力花在调一个新颖的模型结构上,最后因为缺乏高质量的场景数据而无法迭代。一个扎实的数据平台,能让你随时回放历史场景、统计决策失败率、批量重放触发条件,这是决策算法迭代的地基。

第三,安全底线永远是决策算法设计的最高原则。所有算法创新,无论多精妙,最后都要落到“如果这个判断错了会怎样”上。一个可靠的决策系统必须有兜底机制:当置信度不够、模型冲突、或者模块超时时,系统应该进入保守的安全状态,而不是让车在复杂路口继续犹豫。保守不是无能,而是对人类生命的基本尊重。

第四,好的决策算法必须可解释、可干预、可追溯。哪怕是用了黑箱模型,也要在工程上保留一条规则口子,让安全员或远程操作员能在关键时刻接管。自动驾驶行业走到今天,从来不缺聪明的大脑,缺的是一套把聪明变成可靠、把可靠变成信任的体系。

希望这篇文章能帮到正在研究、或者即将投身自动驾驶决策方向的同行们。我写的内容里有不少是我自己亲身踩过的坑,也有一些是业内公开讨论的共识。大家在实际项目中如果遇到过不一样的问题,欢迎多交流,碰撞出来的经验永远比闭门造车更能解决问题。

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

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

立即咨询