结论:大众 MLB 与 PQ 共用同一个 CarController 和一套「统一 CCS 插件接口」,但两者的纵向实现并不等价。静态源码里有两处硬边界:PQ 纵向助手返回帧列表(与 can_sends.extend() 一致),而 MLB 助手返回 CANPacker.make_can_msg() 的 (address, bytes, bus) 单帧三元组,extend() 会把三个成员分别加入列表——这是源码可见的返回类型不匹配;同时 MLB 固件安全配置只允许 HCA_01、LDW_02、两总线的 LS_01,没有 ACC_05/ACC_02。统一接口不能掩盖这些差异。
共享控制器与两套构帧器
基线是 openpilot 固定快照 c8fb906,覆盖 mlbcan.py 与 pqcan.py 的全部实现函数,并追踪共享车型控制器、接口配置、DBC packer 与 panda safety。仅做静态分析:未发 CAN、未改 ECU、未跑实车。共享控制器 CarController.update() 先限扭矩、做重复值缓解,再以非零扭矩作为 HCA 使能值。
| 功能 | MLB 实现 | PQ 实现 |
|---|---|---|
| 转向 | create_steering_control() 输出 HCA_01,状态 7/3 与 lkas_enabled 对应,扭矩拆绝对值和符号。 |
create_steering_control() 输出 HCA_1,仅在 enabled 且扭矩非零时状态 7,否则 3。 |
| LDW / HUD | create_lka_hud_control() 直接委托 MQB 构帧。 |
构造 LDW_Status,可复制五个原车警示字段,再覆盖车道线/告警/转向提示。 |
| 巡航按钮 | 复制 LS_01 四个配置字段,原车 COUNTER+1 mod 16,覆写 cancel/resume。 |
对 GRA_Neu 作同类处理。 |
| 纵向状态 | acc_control_value() 与 acc_hud_status_value() 均固定返回零。 |
acc_control_value() 按活动/主开关返回 1/2/0;acc_hud_status_value() 另将故障置 6。 |
按钮帧由 pcmCruise、原车 COUNTER 变化与 cancel/resume 请求共同决定发送,总线由 CAN.ext 选择;LDW/HUD 按平台 LDW_STEP 发送,输入来自 CarState 的原车缓存。纵向状态分支只在 openpilotLongitudinalControl 为真时走自控纵向及其 HUD 分支。
需要说明的是,「什么时候发」和「发什么内容」由不同东西决定:LDW/HUD 依平台的 LDW_STEP 节拍发送,纵向 HUD 依 ACC_HUD_STEP 把单个返回值 append 到发送列表,而内容取自 CarState 缓存的原车配置与计数。节拍常量与原车缓存只保证本机按序产出候选帧,并不等于车辆已接受该帧。
纵向路径与返回类型不匹配
加速度与纵向 HUD 构帧是差异最集中的地方。MLB 的 create_acc_accel_control() 用空字段构造单个 ACC_05 三元组,create_acc_hud_control() 用空字段构造 ACC_02;PQ 的 create_acc_accel_control() 构造 ACC_System 并返回单元素列表(关闭时加速度字段用 3.01),create_acc_hud_control() 构造 ACC_GRA_Anzeige,包含状态、目标车速和距离。
控制器统一调用 can_sends.extend(...),但两种助手的返回类型并不一致:PQ 返回 list[frame],与 extend() 语义一致;MLB 返回 CANPacker.make_can_msg() 的 (address, bytes, bus) 单帧三元组,extend() 会把三个成员分别加入 can_sends,不再是帧列表。这是源码可见的返回类型不匹配,MLB 自控纵向不能据此视为可工作。
这类差异不会在简单调用里立刻显形:PQ 返回单元素列表,可直接被 extend() 展开为帧;MLB 返回的是 make_can_msg() 的三元组,被 extend() 展开后会把地址、字节和总线各自当成一个元素,破坏原本的帧列表结构。只有真正进入发送链路,这种结构错位才会以异常或错误帧的形式暴露。
校验与固件白名单
MLB 的 volkswagen_mlb_checksum() 对十个指定地址使用不同 XOR 初值,其他地址回退 MQB/MEB CRC;PQ 文件没有独立校验函数,由其 DBC/packer 负责已声明的计数和校验字段。CANPacker.pack() 按 DBC signal 类型选回调并填入校验,但它不替代 panda RX/TX 安全检查。
换句话说,校验只回答「这段字节是否按 DBC 约定自洽」,不回答「这条帧是否应该被允许发出」。后者由固件白名单与安全模式独立裁定,两者不能互相代替。
| 可达性边界 | 源码可见事实 |
|---|---|
| 接口能力 | 接口对 PQ/MLB 都可在 alpha_long 置位时设置 openpilotLongitudinalControl,但两者纵向实现不等价。 |
| 返回类型 | MLB 纵向助手返回单帧三元组,被 extend() 拆成三个成员;PQ 返回帧列表。 |
| 固件白名单 | MLB 仅允许 HCA_01、LDW_02 与两总线的 LS_01,无 ACC_05/ACC_02。 |
| 构建门 | MLB/PQ 两个 safety 模式都仅在 ALLOW_DEBUG 下注册,发布构建不能因识别到平台便假定可启用。 |
| 数据质量 | 按钮门的当前实现只比较 COUNTER 是否变化,未同时校验该帧接收时间或原车数据质量。 |
PQ 的 ACC_System 虽然存在明确的活动/非活动加速度编码、固件也有单独的纵向配置与加速度限幅,但这仅说明源码中存在对应路径,不等于车辆已验证。按钮帧引用 CarState 缓存的原车配置及计数,接线/插件层需保留 bus、时间戳与报文健康,不能只传一个 cancel 布尔量。
新硬件的验收要点
新硬件的验收应分别列出 MLB/PQ 车型身份、网络位置、线束、DBC、固件 safety 配置、计数/校验、失联数据新鲜度和拒帧行为。尤其不能让「统一 CCS 插件接口」掩盖 MLB 的占位纵向实现或返回类型差异。
| 验收项 | MLB 关注点 | PQ 关注点 |
|---|---|---|
| 纵向可发性 | 返回类型须先修正,且固件白名单不含 ACC 帧。 | 返回列表与 extend 一致,但仍需实车验证。 |
| 安全模式 | 仅在 ALLOW_DEBUG 注册。 | 仅在 ALLOW_DEBUG 注册。 |
| 计数/校验 | 十地址 XOR 初值 + MQB/MEB 回退。 | 由 DBC/packer 声明字段负责。 |
| 数据新鲜度 | 按钮门不校验接收时间。 | 按钮门不校验接收时间。 |
本机隔离探针未完成:系统 Python 缺 numpy,工作区 Python 缺 capnp;本篇没有运行 DBC 字节回放、目标固件或实车试验。归档源码未编辑。
常见问题
为什么大众 MLB 的自控纵向「看起来有实现」却不能用?
因为源码里 MLB 的纵向助手返回的是 CANPacker.make_can_msg() 的 (address, bytes, bus) 单帧三元组,而控制器用 can_sends.extend() 追加,会把三个成员拆开,不再是帧列表;同时 MLB 固件安全配置只允许 HCA_01、LDW_02 与两总线的 LS_01,没有 ACC_05/ACC_02。返回类型不匹配与白名单缺口是两处独立证据。
PQ 和 MLB 的转向构帧有什么差别?
MLB 的 create_steering_control() 输出 HCA_01,状态 7/3 与 lkas_enabled 对应,扭矩拆成绝对值和符号;PQ 输出 HCA_1,仅在 enabled 且扭矩非零时状态取 7,否则取 3。两者都经共享控制器先限扭矩、做重复值缓解。
两个平台都设了 openpilotLongitudinalControl 就等价吗?
不等价。接口对 PQ/MLB 都可在 alpha_long 置位时设置 openpilotLongitudinalControl,但两者的纵向实现(返回类型、固件白名单、状态编码)都不同;且 MLB/PQ 两个 safety 模式都仅在 ALLOW_DEBUG 下注册,发布构建不能因识别到平台就假定可启用。
按钮帧只比较 COUNTER 变化够吗?
源码中该门只比较 COUNTER 是否变化,没有在本地控制器同时校验该帧的接收时间或原车数据质量。接线/插件层因此需保留 bus、时间戳与报文健康,不能只传一个 cancel 布尔量。
延伸阅读
- opendbc 校验算法族与 RX/TX 契约 —— 承接本文 MLB 十地址 XOR 与 MQB/MEB 回退的校验边界。
- Ford CAN 构帧契约 —— 与本文同一「构帧器返回什么」的对照案例。
- 从使能到车轮:执行链上的八道门 —— 说明构帧之后仍由固件白名单独立许可。
- 同一个「转向灯」在三家车厂是三种实现 —— 解释按钮帧为何依赖按品牌缓冲的原车状态。
参考资料
- 项目 02 ——
openpilot-research/VW_MLB_PQ_CAN_BUILDER_CONTRACT_DEEP_DIVE.md(取用了 MLB/PQ 构帧函数矩阵、纵向返回类型不匹配、MLB 校验与固件白名单、验收要点)。 - 项目 02 ——
openpilot-research/VOLKSWAGEN_MLB_PANDA_SAFETY_DEEP_DIVE.md(仅用于确认 MLB safety 语境的接续关系,未取用其未公开内容)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11