菲亚特 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 初稿

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注