自动驾驶汽车 自动驾驶汽车(self-driving car)是商业上最成熟的自主系统,它把感知、预测、规划和控制整合进一辆车里。本文件涵盖自动驾驶软件栈、高精地图、运动预测、规划、端到端驾驶、仿真、安全标准与自动驾驶等级。 自动驾驶汽车可以说是目前在大规模尝试的最难的机器人问题。与在受控环境中运行的工厂机器人不同,自动驾驶汽车必须应对开放世界:不可预测的人类驾驶员、乱穿马路的行人、一夜之间冒出来的施工区,以及每分钟都在变化的天气。 代价也独特地高。自动驾驶汽车在高速公路车速下穿行于脆弱的道路使用者之间。对安全关键的失效而言,容错几乎为零。
自动驾驶汽车(self-driving car)是商业上最成熟的自主系统,它把感知、预测、规划和控制整合进一辆车里。本文件涵盖自动驾驶软件栈、高精地图、运动预测、规划、端到端驾驶、仿真、安全标准与自动驾驶等级。
自动驾驶汽车可以说是目前在大规模尝试的最难的机器人问题。与在受控环境中运行的工厂机器人不同,自动驾驶汽车必须应对开放世界:不可预测的人类驾驶员、乱穿马路的行人、一夜之间冒出来的施工区,以及每分钟都在变化的天气。
代价也独特地高。自动驾驶汽车在高速公路车速下穿行于脆弱的道路使用者之间。对安全关键的失效而言,容错几乎为零。
感知(本章第 1 节已介绍)把原始传感器数据处理成结构化的场景表示:检测到的物体及其 3D 位置、速度和类别标签;车道标线;交通灯;可驾驶表面的边界。
预测预报其他智能体(车辆、行人、骑行者)在未来将如何运动。给定当前场景状态,预测模块在每个智能体上输出一条覆盖某个时间范围(通常是未来 3-8 秒)的轨迹。
规划决定本车(ego vehicle)该做什么:跟随哪条路径、何时变道、何时让行、何时加速或刹车。它接收预测后的场景,为自车产生一条安全、舒适且能朝目的地推进的轨迹。
控制把规划好的轨迹转化为执行器命令:方向盘转角、油门和刹车。这是最低层,把抽象的轨迹翻译成物理运动。
模块化设计有明显的工程优势:每个模块都可以独立开发、测试和改进。但它也有弱点:误差会向下游传播(一次漏检对规划器来说是不可见的),而信息在每个接口处都会损失(规划器看到的是边界框,而不是产生这些框的丰富传感器数据)。
高精(High-Definition,HD)地图是详细的、厘米级精度的数字地图,编码了道路结构:车道边界、车道连通性(在路口哪条车道连到哪条)、交通标志位置、限速、人行横道位置以及路面高程。
HD 地图为驾驶任务提供了强有力的先验。感知模块不必每帧都从头发现车道边界,只需把车辆定位到地图中,并核实现实是否与存储的结构相符。这极大地简化了规划。
构建 HD 地图需要装备高端 LiDAR、摄像头和 RTK-GPS 的专用测量车。地图还必须随道路变化而维护和更新。这很昂贵,也很难扩展到地球上的每一条道路。
无图驾驶(mapless driving)(也叫"在线建图")旨在消除对预建 HD 地图的依赖。相反,车辆用自己的传感器实时构建局部地图。像 MapTR 和 MapTRv2 这样的模型使用 transformer 架构直接从摄像头图像预测向量化的地图元素(车道中心线、道路边界、人行横道),把折线作为有序点序列输出。
无图方案用地图精度换可扩展性:凡是车能开上去的路,它都能建图。但它要求感知系统足够鲁棒,能实时检测所有相关的道路结构,包括在复杂的路口、高速公路匝道和施工区。
实践中,许多系统采用混合方案:一张带有粗略道路拓扑的轻量地图(来自现有的地图供应商),再由车辆传感器实时丰富。
预测其他道路使用者会去哪里,是自动驾驶中最难的子问题之一。人类不可预测,意图是隐藏的,而可能未来的空间会迅速分叉。
预测模型的输入是场景上下文:所有检测到的智能体在最近过去(通常是 1-2 秒历史)的位置和速度,加上静态上下文(车道几何、交通信号、道路边界)。
输出是每个智能体的一组预测轨迹,通常覆盖未来 3-8 秒。由于未来不确定,好的预测模型会输出多条带概率的可能轨迹,而不是单个点估计。
轨迹预测作为一个回归问题:预测每个智能体在未来离散时间步的未来 (x, y) 坐标。损失通常是 K 条预测轨迹上的最小平均位移误差(minADE):
这是一个"K 中取最优"的指标:只要 K 条预测中有任何一条接近真值,模型就得分。这鼓励多样化、多模态的预测。
**社会力(social forces)**把行人行为建模成一个动力学系统,每个人受到吸引力(朝向目标)和排斥力(远离其他行人和障碍物)。人 i 的加速度为:
这是一组微分方程,类似于本章第 2 节的机器人动力学方程。这个模型很优雅,但依赖手工调参的力参数,在复杂的多智能体交互中表现吃力。
**图神经网络(Graph Neural Networks,GNN)**用于预测时把场景建模为图:每个智能体是一个节点,边表示空间关系(邻近、共用车道)。节点之间的消息传递捕捉交互:"这辆车正在给那个行人让行"或"这两辆车正在汇入同一条车道"。
现代预测架构(如 MTR、QCNet)使用基于 transformer 的模型,联合推理智能体历史、地图上下文和智能体间的交互。智能体通过交叉注意力关注相关的地图特征(当前车道、即将到来的路口)和其他智能体(前方的车、人行横道上的行人)。输出是通过自回归或混合模型生成的一组轨迹假设。
目标条件预测先预测一个智能体可能去哪里(一组候选目标点,如车道端点或路口出口),再预测到达每个目标的轨迹。这把问题分解为"去哪里"(离散、可控)和"怎么去"(给定目标的连续路径),使多模态预测问题更易处理。
给定预测后的场景,规划器必须为本车产生一条轨迹。这是一个受约束的优化问题:找到一条安全、舒适、高效且合法的轨迹。
基于规则的规划器把驾驶行为编码为一组 if-then 规则:"如果人行横道上有行人,就让行","如果与前车的时距小于 2 秒,就不要变道","如果接近红灯,就减速停在停止线"。这些规则可解释、可审计,但在复杂场景下会变得臃肿(上千条规则、许多边缘情形、规则之间的相互作用)。
基于优化的规划器把驾驶表述为轨迹优化。本车轨迹被参数化(例如未来时间步的一串 (x, y, \theta, v) 状态),最小化一个目标函数:
进展项惩罚偏离期望路线。舒适项惩罚高横向加速度、急动度(加速度的导数)和突兀的转向,因为乘客能感受到这些。安全项惩罚靠近其他智能体,用预测轨迹评估碰撞风险。
这是受约束优化(第 3 章):在不等式约束下最小化代价函数。权重 w_1, w_2, w_3 在相互竞争的目标之间权衡(激进驾驶更快,但更不舒适也更不安全)。
基于学习的规划器使用在人类驾驶数据上训练的神经网络来生成轨迹。模型观察场景并直接输出规划轨迹,从人类专家驾驶的示例中隐式地学会复杂的权衡。
优点是人类驾驶行为被整体捕捉,包括那些微妙、难以形式化的方面:并线时该多激进、在路口该往前蹭多少、该给骑行者留多大空间。缺点则是与模仿学习(第 2 节)相同的分布偏移问题:模型在训练数据中表征不足的情况下可能行为不可预测。
端到端驾驶完全去除模块边界。单个神经网络接收原始传感器输入(摄像头图像、LiDAR 点云),直接输出驾驶命令(方向盘、油门、刹车)或一条规划轨迹。没有独立的感知、预测或规划模块。
它的吸引力在于整个系统针对最终任务(安全驾驶)被联合优化,因此没有信息在模块边界处损失。感知模块学会精确地提取规划器所需的特征,而不是那些可能与任务无关的通用物体检测。
UniAD(Unified Autonomous Driving)是一个里程碑式的端到端架构。它通过 BEV 编码器处理多摄像头图像,然后施加一串基于 transformer 的模块级联:跟踪、在线建图、运动预测、占用预测和规划。虽然它内部有模块,但它们都是可微的,并且端到端联合训练,规划损失会反向传播穿过整个网络。
UniAD 中的规划模块通过关注预测的 BEV 特征、预测的智能体轨迹和预测的占用来生成未来自车航点。这正是多元链式法则(第 3 章)在实际中的体现:梯度从规划损失一路流回图像编码器,告诉感知特征如何才能对规划更有用。
更近期的端到端方法使用 VLA 风格的架构(本章第 3 节)。像 DriveVLM 这样的模型接收摄像头图像和导航指令(或路线),用 VLM 主干产生驾驶动作。这把大规模预训练的好处(视觉理解、推理)直接带进了驾驶软件栈。
端到端驾驶中的张力在于可解释性。模块化系统可以报告"我在 (x, y) 检测到一个行人,并预测他会横穿"——失效模式是可诊断的。端到端系统则是一个输出方向盘转角的黑箱。当它失效时,诊断原因很困难,这对安全认证是个严肃的担忧。
世界模型学习在给定当前状态和自车动作的情况下预测驾驶场景的未来状态:p(s_{t+1} \mid s_t, a_t)(第 10 章已介绍)。在驾驶中,这意味着生成逼真的未来帧或 BEV 布局:"如果我加速并向左转,3 秒后场景会变成这样。"
世界模型为自动驾驶提供两种强大能力:
基于想象的规划:规划器不必贸然采取一个动作再看结果,而是可以通过在世界模型中推演多条候选轨迹来"想象",逐个评估其安全性和舒适性,挑出最好的。这就是基于模型的 RL(本章第 2 节已介绍)在驾驶上的应用。
学习型仿真:在真实驾驶数据上训练的世界模型实际上就是一个数据驱动的仿真器。它能生成逼真的场景(包括稀有的边缘情形),而无需手工搭建仿真器的繁琐劳动。至关重要的是,它捕捉了真实驾驶的统计模式:其他司机实际上如何行为、光照如何变化、雨水如何影响能见度。
GAIA-1(Wayve)是一个用于驾驶的生成式世界模型。给定一段过去的摄像头帧序列和自车动作,它自回归地生成未来视频帧。它使用以动作为条件的视频扩散架构。模型学会生成合理的未来:遵守交通规则的车辆、走在人行道上的行人、正确切换的交通灯——全部从训练数据中涌现,而非通过编程规则。
DriveDreamer 和 GenAD 采用类似方法,但在 BEV 空间而非像素空间操作。预测未来 BEV 布局比生成完整视频帧更紧凑(类似于机器人的 DreamerV3 在潜在空间而非像素空间预测,见第 2 节)。BEV 世界模型预测所有智能体将去哪里、道路结构会是什么样、以及空闲空间在哪里,规划器直接使用这些。
神经闭环仿真用世界模型替代手工仿真器来做测试。给定一段真实驾驶日志作为起点,世界模型生成"如果自车当时采取了不同动作会发生什么"。这使得反事实评估成为可能:"如果我晚刹车 0.5 秒会怎样?"——而完全不需要物理上重现该场景。
它与 JEPA 框架(第 10 章)的联系在这里很自然。驾驶世界模型不需要预测像素级完美的未来(每个像素的精确 RGB 值)。它需要预测那些对规划有意义的方面:智能体在哪里、它们移动得多快、空闲空间在哪里。嵌入空间预测(JEPA 风格)捕捉这些语义上有意义的属性,而不会把容量浪费在无关的视觉细节(如精确的云朵纹理)上。
主要挑战是长程保真度。世界模型会随时间累积误差:第 2 帧的一个小错误会偏移之后所有帧。对驾驶而言,3 秒的预测范围对战术决策(我现在该并线吗?)有用,但 30 秒的范围(路线规划等战略决策所需)仍然不可靠。当前工作通过重新锚定(周期性地用真实观测重置模型)和不确定性估计(在预测变得不可靠时标记出来)来缓解这一问题。
仅靠真实道路测试自动驾驶汽车是必要的,但远远不够。危险场景(近碰撞、边缘情形)很罕见,所以按行驶里程来测试效率很低。一辆车需要开上数亿英里才能在统计上证明安全,这不可行。
仿真提供无限、可控、安全的测试。真实世界中罕见的场景(小孩冲进道路、轮胎爆胎、突如其来的障碍物)可以在仿真中测试上百万次。
CARLA 是一个基于 Unreal Engine 的开源驾驶仿真器。它提供逼真的城市环境、动态天气、交通智能体和传感器仿真(摄像头、LiDAR、雷达)。研究者用 CARLA 训练基于 RL 的驾驶智能体并评估感知算法。
nuPlan(Motional)是一个闭环规划基准。与开环评测(回放日志数据并比较规划器输出与人类驾驶员实际轨迹)不同,闭环评测让规划器的决策影响仿真:如果规划器决定变道,仿真会相应演化。这测试的是反应式行为,而不仅仅是轨迹相似度。
开环与闭环评测的区别至关重要:
开环:回放一个录制好的场景,计算模型输出与人类驾驶员动作的相似度。这容易搭建,但有误导性:一个永远预测"直行"的模型在高速公路上可能误差很低,但到第一个弯道就会撞车。
闭环:模型的动作改变仿真状态,仿真随之响应。这测试模型从自身错误中恢复并应对动态情况的能力。它代价大得多,但有意义得多。
场景生成创建给系统施压的测试用例。对抗性场景(一辆车突然刹车、一个躲在停泊车后面的行人)通过优化寻找自动驾驶系统表现最差的情况来生成。这与机器学习中的对抗训练(第 6 章)相关:寻找最大化损失的输入。
自动驾驶中的安全由工程标准治理,而不仅仅是机器学习指标。
ISO 26262(功能安全)是汽车安全关键电子系统的标准。它根据潜在危害的严重性、暴露率和可控性,定义了从 A(最低)到 D(最高)的汽车安全完整性等级(Automotive Safety Integrity Level,ASIL)。自动驾驶系统的感知和规划组件通常是 ASIL-D,即最高等级,需要大量的验证、冗余和故障安全设计。
SOTIF(Safety of the Intended Functionality,预期功能安全,ISO 21448)针对另一类危害:不是硬件失效(那是 ISO 26262 覆盖的),而是系统按设计工作却仍产生不安全结果的情况。一个把白色卡车误分类为天空的感知模型(真实事故)就是 SOTIF 问题:硬件工作正常,但算法的局限造成了危害。
**运行设计域(Operational Design Domain,ODD)**定义了自动驾驶系统设计运行的条件:特定地理区域、道路类型(仅高速、城市、两者兼有)、天气条件(无大雪)、速度范围以及一天中的时段。超出 ODD 运行是不允许的:如果系统应付不了雪,它就不得在雪中行驶。
**故障安全(fail-safe)与故障运行(fail-operational)**设计:
冗余是根本。关键感知传感器会被复制:多个摄像头覆盖重叠的视场、LiDAR 和雷达同时提供独立的深度测量、双计算平台运行相同软件。任何一个组件失效,其他组件仍能提供足够信息来安全驾驶。
SAE J3016 标准定义了六个驾驶自动化等级,从 0(无自动化)到 5(完全自动化):
0 级(无自动化,No Automation):人类做所有事。系统可能提供警告(车道偏离警报)但不控制车辆。
1 级(驾驶员辅助,Driver Assistance):系统控制转向或速度中的一种,但不能同时控制两者。自适应巡航控制(保持速度和车距)或车道保持辅助(让车保持在车道中央)属于 1 级。
2 级(部分自动化,Partial Automation):系统同时控制转向和速度,但人必须全程监控并随时准备接管。Tesla Autopilot、GM Super Cruise 以及当前大多数"自动驾驶"功能都是 2 级。人仍然是责任驾驶员。
3 级(条件自动化,Conditional Automation):系统驾驶并监控环境,但仅在特定条件(ODD)下。人可以脱手,但当系统请求时必须准备好接管(有一个时间缓冲,通常 10 秒以上)。Mercedes Drive Pilot(在特定高速上、低于 60 km/h)是首个通过认证的 3 级系统。
4 级(高度自动化,High Automation):系统在其 ODD 内驾驶并处理所有情况,无需人介入。如果遇到 ODD 之外的情况,它能安全地自己停下。Waymo 的无人出租车服务在特定地理区域以 4 级运行。
5 级(完全自动化,Full Automation):系统能在人能开的所有地方、所有条件下驾驶。不需要方向盘或踏板。这尚不存在。
关键的区别在于谁对安全负责。在 0-2 级,人负责。在 3-5 级,系统负责(在其 ODD 内)。这具有深远的法律、保险和伦理含义。
当前的行业状态是 2 级(广泛部署)、3 级(开始部署)和 4 级(有限地理部署)的混合。5 级仍是长期的研究目标。
import jax import jax.numpy as jnp import matplotlib.pyplot as plt # 轨迹:N 个航点,每个 (x, y) N = 20 start = jnp.array([0.0, 0.0]) goal = jnp.array([10.0, 0.0]) obstacle = jnp.array([5.0, 0.0]) obs_radius = 1.5 # 初始化:从起点到终点的直线 waypoints_init = jnp.linspace(start, goal, N) def cost(waypoints): wp = jnp.concatenate([start[None], waypoints, goal[None]], axis=0) # 平滑性:惩罚加速度(二阶差分) accel = wp[2:] - 2 * wp[1:-1] + wp[:-2] smooth_cost = jnp.sum(accel ** 2) # 避障:惩罚靠近 dists = jnp.linalg.norm(wp - obstacle, axis=1) collision_cost = jnp.sum(jnp.maximum(0, obs_radius + 0.5 - dists) ** 2) return 10 * smooth_cost + 100 * collision_cost grad_cost = jax.grad(cost) # 优化内部航点 waypoints = waypoints_init[1:-1] lr = 0.01 for _ in range(500): g = grad_cost(waypoints) waypoints = waypoints - lr * g # 绘图 full_path = jnp.concatenate([start[None], waypoints, goal[None]], axis=0) theta = jnp.linspace(0, 2 * jnp.pi, 100) plt.figure(figsize=(10, 4)) plt.plot(full_path[:, 0], full_path[:, 1], "b.-", label="Optimised path") plt.plot(waypoints_init[:, 0], waypoints_init[:, 1], "r--", alpha=0.5, label="Initial (straight)") plt.fill(obstacle[0] + obs_radius * jnp.cos(theta), obstacle[1] + obs_radius * jnp.sin(theta), alpha=0.3, color="red", label="Obstacle") plt.plot(*start, "go", markersize=10); plt.plot(*goal, "g*", markersize=15) plt.legend(); plt.axis("equal"); plt.grid(True) plt.title("Trajectory Optimisation: Smooth Collision-Free Path") plt.show()
import jax.numpy as jnp import matplotlib.pyplot as plt # 真值:车辆右转 dt = 0.1 T = 40 # 4 秒 v = 10.0 # m/s omega = 0.3 # rad/s(转弯率) # 真实轨迹(恒定转弯率) t = jnp.arange(T) * dt theta = omega * t gt_x = (v / omega) * jnp.sin(theta) gt_y = (v / omega) * (1 - jnp.cos(theta)) # 从 t=0 出发的匀速预测 # 假设车以当前朝向继续直行 obs_steps = 10 # 观察前 1 秒 vx0 = v * jnp.cos(theta[obs_steps - 1]) vy0 = v * jnp.sin(theta[obs_steps - 1]) pred_t = jnp.arange(T - obs_steps) * dt pred_x = gt_x[obs_steps - 1] + vx0 * pred_t pred_y = gt_y[obs_steps - 1] + vy0 * pred_t plt.figure(figsize=(8, 6)) plt.plot(gt_x[:obs_steps], gt_y[:obs_steps], "ko-", label="Observed") plt.plot(gt_x[obs_steps:], gt_y[obs_steps:], "g-", linewidth=2, label="True future") plt.plot(pred_x, pred_y, "r--", linewidth=2, label="Constant velocity prediction") plt.legend(); plt.axis("equal"); plt.grid(True) plt.xlabel("x (m)"); plt.ylabel("y (m)") plt.title("Constant Velocity Prediction vs Turning Vehicle") plt.show()
import jax.numpy as jnp def rule_based_planner(ego_speed, obstacles, speed_limit=13.9): """ 简单的基于规则的规划器。 ego_speed: 当前速度 (m/s) obstacles: 前方车辆的 (距离, 速度) 元组列表 speed_limit: 最大允许速度 (m/s),默认约 50 km/h 返回: (目标速度, 动作标签) """ min_following_distance = 2.0 * ego_speed # 2 秒法则 emergency_distance = 5.0 # 米 if not obstacles: return speed_limit, "cruise" # 找到前方最近的障碍物 closest_dist, closest_speed = min(obstacles, key=lambda o: o[0]) if closest_dist < emergency_distance: return 0.0, "EMERGENCY STOP" elif closest_dist < min_following_distance: # 匹配前方车辆速度 target = min(closest_speed, speed_limit) return target, "following" else: return speed_limit, "cruise" # 测试场景 scenarios = [ (13.9, [], "Empty road"), (13.9, [(30.0, 10.0)], "Slower car ahead"), (13.9, [(3.0, 0.0)], "Stopped car very close"), (13.9, [(50.0, 13.9)], "Car ahead at same speed"), ] for speed, obs, desc in scenarios: target, action = rule_based_planner(speed, obs) print(f"{desc:30s} → {action:15s} target_speed={target:.1f} m/s ({target*3.6:.0f} km/h)")