结论:Talaria 电动越野车的车载 CAN 是一条 250 kbit/s、11 位标准 ID、15 个报文 ID、约 92 帧每秒的总线,用一颗 3.3 V 收发器挂在 ESP32-S3 的 TWAI 控制器上即可只读取数。真正有复用价值的不是那张 14 项信号表,而是表里被明确证伪的四处:0x103[0] 不是电量、0x202[6:8] 不是里程、0x490 不是温度也不是单字段、节流需求偏移随固件而变。把这几条排除后再取数,才不会把「看起来像」当成「就是」。
总线前提与接入方式
这条总线在电机控制器处即可挂到 CAN_H 与 CAN_L,硬件侧只需要一个 3.3 V 的 SN65HVD230 收发器:发送脚接 GPIO7、接收脚接 GPIO8,直连而非交叉——这一点与同一块板上的 GPS 串口不同,后者是交叉的。CAN 外设用的是 ESP32-S3 自带的 TWAI 控制器,外部模块只承担物理层。
两个电气细节必须在上电前处理。第一,模块板上那个标着 121 的 120 欧终端电阻要拆掉:车辆总线两端已经各自终端,跨 CAN_H/CAN_L 量到的是 60 欧,再并一个电阻会掉到 40 欧,波形裕量直接被吃掉。第二,一旦 CAN 双线接入,设备的地就通过降压模块的负极与车辆共地,此时再插 USB 会把车辆电池负极接到保护地,同时 USB 的 5 V 与降压模块的 5 V 在 VUSB 上相撞;拔掉车端连接器可以同时隔离这两个风险,遥测数据改走无线链路读取。
总线默认是只读取模式:收发器从不驱动总线,甚至不应答,因此即便波特率猜错也不会扰动车辆。这一点是整套方案能从「只读」安全扩展到「可写」的前提。
| 参数 | 取值 | 备注 |
|---|---|---|
| 波特率 | 250 kbit/s | 扫描子命令会遍历波特率与标准/扩展 ID 组合 |
| ID 类型 | 11 位标准 ID | 与整车厂常见的 29 位扩展 ID 不同 |
| 总线报文 ID 数 | 15 | 固件当前只解析其中 8 个 |
| 帧率 | 约 92 帧/秒 | 全总线合计 |
| 终端电阻 | 60 欧(熄火状态下测量) | 读到 120 欧说明只挂到了单端 |
| 接地 | 无需单独地线 | 通过降压模块负极已与车辆共地 |
| DBC 规模 | 9 条报文、26 条信号行 | 每条信号的验证过程写在 CM_ 注释里 |
已解码信号与字节定义
下面这张表是这份研究的核心产出。所有偏移都按小端处理,物理量的缩放因子在最后一列。值得注意的是,电芯最高/最低电压与序号共用同一帧的不同字节组,序号分别落在字节 4 与字节 5。
| 信号 | 帧 ID | 字节与位 | 缩放 |
|---|---|---|---|
| 车速 | 0x303 |
字节 0–1,小端 | 0.1 km/h |
| 电机转速 | 0x203 |
字节 0–1,小端 | 1 rpm |
| 功率 | 0x203 |
字节 2–3,小端 | 1 W |
| 电流 | 0x302 |
字节 4–5,小端 | 0.1 A |
| 电池包电压 | 0x101 |
字节 0–1,小端 | 0.1 V |
| 电量百分比 | 0x401 |
字节 0 | 1 % |
| 最高电芯电压与序号 | 0x201 |
字节 0–1 小端,序号在字节 4 | 1 mV |
| 最低电芯电压与序号 | 0x201 |
字节 2–3 小端,序号在字节 5 | 1 mV |
| 边撑 | 0x202 |
字节 0 第 7 位 | 1 为放下 |
| 骑行模式 | 0x202 |
字节 0 第 5:4 位 | 1 节能、2 运动 |
| 动能回收等级 | 0x490 |
字节 0 第 2:0 位 | 1 至 4 |
| 骑行模式(仪表指令) | 0x490 |
字节 0 第 5:3 位 | 1 节能、2 运动 |
| 里程 | 0x402 |
字节 2–3,小端 | 1 km |
| 转把需求 | 0x202 |
字节 3–4,小端 | 单位未确认 |
交叉验证给了两个可信锚点:车速与转速在两次独立骑行中保持 5.887 的固定比值,相关系数 0.999,对车速积分也能还原出合理的骑行距离;最高与最低电芯电压的平均值乘以 16 能复现电池包电压到 0.02 V 以内,这坐实了 16 串的电池包结构。这两条把「解析对了」从感觉变成了可检验的判据。
遥测包里的 CAN 块与门控位
解码后的车辆数据占遥测包第 50 至 69 字节,配套一个状态字节:第 0 位表示总线存活,第 1 位是边撑,第 3:2 位是骑行模式,第 6:4 位是回收等级。规则只有一条但必须遵守——超过 2 秒没有收到任何帧时,整个字节块会被清零、存活位同时拉低,因此判空要门控在存活位上,而不能相信「速度为零」。否则一辆停着的车和一根拔掉的线在数据上完全一样。里程字段在第 88 字节,取的就是 0x402[2:4],读到 0 表示还没见过该帧。
四处已被证伪的字段
这份研究最值得照搬的不是结论,而是它把「曾经以为」逐条推翻并留下判据的过程。四条错误里前两条是典型的形状误导,第三条是位域切分错误,第四条是跨设备外推错误。
| 被误认的字段 | 为什么看起来像 | 证伪判据 | 正确取法 |
|---|---|---|---|
0x103[0] 当电量 |
数值形态像百分比 | 实际电量在别处变化时它恒为 100,几乎可以确定是健康度 | 取 0x401 字节 0 |
0x202[6:8] 当里程 |
单调递增,形态极像里程计 | 与车速的相关系数为负 0.0005,两次骑行的每公里计数相差 34% | 取 0x402[2:4],整公里 |
0x490[0] 当温度或单字段 |
整字节与模式的相关系数 0.99,看起来整字节都是模式 | 第 5:3 位是模式、第 2:0 位是回收等级;节能模式下第 3 位被置起,回收 1 会读成 0x09 而非 0x01 |
掩 3 位而不是 4 位 |
| 转把需求偏移固定 | 同车型同帧 ID,默认偏移可复用 | 本车在 0x202[3:5],参考日志里那辆车在 0x202[2:4] 且根本不跟随转把 |
换车必须重新验证偏移 |
里程的发现过程有一条通用经验值得单独记:这份研究曾长期写着「总线上没有找到里程计」,而这个结论是从固件捕获的 8 个帧里得出的,0x402 恰恰属于没人解码的那 7 个。后来是照着车辆仪表自己显示的 400 km 去全总线捕获里找这个数,0x402[2:4] 正好读出 400。由于总线上存在 1200 这类整常数(同时出现在 0x101[4:6] 与 0x302[6:8]),单次对上整数只是提示而非证明,因此它被明确标注为待验证——需要一次实际骑行看它自增。
从只读到可控:0x490 是命令不是回声
0x490 长期被当作控制器的回声,直到一次按键对比实验才被推翻:连续五次按键里,0x490[0] 每次都先动,0x202 在 20 至 27 毫秒之后才跟着变,同时带上新的模式位与新的需求下限(运动 1100、节能 750)。在仪表持续以 5 Hz 发运动模式的同时注入节能,控制器在整个注入期间被钉在需求 750 上。结论是仪表与控制器是两个不同节点,控制器服从总线上最近一次 0x490,而且从不锁存。
这就决定了「覆盖」不能以命令的方式实现,只能以持续争论的方式实现:仪表下一帧在 200 毫秒后就会把单次发送的内容推翻,所以只要覆盖还生效,就必须应答仪表发出的每一个 0x490。实测差距很明显——自由运行在 20 Hz 注入会输掉 24% 的帧,而收到即回则在控制器自己的 297 帧里守住了 297 帧。决定成败的是延迟,不是发送频率。
| 机制 | 行为 | 后果 |
|---|---|---|
| 锁存 | 控制器不锁存,服从最近一帧 | 覆盖必须持续应答,发一次无效 |
| 注入方式 | 收到即回,守住 297/297;自由运行 20 Hz 丢失 24% | 延迟是机制,频率不是 |
| 释放路径 | 无线断连、CAN 超时、车把按键任一触发 | 100 毫秒内回到仪表控制 |
| 可验证性 | 模式可见,回收等级无法验证 | 回收不带动总线上任何其他量,功率与电流都是无符号的 |
| 仪表显示 | 仪表不监听总线 | 覆盖期间仪表显示与实车状态真实不一致 |
| 回收限制 | 电量高于约 90% 时车辆自行抑制 | 指令发出但正确地不产生效果 |
另外,喇叭与灯光根本不上总线,它们是车把开关直接控制的 12 V 回路;刹车拉杆在部分车上有信号,改装的无传感器拉杆什么也发不出。这些边界决定了这套数据能覆盖到什么程度。
嗅探工具与验证命令
逆向过程被固化成四个子命令,全部跑在主机侧,配合一个串口转 CAN 适配器工作。 scan 负责扫波特率与 ID 类型组合,如果到处都是零帧,最常见的原因是 CAN_H 与 CAN_L 接反——无害,换过来即可;sniff 给出实时表格,包含解码后的物理量、每个 ID 的速率、逐字节变化图;events 先自学哪些字节会自行漂移,然后只打印真正的变化,使用时一次只操作一个控件,就能定位该控件落在哪个字节;log 落盘为 .asc、.blf 或 .csv 供离线分析。
| 子命令 | 用途 | 典型判据 |
|---|---|---|
scan |
扫描波特率与标准/扩展 ID | 全组合零帧通常是 CAN_H/CAN_L 反接 |
sniff |
实时表格:物理量、每 ID 速率、逐字节变化图 | 用于确认波特率与帧清单 |
events |
过滤自发漂移,只打印真实变化 | 一次只动一个控件 |
log |
录制 .asc/.blf/.csv |
供离线回归与跨骑行比对 |
配套环境搭建只需两条命令:先建虚拟环境并安装依赖,再用 250000 的波特率参数调用对应子命令,串口设备名按实际枚举结果传入。整个链路不需要改动车辆任何部件,这也是只读取数能长期稳定运行的底气。除了这套主机侧工具,固件侧还有一个专门的 CAN 探测程序,它把解码后的仪表直接输出到屏幕与无线链路上——之所以刻意走无线,是因为车辆与 USB 主机任何时候都不能同时连接。
最后补一条容易被忽略的经验:总线上的 15 个 ID 与实际解析的 8 个之间的落差,本身就是最大的风险来源。任何「总线上没有某个信号」的结论,只有在完整捕获全部 ID 之后才成立;而车辆仪表已经显示的数值,是验证解码结果最便宜的基准。
常见问题
这条总线能直接拿来读取车辆数据吗?
可以,但必须只读取:收发器不驱动总线也不应答,波特率猜错也不会扰动车辆。前提是先拆掉收发器模块上的 120 欧终端电阻,否则总线的 60 欧会变成 40 欧。另外不要同时接 USB 与车辆,两者会在 VUSB 上相撞并把车辆地接到保护地。
为什么我读到的电量一直是 100?
因为取的是 0x103 字节 0,那个字段在真实电量变化时保持不变,几乎可以确定是电池健康度。真实的电量百分比在 0x401 的字节 0,缩放为 1%。
里程到底在哪个帧?
在 0x402 的字节 2 至 3,小端,单位 1 公里。曾经被误认为里程的 0x202[6:8] 虽然单调递增,但与车速相关系数只有负 0.0005,两次骑行的每公里计数相差 34%,已被排除。由于总线上存在 1200 这类整常数,该结论仍标注为待一次自增骑行验证。
能不能通过总线改骑行模式?
可以,但不能用「发一次命令」的思路。控制器服从最近一次 0x490 且不锁存,仪表每 200 毫秒就会覆盖一次,因此必须持续应答仪表的每一帧;实测收到即回守住 297/297,自由运行 20 Hz 会丢失 24%。同时要注意仪表不监听总线,覆盖期间仪表显示与实车真实状态不一致,而回收等级发出后无法从总线验证。
换一辆同型号车能直接复用这套偏移吗?
不能。转把需求在本车位于 0x202[3:5],在参考日志那辆车上位于 0x202[2:4] 且完全不跟随转把。上游明确提示字节偏移随固件版本变化,换车必须重新验证,且这套解码本身是以另一份公开的 Talaria CAN 日志项目为地基的派生研究,并非独立来源。
延伸阅读
- 车电接入:为什么 ESP32 的 TWAI 不等于 OBD 接口 —— 同一颗控制器的电气与协议前提
- Indian Springfield 2017:J1939 摩托车 CAN 档案 —— 摩托车总线的另一套体系
- LiveWire S2 Del Mar:60 报文副总线与 9 个 UDS 模块 —— 电动摩托的多节点结构对照
- KTM TBI mapswitch:31 条 BO_ 里只有 4 条真实帧 —— 同类「看起来像实则不是」的排查思路
- 车型数据库 —— 更多车型 CAN 档案
参考资料
- 项目 01 ——
public-can-dbc-datasets/additional/kbirand-talaria-tripper/README.md(总线参数、硬件接入、14 项解码信号表、四个字段证伪过程与覆盖机制实测) - 项目 01 ——
public-can-dbc-datasets/additional/kbirand-talaria-tripper/SOURCE.md(DBC 的 9 报文 26 信号行规模、里程字段的待验证声明、派生来源与权利状态说明)
免责声明
本文所述的总线参数与信号定义均为社区研究报告产物,不代表车辆制造商的官方数据,文中数字均来自上述公开仓库的说明文件,未经独立实车验证。上游明确指出该解码是以另一份公开的骑行日志为地基的派生研究,适用车型、固件版本与其他车辆均未确立,字节偏移随固件变化,换车必须重新验证。该仓库快照中未发现任何许可证或逐文件再分发授权,仅可作私有离线研究副本,再分发或集成前须先行确认权利。涉及写入总线的操作请仅在封闭场地、由具备资质的人员执行,并以官方资料与实际测量为准。
更新记录
- 2026-10-15 初稿
发表回复