2025年6月14日

造车这几年:智能驾驶架构的演进实录


架构本质是个填坑的活

在智能驾驶研发一线摸爬滚打这几年,最大的感受不是“运筹帷幄”,而是“焦头烂额”。刚入行时,总觉得搭建系统骨架是画出完美的蓝图;后来才发现,这项工作更像是在泥潭里修路的工头

如果非要总结一点经验,核心不在于某种高大上的模式,而是适配业务生命周期的演进式思维

系统结构从来不是一成不变的艺术品,它是服务于业务的工具箱。在项目的不同阶段,需要拿出不同的工具来解决当下的问题,而不是试图用一把钥匙开所有的锁。

  • 0-1 阶段 (原型验证):这时候目标单纯,就是快。快速验证功能,快速试错。为了让算法先跑起来,甚至可以用 ROS2 配合 Python 脚本快速搭个架子。那时候代码乱点没关系,重要的是验证“这路通不通”。
  • 1-100 阶段 (产品量产):到了这个阶段,目标变成了稳。可靠性、安全性、成本、功耗,这些“隐形”的约束条件开始占据主导地位。这时候如果不引入车规级、标准化的流程和组件,后面绝对会付出惨痛的代价——曾经因为忽视了日志系统的开销,导致量产车在长时间运行时存储爆满,差点召回。

与其说是在“设计”系统,不如说是在为团队在不同阶段寻找最顺手的“武器”。

分代规划无法一步到位

在这个行业里,把“城市领航辅助”这样一个宏大的产品构想,翻译成工程团队能执行的技术路径,是系统搭建的第一步,也是最容易产生分歧的地方。

最开始我们也犯过贪大的毛病,试图在第一代平台上就预留未来五年的扩展性,结果导致系统极其臃肿,开发进度严重滞后。后来学乖了,采用分代规划的方式来达成团队共识:

  • Gen 1.0 (高速 NOA):目标是快速上车。传感器方案选择了性价比高的“视觉+前向毫米波”,域控制器直接选成熟的货架产品。软件结构上,重点解决结构化道路的问题,模块化程度适中即可。
  • Gen 2.0 (城市 NOA):这是一个坎,目标是啃硬骨头。系统不得不大改。
    • 硬件升级:引入激光雷达、高分辨率摄像头,算力平台也需要升级以支持大模型。
    • 软件重构:为了适配 BEV + Transformer 这类新模型,数据吞吐量激增,对中间件和 OS 的要求完全不同。这是当前的主流趋势,如果不提前布局,后期重构成本极高。
  • Gen 3.0 (迈向 L3+):这是一个长期的愿景。核心在于冗余——计算冗余、传感器冗余、执行冗余。结构上需要开始探索原生支持“影子模式”,让量产车队成为数据收集和算法迭代的闭环系统。

这张蓝图不仅是画给技术团队看的,更需要和产品经理、项目经理反复对齐。大家在同一张图上作战,才能减少后期的拉扯(虽然拉扯还是不可避免)。

选型的艺术(或者说是妥协)

技术选型中最痛苦的往往是做决定,比如选哪家的芯片、用什么中间件。这些决定影响深远,一旦选错,推倒重来的代价巨大。

在做决策时,尽量避免“拍脑袋”,而是依赖基于 PoC (概念验证) 的实测数据

记得有一次选型 SoC,PPT 上两家的数据都很好看。没有全信,而是拿了 EVK 开发板,让算法同事把最核心的 BEV 模型跑上去。

结果很真实:方案 A 虽然号称算力强,但跑满载后发热严重,如果不加昂贵的水冷系统根本压不住;方案 B 算力略低,但工具链成熟,发热控制也好。最后选了方案 B。因为在那个项目中,散热成本的优先级高于极致算力。最终的选择,往往是基于当前项目约束下的妥协。

另外,随着 BEV 模型带来的数据量激增,传统的 CAN 总线确实捉襟见肘。最近在设计中也开始更多地考虑支持 DDS 或类似的高带宽中间件,配合车载以太网,这似乎是支撑“软件定义汽车”绕不开的基础设施。

