标签: 车型协议

  • VTRUX 与 Coda 的 CAN 解码笔记:信号、电芯索引与验证方法

    结论:这份笔记覆盖九份 DBC、合计 238 条报文与 1,066 条信号,分属 Coda 的 B/C/D 三总线、VTRUX 的 OBD/PT 两总线、Bel 逆变器的 J1939 扩展帧,以及一辆 1975 Porsche 914 改装车的自定义 VCU 遥测。它的价值不在清单本身,而在把「反编译出来的标签」和「验证过的信号」分成五档,并如实记录了一次被纠正三次的电芯索引映射与八条被推翻的假设。

    九份 DBC 的量级与定义来源

    仓库统计明确说明:下面的报文 / 信号数来自拷进来的 DBC 文件本身,而不是上游 README 的表格——后者已经过期。Coda 的 B、D 两总线在上游 README 里写的是 35 和 22,实际文件是 34 和 23;914 的 README 还在描述一份 75 报文 / 496 信号的 schema 3.0,而文件已经是 schema 4.2、hash 0x09EB175A。

    DBC 文件 报文 / 信号 总线 定义来源 证据边界
    CODA-B-CAN.dbc 34 / 156 B CAN 原厂 CODACAN LabVIEW 诊断应用 + 实车抓包 上游 README 的 35 为过期值,以文件为准
    CODA-C-CAN-cells.dbc 26 / 104 C CAN 26 帧 0x000–0x019,每帧 4 个 16 位 Motorola 电芯,1 mV/bit 电芯编号自 2026-07-22 起改为 1-based
    CODA-D-CAN.dbc 23 / 44 D CAN LabVIEW 反编译 + 日志 上游 README 的 22 为过期值
    epri-obd-bus.dbc 12 / 18 OBD EPRI Logger iPhone 应用的 Ghidra ARMv7 反编译,再用车辆日志比对修正 字节位置与刻度并非一律正确
    epri-pt-bus.dbc 26 / 101 PT 同上 同上
    vtrux-obd-experimental.dbc 3 / 5 OBD 作者由日志推导的实验性定义 含未解析报文桩
    vtrux-powertrain-experimental.dbc 19 / 26 PT 同上 同上
    BelInverter-v2.dbc 8 / 73 J1939 扩展 ID EPRI 结论 + 一份更早的 DBC 合并 原始作者与部分字节布局未确认
    914-telemetry.dbc 87 / 539 自定义 VCU 遥测 改装 914 的 VCU 映射,非原厂 Porsche 协议 标准 11 位 ID 为真实车辆帧;29 位扩展 ID 为 VCU 串行遥测里的内部合成值

    确认档位:怎么区分「反编译出来的」和「验证过的」

    这份仓库最值得抄的一点是它不给信号打勾,而是打档。反编译只能告诉你应用把哪个字节当什么读,不能告诉你它读对了;日志相关只能告诉你两件事一起动,不能告诉你它们是不是一件事。于是每条信号都落在下面五档之一,档位直接写在验证表里。

    档位 含义
    CONFIRMED 编码与角色都被独立验证过:物理测试、行为日志证据、与已知参考相关、或跨 DBC 比对一致
    CONFIRMED-SYMM 靠与某个 CONFIRMED 信号的结构对称性确认,没有独立测试
    CONFIRMED-DECOMPILE 编码由 Ghidra 确认,角色只是应用自己的标签,没有独立物理或行为检查
    PARTIAL 编码确认,角色或刻度还有一条具体问题挂着
    REMOVED 按 DBC 信号策略删掉 SG_ 条目,原因记在 CM_ 注释里

    档位不是形式主义

    PT 总线上 0x0054 的 GENE_EmergcyStp_flg 是 CONFIRMED-DECOMPILE:Ghidra 里写着 (pbVar15[6] 与 8) 不等于 0,但所有日志里它一次都没触发过,没有行为测试。同理 0x0580 的 tcm_CAN_ERR。这类条目可以读,但不能当成「已经证明这个位是这个意思」来用。

    0x381 与 C CAN 电芯索引:一条被纠正了三次的映射

    C CAN 只在少数几次采集里被同时录下(需要第三个适配器),所以能回答这个问题的只有三份日志。总线识别靠内容而不是总线号:0x000–0x019 的电芯帧是 C CAN,0x381/0x382/0x383/0x390/0x439 是 B CAN,0x308/0x312/0x325/0x330/0x55C 是 D CAN——两次会话给同一条物理总线编的总线号并不一致。

    会话 日志 配对样本 偏移 +1 严格命中率
    2026-07-21 Android 三适配器 coda_20260721_192435_T0..T2、_201109_T0/T1、_202031_T0 660 82–87%
    2026-02 Bonnydoon 行驶 33 min projects/coda/logs/frombonnydoon.log 1,972 80–84%
    2026-07-22 充至 100% coda_20260722_173203_T0..T21 979 100%

    合计 43 万帧以上的 C CAN 电芯帧、8,300 帧以上 0x381、3,600 对以上时间配对样本,且配对时刻 C CAN 数组完整、没有帧旧于 2 秒。充电会话最干净:负荷低而稳,电芯在 B 与 C 两轮扫掠之间几乎不重排,严格测试在 VmaxId(591 样本)与 VminId(706 样本)上都命中 100.0%。

    会话 信号 严格样本数 命中偏移 +1 不同 ID 数 ID 范围
    Android VmaxId 135 82.2% 11 6–104
    Android VminId 146 87.0% 26 1–101
    Bonnydoon VmaxId 225 79.6% 44 6–104
    Bonnydoon VminId 376 84.3% 33 1–104
    充电 07-22 VmaxId 591 100.0% 2 82–95
    充电 07-22 VminId 706 100.0% 1 96

    「严格」的口径是:只保留 C CAN 数组自身的极值恰好等于所报极值、该极值由唯一一只电芯持有、且领先第二名至少 3 mV 的样本。行驶会话里没有任何竞争偏移超过 4%;剩下约 15% 也不是反例——两条总线不是同时采样的,C CAN 扫完 26 帧要约 800 ms,而 0x381 只有约 1.1 Hz,行驶中负荷波动会在两个时刻之间把几乎并列的电芯重排。签名也说明这是偏斜而不是置换:未命中的配对集中在少数几个本来就常年处于极值的 C CAN 索引上(max 侧 81/83/94/102,min 侧 76/80/95),真置换会把它们撒满整个数组。

    三次纠正各纠正了什么

    第一次是编号口径:映射被发现时 C CAN DBC 还是 0-based,关系是「上报 id 等于旧索引加 1」;2026-07-22 改为 1-based 后加 1 消失,两套编号重合。这也推翻了更早那句「id 用的是与 C CAN 位置无关的 BMS 内部编号」——BMS 编号就是 C CAN 的发送顺序(1-based)。

    第二次是字节序。2026-07-15 之前 0x381 的归属是 B0-1=MinCellVoltage、B2-3=MaxCellVoltage、B4-5=AvgCellVoltage、B6=VminId、B7=VmaxId;修正后是 B0-1=Avg、B2-3=Max、B4-5=Min、B6=VmaxId、B7=VminId。当年的错误来自照着 LabVIEW cluster 的名字「VminVmax」排,而不是按 LabVIEW 字段顺序 Vavg、Vmax、Vmin、VmaxId、VminId。重跑严格测试可以量化这两种读法的差距。

    归属方式 Android 样本 / 命中 +1 Bonnydoon 样本 / 命中 +1
    修正后 max — 值 B2-3,id B6 135 / 111(82.2%) 225 / 179(79.6%)
    修正后 min — 值 B4-5,id B7 146 / 127(87.0%) 376 / 317(84.3%)
    旧 max — 值 B2-3,id B7 135 / 0(0.0%) 225 / 1(0.4%)
    旧 min — 值 B0-1,id B6 0 / 0 0 / 0

    两端的失效并不对称。min 侧当时根本没有信号可用:旧的 MinCellVoltage 读 B0-B1,而那其实是包平均值;平均值几乎不可能唯一且带余量地等于某一只电芯,所以两次会话里都是零样本存活,没有东西可相关。min 侧还有第二个错:id 也取自错误的字节(B6 其实是真正的 VmaxId)。max 侧则是「值对、id 错」:B2-B3 在两种读法下都真是最大值,但索引来自 B7(真正的 VminId),于是正确的最大电压配上了最小电芯的编号,噪声里最好的偏移只有 21%——读起来很像「另一套编号约定」,非常容易被误判。

    第三次是对比方式。frombonnydoon.log 同时带 C CAN 与 0x381,它自己的 0x381 报 VminId 95 / VmaxId 84,正是那次笔记已经点名的两只电芯。也就是说这条映射在单份日志内部就可验,而当时的笔记却拿它们去和另一次(充电)会话的 96/76 比,把差距读成了编码差异。结论成了方法:只要两条总线同时在场,就在同一会话内部比。

    还有一条适用范围限制:本节的「+1」只适用于经 DBC 从原始字节解出来的值。从 CODACAN 界面截图上读到的数字(如充电分析里的 VminId=96 / VmaxId=76)来自 LabVIEW cluster,它一直是对的,不受 DBC 错误影响。哨兵值 255 也要单独处理:104 只电芯的包里 255 不可能是索引,它是无效 / 无数据哨兵,不要当成「第 254 只电芯」。

    证据边界:部分解码、未解与已推翻

    「已确认且完整」的信号有其编码摘要,例如 0x275 BMSDriveLimits 的 B0 = 放电限值(uint8 乘 2 得 A)、B1 = 充电限值(乘 2 得 A)、B2-B3 = 包电流(BE uint16 乘 0.1 A,零点 0x8000)、B4-B5 = 包电压(BE uint16,1 V/bit)、B6 = HVAC 限值(乘 2 得 A)、B7 未知(基线 0xDD)。下面列的是还没收口的。

    ID 名称 已知 还缺什么
    0x050 BMSChargerCmd B0-B1 = HVCurrentCmd(BE uint16 乘 0.1 A,R2 = 0.992;基线 0x00DC = 22 A);B2-B3 = MaxVoltage(乘 0.1 V,R2 = 0.605;基线 0x0FF7 = 408.7 V);中位帧 00 dc 0f f7 00 01 3e 01 B4-B5 取非基线值会把 Main Current 压到约 6 A,疑似帧校验或滚动计数;B6-B7 未知;需注入测试
    0x270 BMS_FaultStatus B0 为故障字节(0x00 无故障,0x12 = 故障码 18,bit 1 = 0x02 与 bit 4 = 0x10 置位);比 0x271 早一帧;drop 后 CODACAN 的 BMS Fault Severity 掉下去 B0 内部故障码与严重度的分界未扫;B6-B7 未知
    0x2C1 BMSDrivingRange B0 状态字节(raw = 0x70 时翻转);B1 / B3 / B5 分别为 Exp / Max / Min,R2 约 0.96–0.97;比例暂定约 1.1 乘 raw 减 19 刻度 / 偏移未精确确认;B2、B4、B6-B7 未扫;单位可能是英里
    0x330 Long_Accel 被抑制时会掉,但与噪声边界模糊;VICD 刻度为有符号字节乘 0.08 m/s² 未确认为模拟量;需要一次含急刹的行驶事件做时序提取
    0x383 BMSBattStatus SoC 在 B0-B1(BE uint16 除以 10 得 %)已确认;同时带 HVBattCharging、ChrgPortOpen、ChargeCableConnected 三个布尔位的确切位号未记录
    0x410 AC_Compressor_Command B2 = compressor_on_off / CASS_on_off / warmup_cycle_cntr_incr;B6 = 目标转速(乘 60 rpm/bit);B7 = 最大功耗(乘 0.1 kW/bit) B0 的三个布尔位(HVAC FaultRed、FaultYellow、KeepWakeNetworkHVAC)位号未解;也可能是扫描引起的 ECU 响应假象
    0x241 MCM_Thermal 角色已确认:drop-ID 后 Rotor / Stator / IGBT 三个字段归零;DLC = 8 已由日志确认 逐字节归属未确认;偏移假定为减 40 摄氏度;B4 恒为 0x00,疑似哨兵或非温度字段
    0x491 / 0x273 IPK 帧 两者都带 Primary ODO(km)、Interior Illum、Side Light Active、Low Beam Active;0x491 还会点亮 Overview 的 IPK 指示,0x273 不会 ODO 的字节位置与编码(可能是 BE uint24 或 uint32);灯光的位号

    八条被推翻的早期假设

    这些条目都曾写进笔记或报告,后来被数据推翻。留着不是自曝,而是让下一个人不用再踩一遍。

    早期假设 更正为
    0x212 = EPS_SAM_1(转向角,0.25 deg/count) 0x212 = DLCM Torque Request;转向角在 0x080
    0x210 = Vehicle_Mode 含 VBatt(乘 0.4 V/count) 0x210 B2 = ThrottlePedalPos(乘 0.4 %/count)
    0x271 = Death Counter 的一部分(整数字节计数) 0x271 = GWM 心跳 + VehFaults 的源
    0x55C = VehFaults(3 字节:灯 / 严重度 / 故障字) 0x55C = TCM 心跳
    0x381 = BMSDriveLimits 候选(哨兵 1000.0 A) 0x381 = BMSVminVmax;BMSDriveLimits 在 0x275
    0x382 B0 = 充电阶段计数器(0x8B 到 0x8E 步进) B0 = Cell_T_avg;充电过程中包升温时为 11–14 摄氏度
    0x275 B4 = HV Active 布尔标志 B4-B5 = PackVoltage(BE uint16,1 V/bit);104 串 LFP 包始终使 uint16 的最高位置位
    BattSentDischargeLimit / ChargeLimit 刻度 = 1 刻度 = 2(uint8 乘 2 得 A)

    常见问题

    反编译出来的 DBC 能直接拿来解日志吗?

    不能直接。反编译只证明应用把某个字节按某种方式读,不证明它读对了。所以这里把信号分成 CONFIRMED、CONFIRMED-SYMM、CONFIRMED-DECOMPILE、PARTIAL、REMOVED 五档,只有前两档带独立验证,第三档只是「应用自己这么命名」。

    电芯编号到底是 0 起还是 1 起?

    C CAN DBC 自 2026-07-22 起改为 1-based(Cell1 到 Cell104),与 BMS 自己的 VmaxId / VminId 直接对应,VmaxId 82 就是 Cell82。此前是 0-based,老 CSV、老图、老导出都要加 1 才能对上,例如旧 Cell94 等于现 Cell95。MinTempId / MaxTempId 是另一套索引,不受影响。

    为什么 0x381 的映射要改字节序?

    因为最初的归属照着 LabVIEW cluster 的名字「VminVmax」排,把 Min 与 Avg、VminId 与 VmaxId 都放反了;按 LabVIEW 字段顺序应是 Vavg、Vmax、Vmin、VmaxId、VminId。重跑严格测试后,旧的 max 读法命中 0.0%,旧的 min 读法零样本存活,修正后分别是 82.2% 与 87.0%。

    偏航率刻度为什么判不出来?

    两种说法分别是 0.0045(转向角 / 轴距运动学模型)与 0.003924(后轮差速几何法),但它们不是两条独立标定:同一几何法随速度窗口与轮距取值会给出 0.00347 到 0.00488。系统误差预算合计 43.4%(左右不对称 34.1%、速度窗口 21.5%、旅程间 16.0%),远大于两者相差的 14.7%,因此只能记为「判不出」。

    这份素材的许可证状况如何?

    被检查的上游快照里没有许可证文件,本文所依据的是一份离线私有研究副本。公开仓库可访问并不等于取得再分发或制作衍生作品的权利,对那些从第三方应用推断出来的定义尤其如此。共享或商用之前应与相关权利人确认。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/SOURCE.md(九份 DBC 的报文 / 信号数与权利边界)
    • 项目 01 —— public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/projects/coda/notes/codacan-signal-decode-notes.md(CODACAN 台架方法、分阶段完成表、模块在位映射与已推翻假设)
    • 项目 01 —— public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/projects/coda/notes/cell-index-mapping.md(0x381 VmaxId/VminId 与 C CAN 电芯数组的三次纠正与严格测试口径)
    • 项目 01 —— public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/projects/vtrux/notes/epri-verification.md(PT 与 OBD 总线的逐信号确认档位与 Gap)

    免责声明

    本文所述信号定义全部来自社区逆向工程,不代表车辆制造商的官方数据。Coda 与 VTRUX 两家整车企业均已退出市场,无原厂文档可核对;VTRUX 的 EPRI 定义最初由一款 iPhone 日志应用的二进制反编译重建,再用车辆日志比对修正,字节位置与比例并非一律正确。上游快照未包含许可证文件,公开仓库可访问不构成再分发或衍生权利。涉及安全相关用途时请仅作参考,并以实际测量为准。

    更新记录

    • 2026-10-15 初稿

  • 菲亚特 Ducato X250 车身 CAN:五组抓包能还原出什么

    结论:这辆 Ducato X250 的 OBD 6/14 脚上只有 50 kbit/s 的车身 CAN,500 kbit/s 一帧都没有。五份抓包(30 s 到约 20 min)覆盖钥匙静态、车门与灯光、开关动作、冷启动加油到 7 km 实路行驶,总线共 18 个 ID、约 90 帧/s,19 条已验证解码逐条与仪表、GPS 或 OBD PID 对过。增压压力、发动机负荷、进气温度与故障码不在这条总线上——它们在 7 脚的 K 线上。

    五组抓包样本矩阵:每档各解决一类问题

    抓包是用仓库里的 tools/slcan_capture.py 通过 TCP 23 口连上只听模式的适配器录的,脚本先发 C(关通道)、S2(50 kbit/s)、L(只听),随后每帧写成一行「启动后秒数 + slcan 帧」,例如 t28180080803800000000 即 ID 0x281、DLC 8、后接八个字节。时间戳是相对的,不含位置信息。

    决定一份抓包能还原什么的是工况,不是文件体积。常发帧识别、开关类位分离、随动模拟量拟合、随负荷变化的量验证,各需要不同的一档;下面这张表按「不可替代性」分档,缺任何一档都会让相应的一类信号失去证据。

    抓包文件 时长 工况 能取到的数据 为什么这一档不可替代
    01_ignition-on_engine-off 30 s 钥匙拧到 MAR,全程不碰任何开关 静态基线与常发帧清单:0x281 20 Hz、0x286/0x2A0 10 Hz、0x180/0x380/0x39A 4 Hz、0x3C3/0x3E0 2 Hz、0x603/0x643/0x683 1 Hz;冷车水温与静态电瓶电压 唯一能界定「哪些帧与操作无关」的一档。没有它,后面的字节差分会把常发噪声当成动作响应
    02_doors_and_lights 300 s 车门逐个开合,示宽灯、近光、远光、闪光各一遍 0x380 的手刹 / 车门 / 倒挡 / 电瓶电压 / 低油量告警 / 油量;0x180 的示宽灯、近光、远光、后雾灯 灯光位只在原地逐个打才能分离;行驶中它们与负荷、电压混在一起
    03_misc-actions 420 s 转向灯、刹车踏板、驻车制动及其它开关 0x180 的刹车踏板(b0 bit 7)与左右转向(0x40 / 0x20 随闪光翻转)、0x380 b0 bit 5 手刹、0x39A b2 bit 0 安全带 转向灯是「闪烁」而非电平,只有这一段能看到周期性的位翻转,从而与常亮的示宽灯区分
    04_engine-idle_revs 180 s 冷启动,怠速约 800 rpm,再分别点油门到约 2000 与约 3000 rpm 0x281 的转速 / 水温 / 发动机在转判据;怠速与加油时的电压变化 转速刻度与「发动机在转」的判据只能靠怠速加两段加油对照,静态档给不出斜率
    05_short-drive 约 20 min 7 km 城镇 / 乡村路段,最高约 80 km/h 0x286/0x2A0 车速与 GPS 对照;0x603 里程与续航;0x643 小计(平均油耗、平均车速、时间、距离);0x683 仪表时钟 唯一带车速变化的一档。里程增量(7 km 行程后 +7 km)也只有这一段能验

    18 个 ID 的已验证解码

    参考表的口径:总线为车身 CAN(B-CAN),OBD 6/14 脚,50 kbit/s,11 位 ID,18 个 ID,约 90 帧/s。b0 是第一个数据字节,位号 7(最高位)到 0。每条解码都在车上对照过仪表、GPS 或重复动作,没有一条是仅凭取值范围猜的。

    ID 速率 DLC 信号 解码 怎么验的
    0x180 4 Hz 6 刹车踏板 b0 bit 7 踩踏板
    0x180 示宽灯 b1 bit 5 灯光开关
    0x180 近光灯 b1 bit 3 灯光开关
    0x180 远光 / 闪光 b1 bit 4 拨杆
    0x180 左 / 右转向灯 b2 = 0x40 / 0x20,随闪光翻转 拨杆
    0x180 后雾灯 b1 bit 1(仅在开灯时有效) 开关三次
    0x281 20 Hz 8 发动机在转 用「转速大于 300」,不要用 b1 bit 7 三次钥匙测试(仅钥匙开、启动、运转后熄火)
    0x281 冷却液温度 b3 减 40,摄氏度 水温表指针居中时读 81
    0x281 发动机转速 (b6 乘 256 加 b5)除以 8 怠速约 830,点油门 1800 / 3000
    0x286 10 Hz 8 车速 (b2 乘 256 加 b3)除以 16,km/h 四段匀速与 GPS 差在 1% 以内
    0x2A0 10 Hz 4 车速(副本) (b0 乘 256 加 b1)除以 16,km/h 同 0x286
    0x380 4 Hz 8 驻车制动 b0 bit 5 手刹杆
    0x380 车门 b1 等于 0x0C 表示任一门开,0x00 全关 驾驶室门、生活舱门、储物舱共用一个回路
    0x380 倒挡 b2 bit 2 进出倒挡三次
    0x380 启动电瓶电压 b3 乘 0.16,V(0x53 = 13.3 V) 20 min 行驶中对照启动电瓶库仑计
    0x380 低油量告警 b4 bit 1(0x02 进入储备区,否则 0x00) 仪表储备灯亮时读 0x02
    0x380 油量 b5,升 满箱 90 L 读 91;本车 23 对应 26%
    0x39A 4 Hz 8 驾驶员安全带 b2 bit 0,1 = 未系 插拔三次
    0x3C3 2 Hz 8 驾驶员安全带(副本) b4 bit 1,同 0x39A 同上
    0x603 1 Hz 8 总里程 20 位:b1 低半字节 + b2 + b3,km 61744 = 仪表;7 km 行程后 +7
    0x603 续航里程 11 位:b4 的 bit 2-0 + b5,km 272 = 仪表
    0x603 瞬时油耗(待行驶中验证) b0 + b1 高半字节,BCD,L/100km(11 6x = 11.6) 怠速时与仪表小计一致;随负荷变化
    0x643 1 Hz 8 小计平均油耗 b0 + b1 高半字节,BCD,L/100km 11.7 = 仪表
    0x643 小计平均车速 b2,km/h(截断) 48 = 仪表;等于距离除以时间
    0x643 小计时间 b3 小时、b4 分钟,BCD(47 37 = 47 小时 37 分) 仪表;分钟从 19 跳到 20
    0x643 小计距离 20 位:b5 + b6 + b7 高半字节,乘 0.1 km 2329.2 = 仪表;复位后 0.0
    0x3E0 2 Hz 4 启动电瓶电压(副本) b1 乘 0.16 V,同 0x380 b3 同上
    0x683 1 Hz 6 仪表时钟 b0 小时、b1 分钟,BCD(16 50 = 16:50) 仪表时钟(本车慢约 3 分钟)

    三处「看起来能用、实际会错」的位

    0x281 b1 bit 7 只在点火开且发动机停时为 1,熄火最后一帧它读「在转」,行驶结束后 ECU 还会继续发约 20 s;三种钥匙测试下都以「转速大于 300」为准。0x603 b4 bit 3 是发动机运转标志位,做续航时必须排除,否则会得出 2265 km 这种数。车门位 0x380 b1 只回答「有门开着」,房车改装上驾驶室门、生活舱门与储物舱在同一回路,无法区分。

    灯光的另一个工程约束:同一 ID 上挂三条位条目在 0x281 上能工作,但测试里 0x180 上分离的位条目发布并不可靠,所以灯光、刹车踏板与转向灯在适配器里被合成一个 24 位的 raw_180 值发布,拆位留到 Home Assistant。过滤器文件的字段口径也要注意:CANID 用十进制(641 = 0x281),StartBit 从 b0 的最高位算起(b0 的 bit 7 是 0,b1 的 bit 7 是 8),Expression 里 V 是取出的值、B5 是字节 5。

    证据边界:不在这条总线上,以及会骗人的那一帧

    这套数据最有价值的部分之一,是它明确标注了「测不到」的地方。下面每一条都是试过之后的结论,不是「没看到就等于没有」。

    边界类型 具体情形 处理动作
    总线静默 钥匙拔出后总线完全静默,停车状态读不到任何东西 实时传感器设 expire_after: 15,让它变成 unavailable 而不是冻在旧值
    假帧 钥匙关闭前的最后一帧是假的:油量 0、手刹释放、发动机仍显示运转 不要把任何自动化建在 key-off 边沿上
    错误判据 0x281 b1 bit 7 不是「发动机在转」 一律用转速大于 300 判定
    位污染 0x603 b4 bit 3 是运转标志,参与续航解码 做 11 位续航时排除该位
    回路合并 车门状态只有一个共用回路 只能读「有门开着」,不能定位到具体门
    协议外 增压压力、发动机负荷、进气温度、故障码走 7 脚 K 线(ISO 14230-4 KWP2000) 只带 CAN 的适配器看不到;电瓶电压改看 0x380 b3(车身电脑视角)
    波特率 6/14 脚只有 50 kbit/s 的车身 CAN,500 kbit/s 无帧 50K 是唯一可用档位,模式设 Silent(只听)

    常见问题

    这五份抓包能直接当 DBC 用吗?

    不能。它们是 slcan 文本行(相对秒 + 帧),仓库里没有 DBC。仓库提供的是 tools/decode.py,只解已知信号、只输出变化行,并带 --test 自检。要把抓包变成 DBC,得自己按 ID 做字节差分,再逐条与仪表、GPS 或 OBD PID 对照。

    为什么钥匙拔掉之后一个数据都读不到?

    因为这条车身 CAN 在钥匙离开 MAR 之后完全静默,停车时没有任何帧可听。这不是适配器的问题,是车辆本身的行为,所以任何「停车监控」类的需求在这条总线上都不成立,传感器只能走过期置为 unavailable 的路子。

    车速有两个来源,该用哪一个?

    0x286 的 b2/b3 与 0x2A0 的 b0/b1 都是车速,都除以 16 得 km/h,区别只在 DLC(8 与 4)与所属报文。两者结果一致,与 GPS 对照的偏差在 1% 以内,任选其一即可,但不要在同一条链路上混用而忽略 DLC 差异。

    油量 0x380 b5 为什么不能当百分比用?

    因为满箱 90 L 的箱子上它读到 91,如果是百分比应该接近 100。它的单位接近升,但零点还没在这辆车上最终确认(本车 23 对应 26%,OBD 燃油 PID 给 24%),且钥匙关闭帧里读 0。作为趋势量可用,作为绝对值要谨慎。

    能不能靠这些抓包拿到增压压力或故障码?

    不能。这两类数据在发动机 ECU 的 K 线上(OBD 7 脚,ISO 14230-4 KWP2000),需要主动发请求才会应答。这里全部是只听模式,从不发帧,因此它们不可能出现在抓包里。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/danderik88-fiat-ducato-x250/captures/README.md(五份抓包的时长、工况与录制格式)
    • 项目 01 —— public-can-dbc-datasets/additional/danderik88-fiat-ducato-x250/docs/can-id-reference.md(18 个 ID、速率、DLC、逐信号解码与验证方式)
    • 项目 01 —— public-can-dbc-datasets/additional/danderik88-fiat-ducato-x250/README.md(车辆配置、OBD 引脚分配、Gotchas 与免责声明)
    • 项目 01 —— public-can-dbc-datasets/additional/danderik88-fiat-ducato-x250/tools/slcan_capture.py(S2 = 50 kbit/s、L = 只听的初始化序列)

    免责声明

    本文所述解码均为社区逆向工程产物,不代表车辆制造商的官方数据,且全部来自一辆 2009 年 Ducato X250(2.3 MultiJet,Elnagh Prince 55L 房车改装,意大利市场)。同平台另有 Citroën Jumper 与 Peugeot Boxer(2006–2014),但只有文中这辆 Ducato 实测过。不同车型年款、市场与 ECU 版本可能存在差异。文中所有操作均为只听,不向总线发送任何帧;连接任何设备到车辆 OBD 口的风险由操作者自行承担。涉及安全相关用途时请仅作参考。

    更新记录

    • 2026-10-15 初稿

  • Freelander 2 中速 CAN 梳理:两个 DBC 版本、39 报文与 125 kbit/s

    结论:神行者 2(Freelander 2)的这套中速 CAN 材料不是一个已完成的解码成果,而是一个进行中的信息娱乐替代工程副产品。它的核心是两份同名不同版本的 DBC:FL2_13MY_MSCAN r01.dbc 有 35 条报文 12 条信号,r03.dbc 有 39 条报文 39 条信号——两者 ID 相互重叠,是迭代关系而非总线分区互补。信号数从 12 跳到 39 而报文只多 4 条,说明大量条目仍停留在报文清单或初步解释层面。硬件侧倒是清晰:两路 MCP2515 分别跑 125 kbit/s 与 500 kbit/s,对应中速与高速两条总线。

    两个版本是迭代关系,不是互补分区

    最容易犯的错是把 r01 与 r03 当成两条不同总线的定义拼在一起用。归档记录明确写着:这是两个版本、ID 重叠,不是互补的总线分区。正确做法是只取较新的一份作为当前基线,把旧版留作来源快照。

    文件 报文数 信号数 与另一版的关系 使用建议
    FL2_13MY_MSCAN r01.dbc 35 12 较早版本,ID 与 r03 重叠 留作来源快照,不参与合并
    FL2_13MY_MSCAN r03.dbc 39 39 较新版本,比 r01 多 4 条报文、多 27 条信号 作为当前基线,逐条核对

    多出来的 27 条信号分布在 39 条报文里,平均下来每条仍不足 1 条。这个比例本身就是一条判据:文件里相当一部分条目只是被登记了报文 ID,尚未解出对应的物理信号。较新版本还包含 4 条扩展 ID 条目,发送方被标注为项目自定义来源(原文记作 JPL-Added),分别对应转向灯、背光、驻车雷达与钥匙电池状态。

    三条总线的分工:中速、高速与娱乐总线

    这个工程同时面对三条总线。中速 CAN 是主攻方向,高速 CAN 目前主要用于生成 CanDump 供调试;娱乐总线则是音频主机与显示屏之间的专用链路,独立于 MS/HS 之外,解码进度反而更具体。

    总线 速率 接口 承载内容 解码状态
    中速 CAN(MS-CAN) 125 kbit/s can0 车身与信息类 ID,含 VIN 进行中,README 标注 work in progress
    高速 CAN(HS-CAN) 500 kbit/s can1 车辆高速总线 可生成 CanDump 用于调试开发
    娱乐总线(Entertainment Bus) 未在 README 中标注 音频主机与主机显示屏之间 音源(FM/DAB/AM/Aux/蓝牙,CD 待定)、电台名与 RDS 附加数据、音量、蓝牙媒体的曲名与艺术家 部分解码,条目比 MS-CAN 更具体

    娱乐总线的音量项有个细节:它只在操作原车硬件旋钮开关时弹出。这类「事件触发而非周期广播」的行为,是被动监听时最容易漏掉的报文类型,也说明了为什么单纯抓一段 CanDump 不足以还原总线行为。

    硬件与接口配置:两路 MCP2515 与两个波特率

    工程跑在树莓派上,通过 SPI 挂两路 MCP2515 控制器。/boot/config.txt 里先开 SPI,再声明两个 overlay,晶振均为 16000000,中断脚分别是 25 与 23;/etc/rc.local 里在 exit 0 之前拉起两个接口,速率一高一低。

    配置项 取值 说明
    SPI dtparam=spi=on MCP2515 经 SPI 挂载的前提
    can0 晶振 16000000,中断 23,bitrate 125000 对应中速 CAN
    can1 晶振 16000000,中断 25,bitrate 500000 对应高速 CAN
    系统依赖 can-utils、libsocketcan2、libsocketcan-dev 通过 apt 安装
    运行时 Node.js 20.10.0(仅在此版本测试过) 随后执行 npm i
    构建目标 pi64-build(RPi 4 且 4GB 以上)、pi32-build(RPi 3 或 4GB 以下的 RPi 4)、electron-build(Ubuntu,仅供测试) 产物在 /dist 下,运行 AppImage
    免硬件调试 vcan 加 can-gw 双向转发 先 down 掉 can1 再以 125000 拉起,或建两条 vcan 互转

    证据边界:哪些是已解码,哪些只是假设

    这份材料的价值在于把「已实现」「进行中」「假设」分得很清楚。直接照抄 DBC 里的信号名会带来两类风险:把未验证的假设当结论,以及把项目自定义的编码当原车报文。

    条目 状态 边界说明
    VIN 解析 已实现 解析 VIN 得出车龄、品牌与型号;首次启动需要一点时间完成配置
    娱乐总线解码 部分实现 音源、电台名与 RDS、音量、蓝牙曲目均已覆盖
    CD 音源 待定 原文标注为 Pending
    MS-CAN ID 解码 进行中 README 明确标注 work in progress
    4 条扩展 ID(转向灯、背光、驻车雷达、钥匙电池) 未确立 发送方被标注为项目自定义来源,尚未确认是原车观测帧还是项目自有编码
    带问号的注释(如胎压归属) 假设 仍是推测,未验证
    车辆配置文件解析 TBC 是否需要尚未确定
    逐信号验证与配置/固件适配 缺失 README 只给出工程与大致车型范围
    许可证 无 检查的快照中没有许可证文件

    被动监听时要特别留意的两类帧

    第一类是非周期帧:娱乐总线的音量只在操作原车旋钮时弹出,短时抓包很可能整段缺失。第二类是来源存疑的帧:那四条扩展 ID 与带问号的注释都属于此类。合理的抓取策略是先长录一段覆盖静置、上电、操作旋钮与行驶四个阶段,再按 ID 出现次数做筛选,而不是只看某一段 CanDump 里出现了什么。

    常见问题

    r01 与 r03 该用哪个?

    用 r03 作基线,r01 只作来源快照。归档记录明确说明两个版本 ID 相互重叠、是迭代关系而非互补的总线分区,把它们合并会引入重复 ID 与冲突定义。r03 有 39 条报文 39 条信号,比 r01 多 4 条报文、27 条信号。

    125 kbit/s 与 500 kbit/s 分别对应哪条总线?

    125 kbit/s 是中速 CAN,绑定在 can0;500 kbit/s 是高速 CAN,绑定在 can1。两者都由 MCP2515 经 SPI 提供,晶振 16000000,中断脚分别为 23 与 25,配置写在 /boot/config.txt 与 /etc/rc.local 里。

    那四条扩展 ID 是原车报文吗?

    尚未确立。它们出现在较新版本里,对应转向灯、背光、驻车雷达与钥匙电池状态,发送方被标注为项目自定义来源。归档记录明确写到,尚未独立确认这些条目是观测到的原车帧还是项目自有编码,因此不能当作原厂信号使用。

    娱乐总线和中速 CAN 是同一条总线吗?

    不是。README 把娱乐总线描述为音频主机与主机显示屏之间的专用总线,独立于 MS/HS 之外,并单独列出了音源、电台名与 RDS、音量、蓝牙曲目等解码项。它的速率未在 README 中标注。

    这套配置能直接搬到别的车型上吗?

    硬件部分可以复用,报文部分不能。两路 MCP2515 加 can-utils 的接法与车型无关;但 DBC 里的 ID 与信号是针对 2012 年款之后的 Freelander 2 整理的,且 README 未提供逐信号验证与具体配置、固件适配的证据,换车型必须重新取证。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/n95jpl-freelander2-mscan/SOURCE.md(两个 DBC 版本的报文数与信号数、重叠关系、扩展 ID 与许可证状态)
    • 项目 01 —— public-can-dbc-datasets/additional/n95jpl-freelander2-mscan/README.md(功能清单、娱乐总线解码项、树莓派双 CAN 接口配置与 vCAN 调试步骤)

    免责声明

    本文所述内容均为社区逆向与开发中的工程产物,不代表车辆制造商的官方数据。文中数字均来自上述公开仓库的说明文件,未经独立实车验证;不同车型年款、配置与固件版本可能存在差异,部分条目在原始材料中即标注为假设或未确立。涉及安全相关用途时请仅作参考,并以实际测量与官方资料为准。

    更新记录

    • 2026-10-14 初稿

  • 马自达 RX-8 的 CAN 笔记:6 个 ID、9 个信号与两处未定系数

    结论:这是一份为赛道遥测整理的马自达 RX-8 CAN 笔记,用 6 个报文 ID 承载 9 个信号:0x201 同时给出油门、转速与车速,0x212 给出刹车与手刹两个开关量,0x231、0x420、0x250、0x81 各给出一个信号。它的价值在于把字节偏移、长度、位掩码与换算公式写到了可直接落地的粒度;边界也同样清楚——只在 2006 年款(series 1)手动挡带 DSC 的一台车上用 OBDLink MX+ 与 RaceChrono v7.5.3 验证过,转速除数还有 4.0 与 3.85 两套并存,刹车压力至今只有开关量、没有连续量。

    九个信号的字段边界

    先要澄清一个术语:笔记里的「PID」指的是 CAN 报文 ID,不是 OBD-II 服务 01 下的参数标识符。这决定了取数方式是被动监听总线,而不是主动请求应答。多字节值统一按大端解析,这是后面所有公式的前提。

    信号 报文 ID 字节偏移 长度 位掩码 类型 换算公式
    油门开度 0x201 6 1 无 UINT8 百分比 = 值 / 2(原始值范围 0 到 200)
    引擎转速 0x201 0 2 无 UINT16 rpm = 值 / 4.0
    车速 0x201 4 2 无 UINT16 km/h =(值 – 10000)/ 100.0
    刹车踏板 0x212 5 1 0x08 Bool 踩下 = 值
    手刹 0x212 4 1 0x40 Bool 拉起 = 值
    空挡 0x231 0 1 0x80 Bool 空挡 = 取反后的值
    冷却液温度 0x420 0 1 无 UINT8 摄氏度 = 值 – 40
    进气温度 0x250 3 1 无 UINT8 摄氏度 = 值 – 40
    转向角 0x81 2 2 无 INT16 度 = 值(有符号)

    九个信号里 0x201 一条报文就占了三个,且彼此不重叠:转速在偏移 0 占 2 字节,车速在偏移 4 占 2 字节,油门在偏移 6 占 1 字节。这种紧凑布局意味着解析时一次取 8 字节即可解出三个量,但也意味着任何一个偏移写错都会静默地取到相邻信号。

    位掩码到 RaceChrono 位号的换算

    笔记给字节偏移与位掩码,RaceChrono 公式里用的却是 0 到 63 的位号,两者需要对账。RaceChrono 的约定是从最高位起算:位 0 是最高位,位 57 的权值为 64。据此可以推出换算关系——位号等于字节偏移乘以 8,再加上掩码在该字节内从高位往低数的序号。

    信号 字节偏移 位掩码 掩码在字节内的高位序号 RaceChrono 位号 RaceChrono 公式
    空挡 0 0x80 0 0 (1 – BitsToUInt(raw, 0, 1)) * 100
    手刹 4 0x40 1 33 BitsToUInt(raw, 33, 1) * 100
    刹车踏板 5 0x08 4 44 BitsToUInt(raw, 44, 1) * 100

    三个位号都能对上:0 = 0×8+0,33 = 4×8+1,44 = 5×8+4。三个开关量都乘 100,是为了把布尔量塞进 RaceChrono 的百分比通道。空挡那一项额外做了取反:原始位在空挡或踩离合时为 0,其余情况为 1。

    两处未定系数与一处待办

    笔记里真正需要用户在落地时做判断的,是笔记公式与 RaceChrono 公式不一致的地方。这些差异大多有明确原因(单位制不同),唯独转速那一处被原作者标记为「需要调查」。

    信号 笔记公式 RaceChrono 公式 差异原因 是否待定
    引擎转速 值 / 4.0 值 / 3.85 4.0 是标准公式,3.85 更贴合仪表显示 是,原作者标注需调查
    车速 (值 – 10000)/ 100.0 得 km/h (值 – 10000)/ 360 RaceChrono 需要 m/s,故除以 360 而非 100 否
    冷却液温度 值 – 40 得摄氏度 值 – 40 RaceChrono 自动转换为华氏度 否
    进气温度 值 – 40 得摄氏度 值 – 40 RaceChrono 自动转换为华氏度 否
    转向角 值(有符号) 值 × -1 RaceChrono 需取反才能正确显示转向动画 否
    刹车压力 无 无 笔记 TODO:希望以压力量替代开关量 是,尚未找到

    转速除数为什么不能随手选一个

    4.0 与 3.85 在 7000 rpm 处的差值约 273 rpm,足以让换挡提示与圈速分析出现系统性偏差。笔记明确写到除以 4 是标准公式,但 3.85 看起来更接近车辆仪表显示的值,而作者并未判定哪个正确。落地时的合理做法是用仪表或独立转速计做一次标定,而不是沿用其中任意一个。

    车速公式里的 10000 偏移

    车速要先把原始值减掉 10000 再除以 100,说明这条通道带了一个 10000 的零点偏移,而不是从 0 计起。这样的设计让原始值具备表达负速度(倒车)的余量,但也意味着如果直接把该 uint16 当无符号数解释而忘记减偏移,会得到约 100 km/h 的固定假值。落地时应先确认目标工具是按有符号还是无符号取值,并在静态停车状态下先读一次原始值做零点校验。

    验证环境与适用边界

    这套代码带的免责声明写得很直接:仅供实验用途,使用风险自负。它的验证矩阵也很窄,只有一台车、一个适配器、一个手机型号与一个软件版本。

    项目 取值 对适用性的影响
    车辆 Mazda RX-8 2006(series 1),手动变速箱,带 DSC 自动挡或其他年款未验证
    适配器 OBDLink MX+ 蓝牙扫描仪 换适配器后需重新确认透传是否完整
    手机 Huawei P30 Pro,Android 10 蓝牙协议栈差异可能影响采样连续性
    软件 RaceChrono v7.5.3,需开启实验功能 7.5.3 起必须启用实验特性才能生效
    字节序 多字节值为大端 按小端解析会得到完全错误的速度与转速
    位编号 从最高位起算,范围 0 到 63,位 57 的权值为 64 与常见 LSB 起算工具不通用

    常见问题

    这里的 PID 是 OBD-II 的 PID 吗?

    不是。笔记里的 PID 指 CAN 报文 ID,例如 0x201、0x212、0x231、0x420、0x250、0x81,取数方式是被动监听总线而不是主动请求应答。这与 OBD-II 服务 01 下的参数标识符是两套体系,混用会得到完全不同的字节布局。

    这些报文适用于所有 RX-8 年款吗?

    不能这样假定。笔记声明只在 Mazda RX-8 2006(series 1)、手动变速箱、带 DSC 这一台车上验证成功,并明确为实验用途。自动挡、其他年款或不同市场版本的报文布局可能不同。

    引擎转速为什么会有 4.0 和 3.85 两套除数?

    笔记写到除以 4 是标准公式,但 3.85 看起来更接近车辆仪表显示的值,作者自己也标注「不知道哪个是对的,需要调查」。两者在高转速区的差值可达数百 rpm,落地前应用仪表或独立转速计做一次标定。

    RaceChrono 里的位号 44、33、0 是怎么算出来的?

    由字节偏移与位掩码换算而来。RaceChrono 从最高位起算,位号等于字节偏移乘 8 再加掩码在字节内从高位往低数的序号:刹车 0x08 在偏移 5,得 5×8+4 = 44;手刹 0x40 在偏移 4,得 4×8+1 = 33;空挡 0x80 在偏移 0,得 0×8+0 = 0。

    刹车压力能从这些报文里取到吗?

    暂时不能。笔记只解出了 0x212 里的刹车踏板开关量与手刹开关量,并把「找到刹车压力代替开关信号」列为 TODO。也就是说目前只有布尔状态,没有连续的制动压力通道。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/topolittle-rx8-can-notes/README.md(9 个信号的报文 ID、字节偏移、位掩码、换算公式与验证设备清单)

    免责声明

    本文所述的 CAN 报文解析均来自公开仓库的实验性笔记,原作者明确声明仅供实验用途、使用风险自负,且与文中提到的任何公司无关联或赞助关系。文中数字未经独立实车验证,不同年款、市场与 ECU 版本可能存在差异。涉及安全相关用途时请仅作参考,并以实际测量与官方资料为准。

    更新记录

    • 2026-10-14 初稿

  • 五菱 Air EV 的 CAN 信号:115 个 ID 与一处未解的字节冲突

    结论:五菱 Air EV 的这份 CAN 嗅探研究给出了一条可复现的低成本采集链路和 115 个唯一 ID 的规模,但三个主参数的字节映射存在未解决的冲突:README 把油门踏板记在 0x17D 的字节 4 与 6,而随车保留的处理脚本把 0x155 标为踏板,并额外加了一个 0x1E5 电池电压。仓库里既没有 DBC、也没有原始 CSV 抓包和字节级换算公式,因此这些 ID 只能当作候选,不能当作已验证的解码表。

    一条 500 kbit/s 的被动采集链路是怎么搭起来的

    整套采集是被动的:ESP32 DevKitC 加 MCP2515 收发模块,走 OBD-II 接口的 6 脚(CAN High)与 14 脚(CAN Low),固件以监听模式运行,不做任何主动请求。晶振配置为 8 MHz,CAN 速率设为 500 kbit/s。一次约 49 分钟的道路测试记录下 115 个唯一 CAN ID。

    抓下来的原始记录以分号分隔的 CSV 落地,Python 侧用 pandas 读取后,把 Data_Raw 这一列按空格拆成 Byte_1 到 Byte_8 八列,再按 CAN ID 做映射标注,最后导出成一份包含全部 115 个 ID 的 Excel。未被映射表命中的 ID 统一标记为「尚未识别」。

    环节 配置项 取值 说明
    控制器 MCU / 收发器 ESP32 DevKitC + MCP2515(8 MHz) 固件使用 mcp_can 库,监听模式
    物理接入 OBD-II 引脚 6 脚 CAN High,14 脚 CAN Low 直接挂诊断口,无需破线
    总线速率 标称波特率 500 kbit/s 由固件按 8 MHz 晶振配置
    采样规模 时长与 ID 数 约 49 分钟,115 个唯一 ID 覆盖多种行驶工况
    落盘格式 CSV 分隔符 分号 读取时需显式指定分隔符
    后处理 字节拆分 Data_Raw 拆为 Byte_1–Byte_8 缺失字节填占位符
    产出 汇总文件 REKAP_TOTAL_PERCOBAAN_DUA.xlsx 115 个 ID 全部进入汇总表

    三处冲突:油门到底在哪个 ID

    把 README 的结论和保留下来的处理脚本并排看,会发现两套标注并不一致。差异集中在踏板这一项上,另外脚本多出一个电池电压条目,而 README 完全没有字节级换算公式。

    参数 README 给出的 ID 与字节 处理脚本给出的 ID 一致性判断
    加速踏板位置 0x17D,字节 4 与字节 6 0x155 冲突,未解决
    电机转速 0x16E,字节 5 与字节 7 0x16E ID 一致,无换算公式
    电池电流 0x16C,字节 5 与字节 6 0x16C ID 一致,无换算公式
    电池电压 未提及 0x1E5 脚本独有,无字节定义

    需要强调的是:脚本里的映射只是一张 ID 到标签的字典,用于给每一行打标注,并不包含缩放因子、偏移量或字节序。也就是说,即便 ID 确定,也无法据此直接得到工程量。README 里那句「字节 4 与 6」是目前唯一出现的字节位置线索,且同样没有给换算规则。

    为什么这个冲突不能靠猜来解决

    两个 ID 指向同一类信号,在实际解码里是两种完全不同的后果:如果 0x155 才是踏板而 0x17D 是别的量,那么按 README 取数会得到一条看似有变化、实则无关的物理量曲线,而且因为它随工况变化,很容易被误判为「已经解出来了」。判定办法只有一条——同时抓两个 ID 的原始数据,踩踏板做阶跃,看哪个字节随踏板线性跟随。

    证据边界:仓库里缺什么

    这份材料的定位是学术研究记录,不是可用的解码资产。判断它能用到什么程度,关键看缺失项,而不是看已给出项。

    缺失项 对使用的影响 建议处理
    DBC 文件 无法用标准工具直接解码全部 115 个 ID 自建候选 DBC 时把每个 ID 标为待验证
    原始 CSV 抓包 无法复算、无法复核字节位置 自行重采,保留原始文件
    字节级换算公式 ID 确定也得不到工程量 用独立参考源做标定后再写公式
    具体配置年款 无法判断结果能否迁移到同车型其他批次 记录自己的车辆配置,不跨车套用
    独立标定记录 三个主参数的精度无从评估 用仪表读数或 OBD 标准 PID 交叉验证
    明确的再分发许可 README 只要求署名,未给出许可证 仅作私有离线研究副本,商用前先确认权利

    仓库里的两份 DOCX 论文和若干绘图图像并未随本次归档保留,因此论文中是否给出了更完整的推导,无从判断。这也是为什么「未解决」比「错误」更准确:现有材料不足以判定谁对。

    常见问题

    这份研究能给五菱 Air EV 出一份可用的 DBC 吗?

    不能。仓库里没有 DBC,也没有原始 CSV 抓包与字节级换算公式,只有 115 个 ID 的规模和三个(实为四个)候选标签。它能提供的是采集方法和候选 ID 清单,DBC 必须由使用者自行采集、标定后重建。

    油门踏板到底应该用 0x17D 还是 0x155?

    目前无法确定。README 把踏板记在 0x17D 的字节 4 与 6,保留下来的处理脚本却把 0x155 标为踏板,两者冲突且未解决。可靠的判定方式是同时抓这两个 ID,踩踏板做阶跃,看哪个字节随踏板线性跟随。

    500 kbit/s 是这个车型 OBD 口的确定波特率吗?

    它是这次采集所用的配置值,不是车型的官方标称值。固件按 8 MHz 晶振把 CAN 速率设为 500 kbit/s 并成功收到 115 个 ID,说明该配置在本车可用;其他批次或年款是否一致未做验证。

    为什么脚本映射出四个 ID 却没有任何换算公式?

    因为脚本里的映射只是一张 ID 到标签的字典,作用是在汇总表里给每行打标注并统计 ID 分布,本身不做物理量解码。字节位置线索只在 README 中出现过一次,同样没有给出缩放因子与偏移量。

    这份材料可以再分发或放进产品吗?

    不建议直接使用。检查的仓库快照中没有找到任何许可证文件或 SPDX 声明,README 只提出署名要求,而署名要求并不构成明确的再分发许可。目前应按私有离线研究副本处理,商用前须确认权利。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/ilham511-wuling-air-ev/README.md(500 kbit/s 被动采集、115 个 ID、三个主参数的候选 ID 与字节)
    • 项目 01 —— public-can-dbc-datasets/additional/ilham511-wuling-air-ev/Processing_Data.py(ID 到标签的映射字典、字节拆分逻辑与汇总导出流程)
    • 项目 01 —— public-can-dbc-datasets/additional/ilham511-wuling-air-ev/SOURCE.md(快照版本、许可证状态与证据边界说明)

    免责声明

    本文所述 CAN ID、字节位置与采集参数均来自公开仓库的说明文件与脚本,未经独立实车验证,且 README 与脚本之间存在未解决的标注冲突。车辆配置年款、市场与 ECU 版本可能导致差异。涉及安全相关用途时请仅作参考,并以实际测量与官方资料为准。

    更新记录

    • 2026-10-14 初稿

  • MX-5 ND2 自定义仪表盘:8 报文 14 信号的取数边界

    结论:MX-5 ND2 做自定义仪表盘时,这份 8 报文 14 信号的 DBC 只能当种子定义,不能当判据。它的价值是给出了转速、车速、油门、挡位/离合、转向、制动压力、轮速以及冷却液/进气温度的分域清单,但重复的属性定义、多处写成 0|0 或 0|1 的物理量范围、以及 0.01 车速比例与另一份 ND 笔记公式不一致这三点,决定了上仪表前必须先做一轮复核。

    仪表盘的取数要先分清楚三种数据源

    这套记录仪分成显示单元与传感器单元两部分,两者之间走 I2C,1.2 米的线缆在做好线材处理后仍有约 0.5% 的通信错误率。显示单元由 Raspberry Pi 4B 加一块 4.3 英寸 DSI 触摸屏构成;传感器单元集成 5V 电源、两片 4 通道 ADC、一个运动追踪模块,以及一块带定制固件的 I2C CAN 控制器。模拟量与车辆 CAN 走的是完全不同的通路,混在一起排查会浪费大量时间。

    系统对 RaceChrono 而言是一个 DIY BLE 设备:一部分选定的 CAN 帧直接透传,采集到的模拟量则被打包成一条额外的 CAN 帧一起送给 RaceChrono 记录。也就是说,仪表上看到的数字至少有车辆原始帧、透传帧、合成帧三种来源。

    数据源 硬件通路 典型信号 证据状态
    车辆 CAN I2C CAN 控制器 + 定制固件 转速、车速、油门、冷却液温度、进气温度 8 报文 DBC,标注在 2019 ND2 AE 上验证
    模拟量采集 两片 4 通道 ADC 机油压力、机油温度、转子温度 作者自建通道,未见独立标定记录
    红外测温 0~1000 °C 工业红外测温仪,4–20 mA 输出 转子温度 硬件选型已定,截至 2023-09-04 尚未装车
    运动追踪 已安装的运动追踪模块 未接入 README 列为后续开发项
    合成帧 BLE 侧自行封装 全部模拟量打包成一条 CAN 帧 仅供 RaceChrono 记录,非原车帧

    8 报文 14 信号覆盖的六个域

    DBC 本体很小:8 条报文、14 个信号,覆盖的全是仪表盘最关心的量。把它按信号域摊开看,才能判断哪些域可以直接用、哪些域需要补枚举或补标定。

    信号域 DBC 覆盖内容 上表盘前的注意
    动力 转速、车速、油门 车速比例与另一份 ND 笔记公式不一致,须对抓包复核
    传动 挡位、离合 状态类信号,先确认枚举值是否齐全再显示
    转向 转向角 需确认零位与左右符号约定
    制动 制动压力 与轮速联合判读才有意义
    轮速 车轮轮速 四轮一致性可反向验证车速公式
    温度 冷却液温度、进气温度 与机油温度分属不同通路,报警阈值不通用

    值得注意的是:机油压力与机油温度并不在这 14 个信号里,它们来自模拟量通道。因此机油压力报警的判据是电压换算后的工程量,而不是 DBC 解码结果——这决定了它的精度取决于 ADC 与传感器标定,与 CAN 侧无关。

    三处必须在上仪表前处理的 DBC 缺陷

    这份归档 DBC 保留了原文件的原样,包括它的瑕疵。三处缺陷都会直接影响解码器的行为,且都不是「看看就好」的级别。

    缺陷类型 具体表现 处理动作
    属性定义重复 同一条属性被重复声明 部分解析器会告警甚至拒绝加载,导入前先跑一遍加载测试
    物理量范围不成立 多处 minimum|maximum 写成 0|0 或 0|1,不描述缩放后的输出 不要用 DBC 上下限做滑块量程或报警阈值
    车速比例分歧 归档 DBC 的车速比例为 0.01,另一份公开 ND 笔记给出的公式不同 拿抓包数据与独立车速参考源比对后再选定
    文件出处不明 DBC 文件名带 BY_TDO 后缀,来源未独立确认 商用复用前先核对第三方信号与表格的出处

    其中第二点最容易被忽略:很多人把 DBC 的 minimum/maximum 直接拿来生成 UI 滑块的上下限或报警门限,而这里的 0|0 和 0|1 并不描述缩放后的物理量,照抄会得到错误区间。

    蜂鸣器报警是双条件触发

    显示单元带一个蜂鸣器,触发条件是机油压力低于阈值且转速高于怠速。两个条件同时成立才响,这是为了避免熄火状态下机油压力为零时误报。这个逻辑也说明:仪表盘的报警判据是跨数据源的,CAN 侧给转速,模拟侧给压力。

    常见问题

    这份 8 报文 DBC 能当 MX-5 ND2 的整车网络定义吗?

    不能。它只有 8 条报文、14 个信号,覆盖动力、传动、转向、制动、轮速与温度六个仪表域;上游并未把它描述为整车网络定义,标注的验证车辆也只有 2019 ND2 AE 一台,其他年款与市场未做确认。

    为什么车速不能直接用 DBC 里的 0.01 比例?

    因为同一车型的另一份公开 ND 信号笔记给出的车速公式与归档 DBC 的 0.01 比例不同,两者来源不同且未做交叉验证。在没有抓包数据和独立车速参考源比对之前,这两套公式不能互换使用。

    仪表盘的报警阈值能不能取 DBC 的物理量上下限?

    不能。这份 DBC 里多处物理量范围写成 0|0 或 0|1,并不描述缩放后的输出值。用它生成滑块量程或报警门限会得到错误区间,阈值应当来自实测标定或官方资料。

    机油压力报警在什么条件下触发?

    机油压力低于设定阈值并且转速高于怠速时,显示单元的蜂鸣器才会响起。两个条件必须同时成立,这样设计是为了避免熄火后机油压力归零导致的误报。

    显示单元和传感器单元之间的 I2C 有什么实测问题?

    两者之间用 1.2 米 I2C 线缆连接,作者说明即使做了仔细的线材处理,通信仍有约 0.5% 的错误率。长距离 I2C 是这个架构的已知短板,做数据完整性校验时要把这个错帧率算进去。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/chrumck-knurdash-mx5-nd/SOURCE.md(8 报文 14 信号 DBC 的覆盖范围、0.01 车速比例分歧与 MIT 许可证提示)
    • 项目 01 —— public-can-dbc-datasets/additional/chrumck-knurdash-mx5-nd/README.md(显示单元与传感器单元的硬件构成、I2C 错误率、蜂鸣器逻辑与装车状态)

    免责声明

    本文所述信号与硬件参数均来自公开仓库的说明文件与源码注释,未经独立实车验证。DBC 标注的验证车辆为 2019 ND2 AE,其他年款、市场与 ECU 版本可能存在差异。涉及安全相关用途时请仅作参考,并以实际测量与官方资料为准。

    更新记录

    • 2026-10-14 初稿

  • 比亚迪 / Proton 的 openpilot 移植:指纹规模与功能替换边界

    结论:bukapilot 是 openpilot 之上的维护型补丁集,目标是把 ADAS 带到马来西亚在售车型(尤其 Perodua 与 Proton),并在既有能力上补齐完整的右舵支持。落到 CAN 适配层,判断一个车型「算不算移植完成」要看两件事:DBC 字典有没有映射、指纹有没有登记。按这个口径,BYD ATTO 3 有 2 组指纹(144 与 110 个地址),Proton X50 有 1 组(179 个地址),而 Proton S70 与 X90 只有 DBC 映射、没有指纹,属于未完成的端口条目。

    车型移植的两张表:DBC 映射与指纹

    移植数据集中在两个 values.py 里:一份按品牌给出 CAR 常量、DBC 字典与指纹字典,另一份给出 HUD 倍率。DBC 字典走 openpilot 的 dbc_dict 形式,第二项为 None,即未登记雷达侧 DBC。HUD 倍率直接影响仪表与抬头显示上的速度呈现,BYD 侧为 0.718,Proton 侧为 1.035 且在源码里留着「Todo」标记,说明它仍是待标定的值。

    品牌 车型常量 DBC 字典 指纹组数 HUD 倍率
    BYD ATTO3 = "BYD ATTO 3" byd_general_pt(雷达侧 None) 2 0.718
    Proton S70 = "PROTON S70" proton_general_pt(雷达侧 None) 0 1.035(Todo)
    Proton X50 = "PROTON X50" proton_general_pt(雷达侧 None) 1 1.035(Todo)
    Proton X90 = "PROTON X90" proton_general_pt(雷达侧 None) 0 1.035(Todo)

    指纹规模与非 8 字节 DLC

    指纹记录的是「地址到长度」的映射,是车型识别的第一道判据。三组的规模差异很大,而真正有价值的信号藏在那些长度不等于 8 的地址里。

    指纹 地址数 长度非 8 的地址 地址范围
    ATTO 3 指纹一 144 204:20、287:5、385:3、682:2、1542:2、1798:3 85 – 2027
    ATTO 3 指纹二 110 287:5、385:3、682:2、1542:2、1798:3 85 – 1832
    Proton X50 指纹 179 385:3、1542:2、1798:3 32 – 2025

    把三组放在一起比对,能读出三条结论。其一,ATTO 3 的两组指纹共有 107 个地址,第一组独有 37 个、第二组独有 3 个,说明第二组几乎是第一组的子集,多数组差异来自配置或年款导致的报文增减。其二,三组指纹共有 17 个地址,其中 385(长度 3)、1542(长度 2)、1798(长度 3)长度都不是 8,这类跨品牌稳定的短帧通常是通用或诊断相关报文,不应作为车型特征。其三,X50 的 179 个地址里有 159 个不在 ATTO 3 两组指纹的并集(147 个地址)之内,两个品牌的报文空间基本不重叠,因此 DBC 也必须分成 byd_general_pt 与 proton_general_pt 两套。

    另有一个需要单独确认的点:ATTO 3 第一组指纹里出现 204:20,长度 20 超出经典 CAN 的 8 字节上限。它可能来自 CAN FD 采集,也可能来自采集工具的合并口径,在把它写进匹配规则之前必须先确认采集链路。

    功能替换边界:哪些被替换,哪些叠加

    移植不只是接上 CAN,还要说清接管了哪些原厂功能。README 把这件事分成「所有受支持车型」与「特定受支持车型」两层,处理逻辑完全不同。

    功能 所有受支持车型 特定受支持车型
    LKA 原厂 LKA 被替换,仅在用户启用后生效 同上
    LDW 原厂 LDW 被替换 同上
    ACC 不替换 原厂 ACC 被替换
    FCW 不声明 在原厂 FCW 之外叠加运行
    AEB、自动远光、盲区警示、侧向碰撞警示 原厂功能一律保留 原厂功能一律保留

    这套划分的工程含义是:横向控制(LKA/LDW)是移植的必选项,纵向控制(ACC)只在完成标定的车型上接管,前向碰撞预警采取「叠加而非替换」以保留原厂兜底,其余主动安全功能不动。开发车端口时,也应按同样的层次逐项确认,而不是一次性接管全部。

    数据上传与责任边界

    默认情况下驾驶数据会上传到项目方服务器。日志范围按项列出,可退出性并不一致,做合规评估时要逐项核对。

    数据项 默认状态 可否关闭
    路面相机、CAN、GPS、IMU、磁力计、热传感器、崩溃与操作系统日志 记录并上传 仅在设置中显式退出驾驶员相机一项,其余未说明可关闭
    驾驶员朝向相机 默认记录 可在设置中显式 opt-out
    麦克风 不录制 不适用
    数据使用权 授予项目方不可撤销、永久、全球范围的使用权 使用即视为同意

    责任侧同样写得很硬:软件以 MIT 许可发布(部分组件按各自许可),但被明确定性为 alpha 质量的 research-only 软件,不是产品;使用者须自行遵守当地法律法规,无明示或默示担保,并须就使用该软件产生的一切索赔向项目方作出赔偿与免责。性能限制也被逐条列出:恶劣能见度、相机被遮挡或损坏、车身贴膜贴纸或橡胶涂层造成的遮挡、设备安装不当、急弯与匝道路口的转向扭矩上限、受限车道与施工区、大横坡或强侧风、极热极冷、强光直射、坡道窄路与蜿蜒道路。它不会自动驾驶,也不减轻驾驶者必须付出的注意力;变道时它无法查看盲区,确认安全后由人工轻推方向盘发起。

    常见问题

    bukapilot 与 openpilot 是什么关系?

    bukapilot 是 openpilot 的维护型补丁集,目标是支持马来西亚在售车型(尤其 Perodua 与 Proton),使用为这些车型专门设计的硬件,并在 openpilot 既有能力之上补齐完整的右舵支持。它实现 ACC、LKA、FCW、LDW,并在启用时叠加基于相机的驾驶员监测;作为 openpilot 的补丁集,它也继承了 openpilot 的软件安全模型,并针对补丁部分逐步补充增量测试。

    为什么 Proton S70 与 X90 不能算已适配?

    因为它们在 values.py 里只有 DBC 映射(proton_general_pt)而没有指纹条目。指纹是车型识别的第一道判据,缺失意味着无法在实车上完成确定的车型匹配;同为 Proton 的 X50 则有 1 组含 179 个地址的指纹。此外 Proton 侧的 HUD 倍率 1.035 在源码里仍带 Todo 标记,属于待标定值。

    指纹里的 204:20 该怎么理解?

    它表示地址 204 的帧长度为 20 字节,超出经典 CAN 的 8 字节上限,可能来自 CAN FD 采集或采集工具的合并口径。在把它写进车型匹配规则之前必须先确认采集链路与总线类型,否则会在不支持该长度的接口上造成误匹配。

    默认会上传哪些数据,能不能关掉?

    默认上传驾驶数据,日志包括路面朝向相机、CAN、GPS、IMU、磁力计、热传感器、崩溃与操作系统日志;驾驶员朝向相机默认记录但可在设置中显式退出;麦克风不录制。使用即视为授予项目方不可撤销、永久、全球范围的数据使用权,除驾驶员相机外其余项的关闭方式在文档中未作说明。

    bukapilot 会接管原厂 AEB 和盲区警示吗?

    不会。文档要求保留车辆其他全部原厂功能,明确列举的包括 FCW、自动紧急制动(AEB)、自动远光、盲区警示与侧向碰撞警示。被替换的是原厂 LKA 与 LDW;在受支持的特定车型上,原厂 ACC 被替换,而 bukapilot 的 FCW 是在原厂 FCW 之外叠加运行,不是替换。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/alienware-sa-bukapilot-byd-proton/README.md(项目定位、功能替换层次、限制清单、数据上传与许可责任条款)
    • 项目 01 —— public-can-dbc-datasets/additional/alienware-sa-bukapilot-byd-proton/selfdrive/car/byd/values.py(ATTO 3 的 DBC 映射、HUD 倍率与两组指纹)
    • 项目 01 —— public-can-dbc-datasets/additional/alienware-sa-bukapilot-byd-proton/selfdrive/car/proton/values.py(S70/X50/X90 的 DBC 映射、HUD 倍率与 X50 指纹)

    免责声明

    本文所述内容为公开开源项目的移植数据与文档摘录,不代表车辆制造商或项目方的官方承诺。素材自身已声明:该软件为 alpha 质量的 research-only 版本,不是产品,无明示或默示担保,使用者须自行遵守当地法律法规并承担相应责任;它不会自动驾驶,也不减轻驾驶者必须付出的注意力。文中指纹地址与长度均按公开文件统计,未经实车复现,不同年款、市场与配置可能存在差异,涉及行车安全的改装请务必在封闭场地与专业监督下进行。

    更新记录

    • 2026-10-14 初稿

  • Palisade 只读 CAN 解码器:9 条报文、28 信号与三条边界

    结论:这份 Palisade 2020 解码器不是通用 DBC 解析器,而是被压缩到 9 条报文、28 个信号的窄口径只读实现:未知帧静默忽略,已知报文的 payload 长度不符则直接返回错误。决定它可用性的不是那张报文表,而是三条边界——它是 opendbc 的 MIT 授权只读子集、不引入上游任何车辆控制与发送代码、未用实车日志按年款与市场确认前不得把新信号提升为 canonical 状态。

    解码授权清单:只有 9 条报文

    解码器被固定在 dbc 仓库的 HYUNDAI_PALISADE_2020 provenance manifest 上,只直接解析下表中的报文,其余一律视为未知帧。六条报文在素材里给出了十六进制 ID,另外三条以 DBC 报文名引用。用途分两类:少数信号进入 canonical 状态(车速、转向角、纵向加速度、挡位、轮速、SCC 状态),其余只作为 raw diagnostics 呈现。

    DBC 报文 CAN ID 信号 解码后用途
    CLU11 未给出 CF_Clu_Vanz、CF_Clu_SPEED_UNIT 仪表车速与单位,canonical
    SAS11 未给出 SAS_Angle 转向角,canonical
    TCS13 未给出 ACCEL_REF_ACC、DriverOverride 纵向加速度与驾驶员制动状态,canonical
    CGW1 0x541 近光、驾驶席车门、前排安全带、雨刮与灯光开关 近光映射为 night_mode,其余为 raw diagnostics
    GW_DDM_PE 0x521 四门状态 raw diagnostics
    DATC12 0x042 驾驶席/副驾摄氏设定温度 raw diagnostics
    LVR12 0x367 CF_Lvr_Gear 换挡杆挡位状态,canonical
    WHL_SPD11 0x386 WHL_SPD_FL/FR/RL/RR 四轮轮速,canonical
    SCC14 0x389 ACCMode SCC 激活状态,canonical

    raw diagnostics:可以读,不能判定

    素材明确写明当前没有实车捕获,因此这组信号以 manifest 固定版本的 DBC 所载 message ID、bit 位置与 scale 为唯一依据。数值以 MESSAGE.SIGNAL 为键写入 VehicleState.raw_signals,在 HMI Diagnostics 中只读展示。硬规则是:不得自行解释 DBC 枚举值的含义,也不得把这些值用于车门、安全带、空调的 canonical 状态或任何车辆控制。

    raw 键 DBC 物理值 换算
    CGW1.CF_Gway_DrvDrSw 驾驶席车门开关 原始枚举,不解释
    CGW1.CF_Gway_DrvSeatBeltSw、CGW1.CF_Gway_AstSeatBeltSw 前排安全带开关 原始枚举,不解释
    GW_DDM_PE.C_DRVDoorStatus、C_ASTDoorStatus、C_RLDoorStatus、C_RRDoorStatus 四门状态 原始枚举,不解释
    DATC12.CR_Datc_DrTempDispC、CR_Datc_PsTempDispC 驾驶席/副驾摄氏设定温度 raw × 0.5 + 14

    唯一给出换算式的只有空调温度这一组,其余全部停在「原始枚举」层级。这不是偷懒,而是把「DBC 说有这个信号」和「这个枚举在这个年款上代表开或关」两件事分开——后者只能由实车日志证明。

    0x541 近光位的实车验证判据

    CF_Gway_HeadLampLow 只表示近光是否点亮,既推断不出自动灯光设置,也推断不出环境照度。因此批准这条映射前,必须在停车、点火 ON 状态下逐条记录,并核对日志 payload 第四个字节的最高位是否与下表一致;不一致就不发布该映射,而是回到 DBC 与车辆年款、配置的核对上。

    条件 期望 0x541 bit 31 期望 night_mode
    灯光 OFF 0 false
    近光 ON 1 true
    AUTO 模式 与实际近光点亮状态相同 与实际近光点亮状态相同

    采集与回放必须走两条不同的路:设备以 SocketCAN can0 接入后只做接收,用带时间戳的日志记录 0x541;捕获内容绝不向物理 can0 回发,开发环境只在 vcan0 上回放。每次切换条件时单独记录时刻与观察到的灯光状态。回归 fixture 中不得放入车辆识别信息、位置、时间等敏感原始日志,只保留已验证的 0x541 帧与必要的最小状态帧。

    三条边界与当前证据状态

    把散落在 NOTICE 与源说明里的约束收拢成一张表,才能看清这份解码器能承担什么。

    边界 具体要求 落地动作
    只读 文件与解码器均为接收专用,上游的车辆控制与发送代码不引入 工程上只允许 candump 侧记录,禁止任何向实车总线的写入
    未验证不提升 在车辆年款、市场、配置上用实车日志确认 frame 与 signal 之前,不把新信号加入 canonical state 新增信号先进 raw_signals,验证通过后再提级
    权利与适配 派生自 opendbc 的 MIT 授权内容,须保留原始通知;须核对车型年款与市场适配性 分发时保留上游 MIT 声明,逐车型做适配核对

    证据状态同样要如实标注:源说明指出实车信号验证仍在进行中,且该 DBC 的 BU_ 列表缺少若干被其报文与信号引用的节点名,严格解析器可能需要先做清理;文件本身按字节原样保留。子集规模为 9 条报文、28 个信号,固定版本的上游修订与 MIT 归属均记录在 NOTICE 中。

    常见问题

    这份解码器能当作完整 DBC 解析器使用吗?

    不能。它是已批准 schema 的窄口径只读实现,只解码 9 条报文、28 个信号;未知帧按正常流程忽略,已知报文的 payload 长度不一致时返回错误。要做全量解析应使用通用 DBC 解析器,而不是这份子集。

    raw diagnostics 里的枚举值可以直接当车门或安全带状态用吗?

    不可以。素材明确要求不得自行解释 DBC 枚举的含义,也不得把这些值用于车门、安全带、空调的 canonical 状态或车辆控制。它们在 VehicleState.raw_signals 中以 MESSAGE.SIGNAL 为键只供 HMI Diagnostics 只读查看,只有空调温度给出了 raw × 0.5 + 14 的换算。

    0x541 的近光位要怎么在实车上确认?

    在停车、点火 ON 状态下,对灯光 OFF、近光 ON、AUTO 三种条件分别记录时刻与观察到的灯光状态,并核对日志 payload 第四个字节的最高位是否与判据表一致:OFF 为 0、ON 为 1、AUTO 与实际点亮状态相同。不一致则不得发布该映射,需重新核对 DBC 与车辆年款、配置。

    采集到的车辆日志可以回放到车上总线吗?

    不可以。素材规定捕获内容不向物理 can0 回发,开发环境只在 vcan0 上回放。回放前需加载 vcan 模块并创建 vcan0 接口,再用日志回放工具把 can0 映射到 vcan0。回归 fixture 中也不得保留车辆识别信息、位置与时间等敏感原始日志。

    这份 DBC 子集的权利与适配边界是什么?

    它是 opendbc 中 Hyundai CAN DBC 的只读子集,沿用上游 MIT 授权,分发时必须保留原始通知与归属声明;同时源说明要求在使用前核对车型年款、市场与配置适配性。此外该文件的 BU_ 列表缺少若干被引用的节点名,严格解析器可能需要先清理,实车验证也仍在进行中。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/oas-ai-palisade-read-only/decoder-guide.md(9 条报文解码清单、raw diagnostics 目录与 0x541 验证判据)
    • 项目 01 —— public-can-dbc-datasets/additional/oas-ai-palisade-read-only/NOTICE.md(只读子集的上游修订、MIT 归属声明与只读使用限制)
    • 项目 01 —— public-can-dbc-datasets/additional/oas-ai-palisade-read-only/SOURCE.md(9 报文/28 信号的版本固定、BU_ 缺失提示与年款适配提醒)

    免责声明

    本文所述解码器与 DBC 子集为社区逆向工程与公开派生产物,不代表车辆制造商的官方数据。素材中的使用限制已如实转述:该子集为接收专用,不引入上游车辆控制与发送代码;在按车辆年款、市场、配置用实车日志确认 frame 与 signal 之前,不得将新信号纳入 canonical 状态;分发时须保留上游 MIT 授权通知。文中所有 ID、位定义与换算均来自上述公开文件,未经独立实车验证,不同年款与市场可能存在差异,涉及安全相关用途时仅作参考。

    更新记录

    • 2026-10-14 初稿

  • sygnal_dbc 前缀契约:cb_niro_dcan 不是原厂帧

    结论:sygnal_dbc 最容易被误读的一点是目录名叫 niro。归档说明明确指出:cb_niro_dcan/ 里的四个单报文文件描述的是 Sygnal 项目自己的 UserApplication 到 MCM 接口,其 CAN ID 与位布局不能被假定为 Kia Niro 的原厂诊断帧。而真正属于 Hyundai/Kia 整车定义的是另一个文件——140 条报文、1,301 个信号的 hyundai_kia_generic.dbc,它同样没有标定到具体年款。

    包结构与前缀规则

    这个仓库的做法是把每个子系统目录都做成一个独立的 ament_cmake 包,用 dbc_gen_cpp 从目录里的 .dbc 生成并导出 C/C++ 报文类型。七个目录对应七个包,每个包有固定的库前缀。

    目录 包名 库前缀
    mcm/ dbc_sygnal_mcm mcm_
    io/ dbc_sygnal_io io_
    cb/ dbc_sygnal_cb cb_
    cb_niro_dcan/ dbc_sygnal_cb_niro_dcan cb_niro_dcan_
    hpo/ dbc_sygnal_hpo hpo_
    vehicles/ dbc_sygnal_vehicles vehicles_
    sygnal_dbc/ sygnal_dbc 伞形包,无前缀

    命名规则是「<前缀>_<dbc 文件名主干,小写>」,并且这一串字符串同时是库名、C++ 命名空间、C 符号前缀与头文件目录。例如 mcm/Control.dbc 产出库 mcm_control、头文件 mcm_control/mcm_control.h 与 .hpp、命名空间 mcm_control、C 符号 mcm_control_*。

    C 用法的关键是:这些库以命名空间化的 imported target 导出,写作 dbc_sygnal_mcm::mcm_control。跨子系统同名的 DBC 不会冲突,因为包名已经把作用域隔开了。

    为什么必须有前缀

    前缀不是洁癖,而是被 colcon 与链接器逼出来的。有六个文件名在 cb/、hpo/、io/、mcm/ 四个子系统中同时存在:Control.dbc、Heartbeat.dbc、Identify.dbc、Configuration.dbc、Error.dbc、Commissioning.dbc。

    若按主干直接命名 后果
    四个库都叫 Control 同时链接其中任意两个即出现重复符号错误
    C 符号均为 control_* 静态链接阶段冲突,且无法按子系统区分版本
    头文件都装到 include/Control/Control.hpp 安装阶段互相覆盖,包含路径失去区分度

    还有一个目录结构的细节值得记住:cb_niro_dcan/ 是 cb/ 的兄弟目录,而不是 cb/niro_dcan/ 子目录。原因是 colcon 不会进入一个它已经识别为包的目录的子目录。但在安装产物里,database 树仍然把它摆回 cb/niro_dcan/ 的位置——也就是说源码布局与安装布局故意不一致,这是构建系统约束的结果,不是笔误。

    新增一份 DBC 不需要改 CMake

    每个包的 CMakeLists.txt 都只是一个薄壳,真正干活的是共享的 cmake/dbc_package.cmake 里的 dbc_package() 函数:它 glob 目录里的每一个 *.dbc,为每个文件生成一个导出库。因此新增一份 DBC 只需把文件丢进目录,无需改任何构建脚本。

    需要跑到原始文件时,find_package(sygnal_dbc) 会把 SYGNAL_DBC_DIR 指向 <install-prefix>/share/sygnal_dbc/database,并保留 <子系统>/<名称>.dbc 的原始布局;每个子系统包也会把自己的 DBC 装到 share/<包名>/database 下。要用哪一层,取决于你是想按子系统引用还是想按整车打包。

    向后兼容也做得干净:以前这个包会编译出一个名为 sygnal_dbc 的聚合库,并把头文件安装成 sygnal_dbc/<前缀>_<名称>.h。拆分之后两种方式都还能用——聚合库变成一个链接了所有生成库的 INTERFACE 库,转发头文件位于 include/sygnal_dbc/<库名>.h。关键在于旧的构建本来就给 cantools 传 --database-name <前缀>_<名称>,正好等于新的库名,因此 C 符号完全没变,老代码无需改动。新代码则应包含 "<库名>/<库名>.hpp",直接链接 dbc_sygnal_<子系统>::<库名>。

    两个必须核对的事实点

    第一,cb_niro_dcan 的四个文件——batterySOC.dbc、door_seatbelt_state.dbc、dtc.dbc、tpms.dbc——每个只有一条报文,合起来描述的是 SOC、车门与安全带状态、DTC 状态与胎压。它们是工程接口定义,不是车型 niro 的诊断帧;把它当作 Kia Niro 的原厂数据去对接,方向一开始就错了。

    第二,hyundai_kia_generic.dbc 虽然有 140 条报文、1,301 个信号,但它的问题恰恰藏在规模里。归档对比发现,这份文件相对于一份较早的 OpenDBC 派生副本修改或移除了多条报文与信号布局;而仓库既没有固定上游修订版,也不解释每一处改动,更没有说明对应的车型年款,也不提供匹配的抓包数据。这五个 Git blob 在归档收录时都不在已有存档里,Niro 那些文件还保留着原始的 CRLF 行尾。

    结论很直接:Apache-2.0 许可对仓库代码成立,但整车数据的来源与权利链并没有被记录下来。若要把这份 140 报文的文件用在项目里,需要先回溯原始许可链,并用真实抓包做车型适配验证——规模大不等于证据强。

    常见问题

    cb_niro_dcan 里的四个文件是 Kia Niro 的原厂 CAN 定义吗?

    不是。归档说明明确写道,这四个单报文文件描述的是 Sygnal 项目中 UserApplication 到 MCM 的接口,涵盖电池 SOC、车门与安全带状态、DTC 状态与胎压;其 CAN ID 与位布局不能被假定为工厂 Kia Niro 的诊断帧。

    为什么库名必须带子系统前缀?

    因为文件名在多个子系统里重复。Control、Heartbeat、Identify、Configuration、Error、Commissioning 六个文件名在 cb、hpo、io、mcm 中都存在,按主干命名会产生四个同名库、四份同名 control_* 符号与四条相同的安装路径,同时链接其中两个即报重复符号错误。

    新增一份 DBC 需要改 CMakeLists 吗?

    不需要。每个包的 CMakeLists 只是薄壳,实际调用共享的 cmake/dbc_package.cmake 里的 dbc_package() 函数,该函数 glob 目录内的所有 dbc 文件并为每个文件生成一个导出库。把新文件放进目录即可。

    hyundai_kia_generic.dbc 有 140 报文,能直接用吗?

    不建议直接用。归档对比发现它修改或移除了多条报文与信号布局,而仓库既没有固定上游修订版,也没有解释改动、标注车型年款或提供匹配的抓包数据。使用前需回溯 OpenDBC 的许可链并用真实抓包验证车型适配。规模大不等于证据充分。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/polymathrobotics-sygnal-niro/sygnal_dbc/README.md(七个子系统与七个 ament_cmake 包及其库前缀、dbc_package() 与 cmake/dbc_package.cmake 的 glob 机制、mcm/Control.dbc 到 mcm_control 的命名规则、同名文件在四个子系统中重复导致的重复符号问题、cb_niro_dcan 作为兄弟目录的 colcon 原因、命名空间化 imported target、向后兼容的 INTERFACE 库与转发头文件、SYGNAL_DBC_DIR 与安装布局)
    • 项目 01 —— public-can-dbc-datasets/additional/polymathrobotics-sygnal-niro/SOURCE.md(仓库与快照 commit、采集日期 2026-10-04、四个 Niro 接口文件的性质与「不得假定为原厂帧」的断言、140 报文 1,301 信号的 hyundai_kia_generic.dbc 及其与 OpenDBC 派生副本的差异、五个 blob 的 sha 记录、Apache-2.0 保留与整车数据权利链未记录)

    免责声明

    本文所述包结构、命名规则与文件规模均来自公开开源仓库的说明与归档文件,未经实车独立验证,也不代表任何车辆制造商的官方数据。涉及车辆定义的文件并未标注适配年款,也无匹配抓包可供核验。涉及行车安全的功能请以实际测量与官方资料为准。

    更新记录

    • 2026-10-14 初稿

  • Alfa Giulia 的 177 行 PID:header 错了会触发防盗

    结论:这份针对 Alfa Romeo Giulia 2.2 JTDm(MY2016)柴油版的 PID 表共 177 行、覆盖 8 个 header,含金量很高但带着一条硬性安全告警:如果车上装的那块直连 CAN 适配板启用了防盗功能,绝对不要用 header 为 DAC7F1 的轮胎 PID,它会触发防盗锁止并让车熄火。使用顺序必须是先看 header,再看公式。

    八个 header 的分工

    命令之前要先发 header,它的作用是选定要对话的 ECU。177 行按 header 的分布极不均衡,这个分布本身就是本表性质的说明。

    Header 行数 性质 代表 PID
    DA10F1 129 厂商自定义,涵盖发动机、DPF、喷油、启动停止 221003 冷却液温度 (((A*256)+B)*0.02)-40 摄氏度
    DABAF1 15 直连 CAN 适配板专用地址 2200000000FC 发动机转速 ((B*256+C) 与 65534 按位与) 右移 2
    DB33F1 11 标准 OBD-II 通道 010C 转速 ((256*A)+B)/4、010D 车速 A km/h
    DAC7F1 8 轮胎压力与温度,带安全告警 2240B1 至 2240B4 四轮压力 ((A*256)+B)/1000 bar
    DA40F1 7 IBS 蓄电池传感器与钥匙位置 221005 同帧多字段,含 SoC(B 字节)与温度(G 减 40)
    DA18F1 5 变速箱相关 221018 扭矩 ((A*256+B)-500) Nm
    DA2AF1 1 转向角 22083C ((SIGNED(A)*256)+B)/16 度
    DA60F1 1 仪表亮度 220104 A

    这张表立刻能读出两件事。第一,真正属于标准 OBD-II 的只有 DB33F1 那 11 行,其余 166 行全是厂商或改装板自定义通道——也就是说,指望一个通用 OBD App 自动识别是不现实的,必须手工导入自定义 PID。

    第二,DA10F1 独占 129 行,而这个 header 有一个非常具体的行为特征:它的响应需要较长时间。作者给出的应对办法很聪明——同一个仪表页里如果混放 DA10F1 的传感器和其他传感器,前者会因为来不及应答而完全不显示。正确做法是把所有 DA10F1 的传感器集中放在同一个页面、与其他页面隔离,因为 App 只轮询当前仪表页上的传感器。

    十五条「?」行与重复 PID

    作者给数据加的自证标注是这张表最值得尊敬的地方:长描述以 ? 开头的行,表示他在自己的车上无法验证。177 行里有 15 行属于这一类,其中包括 MY20 才有的几个电池 PID(如 2240B2 电池 SoH、222B0E 电池电流)与几条 Hall 值(例如 223888 时间格式、2202000001F7 变速箱温度)。把这些行直接搬进自己的仪表配置,等于替作者承担未验证的风险。

    现象 实例 该怎么处理
    长描述以 ? 开头 ? 前缀共 15 行,作者自述无法在车上验证 仅在确认车型年款后作为候选,不进告警逻辑
    同一 PID 重复出现且单位不同 012F 燃油液位同时给出百分比 A*100/255 与升 A*53/255 二选一,不要同时上仪表否则读数冲突
    同一 PID 重复出现且公式不同 里程 22380E 一处为三字节除以 10,另一处为「总里程减去该值」 按车辆年款选定一条,交叉验证后再用
    同一 PID 原样重复 DPF 再生次数 2218A4 出现两次,公式相同 导入前去重,避免同名重复传感器
    仅在特定年款可用 MY20 系列电池 PID 标注 (MY20) MY2016 柴油车不适用,勿据此判断电池状态

    还有一个平台差异必须写在前面:这些参数全部在一台 2.2 柴油 Giulia 上测试。作者明确说,其中一部分在 2.0 与 2.9 汽油版上不适用也不工作;反过来,论坛上流传的汽油版 PID 在他车上也不工作、未经他测试。跨动力总成使用这份表之前,请先假设它不成立。

    两条硬约束:安全与轮询预算

    第一条是安全。为了绕过 ELM327 拿不到的数据,作者使用了一块廉价的 CAN 适配板,并为它定义了专用 header DABAF1;长描述里标注为直连板专属的 15 行就是走这条通道的。而紧跟着有一条全大写的告警:如果车上的这块板启用了防盗功能,不要使用 header 为 DAC7F1 的轮胎 PID,它会触发防盗并让车熄火。这一条属于操作红线,不是免责声明。

    第二条是轮询预算。每个传感器都有一个 priority 字段:1 表示每个仪表刷新循环都请求一次,1/50 表示每 50 个循环才请求一次。作者的建议是按信号的变化速度分配——涡轮压力变化快、给高优先级,冷却液温度变化慢、给低优先级,把这个页面挤出来给快变量。这个字段是传感器自身的属性,在所有使用它的仪表页生效,因此改一处会影响到其他页面。

    常见问题

    为什么我的 App 用这份表什么都读不出来?

    先看 header 混放问题。177 行里 129 行属于 DA10F1,而这个 header 的响应较慢:同一仪表页若混放 DA10F1 与其他 header 的传感器,DA10F1 会来不及应答而不显示。作者的建议是把所有 DA10F1 传感器集中在同一页并与其他页隔离。

    轮胎 PID 到底能不能用?

    看车上那块直连 CAN 板是否启用了防盗:如果启用,绝对不要用 header 为 DAC7F1 的 8 行轮胎 PID,它会触发防盗锁止并使车辆熄火。没有装该板或未启用防盗时才可尝试,且同样建议你先确认车辆年款。

    标着 ? 的 PID 是什么意思?

    作者自述:长描述以 ? 开头的 PID 是他无法在自己车上验证的条目,共 15 行,包含 MY20 系列的几个电池参数与若干未确认的 Hall 值。这类条目只能作为候选,不应写入告警或长期趋势判断。

    2.0 汽油版能不能直接套用这份表?

    不能直接套用。全部参数是在一台 2.2 JTDm 柴油 MY2016 上测试的,作者明确说明其中一部分在 2.0 与 2.9 汽油版上不适用也不工作。跨动力总成使用前应先假设不成立,逐条实车验证。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/danardi78-alfa-giulia-pids/README.md(适用车型 Giulia 2.2 JTDm MY2016、文件清单与八列字段含义、? 前缀表示无法验证、DA10F1 响应较慢的仪表页排布建议、priority 字段取值为 1 与 1/50 的含义、直连 CAN 板专用 header DABAF1 及其目的、DAC7F1 轮胎 PID 触发防盗锁止的安全告警、仅柴油版测试的适用边界)
    • 项目 01 —— public-can-dbc-datasets/additional/danardi78-alfa-giulia-pids/custompids.csv(177 行 PID 的 header、命令 ID、公式、单位与量程;用于核对 DA10F1 129 行、DABAF1 15 行、DB33F1 11 行、DAC7F1 8 行等的分布与 15 行 ? 标注)

    免责声明

    本文所述 PID、header 与换算公式均来自公开开源资料分享,属第三方逆向工程产物,未经独立实车验证,也不代表车辆制造商的官方数据。文中前述的安全告警(启用了防盗功能时禁用 DAC7F1 轮胎 PID)为原作者明确声明,实际操作前必须确认车辆配置。不同年款、市场与动力总成存在差异,涉及行车安全的判断请以实际测量与官方资料为准。

    更新记录

    • 2026-10-14 初稿