标签: CAN总线

  • Ford 构帧:CAN FD 校验不是 CRC,名义频率不是负载预算

    结论:Ford 的 fordcan.py 只负责生成候选帧:横向、纵向、界面与按钮四类构帧函数把 CarControl 变成带计算器/校验的 CAN 载荷,是否真正上总线由独立固件白名单与继电器门裁决。CAN FD 校验 calculate_lat_ctl2_checksum() 是「原始位求和取反」的专用算法,不是通用 CRC;而函数注释里的 33/20/50/5/1 Hz 只是名义频率,不能当作总线最大负载预算。

    本文基于固定源码快照,从 fordcan.py 的公开构帧函数出发,追踪 CarController.update() 与 panda 安全钩子,属于静态结构分析,未连接车辆或发送 CAN。完整固件侧规则见 Ford panda safety 专题,本文只解释主机侧「构帧了什么、依赖了什么」。

    构帧函数与报文契约

    四类输出分工明确:横向有 create_lka_msg()(空 Lane Assist)、create_lat_ctl_msg()(经典 CAN 曲率与路径)、create_lat_ctl2_msg()(CAN FD 曲率、计数、校验);纵向是 create_acc_msg();界面与按钮是 create_acc_ui_msg()、create_lkas_ui_msg()、create_button_msg()。它们只产出候选帧,不提供安全许可。

    函数 控制器调用 输出与关键限制
    create_lka_msg() 33 Hz 名义节拍 对 Lane_Assist_Data1 传空信号字典;panda 要求其动作字段必须为零,不能当额外转向通道
    create_lat_ctl_msg() 经典 CAN 分支 构造 LateralMotionControl,LatCtl_D_Rq 随横向活动位切换;曲率取限幅后符号反转值
    create_lat_ctl2_msg() CAN FD 分支 先以校验字段零值打包同名帧,算完校验再以实际 CAN.main 构帧;计数器按节拍 modulo 16,当前只用 mode=0/1
    create_acc_msg() 纵向控制分支 ACCDATA 带加速度、油门、预充/减速、停车与目标速度;仅自控纵向配置下按名义 50 Hz 发送
    create_acc_ui_msg() 5 Hz 或 UI 变化 从相机 ACCDATA_3 复制多项字段,再覆盖 TJA 状态、自控纵向显示与 FCW 告警
    create_lkas_ui_msg() 1 Hz 或 UI 变化 从相机 IPMA_Data 复制配置/告警字段,再改写车道线状态与握盘提示
    create_button_msg() 按钮分支 从主总线 Steering_Data_FD1 复制开关状态,只覆盖 cancel/resume/TJA 三个位;取消和恢复同时送 camera/main,TJA toggle 只送 camera

    CanBus 定下总线映射:main=offset、radar=offset+1、camera=offset+2,基类以 len(CP.safetyConfigs) 推导 4 路一组的偏移。不能硬编码所有车辆为 bus 0,偏移取决于安全配置数量。

    CAN FD 校验:专用算法,不是通用 CRC

    calculate_lat_ctl2_checksum() 从已编码的 8 字节中抽取曲率、曲率率、路径角、路径偏移的原始位值,加模式和计数器,再取 0xFF - (sum & 0xFF)。它与固件侧从相同位置提取字段的做法对应,所以构帧器依赖所选 DBC 的位布局与物理总线映射——把该函数当成跨平台字节数组插件会失效。

    两步打包的原因也在这里:先打包零校验占位帧是为了让校验字段取值稳定,计算后再用实际 CAN.main 构帧。计数器和校验只保证字节自洽,不保证 ECU 接受,也不替代安全门。

    环节 做法 边界
    校验算法 原始位求和后取 0xFF - (sum & 0xFF) 专用算法,非通用 CRC;依赖 DBC 位布局
    计数器 按发送节拍 modulo 16 节拍来自 100 Hz 控制帧计数与状态变化时的额外发送
    模式字段 当前只用 mode=0/1 不代表其余模式在实车被验证

    横向与纵向:控制器负责限幅,构帧器不查许可

    CarController 在横向发送前计算当前曲率、按车速施加曲率误差/速率限制,然后对 CAN FD 与经典 CAN 分别构帧。两条路径的 path_offset、path_angle、curvature_rate 在当前调用中都传零——源码中对多项式完整操控的描述不是当前已启用能力。

    纵向方面,自控纵向的 gas 和 accel 分开限幅;若非 longActive 或油门低于门槛,油门设为中性原始值。制动预充/减速请求根据坡度补偿后的加速度在 >0.3 与 <0 之间迟滞,位状态由控制器记忆。构帧器不自行检查这些状态是否与 panda 许可一致:限幅是主机策略,许可在固件。

    两种 UI 构帧和按钮构帧从 CarState.update() 缓存的原车解析字典复制字段。字典存在不等于所依赖 CAN 帧足够新鲜;插件接口应保留总线、时间戳和健康信息,并在台架验证失联后的透传行为。panda 对 ACCDATA_3/IPMA_Data 有白名单但无逐字段专属限制,对按钮仅专门约束 cancel/resume 权限。

    名义频率不能当负载预算

    fordcan.py 的 docstring 所列 33/20/50/5/1 Hz 是名义频率,实际来自 100 Hz 控制帧计数和状态变化时的额外发送。create_button_msg() 自身写 10 Hz,但 cancel 可以随每次控制更新发送。不能拿函数注释当作总线最大负载预算。

    新硬件或插件化验收至少要分别验证:车型 flags、CAN FD/经典 DBC、总线偏移、帧长度、计数器/校验、原车 UI 字段的新鲜度,以及 panda TX 拒帧。Ford 构帧插件只能交付候选帧;白名单、曲率/纵向限值及原车 AEB 禁止位必须继续由独立安全层执行。

    固定快照附带两份离线探针用于核对契约:原版 DBC 构帧探针把经典 CAN 与 CAN FD 两种格式各验证一次,界内帧通过、主机速度突变候选被拒;此前的手工帧探针用正的曲率 CAN 单位测试对称安全限值,但控制器实际在调用 fordcan 前将曲率取负,原版探针按该符号链送入 CANPacker,并包含 DBC 精度位与 CAN FD 校验。需要记住边界:它未覆盖 CarController.update() 的前置测量裁剪、状态迁移或车辆 ECU 响应。

    常见问题

    calculate_lat_ctl2_checksum 是 CRC 吗?

    不是。它从已编码的 8 字节中抽取曲率、曲率率、路径角、路径偏移的原始位值,加模式和计数器,再取 0xFF - (sum & 0xFF),是与固件同位置取值对应的专用算法,不是通用 CRC,也不能当作跨平台字节数组插件。

    Ford 的 CAN 总线一定是 bus 0 吗?

    不是固定值。CanBus 用 main=offset、radar=offset+1、camera=offset+2 映射,偏移由基类按 len(CP.safetyConfigs) 以 4 路一组推导,所以不能硬编码所有车辆为 bus 0。

    控制器已经限幅,为什么还要固件安全门?

    因为构帧器不检查状态是否与 panda 许可一致。主机侧只负责曲率/纵向限幅与状态记忆,白名单、曲率与纵向限值、原车 AEB 禁止位仍由独立固件层裁决;构帧器只交付候选帧。

    函数注释里的发送频率能当负载预算吗?

    不能。33/20/50/5/1 Hz 是名义频率,实际来自 100 Hz 控制帧计数和状态变化时的额外发送;create_button_msg() 虽写 10 Hz,cancel 仍可随每次控制更新发送。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/FORD_CAN_FRAME_CONSTRUCTION_CONTRACT_DEEP_DIVE.md(取用了 fordcan.py 构帧函数契约、CAN FD 校验算法、总线映射与名义频率边界)。
    • 项目 02 —— openpilot-research/FORD_PANDA_SAFETY_MODE_DEEP_DIVE.md(仅用于确认固件侧白名单与限值边界,未取用其未公开内容)。

    说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • Strym 工具链:Toyota RAV4 / CHR 与 Honda Pilot 的 CAN 记录与可视化

    结论:Strym 不是一个「某台车的信号表」,而是一套围绕 comma.ai Panda 与 Giraffe 连接器的 CAN 数据记录、分析与可视化工具链,文档把它的适用车型举例为 Toyota RAV4、Toyota CHR 与 Honda Pilot。它能做的是:把 OBD 口采到的原始帧按 DBC 解码成时间序列,再用 isoviz/isolog 实时绘图或离线分析。关键边界在于——真正的信号定义来自外部 DBC 文件(示例引用 newToyotacode.dbc),源文档并未附上逐信号解码表,因此不能据此列出任何一台车的具体信号清单。

    本文整理自该工具项目的说明文档。它记录的是「数据怎么进、怎么出」的管线,而不是某个车型的字段含义;下文严格区分「文档已说明的工具能力」与「文档未给出的车型信号定义」。

    车辆与适用范围

    源文档以举例方式列出可用车型,并说明其数据形态是「Panda 与 Giraffe 采到的时间序列」。文档给出的示例 CSV 文件名包含一个 RAV4 的 VIN,但它没有标注年款、市场版本或具体配置,也没有针对任一车型给出字段验证结论。

    项 内容
    车型 文档举例:Toyota RAV4、Toyota CHR、Honda Pilot(表述为「supported modern vehicles such as …」)
    年款 / 市场版本 源文档未确认;示例 CSV 文件名含 VIN 2T3MWRFVXLW056972,未标注年款
    ECU / 改装状态 由 comma.ai Panda USB-CAN 板配合 Giraffe 连接器接入车辆 OBD 口采集
    采集跨度 源文档未给出;示例为一段 CSV 记录
    适用范围 工具能力层面;不含任一车型的逐信号定义与验证

    总线与寻址

    文档只说明数据经 Panda 与 Giraffe 从 OBD 口进入主机,并由 DBC 文件解析消息。它没有给出物理层速率、11 位 / 29 位寻址、CAN FD 是否存在等链路层细节,也没有描述 OBD 口后是否存在网关。这些都属于源文档未覆盖项,本文不补。

    项 内容
    物理层 经 comma.ai Panda + Giraffe 从 OBD 口采集(源文档未给速率)
    链路层 源文档未给出
    寻址 源文档未给出 11 位 / 29 位结论
    CAN FD 源文档未提及
    消息定义来源 外部 DBC 文件(示例引用 newToyotacode.dbc)

    已解码信号

    源文档是工具项目,没有提供逐信号的解码表;信号含义由外部 DBC 决定,而该 DBC 内容未收录在文档中。下表只列出文档中可确认的可解码对象与数据通路,每条的证据都指向工具说明本身,而非某台车的实测。

    条目 位置(来源 / 入口) 解码 / 处理 证据
    消息类型 SPEED DBC newToyotacode.dbc;示例属性号 1 作为 isoviz / isolog 的「消息类型 + 属性号」入参 源文档示例代码
    车速时间序列 strymread(file).speed() 返回速度数据框(DataFrame) 源文档「快速开始」
    时间列 Time CSV 第 1 列(Unix 秒) 解析为 Pandas DataFrame 的时间列 源文档格式表
    数值列 Message CSV 第 2 列 解析为 DataFrame 的数值列 源文档格式表
    车型 Toyota RAV4 支持车型举例 由 Panda + Giraffe 接入 OBD 采集 源文档
    车型 Toyota CHR 支持车型举例 同上 源文档
    车型 Honda Pilot 支持车型举例 同上 源文档
    DBC 解码 cantools 库 按 DBC 消息定义解码原始帧 源文档依赖与示例
    实时可视化 isoviz() 边采集边绘制目标信号,同时写 CSV 源文档示例
    离线分析读入 strymread(csvfile, dbcfile) 读 CSV + DBC 后调用分析方法 源文档快速开始

    读取方法与注意事项

    输入形态。文档规定工具期望的时间序列是两列 DataFrame:Time(Unix 时间戳)与 Message(数值)。文档特别说明,虽然默认来源是 Panda,但任何符合该两列格式的时间序列都可以使用这套方法,因此它的处理对象是「规整后的时间序列」,不是原始帧本身。

    实时与离线两条路径。实时路径用 isoviz():它按「消息类型 + 属性号」指定要看的信号,一边把 CAN 消息写进 CSV,一边绘制该信号;按 Ctrl-C 触发 SIGINT 处理,结束记录并把图分别保存为 pdf 与 pickle。离线路径先用 strymread() 读入 CSV 与 DBC,再调用具体分析方法(例如 speed())。

    工程条件。文档列出的软件要求是 Ubuntu 20.04 或更高、Python 3.12 与 UV 包管理器;硬件要求是 comma.ai Panda 板、Giraffe 连接器与一台带 CAN 总线的现代车辆。若在树莓派上安装,文档建议从源码装 Python 3.7,并预先准备 NumPy 的预编译二进制,否则构建会比较麻烦。以上都是源文档给出的操作条件,本文未在实车上复核。

    证据等级与边界

    源文档是工具说明,没有为任何字段标注置信度或证据等级,也没有给出原始 CAN 抓包或实车验证结论。它唯一带有「实测」色彩的内容是一段示例 CSV 与一段示例 DBC 的引用,二者都只是用法演示。

    因此边界很明确:第一,本文列出的信号条目只是「文档说明的处理对象与数据通路」,不代表任何车型的真实字段含义;第二,真正的信号定义在外部 DBC 里,而该 DBC 未被收录,无法据本文列出某一台车的信号清单;第三,支持车型是文档的举例表述,其年款、配置与协议细节均未确认。任何字段级结论都不能从工具文档外推到具体车辆。

    常见问题

    Strym 支持哪些车型?

    源文档以举例方式写出 Toyota RAV4、Toyota CHR 与 Honda Pilot,并说明适用对象是「带 CAN 总线的现代车辆」。它没有给出完整的支持清单,也没有标注每款车的年款与配置,本文不据此扩展。

    它能直接给出某台车的信号清单吗?

    不能。该项目的信号含义来自外部 DBC 文件,示例引用的是 newToyotacode.dbc,而源文档没有收录该文件内容,也没有逐信号解码表。它提供的是「用 DBC 解码」的工具能力,不是现成的车型字段表。

    它的数据格式是什么?

    文档规定核心输入是两列 Pandas DataFrame:Time(Unix 时间戳)与 Message(数值)。符合该格式的时间序列都能使用这套方法,不一定非得来自 Panda。

    这套工具能替代某台车的协议分析吗?

    不能。它负责记录、解码与可视化,协议与字段含义由外部 DBC 决定。要判断某台车的字段,仍需以该车自己的 DBC 与实测为准,本文不把工具文档当作车型结论。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/jmscslgroup-strym/README.md(本项目车型档案唯一来源;取用了支持车型举例、两列数据格式与 isoviz/strymread 工作流)。

    说明:本文整理自第三方开源项目的公开文档,仅代表该文档所记录的单个车辆样本,不代表同型号全系车型。CAN 与诊断操作存在风险,任何实车操作前请自行复核并遵守当地法规。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • BMW E46 PT-CAN 数据档案:MS42/MS43 的 500 kbps 报文表

    结论:BMW E46 的 PT-CAN 是一张没有加密、没有网关隔离的广播总线:500 kbps、11 位 ID、DLC=8,DME、DSC、IKE、转向角传感器和(选装)变速箱都在这张网上直接广播,被动监听即可解码转速、水温、车速、四轮速、转向角、制动压力、挡位、里程与油量等信号。它的典型难点不在「能不能抓」,而在同一份 ID 在 MS42(M52TU)与 MS43(M54)上字节位置不同:源文档明确标注 MS42 的字节位置是从 MS43 文档抄来的、仍需真实抓包验证。下述结论仅限源文档记录的这一套 DME+DSC+IKE 组合。

    车辆与适用范围

    源文档是一份开源车载仪表项目为 E46 机箱写的 CAN 参考,信号表的权威来源是公开的 MS4X 维基,项目自述其解码表「逐字节镜像维基表格」。项目本身处于早期(README 自述 Early),只覆盖 E46 的 PT-CAN 一张网。

    项 内容
    车型 BMW E46,覆盖 M52TU(MS42)与 M54(MS43)两种 DME
    年款 / 市场版本 源文档未给出具体年款与市场版本,只按 DME 区分 M52TU / M54
    ECU / 改装状态 DME(MS42/MS43)、MK60 / DSC III ABS、IKE 仪表、转向角传感器、可选 EGS 自动变速箱;使用 SLCAN 适配器被动监听,不改线束
    采集跨度 源文档未给出日志数或帧数;DBC 侧记载 MS42 文件 11 条报文、102 条信号,MS43 文件 11 条报文、108 条信号
    适用范围 仅限文档所记录的 MS42/MS43 + DSC + IKE 组合;具体年款、动力总成、ABS 版本与配置须自行核对

    总线与寻址

    源文档明示 PT-CAN 运行在 500 kbps、11 位 ID、DLC=8。多字节整数都注明端序;位位置写成 B<字节>.<位>,位 0 是 LSB;百分比缩放的规范系数是 BMW 的 0.390625 = 100/256。有一点很关键:项目只做广播帧的监听与解码,明确不做诊断协议(无 DS2、无 UDS、无 EDIABAS)。

    项 内容
    物理层 双绞线 CAN,PT-CAN(动力总成 CAN)
    链路层 / 比特率 500 kbps(源文档明示)
    寻址方式 11 位 ID,DLC=8
    CAN FD 否;源文档按经典 CAN(8 字节载荷)处理
    端序约定 绝大多数报文为 Intel/小端;LWS1(0x1F5,转向角)为 Motorola/大端
    不做的事 不含诊断协议;电池电压不在 PT-CAN 广播,只能走 DS2 诊断

    已解码信号

    下表从源文档的信号表中抽取代表性条目。MS43 独有或与 MS42 位置不同的信号单独标注;源文档标注「未验证」「无外部旁证」的条目按原样保留。

    信号 位置(ID / 字节 / 位) 解码 证据
    转速 N_ENG 0x316 DME1,B2-B3 小端 × 0.15625 rpm MS4X 维基 0x316 页
    指示扭矩 TQI_CAN 0x316,B4 × 0.390625 % MS4X 维基 0x316 页
    冷却液温度 TEMP_ENG 0x329 DME2,B1 × 0.75 − 48 → °C MS4X 维基 0x329 页
    油门踏板 TPS_CAN 0x329,B5 × 0.390625 % MS4X 维基 0x329 页
    车速 VSS 0x153 ASC1,13 位(B1.3-7 + B2) ((MSB×256+LSB − 0x160) × 0.0625) km/h 维基公式;源文档指出维基公式与「最小值 0x160」不自洽,解码器补了偏移并钳位到 ≥0
    四轮车速 0x1F0 ASC2,B0-B7 小端(每 2 字节一轮) (raw − 44) / 15.875 km/h MS4X 维基 0x1F0 页;raw 最小 0x002C=44 对应 0
    转向盘转角 ANG_PSTE 0x1F5 LWS1,B0-B1 大端 有符号 × 0.04394° 维基页;源文档指出维基把量表四舍五入,真实系数约 0.04395,解码器仍用维基系数
    转角角速度 VEL_ANG_PSTE 0x1F5,B2-B3 大端 有符号 × 0.04394 °/s MS4X 维基 0x1F5 页
    制动压力 P_BRAKE 0x1F8 ASC4,B2 × 1 bar(0–255) MS4X 维基 0x1F8 页
    纵/横向加速度 AX_REF / AY_REF 0x1F3 ASC3,10 位有符号原始值 维基未给缩放;界面按 10 位有符号原始值呈现 MS4X 维基 0x1F3 页(无缩放公式)
    挡位 GEAR_INFO 0x43F EGS1,B0.0-2 3 位枚举(0=N,1-6 前进挡,7=R) MS4X 维基 0x43F 页
    里程 KM_CTR_CAN 0x613 ICL2,B0-B1 小端 × 10 → km MS4X 维基 0x613 页
    油量 FTL_CAN 0x613,B2.0-6 7 位原始值(仪表映射到刻度) MS4X 维基 0x613 页
    机油温度 TOIL_CAN 0x545 DME4,B4(MS43 独有) raw − 48 → °C MS4X 维基 0x545 页;MS42 不广播此字节
    油面高度(MSS54HP) 0x545,B6(MS43 独有) (raw − 158) / 10 → L MS4X 维基 0x545 页

    读取方法与注意事项

    第一是端序陷阱:源文档特别提醒 Intel/小端的 start bit 是 LSB,而 Motorola/大端的 start bit 是 MSB,两者在同一个字节里所指的位完全不同。E46 上除 LWS1 转向角外都是 Intel,LWS1 是唯一的 Motorola 报文,混用会解出错误数值。

    第二是 MS42 / MS43 的字节错位:源文档用一整节列出 DME 发送帧里两种 DME 把信号放在不同位置的条目。例如 TQI_MAF_CAN 在 MS43 位于 DME1 的 B7、在 MS42 位于 B6;机油温度、换挡提示、机油压力低、胎压、机油液位等一串信号在 MS42 上根本不广播。源文档据此为 MS42 做了一个去掉 MS43 专有信号、并重定义 TQI_MAF_CAN 与 ERR_AMT_CAN 字节位置的配置。

    第三是维基公式的已知瑕疵。车速那条,维基同时给出「公式 = ((MSB×256)+LSB) × 0.0625」和「最小值 0x160(0 km/h)」,两者只有在先减偏移再缩放时才自洽;解码器选择减去 0x160 并钳位到 ≥0,让静止车读 0。转向角那条,维基把量表取整到 5 位有效数字(0.04394),真实系数约为 0.04395,量程末端会有约 0.2° 偏差。

    第四是取值语义:源文档规定解码器只在「该帧本就不携带该信号」时(多路复用场景)返回空值,绝不把「数值未知」编码成空值——那是仪表该处理的事,不是解码器的职责。

    证据等级与边界

    可视为外部旁证的是各条 ID 对应的维基页面,项目自述解码表与维基表格逐字节一致;这属于公开文档级证据,不等同于本项目自己的实车复现。属于明确不确定性的是 MS42:维基 MS42 页自己写了「数值抄自 MS43 页,需验证」,因此 MS42 专有的字节位置在真实抓包确认前应视为暂定。

    不能外推的地方有两处。第一,可选装件会改变报文存在性:EGS 自动变速箱、SMG 变速箱、MSS54 相关信号只在对应配置上出现,源文档明确把 0x338 DME3、0x43D AMT1、0x445 TXU1、0x610 ICL1 列为「未解码」,理由分别是赛道化选装、缺真实 SMG 抓包、维基页为空、以及对 VIN 远程帧只做被动监听。

    第二,本文所有条目都绑定 E46 PT-CAN 这一张网与文档所列 ECU 组合,不能套到其他宝马机箱或其他总线(例如诊断总线)。电池电压这条尤其要记住:源文档写明它不在 PT-CAN 由任何已记录的 DME 广播,只能通过 DS2 诊断获得,所以「在广播流里找电池电压」在这台车上找不到。

    常见问题

    E46 的 OBD 口能直接抓到这些信号吗?

    源文档记录的是 PT-CAN 广播帧的监听与解码,总线为 500 kbps、11 位 ID。它明确不做诊断协议(无 DS2、无 UDS、无 EDIABAS),也不保证从标准诊断适配器(如只透传 ISO-TP 请求/响应的电缆)能拿到广播帧;实际取数用 SLCAN 适配器被动监听。

    为什么同一条 ID 在 MS42 和 MS43 上解码结果不同?

    因为源文档列出了一串信号在两种 DME 上位于不同字节:例如 TQI_MAF_CAN 在 MS43 是 DME1 的 B7、在 MS42 是 B6,机油温度等信号 MS42 直接不广播。项目为此为 MS42 单独定义了一套配置。

    车速解码为什么要先减 0x160?

    因为源文档指出维基的公式与「最小值 0x160 对应 0 km/h」不自洽,只有在缩放前减去该偏移才能让静止车读 0;解码器据此补了偏移并钳位到 ≥0。

    电池电压能从总线上读到吗?

    不能。源文档写明电池电压不在 PT-CAN 由已记录的 DME 广播,只能通过 DS2 诊断获得。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/emdzej-dashx-e46/docs/bmw-e46-can-ids.md(主来源:E46 PT-CAN ID 与逐字节信号表)。
    • 项目 01 —— public-can-dbc-datasets/additional/emdzej-dashx-e46/docs/vehicle-overlays.md(DBC + overlay 表达方式与端序/复用说明)。
    • 项目 01 —— public-can-dbc-datasets/additional/emdzej-dashx-e46/SOURCE.md(快照范围、DBC 信号条数与适用范围提示)。

    说明:本文整理自第三方开源项目的公开文档,仅代表该文档所记录的单个车辆样本,不代表同型号全系车型。CAN 与诊断操作存在风险,任何实车操作前请自行复核并遵守当地法规。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • pandad 原生 CAN 编解码与健康回执:短读、下溢与 512 字节缓冲

    结论:原生 pandad 的 Panda C++ 封装把「CAN 编解码」「健康回执」「命令确认」拆成三层,但三层的校验并不对称——发送路径用 assert 而非显式长度校验,接收路径存在短读下溢,健康结构接受零字节/短读。因此「sendcan 收到」「SPI 交易成功」「MCU 已入队」「安全钩子放行」是四个不同观测点,任何一个都不能替代另一个。

    位置与调用链:从 sendcan 到 6 字节帧头

    Panda 是 pandad.cc 与 PandaSpiHandle 之间的 C++ 设备封装,而 can_header 把总线、DLC、拒绝/回环位、29 位地址和 XOR 校验压成 6 字节。构造函数创建 SPI 句柄、读取板型,再用 0xc0 清通信状态。

    发送路径从 sendcan 取消息并做一秒年龄门,再调用 can_send();接收路径从 can_receive() 得到帧,包装为 can 事件,并把 bool 结果写入事件 valid。send_panda_states() 消费健康结构,按 ignition/onroad 调整安全模式和省电,心跳由后续的 process_panda_state() 发送。封装本身不是独立的 MCU 安全策略,它只是主机侧的一段设备协议。

    函数/组件 作用与边界
    Panda::Panda()、get_hw_type() 构造 SPI 句柄、查板型、复位通信;板型读未核对返回长度。
    get_state()、get_can_state() EP0 读取 health_t/can_health_t,负值才返回空值。
    get_firmware_version()、up_to_date() 两次 64 字节读拼签名,与本地签名文件尾部比较;这不是运行中固件完整性远程证明。
    len_to_dlc()、pack_can_buffer() 过滤非本 Panda 总线,编码 DLC/头/XOR;批次达到 256 字节后调用写回调。
    can_send() 把批次写向 bulk 端点 3,未向调用方返回实际写入量或错误。
    can_receive()、unpack_can_buffer() 从端点 0x81 读最多 16 KiB,保留未完整帧;XOR 失败清接收缓存并请求 MCU 复位通信。

    CAN 字节流边界:512 字节缓冲与 256 字节软阈值

    发送缓冲为 2 * USB_TX_SOFT_LIMIT(512 字节),每个合法 CAN FD 帧至多 6 + 64 字节,写后超过 256 字节就清零位置。因此在长度被限制为 64 的前提下,单次追加不超过缓冲。

    但当前的长度检查只有 assert:代码先把 can_data.size() 传给接受 uint8_t 参数的 len_to_dlc(),再断言 <=64 及长度与 DLC 表相符。在关闭断言的构建中,超长或不能由 CAN FD DLC 表表示的负载不被拒绝,随后的 memcpy 仍按原始 can_data.size() 写进 512 字节栈缓冲。即使保留断言,这也是进程终止而非可恢复的输入错误,必须先做显式长度/DLC 校验再写缓冲。

    另一点常被误读:src 在 cereal CanData 中已经是 UInt8,因此不能把 C++ 局部 uint8_t 赋值本身当作独立的源总线截断漏洞;bus < 4 才是此封装对可发送总线的实际门。

    assert 不是输入校验:短读下溢与半包

    接收循环的条件是 pos <= size - sizeof(can_header),其中 size 为 uint32_t 而 sizeof 为无符号 size_t。当本次读取只得到 1–5 字节且之前没有半包时,减法下溢,循环仍可能进入并从不足 6 字节的数据中拷贝头,之后按头部 DLC/长度判断和移动缓冲,属于条件性越界/错误解析风险。SPI bulk 读允许返回实际收到的字节数,不能假设总是帧头以上。改法是先判断 size - pos >= sizeof(can_header),且只在 pos <= size 不变量成立时做减法。

    头中的 DLC 为 4 位,查 16 项表本身有边界;完整帧的 XOR 校验失败会清缓存,但已在同一轮压入 out_vec 的先前帧不会回滚,上层会发布 valid=false 的事件。接收缓存大小为 RECV_SIZE + sizeof(can_header) + 64,can_receive() 只用 assert 检查剩余容量再读 16 KiB;正常解析最多保留一个未完成帧,但不应依靠断言证明这个不变量。

    健康回执与命令确认的分离

    get_state()、get_can_state() 把结构体零初始化,但只以 err >= 0 接受控制读。SPI 层返回实际字节数,因此零字节或短读也可能被包装成「存在的健康结构」;send_panda_states() 只检查 optional 是否存在,随后据这些字段判断点火、模式及省电。get_serial() 同样接受非负短读;get_firmware_version() 则要求两次恰好 64 字节;风扇 RPM 与板型读没有长度门。这里属于主机读取契约风险,不能推断正常 MCU 必然会产生短响应。

    安全模式、心跳、波特率、IR、电源等控制写方法为 void,未检查 SPI 交易返回值;can_send() 也丢弃 bulk_write 的字节数/错误。这正是必须区分四类观测点的原因:

    观测点 它到底证明了什么
    sendcan 消息收到 主机侧已提交发送请求,仅此而已。
    SPI 交易完成 字节写到了端点;返回值可能被调用方丢弃。
    MCU 入队 需固件侧回执,封装层不提供确认。
    安全钩子放行 由 panda 固件独立许可,主机侧无从得知。

    自制硬件与插件重构的最低契约

    设备插件可以输出带设备身份、采样时间、实际字节数及逐字段有效位的只读健康数据;可替换的 CAN 观测解码器须显式声明帧头、DLC、校验、总线编号和分块恢复契约。发送则由单一受信任网关持有能力:插件只提交候选帧,网关在序列化前校验载荷长度/总线/地址,实施年龄门、资源上限和安全策略,并分别报告「接收请求、SPI 完成、MCU 入队、被安全拒绝」等可观测结果。安全模式、心跳和复位绝不开放给普通插件直接调用。

    离线单测应优先覆盖 0–5 字节短头、分块恰在头中间结束、CAN FD 合法长度与非法 9/65/超大长度、非本 Panda 总线过滤、坏 XOR 前已有好帧、健康结构短读,以及 bulk 部分写/负返回。随后在无车台架以 ASan/UBSan、故障注入和 MCU 回执核验;真实车辆执行控制还需车型安全钩子与接管测试。

    常见问题

    为什么「sendcan 收到」不能当作 MCU 已发送?

    因为 can_send() 丢弃 bulk_write 的字节数与错误,控制写方法为 void;sendcan 只是主机侧入队请求。SPI 交易成功、MCU 入队、安全钩子放行是另外三个独立观测点。

    发送超过 64 字节的 CAN FD 负载会被拒绝吗?

    当前长度检查只有 assert。在关闭断言的构建中不被拒绝,memcpy 仍按原始长度写进 512 字节栈缓冲;即使保留断言,这也是进程终止而非可恢复的输入错误。

    为什么 1–5 字节的 SPI 读取会导致帧头解析错误?

    因为接收循环用无符号的 size 减去 sizeof(can_header),短读时减法下溢,循环仍可能进入并从不足 6 字节的数据中拷贝头。改法是先判断 size - pos >= sizeof(can_header)。

    健康结构读到零字节意味着什么?

    get_state()、get_can_state() 只以 err >= 0 接受控制读,零字节或短读也可能被包装成「存在的健康结构」,send_panda_states() 只检查 optional 是否存在,因此不能把结构存在当作字段有效。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/PANDAD_NATIVE_PANDA_CAN_CODEC_HEALTH_CONTRACT_DEEP_DIVE.md(取用了 CAN 字节流边界、短读下溢、健康回执与命令确认分离的静态结论)。
    • 项目 02 —— openpilot-research/PANDAD_NATIVE_SPI_RESPONSE_BOUNDS_RETRY_CONTRACT_DEEP_DIVE.md(仅用于确认底层 SPI 响应长度与重试契约的边界)。

    说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • Fisker Ocean 2023-24 的 ADASBUS:单总线取数与 92 个地址

    结论:这台 Fisker Ocean 2023-24 的 CAN 数据特征不是「OBD 口后面有没有网关」,而是整车信号被网关镜像到一条 ADASBUS 上:只需要接一条 CAN-FD 总线就能读到车身与 HMI 信号。源文档记录,panda 以摄像头转接线束插在原车网关侧(bus 0)与 OEM ADAS 模块侧(bus 2)之间,bus 1 未使用;bus 0 一次实车指纹抓取到 92 个地址(网关镜像的车身/HMI 加上 ESP、EPS、YRS、BCM、VCU、MFS、ICC),bus 2 约 65 个地址且全部由 ADAS 发出。下述结论仅限源文档记录的这一台车与 2023-24 年款,不代表同型号全系。

    车辆与适用范围

    源文档是一份开源 ADAS 项目里的车型平台定义,属于单车型移植(single-model port),不是车厂或第三方机构的批量采集。文档明确说明固件版本指纹被故意留空,识别以 CAN 指纹为准,因此「适配到哪一台车」由这一次实车抓包决定。

    项 内容
    车型 Fisker Ocean 2023-24(源文档记为 Ocean Extreme 整备质量口径)
    年款 / 市场版本 2023-24;市场版本源文档未确认
    ECU / 改装状态 摄像头转接线束(camera-splice harness);panda 接在车辆侧网关与 OEM ADAS 模块之间;bus 1 未使用
    采集跨度 源文档只写「来自一次实车指纹抓取(live fingerprint capture)」,未给出日志数或帧数
    适用范围 仅限该次抓取的一台 2023-24 Ocean;轴距、方向盘比、轮胎刚度等车辆模型参数仍标注为待阶跃响应日志复核

    总线与寻址

    源文档把总线分成两侧:车辆侧(bus 0)与 OEM ADAS 模块侧(bus 2)。因为网关把车身/HMI 信号镜像到同一条总线上,移植只需要接一条总线;bus 1 在代码里被标为未使用。报文 ID 都是 11 位,ADAS 侧除固定报文外还有一段雷达目标列表。

    项 内容
    物理层 CAN-FD 双绞线;源文档注明 ADASBUS 为 CAN-FD
    链路层 / 比特率 源文档未给出比特率数值
    寻址方式 11 位 ID,例如 0x117、0x118、0x121、0x1C0、0x1D0、0x313、0x314、0x315、0x316、0x317、0x31A、0x31C
    总线划分 bus 0 = 车辆侧(网关镜像);bus 2 = OEM ADAS 模块侧;bus 1 未使用
    CAN FD 是;源文档按 CAN-FD 处理
    SecOC 0x1D0 与 0x121 受 SecOC 保护;同步报文 0x20 GW_Syn_All,50 ms,线上 40 位 freshness

    已解码信号

    下表只登记源文档里带证据或明确标注状态的条目。挡位枚举与按键映射直接来自平台定义中的 DBC 值表与按键映射表;转向与加速度指令给出缩放与周期,但周期条目原文标注为「需从日志确认」。雷达目标只给 ID 区间,未给字段定义。

    信号 / 功能 位置(ID / 来源) 解码 证据
    挡位 VCU_GearSig 网关镜像到 bus 0 的 VCU 报文 枚举 1=P、2=N、3=R、4=D、6=E、7=S 平台定义 DBC VAL_ 注释
    转向角指令 ADAS_LatCtrl_SteerAnReq 0x1D0(ADAS 侧) 0.0625°/LSB,量程 ±780°;周期 10 ms(≈100 Hz),原文标注需从日志确认 平台定义注释
    加速度指令 ADAS_LgtCtrl_AccelReq 0x121 0.0004882 m/s²/LSB,偏移 −16 平台定义注释
    驾驶员转向力矩 EPS_DrvrSteerTq 网关镜像的 EPS 报文 0.01 Nm/LSB;驾驶员接管阈值 0.5 Nm 平台定义注释
    巡航主开关 MFS_RiBtnNorth MFS(方向盘多功能开关) 映射为 mainCruise(ADAS 总开关) 按键映射表
    巡航设定 MFS_LeRollPress MFS 映射为 setCruise(接合巡航) 按键映射表
    加速 / 减速 MFS_LeRollUp、MFS_LeRollDwn MFS 映射为 accelCruise / decelCruise 按键映射表
    LKAS 开关 MFS_RiBtnSouth MFS 映射为 lkas 按键映射表
    取消 / 恢复 / 车距调节按键 MFS 源文档标注为 TBD(待台架测试确定) 按键映射表注记
    雷达目标列表 0x2C7…0x2E9(ADAS 侧) 源文档只给 ID 区间,未给字段定义 总线说明
    网关镜像的车身/HMI 信号 bus 0 挡位、踏板、车门、安全带、转向灯、MFS 按键 总线说明

    读取方法与注意事项

    第一条是取数路径:因为网关把车身/HMI 信号镜像到 ADASBUS,移植只接一条总线,摄像头转接线束让 panda 落在车辆侧网关与 OEM ADAS 模块之间。源文档强调 bus 1 未使用,因此不要把抓不到流量归因于「少接了一条线」。

    第二条是 SecOC:转向角指令与加速度指令在 ADAS 侧受 SecOC 保护,需要同步报文 0x20 GW_Syn_All 提供的 40 位 freshness,同步报文周期 50 ms。源文档说明这些数据 ID 在 AUTOSAR Short SecOC 口径下等于 CAN 报文 ID。任何只解析载荷、不做 freshness 校验的读取方式,都拿不到可信的指令值。

    第三条是周期:0x1D0 每个控制帧都发送,源文档把周期记为 10 ms(≈100 Hz),但同一行原文写了「需从日志确认周期」,因此本条保留不确定性,不作为实测结论。第四是识别:固件版本指纹被故意留空,品牌不参与固件版本匹配,CAN 指纹是唯一依据。

    最后是车辆模型参数:轴距按公布数据从 2.99 改成 2.921(源文档给出理由:原值让横向模型预期更慢的入弯、导致 MPC 在弯道入口过度指令转角),steerRatio 15.0 记为「first-cut」,tireStiffnessFactor 0.85 记为「crossover-typical」。这些都属待复核值,不应作为 Fisker Ocean 的通用参数。

    证据等级与边界

    可视为实车观测的是总线地址数量(bus 0 约 92 个、bus 2 约 65 个)与两侧总线的分工,它们来自一次实车指纹抓取;挡位枚举和按键映射来自 DBC 值表与映射表,属文档级证据。属于待复核或推测的是转向角周期、steerRatio、tireStiffnessFactor,以及取消/恢复/车距调节三个按键。

    不能外推的地方有三处。第一,源文档是单车型移植,固件指纹为空,挡位与按键映射只在这台车上被记录,其他年款、市场版本的报文布局未验证。第二,雷达目标列表只给了 ID 区间,字段含义未知,不能据此宣称读到了目标距离或速度。第三,车辆模型参数是工程首值,不是实测标定,换车即失效。

    关于「安全访问」类问题:源文档未提供任何绕过方法,且不建议尝试;本文只整理公开文档登记的广播信号与指令定义,不涉及对车辆安全机制的规避。

    常见问题

    Fisker Ocean 是从 OBD 口取数,还是接别的总线?

    源文档没有走 OBD 诊断口,而是接 ADASBUS:panda 以摄像头转接线束落在车辆侧网关(bus 0)与 OEM ADAS 模块(bus 2)之间。OBD 口在本车是否可读这些报文,源文档未给出结论,因此不能据此推断。

    为什么只需要接一条 CAN 总线?

    因为网关把车身/HMI 信号(挡位、踏板、车门、安全带、转向灯、MFS 按键)镜像到 ADASBUS 上,源文档说明移植只接一条总线即可;bus 1 未使用。

    转向角和加速度指令为什么不只解载荷?

    因为 0x1D0 与 0x121 受 SecOC 保护。源文档说明需要同步报文 0x20 GW_Syn_All(50 ms、40 位 freshness)才能得到可信指令值,只解析载荷不做 freshness 校验拿不到可信值。

    挡位信号在哪条总线上?

    挡位来自网关镜像到 bus 0 的 VCU 报文,源文档的 DBC 值表给出 1=P、2=N、3=R、4=D、6=E、7=S 的枚举。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/jos-technion-fisker-ocean/README.md(主来源:该项目保留的开源 ADAS 项目根文档)。
    • 项目 01 —— public-can-dbc-datasets/additional/jos-technion-fisker-ocean/opendbc/car/fisker/values.py(平台常量、总线划分、挡位与按键映射、SecOC 说明)。

    说明:本文整理自第三方开源项目的公开文档,仅代表该文档所记录的单个车辆样本,不代表同型号全系车型。CAN 与诊断操作存在风险,任何实车操作前请自行复核并遵守当地法规。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • Mercedes-Benz W212 仪表台:CAN E 状态图与唤醒帧

    结论:2010 款 Mercedes-Benz E350(W212)的组合仪表是一个可以单独上台架的 CAN 节点:20 针连接器里只有 7 针有关,接上 500 kbit/s 的 CAN E 就能点亮。源文档用「试验法」(逐位扫描观察仪表反应)找出了 0x001 的状态编码与唤醒帧,并把 CAN E 的上电状态整理成一张状态图。以下所有结论仅限源文档记录的这一个仪表台。

    车辆与适用范围

    本文数据来自第三方开源项目对一台 W212 E350 组合仪表的台架逆向记录。项目的目标是把这个仪表台用于模拟赛车,因此在台架上重建了它的供电与 CAN 环境,再逐条找出让它显示、点亮的报文。

    项 内容
    车型 Mercedes-Benz E350(W212),2010 年
    对象部件 组合仪表(cluster);20 针 A1 连接器,其中只有 7 针有关:1 / 4 / 6 为供电,12 / 13 为 CAN E,17 / 18 为 CAN B
    台架硬件 Arduino Mega 2560 加 Seeed CAN-BUS Shield V2.0(MCP2515 控制器);两个 120 Ω 终端电阻
    台架参数 500 kbit/s;MCP2515 晶振 16 MHz;串口 115200 baud
    适用范围 仅限源文档记录的这个仪表台;不适用于其他年款或其他配置的 W212

    总线与寻址

    因为是「只把一个仪表台搬上台架」,环境被大大简化:没有整车、没有网关,只有仪表自身与台架控制器之间的两条总线。

    项 内容
    总线 CAN E(引脚 12 / 13)、CAN B(引脚 17 / 18)
    速率 500 kbit/s
    终端 两个 120 Ω 电阻
    控制器 MCP2515(经 Arduino Mega 2560 驱动)
    ID 约定 源文档的 DBC 中消息 ID 记为十进制,使用前必须转成十六进制
    状态可读性 仪表上电后自身会发出若干帧(0x015、0x39D),可作为机器可读的状态指示

    已解码信号

    下表从源文档的记录中抽取。项目把已确认的编码与仅来自 DBC 命名、尚未在台架上触发的条目分开,本文原样保留标注。

    信号 位置(ID / DID / 字节) 解码 证据
    CAN E 状态 0x001 B0 枚举:00=OFF、04=Minimal full ON、C2=Limited/ACC-like、CC=Alternate full ON、CF=Delayed OFF、07=过渡候选 已确认(试验法逐位扫描)
    唤醒 0x045 载荷 00 00 00 00 FF 00 00 00 已确认
    OK 按钮 0x045 载荷 00 00 00 00 FF 02 00 00 已确认
    车门状态 0x283 55 = 全关;56 = 左前门开 已确认
    状态指示 A 0x015 3D FE 00 00 与 00 FE 00 00 两种 标定记录
    状态指示 B 0x39D B0 及末字节 B0:80 或 FF;末字节为存活计数器(07, 0F, …, 7F) 标定记录
    驱动控制(DRIVER_CONTROLS) 0x045(DBC 十进制 69) — 标定记录
    点火(IGNITION) 0x245(DBC 十进制 581) — 未确认(静态搜索无响应)
    轮速(WHEEL_SPEEDS) 0x203(DBC 十进制 515) — 标定记录
    安全带(SEATBELT_SENSORS) 0x375(DBC 十进制 885) — 标定记录
    油门(GAS_PEDAL) 0x105(DBC 十进制 261) — 标定记录
    挡杆(GEAR_LEVER) 0x06D(DBC 十进制 109) — 标定记录
    挡位包(GEAR_PACKET) 0x073(DBC 十进制 115) — 标定记录

    读取方法与注意事项

    第一条是接线与终端。20 针连接器里真正有用的是 7 针:1 / 4 / 6 是供电,12 / 13 是 CAN E,17 / 18 是 CAN B。台架上需要接两个 120 Ω 终端电阻,否则总线反射会让通信不稳定。

    第二条是 ID 进制。源文档的 DBC 把消息 ID 记成十进制(如 69、581、515),而 CANID 是十六进制的——所以 DRIVER_CONTROLS 十进制 69 对应 0x045,IGNITION 十进制 581 对应 0x245。解析前必须先做这个换算,否则会对着错误的 ID 收发。

    第三条是「试验法」。项目找编码的方式是逐位扫描 0x001 的字节并观察仪表反应,从而归纳出 ON/OFF 的取值(如 00 表示 OFF、04 表示最小开启、C2 表示受限/类似 ACC、CC 表示另一种全开)。源文档还记录了一个细节:让保持开启成立的是约 450 毫秒的 07 脉冲。

    证据等级与边界

    项目有一条很好的「机器可读验证」手段:仪表上电后自身会发回 0x015(其值在 3D FE 00 00 与 00 FE 00 00 之间变化)和 0x39D(首字节 80 或 FF,末字节是存活计数器),因此台架可以用这些回发帧判断仪表当前处于什么状态,而不必靠肉眼观察。这比单纯看背光亮不亮更可靠。

    但也存在明确未解项。0x245(IGNITION)在静态搜索下没有任何响应,源文档把它归入未解与下一步清单。此外,若干信号(轮速、安全带、油门、挡杆、挡位包)只是按 DBC 命名列出,尚未在台架上逐一触发验证,本文按「标定记录」而非「已确认」标注。

    边界上必须强调:以上编码、载荷与状态图都限定在源文档记录的这个仪表台(2010 款 W212 E350)上。台架环境与整车环境不同——整车上有网关与其它节点参与,仪表台在整车上的行为未必与台架一致;不同年款或配置的仪表也可能使用不同的编码。

    常见问题

    为什么只接 7 根线就能点亮这个仪表?

    因为源文档确认 20 针连接器里只有 7 针有关:1 / 4 / 6 供电,12 / 13 为 CAN E,17 / 18 为 CAN B。其余针脚在该用途下不需要。台架上再接两个 120 Ω 终端即可组成可通信的最小系统。

    0x001 的状态值是怎么找出来的?

    用试验法:逐位扫描 0x001 的字节并观察仪表反应,归纳出各取值的含义(00=OFF、04=最小开启、C2=受限/类似 ACC、CC=另一种全开、CF=延时关闭、07=过渡候选)。源文档还指出让「保持开启」成立的是约 450 毫秒的 07 脉冲。

    怎么判断仪表当前处于什么状态?

    用仪表自己发回的帧作为机器可读指示:0x015 的值在 3D FE 00 00 与 00 FE 00 00 之间切换,0x39D 的首字节为 80 或 FF、末字节是存活计数器(07, 0F, …, 7F)。据此判断状态比看背光是否点亮更可靠。

    台架上找出来的结论能直接用到整车上吗?

    不能直接套用。台架是把这个仪表台从整车中独立出来,缺少网关与其它节点。同一仪表台在整车上的行为可能与台架不同,不同年款或配置的仪表也可能使用不同编码。实车使用前必须重新验证。

    延伸阅读

    参考资料

    • 项目 10 —— public-can-dbc-datasets/additional/izakulus-w212-cluster-notes/README.md(本项目车型档案主来源:接线、台架参数、状态图与未解清单)

    说明:本文整理自第三方开源项目的公开文档,仅代表该文档所记录的单个车辆样本,不代表同型号全系车型。CAN 与诊断操作存在风险,任何实车操作前请自行复核并遵守当地法规。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • process_replay 的配置、触发器与同步:14 个进程怎么被回放

    结论:process_replay 的 ProcessConfig 里 pubs 是注入给进程的主题,subs 是采集进程输出的主题——与被测进程自己的发布 / 订阅视角相反。回放的「首帧」「双摄齐备」「输出主题周期」都是测试调度逻辑,给出的是功能回归证据,不等于实时车载时序:processing_time 只用于给输出合成 logMonoTime,不是测量到的运行时延。固定快照基线为 c8fb906,本文对原版三个回调做了 AST 隔离探针,不启动任何受管进程。

    配置字段与调用顺序

    ignore 和 tolerance 由测试比较器消费;processing_time 仅给输出合成 logMonoTime;timeout 控制单个 run_step() 周期。vision_pubs 把相机状态与额外 VisionIPC 帧发送关联起来。注意 ignore_alive_pubs 在两个模型配置中赋值,但该字段在本回放模块没有读路径,不能把它当作已实现的存活校验豁免。

    get_process_config() 从表中深拷贝配置;ProcessContainer.__init__() 再深拷贝配置及受管进程,故有状态触发器通常每次回放独立。start() 依次建立隔离前缀、Params / 环境、config_callback、fake 事件、Pub / Sub、可选 VisionIPC、进程,再执行 init_callback。ProcessConfig.__post_init__() 对普通 MessageBasedRcvCallback 自动把触发主题设为 main_pub,模型配置则显式指定 VisionIPC 端点——后者的事件同步点是图像流端点,不能简单等同相机状态消息自身。

    14 个进程配置速查

    下表是回放触发逻辑,不是车型支持或测试实际覆盖矩阵;默认测试会排除两个模型进程。各行 pubs / subs 的完整清单以 CONFIGS 定义为准。

    进程 回放触发 / 同步入口 主要输出
    selfdrived carState,并设置 first_frame=True selfdriveState、onroadEvents
    controlsd selfdriveState carControl、controlsState
    card can 输出频率与 sendcan 启动门,main_pub_drained=True sendcan、carState、carParams、carOutput、radarTracks
    radard modelV2 radarState
    plannerd modelV2 longitudinalPlan、driverAssistance
    calibrationd cameraOdometry,first_frame=True extrinsicsCalibration
    dmonitoringd driverStateV2 driverMonitoringState
    locationd cameraOdometry deviceMotion(合成处理时间 10 ms)
    paramsd deviceMotion vehicleParameters
    lagd deviceMotion lateralDelay
    ubloxd 没有回调:每条被注入消息都可结束一轮 ubloxGnss、gpsLocationExternal
    torqued deviceMotion,first_frame=True lateralTorqueParameters
    modeld 双路道路相机状态标志;主入口为窄路 VisionIPC 端点 modelV2、drivingModelData、cameraOdometry
    dmonitoringmodeld cabinCameraState;主入口为座舱 VisionIPC 端点 driverStateV2

    除 locationd 外,显式 processing_time 是 selfdrived / card / paramsd 的 4 ms 和两个模型的 20 ms,其余默认 1 ms。这些值用于回放中不同进程输出的排序,不能拿来证明对应进程在硬件上达到该延迟。

    ignore / tolerance 由测试比较器消费,属于输出比对边界,而不是进程行为的一部分;调整它们改变的是「通过」的定义,而非被测逻辑本身。ubloxd 没有回调,每条被注入消息都可结束一轮——这类「无触发门」的进程在回放里最容易产生与真实节拍不同的批次划分。模型配置的 fake 事件主入口是图像流端点(窄路或座舱 VisionIPC),而不是相机状态消息本身。

    触发器逐函数行为

    MessageBasedRcvCallback.__call__() 返回「当前主题是触发主题」或「first_frame=True 且 frame==1」。这里的 frame 实际是 run_step() 完成周期后递增的 self.cnt。对非触发主题做隔离探针,计数为 0、1、2 时结果依次为 False, True, False;因此「首帧」并不意味着第一个到达的输入无条件结束周期。

    触发器 探针结果与含义
    ModeldCameraSyncRcvCallback 双摄时两路出现标志齐备才返回真并复位;单摄时窄路出现即可。输入 wide, wide, narrow 结果为 False, False, True——只追踪出现标志,不匹配 frameId,也不验证宽 / 窄帧同一时刻。
    card_rcv_callback 只对 can 计算输出主题周期 frame % int(can频率 / 输出主题频率),且 sendcan 在 (frame - 1) < 2000 时从候选主题删掉。频率相同且仅 sendcan 为输出时,周期计数 0、1、2000、2001 返回 False, False, False, True。
    selfdrived_config_callback 把 cfg.pubs 由列表改为集合差值,删除 GPS 二选一的一侧。
    card_fingerprint_callback 初始化时喂入最多 300 条 CAN,等待 CarParams 出现;get_car_params_callback() 优先按指定指纹构造参数,否则用 CAN、固件查询跳过标志和缓存去识别车型。

    某一路相机缺失时消息会在 msg_queue 中继续累积,不能把「已等齐两路」解释为视觉同步已验证。card_rcv_callback 是测试初始化阶段的输出采集门,不是车端允许发送 CAN 的 safety 决策;配置的频率比还需保持可除且 int 后非零,源码没有在此函数显式校验非法配置。

    对插件化与自制硬件的含义

    新增插件不能只注册一个进程名:应同时声明输入 / 输出主题、schema、触发帧或时间门、初始 Params、相机帧关联键、输出完整性和故障策略。回放配置要能区分「收到任意消息」「收到触发主题」「同一 frameId 的双摄齐备」和真实 deadline;当前回放的标志同步与合成时间戳只给出功能回归证据。自制相机 / 计算板还须独立验证时间戳域、丢帧 / 重复帧、IPC 缓冲寿命、端到端帧年龄、超时回退,以及 panda / opendbc 的发送限制。本文未运行目标硬件或完整回放。

    常见问题

    pubs 和 subs 到底哪个是给被测进程的?

    pubs 是注入给进程的主题,subs 是采集进程输出的主题,与被测进程自己的发布 / 订阅视角相反。混淆两者会读错回放配置。

    回放的 processing_time 是真实运行时延吗?

    不是。processing_time 只给输出合成 logMonoTime,用于回放中不同进程输出的排序。显式值有 selfdrived / card / paramsd 的 4 ms 与两个模型的 20 ms,其余默认 1 ms;不能拿来证明硬件达到该延迟。

    双摄对齐在回放里有校验吗?

    没有校验同一时刻。ModeldCameraSyncRcvCallback 只追踪宽 / 窄两路「出现」标志,标志齐备即返回真,不匹配 frameId。探针输入 wide, wide, narrow 得到 False, False, True。

    「已等齐两路」能说明视觉同步已验证吗?

    不能。回放只检查出现标志;某一路缺失时消息会在 msg_queue 中继续累积。「首帧」也不意味着第一个到达的输入无条件结束周期——它依赖周期计数在 1 时被其他条件允许。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/PROCESS_REPLAY_CONFIG_TRIGGER_SYNC_CONTRACT_DEEP_DIVE.md(取用了 ProcessConfig 字段、14 个 CONFIGS、触发器探针行为与插件化含义分析)。

    说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • Ford Fiesta MK5 影音 CAN 档案:125 kbps 车身信号

    结论:这份档案的对象是2006 年以后的 Ford Fiesta MK5(改款,配 2-DIN 与 6000CD 收音机)的影音 CAN(MS-CAN)。它的数据特征是「低速、易接入、以车身与影音信号为主」:总线速率 125 kbps,从收音机 QuadLock 连接器的 CANH/CANL 即可旁听,不需要 120 欧姆终端电阻;可见内容包括仪表显示屏文字(经 ISO-TP)、电台名、音量、CD 状态、时间、车门/车灯/挡位/踏板等。源文档只覆盖这一台改款 Fiesta 与这台 6000CD 收音机,且其定义文件不完整,部分报文只做到部分解码;下述结论不外推到其他年款或配置。

    车辆与适用范围

    源文档是一份逆向记录:作者以「截取收音机送给仪表 LCD 的文字」为起点,顺带解出若干其他报文。以下范围仅对应这一台车与这台收音机。

    项 内容
    车型 Ford Fiesta MK5,2006 年以后(MK5 改款),配 2-DIN 与 6000CD 收音机
    年款 / 市场版本 源文档以「>2006 改款」界定;其他年款与市场版本未确认
    ECU / 改装状态 无改装;在收音机 QuadLock 连接器的 CANH/CANL 上旁接一块 CAN 扩展板
    采集跨度 源文档未提供日志时长或帧数
    适用范围 仅这一台改款 Fiesta 与 6000CD 收音机的影音 CAN;定义文件不完整,部分报文仅部分解码

    总线与寻址

    源文档对物理层描述简练而具体:接入选定在收音机端,且对终端条件有明确说明。

    项 内容
    物理层 / 比特率 MS-CAN,125 kbps
    寻址 / 帧格式 源文档列出的 ID 均为 11 位标准帧(0x080–0x4F3)
    接入点 收音机 QuadLock 连接器的 CANH/CANL
    终端 不需要 120 欧姆终端电阻(源文档明示)
    CAN FD 源文档未提供(该年代与总线类型指向经典 CAN)
    传输层 仪表文字使用 ISO-TP(ISO 15765-2)分帧,含单帧与首帧/连续帧/流控

    已解码信号

    下表抽取源文档中最有代表性的条目(车身状态、影音与仪表文字)。位置列保留原文 ID 与字节序号,解码列保留其换算公式;证据列注明源文档对该条目的完成度或限定。

    信号 位置(ID / 字节) 解码 证据
    日期时间 0x080 / 字节 1–6 年(两位)、月、日、时、分、秒;1 秒分辨率 车载 RTC 独立于收音机时钟
    电台名 0x1E9 / 8 字节 ASCII 文本 完全解码
    转速 / 车速 / 油门 0x201 / 字节 1–2、5–6、7–8 km_h = speed/100;gas_percent = gas*100/50944 部分字段未标注
    转向灯箭头 0x265 / 字节 1 位掩码:左 0x20、右 0x40 位掩码按需相加
    前灯 / 手刹 0x286 / 字节 1 位掩码:手刹 0x10、示宽/近光 0x80、远光 0x40 示宽与近光共用同一 LED,无法区分
    音量 0x2D8 / 字节 2 volume = volume_raw/8 完全解码
    CD 状态 0x2DA / 字节 2、4 模式 0x2A/0x4A/0x6A;驱动器 0x23/0x21/0x22/0x26 枚举表完整
    CD 曲目 / 时间 0x2DB / 字节 3–4、6 曲目时间 track_seconds = track_time - 64;另含 track_id 非播放时为全 FF
    方向盘模式/选台键 0x2D5 / 字节 2 位掩码:模式 0x10、上选 0x40、下选 0x80 音量键不经此报文
    制动状态(一) 0x360 / 字节 6 未踩 0x60、轻搭 0x68、踩下 0x78 同一状态在两报文重复
    冷却液 + 制动(二) 0x420 / 字节 1、6 coolant_degrees = coolant - 40;制动 0x00/0x10/0x30 两处制动编码不同
    蓄电池电压 0x428 / 字节 2 battery_v = battery/10(十分之一伏) 完全解码
    车门 / 倒挡 / 锁止 0x433 / 字节 1、4、6 门位掩码:左前 0x80、右前 0x40、后备箱 0x08;倒挡 0x02;锁 0x10/解锁 0x20 位掩码完整
    仪表文字 0x4C0 / 短格式与扩展格式 短格式:0x07 0x34 + ASCII;扩展格式:首帧 0x10 + 长度 + 0x34,连续帧 0x21 + ASCII 为 ISO-TP;配套 0x4C8 流控
    车辆识别(VIN 低位) 0x4F3 / 8 字节 周期性广播的车辆 ID(VIN 低位,含生产日期信息) 完全解码

    读取方法与注意事项

    接入非常直接:源文档说明只需把 CAN 接口接到收音机 QuadLock 连接器的 CANH/CANL,无需 120 欧姆终端电阻。这一条与多数两节点试验台的接线习惯相反,源文档把它作为结论明确写出,实际接线时不要凭经验加终端。

    仪表文字那一类是ISO-TP(ISO 15765-2)传输:短格式只在收音机切到 AUX 模式时可见,形如「首字节标志 + 0x34 + ASCII」;扩展格式由一条含文本长度的首帧加若干条提供后续文本的连续帧组成。响应里随后出现的 ACK 报文提供流控:字节 1 为 0x30 表示「可继续发送」,字节 2 为 0x00 表示不做分帧流控,字节 3 为 0x00 表示按发送方最快速度。解析这类文本时,必须按 ISO-TP 的帧类型分别处理,而不能把每条 ID 当独立报文读。

    还有一处容易混淆:制动状态在两条报文里重复出现但编码不同——0x360 用 0x60/0x68/0x78,0x420 用 0x00/0x10/0x30。同一物理状态的多套编码要求解析方选定一个来源并保持口径一致。此外,音量键并不经方向盘那条报文(0x2D5 只覆盖模式与选台键),源文档对此如实标注为「似乎如此」。

    证据等级与边界

    本文属于单台实车逆向观测:ID、字节与换算公式均可在源文档逐条核对,属于直接证据;但源文档没有给出采集时长、帧数或时序,也未声明校验与计数器机制(除 ISO-TP 流控外)。随文档提供的定义文件(某类商业诊断工具的 .kcd 格式)源文档明确标注为不完整,因此不能把它当作完整协议描述。

    两点不能外推。第一,全部内容来自一台「2006 年以后改款」的 Fiesta 与一台 6000CD 收音机;换成其他年款、其他市场版本或其他音响配置,ID 与编码都可能不同。第二,多个报文只做到部分解码,源文档用「unspecified」标记了未解析字节;把这些字节当作已知信号会超出源文档证据。关于安全访问,源文档未提供任何绕过方法,且不建议尝试;本文只整理只读旁听所能看到的内容。

    常见问题

    接入这条总线要不要加 120 欧姆终端?

    不需要。源文档明确:把 CAN 接口接到收音机 QuadLock 的 CANH/CANL 即可,不用终端电阻。这与多数两节点试验台的接线习惯相反,接线时按源文档结论来,不要凭经验加终端。

    仪表屏的文字是怎么传的?

    走 ISO-TP(ISO 15765-2)。短格式如同「0x07 0x34 + ASCII」,只在 AUX 模式可见;扩展格式由带文本长度的首帧(0x10 + 长度 + 0x34)加若干连续帧(0x21 + ASCII)组成,随后有 0x4C8 流控 ACK。解析时必须按 ISO-TP 帧类型分别处理。

    为什么同一制动状态有两种编码?

    因为在源文档里它被两条报文重复承载:0x360 用 0x60/0x68/0x78,0x420 用 0x00/0x10/0x30。这是源文档记录的实际状态,解析时应选定一个来源并保持口径一致,不要混用两套编码。

    随文档提供的定义文件能当完整协议看吗?

    不能。源文档明确标注该文件(某类商业诊断工具的 .kcd 格式)不完整,多处字节以「unspecified」标记为未解析。把它当作完整协议描述会引入未经证实的字段。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/roncapat-ford-fiesta-mk5/README.md(本项目车型档案主来源:总线速率、接入方式、全部已解码 ID 与换算公式)。

    说明:本文整理自第三方开源项目的公开文档,仅代表该文档所记录的单个车辆样本,不代表同型号全系车型。CAN 与诊断操作存在风险,任何实车操作前请自行复核并遵守当地法规。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • Chevrolet Impala 2008:怠速采集的 50 个 ID

    结论:Chevrolet Impala(2008 款)是一辆典型的「HS-CAN 直读」车:500 kbps、11 位标准帧,源文档在 6 次采集中识别出 50 个唯一 ID,并把解码整理成 22 条消息、71 个信号的 DBC。但它有一个必须说清的限制:所有采集都在静止怠速下完成,因此车速与轮速的换算公式从未被运动数据验证过。以下所有结论仅限源文档记录的这一台车。

    车辆与适用范围

    本文数据来自第三方开源项目对一台 2008 款 Chevrolet Impala 的 HS-CAN 采集与解码。项目用多次定向采集诱发特定开关动作,再结合公开的 GM 数据库做交叉对照。

    项 内容
    车型 Chevrolet Impala,2008 款
    年款 / 市场版本 2008 款;具体市场版本源文档未确认
    采集构成 5 次约 15 秒的定向采集(用于诱发特定开关),加 1 次约 90 秒的基线采集
    采集状态 全部为静止怠速;源文档明确此时没有轮速与车速数据
    适用范围 仅限源文档记录的这一台车;结论不适用于其他年款或平台

    总线与寻址

    这辆车没有复杂的多总线结构或隐藏网关,接入相对直接。它的问题不在「能不能抓到」,而在「抓到后能证明到哪一步」。

    项 内容
    总线 HS-CAN;OBD-II 引脚 6 / 14
    速率 / 帧格式 500 kbps;11 位标准帧
    唯一 ID 数 50 个(6 次采集合计)
    DBC 22 条消息、71 个信号
    外部交叉引用 与公开的现代 GM Global A 数据库比对,50 个 ID 中有 20 个能匹配
    网关 源文档未记录网关行为;按同年款 GM 车的一般结构为单一 HS-CAN

    已解码信号

    下表从源文档的 Quick-Reference 解码表中抽取。项目对已被运动数据验证过的条目与仅靠怠速数据推出的条目做了区分,本文原样保留「未验证」标注。

    信号 位置(ID / DID / 字节) 解码 证据
    发动机转速 0x0C9 源文档更正:byte 0 是高半字节滚动计数器,不参与 RPM 计算 已确认
    制动开关 0x0C9 位标志 已确认
    制动压力 0x0F1 — 已确认
    挡位 PRNDL 0x1F5 枚举 已确认
    喷油脉宽 0x191 — 已确认
    冷却液温度 / 进气温度 0x4C1 — 已确认
    机油温度 0x4D1 — 已确认
    燃油轨压 0x4F1 — 已确认
    VIN 0x514 / 0x4E1 / 0x52A 多帧拼接为文本 已确认
    方向盘转角 / 角速度 0x1E5 — 已确认
    横加速度 / 横摆率 0x1E9 — 已确认
    电源模式 0x1F1 枚举 已确认
    车门 / 安全带 0x12A 位标志 已确认
    车速 0x3E9 公式存在,但未由运动数据验证 未验证
    轮速 0x348 / 0x34A 公式存在,但未由运动数据验证 未验证

    读取方法与注意事项

    第一条是采集设计。由于全部采集都在静止怠速下完成,任何与「车在动」相关的量都无法闭环:车速与轮速的换算公式虽然在文档里给出了,但没有运动数据能证明它对。若要把这些公式当作可用结论,必须补做一次实际行驶的采集。

    第二条是数据字段的坑。转速信号的 byte 0 曾被当成数据参与计算,源文档更正指出它其实是高半字节滚动计数器——这类「带头字节」的报文在很多车上都存在,把计数器当数据会引入周期性误差。处理多字节数值前,应先确认前导字节是否为计数器或状态位。

    第三条是外部对照的限度。项目把本车的 50 个 ID 与公开的现代 GM Global A 数据库比对,有 20 个能匹配。但这是跨世代的对照,只能作为线索,不能代替在本车上的实测——匹配上了不代表字节位置与刻度在本车上也一致。

    证据等级与边界

    源文档区分了「已确认」与「未验证」两类。已确认的多为怠速下就能观测的开关量、温度与静态值;未验证的集中在与运动强相关的车速与轮速。此外源文档指出,转向灯信号在这辆车的 HS-CAN 上并没有被找到——这是一个负向结论,说明该信号可能在别的总线或不经 CAN 传输。

    还有三处必须如实交代的边界。第一,源文档的 DBC 中,加速踏板位置字段从 bit 48 开始,但该消息被声明为 3 字节,两者不一致,说明这一条布局尚未定稿;第二,声称的原始采集文件并不在项目快照中,因此无法用原始数据复现结论;第三,上游 DBC 文件缺少仓库许可证信息,使用时需自行确认授权。

    适用范围上必须强调:以上 ID、字段与公式都限定在这一台 2008 款 Impala 上,且以怠速数据为主。不同年款、不同平台的车辆,ID 布局与刻度都可能变化;跨车使用前必须重新采集验证。

    常见问题

    为什么车速与轮速被标为「未验证」?

    因为全部 6 次采集都在静止怠速下完成,源文档明确此时没有轮速与车速数据。虽然文档给出了换算公式,但没有任何运动数据能证明它对。要确认这些公式,必须补做一次实际行驶的采集。

    转速信号里为什么要排除 byte 0?

    因为源文档更正指出 byte 0 是高半字节滚动计数器,不参与转速计算。早期把 byte 0 当数据会引入周期性误差。这类「带头字节」在车上很常见,解析多字节数值前应先确认前导字节是否为计数器或状态位。

    和公开 GM 数据库匹配上就代表正确吗?

    不代表。项目只做到 50 个 ID 里有 20 个能匹配现代 GM Global A 数据库,但这是跨世代对照,只能作为线索。匹配成功不等于字节位置与刻度在本车上也一致,仍需在本车实测确认。

    这份 DBC 可以直接拿来做产品吗?

    需谨慎。源文档已指出三处问题:加速踏板字段位置与消息长度声明不一致、原始采集文件不在快照中(无法复现)、上游文件缺少许可证信息。使用前应自行确认授权并补做缺失的验证。

    延伸阅读

    参考资料

    • 项目 09 —— public-can-dbc-datasets/additional/dwilson2547-impala-2008/can_data/analysis/gm/chevy_impala_2008.md(本项目车型档案主来源:解码表、ID 清单与置信度)
    • 项目 09 —— public-can-dbc-datasets/additional/dwilson2547-impala-2008/can_data/README.md(车辆覆盖与 DBC 文件清单)
    • 项目 09 —— public-can-dbc-datasets/additional/dwilson2547-impala-2008/SOURCE.md(采集状态、DBC 规模与已知问题)

    说明:本文整理自第三方开源项目的公开文档,仅代表该文档所记录的单个车辆样本,不代表同型号全系车型。CAN 与诊断操作存在风险,任何实车操作前请自行复核并遵守当地法规。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11

  • CarCluster 仪表注入:13 个 Simhub 字段与 13 款仪表盘

    结论:这份档案记录的是一个反方向的 CAN 项目:不是从车上读信号,而是用 ESP32 + MCP2515 把 PC/游戏数据注入真实仪表盘,让一台退役的原车仪表在桌面上工作。源文档最可直接引用的是它的输入字段表——Simhub 集成示例把 13 个字段(车速、挡位、转速、最大转速、左右转向、机油温度、暂停、运行、油量百分比、手刹、ABS、TC)映射进这套固件。硬件与支持的仪表清单同样值得记录,但要注意:多款较新仪表(如 T-Cross)存在组件保护,一旦触发无已知解法。

    车辆与适用范围

    源文档是一个开源桌面项目,目标是驱动真实仪表盘,主要用于游戏,也可作时钟等用途。硬件极简:一块 ESP32、一个 MCP2515 CAN 模块、一个 12V 电源。

    项 内容
    车型 面向多种车型仪表盘(VW PQ35/MQB/PQ46、BMW F/E 系、Mercedes W204/W221、Mini F55/F56/F57、Opel Corsa E 等)
    年款 / 市场版本 随平台不同;源文档未统一给出年款,示例为 VW Polo 5、Golf 7、Škoda Superb 2、BMW F10/F30 6WA、E60、E46、W204/W221 等
    ECU / 改装状态 退役仪表盘 + 自制电源/线束;部分平台需逻辑电平转换(如 E46)、数字电位器模拟油位
    采集跨度 源文档未给出;无整车采集,数据来自游戏或网页界面
    适用范围 仅限源文档明确「已完整测试并支持」的仪表型号;相近平台「可能可用但需按具体车型修改」

    总线与寻址

    物理连接对普通爱好者很友好:ESP32 Devkit 板 + 通用 MCP2515 CAN 模块,另可用项目自制的转接 PCB 或跳线/面包板两种接法。仪表侧接线按平台各有专门文档。

    项 内容
    物理层 ESP32 板 + MCP2515 CAN 模块 + 12V 电源;E46 需逻辑电平转换
    链路层 / 比特率 源文档未给出
    寻址方式 源文档未给出
    CAN FD 源文档未提及
    仪表侧接线 按平台各有一份接线文档(PQ/MQB/BMW F/E60/E46/MB W204/W221/Opel Corsa E)

    已解码信号

    这份主素材不是从整车抓包的信号表,而是注入端的数据字段映射。下表逐条来自源文档给出的 Simhub 集成更新消息格式,是文档中唯一逐字段列出的信号清单,括号内为默认值(若有)。

    字段 键名 含义 / 默认值 证据
    车速 spe 车速(km/h),取整 Simhub 更新消息示例
    挡位 gea 挡位字符串,空值默认 P Simhub 更新消息示例
    转速 rpm 当前转速,空值默认 0 Simhub 更新消息示例
    最大转速 mrp 红线转速,空值默认 8000 Simhub 更新消息示例
    左转向灯 lft 左转向指示,默认 0 Simhub 更新消息示例
    右转向灯 rit 右转向指示,默认 0 Simhub 更新消息示例
    机油温度 oit 机油温度,默认 0 Simhub 更新消息示例
    游戏暂停 pau 是否暂停,默认 0 Simhub 更新消息示例
    游戏运行 run 是否运行,默认 0 Simhub 更新消息示例
    油量百分比 fue 计算得到的燃油百分比,默认 0 Simhub 更新消息示例
    手刹 hnb 手刹状态,默认 0 Simhub 更新消息示例
    ABS abs ABS 是否激活,默认 0 Simhub 更新消息示例
    TC tra 牵引力控制是否激活,默认 0 Simhub 更新消息示例

    读取方法与注意事项

    初始化流程在源文档里很明确:下载项目后用 Arduino IDE 打开 Carcluster.ino,在 BEGIN USER CONFIGURATION 段选择目标仪表盘(例如把 #define CLUSTER 1 改成 3 使用 Golf 7 仪表),其余参数按具体仪表配置;项目已内置所需库,无需额外安装。烧录后 ESP32 会开一个名为 CarCluster 的 Wi-Fi 热点(密码 carcluster),连上后跳转 192.168.4.1 选择要接入的网络;若 3 分钟内未配置,则进入串口模式,可配合 Simhub 使用。

    两个易踩的坑:一是接上 CAN 模块时可能无法烧录,需先断开再上传;二是部分 ESP 板的串口不支持全速,会出现「板子无响应」之类错误,此时把 SERIAL_BAUD_RATE 改成 460800,并同步修改串口监视器、Simhub 与 Arduino 的上传速度。仪表侧的功能自测可以用网页界面(可设转速、车速等)来验证。Simhub 目前只支持 USB 连接、不支持 Wi-Fi。

    证据等级与边界

    本档案属于项目登记 + 集成示例。字段表本身是源文档写死的键名,可核对;「某款仪表盘被完整支持」是作者自测结论;至于实车报文,本项目并不产生——它是把游戏/PC 数据注入仪表,信号方向与整车抓包相反。

    三处不能外推。第一,字段表是注入协议,不是任何一辆车的 CAN 信号定义,不能当成车型档案使用。第二,平台相近不等于可用:源文档明说「相近平台可能可用,但需按具体车型修改」。第三,组件保护是硬边界:较新的 MQB 仪表(如 T-Cross)在未知时间后会进入组件保护模式,闪屏且多数指示灯失效,目前无已知解法,应避免使用。

    关于「安全访问」类问题:本文只整理公开文档登记的注入字段与硬件,未涉及对车辆安全机制的规避;源文档未提供绕过方法,且不建议尝试。

    常见问题

    CarCluster 是从车上读信号吗?

    不是,方向相反。它把 PC/游戏的数据注入真实仪表盘,让仪表显示外部数据;项目目的是在桌面使用退役仪表,而非从整车抓包。

    为什么有些仪表盘不能用?

    以 VW T-Cross 为代表的新款 MQB 仪表会在未知时间后进入组件保护模式,闪屏且多数指示灯失效,源文档明说目前无已知解法,建议改用较老的 Golf 7 等。

    哪些仪表盘支持得最好?

    源文档给出的入门推荐顺序是:Mercedes 某几款仪表、BMW F 系仪表、VW MQB 系仪表;并列出已完整测试支持的具体型号,其中 W204/W221、BMW F10/F30 6WA、E46 等标为完整支持,E60 标为「部分支持、开发中」。

    注入的信号都有哪些?

    源文档的 Simhub 集成示例列出 13 个字段:车速、挡位、转速、最大转速、左右转向灯、机油温度、暂停、运行、油量百分比、手刹、ABS、TC。它们都有默认值,缺省时按默认显示。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/r00li-carcluster/README.md(本项目车型档案主来源:硬件、支持的仪表清单、Simhub 字段映射与安装说明;本快照仅含此文件)。

    说明:本文整理自第三方开源项目的公开文档,仅代表该文档所记录的单个车辆样本,不代表同型号全系车型。CAN 与诊断操作存在风险,任何实车操作前请自行复核并遵守当地法规。

    更新记录

    首次发布 2026-10-11 最近核对:2026-10-11