接口即契约

为了管理复杂的系统,通常用 Node(节点) 作为基本开发和部署单元。系统一复杂,几十个节点跑起来,如果没有良好的解耦,联调时就是一场灾难。

1. 核心节点拆解与数据流

在设计时,大致将系统拆解为以下几类节点,并通过清晰的数据流将它们串联起来:

graph TD
subgraph Drivers ["驱动层"]
Lidar[lidar_driver_node]
Camera[camera_driver_node]
Radar[radar_driver_node]
GNSS[imu_gnss_driver_node]
end
subgraph Perception ["感知层"]
Fusion["perception_fusion_node<br/>(BEV Fusion)"]
TL[traffic_light_detection_node]
end
subgraph Localization ["定位层"]
Loc[localization_node]
end
subgraph Planning ["规划与决策层"]
Pred[prediction_node]
Behavior[behavior_planner_node]
Motion[motion_planner_node]
end
subgraph Control ["控制与执行层"]
Ctrl[control_node]
Interface[vehicle_interface_node]
end
%% Data Flow
Lidar --> Fusion
Camera --> Fusion
Radar --> Fusion
GNSS --> Loc
Loc --> Pred
Loc --> Behavior
Loc --> Motion
Fusion --> Pred
TL --> Behavior
Pred --> Behavior
Behavior --> Motion
Motion --> Ctrl
Ctrl --> Interface
Interface --> Vehicle["车辆底盘 CAN"]
style Fusion fill:#f9f,stroke:#333,stroke-width:2px
style Motion fill:#bbf,stroke:#333,stroke-width:2px

2. 接口定义 (Interface Definition)

为了避免“口口相传”导致的误差,倾向于用代码化的方式定义接口,比如 Protobuf

曾经发生过感知组改了字段类型,规划组不知道,结果联调时车子行为异常的情况。后来强制要求所有接口变更必须通过 IDL (Interface Definition Language) 文件进行,并且有 Code Review。

比如 Perception 节点产出给 Prediction 节点的数据,我们会这样定义:

// message definition for a perceived object
message Object {
uint32 id = 1;
Type type = 2; // VEHICLE, PEDESTRIAN, CYCLIST...
Position3D position = 3;
Velocity3D velocity = 4;
// ... 其他字段
}

清晰的接口定义,最大的好处是让感知组和规划组可以并行开发。大家约定好契约,各自跑通单测,最后联调时就会顺畅很多。

给AI装个“监工”落实功能安全

车会跑只是基础,安全、稳定、不出事,才是从业者最需要敬畏的底线。

在落实功能安全 (ISO 26262) 时,并没有把它当作一个独立的“任务”,而是尝试将其融入到架构设计中。我们采用了 主-监控 (Main-Monitor) 架构:

  • 主功能 (Main Path):负责处理复杂的感知、规划,追求极致的性能和体验。
  • 监控功能 (Monitor Path):这是一条并行的“守门员”链路。

具体的做法是增加一个 safety_monitor_node。它不处理复杂的传感器数据,而是只盯着关键节点的输出(如轨迹和控制指令)。它运行一套简单但绝对可靠的物理规则检查。

例如:

  • 规划出的轨迹未来 3 秒会不会撞墙?
  • 请求的转角是不是大得离谱?

一旦监控节点发现主功能的输出违反了这些安全规则,它拥有最高裁决权,可以直接屏蔽主控制器的指令,触发“紧急制动”或“降级模式”。这就像给 AI 系统装了一个物理世界的“刹车片”,或者说是给一个天才但偶尔会发疯的赛车手配了一个冷静的副驾。

写在最后

经历几个量产周期后,深感画完图只是工作的一小部分。

更多时候是在平衡——平衡性能与成本,平衡理想与现实,平衡激进与稳健。确保这台复杂的机器,在从实验室原型走向用户的过程中,始终保持在一条相对正确、安全的轨道上。

这条路很长,我们都在路上。