# python-can-candle `python-can-candle` 适合在 Windows 或 Linux 上使用 Python 直接访问 CAN 和 CAN FD 设备。 开发板包含两颗 MCU,每颗 MCU 提供两个 CAN/CAN FD channel,因此通常可 检测到两个 USB 设备、共四个 channel。USB 设备枚举顺序和 channel 编号不能 直接对应板上接口丝印,首次使用时应逐路确认。 `python-can-candle` 主要用于 Windows Python 程序控制,以及需要跨平台统一 `python-can` API 的场景。 ## 安装 本说明基于 `python-can-candle 1.2.4`: ```bash python -m pip install "python-can-candle==1.2.4" ``` SANPO 集成板已经通过 Windows WCID 自动绑定 WinUSB, 不需要使用 Zadig,也不需要安装驱动。 安装后查看版本: ```bash python -m pip show python-can-candle candle-api python-can ``` ## 检测通道 ```python import can for config in can.detect_available_configs("candle"): print(config) ``` 开发板通常输出四项,channel 格式类似: ```text SERIAL_0:0 SERIAL_0:1 SERIAL_1:0 SERIAL_1:1 ``` `SERIAL_0`、`SERIAL_1` 是两颗 MCU 各自的 USB 序列号。序列号可以稳定区分 两颗 MCU,但不能仅凭序列号判断它对应板上的哪两路接口。 ## 经典 CAN 以下示例在指定 MCU 的 channel 0 上使用 1 Mbit/s,发送一个标准帧并等待回复: ```python import can serial = "替换为实际序列号" with can.Bus( interface="candle", channel=f"{serial}:0", vid=0x1209, pid=0x2323, manufacture="SANPO", product="SANPO gs_usb CDC Composite fdV8", bitrate=1_000_000, sample_point=80.0, ignore_config=True, ) as bus: message = can.Message( arbitration_id=0x123, is_extended_id=False, data=[0x11, 0x22, 0x33, 0x44], ) bus.send(message, timeout=1.0) reply = bus.recv(timeout=1.0) print(reply) ``` 示例 ID 和数据没有实际设备含义,应替换为所连接设备的协议内容。 ## CAN FD 以下示例配置仲裁段 1 Mbit/s、数据段 5 Mbit/s,并发送开启 BRS 的 CAN FD 帧: ```python import can serial = "替换为实际序列号" with can.Bus( interface="candle", channel=f"{serial}:0", vid=0x1209, pid=0x2323, manufacture="SANPO", product="SANPO gs_usb CDC Composite fdV8", fd=True, bitrate=1_000_000, sample_point=80.0, data_bitrate=5_000_000, data_sample_point=75.0, ignore_config=True, ) as bus: message = can.Message( arbitration_id=0x123, is_extended_id=False, is_fd=True, bitrate_switch=True, data=bytes(range(16)), ) bus.send(message, timeout=1.0) ``` SANPO SPINE 的 CAN FD 数据段支持 2/3/4/5 Mbit/s。使用 2/3/4 Mbit/s 时 推荐 `data_sample_point=80.0`;使用 5 Mbit/s 时推荐 `data_sample_point=75.0`。 ## 同一颗 MCU 的两个通道 同一颗 MCU 的两个 channel 应由一个 `CandleBus` 实例共同打开: ```python import can with can.Bus( interface="candle", channel=[0, 1], serial_number="替换为实际序列号", bitrate=1_000_000, sample_point=80.0, ignore_config=True, ) as bus: message = can.Message( arbitration_id=0x123, is_extended_id=False, channel=1, data=[0x01, 0x02], ) bus.send(message, timeout=1.0) ``` 这里的 `Message.channel` 只用于主机选择物理 CAN 通道,不会写入 CAN 数据, 也不是 SANPO 自定义通道报文。访问完整四路 CAN 时,应分别为两颗 MCU 创建 一个 `CandleBus`。 ## 小米 CyberGear 示例 示例程序: [python-can-candle CyberGear 逐步使用说明](https://gitcode.com/sanpo/robot/blob/main/products/spine/v8/demo/guides/pythoncan-cybergear.md) 先执行只读设备枚举,不发送 CAN 帧: ```bash python pythoncan_cybergear_demo_v8.py --list-devices ``` 确认两颗 MCU 的序列号和物理通道映射后,再进行空载初始化测试。以下命令会 配置 CAN 并向电机发送初始化、使能和停止指令: ```bash python pythoncan_cybergear_demo_v8.py \ --enable-motion \ --init-only \ --device-serials "SERIAL_0,SERIAL_1" \ --motor-map "0/0:1,2,3;0/1:4,5,6;1/0:7,8,9;1/1:10,11,12" ``` `0/1` 表示 `--device-serials` 中第 0 颗 MCU 的 channel 1。首次运行必须空载, 确认急停有效,并根据实际接线调整电机 ID 和通道映射。 ## 使用限制 - 同一个 gs_usb 接口不能同时由 CANgaroo、`python-can-candle` 或其他 WinUSB 程序占用。运行 Python 示例前应关闭 CANgaroo 的连接。 - 同一个物理 CAN/CAN FD 通道不要同时由 USB 透传、管理口协议、SPI 或离线 任务发送数据。 - `python-can-candle` 打开通道时会重新配置波特率;这些设置不会作为用户配置 永久保存。 - Linux 下如果接口已经由内核 `gs_usb` 驱动生成 `canX`,应直接使用 SocketCAN,避免两个主机驱动竞争同一 USB 接口。 ## 常见问题 | 现象 | 处理方法 | | --- | --- | | `Access denied` 或设备忙 | 关闭 CANgaroo、其他 Python 进程及占用该 WinUSB 接口的软件 | | 能发送但设备不回复 | 检查 channel 与物理接口映射、波特率、终端电阻、设备 ID 和供电 | | CAN FD 通信错误 | 确认仲裁段、数据段波特率及采样点与总线中所有设备一致 |