piper-can
CAN 硬件抽象层,为 Piper 机械臂 SDK 提供统一的 CAN 接口。
概述
piper-can 是 Piper SDK 的底层 CAN 抽象层,提供:
- 统一的
CanAdaptertrait:跨平台的 CAN 接口抽象 - 多后端支持:SocketCAN(Linux)和 GS-USB(跨平台)
- 自动平台选择:默认通过
auto-backendfeature 自动选择合适的后端 - 灵活的 feature 控制:支持显式选择后端和 mock 测试模式
- 类型安全:基于
PiperFrame的强类型 CAN 帧接口
Features
piper-can 使用 Cargo features 来控制后端选择和功能:
| Feature | 说明 | 默认 |
|---|---|---|
auto-backend |
根据平台自动选择后端(Linux: SocketCAN + GS-USB,其他: GS-USB) | ✅ |
socketcan |
强制启用 SocketCAN(仅 Linux) | - |
gs_usb |
强制启用 GS-USB(所有平台) | - |
mock |
禁用所有硬件依赖(用于 CI 测试) | - |
serde |
启用 Serde 序列化支持 | - |
Feature 组合示例
| Feature 组合 | 行为 | 使用场景 |
|---|---|---|
default |
Linux: SocketCAN + GS-USB其他: GS-USB | 生产环境(推荐) |
gs_usb, default-features = false |
仅 GS-USB | 交叉平台测试 |
socketcan, gs_usb |
Linux: 两者都启用其他: 编译失败(仅 Linux) | 高级用例 |
mock, default-features = false |
仅 Mock Adapter | CI 测试 |
Feature 优先级
Mock 优先级最高:
mockfeature 会禁用所有硬件依赖(socketcan 和 gs_usb)- 即使同时启用
auto-backend和mock,也只会编译 Mock Adapter - 用于 CI 测试和无硬件的开发环境
显式 Feature 优先于自动推导:
- 用户显式指定的 features(如
socketcan)优先于auto-backend - 例如:
features = ["auto-backend", "socketcan"]等同于只启用socketcan
优先级顺序:
mock > 显式 features (socketcan, gs_usb) > auto-backend
⚠️ 平台限制
socketcan feature 仅在 Linux 上可用:
# ❌ 错误:在 Windows/macOS 上启用 socketcan 会失败
= { = ["socketcan"] } # 编译失败(nix crate 不支持)
# ✅ 正确做法:依赖 auto-backend 的自动选择
= "0.0.3" # 自动选择平台合适的后端
平台支持
Linux
- 默认后端:SocketCAN(通过
cfg(target_os = "linux")自动启用) - 可选后端:GS-USB(可通过
PiperBuilder在运行时切换) - 特性:
- 内核级性能,支持硬件时间戳
- 通过
ip link工具配置接口和波特率 - 支持标准帧和扩展帧
使用示例:
use SocketCanAdapter;
// 打开 can0 接口
let mut adapter = new?;
// 发送帧
let frame = new_standard;
adapter.send?;
// 接收帧
let rx_frame = adapter.receive?;
macOS / Windows
- 唯一后端:GS-USB(通过
cfg(not(target_os = "linux"))自动启用) - 特性:
- 通过 USB 连接的 CAN 适配器(如 candleLight)
- 跨平台支持(Linux/macOS/Windows)
- 应用层配置波特率和模式
使用示例:
use GsUsbCanAdapter;
// 自动打开第一个可用的 GS-USB 设备
let mut adapter = new?;
// 或通过序列号指定设备
let mut adapter = new_with_serial?;
// 配置波特率并启动
adapter.configure?;
// 发送帧
let frame = new_standard;
adapter.send?;
// 接收帧
let rx_frame = adapter.receive?;
架构设计
PiperFrame:通用 CAN 帧抽象
PiperFrame 是贯穿所有 SDK 层次的中央数据结构:
特性:
- 零成本抽象:
Copytrait,固定大小数组,无堆分配 - 类型安全:编译时检查帧格式
- 时间戳支持:保留硬件时间戳,用于力控和时间敏感应用
CanAdapter Trait
所有 CAN 适配器实现的统一接口:
支持的适配器:
SocketCanAdapter:Linux SocketCAN 接口GsUsbCanAdapter:GS-USB 设备(跨平台)GsUsbUdpAdapter:GS-USB 守护进程客户端(网络)
分离适配器(Splittable Adapter)
对于需要高并发的场景,支持将适配器分离为独立的 RX 和 TX 部分:
use SplittableAdapter;
// 分离为 RX 和 TX 适配器
let = adapter.split?;
// 可以在不同线程中并发使用
spawn;
// TX 线程
for frame in frames
Features
serde(可选)
启用 PiperFrame 的 Serde 序列化支持,用于帧录制和回放:
# Cargo.toml
= { = "0.0.3", = ["serde"] }
使用示例:
use ;
平台自动选择
piper-can 使用 混合模式(target_cfg + features)自动选择平台合适的后端:
| 目标平台 | 默认启用的后端 | 可用的后端 |
|---|---|---|
| Linux | SocketCAN + GS-USB | SocketCAN, GS-USB, Mock |
| macOS | GS-USB | GS-USB, Mock |
| Windows | GS-USB | GS-USB, Mock |
使用默认配置
推荐使用默认配置(auto-backend feature),无需手动指定:
# ✅ 推荐:使用默认配置
[]
= "0.0.3"
显式选择后端
如果需要禁用某些后端或启用特定功能,可以手动配置 features:
# 只使用 GS-USB(移除 SocketCAN 依赖)
[]
= { = "0.0.3", = ["gs_usb"], = false }
# CI 测试(无硬件依赖)
[]
= { = "0.0.3", = ["mock"], = false }
# 启用 Serde 序列化
[]
= { = "0.0.3", = ["serde"] }
运行时后端选择
使用 PiperBuilder 在运行时选择后端:
use ;
// 自动选择(Linux 优先 SocketCAN)
let piper = new
.build?;
// 强制使用 GS-USB(所有平台)
let piper = new
.with_driver_type
.build?;
// 强制使用 SocketCAN(仅 Linux)
let piper = new
.with_driver_type
.build?;
Mock Adapter(测试模式)
mock feature 提供无硬件依赖的 MockCanAdapter,用于 CI 测试和单元测试。
启用 Mock 模式
[]
= { = "0.0.3", = ["mock"], = false }
使用示例
use ;
let mut adapter = new;
// 注入测试帧
let frame = new_standard;
adapter.inject?;
// 接收帧
let rx_frame = adapter.receive?;
assert_eq!;
// 回环模式:发送的帧自动进入接收队列
adapter.send?;
let rx_frame2 = adapter.receive?;
assert_eq!;
Mock 特性
- 回环模式:发送的帧自动进入接收队列
- 零延迟:所有操作立即完成
- FIFO 队列:模拟 CAN 总线的帧顺序
- 超时模拟:支持测试超时逻辑
CI 测试示例
# .github/workflows/test.yml
test-mock:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- name: Test mock backend
run: cargo test --package piper-can --features mock,default-features=false
架构设计
PiperFrame:通用 CAN 帧抽象
PiperFrame 是贯穿所有 SDK 层次的中央数据结构:
特性:
- 零成本抽象:
Copytrait,固定大小数组,无堆分配 - 类型安全:编译时检查帧格式
- 时间戳支持:保留硬件时间戳,用于力控和时间敏感应用
CanAdapter Trait
所有 CAN 适配器实现的统一接口,包括 SocketCanAdapter、GsUsbCanAdapter 和 MockCanAdapter:
错误处理
piper-can 提供结构化的错误类型:
use ;
match adapter.receive
权限要求
Linux
- SocketCAN:通常需要
dialout组权限或sudo - GS-USB:需要 udev 规则或
sudo
安装 udev 规则(推荐):
macOS / Windows
- GS-USB:可能需要管理员权限(首次连接时安装驱动)
性能特性
SocketCAN(Linux)
- 零拷贝:内核级 CAN 处理
- 硬件时间戳:支持硬件时间戳(微秒级精度)
- 高效轮询:使用
poll+recvmsg实现非阻塞接收
GS-USB(跨平台)
- 批量读取:一次 USB 传输可包含多个 CAN 帧
- 接收队列:缓存 USB 包中的多帧,避免丢包
- 实时模式:可配置写超时,实现快速失败(力控场景)
相关文档
- 架构概述(CLAUDE.md)
- GS-USB 实现对比
- 硬件时间戳实现
- Position Control 用户指南
License
MIT OR Apache-2.0