优化无线/有线CAN,以及控制指令解析
This commit is contained in:
+15
-11
@@ -13,19 +13,19 @@ CAN0 与 CAN1 必须分开解释。本文中的 `seat passenger ...` 只生成
|
||||
|
||||
| 类别 | 规范指令 | 参数约束 | 当前执行逻辑 |
|
||||
| --- | --- | --- | --- |
|
||||
| 水平绝对位置 | `seat passenger horizontal position <0-100>` | 整数百分比 | 有线:`0x300`,一般位置使用 Opcode `0x01`;显式 0% 使用安全归零 Opcode `0x0B`。无线:转换为 seat-ota `0x6A0` MOVE,并以新鲜 `0x302` 确认位置 |
|
||||
| 水平绝对位置 | `seat passenger horizontal position <0-100>` | 整数百分比 | 有线和无线使用相同的固件原生 `0x300`:一般位置为 Opcode `0x01`;显式 0% 为安全归零 Opcode `0x0B`;均以 `0x301/0x302` 闭环确认 |
|
||||
| 坐盆/高度绝对位置 | `seat passenger basin position <0-100>` | 整数百分比;对应固件 Motor 1 | 同上 |
|
||||
| 靠背绝对位置 | `seat passenger backrest position <0-100>` | 整数百分比;对应固件 Motor 2 | 同上 |
|
||||
| 腿托绝对位置 | `seat passenger legrest position <0-100>` | 整数百分比;对应固件 Motor 3 | 同上 |
|
||||
| 水平相对移动 | `seat passenger horizontal relative <forward\|backward> <1-100>` | 移动量为整数百分比;必须存在有效当前位置 | 先根据 CAN0 当前位置计算有界绝对目标;有线优先闭环 Opcode `0x01`,位置未标定且移动量足够小时才使用有界定时回退;无线转换为 seat-ota MOVE |
|
||||
| 坐盆/高度相对移动 | `seat passenger basin relative <up\|down> <1-100>` | 同上 | 同上 |
|
||||
| 水平相对移动 | `seat passenger horizontal relative <forward\|backward> <1-100>` | 移动量为整数百分比 | 先根据 CAN0 当前位置计算有界绝对目标;位置有效时使用闭环 Opcode `0x01`,位置未标定且移动量满足轴级限制时使用 Opcode `0x03` 有界定时回退;有线和无线完全一致 |
|
||||
| 坐盆/高度相对移动 | `seat passenger basin relative <up\|down> <1-100>` | 同上;当前 C++ 台架工具依据实测把 `up` 映射为归一化位置增加、`down` 映射为减少 | 同上;该方向修正仅限 CAN0,不影响 CAN1 |
|
||||
| 靠背相对移动 | `seat passenger backrest relative <forward\|backward> <1-100>` | 同上 | 同上 |
|
||||
| 腿托相对移动 | `seat passenger legrest relative <up\|down> <1-100>` | 同上 | 同上 |
|
||||
| 副驾通风 | `seat passenger vent <off\|low\|medium\|high>` | `low/medium/high` 对应 1/2/3 档 | 有线和无线均发送固件原生 `0x29E`,状态以 `0x4FA` 确认;无线模式把原始 CAN0 帧封装到 MQTT 控制话题 |
|
||||
| 副驾加热 | `seat passenger heat <off\|low\|medium\|high>` | `low/medium/high` 对应 1/2/3 档 | 有线和无线均在开启时先发固件原生 `0x3CE` 模式,再发 `0x29E`,状态以 `0x4FA` 确认 |
|
||||
| 木马模式 | `seat passenger dynamic rocking-horse` | 固件模式 ID 1 | 有线:`0x300` Opcode `0x0E`、ParamA=1;无线:seat-ota `0x6A0` DYNAMIC,运行状态以 `0x306` 或 OTA 应答确认 |
|
||||
| 摇篮模式 | `seat passenger dynamic cradle` | 固件模式 ID 2 | 有线:`0x300` Opcode `0x0E`、ParamA=2;无线:seat-ota `0x6A0` DYNAMIC,运行状态以 `0x306` 或 OTA 应答确认 |
|
||||
| 停止动态模式 | `seat passenger dynamic stop` | 无附加参数 | 有线:`0x300` Opcode `0x0F`;无线:seat-ota STOP ALL |
|
||||
| 木马模式 | `seat passenger dynamic rocking-horse` | 固件模式 ID 1 | 有线和无线均发送 `0x300` Opcode `0x0E`、ParamA=1,并以 `0x301/0x306` 确认 |
|
||||
| 摇篮模式 | `seat passenger dynamic cradle` | 固件模式 ID 2 | 有线和无线均发送 `0x300` Opcode `0x0E`、ParamA=2,并以 `0x301/0x306` 确认 |
|
||||
| 停止动态模式 | `seat passenger dynamic stop` | 无附加参数 | 有线和无线均发送 `0x300` Opcode `0x0F`、ParamA/ParamB=0 |
|
||||
|
||||
为了兼容现有页面,精确指令入口仍接受以下旧别名,但前端“已解析 CAN 控制指令”统一显示上表规范形式:
|
||||
|
||||
@@ -38,11 +38,11 @@ CAN0 与 CAN1 必须分开解释。本文中的 `seat passenger ...` 只生成
|
||||
|
||||
| Byte | 字段 | 说明 |
|
||||
| ---: | --- | --- |
|
||||
| 0 | Opcode | `0x01` 绝对、`0x02` 固件原生相对、`0x0E` 启动动态、`0x0F` 停止动态 |
|
||||
| 0 | Opcode | `0x01` 绝对、`0x02` 固件原生相对、`0x03` 有界定时、`0x08/0x09` 停止、`0x0B` 已知量程归零、`0x0E/0x0F` 启停动态模式 |
|
||||
| 1 | Control | bit0..1 Motor,bit2..3 Direction,bit4..5 Protocol Version=1 |
|
||||
| 2..3 | Sequence | uint16 little-endian |
|
||||
| 4..5 | ParamA | 绝对目标 0..10000;原生相对量为 int16;动态模式为 1/2 |
|
||||
| 6..7 | ParamB | 绝对/相对超时 0 或 100..60000 ms;动态模式必须为 0 |
|
||||
| 4..5 | ParamA | 绝对目标 0..10000;原生相对量为 int16;定时时长 100..60000 ms;归零密钥 `0x4B52`;动态模式为 1/2 |
|
||||
| 6..7 | ParamB | 绝对/相对超时 0 或 100..60000 ms;定时 Duty×10 为 300..1000;归零超时 10..600 s;动态模式必须为 0 |
|
||||
|
||||
当前自然语言相对移动采用“读取当前位置→计算目标→闭环执行”的安全策略,不直接无条件暴露 Opcode `0x02`。这是执行策略与语义命令的区别:用户仍能看到相对语义,底层可根据位置是否有效选择更安全的原始帧序列。
|
||||
|
||||
@@ -59,6 +59,10 @@ CAN0 与 CAN1 必须分开解释。本文中的 `seat passenger ...` 只生成
|
||||
| `0x4FA` | 副驾通风和加热状态 | `passenger.ventilation`、`passenger.heating` |
|
||||
| `0x6A0/0x6A2` | 旧车机 seat-ota 查询/应答 | 保留兼容;位置查询应答转换为同一内部 `0x302` 状态,不与原生状态重复解释 |
|
||||
|
||||
`0x6A0/0x6A2` 只允许作为旧车机状态查询兼容输入。自然语言、设备控件和
|
||||
无线 MQTT 控制白名单均禁止发送 `0x6A0`;无线只是把原生 CAN0 帧封装进
|
||||
`n7/n7-headunit/can/command`,不会改变 CAN ID 或载荷。
|
||||
|
||||
无线状态来自 `n7/n7-headunit/can/state` 时,以上字段使用 `wireless_mqtt_ch0` 标记;有线台架使用 `physical_can`。前端只把这些物理来源显示为实车反馈。
|
||||
|
||||
## 自然语言示例
|
||||
@@ -72,6 +76,6 @@ CAN0 与 CAN1 必须分开解释。本文中的 `seat passenger ...` 只生成
|
||||
## 安全边界
|
||||
|
||||
- 百分比越界、非法方向、未知轴和不在枚举内的动态模式会在生成 CAN 帧前拒绝。
|
||||
- 相对移动缺少有效 CAN0 当前位置时拒绝,不使用虚构位置计算目标。
|
||||
- 相对移动不会使用虚构位置计算目标;位置无效时仅允许编译器已限制时长、方向和 Duty 的 `0x03` 回退,否则拒绝。
|
||||
- MQTT Broker 接受消息只代表已提交;车辆动作是否完成仍以 CAN0 状态反馈为准。
|
||||
- 固件还实现校准、清故障、查询、停止单电机等维护 Opcode,但它们不属于面向自然语言和前端设备控件的控制白名单。
|
||||
- 固件还实现全量程校准、清故障和查询等维护 Opcode,但它们不属于面向自然语言和前端设备控件的控制白名单。
|
||||
|
||||
+16
-2
@@ -20,6 +20,7 @@
|
||||
| 空调温度 | `ac temp <driver\|passenger\|rear> <18-32>` | 温度只接受 18–32 的整数 | `0x1DE` 经典 CAN;`driver`/`passenger` 各发 3 帧(间隔 100 ms),`rear` 发 1 帧;反馈 ID `0x404` |
|
||||
| 空调控制模式 | `ac control <manual\|auto>` | 手动或自动 | `0x1DE` 经典 CAN,连续 3 帧,间隔 100 ms;反馈 ID `0x404` |
|
||||
| 空调循环 | `ac cycle <internal\|external>` | 内循环或外循环 | `0x1DE` 经典 CAN,连续 3 帧,间隔 100 ms;反馈 ID `0x404` |
|
||||
| 单个风口开关 | `outlet <driver-left\|driver-right\|passenger-left\|passenger-right> <open\|close>` | 必须明确指定四个前排电动风口之一;不提供隐式默认目标 | `0x4EF` CAN FD+BRS,使用车机差分抓包确认的逐字节请求,连续 3 帧,间隔 100 ms;反馈 ID `0x4BB`/`0x37B` |
|
||||
| 风口百分比 | `outlet <driver-left\|driver-right\|passenger-left\|passenger-right> percent <0-100> <0-100>` | 依次为左右、上下整数百分比 | `0x4EF` CAN FD+BRS,连续 3 帧,间隔 100 ms;反馈 ID `0x2F5`/`0x37B` |
|
||||
| 风口标定坐标 | `outlet <区域> position <左右坐标> <上下坐标>` | 必须同时满足通用有符号范围和对应风口标定范围 | `0x4EF` CAN FD+BRS,连续 3 帧,间隔 100 ms;反馈 ID `0x2F5`/`0x37B` |
|
||||
| 主驾座椅通风/加热 | `seat driver <vent\|heat> <off\|low\|high>` | `front-left` 可作为主驾输入兼容别名,规范输出仍为 `driver` | `0x431` CAN FD+BRS,连续 3 帧,间隔 100 ms;反馈 ID `0x4FA` |
|
||||
@@ -41,6 +42,19 @@
|
||||
| 遮阳帘动作 | `shade <open\|close\|half\|stop>` | 0/50/100 位置与已验证预设动作复用 | `0x431` 经典 CAN;`open/close/half` 先发 1 帧预设命令,最长监听 `0x41A` 15 s,在匹配目标位置但仍在运动时追加 1 帧 STOP 并确认停止;`stop` 发 1 帧 STOP 并等待停止反馈 |
|
||||
| 遮阳帘位置 | `shade position <0-100>` | 中间位置使用状态反馈闭环并自动停止 | 0/50/100 按上述预设逻辑发送。其他位置先等待最长 2500 ms 的新鲜 `0x41A`;已在目标 ±2% 内且停止则发 0 帧,已到位但仍运动则发 1 帧 STOP。否则用 `0x431` 经典 CAN 发 1 帧开/关启动命令,最长监听 15 s,并在 `finally` 中强制发 1 帧 STOP,再确认位置与停止状态 |
|
||||
|
||||
## 单个风口开关帧
|
||||
|
||||
以下请求来自车机逐个开关四个风口时的 CAN1 差分抓包。每条均为标准 ID `0x4EF`、CAN FD+BRS、DLC 8,连续发送 3 次,间隔约 100 ms:
|
||||
|
||||
| 目标 | `open` 数据 | `close` 数据 |
|
||||
| --- | --- | --- |
|
||||
| `driver-left` | `02 FF FF FF FF 01 FF FF` | `02 FF FF FF FF 02 FF FF` |
|
||||
| `driver-right` | `02 FF FF FF FF 04 FF FF` | `02 FF FF FF FF 08 FF FF` |
|
||||
| `passenger-left` | `03 FF FF FF FF 01 00 00` | `03 FF FF FF FF 02 00 00` |
|
||||
| `passenger-right` | `03 FF FF FF FF 04 00 00` | `03 FF FF FF FF 08 00 00` |
|
||||
|
||||
副驾两个请求的末两字节必须保持为 `00 00`,不能复用主驾请求的 `FF FF`。`0x4BB` 位置签名及部分网关上的 `0x37B/0x50` 开关枚举用于协议反馈匹配;反馈匹配和 CAN ACK 都不能替代实体风口动作核对。
|
||||
|
||||
## 风口标定坐标范围
|
||||
|
||||
| 风口 | 左右范围 | 上下范围 |
|
||||
@@ -62,7 +76,7 @@
|
||||
|
||||
## CAN0 边界
|
||||
|
||||
本文档只描述 CAN1 车身控制白名单。CAN0 只用于副驾座椅,其状态、轴位置、热舒适和动态模式控制必须依据 `seat-ota` 协议独立处理,不得使用本 CAN1 白名单生成或猜测 CAN0 帧。
|
||||
本文档只描述 CAN1 车身控制白名单。CAN0 只用于副驾座椅,其状态、轴位置、热舒适和动态模式控制必须依据 `/home/orin/project511/passenger_seat_firmware` 中的固件原生协议独立处理,不得使用本 CAN1 白名单生成或猜测 CAN0 帧。
|
||||
|
||||
## 实现与回归测试
|
||||
|
||||
@@ -71,4 +85,4 @@
|
||||
- 风口标定范围:`platforms/t2g_cabin_bench/calibration/body_can.yaml`
|
||||
- 完整白名单回归测试:`tests/unit/test_can1_semantic_whitelist.py`
|
||||
|
||||
白名单回归测试展开覆盖 119 条有效命令,并验证越界、非整数、非法枚举和超出风口标定范围的指令不能通过白名单门禁。
|
||||
白名单回归测试展开覆盖 129 条有效命令(包括内/外循环和 8 条单风口开关组合),并验证越界、非整数、非法枚举和超出风口标定范围的指令不能通过白名单门禁。`can_read_trans self-test` 还会将这 129 条指令按 Console 单批 32 条的上限拆成 5 批,逐条验证 CAN1 路由,并用一批 30 条指令覆盖所有 CAN1 控制类别的混合校验。
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
,orin,ubuntu,25.08.2026 09:37,file:///home/orin/.config/libreoffice/4;
|
||||
@@ -0,0 +1,208 @@
|
||||
# can_read_trans 双通道检测与控制
|
||||
|
||||
`can_read_trans` 是当前项目的 Linux C++ 命令行诊断程序。一个进程独占一台
|
||||
ZLG USBCANFD-200U,并同时启动两个通道:
|
||||
|
||||
| 通道 | 用途 | 总线格式 | 状态依据 | 控制依据 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| CAN0 | 右前/副驾座椅 | Classic CAN,500 kbit/s,11 位标准 ID | `0x301–0x306/0x4FA` | 副驾固件原生 `0x300/0x29E/0x3CE` |
|
||||
| CAN1 | 其余车辆设备 | 仲裁 500 kbit/s、数据 2 Mbit/s,Classic CAN + CAN FD/BRS | N7 CAN1 矩阵反馈 | 当前 CAN1 语义白名单 |
|
||||
|
||||
CAN0 的运动、通风、加热、木马和摇篮报文来自
|
||||
`/home/orin/project511/passenger_seat_firmware`。程序不会把旧车机
|
||||
`0x6A0/0x6A2` 当作控制协议。CAN1 的字节编译和反馈解析复用
|
||||
`/home/orin/project511/project-code/canfd/can_read_trans.cpp`,避免维护另一份
|
||||
可能漂移的 CAN1 实现。
|
||||
|
||||
## 构建和离线自检
|
||||
|
||||
```bash
|
||||
make can-read-trans
|
||||
make can-read-trans-test
|
||||
```
|
||||
|
||||
生成的程序位于:
|
||||
|
||||
```text
|
||||
build/can_read_trans/can_read_trans
|
||||
```
|
||||
|
||||
如 CAN 库不在默认目录,可在构建时覆盖:
|
||||
|
||||
```bash
|
||||
make can-read-trans CAN_READ_TRANS_CANFD_ROOT=/path/to/canfd
|
||||
```
|
||||
|
||||
离线自检只核对 ZLG ABI、CAN0 固件字段字节序、动态模式 payload、CAN1 已验证
|
||||
车窗 payload 和白名单拒绝规则,不打开 USB 设备,也不发送 CAN 帧:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans self-test
|
||||
```
|
||||
|
||||
## 状态检测
|
||||
|
||||
持续监听两个通道,按 Ctrl-C 退出:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans monitor
|
||||
```
|
||||
|
||||
监听 5 秒并打印最近状态汇总:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans status --duration-ms 5000
|
||||
```
|
||||
|
||||
只跟踪 CAN0 或 CAN1 的每一条原始接收帧:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans monitor --channel can0 --trace-all
|
||||
build/can_read_trans/can_read_trans monitor --channel can1 --trace-all
|
||||
```
|
||||
|
||||
`--trace-all` 强制只读,不能与 `send` 组合。程序同时轮询 CAN1 的
|
||||
`VCI_Receive` 和 `VCI_ReceiveFD`,不会因为只读了其中一个 SDK 队列而漏掉帧。
|
||||
|
||||
## 持续交互 Console
|
||||
|
||||
只读进入交互终端,可以持续查看状态和校验命令,但不会发送控制帧:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans console
|
||||
```
|
||||
|
||||
确认台架净空、人员远离机构且急停可用后,显式允许本次会话发送白名单命令:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans console --execute
|
||||
```
|
||||
|
||||
程序在同一进程中持续持有 CAN0/CAN1,后台接收线程不会在执行命令时停止,但只
|
||||
缓存解析结果,不会把周期状态持续打印到交互终端。输入一次 `status` 才会打印一次
|
||||
当时缓存的 CAN0/CAN1 状态快照。交互命令会根据两份白名单自动路由,不需要手工
|
||||
添加通道前缀:
|
||||
|
||||
```text
|
||||
can[all]> status
|
||||
can[all]> seat passenger backrest position 35
|
||||
[route] CAN0 <- seat passenger backrest position 35
|
||||
can[all]> ac fan 2
|
||||
[route] CAN1 <- ac fan 2
|
||||
can[all]> outlet driver-left close
|
||||
[route] CAN1 <- outlet driver-left close
|
||||
can[all]> batch seat passenger basin relative up 10 ; ac fan 2 ; light ambient on
|
||||
[batch validated] commands=3 execution=sequential stop-on-hard-failure
|
||||
can[all]> whitelist
|
||||
can[all]> mark before-shade-test
|
||||
can[all]> quit
|
||||
```
|
||||
|
||||
内置交互命令:
|
||||
|
||||
- `status`:一次性显示最近解析出的 CAN0/CAN1 状态,不发送查询帧;
|
||||
- `whitelist`:显示全部可发送语义命令;
|
||||
- `help`:显示 Console 帮助;
|
||||
- `mark <文本>`:打印带时间戳的调试标记;
|
||||
- `quit`/`exit`:复位两个通道、关闭设备并退出。
|
||||
|
||||
批量命令使用 `batch`,各条语义命令用英文分号分隔:
|
||||
|
||||
```text
|
||||
batch seat passenger basin relative up 10 ; ac fan 2 ; light ambient on
|
||||
```
|
||||
|
||||
程序先完成整批预校验,再发送任何帧。任意一条超出白名单、路由到被
|
||||
`--channel` 禁止的通道、命令为空,或同批混用 CAN0 动态模式启动与 CAN0 轴移动,
|
||||
都会拒绝整批且不发送帧。预校验通过后严格按输入顺序串行执行;构造、安全门禁或 SDK
|
||||
提交失败时立即停止,后续命令不再发送。单风口开关的 3 帧全部提交成功、但在 1500 ms
|
||||
内未收到 `0x4BB/0x37B` 匹配反馈时,记为 `submitted-unverified`,不误报实体动作成功,
|
||||
但会继续下一条相互独立的批量命令。最终汇总分别打印 `submitted`、`verified`和
|
||||
`unverified`。其他依赖闭环或前置状态的命令仍保持原有失败停止策略。单批最多 32 条,
|
||||
每条最多 160 个字符。
|
||||
|
||||
CAN1 的 129 条规范/边界白名单命令已在离线自测中拆成 5 批全部通过;另有一批
|
||||
30 条的混合用例覆盖门锁、车窗、空调、循环、单风口开关、风口位置、主驾座椅、灯光和遮阳帘。
|
||||
这证明它们能共同通过批量语义校验并按 CAN1 路由,不等同于无条件完成实体动作:
|
||||
单窗位置需要新鲜 `0x388`,风口标定坐标需要有效标定,座椅记忆需要 PAD 学习值和
|
||||
新鲜 `0x494`,遮阳帘位置需要 `0x41A` 闭环;运行时前置条件不满足会停止该批次。
|
||||
|
||||
可以用 `--channel can0` 或 `--channel can1` 限制本次会话。路由到未选择通道的
|
||||
命令会被拒绝。`console --trace-all` 是只读全帧跟踪模式;为防止抓包过程中误发,
|
||||
它不能与 `--execute` 同时使用。
|
||||
|
||||
## 白名单控制
|
||||
|
||||
先查看程序接受的完整语义命令:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans whitelist
|
||||
```
|
||||
|
||||
发送必须同时显式给出 `send`、目标通道、白名单语义命令和 `--execute`。例如:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans send \
|
||||
--channel can0 \
|
||||
--command "seat passenger backrest position 35" \
|
||||
--execute
|
||||
|
||||
build/can_read_trans/can_read_trans send \
|
||||
--channel can1 \
|
||||
--command "ac fan 2" \
|
||||
--execute
|
||||
```
|
||||
|
||||
以上命令会操作真实硬件,执行前必须确认台架净空、人员远离机构、急停可用,且
|
||||
车辆满足当前项目的安全条件。程序没有 `--id/--data` 一类任意原始帧发送入口;
|
||||
不在 CAN0 或 CAN1 语义白名单中的命令会在构造帧前被拒绝。
|
||||
|
||||
CAN0 相对移动不会直接信任此前无线链路生成的原始帧:
|
||||
|
||||
1. 先读取新鲜、有效的 `0x302` 当前位置;
|
||||
2. 计算限制在 0–100% 内的绝对目标;
|
||||
3. 采用固件原生 `0x300` 闭环执行;
|
||||
4. 只有当前位置不可用且相对量不超过该轴 15% 时,才使用固件限定时长和 Duty
|
||||
的 Opcode `0x03` 回退;程序不直接暴露 Opcode `0x02`;
|
||||
5. 未收到终态反馈时发送固件原生 STOP_ALL 安全帧。
|
||||
|
||||
当前台架已实测 `seat passenger basin relative up/down` 的物理方向与仓库中旧坐标
|
||||
说明相反,因此本 C++ 工具把 `up` 映射为 CAN0 归一化位置增加、`down` 映射为减少。
|
||||
此修正只作用于副驾 CAN0,不会改变 CAN1 主驾坐盆命令或任何 CAN1 帧。
|
||||
|
||||
热舒适命令必须先收到新鲜有效的 `0x4FA`,用它保留未被本次命令修改的另一项
|
||||
功能,防止“调通风”意外关闭加热,或反之。
|
||||
|
||||
CAN0 固件要求除 `STOP_ALL` 外的 16 位 sequence 按有符号环形顺序递增。工具重启
|
||||
后第一次控制若收到 `0x301 RejectReason=8 (SEQUENCE_OLD)`,程序不会猜测或遍历
|
||||
序号,而是使用固件定义的 `STOP_ALL (0x09)` 序号同步屏障;确认 ACK 且四轴均停止
|
||||
后,只重试原语义命令一次。若同步或重试仍失败,则保持 Console 可用并停止自动
|
||||
重试,避免与另一个 CAN0 命令源争抢序号所有权。
|
||||
|
||||
## 反馈判定
|
||||
|
||||
程序明确区分四个层级:
|
||||
|
||||
1. `VCI_Transmit/VCI_TransmitFD=1`:SDK/适配器完成提交;
|
||||
2. CAN ACK:至少一个正常节点确认该帧;
|
||||
3. 协议反馈:CAN0 的 `0x301/0x302/0x306/0x4FA` 或 CAN1 对应状态帧出现;
|
||||
4. 实体动作:机构或车辆设备确实完成动作。
|
||||
|
||||
SDK 返回 1 不能单独证明目标 ECU 接收或执行。CAN0 命令会匹配新的 Sequence、
|
||||
Opcode 和后续状态代次;CAN1 保留既有矩阵反馈等待逻辑。最终仍应结合实体动作、
|
||||
故障位和总线抓包判断。
|
||||
|
||||
## 设备占用和终端电阻
|
||||
|
||||
ZLG 设备应只有一个持有进程。运行本工具前,先停止正在占用同一 USB-CAN 盒的
|
||||
Web 后端、旧版 `can_read_trans` 或 CANPro;否则会出现 `VCI_OpenDevice` 失败。
|
||||
|
||||
两个通道的适配器内部 120 Ω 默认都关闭。只有确认适配器位于对应总线物理端点且
|
||||
拓扑确实缺少该端终端时,才显式增加:
|
||||
|
||||
```bash
|
||||
build/can_read_trans/can_read_trans monitor --can0-termination
|
||||
build/can_read_trans/can_read_trans monitor --can1-termination
|
||||
```
|
||||
|
||||
不要把“收不到帧”直接解释为“需要打开终端电阻”;应先核对供电、共地、CAN_H、
|
||||
@@ -0,0 +1,41 @@
|
||||
# CAN0/CAN1 共享语义协议清单
|
||||
|
||||
CAN 语义控制的单一来源是:
|
||||
|
||||
- `config/can_protocol/semantic_protocol.json`
|
||||
|
||||
该清单同时定义 CAN0/CAN1 的语义语法、能力映射、帧 ID、经典 CAN/CAN FD、BRS、DLC、基础帧模板、固定或动态重复策略、周期和反馈 ID。需要实时状态参与的窗口位置、遮阳帘位置、座椅相对移动和记忆位置仍由命名的 `special_handler` 执行闭环算法;这些算法不得另行定义帧 ID、重复节拍或反馈来源。
|
||||
|
||||
## 生成物
|
||||
|
||||
不要直接修改以下文件:
|
||||
|
||||
- `src/cognitive_agent/generated/can_semantic_protocol.py`
|
||||
- `tools/can_read_trans/generated/can_semantic_protocol.hpp`
|
||||
|
||||
更新清单后执行:
|
||||
|
||||
```bash
|
||||
make can-protocol-generate
|
||||
```
|
||||
|
||||
只检查生成物是否同步:
|
||||
|
||||
```bash
|
||||
make can-protocol-check
|
||||
```
|
||||
|
||||
`make validate`、`make test` 和 `make can-read-trans-test` 都会检查或重新生成协议视图。生成内容携带规范化源文件的 SHA-256,便于确认 Python 与 C++ 来自同一版本。
|
||||
|
||||
## 运行时接入
|
||||
|
||||
- Python CAN1 `NativeCanRuntime` 从生成模块取得支持能力、帧格式、帧 ID、重复策略和反馈 ID。
|
||||
- Python CAN0 `T2GSeatCompiler` 在每个物理命令中附带生成的协议契约;`HardwareSeatExecutor` 会在发送前校验矩阵编码的 ID、DLC 和格式,并使用契约中的反馈 ID。
|
||||
- C++ `can_read_trans` 使用生成头文件匹配 CAN0/CAN1 白名单、打印帮助、取得 CAN0 传输元数据和 CAN1 单风口精确 payload。其自检还会将生成模板与已验证的状态闭环编码器交叉比对。
|
||||
|
||||
## 修改规则
|
||||
|
||||
1. 仅在协议证据明确时修改帧模板、重复次数或反馈 ID。
|
||||
2. 新增命令时必须同时填写 `patterns`、`frames`、`repeat` 和 `feedback_ids`。
|
||||
3. 有状态序列使用 `special_handler`,但传输元数据仍放在共享清单中。
|
||||
4. 先执行离线生成和测试;真实总线验证必须另外明确授权,且分别记录 SDK 提交、CAN ACK、应用反馈和实体动作。
|
||||
@@ -1,10 +1,10 @@
|
||||
# Linux ZLG 车辆状态接入
|
||||
|
||||
当前工程可以通过 ZLG Linux VCI SDK 被动读取 USBCANFD-200U 的 CH1,并把
|
||||
车辆状态送入 `/api/hardware/vehicle-state` 和前端整车孪生。状态轮询使用独立
|
||||
`monitor-only` 桥,桥进程会拒绝所有发送请求。服务启动后由一个常驻监听线程
|
||||
持续缓存最新的已验证状态,HTTP 接口不会为每次前端请求反复开关 USB 设备。
|
||||
Linux 只读状态模式的前端刷新周期为 500 ms;缓存只保留 3 秒内的新鲜反馈,
|
||||
当前工程可以通过 ZLG Linux VCI SDK 使用 USBCANFD-200U 的 CAN0/CAN1,并把
|
||||
车辆状态送入 `/api/hardware/vehicle-state` 和前端整车孪生。只读配置使用独立
|
||||
`monitor-only` 桥,桥进程会拒绝所有发送请求;有线控制配置则在一次请求内由
|
||||
同一桥进程共同持有 CAN0/CAN1,完成安全预检、控制和反馈后关闭。Linux 只读
|
||||
状态模式的前端刷新周期为 500 ms;缓存只保留 3 秒内的新鲜反馈,
|
||||
断线后会自动关闭旧桥并重试连接。监听通道只接受本文列出的 12 个标准帧 ID,
|
||||
同时在 SDK 桥内保留同样的软件过滤,避免把无关总线流量转发给服务进程。
|
||||
|
||||
@@ -19,6 +19,11 @@ Linux 只读状态模式的前端刷新周期为 500 ms;缓存只保留 3 秒
|
||||
- 数据段:2 Mbit/s,`tseg1=10, tseg2=2, sjw=2, brp=1`
|
||||
- 终端:默认不启用适配器内部 120 欧;只能按实际拓扑调整
|
||||
|
||||
有线真实执行采用一个设备 owner 同时初始化两个通道:CAN0 为最新副驾座椅
|
||||
经典 CAN 500 kbit/s,CAN1 为车辆 ISO CAN FD 500 kbit/s / 2 Mbit/s。副驾控制
|
||||
使用 `0x300/0x29E/0x3CE`,状态反馈覆盖 `0x301–0x306/0x4FA`。Linux CAN0
|
||||
不依赖旧 IAR profile、自动烧录或 T2G combined 固件检查。
|
||||
|
||||
前端车辆概况依赖 `0x342`(档位)、`0x4EB/0x07`(车速)和 `0x407`
|
||||
(门锁)。主驾座椅依赖 `0x4FA`、`0x494`。收到其他帧不能替代这些已验证
|
||||
反馈。车身设备还会按帧独立更新:`0x388` 四窗、`0x404` 空调、`0x41A`
|
||||
@@ -28,7 +33,7 @@ Linux 只读状态模式的前端刷新周期为 500 ms;缓存只保留 3 秒
|
||||
|
||||
前端“车辆连接方式”提供两个相互独立的传输选项:
|
||||
|
||||
- 有线控制:状态和控制都走后端 ZLG CH1。
|
||||
- 有线控制:副驾座椅状态和控制走后端 ZLG CAN0,其余车辆状态和控制走 CAN1。
|
||||
- 无线控制:状态订阅 `n7/n7-headunit/can/state`,控制发布到
|
||||
`n7/n7-headunit/can/command`;默认 Broker 为 `127.0.0.1:1883`。MQTT CAN0 专用于
|
||||
副驾座椅,MQTT CAN1 专用于除副驾座椅外的车辆状态和控制。
|
||||
@@ -89,22 +94,25 @@ FD+BRS。车机按通道、控制 ID 和帧类型推断预期反馈 ID。
|
||||
|
||||
无线通道边界为:
|
||||
|
||||
- CAN0:经典 CAN 副驾座椅;直接状态接收 `0x301–0x307`、`0x4FA`。当前车端
|
||||
- CAN0:经典 CAN 副驾座椅;直接状态接收 `0x301–0x306`、`0x4FA`。当前车端
|
||||
还会以只读 `0x6A0` `SEAT_INFO(0x60)` 查询和 `0x6A2` 响应上报四轴 Hall
|
||||
位置、范围和标志。后端只配对 `C7/7C`、相同序号、`status=0` 的查询响应,
|
||||
再转换成统一的四轴 `0x302` 状态;查询帧不会被当作普通动作执行。
|
||||
无线副驾控制只允许 `0x6A0` 中固件明确提供的运行时 opcode:
|
||||
`STOP(0x63)`、`MOVE(0x64)`、`HEARTBEAT(0x65)` 和
|
||||
`DYNAMIC_START(0x66)`,并等待匹配序号/opcode 的 `0x6A2` 成功响应及新鲜
|
||||
四轴位置反馈。刷写、进入 Bootloader、测试、校准和回零 opcode 全部拒绝;
|
||||
旧 `0x29E/0x300/0x3CE` 不会在该无线 CAN0 路径发布。
|
||||
无线副驾控制直接发布与有线相同的固件原生帧:运动/停止/木马/摇篮使用
|
||||
`0x300`,通风/加热使用 `0x29E/0x3CE`;运动等待 `0x301/0x302`,动态模式
|
||||
等待 `0x301/0x306`,热舒适等待 `0x4FA`。`0x300` 只开放语义运行时子集
|
||||
`0x01/0x02/0x03/0x08/0x09/0x0B/0x0E/0x0F`,并逐字段校验版本、轴、方向、
|
||||
sequence、ParamA 和 ParamB。刷写、进入 Bootloader、测试、全量程校准、查询
|
||||
和清故障全部拒绝;`0x6A0` 不再允许作为无线控制帧发布。
|
||||
- CAN1:除副驾座椅以外的整车 CAN;状态和控制继续使用项目中已有的 CH1
|
||||
车辆白名单。CAN0 控制 ID 不能经 CAN1 发送,CAN1 控制 ID 也不能经 CAN0
|
||||
发送。
|
||||
|
||||
两个通道的协议来源严格分离:
|
||||
|
||||
- CAN0 只以 `/home/orin/project511/seat-code-file/seat-ota` 副驾固件为准;
|
||||
- CAN0 只以 `/home/orin/project511/passenger_seat_firmware/firmware` 与
|
||||
`/home/orin/project511/passenger_seat_firmware/Passenger_Seat_Controller_demo`
|
||||
中的副驾固件协议为准;
|
||||
入站状态必须是 11 位标准帧、经典 CAN、无 BRS、DLC 8。
|
||||
- CAN1 只以
|
||||
`/home/orin/project511/project-code/canfd/CAN矩阵表_filled.xlsx` 为准。
|
||||
@@ -124,8 +132,8 @@ MQTT 消息自带的 `can0Seat.parsed` 和 `can1Vehicle.parsed` 只可用于车
|
||||
|
||||
每个 MQTT 总线视图只会收到本通道反馈。发布完成仅代表 Broker 接收消息;
|
||||
座椅和整车执行器仍必须等待对应状态 ID 与目标字段匹配,才会报告动作成功。
|
||||
当前 seat-ota 固件只提供四轴位置和动态模式控制,没有副驾加热/通风运行时
|
||||
opcode;无线模式收到这两类副驾请求会在发布前明确失败,不会伪造反馈。
|
||||
副驾加热/通风使用固件已有的 `0x3CE/0x29E` 控制和 `0x4FA` 反馈;无线模式
|
||||
与有线模式共享同一套原始帧、参数白名单和反馈闭环,仅传输载体不同。
|
||||
|
||||
车端现有 `n7-can-signals/v1` 状态封装也可直接发布到
|
||||
`n7/n7-headunit/can/state`。后端优先从顶层 `signals` 读取,避免与嵌套副本重复;
|
||||
@@ -170,11 +178,11 @@ getfacl -p /dev/bus/usb/001/006
|
||||
|
||||
## 服务配置
|
||||
|
||||
将 `config/environments/linux_vehicle_state.example.env` 中的配置复制到仓库
|
||||
根目录 `.env`,并按实际 SDK 位置修改
|
||||
`COGNITIVE_AGENT_ZLGCAN_LINUX_LIBRARY`。不要设置硬件批准令牌;此时
|
||||
`vehicle_can.state_configured=true`,但 `vehicle_can.configured=false`,所以只
|
||||
允许状态同步,前端真实执行保持锁定。
|
||||
只读 CH1 状态监听使用 `config/environments/linux_vehicle_state.example.env`。
|
||||
CAN0/CAN1 有线控制使用
|
||||
`config/environments/linux_wired_dual_channel.example.env`,复制到仓库根目录
|
||||
`.env` 后按实际 SDK 位置修改 `COGNITIVE_AGENT_ZLGCAN_LINUX_LIBRARY`。本地有人
|
||||
值守台架可以显式关闭逐请求令牌;共享或远程环境应恢复令牌门禁。
|
||||
|
||||
启动:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user