返回教程正文

配套源码

README.md

app/bricks/zdt_x57s_can/README.md
zdt_x57s_can Brick:把一台 ZDT X57S 封装成可复用对象app/bricks/zdt_x57s_can/README.md
Markdown179 行
  1. # ZDT X57S CAN Custom Brick
  2. `zdt_x57s_can` 为一台 ZDT X57S 第二代 `FW_Emm` 电机提供 Python 对象 API。每个
  3. `ZdtX57SCan` 实例在构造时绑定一个 `motor_id`;使用一台电机就创建一个对象,使用四台
  4. 电机则由 App 创建四个对象。
  5. 这个 Brick 是 **Linux 原生 CAN 网关的客户端/代理**,不是直接 SocketCAN 驱动:它不
  6. 打开 `can0`,也不发送原始 CAN 帧。真正拥有 `can0` 的进程位于:
  7. ```text
  8. /home/arduino/work/zdt_x57s_can_gateway
  9. ```
  10. ## 数据链路
  11. ```text
  12. App 的 python/main.py
  13. ↓ 单电机 Python 方法
  14. ZdtX57SCan 对象
  15. ↓ 带令牌的换行分隔 JSON/TCP
  16. Linux 原生 zdt_x57s_can_gateway
  17. ↓ SocketCAN can0
  18. CANnectivity / gs_usb / FDCAN1
  19. ↓ 经典 CAN 500 kbit/s,29 位扩展帧
  20. ZDT X57S 第二代 FW_Emm
  21. ```
  22. VENTUNO Q 的 FDCAN 控制器虽然支持 CAN-FD,本协议实际发送的是经典 CAN 帧,不使用
  23. CAN-FD 数据阶段或 BRS。
  24. ## 运行前提
  25. - `can0` 已设为 `500000 bit/s` 并处于 `UP`、`ERROR-ACTIVE`。
  26. - 原生网关已启动,并只监听 Docker 主机内部地址 `172.17.0.1:8766`。
  27. - App 与网关配置了同一个随机令牌;公开源码只保存 `<随机令牌>` 占位符。
  28. - 电机协议为第二代 XS 系列 `FW_Emm`,不能套用旧版 X57 V2 报文。
  29. `brick_config.yaml` 的默认容器访问主机名是 `msgpack-rpc-router`。原生网关是独立部署
  30. 依赖,安装 Brick 本身不会自动安装或启动网关,也不会自动配置 `can0`。
  31. ## 在 App 中引用
  32. ```yaml
  33. bricks:
  34. - zdt_x57s_can:
  35. variables:
  36. ZDT_CAN_GATEWAY_HOST: "msgpack-rpc-router"
  37. ZDT_CAN_GATEWAY_PORT: "8766"
  38. ZDT_CAN_GATEWAY_TOKEN: "<随机令牌>"
  39. ZDT_CAN_REQUEST_TIMEOUT_S: "1.5"
  40. ```
  41. 创建对象时绑定地址:
  42. ```python
  43. from zdt_x57s_can import ZdtX57SCan
  44. motor_1 = ZdtX57SCan(motor_id=1)
  45. print(motor_1.probe())
  46. motors = tuple(ZdtX57SCan(motor_id) for motor_id in (1, 2, 3, 4))
  47. speeds = {motor.motor_id: motor.read_speed() for motor in motors}
  48. ```
  49. Brick 接受协议地址 `1~255`。对象方法不再接收 `motor_id`,从接口上避免一次调用意外
  50. 操作其他地址。多电机聚合、四轮同步、`stop_all` 和底盘运动学应由上层 App 实现。
  51. ## Python API
  52. | API | 是否发送 CAN | 语义 |
  53. | --- | --- | --- |
  54. | `motor_id` | 否 | 返回对象绑定的电机地址 |
  55. | `status()` | 否 | 查询原生网关进程和 `can0` 状态;不能证明电机有应答 |
  56. | `read_speed()` | 是 | 查询当前地址的实时整数 RPM |
  57. | `probe()` | 是 | 调用 `read_speed()` 并返回 `motor_id` 与 `speed_rpm` |
  58. | `enable(confirmation)` | 是 | 发送当前电机使能命令 |
  59. | `disable()` | 是 | 发送当前电机失能命令 |
  60. | `set_speed(rpm, acceleration_level, confirmation)` | 是 | 设置当前电机速度 |
  61. | `stop()` | 是 | 依次尝试零速、立即停止和失能,并汇总结果 |
  62. | `timed_speed_test(...)` | 是 | 执行最长 5 秒的限时运行,`finally` 中停车 |
  63. `status()` 只验证 App 到原生网关的控制链路。确认某个电机 CAN 通信必须调用
  64. `probe()` 或 `read_speed()`,并成功解析该地址返回的 `35 ... 6B` 应答。
  65. ## 只读通信检查
  66. ```python
  67. from zdt_x57s_can import ZdtX57SCan, ZdtX57SCanError
  68. try:
  69. motor = ZdtX57SCan(motor_id=1)
  70. print(motor.status()) # 不发 CAN
  71. print(motor.probe()) # 发送实时速度查询,但不会使能电机
  72. except ZdtX57SCanError as error:
  73. print(error)
  74. ```
  75. 从 App 容器手动执行测试脚本时,需要显式提供 Brick 搜索路径;正常 App 启动脚本会自动
  76. 设置该路径:
  77. ```bash
  78. docker exec \
  79. -e PYTHONPATH=/app/bricks \
  80. zdt-x57s-can-test-main-1 \
  81. python3 -B /app/python/manual_test.py --probe --motor-id 1
  82. ```
  83. ## 运动方法与安全约束
  84. `enable()`、`set_speed()` 和 `timed_speed_test()` 必须接收精确确认口令:
  85. ```text
  86. RUN_ZDT_X57S_V1_0
  87. ```
  88. ```python
  89. motor.timed_speed_test(
  90. rpm=20,
  91. acceleration_level=10,
  92. duration_s=3.0,
  93. confirmation="RUN_ZDT_X57S_V1_0",
  94. )
  95. ```
  96. 当前原生网关限制目标速度绝对值不超过 60 RPM,限时测试不超过 5 秒。非零
  97. `set_speed()` 必须在 500 ms 内持续刷新,否则网关看门狗会尝试零速、停止和失能。
  98. 固定确认口令只是防止误调用,不替代架空底盘、清空周围人员和准备硬件断电。
  99. ## Brick 与原生网关协议
  100. 每个 TCP 连接处理一个请求和一个响应,报文是以 `\n` 结束的 UTF-8 JSON。请求包含
  101. 协议版本、唯一请求 ID、随机令牌、方法和参数:
  102. ```json
  103. {"version":1,"request_id":"d0c1","token":"<随机令牌>","method":"read_speed","params":{"motor_id":1}}
  104. ```
  105. 成功响应:
  106. ```json
  107. {"version":1,"request_id":"d0c1","ok":true,"result":{"motor_id":1,"speed_rpm":0}}
  108. ```
  109. 失败响应中的程序分支应依据稳定的 `error.code`,不能依据英文 `message`:
  110. ```json
  111. {"version":1,"request_id":"d0c1","ok":false,"error":{"code":"can_error","message":"motor 1 speed reply timed out"}}
  112. ```
  113. 客户端会检查响应协议版本和 `request_id`。任一连接、超时、JSON、版本、地址或网关错误
  114. 都会转换为 `ZdtX57SCanError`。
  115. ## 电机 CAN 协议
  116. | 项目 | 当前实现 |
  117. | --- | --- |
  118. | 总线类型 | 经典 CAN,不使用 CAN-FD/BRS |
  119. | 位速率 | `500000 bit/s` |
  120. | 帧格式 | 29 位扩展帧 |
  121. | CAN-ID | `(motor_id << 8) \| packet_index` |
  122. | 当前 `packet_index` | `0` |
  123. | 校验字节 | `0x6B` |
  124. | 成功/拒绝状态 | `0x02` / `0xE2` |
  125. | 功能 | 数据字段 |
  126. | --- | --- |
  127. | 读取实时速度 | `35 6B` |
  128. | 速度应答 | `35 DIR SPEED_H SPEED_L 6B` |
  129. | 使能/失能 | `F3 AB EN SYNC 6B` |
  130. | 速度模式 | `F6 DIR SPEED_H SPEED_L ACC SYNC 6B` |
  131. | 立即停止 | `FE 98 SYNC 6B` |
  132. | 控制应答 | `FUNC 02 6B` 或 `FUNC E2 6B` |
  133. 驱动层只接受匹配当前对象地址、期望命令字和 `0x6B` 校验的应答。以上字节只适用于
  134. 本项目确认的第二代 XS/`FW_Emm` 固定 CAN 协议。