标签: CAN总线

  • panda safety 测试链:libsafety、回放与变异的证据边界

    结论:panda safety 的测试链要分四层证据看——本机逻辑库、离线回放、板级验证、车辆验证,它们不能互相替代。源文档反复强调:默认启用的 ALLOW_DEBUG 测试库、test.sh 要求的 100% 行覆盖率、以及回放返回的布尔通过,都不等于目标固件、线束或实车安全认证。make_CANPacket() 得到的只是 DBC 构帧后的 CFFI CANPacket_t,不是 panda USB/SPI、FDCAN 或 ECU 真实发送回执。

    一、本机库与通用断言

    入口 作用与限制
    _build_libsafety()、__getattr__() 首次取 libsafety 时将测试 C 翻译单元编译为临时共享库;默认启用 ALLOW_DEBUG,release=True 才不加该宏。正常模式加 UBSan,覆盖率模式改用 gcov flags。
    make_CANPacket()、CANPackerSafety.make_can_msg_safety() DBC 构帧后转成 CFFI CANPacket_t,保留地址、bus、长度码与数据;不是 panda USB/SPI、FDCAN 或 ECU 真实发送回执。
    init_tests() 测试库可人工改时钟、使能和测量窗口,并设置 safety_mode_cnt=2 等测试专用状态,并不模拟真实 MCU 启动。
    test_spam_can_buses()、test_fwd_hook() 对已列扫描地址、总线及测试用长度检查 TX/转发;不是 29 位地址和 0~64 字节载荷的全穷举。
    test_safety_tick()、test_relay_malfunction() 分别验证缺失关键 RX 时退出与继电器故障否决;仍是本机状态模拟。

    库编译使用 -Wall -Wextra -Werror -nostdlib -fno-builtin;common.py 用继承式 mixin 组合地址扫描、踏板/巡航、转向扭矩、角度、曲率、纵向和转发断言。SCANNED_ADDRS 扫全 11 位地址,但仅取少量 29 位诊断区间,且基础 spam 测试固定构造 8 字节零载荷。test_tx_hook_on_wrong_safety_mode() 读取其他测试类声明的 TX 列表并有多组车型/地址重叠例外,它是跨模式回归检查,不是形式化证明。另一个关键点:独立 test_release_build.py 只确认两种测试库能编译,没有对 release 版本逐车型跑相同 TX/RX 行为矩阵。

    还要注意测试库与真实固件的差异:libsafety/safety.c 内嵌仓库的 can.h、safety.h、ignition.h,以全局 timer_cnt 替代 MCU 微秒计时器,并暴露测试专用 getter/setter。模式切换仍走真实 safety 头文件,但总线驱动、线束继电器、电源/心跳和芯片时钟不在测试库内;init_tests() 在 set_safety_hooks() 之后另改测试状态,例如跳过初期继电器忽略窗口,故它是逻辑钩子验证而不是板级启动验证。

    二、覆盖率与变异测试的解释边界

    机制 给出的结论 不能被读成什么
    test.sh + UBSan 先跑 UBSan 单测,再在 SAFETY_COVERAGE=1 下重跑。 行覆盖率(排除 libsafety 包装器后 100%)不等于分支、状态序列、真实总线或发布固件覆盖。
    MISRA(test_misra.sh) 用 cppcheck 执行静态检查。 不能与动态 safety 断言合并为同一种证据。
    enumerate_sites()、build_priority_tests()、eval_mutant() 对预处理后的 safety C 生成变异点,按车型文件或共享核心测试选用例,统计杀死、存活或基础设施错误。 modes/ 下默认只取同名 test_<mode>.py;共享模式头文件若无同名测试,所选列表可能为空,不能据「该文件变异全部存活」直接断言无测试能覆盖它。

    变异统计里还有两个陷阱:worker 异常或进程池崩溃在结果汇总中被记为 killed,而另一路 Python 异常记为 infra_error——查看变异得分时必须把崩溃原因从有效测试断言失败中分离;脚本还有三条已知存活变异例外,不能把返回码零解释为零存活点。

    三、回放的证据边界

    replay_drive() 从日志 carParams.safetyConfigs[-1] 默认取最后一个模式,可覆盖参数;package_can_msg() 将 src % 4 映射为本地 bus。它按 logMonoTime 排序,给安全库设置软件时钟;在离片段首尾各超过 1 秒的区间,对每条 CAN 消息调用 safety_tick(),而板端该函数按 1 Hz 调用。回放成功条件是「控制允许时无 TX 被拒、无 RX 无效、没有区间内的 RX 健康失败」;控制未允许时被拒的 TX 仍计数但不使返回值失败。没有 can/sendcan 消息时会在首尾索引处失败,不是空路段的安全通过证明。

    init_segment() 用首个识别到的转向 sendcan 帧人工设 controls_allowed、上轮目标及测量值,然后断言该帧 TX 可过。这样可降低片段开头状态缺失导致的误报,但也意味着回放不完整验证实际巡航使能沿和最初几帧的真实状态。测试前应记录路段是否从设备启动/控制开始,不能只看最终布尔结果。

    四、自制硬件的验收证据链

    1. 本机逻辑:按目标安全模式分别运行 development/release 构建和关键 RX/TX 单测,保存精确源提交、编译宏、测试选择及失败列表。
    2. 离线时序:用目标车型路段回放,记录首帧预置、源 bus 映射、RX 健康与「控制未允许时拒帧」;回放不能替代无车故障注入。
    3. 板级验证:确认 MCU 固件签名/模式参数读回、实际 FDCAN 发送回执、继电器方向、心跳失联和异常报文抑制,不用 CFFI 测试库结果替代。
    4. 车辆验证:在合法合规的受控条件下单独确认 ECU 接受、原车 AEB/制动保留、驾驶员覆盖与恢复;插件系统不得把测试报告布尔值当作实时控制许可。

    本轮未运行完整安全测试,也没有目标硬件/车辆证据;上述内容是测试框架能力与缺口的源码索引。

    常见问题

    默认测试通过能否当作发布固件权限证明?

    不能。测试库默认启用 ALLOW_DEBUG,日常单测可覆盖仅调试注册的模式和纵向参数;test_release_build.py 只确认两种测试库能编译,没有对 release 版本逐车型跑相同 TX/RX 行为矩阵。

    100% 行覆盖率说明什么?

    只说明在 SAFETY_COVERAGE=1、排除 libsafety 包装器后行覆盖达到 100%,不等于分支、状态序列、真实总线或发布固件覆盖。MISRA 的 cppcheck 检查是另一种证据,不能与之合并。

    回放成功是否等于通过了安全验证?

    不等于。回放要求「控制允许时无 TX 被拒、无 RX 无效、无区间 RX 健康失败」,但控制未允许时被拒的 TX 仍计数而不使返回值失败;init_segment() 还人工预置首个转向帧状态,故不完整验证实际使能沿与最初几帧。

    变异评分零存活就代表没有缺口吗?

    不代表。共享模式头文件若无同名测试文件,所选用例列表可能为空;worker 异常或进程池崩溃会被汇总记为 killed,脚本还有三条已知存活变异例外,因此不能把返回码零解释为零存活点。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/SAFETY_TEST_HARNESS_REPLAY_EVIDENCE_DEEP_DIVE.md(取用了本机库与通用断言、覆盖率与变异边界、回放证据边界、硬件验收证据链)。

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

    更新记录

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

  • 实时车辆诊断 CLI:ECU 地址、VIN、固件与通信控制边界

    结论:这四个实时诊断 CLI 不是只读日志分析器:它们都经 sendcan 向车辆发送诊断帧,其中 disable_ecu.py 会请求改变 ECU 通信状态。判断结果是「脚本打印」还是「目标 ECU 真的接受」,是两条不同层级的问题——发布成功只表示请求进入了发送链,能否真正上总线还取决于 pandad 与 panda 固件状态。多个工具还会读写 Params、切换 OBD 复用,且没有 finally 恢复。固定快照基线为 c8fb906,本文未执行脚本、连接车辆或发送 CAN。

    共同调用链

    四个 CLI 都调用 can_comm_callbacks():从 can 读取 CanData,把请求封装为 sendcan Event。后者被 can_send_thread() 接收并交给 panda;能否真正上总线还取决于 pandad 与 panda 固件状态。不能把「脚本打印结果」或「发布成功」直接等同于目标 ECU 接收成功。

    入口 请求与输出 本机状态变化
    ecu_addrs.py 默认 bus 1、超时 1 秒;生成 256 个 11-bit 和 256 个 29-bit 候选地址,批量发送 tester-present;仅打印响应地址及可选子地址。 删除 FirmwareQueryDone,IsOffroad 写真、等 0.2 秒再写假;依 --no-obd 切换 OBD 复用。
    vin.py 默认 bus 1、单次超时 0.1 秒、最多 5 轮;尝试该总线允许的 UDS / OBD 或品牌特例,打印响应地址、bus 和 VIN。 脚本本身不写 Params、不切 OBD 复用;仍向 sendcan 发诊断请求。
    fw_versions.py 先查 bus 0/1 的 VIN,再查品牌固件,输出原始版本字节及可能车型;--brand 只缩小固件查询范围。 同样删除 / 改写 Params;VIN 前先请求 OBD 复用,固件请求期间可逐请求切换。
    disable_ecu.py 固定在 bus 1 向 Honda Bosch 雷达地址请求扩展会话,再发送通信控制请求;打印布尔值。 不写 Params、不切 OBD 复用;会尝试改变目标 ECU 的收发状态,且没有恢复调用。

    OBD 复用与状态位

    obd_callback() 在目标模式与 Params 当前值不同时,删除 ObdMultiplexingChanged、写 ObdMultiplexingEnabled,然后无独立期限地阻塞等待确认;pandad 的 updateMultiplexingMode() 在实际切换后写确认。ECU 地址与固件脚本没有恢复先前 Params / OBD 状态的路径。

    FirmwareQueryDone 被删除后,pandad 的 fetchCarParams() 会拒绝继续取得车辆参数,直到其他流程重新置位;常规 Car.__init__() 会在车型识别后置位。IsOffroad 的真 / 假写入是脚本行为,不能据此断言 pandad 已同步切换安全模式——其安全模式配置使用 deviceState.started。

    工具 是否读写 Params 是否切 OBD 复用 是否恢复原状态
    ecu_addrs.py 删除 FirmwareQueryDone,改写 IsOffroad 是(--no-obd 控制) 否(无 finally)
    vin.py 否 否 不适用
    fw_versions.py 删除 / 改写同 ECU 地址脚本 是(VIN 前与固件期间) 否
    disable_ecu.py 否 否 否(改 ECU 收发状态且无恢复调用)

    失效与证据边界

    1. --scan 当前不可用。 脚本把 256 组三种地址形状放进 extra={"any": {"debug": extra}},但固件查询按品牌执行 FW_QUERY_CONFIGS[brand];当前归档没有 any 品牌配置。因此 VIN 查询和 Params / OBD 副作用已经发生后,固件地址构建阶段抛 KeyError('any');--brand 也不会消除此额外键。
    2. ECU 清单不是全量证明。 get_all_ecu_addrs() 把 TX 候选集合直接当 RX 白名单;29-bit 响应通常采用交换后的地址,可能被过滤。get_ecu_addrs() 捕获异常后返回已收集的部分集合,timeout 也不能限制阻塞式接收的整个墙钟时间。
    3. VIN 既不验证身份,也不保证隐藏。 get_vin() 对命中地址的结果做少量去填充后直接解码返回,CLI 原文打印 VIN。失败时返回 (-1, -1, "00000000000000000"),不等同于「车辆没有 VIN」;源码另有 is_valid_vin(),此 CLI 没有调用它。
    4. 固件列表可以是部分结果。 固件查询按请求配置与子地址分组,单个请求异常记录后继续;返回版本可能缺 ECU 或缺品牌。候选车型匹配给的是候选集合,不是执行许可。原始固件字节与 VIN 可能包含可识别车辆的信息。
    5. 手动禁用雷达不确认禁用成功。 通用 disable_ecu() 最多重试 10 次,先要求扩展会话的有效应答,再调用 get_data(0) 发送通信控制请求并丢弃返回字典;零超时和空的期望响应前缀不能提供可靠的正响应证据。帮助函数注释明确警告会禁用原车 AEB,脚本没有配套恢复路径。

    面向硬件与插件化的接口约束

    以下是设计建议,并非当前实现:将前三类查询工具改为只提交有界诊断任务的证据插件,sendcan 与 OBD 复用由唯一诊断代理持有。代理校验点火 / 车速、bus、地址、服务、速率和总时长,记录每次请求与局部响应;--scan 需先修复配置建模,再在隔离台架验证总线负载。通信控制应归入单独的高危能力,需要目标 ECU / 版本白名单、原车 AEB 影响评估、正响应和总线状态回读、持续保活及恢复方案。身份插件只返回带来源和时间戳的 VIN / 固件证据,不提供控制权限;执行权限仍由独立 MCU / panda safety 和车型适配门决定,不能由插件加载或候选车型自动授予。

    常见问题

    这些 CLI 会向车辆发 CAN 吗?

    会。四个工具都经 sendcan 向车辆发送诊断帧,其中 disable_ecu.py 会请求改变目标 ECU 的通信状态。它们不是只读日志分析器;「脚本打印结果」不等同于目标 ECU 接收成功。

    运行这些脚本会留下什么状态?

    ECU 地址与固件脚本会删除 FirmwareQueryDone,把 IsOffroad 写真、等 0.2 秒再写假,并切换 OBD 复用,且没有恢复先前 Params / OBD 状态的 finally。FirmwareQueryDone 被删后,pandad 会拒绝继续取得车辆参数直到重新置位。

    –scan 现在能用吗?

    不能。脚本把地址形状放进 extra={"any": ...},但固件查询按品牌执行 FW_QUERY_CONFIGS[brand],当前归档没有 any 品牌配置,固件地址构建阶段会抛 KeyError('any');--brand 也不会消除该额外键。VIN 查询和 Params / OBD 副作用已经发生。

    打印 disabled: True 就说明雷达被禁用了?

    不能这样认为。通用 disable_ecu() 丢弃查询结果,零超时与空期望响应前缀无法提供可靠的正响应证据;即使底层打印成功,也不等于已证实 ECU 停发、AEB 状态或会话保持。帮助函数注释明确警告会禁用原车 AEB。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/CAR_LIVE_DIAGNOSTIC_CLI_CONTRACT_DEEP_DIVE.md(取用了四个 CLI 的请求与副作用、失效边界与插件化接口约束分析)。

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

    更新记录

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

  • BYD Atto 3 档案:Chassis 与 Private 双总线分工

    结论:这份档案的对象是一台 2024 年款、右舵出口版的 BYD Atto 3(元 PLUS EV)。它的数据特征是双总线分工:在 P13 摄像头连接器处接入后,Chassis CAN(引脚 4/8)为 500 kbit/s 经典 CAN、8 字节帧,承载转向、车速、踏板、挡位等整车状态,读与写都在这里;Private CAN(引脚 3/7)为 CAN-FD、数据段近 2 Mbit/s,承载摄像头、前向雷达与约 72 个来源未确认的经典格式 ID。整车消息在发送前需补一个字节校验,纵向与横向命令只允许三条报文。以下所有结论仅来自这一台车,中国国内版本与其他年款可能不同。

    车辆与适用范围

    源文档明确:全部数据来自一辆车——2024 年款右舵出口版 Atto 3;并把「换车前的检查项」单列一节。以下范围只对应这一辆。

    项 内容
    车型 BYD Atto 3 / 元 PLUS EV,2024 年款,右舵出口版(VIN 世界厂商标识 LGX)
    年款 / 市场版本 2024 右舵出口版;中国国内版本与其他年款可能不同(源文档明示)
    ECU / 改装状态 P13 摄像头连接器处旁接;以红熊猫板作 CAN 接口;无原厂设备,因此无 IMU,改用 CAN 桥接
    采集跨度 源文档未给出日志时长或帧数;给出整车质量 1750 kg、轴距 2.72 m、转向比 19.8
    适用范围 仅这一台 2024 右舵出口车;换车须重新测量连接器(BYD 用过两个摄像头供应商,连接器不同)

    总线与寻址

    数据来自 P13 摄像头连接器,共 8 个腔位、6 个接线。两条 CAN_H 同为粉色、两条 CAN_L 同为紫色,源文档要求按引脚位置而非颜色识别总线。

    项 内容
    Chassis CAN 引脚 4/8;经典 CAN,500 kbit/s,8 字节帧;本系统的读与写都在此
    Private CAN 引脚 3/7;CAN-FD,数据段近 2 Mbit/s;承载摄像头、雷达与约 72 个来源未确认的经典格式 ID
    寻址 / 帧格式 整车消息为经典 11 位 ID 格式;私有总线为 FD 帧,含 32 字节与 64 字节两类
    终端 在旁接点处为 Chassis CAN 增加终端,因为接入设备会在摄像头连接器处断开总线
    供电 引脚 1 = 摄像头地,引脚 2 = IG1(受控 12V);点火状态也可从 CAN 推断

    已解码信号

    下表抽取源文档中带明确报文、缩放或位域的信号。位置与解码保留原文写法;证据一列注明来源,凡源文档标注为「未确认」的均原样保留。

    信号 位置(报文 ID / 字段) 解码 证据
    转向角 STEER_MODULE_2 0x11F / STEER_ANGLE_2 0.1 度 / LSB 源文档状态解码表
    驾驶员力矩 STEERING_TORQUE 0x1FC / DRIVER_TORQUE 0.1 Nm / LSB;用于人工接管判定,阈值 18 Nm 源文档;符号正值为左
    EPS 电机力度 0x1FC / MAIN_TORQUE 电机输出,非驾驶员输入 源文档
    EPS 状态 0x1FC 低半字节(位而非枚举) bit0 LKS_PREPARED、bit1 CRUISE_ACTIVATED、bit3 恒 1;0x318 恒 0xFF 源文档;状态 11 需 0.5 s 去抖
    车速 WHEELSPEED_CLEAN 0x1F0 16 位原始计数,0.0713 km/h 每计数 源文档
    单轮转速 WHEEL_SPEED 0x122 / WHEELSPEED_BR 14 位;bit 62 为有效位 源文档
    挡位 / 点火 DRIVE_STATE 0x242 任意有效挡位即视为点火接通 源文档
    制动状态 DRIVE_STATE 0x242 / BRAKE_PRESSED 已去抖;须与安全模块读同一信号 源文档
    油门 PEDAL 0x342 / GAS_PEDAL 不采用 DRIVE_STATE.RAW_THROTTLE 源文档
    转向灯 STALKS 0x133 — 源文档
    方向盘按钮 PCM_BUTTONS 0x3B0 SET / RES / LKAS / 车距 / ACC 开 源文档
    巡航状态 ACC_HUD_ADAS 0x32D / ACC_STATE 2 可用、3 与 5 已启用、7 错误(摄像头总线) 源文档
    偏航角速度 YAW_RATE 0x222 / YawRate 0|12@1+ × 0.002133 − 2.094 rad/s;另含偏置字段需相减 源文档 IMU 桥接节
    平面加速度 AXAY 0x223 / Ax、Ay 0|12@1+ 与 24|12@1+,× 0.027167 与 × 0.027127 m/s² 源文档;Ay 需反号
    雷达目标 私有总线 0x280–0x289 轨道含 TRACK_ID、LONG_DIST、LAT_DIST、VLEAD 等 源文档;COUNTER12_1/2 字段已修正

    读取方法与注意事项

    接入前先做识别。源文档指出:查询固件版本要用 0xF195(SUPPLIER_SOFTWARE_VERSION),因为 BYD 的 ECU 拒绝本平台默认的 0xF188;总线 0 上有 24 个 ECU 应答 0xF195,其中六个返回固件版本(摄像头、制动/IPB、EPS、前向雷达、驱动单元、安全气囊),版本载荷是 6 个原始字节而非 ASCII。摄像头 ECU 不应答固件查询,须设为非必需。

    发送前必须补校验:Chassis CAN 上被签名的 12 条消息,其校验是最后一字节,data[7] = (~sum(data[0:7])) & 0xFF;本系统只发送三条——转向角命令 0x1E2、HUD 帧 0x316、纵向命令 0x32E。0x1E2 按 50 Hz 发送(每两帧中的一帧为 100 Hz),而原车摄像头是 33 Hz。转向命令须在启用期间持续发送,包括静止时也要发请求位为 0 的空闲帧——出现间隙会让 EPS 进入状态 11 并闭锁,单靠随后发 STEER_REQ = 1 无法解除。

    私有总线的完整性另有一套:每条帧的第 0 字节是校验,形式为 CRC8(poly=0x1D, init=0x00, data[1:32]) XOR K[id];64 字节 ID 的两半各自独立保护,K 是逐报文常量、并入 init/xorout/DataID,不是 CAN ID 的函数,需从本车日志逐 ID 采集。另需注意:源文档修正了雷达 DBC 中两个字段的解读——COUNTER12_1/COUNTER12_2 并非 12 位计数器,第 0 与第 32 字节是帧校验、计数器是第 1 与第 33 字节的低半字节。

    还有一处几何修正:雷达 LONG_DIST 以后轴中心(ISO 8855 车体坐标系)为原点,而非传感器面,需减去 3.60 m(前悬 885 mm + 轴距 2720 mm)后才是相对车头距离;不修正会让每个前车读数偏远 3.6 m,修正后雷达与视觉在 12 m 内一致到 0.5 m 以内。

    证据等级与边界

    本文属于单台实车观测:报文、缩放与位域都在源文档里按车辆实测列出,并标注了去抖时间、保活与几何修正等工程条件。但证据范围的边界同样清楚:源文档在末尾单列一节强调,全部数据来自一辆 2024 右舵出口版;中国国内版本与其他年款可能不同,BYD 还使用过两个摄像头供应商、连接器不同,换车必须重新测量连接器。此外,若用不带继电器直通的旁接线束,本系统运行时没有硬件回退;源文档建议使用带直通继电器的线束盒。

    一处不确定性必须原样保留:EPS 掉线前的状态字段被某份未合并的草稿 DBC 命名为 TORQUE_TEMP_FAILED(取值 1 "TooLarge"、2 "TooFast"),但源文档明确——没有 BYD 官方文档、没有 EPS 诊断码、也没有其他分支能确认该命名,应视为未确认;文档给出的转角上限结论并不依赖该命名。另据源文档,ABS/ESP 侧的转向限值表现为一个恒定的偏航率:EPS 在乘积约 3155 及以上放弃车道保持,故取 3000 留余量,不要抬高到 3155 或观测均值 3578。

    关于安全访问,源文档未提供任何绕过方法,且不建议尝试;本文只整理源文档记录的可读信号与发送约束。

    常见问题

    为什么查询固件版本要用 0xF195 而不是 0xF188?

    因为源文档记录 BYD 的 ECU 会拒绝 0xF188(本平台默认的那个)。改用 0xF195 后,总线 0 上有 24 个 ECU 应答,其中六个返回固件版本;版本载荷是 6 个原始字节而非 ASCII,摄像头的 MPC ECU 不应答、须设为非必需。

    Chassis CAN 上发送报文要注意什么?

    两条硬约束。其一,被签名的 12 条消息必须补末字节校验 data[7] = (~sum(data[0:7])) & 0xFF;其二,本系统只允许发送 0x1E2、0x316、0x32E 三条。转向命令还要 50 Hz 连续发送、静止时发请求位为 0 的空闲帧,避免 EPS 进入状态 11 并闭锁。

    雷达距离为什么要减 3.6 m?

    因为 LONG_DIST 的原点是后轴中心(ISO 8855 车体坐标系),不是传感器面。需减去前悬 885 mm 加轴距 2720 mm 共 3.60 m 才得到相对车头距离;不修正每个前车会偏远 3.6 m,修正后在 12 m 内与视觉一致到 0.5 m 以内。

    TORQUE_TEMP_FAILED 这个信号名可信吗?

    不可信。源文档明确:该命名来自一份未合并的草稿 DBC,没有 BYD 文档、没有 EPS 诊断码、也没有其他分支能确认,应视为未确认。文档给出的转角上限(约 3000 / 车速)并不依赖这个命名。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/shemps-byd-atto3/README.md(本项目车型档案主来源:线束与总线拓扑、指纹、状态解码、校验、横向与纵向控制、雷达与 IMU 桥接、适用性边界)。

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

    更新记录

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

  • Western Formula Racing 的 PECAN 遥测链

    结论:这份档案记录的是 Western Formula Racing(学生方程式车队)的整车遥测链:车辆 CAN 报文由车上的树莓派 + CAN HAT 采集,打包成 UDP/TCP 经无线电发到基站,再经 Redis 广播到 WebSocket,最终在浏览器仪表板(PECAN)上实时显示,并落库到 TimescaleDB 供历史查询。它的价值是一条从总线到仪表盘的完整数据通路,而不是逐条信号解码:CAN 报文的分类由一份可配置清单管理(VCU、BMS、INV、TEST MSG 等),逐条定义放在 DBC 里。需要说明的是,本快照只包含项目 README,DBC 与逐条信号未包含在内。

    车辆与适用范围

    源文档是车队开源的数据采集系统仓库,覆盖车辆侧与基站侧两端软件,以及一台用于无实车测试的仿真器。

    项 内容
    车型 Western Formula Racing 方程式赛车(车队项目 PECAN)
    年款 / 市场版本 源文档未给出具体赛季,仅出现运行数据标识 ECU_25
    ECU / 改装状态 车队自研 VCU、BMS、逆变器等部件,构成车辆 CAN 报文来源
    采集跨度 源文档未给出日志数或帧数;提供 CSV 回放样例与仿真器
    适用范围 仅限该队的这套软硬件;逐条信号定义见其 DBC(公开样例在仿真器内,私有部分在受限子模块)

    总线与寻址

    数据流在源文档里以流程图给出:车辆 CAN → 树莓派 CAN HAT(SPI/CAN)→ 车上树莓派(原生 systemd 服务)→ 射频 UDP/TCP → 基站 → Redis → WebSocket → PECAN 仪表板;基站还可把解码后的 CAN 帧直接写入服务器的 TimescaleDB,由 Grafana 做历史可视化。

    项 内容
    物理层 车辆侧树莓派 CAN HAT(经 SPI 接口)读取 CAN 总线
    链路层 / 比特率 源文档未给出
    寻址方式 支持标准 CAN ID 与扩展 CAN ID 两类
    CAN FD 源文档未提及
    传输端口 UDP 5005、TCP 重传 5006、本地 PECAN WebSocket 9080、基站地址 10.71.1.20

    已解码信号

    本快照只含项目 README,DBC 本体与逐条信号未包含在内。为守住「只抄源文档里有证据的条目」这条线,下表登记 README 明确写出的报文类别与数据资产,并逐条注明证据;任何具体报文 ID、字节与缩放系数,源文档均未提供。

    条目 归属 / 位置 说明 证据
    VCU 报文 车辆 CAN 类别 整车控制单元报文类别 README「CAN Message Categories」
    BMS 报文 车辆 CAN 类别 电池管理系统报文类别 README「CAN Message Categories」
    INV 报文 车辆 CAN 类别 逆变器报文类别 README「CAN Message Categories」
    TEST MSG 车辆 CAN 类别 测试报文类别 README「CAN Message Categories」
    类别配置清单 pecan/src/assets/categories.txt 文本配置即可改分组与配色,无需改代码 README「CAN Message Categories」
    标准 / 扩展 CAN ID WS 后端 广播服务支持两类 ID README「WebSocket Backend」
    蓄能器仿真 WS 后端 内置 accumulator 仿真 README「WebSocket Backend」
    样例 CAN 数据 car-simulate/(CSV) 可回放的录制数据 README「Car Simulator」
    样例 DBC car-simulate/ 报文定义示例文件 README「Car Simulator」
    私有 DBC secret-dbc/ 子模块 受限的私有 DBC 文件 README「Project Structure」
    运行数据标识 ECU_25 Flight Recorder 记录的上传标识 README「Flight Recorder」
    实时遥测包 UDP 5005 车上→基站的实时流 README「Car RPi Deployment」
    重传包 TCP 5006 丢包重传通道 README「Car RPi Deployment」
    本地广播 WebSocket 9080 车载 Pi 上的本地 PECAN 数据源 README「Car RPi Deployment」

    读取方法与注意事项

    车辆侧不用容器:遥测栈以原生 systemd 服务 car-telemetry.service 运行,配置为 ROLE=car、基站地址、UDP 5005、TCP 重传 5006、本地 WebSocket 9080。部署步骤是 uv sync 后在服务文件里填入 git 短哈希,再 systemctl enable/start。这一点值得注意:车上运行时依赖与基站不同,车上没有 Docker 与 Redis。

    基站侧则用 Docker Compose 起整套栈(Redis、WebSocket、状态页、视频中继,可选 TimescaleDB 日志)。在笔记本上有一份现成的 .env.macbook 默认配置可直接拉起;在 Windows 上还需要保留一个 PowerShell UDP 中继窗口,因为 Docker Desktop 不会把局域网 UDP 转发进容器。

    没有实车时,可用仿真器回放 CSV 数据来做开发与自检:car-simulate 提供 CSV 回放、常驻 WebSocket 广播与示例 DBC。另有一条「Flight Recorder」路径,用手机在车辆热点上记录数据到浏览器 IndexedDB,等有网时再通过 POST /api/can-frames/batch 同步到服务器。

    证据等级与边界

    本档案属于项目登记,可核对的是系统架构、端口、部署方式与配置文件名;不能据此推出车辆具体有哪些信号,因为逐条定义在未被本快照收录的 DBC 里。

    三处不能外推。第一,报文类别(VCU/BMS/INV/TEST MSG)是可配置的分组名,不是信号清单——它由 categories.txt 决定,改配置即可变。第二,公开样例 DBC 与私有 DBC 是两回事:公开的仅用于仿真器开发,实际车辆定义在受限子模块 secret-dbc/,本快照未包含。第三,端口(5005/5006/9080)与基站地址是这套部署的默认值,换环境即需调整。

    关于「安全访问」类问题:本文只整理公开文档登记的数据通路,未涉及诊断写入或安全访问;源文档未提供绕过方法,且不建议尝试。

    常见问题

    PECAN 能读到哪些信号?

    源文档未给出逐条信号。它说明报文按可配置清单分组(示例为 VCU、BMS、INV、TEST MSG),逐条定义放在 DBC 里;本快照未包含该 DBC。

    车辆侧是怎么读 CAN 的?

    车辆侧树莓派接 CAN HAT,遥测软件以原生 systemd 服务运行,把报文打包成 UDP 5005 发送,另有 TCP 5006 用于重传;车载 Pi 上还有本地 WebSocket 9080。

    没有实车怎么测试?

    用 car-simulate 仿真器:回放 CSV 录制数据、常驻 WebSocket 广播,并附带一份示例 DBC;开发时无需连接真车。

    DBC 在哪里?

    公开样例在仿真器目录内;实际车辆定义位于受限子模块 secret-dbc/。本快照只包含项目 README,未包含任何 DBC 文件。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/western-formula-racing/README.md(本项目车型档案主来源:系统架构、数据流、部署与配置;本快照仅含此文件)。

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

    更新记录

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

  • CAN 与 Cap’n Proto 适配层:有效位为何在跨语言边界丢失

    结论:在这套 CAN 与 Cap’n Proto 适配层里,valid 只在 Event 外层,帧本身没有独立有效位:编码器只写外层 logMonoTime 与 valid,解码器只返回时间戳与帧三元组,不返回外层有效位。更关键的是发送侧——C++ 发送线程只读 logMonoTime 和 sendcan,用一秒年龄门与 fake_send 条件决定是否调用打包发送,没有检查 event.getValid(),因此 CS.canValid=False 只是日志与下游可见的标注,并不单独阻止该线程尝试发送。是否实际发上车总线仍受后续编码、传输与 MCU 安全钩子控制。本文为固定源码快照 c8fb906 的静态阅读与假 Event 原函数探针,未运行真实 Cap’n Proto、总线进程或连接车辆。

    组件与关键函数

    CAN 帧在 schema 里有 32 位地址、数据载荷和 8 位来源;Event 有 logMonoTime、默认恒真的 valid,且 can 与 sendcan 是不同 union 成员。编码器首次遇到非空帧时缓存字段对象,后续按相同 schema 访问。

    函数/组件 行为
    CanData/Event 帧有 32 位地址、数据载荷与 8 位来源;Event 有 logMonoTime 与默认真的 valid
    _get_reader_fields()/_get_writer_fields() 首次非空帧时缓存字段对象,后续按相同 CanData schema 访问
    can_list_to_can_capnp() 新建 Event,填入 can 或 sendcan 帧列表并序列化;valid 与时间戳只写在外层
    can_capnp_to_list() 逐条解析 bytes,返回时间戳与帧三元组,不返回 Event valid
    controls_update() 控制侧用 CS.canValid 标注 sendcan Event
    can_send_thread()/can_recv() 发送侧按时间戳与一秒年龄门筛选;接收侧把接收布尔值设为 Event valid

    从帧到 Event 的数据流

    编码器接受三元组列表,按调用方 msgtype 在 Event 上初始化 union 列表,外层 logMonoTime 来自单调时钟。首次遇到非空列表才缓存 CanData 的三个 schema 字段对象;空列表仍可产生合法的空 can 或 sendcan Event。函数自身不检查地址范围、总线号、CAN 或 CAN FD 合法长度与消息数量,依赖 schema 字段类型以及后续边界处理——因此不能把 schema 能序列化当作总线发送合法性证明。

    控制更新时,若控制消息存活则生成 sendcan,以状态里的 canValid 填外层 valid;而车型识别回调使用默认 valid=True。发送线程只读 logMonoTime 和 sendcan,用一秒年龄门与 fake_send 条件决定是否调用打包发送,没有检查 event.getValid()。所以状态标注与是否尝试发送是两件事,日志里看到的无效标注不能推断「危险动作已经发生」或「一定不会发送」。

    接收侧与解码资源边界

    接收侧即使底层接收返回假,仍构造一个有效位为假的 can Event,并放入当前收集到的帧。Python 解码只保留时间戳与帧、不传递外层有效位;状态更新先把这些帧送给车型状态与雷达接口,再以原始消息列表是否非空判断本轮是否收到 CAN。这样「收到一个无效 Event」仍算消息到达,其中已有的帧仍可能进入车型解析——当然车型解析器本身还有 CAN 检查,这里的结论仅限适配层与状态更新的直接门控。

    解码函数用接近无穷的遍历上限解析输入,相当于不在此调用处施加实用的遍历预算,输入消息大小和队列限制需沿上游单独核对。它直接按 msgtype 取 union 字段,没有先核对 union 实际类型,调用方传入错误类型或坏 bytes 时可能抛异常,而非返回结构化的坏消息结果。字段对象全局缓存假设后续仍是同一个 CanData schema,当前正常路径成立;缓存不保存消息内容或设备状态,也不等于逐帧验证。

    离线原函数探针与证据范围

    四项隔离测试从归档文件抽取四个原函数运行,仅替换 Event、帧字段对象与序列化存储。

    输入 原函数观察结果 证据边界
    空 can 列表 可生成并解出空 Event;字段缓存仍为空 假 Event 只实现最小接口,不证明真实序列化字节
    非空 sendcan,有效位为假 帧与时间戳往返;外层有效位不出现在解码结果;首次帧填充缓存 只证明本适配函数的字段路径与返回形状
    错误 union 与坏载荷 假 Event 抛出的属性或解析异常直接向上传播 真实解析库的错误类型与 union 语义仍未验证
    缺字段三元组、非法编码类型 原函数没有预检查;前者索引失败,后者委托初始化失败 假 Event 只模拟非法 union 拒绝,不能外推 schema 约束

    回放与仿真也复用这套适配函数:回放会把日志中的 can Event 转 bytes 后经该解码器导出帧列表,仿真则复用编码器发布合成 can。它们既服务实车运行也服务回放,但信任级别与时间域并不相同。

    自研硬件与插件契约

    消息插件契约应明确区分载荷有效位、总线链路健康、schema 可解析、时间戳年龄和 MCU 安全放行。只读观察插件可拿到带来源与有效位的 CAN 快照;控制候选插件不得直接发布 sendcan 到受信任网关。网关需逐 Event 核对 union 类型、有效位、时间域与年龄、帧数、地址、总线、长度和车型授权,再把送达传输、MCU 接受与安全拒绝分开记录。诊断与回放输入应有明确大小与遍历预算,异常帧应隔离而非让主车控线程意外退出。离线验收至少覆盖空列表、错误 union、有效位为假但含帧、CAN 事件无效且仍有先前好帧、坏 bytes、极大列表与载荷、未来或跨时钟域时间戳。

    常见问题

    CS.canValid=False 会阻止发送吗?

    不会单独阻止。控制更新会把 CS.canValid 写进 sendcan Event 的外层有效位,但 C++ 发送线程只读 logMonoTime 与 sendcan,用一秒年龄门和 fake_send 条件筛帧,没有检查 event.getValid()。是否真正发上车仍受后续编码、传输与 MCU 安全钩子控制。

    为什么解码后拿不到 valid?

    因为有效位只在 Event 外层。编码器把 valid 与时间戳写在外层,解码函数只返回时间戳与帧三元组列表,不返回外层有效位;因此跨语言往返后,帧层面看不到原始的无效标注,需要在上层另行传递。

    收到一个无效 CAN 事件算收到消息吗?

    在这层算到达。接收侧即使底层接收返回假仍会构造有效位为假的 can Event 并放入已收集帧;状态更新以原始消息列表是否非空判断本轮是否收到 CAN,所以无效事件里的帧仍可能进入车型解析,导致「丢帧」判断被低估。

    探针证明了真实 Cap’n Proto 行为吗?

    没有。四项探针替换的是 Event、帧字段对象与序列化存储,属于局部回调与编码器证据;真实解析库的错误类型、union 访问语义、遍历预算下的内存与时间行为都未验证,也不是诊断帧取得板级发送授权的证明。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/PANDAD_PYTHON_CAN_CAPNP_ADAPTER_VALIDITY_DEEP_DIVE.md(取用了编码与解码函数、发送侧不读有效位、接收侧无效事件构造与四项原函数探针)。
    • 项目 02 —— openpilot-research/CAN_PARSER_HEALTH_DEEP_DIVE.md(仅用于确认车型解析器自身的 CAN 检查位置)。

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

    更新记录

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

  • Toyota panda safety:LKA/LTA 与纵向模式矩阵

    结论:Toyota panda safety 是MCU 本地规则,不验证 SecOC CMAC、雷达静默的正响应或车辆 ECU 是否接受命令。同一套 safety 代码按「原车 / 自控纵向 × 非 SecOC / SecOC × LKA / LTA」组合出不同模式,各模式允许的 TX 帧、长度与字段门都不同,不能把两个标志当成可随意组合。SecOC 相关位只在 ALLOW_DEBUG 构建下生效,上层即便能构帧也不能绕开普通固件或发布版 dashcamOnly 的能力边界。固定快照基线为 c8fb906,没有目标固件、车辆密钥、ECU 或实车验证。

    关键函数与调用顺序

    CarInterface._get_params() 配置 Toyota safety 参数、LTA / 替代制动 / SecOC、原车或自控纵向——注意上层参数和目标 ECU 已接受控制不是同一事实。toyota_init() 从 safetyParam 低八位读取 EPS 扭矩比例,高位选择替代制动、原车纵向、LTA;SecOC 位只在 ALLOW_DEBUG 下生效。

    toyota_rx_hook() 更新 EPS / 驾驶员扭矩、测量角、巡航 / 油门 / 制动和轮速;toyota_tx_hook() 分别检查 ACC、LKA 扭矩、LTA 角度 / 请求位、SecOC LTA2、AEB 和诊断保活。更外层,safety_tx_hook() 与 safety_fwd_hook() 先做地址 / 总线 / 长度白名单,继电器状态与静态转发阻断是独立的最终门。

    模式矩阵

    维度 选择与实际影响
    原车纵向 STOCK_LONGITUDINAL 非 SecOC 的 TX 仅含基础 LKA / LTA / HUD 与 0x343 取消;0x343 必须置 CANCEL_REQ 且加速度为零。
    自控纵向,非 SecOC 在基础 TX 上增加 DSU bus 0/1、PCS_HUD、0x750、0x283;0x343 可携带受限加速度,并另以 check_relay=true 登记。
    SecOC + 原车纵向 0x2E4 长度由 5 改 8,增加 0x131;0x343 仍只准零加速度取消;没有 0x183。
    SecOC + 自控纵向 0x2E4 长度 8,增加 0x131 和 0x183;0x343 只许零加速度,实际加速度走 0x183;没有非 SecOC DSU / 雷达诊断扩展表。
    LTA 标志 0x191 是否可执行受限角度由 LTA 位决定,即使同时设置 SecOC 位也如此;0x2E4 必须零扭矩 / 无请求。LKA 模式相反,0x191 必须无角度执行。SecOC 的 0x131 LTA2 在当前钩子中始终不准执行。
    替代制动 仅非 SecOC、非 LTA 的 RX 分支选择 0x224;普通分支用 0x226。LTA 分支固定普通 RX 表,SecOC 固定 0x101。

    自控纵向表里 0x343 同时经基础宏以 check_relay=false、扩展项以 check_relay=true 列出;通用继电器和转发代码遍历整个表,所以后者仍会触发对应故障 / 静态阻断,不能只看第一条白名单记录。

    RX 信号与健康

    所有 safety RX 均在总线 0。0x0AA 轮速 83 Hz,忽略 checksum / counter,但四个轮速故障位必须为零;0x260 转向传感器 50 Hz 检查 Toyota 累加校验,非 SecOC 的 LTA RX 表还要求 STEER_ANGLE_INITIALIZING=0。SecOC 初始化优先选择 TOYOTA_SECOC_RX_CHECKS,即使 LTA 位同时设置,该质量位也不作为 RX 有效性门。忽略某一完整性字段不等于不要求报文存活。

    报文 频率与门
    0x0AA 轮速 83 Hz,忽略 checksum / counter,四路故障位必须为零
    0x260 转向传感器 50 Hz,检查累加校验;非 SecOC LTA 表要求转角初始化位为 0
    0x1D2 巡航 / 油门 普通车 33 Hz,检查校验
    0x226 / 0x224 制动 40 Hz,忽略校验 / 计数;替代制动改用 0x224
    SecOC 路径 使用 0x176 巡航、0x116 油门和 0x101 制动

    toyota_rx_hook() 从 0x260 读取 16 位 EPS 扭矩,乘 safetyParam 低八位比例后采样,并把窗口最小值减 1、最大值加 1 以覆盖整数取整;驾驶员扭矩和测量角分别取独立字段。测量角仅在初始化位关闭时更新,不能把上一样本当成当前有效角。0x0AA 四轮原始值各减 6767 后求和,和不为零即视为移动。

    TX 权限与未覆盖载荷

    1. 扭矩 LKA:非 LTA 时 0x2E4 检查最大 1500、每帧上升 15 / 下降 25、相对 EPS 实测误差 350、实时差 450 与请求位切断节拍;LTA 模式仅允许零扭矩且请求位为零。SecOC 的 0x2E4 长度为 8,普通车为 5。
    2. 角度 LTA:非 LTA 时 0x191 的两个请求位、角度、TORQUE_WIND_DOWN 都必须不执行;LTA 时角度受速度相关变化率、最大 1657 原始单位及测量角邻域约束,两个请求位必须一致,wind-down 只可为 0 / 100,且驾驶员 / EPS 扭矩过高时禁止 100。SecOC 的 0x131 只允许请求位和角度字段均为零——这不是车辆认证成功的证明。
    3. 纵向:0x343 或 SecOC 0x183 的有符号加速度活动范围 -3.5 至 2.0 m/s²,未激活码为 0;共享门还要求允许控制且未踩油门。
    4. AEB 与诊断:仅非 SecOC 自控纵向白名单包含 0x283,前六字节必须全零,避免主机执行 AEB;0x750 仅允许固定载荷 0F 02 3E 00 00 00 00 00,用于雷达 tester-present。

    自制硬件与插件化契约

    车型插件提交 DBC / 平台、LKA / LTA、SecOC、制动地址及 EPS 比例的证据;未知 / 矛盾组合保持 noOutput。受信任网关独占 SecOC 密钥与签名、UDS 雷达静默、DSU / HUD 模板及节拍;普通插件只提交高层转向 / 加速度 / 取消意图,MCU safety 保留独立限幅。验证分层覆盖模式参数组合、错误 CRC / 质量位、双请求位不一致、wind-down、油门覆盖、非零 AEB、诊断错误载荷、签名失败与失联降级;随后是无负载台架和受控场地。当前没有这些目标车证据。

    常见问题

    LKA 和 LTA 模式能随便组合吗?

    不能。0x191 是否可执行受限角度由 LTA 位决定,即使同时设置 SecOC 位也如此;LKA 模式相反,0x191 必须无角度执行。0x2E4 在 LTA 模式必须零扭矩 / 无请求。未知或矛盾组合应保持 noOutput。

    「四个轮速故障位为零」是不是意味着数据都可信?

    不等于。0x0AA 忽略 checksum / counter,只用四个故障位做门;0x260 才检查 Toyota 累加校验并要求转角初始化位为 0。忽略某一完整性字段不等于不要求报文存活,健康判定要按报文明细区分。

    AEB 帧在 safety 里怎么处理?

    仅非 SecOC 自控纵向白名单包含 0x283,且前六字节必须全零,以避免主机执行 AEB。其它 DSU、PCS_HUD、0x1D2 / 0x412 等白名单帧没有同等级的逐字段门。

    panda safety 通过就等于车辆 ECU 接受命令了吗?

    不等于。这些只是 MCU 本地规则,不验证 SecOC CMAC、雷达静默的正响应或车辆 ECU 是否接受命令。SecOC 相关位只在 ALLOW_DEBUG 构建下生效,也不能绕开 dashcamOnly 等能力边界。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/TOYOTA_PANDA_SAFETY_MODE_DEEP_DIVE.md(取用了模式矩阵、RX 健康门、TX 权限与插件化契约分析)。

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

    更新记录

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

  • Talaria 电摩 CAN 档案:250 kbit/s 的 15 个 ID

    结论:Talaria 电动摩托的总线是一条 250 kbit/s、11 位标准帧的小型 CAN:源文档记录 15 个 ID、约 92 帧/秒,并把其中的 9 条消息、26 个信号行整理成 DBC。这条总线的价值在于「小而有坑」——源文档明确记录了三处「看起来像但并不是」的误判(电池百分比、里程、温度),还修正了里程字段并标注为临时值。以下所有结论仅限源文档记录的这一台车。

    车辆与适用范围

    本文数据来自第三方开源项目对一台 Talaria 电动摩托的 CAN 解析。项目用只监听方式读车,DBC 基于更早的第三方整理做了修订,并把每个信号的溯源写在注释里。

    项 内容
    车型 Talaria 电动摩托;具体型号源文档未确认
    电池包 16S;源文档由「电芯高/低平均 × 16」与包电压吻合到 0.02 V 推出
    采集硬件 ESP32-S3 加 SN65HVD230 收发器;默认只监听
    采集跨度 多条骑行日志与台架检查;源文档记录总线约 92 帧/秒、15 个 ID
    适用范围 仅限源文档记录的这一台车;源文档另指出另一台参考车上的字节偏移不同

    总线与寻址

    这条总线的规模很小,接入门槛不高,但正因为 ID 少、字段挤,误判的风险反而更高。识别要点是速率、位宽与终端电阻三件事。

    项 内容
    速率 / 帧格式 250 kbit/s;11 位标准帧
    总线规模 15 个 ID,约 92 帧/秒
    终端 车端已两端终端,整对约 60 Ω;采集器若自带 120 Ω 终端应拆除,否则会降到约 40 Ω
    采集方式 只监听(listen-only);收发器不驱动总线也不应答,因此速率设错也不会干扰车辆
    DBC 规模 9 条消息、26 个信号行;基于第三方先期整理修订

    已解码信号

    下表从源文档的解码清单中抽取。项目对未确认的条目明确标注「单位未确认」或「临时值」,本文原样保留这些标注。

    信号 位置(ID / DID / 字节) 解码 证据
    车速 0x303 B0:B1(小端) 0.1 km/h 已确认(与转速比值恒定 5.887,r=0.999)
    电机转速 0x203 B0:B1(小端) 1 rpm 已确认(同上)
    功率 0x203 B2:B3(小端) 1 W 标定记录
    电流 0x302 B4:B5(小端) 0.1 A 标定记录
    包电压 0x101 B0:B1(小端) 0.1 V 已确认(电芯高低平均 × 16 吻合到 0.02 V)
    电池百分比 0x401 B0 1 % 标定记录
    最高电芯 + 编号 0x201 B0:B1、B4 1 mV 标定记录
    最低电芯 + 编号 0x201 B2:B3、B5 1 mV 标定记录
    侧撑 0x202 B0 bit7 1 = 放下 标定记录
    骑行模式 0x202 B0 bits5:4 1 Eco、2 Sport 标定记录
    回充等级 0x490 B0 bits2:0 1–4 标定记录(须按 3 位掩码)
    骑行模式(仪表指令) 0x490 B0 bits5:3 1 Eco、2 Sport 标定记录
    里程 0x402 B2:B3(小端) 1 km 临时值(源文档要求增量复核)
    油门需求 0x202 B3:B4(小端) 单位未确认 未确认

    读取方法与注意事项

    第一条是终端电阻。车端已经在两端做终端,整对读下来约 60 Ω;如果采集器再挂一个 120 Ω 终端,会把阻抗拉到约 40 Ω,可能影响总线。源文档建议把采集模块自带的终端拆掉。

    第二条是「看起来像但不是」的三处误判。其一,某个字节被当成电池百分比,其实是恒定的 100,源文档判断它更可能是健康状态而非荷电状态;其二,某个字段单调递增,看着像里程,但它与车速的相关系数只有 −0.0005,且每公里计数在两次骑行间相差 34%——真正的里程在另一个 ID 上;其三,某个字节既不是温度也不是单一字段,它同时承载模式位与回充位,必须按 3 位掩码拆开。

    第三条是写入操作的风险边界。源文档记录了对「模式/回充指令所在 ID」是仪表下发还是控制器回显的讨论,并做了注入实验来判断控制权归属。这类对车辆控制总线的写入涉及安全风险,本文不复述具体做法,也不建议尝试。

    证据等级与边界

    项目对已确认信号给出了可复现的依据:车速与转速在两个独立骑行中保持固定比值 5.887(r=0.999),电芯高低平均 × 16 能把包电压还原到 0.02 V。这两条互相独立的证据把「车速、转速、包电压、16S 结构」串成了可信的一组。

    里程是新近发现的字段,源文档明确标注为临时值:它是靠「车自己显示的 400 km」与一次全总线采集里的数值匹配找到的,但只匹配了一次。源文档提醒这条总线上有整数常量(例如某两个 ID 里都出现 1200),所以一次与整数吻合只是「有说服力」,不是证明——必须等到一次骑行里看到它递增才能定案。

    边界上必须强调:以上字段位置与刻度限定在这一台车与这一版固件。源文档已指出另一台参考车上的油门字节偏移就不同(本车在 0x202 的 B3:B4,参考车在 B2:B4 且并不跟随油门)。换车使用前必须重新核对偏移。

    常见问题

    为什么里程字段被标成「临时值」?

    因为它只被匹配到一次:源文档读到车辆自身显示的 400 km,并在一次全总线采集的某个 ID 里找到同样的 400。但这条总线上存在整数常量,单次与整数吻合不能排除巧合,必须等一次骑行里看到该值递增才能确认。

    那个恒定 100 的字节是什么?

    源文档明确它「不是电池百分比」——它在实际电量变化时仍读 100,因此更可能是健康状态之类的字段。不要把它当作荷电状态使用。

    回充等级为什么容易读错?

    因为它与骑行模式共用同一个字节,且只能按低 3 位掩码读。若按整个低半字节(4 位)读,在 Eco 模式下 bit3 会被置位,本该读成 1 的回充等级会读成 9。源文档强调「掩 3 位,不是 4 位」。

    这条总线上有哪些信号是找不到的?

    源文档记录喇叭与灯光不经过总线,它们是来自车把开关的 12 V 通断电路;刹车拉杆只出现在部分车型上,不带传感器的改装拉杆则什么都不产生。因此这些量无法从 CAN 上读到。

    延伸阅读

    参考资料

    • 项目 07 —— public-can-dbc-datasets/additional/kbirand-talaria-tripper/README.md(本项目车型档案主来源:解码清单、陷阱与硬件说明)
    • 项目 07 —— public-can-dbc-datasets/additional/kbirand-talaria-tripper/SOURCE.md(DBC 规模、先期工作与许可证说明)

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

    更新记录

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

  • Honda panda safety:RX/TX 白名单与 AEB 转发

    结论:Honda panda safety 的规则分四段:RX 检查表(地址/总线/长度/频率 + nibble checksum 与二位计数器)、使能状态(主开关、PCM/SET-RESUME 使能沿)、TX 白名单与内容钩子、以及转发钩子。honda_tx_hook() 的 Honda 内容钩子在 controls_allowed=False 时拒绝非零转向,但源码并未在该钩子内对使能时的转向幅度或变化率作额外限制,那部分由主机 CarController 承担。拒帧还可能产生状态副作用:本地 C 探针显示,一帧被拒的主机 0x1FA 仍会先写入全局 honda_brake,从而影响下一次原车 AEB 转发决策。以下为固定源码快照 c8fb906 与本地 C 探针的静态分析,不证明目标板固件编译选项、实际 CAN 总线或整车安全性。

    关键函数与组件

    入口 源码 作用
    honda_nidec_init() / honda_bosch_init() honda.h 按参数选择 RX 期望、TX 地址/总线/长度白名单和平台状态。
    honda_get_checksum() / honda_compute_checksum() / honda_get_counter() honda.h 解码 Honda checksum/计数器,供通用接收检查使用。
    safety_rx_hook() / honda_rx_hook() safety.h、honda.h 通用验证通过且属于 RX 检查表后,才更新 Honda 使能、踏板与 AEB 状态。
    generic_rx_checks() / safety_tick() safety.h 踩刹车等通用退出,以及每秒检查关键 RX 消息是否超时/失效。
    safety_tx_hook() / honda_tx_hook() safety.h、honda.h 通用白名单加 Honda 内容检查;最终还需无继电器故障。
    safety_fwd_hook() / honda_nidec_fwd_hook() safety.h、honda.h 通用阻断冲突帧后,Nidec 对相机原车制动执行动态转发决策。

    RX 与使能状态

    Honda RX 检查表把 SCM_BUTTONS 两种地址、ENGINE_DATA、POWERTRAIN_DATA 纳入核心检查;多数模式还检查 SCM_FEEDBACK,备用刹车模式加 BRAKE_MODULE,Nidec 还检查相机总线 BRAKE_COMMAND。每项声明地址、总线、长度和频率,部分声明最大计数器。Honda 钩子提供 nibble checksum 和二位计数器解码;通用 safety_rx_hook() 仅在消息匹配、校验有效且属于 RX 表时才调用 honda_rx_hook()。safety_tick() 每秒检查迟到/无效关键消息并清除 controls_allowed,不能把 25/100 Hz 配置频率误读为毫秒级 fail-safe deadline。

    honda_rx_hook() 从 ENGINE_DATA 更新是否行驶,从 SCM 更新 ACC 主开关,主开关关闭直接禁止控制。Bosch 原车巡航和 Nidec 使用 PCM 巡航上升沿允许控制;Bosch 巡航退出会撤销许可,但 Nidec 允许在 PCM 退出后继续制动至零。Bosch 自控纵向改用 SET/RESUME 的释放沿使能,MAIN/CANCEL 则退出。用户制动有普通 POWERTRAIN_DATA 的连续开关样本判据或备用 BRAKE_MODULE 来源;随后通用 generic_rx_checks() 再按制动上升沿/车辆运动状态撤销控制。主机侧 CarState 字段不替代 MCU 的这一路独立采样。

    TX 白名单与内容规则

    通用 safety_tx_hook() 先核对当前模式 TX 表中的地址、总线和长度,再调用 Honda 内容钩子,最终还受 relay_malfunction 阻断。Nidec 允许指定转向、BRAKE_COMMAND、ACC_HUD 和 LKAS_HUD;Bosch 普通、纵向、radarless、CAN FD 各有不同表。Bosch 纵向 safetyParam 只在 ALLOW_DEBUG 编译条件下转成纵向模式能力,不能由 Python CarParams 位推断实板支持。

    内容钩子在 controls_allowed=False 时拒绝非零转向;源码未在该钩子内对使能时的转向扭矩幅度、变化率或驾驶员反向扭矩作额外限制。主机 CarController 自身会做变化率和车型 STEER_MAX 处理,但这是与 MCU TX 规则不同的层。当前 Honda 安全测试的转向专项只断言未使能零值可发、非零值被拒,不能把通用车型的转向扭矩安全测试结果自动套给 Honda。Nidec 对 ACC_HUD 的 PCM 速度/gas 和 BRAKE_COMMAND 的制动量做纵向许可检查,并阻止主机设置 AEB 执行位;Bosch 有雷达的 ACC_CONTROL 检查加速度、gas 和 AEB 位,radarless 的加速报文走另一地址与编码。所有这些规则只约束通过当前 TX 表的候选,不能保证 ECU 实际接受。

    Nidec AEB 转发及状态顺序

    相机总线 0x1FA 通过 RX 检查后,如果未设置「禁用原车 AEB」的替代体验位,Honda 钩子比较原车制动力与最近记录的主机制动力:原车 AEB 不活动时清掉转发锁存;AEB 活动且原车制动力不小于主机记录值时置位;较小时保持之前状态。通用转发层先按继电器故障和静态冲突表阻断,Nidec 专属钩子再决定是否允许相机 0x1FA 走向另一总线。

    honda_tx_hook() 读取 Nidec 主机 0x1FA 时,先写全局 honda_brake,后检查制动上限、是否正在转发原车 AEB 和 AEB 位。本地拒帧探针直接编译仓库的 libsafety/safety.c:在 Nidec 模式下,相机 AEB 0x1FA 请求制动 100,基线转发;重新初始化后,先送主机 0x1FA 请求制动 200 且带 AEB 执行位,该帧被 TX 钩子拒绝,再送相同的相机帧,RX 有效但转发被阻断。严格编译和 UBSan 运行输出:

    场景 相机帧 RX 转发 说明
    基线 有效(rx=1) 允许(forward=1) 无先前主机帧干扰。
    先送被拒主机帧 — 候选未被接受(accepted=0) 主机制动 200 且带 AEB 位,被 TX 钩子拒绝。
    随后相机帧 有效(rx=1) 被阻断(forward=0) RX 有效但转发被阻断,证明拒帧有状态副作用。

    这证明当前测试库实现中拒帧可影响下一次 AEB 转发决策,尚不证明目标实板的编译配置、真实消息时序或车辆制动后果。

    自制硬件与插件验收

    车型插件只能提交受限候选,MCU 必须独立持有模式、RX 有效性、TX 白名单、超时与转发规则。Honda 的不同模式要分别验证 PT/camera 总线、备用刹车、Nidec 原车 AEB、Bosch ALLOW_DEBUG 门、诊断固定载荷和失联默认状态。探针应扩展为正式回归测试:对越界、带 AEB 位、因原车 AEB 锁存而被拒的主机 0x1FA,都断言下一帧的转发状态只依据已准许发送的主机制动记录。还需检查使能时转向幅度由哪些独立物理/软件约束承担,不能把 Python 限幅写成 MCU 的保证。本文未运行完整 safety 测试或实板故障注入。

    常见问题

    Honda 的转向扭矩在 MCU 侧会被限幅吗?

    Honda 内容钩子只在 controls_allowed=False 时拒绝非零转向,源码未在该钩子内对使能时的幅度、变化率或驾驶员反向扭矩作额外限制。变化率与车型 STEER_MAX 由主机 CarController 处理,属于不同层次。

    Nidec 用哪种沿使能,Bosch 自控纵向呢?

    Nidec 与 Bosch 原车巡航用 PCM 巡航上升沿允许控制;Bosch 自控纵向改用 SET/RESUME 的释放沿使能,MAIN/CANCEL 退出。Nidec 还允许在 PCM 退出后继续制动至零。

    一帧被拒的主机 0x1FA 会影响后续转发吗?

    会。主机 0x1FA 被 TX 钩子读取时先写全局 honda_brake 再检查,探针显示被拒帧仍能改变下一次相机 AEB 0x1FA 的转发决策,输出为 baseline rx=1 forward=1; rejected candidate accepted=0; stock rx=1 forward=0。

    safety_tick() 是毫秒级 fail-safe 吗?

    不是。它每秒才检查迟到/无效关键消息并清除 controls_allowed,不能把 25/100 Hz 配置频率误读为毫秒级安全时限。

    延伸阅读

    参考资料

    • 项目 02 —— openpilot-research/HONDA_PANDA_SAFETY_RX_TX_FORWARD_DEEP_DIVE.md(RX/TX 白名单、使能状态、Nidec AEB 转发与拒帧探针)。
    • 项目 02 —— openpilot-research/ 同目录 Honda 接口与输出专题(模式参数与控制构帧作为相邻边界参考)。

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

    更新记录

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

  • Opel Astra H 的 LS-CAN 与 MS-CAN 解码档案

    结论:这份档案记录的是欧宝 Astra H 的两条总线:单线的 LS-CAN(即 SW-CAN / GMLAN) 与 MS-CAN。在 LS-CAN 上,源文档把车速、转速、行驶距离、燃油喷射、冷却液温度、燃油液位、系统时间、电压与 TPMS 都逐字节解了出来;例如车速在 0x108 上除以 128、燃油液位是 94 - (值/2) 升。它是一份「按地址逐字节标注」的观测表,而不是厂商规格:大量字段被标为 ?? 或「见过 N 种取值」,这些不确定标记必须原样保留。

    车辆与适用范围

    源文档是一份公开的「车辆 CAN 报文数据库」,按 品牌/型号/代/总线/部件.md 组织。Astra H 这一支同时给出 LS-CAN 与 MS-CAN 两个目录,其中 LS-CAN 以 ALL_TYPES.md 汇总全部观测值。

    项 内容
    车型 Opel Astra H(MS-CAN 文档中点名发动机为 Z16XEP 1.6L)
    年款 / 市场版本 源文档未给出具体年款与市场版本
    ECU / 改装状态 源文档未给出;为车主对原车的观测
    采集跨度 源文档未给出日志数或帧数;部分报文注出周期(如 0x108 约 50ms、0x190/0x440 为 1000ms)
    适用范围 仅限源文档记录的这一台 Astra H;数值标定含多项未确认项

    总线与寻址

    这台车同时有 LS-CAN 与 MS-CAN。LS-CAN 被文档标注为「SW-CAN——单线或 GMLAN」,是单线制总线;MS-CAN 承载车身、信息显示等部件。两条总线都以小写十六进制地址登记(如 0x108、0x530、0x684)。

    项 内容
    物理层 LS-CAN:单线(SW-CAN / GMLAN);MS-CAN:源文档未给出
    链路层 / 比特率 源文档未给出
    寻址方式 表中地址为小写十六进制(如 100、530),源文档未标注位宽
    CAN FD 源文档未提及
    多帧报文 MS-CAN 的 Info-Display 报文超过 8 字节,使用 ISO-15765-2 分包

    已解码信号

    下表抽取 15 条最有代表性的条目,横跨 LS-CAN 与 MS-CAN。凡源文档标为 ??、「见过 N 种取值」或「计算取决于传感器/有时反向」的,均在证据列保留说明。

    信号 位置(ID / 字节) 解码 证据 / 置信度
    车速 LS-CAN 0x108 byte2+3 值 / 128 = km/h(例 0x2098=65.19) 源文档示例与说明
    发动机转速 LS-CAN 0x108 byte5+6 16 位(例 0x04E5=1253 rpm) 源文档示例;MS-CAN 版本在 0x4E8 上为「RPM/4」
    行驶距离(每驱动轮) LS-CAN 0x110 byte2+3 / byte4+5 一次增量 = 1.5748 cm;16 位满周期约 1032 m 源文档说明
    燃油喷射量 LS-CAN 0x130 byte2+3 一次增量 = 0.03054 ml(1.6L 机);满周期约 2 升 标定基于作者 1.6L 发动机
    冷却液温度 LS-CAN 0x145 byte4 值 – 40 = °C(例 0x28→-2 °C) 源文档示例
    发动机/点火状态 LS-CAN 0x145 byte1–3、5 多字节状态码(如 0x20=点火开未着、0x00=运行) 源文档逐值说明
    巡航控制状态 LS-CAN 0x145 byte6 0x04=未激活 / 0x06=激活 源文档说明
    转向灯/拨杆状态 LS-CAN 0x175 byte3 0x01~0x04 表示半推/半抬/全推/全抬 源文档说明
    转向灯控制帧 LS-CAN 0x260 三字节组合区分左/右/双闪 源文档逐组合表
    总里程 LS-CAN 0x190 byte3–5 里程量(周期 1000ms) 源文档标注;单位与系数未在本文展开
    燃油液位 LS-CAN 0x375 byte2 94 – (值/2) = 升(例 0xA0→14.0 L) 「计算取决于传感器,有时反向」
    系统时间 LS-CAN 0x440 byte1–3 时 : 分 : 秒÷4 源文档说明
    户外温度 LS-CAN 0x445 byte2 MS-CAN 同义项 0x682 为「值/2 – 40 = °C」 源文档说明
    电压 LS-CAN 0x500 byte2 源文档标注为电压(周期约 1500ms) 源文档标注;换算未在本页给出
    胎压 TPMS LS-CAN 0x530 byte3–6 每轮 值/25 = Bar;byte1/2 为前/后传感器状态 MS-CAN 版本在 0x684 上同式

    读取方法与注意事项

    源文档的记法本身就是方法约束:页首声明斜体值表示「至今只见固定值」,粗体值表示已被单独页面解释,括号中的数字是见过的不同取值个数。也就是说,一个标了 ? (4) 的字节,作者只见过 4 种取值——它可能是枚举状态,也可能是「从未触发的故障位」,文档对后者也如实保留。

    对使用者而言,最实际的两点:其一,MS-CAN 的 Info-Display 报文超过 8 字节,用 ISO-15765-2 打成多帧,数据块结构是「两字节命令 + 一字节负载长度 + 一字节消息类型 + 若干子包(ID + 字符数 + UTF-16 字符)」;文档给了 AC、音频、导航等消息类型与各类型下的行 ID 清单。其二,按位复用的字节必须做位运算(拨杆/方向盘按键就是「函数由位编码」)。

    证据等级与边界

    本档案属于单车观测:所有条目都来自一位车主对一台 Astra H 的记录,没有第三方旁证,也没有反汇编或厂商规格支撑。可核对的是「作者给出的一条条示例」(如 0x108 的 0x2098→65.1875 km/h、0x375 的 0xA0→14.0 L);不可核对的是这些标定是否适用于其他车。

    三处不能外推。第一,改装的线束、传感器与仪表版本会让个别字节不同,燃油液位文档自己就注明「取决于传感器,有时反向」。第二,作者在页首明说斜体值「可能是从未触发的故障指示」,把「只见固定值」当成「恒为定值」是过度解读。第三,发动机相关标定(燃油喷射的 0.03054 ml)是用作者自己的 1.6L 发动机推出来的,换机型即失效。

    关于「安全访问」类问题:本文只整理被动观测到的广播报文,未涉及任何诊断写入或安全访问绕过;源文档未提供绕过方法,且不建议尝试。

    常见问题

    Astra H 的 LS-CAN 和 MS-CAN 有什么区别?

    LS-CAN 被文档标注为单线的 SW-CAN / GMLAN,承载车速、转速、燃油、里程、TPMS 等;MS-CAN 承载车身与 Info-Display 等。两者的地址与编码各自独立。

    车速是怎么算出来的?

    在 LS-CAN 的 0x108 上取 byte2+3 组成 16 位值,再除以 128。文档示例:0x2098 = 8344,8344 / 128 = 65.1875 km/h。

    燃油液位为什么有时反向?

    文档注明该值「计算取决于传感器,有时反向」,公式为 94 - (值/2) 升。因此同一公式在不同传感器配置下可能得出相反趋势,不能无条件套用。

    Info-Display 的报文为什么超过 8 字节?

    因为它用 ISO-15765-2 把长报文分成多个 CAN 帧(首帧 + 连续帧)。数据块由两字节命令、一字节负载长度、一字节消息类型和若干子包组成,子包再带行 ID、字符数与 UTF-16 字符。

    延伸阅读

    参考资料

    • 项目 01 —— public-can-dbc-datasets/additional/trueffelwurm-opel-astra-h/Opel/Astra/H/LS-CAN/ALL_TYPES.md(本项目车型档案主来源:LS-CAN 全部观测值与逐条说明)。
    • 项目 01 —— public-can-dbc-datasets/additional/trueffelwurm-opel-astra-h/Opel/Astra/H/MS-CAN/Body.md(MS-CAN 的底盘与发动机条目)。
    • 项目 01 —— public-can-dbc-datasets/additional/trueffelwurm-opel-astra-h/Opel/Astra/H/MS-CAN/Info-Display.md(Info-Display 的 ISO-15765-2 分包与消息类型表)。

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

    更新记录

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

  • SAM 项目车 CAN 档案:125 kbit/s 与 37 条消息

    结论:SAM 项目车是一台 125 kbit/s、11 位标准帧的小型电动车,其 CAN 数据档案的价值不在「抓到多少」,而在「修正了多少」:源文档的 DBC 共 37 条消息、161 个信号,并对早期手工整理的布局逐条做了修正——多处把原本当成无符号的字段改正为有符号,还把两个电压刻度由「1」改为实测拟合值。源文档同时明确区分「该车的总线」与「另一台装原厂 BMS 的车」。以下所有结论仅限源文档记录的车辆。

    车辆与适用范围

    本文数据来自第三方开源项目对 SAM 项目车的 CAN 记录与 DBC 修正。项目用某类商业 CAN 记录仪采集 trace,并开发了一个查看器来浏览器与逐帧回放;DBC 的修正以注释形式叠加在文件内。

    项 内容
    车型 源文档以 SAM 指代的一台项目车;具体量产车型未确认
    年款 / 市场版本 源文档未确认
    电控与改装 车上装有自研仪表(STM32)与自研 BMS;源文档同时对照另一台仍装原厂 BMS 的车(在参考日志中的那台)
    采集跨度 两种记录格式(某类商业 CAN 记录工具导出的 `.trc` v2.0 文件,与 SAM 侧记录器导出的纯文本),覆盖行驶、充电与静置场景
    适用范围 仅限源文档记录的这两台车;两车的 BMS 变体不同,报文与周期存在差异

    总线与寻址

    这是一条相对「干净」的台架总线:速率不高、ID 位宽是标准 11 位,车的电控又是自己开发的,因此信号的字节布局大体可从自身设计反推——但仍有多处需要靠实测数据才能定标。

    项 内容
    速率 / 帧格式 125 kbit/s;11 位标准帧
    DBC 规模 37 条消息(`BO_`)、161 个信号(`SG_`)
    修正方式 修正以 `CM_` 注释形式叠加在 DBC 内,逐条标注依据与是否已确认
    多路复用 存在被多路复用的消息(如充电机信息与仪表时间同步共用同一 ID)
    对照来源 除实车 trace 外,还用车辆仪表的报文处理逻辑做交叉对照

    已解码信号

    下表从源文档的修正记录中抽取。项目把依据分成几类:与仪表固件一致(可认为已确认)、与另一条可信信号比值拟合(已确认)、以及仅从原始数据推断、尚无固件旁证(标注为推断)。本文原样保留这些标注。

    信号 位置(ID / DID / 字节) 解码 证据
    电池电压 0x186(消息 390) 每计数 0.0625 V 已确认
    电池电流 0x386(消息 902) 有符号;10 Hz 已确认(由无符号改为有符号)
    电机转速 0x390(消息 912) 有符号 已确认(由无符号改为有符号)
    电机扭矩(实际,skai_torque) 0x290(消息 656)内的 int16 字段 刻度为推断 非固件确认(源文档明确标注)
    直流母线电压 0x290(消息 656) 因子由 1 改为 0.1 已确认(与电池电压比值 0.0997±0.002)
    12 V 电压 0x291(消息 657) 无符号 已确认(由有符号改为无符号;读数约 13.8 V)
    充电机高压 VoltageHV 0x1C0(消息 448) 因子由 1 改为 0.0625 已确认(比值 0.06211±0.00001)
    充电机温度 / 散热器温度 0x1C0(消息 448) 有符号修正 已确认
    电芯电压 0x406,轮转槽位 mV 标定记录(新 BMS 轮转 37 槽,原 BMS 以 cell 0 作填充)
    电芯温度 0x406 摄氏度 标定记录
    BMS 状态 / 剩余能量 0x306(消息 774) — 标定记录(新 BMS 变体下为占位值,原 BMS 为真实值)
    FECU 故障位掩码 0x292(消息 658)B5:B7 位掩码,需按仪表固件的字节序重建 已确认(与仪表报文处理逻辑交叉核对)
    请求扭矩 requested_torque 0x191(消息 401) — 未固件确认

    读取方法与注意事项

    第一条是字节序与符号位。源文档对若干字段做了符号修正:电池电流、电机转速原本被当成无符号,实际是有符号;而 12 V 电压则相反,原本当成有符号,实际是无符号。这类错误不会让程序报错,只会让数值在某个区间里「看起来合理、其实错位」,所以必须逐字段核对。

    第二条是多路复用。源文档指出有消息在仪表侧被复用于多个子报文,例如充电机信息与仪表时间同步共享同一 ID;解析时必须先按子报文的标志位区分,否则会把时间同步的字节当成充电机参数读。项目对涉及掩码的字段做了专门的屏蔽处理。

    第三条是校验和字节序重建。故障位掩码所在的字段不是简单的 24 位小端,源文档依据仪表固件的处理逻辑做了字节序重建,并用一条实车记录验证了修正前后的差异(修正后的取值与预期一致)。这说明「字段看起来是连续的」并不等于「可以直接按小端读」。

    证据等级与边界

    源文档把修正依据分层:与仪表固件一致、或与另一条可信信号做比值拟合的,标为已确认;仅从原始数据推断、没有固件旁证的,明确标注为推断。例如电机扭矩的刻度就是推断值——虽然原始 int16 字段的位置确定,但「一计数等于多少牛米」尚未被固件证实。

    另一条重要边界是「BMS 变体」。源文档把车分成两类:一台装新开发的 BMS(参照原厂设计但不完全相同),另一台在参考日志里仍装原厂 BMS。两者在若干报文上的行为不同——例如电芯电压轮转的填充槽位、某些报文的周期(1 Hz 与 10 Hz)。因此同一辆车的档案也要先确认 BMS 变体。

    边界上必须强调:以上信号位置与刻度都限定在源文档记录的这些车辆与这一版 DBC。不同 BMS 变体、不同固件之间差异明显,跨车使用前必须重新核对。

    常见问题

    为什么这辆车的 DBC 要反复修正?

    因为早期 DBC 是手工整理的,存在真实错误:多个字段被错判符号(电池电流、电机转速被当成无符号;12 V 电压被当成有符号),两个电压的刻度也不对(由 1 改为实测拟合值)。源文档逐条记录了修正依据,并区分「已确认」与「推断」。

    电机扭矩的刻度为什么只标「推断」?

    因为该字段的位置是确定的原始 int16,但「一计数等于多少牛米」没有得到仪表固件的证实,只能从数据推断。源文档没有把它当作已确认值,使用时应保留这一不确定性。

    同一车系为什么会有两套 BMS 行为?

    因为源文档对照了两台车:一台装新开发的 BMS,另一台仍装原厂 BMS。两者在报文周期与电芯电压轮转的填充方式上都不同(例如新 BMS 轮转 37 槽而原 BMS 以 cell 0 填充)。解析前必须先确认 BMS 变体。

    这些修正能直接套到别的车上吗?

    不能。源文档的结论限定在被记录的车辆与 DBC 版本上,不同 BMS 变体与固件之间的差异已被证实存在。跨车使用前必须重新核对。

    延伸阅读

    参考资料

    • 项目 06 —— public-can-dbc-datasets/additional/janniksteiner-sam-can/PROJECT_NOTES.md(本项目车型档案主来源:DBC 修正项、BMS 变体与效率图方法)
    • 项目 06 —— public-can-dbc-datasets/additional/janniksteiner-sam-can/README.md(查看器与记录格式说明)
    • 项目 06 —— public-can-dbc-datasets/additional/janniksteiner-sam-can/SOURCE.md(DBC 规模与来源说明)

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

    更新记录

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