最近在整理《智能驾驶功能软件平台设计规范》第一部分的评审材料,正好借这个机会把系统架构这一章的设计思路沉淀一下。
做智能驾驶软件的人应该都有同感:第一年靠热情把功能跑通,第二年就开始被架构问题折磨。感知模块换了供应商,决策模块要加新场景,底盘协议偷偷改了一个信号定义,结果整个链路都要跟着返工。真正决定这套系统能走多远的,不是某个算法有多惊艳,而是软件平台在架构层面的底盘稳不稳。
这篇内容围绕“系统架构”这个核心来聊,重点解决三件事:功能软件平台应该怎么分层、模块之间怎么定义接口、部署到芯片上之后怎么保证确定性和安全。适合系统架构师、软件负责人、功能开发工程师,以及正准备搭智能驾驶软件团队的Leader参考。我会把架构规范里实际要写的内容、评审时容易被挑战的点、落地中踩过的坑一起说清楚。
1. 为什么非要先定系统架构:从一堆功能到一座房子
1.1 功能软件平台到底是什么
先对齐一个概念。智能驾驶软件栈往下有硬件、BSP、操作系统、中间件,再往上就是应用算法。功能软件平台处于中间件之上、应用算法之下,它要解决的是让上层的感知、预测、决策、控制等算法模块,不直接跟硬件、操作系统、供应商SDK耦合。
你可以把功能软件平台理解成一座房子的框架。墙怎么砌、水电怎么走、房间怎么分,这些是架构设计阶段定下来的。如果一开始不画图纸,直接让每个装修师傅按自己的喜好来,结果就是空调管和电线打架、承重墙上凿洞、住进去之后天天返工。智能驾驶比装修复杂得多,因为房子里的“住户”还会动态变化,今天多一个激光雷达算法,明天换一家地图供应商。
所以《设计规范 第一部分:系统架构》强调的第一件事是:在动手写大量代码之前,先把逻辑架构、部署架构、运行架构三份视图画出来,并把模块边界、接口语义、数据流方向固定下来。
1.2 三份视图与一套规则
架构设计通常要看三个维度。
- 逻辑架构:回答“系统里有哪几类模块,每个模块干什么”。它不关心跑在哪个芯片上。
- 部署架构:回答“逻辑模块最终跑在哪颗SoC、哪个MCU、哪个进程里”。
- 运行架构:回答“运行过程中,数据怎么流动、消息怎么通信、异常怎么处理”。
我们写规范时,最忌讳只画一张漂亮的分层图就完事。评审时一定会被问:某个模块崩溃了怎么办?两个模块同时抢一个算力资源怎么调度?消息时延超了谁来负责?这些在逻辑架构图里看不出来,必须落到部署和运行视图中。
还有一个容易忽略的点:架构规范不只是画图,它是一套规则。规则里至少包含接口定义规范、通信QoS策略、时间同步要求、安全等级分配、变更控制流程。把这套规则写清楚,后面团队协作才有依据。
2. 逻辑架构:五大层级怎么划分、怎么把职责讲清楚
2.1 数据接入层:把传感器差异挡在门外
数据接入层是整个平台的“门卫”。摄像头、激光雷达、毫米波雷达、超声波、GNSS/IMU、高精地图,每类传感器的数据格式、坐标系、时间基准、异常状态都不一样。如果每个算法模块都自己去对接传感器驱动,那整个系统会变成一张复杂的蜘蛛网。
规范里的做法是定义统一的传感器抽象接口。原始数据接入后,统一转换成平台内部定义的数据结构,并带上全局时间戳、传感器内外参、数据质量标志。这样上层模块的输入是干净的,不关心数据到底来自哪个供应商的哪款产品。
这里有一个实战中很关键的点:数据质量标志必须从接入层就开始打。比如摄像头被遮挡、雷达丢帧、GNSS信号弱,这些状态要在数据接入层通过独立的状态机识别出来,并随数据一起上报。很多团队等到决策模块做不下去时才排查传感器异常,结果发现问题出在接入层没有尽力暴露“我不确定”的信息。
2.2 感知融合与认知层:算法模块之间不直接握手
感知融合与认知层是智能驾驶功能软件平台里模块最多、关系最复杂的一层。它通常包含目标检测、语义分割、多传感器融合、目标跟踪、轨迹预测、自车定位等能力。
架构规范要做的不是规定每个算法怎么写,而是规定它们之间的协作方式。我的建议是:感知模块之间不允许直接私有通信。目标检测输出的目标列表,必须经过融合模块统一处理后,才能提供给预测和决策模块。这样做的好处是,任何一路感知源更换算法时,对外发布的接口语义不变,不会引起下游链路的连锁改动。
这层里还要特别注意“置信度”语义的一致性。不同算法模块输出的置信度表示的含义可能不一样,有的表示分类概率,有的表示检测框质量,有的表示跟踪稳定程度。如果不做归一化,决策模块拿到的就是一堆口径混乱的数字。规范里我一般要求每个感知输出结构里明确标注置信度类型和归一化区间。
2.3 决策规划与控制执行层:指令必须“可解释、可追踪”
决策规划层负责行为决策、路径规划、速度规划,控制执行层负责把规划结果转成方向盘转角、加速、制动等具体控制指令。
架构层面对这个区域有两条硬性要求。第一,规划输出的轨迹必须是结构化的,包含时间序列、位置序列、速度、加速度、曲率,以及对应的场景标签和约束来源,比如因为前方行人而减速,因为车道线不清晰而降低目标速度。这些上下文信息是为了让控制层和安全监控层能够理解和校验轨迹是否合理。
第二,控制指令必须可追踪。也就是说,从最终下发到底盘的每个控制量,都能反向追溯到它来自哪一个规划结果、哪一帧传感器数据。这一点在故障排查时特别重要。没有这种追踪能力,一旦出现异常控制,团队只能靠猜。
2.4 基础服务层:所有模块共享的那张桌子
基础服务层是容易被低估但特别体现平台能力的一层。它包含系统状态管理、模块生命周期管理、日志与回放、参数配置、健康监控、时间同步、安全监控等功能。
很多团队一开始觉得这些都是“边角料”,优先级排得很低。实际开发到中后期就会发现,能不能快速定位问题是团队效率的分水岭。比如日志与回放功能,如果架构阶段不规定数据记录的格式、触发条件和存储策略,等出了问题需要复现时,要么没有数据,要么数据量太大没法分析。
状态管理也是同样重要。智能驾驶系统不是一直在最高功能等级运行,会有启动、初始化、降级、退出等状态。状态管理模块要像一个“大脑的调度员”,统一管理所有功能模块的状态切换,并保证切换过程中不会出现半初始化状态。规范里我要求每个业务模块必须实现状态机接口,并定义好状态迁移的合法路径。
3. 接口与数据流:架构规范里最容易被低估的部分
3.1 接口信息表:先统一坐标系、单位、时间戳
软件架构的落地,最终都体现为接口。架构评审中我见过最多的一个问题,就是接口定义得很随意,消息字段里只有一个变量名,没有单位、坐标系、取值范围、时延要求。
规范里应该维护一张接口信息表,每个接口至少包含以下信息:
| 字段 | 说明 |
|---|---|
| 接口ID | 全局唯一标识,禁止重复使用 |
| 接口名称 | 语义化命名,与代码保持一致 |
| 数据内容 | 结构化字段列表,包含类型、单位、范围 |
| 坐标系 | 例如车体坐标系、UTM坐标系,必须统一 |
| 时间戳 | 采样时间还是发送时间,必须明确 |
| 发布频率 | 可能的最大频率,用于预算评估 |
| 时延要求 | 从产生到消费的最大允许时延 |
| 可靠性等级 | 丢包容忍度,对应QoS策略 |
单位这个细节,踩过坑的人都懂。同一个车速,有的模块用km/h,有的用m/s,融合时没有做转换,结果就是输出的目标速度差一个数量级。规范里要明确国际单位制优先,并在接口代码里通过强类型定义来避免这类问题。
时间戳更值得重视。不同传感器、不同处理器上的模块,时钟如果不做同步,时间戳就是废的。架构上必须采用统一的全局时间同步机制,如PTP(精确时间协议),并规定每个消息的时间戳必须基于同一个时钟域。这一点我在后面“常见问题”里还会展开。
3.2 通信机制选择:DDS、SOME/IP、共享内存各管一段
智能驾驶功能软件平台里,通信方式通常不是单一的。不同数据对时延、带宽、可靠性的要求差异很大,合理的做法是混合使用。
- 大带宽低延迟的数据,如摄像头图像、激光雷达点云,适合用共享内存传输,避免频繁拷贝。
- 周期性小数据,如目标列表、车辆状态,适合用面向服务的通信框架,如DDS或SOME/IP,具备灵活的QoS配置。
- 控制指令这类对实时性要求极高的消息,通常走确定性调度保障的实时通道,甚至直接通过专用核间通信机制传递。
规范里要规定的是通信矩阵:哪些消息走哪条通道,QoS怎么配置,可靠性怎么保证。比如DDS里,对于周期性的目标列表,可靠性与时效性要平衡,不能一味要求可靠传输。老的可靠数据包如果丢了重传,可能比发一个实时的新数据包危害更大。所以可靠性策略要按消息语义分类,而不是一刀切。
3.3 端到端时延预算:用一条功能链路验证架构
架构设计是否合理,不能只靠感觉,要拿计算说话。我习惯在系统架构规范里加一个“参考功能链路时延预算”章节。
举个例子,假设某个功能要求从目标出现到系统输出制动请求,端到端时延不超过500毫秒。那么我们可以倒推每一环节的预算:
- 传感器采集与前端预处理:40毫秒
- 感知输出目标列表:80毫秒
- 多传感器融合与目标跟踪:40毫秒
- 轨迹预测:40毫秒
- 决策规划:60毫秒
- 控制指令生成:20毫秒
- 平台调度与通信开销:50毫秒
- 冗余与异常处理余量:170毫秒
如上只是一个示意,各项目差异很大。关键是通过这张预算表,让每个模块负责人清楚自己的时延红线在哪里。后续每次接口变更、算法升级,都要重新核算这个预算,确保新增的环节没有击穿总预算。没有时延预算的架构,就像没有工期节点的项目,一定会失控。
4. 部署架构与冗余:软件架构落地到芯片之后
4.1 部署视图:逻辑模块如何编排到SoC与MCU
逻辑架构解决的是“有哪些模块”,部署架构解决的是“模块跑在哪里”。智能驾驶域控制器通常包含多颗SoC和多颗MCU,有的负责高性能计算,有的负责实时控制,有的负责功能安全监控。规范里要明确芯片资源分区和模块部署约束。
部署设计有几个常见原则:
- 安全等级高的模块可以独占一个核或一个安全岛,避免被非安全模块影响。
- 强实时控制链路要部署在同一颗芯片或通过确定性通信链路相连,避免跨芯片的不可控时延。
- 高算力消耗的深度学习推理要分配到NPU或GPU,并且预留好算力余量。
部署视图不是静态的,还要考虑算力分配和资源竞争。比如多个感知算法同时启动,NPU占用会达到峰值,可能导致某些模块初始化失败。架构规范里必须定义资源使用上限和降级策略,比如初始化阶段分时加载模型,运行阶段监控NPU利用率并对低优先级任务进行降频处理。
4.2 冗余与降级策略:不是多一份备份那么简单
冗余设计是智能驾驶架构里绕不开的话题。很多团队理解冗余就是“再买一套硬件”,但功能软件平台的冗余设计,更多体现在数据、计算、通信的交叉校验和切换逻辑上。
数据冗余,典型的是多传感器融合。摄像头和毫米波雷达同时观测前方目标,融合前的独立性校验很关键,否则两路数据如果都来自同一个不可靠的上游,那就不叫冗余。计算冗余,通常是两套独立软件栈同时运行,一套主计算,一套影子计算,通过监控模块比对结果一致性,发现异常时快速切换。通信冗余,则需要双路通信链路,这里要注意切换时不能丢关键控制消息。
部署架构规范里还要规定降级策略。系统不可能永远满血运行,当某个传感器失效或某颗芯片算力过载时,系统要能按预定义的规则降低运行等级,比如从城市领航降级到ACC,并在人机交互界面明确提示驾驶员。降级策略不是临时拍脑袋,必须在架构阶段把功能等级和资源条件的关系矩阵定义好。
4.3 确定性调度与功能安全拆分
智能驾驶软件平台最大的技术难点之一,是“确定性”。普通Linux上跑软件,线程调度、内存分配、网络传输都带有随机性。但控制指令和某些安全监控逻辑,必须在确定的时间窗口内完成。
架构上通常引入“确定性调度器”,把CPU核或GPU时间片按固定周期分配给关键任务,避免抖动。规范里需要区分“时间关键型任务”和“非时间关键型任务”,前者采用静态优先级或时间触发调度,后者走动态调度。这个设计在评审时经常被挑战,尤其是在算力不足的板子上,很多人会想砍掉确定性调度来换性能。我的经验是:这条路不能退,确定性是智能驾驶软件平台安全的底牌。
功能安全方面,要与功能安全团队共同完成ASIL等级在架构层的分配。一个ASIL D级别的功能,可以通过冗余分解为ASIL B(D)+ ASIL B(D),两个独立通道互相监督。但架构师必须保证这两个通道之间在硬件、软件、时钟、通信链路上是真正独立的,而不是只是在文档上写了两个名字。
5. 规范落地:从架构文档到团队工作习惯
5.1 文档、代码、工具链三件套
架构规范能不能落地,不看文档写得有多厚,而看它能不能指导代码生成和验证。我们的经验是“文档-代码-工具链”三件套要一起设计。
架构文档里定义的模块划分、接口ID、通信矩阵,应该能够自动生成或校验对应的代码骨架。比如接口ID一旦定下来,在代码仓库里就应该是不可随意变更的常量。架构工具链要做到:如果有人改了接口数据结构而没同步更新接口描述文档,CI流水线直接报错。这样架构就不是墙上的图纸,而是嵌入开发流程的硬约束。
很多团队没有这一步,结果就是架构文档和实际代码越来越脱节。半年之后,真正在车上跑的代码和评审时画的架构图已经完全对不上了。这种架构落不了地,还不如一开始就不画。
5.2 接口变更控制:谁都不能随便改消息
接口变更控制是我们在项目里吃过亏后才认真补上的机制。早期团队小,大家觉得改个消息字段没什么,打个招呼就改了。结果就是下游模块经常因为上游悄悄改了数据结构而出现偶发崩溃,问题还特别难排查。
规范里我们规定了接口变更的流程:
- 提议人填写接口变更申请,说明变更原因、影响范围和兼容性方案。
- 架构评审小组评估影响,包括依赖模块、时延预算、回放数据兼容性。
- 通过后统一在版本管理系统中发布新接口版本,并保留旧版本至少一个迭代周期的兼容适配。
- 变更记录纳入发布说明。
刚开始团队会觉得这个流程很重,但一旦通信消息数量到了几百个、参与团队到了几十人之后,这套流程会极大减少返工。接口稳定的项目,不一定架构多先进,但一定比天天改接口的项目走得快。
6. 复盘:常见问题与避坑经验
6.1 七个真实踩坑场景
| 问题表现 | 根本原因 | 解决办法 |
|---|---|---|
| 感知换了算法后,下游预测模块大面积返工 | 感知输出接口语义没有统一,各版本字段含义漂移 | 冻结感知输出接口,建立接口兼容性测试 |
| 融合数据里目标速度偶尔跳变 | 上游某个传感器数据单位不统一,未在接入层转换 | 单位统一在数据接入层转换,并做单元测试 |
| 偶发控制延迟,复现困难 | 多个任务抢占同一CPU核,没有确定性调度 | 关键链路任务绑定独立核或使用固定调度周期 |
| 传感器时间戳不一致,融合结果乱跳 | 各传感器没有统一时钟同步,跨芯片时间基准不同 | 全系统PTP同步,按全局时钟域校准时间戳 |
| 高算力模块同时启动,导致域控过载 | 部署时未评估资源峰值,缺少初始化阶段的错峰策略 | 规范初始化阶段加载顺序,设置资源监控与限流 |
| 出现事故后无法复盘数据 | 日志系统设计滞后,关键数据没有落盘 | 架构阶段定义关键数据记录范围与回放机制 |
| 安全等级分配只写在文档里 | ASIL等级没有映射到具体模块的冗余和监控机制 | 架构评审逐项核对安全机制的代码实现 |
这些坑每一个背后都是真实的深夜排查和上线延期。架构规范的价值,就是在时间还来得及的时候把这些坑提前标记出来。
6.2 给刚起步团队的三条建议
第一,架构规范不要追求一步到位。第一部分系统架构只要能定义清楚模块边界、接口ID和部署约束就足够了,剩下细节留给后续的分册和迭代版本。一上来就追求完美的架构文档,大概率会拖垮进度。
第二,架构评审一定要邀请最终写代码的人来参加。评审不是图好看,是要让执行层的人提出质疑。每一条架构决策都要能回答“为什么这么做”和“这么做会带来什么成本”,回答不了就说明还没想清楚。
第三,把架构基线当成一个正式版本去管理。一旦架构基线确定,每个改动都是变更,每个变更都要有评审、有记录、有通报。刚开始会不适应,但三个月后你就会发现,团队协作的摩擦成本在一个明显下降的通道上。
我个人在实际操作中的最大体会是,系统架构规范并不是为了限制开发者的自由,而是让整个团队把有限的精力集中在真正需要创造力的地方。算法工程师不用再操心消息丢了怎么办,控制工程师不用再追着感知团队问坐标系,大家各自在自己的职责边界内把事情做到极致,整车的软件系统才会真的像一个平台,而不是一堆模块的临时集合。
最后分享一个小技巧:给每个接口和数据消息都安排一个明确的“负责人”,并在架构工具链里记录这个人的名字。遇到接口争议时,不要开会讨论三天,先让负责人拍板,再走变更流程。这个看似简单的方法,能让智能驾驶软件平台在多人协作下始终保持清晰度。