1. 这个例子的目标
目标不是一上来写一个巨大的 main.cpp,而是把三电机控制拆成 5 个职责清晰的模块:
CanBus Linux SocketCAN 收发
DamiaoMotor 单电机状态对象
MitPacketEncoder MIT 控制帧打包
MitPacketDecoder 电机反馈帧解包
DamiaoMotorGroup 三电机批量 enable / MIT / refresh / disable
main_3motor_position 业务流程:插值到目标位置
2. 文件结构
damiao_3motor_demo/
├── CMakeLists.txt
├── include/
│ ├── can_bus.hpp
│ ├── damiao_motor.hpp
│ ├── damiao_motor_group.hpp
│ └── mit_packet.hpp
├── src/
│ └── can_bus.cpp
└── app/
└── main_3motor_position.cpp
3. 类职责
| 类 / 文件 | 职责 | 对应 C 写法 |
|---|---|---|
CanBus |
打开 can0,发送 CAN 帧,读取 CAN 帧 | can_init / can_send / can_recv |
DamiaoMotor |
保存 q / dq / tau / online / last_update | motor_state_t |
MitPacketEncoder |
把 q/dq/kp/kd/tau 打包成 CAN 数据 | pack_mit_frame() |
MitPacketDecoder |
把反馈 CAN 数据解析成状态 | unpack_feedback() |
DamiaoMotorGroup |
管理 3 个电机,提供批量控制接口 | motor_group_xxx() |
4. 控制流程
main
→ 创建 CanBus("can0")
→ 创建 DamiaoMotorGroup
→ enableAll()
→ refreshAll() / readFeedbacks()
→ 读取当前位置 q_start[3]
→ 插值生成 q_cmd[3]
→ mitControlAll(cmds)
→ readFeedbacks()
→ 安全检查
→ 到位保持
→ disableAll()
5. 代码文件
6. 编译方式
cd damiao_3motor_demo
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build -j
./build/main_3motor_position --dry-run
默认是 dry-run,不直接发真机控制命令。真机前必须校验 CAN ID、达妙型号范围、MIT 协议打包、位置/速度/力矩限位、急停与通信超时。
7. 真机安全检查
- 确认 can0 已启动,波特率和电机一致。
- 确认 send_can_id / recv_can_id 和实际电机一致。
- 确认 q_min / q_max / dq_max / tau_max 不会撞机械限位。
- 第一次只用很小的目标位移和很低的 kp/kd。
- 控制循环内禁止无保护地突然跳目标位置。
- 通信超时必须 disableAll 或进入安全保持。