快速上手与配置
CAN配置
硬件配置
终端电阻必须使用 Split termination。禁止使用星形连接接法。必须保证同根CAN线上有且仅有两组终端电阻,并且都在线的两个末端上。
如下图:

软件配置
电机使用 CAN-FD。仲裁段固定为 1Mbps,采样点为0.8。 数据段波特率固定为 5Mbps,采样点为 0.75。
推荐的 CAN 配置命令:
ip link set can0 type can bitrate 1000000 sample-point 0.8 dbitrate 5000000 dsample-point 0.75 sjw 5 dsjw 3 fd on
CAN 配置成功后激活 CAN 线:
注意
必须正确设置采样点,否则发送长帧时必定导致通信失败。有些USB转CAN设备不一定正确支持设置这些参数。如果遇到这种情况,请转而使用 RK3576 等硬件 CAN-FD 支持的 SOC。
配置电机ID
我们的电机使用 CANOpen(CiA301) 协议。CANOpen是工业自动化领域广泛使用的协议,网上拥有诸多教程,在此不做赘述。其中针对PDO做了一些小修改,允许PDO最大长度为 64 字节,以此充分利用CAN-FD的带宽。
如果你想了解CANOpen协议可以看:CANopen Explained
CAN-ID的设置是通过对象字典 2001h, 1h 进行设置的。
例如使用 canopend 工具进行配置,将原本的1号电机改为3号:
关于如何使用 canopend 工具,请参考其 Github 介绍,此处不做解释说明
./canopend can0 -i 0x30 -c stdio # Start the Canopend tool
1 w 0x2001 01 u8 3 # Change Motor No. 1 to Motor No. 3
1 w 0x1010 01 vs "save" # Input save command

新ID断电生效
新ID设置后,断电才会生效。请您务必小心,不要设置了错误的ID。
发送SDO后返回ok即为设置成功
上面修改ID的SDO命令解析
### 命令说明 向节点1的对象字典 `0x2001:01` 写入一个 `uint8_t` 类型数据,数值为 `3`。### SDO请求CAN报文 ### COB-ID解析 因此本次请求报文的 CAN ID 为: ### 数据区解析 对应含义: ### Byte0解析 字段定义: 含义: 因此: ### 应答报文 设备写入成功后返回: 其中: 表示对象 `0x2001:01` 已成功写入数值 `3`。 其他的SDO通讯也和这个大致相同。
使用canopend进行控制测试
下面我们将会使用canopend工具进行简单的控制测试。
请谨慎操作
开始电机控制前,请务必确保周围环境安全。由于在终端中反复发送某个节点的心跳包不是特别方便,这里提供的两个案例都没有使用心跳超时检测。
SDO控制测试
关于SDO控制测试
事实上你应该使用PDO写例如 60FFh 等对象,但我们这里先使用SDO进行CAN通信演示。
请谨慎操作
开始电机控制前,请务必确保周围环境安全
开始之前,我们重新对电机上电,确保电机处于初始状态。假定需要控制的电机为0x01 与 0x02。我们将使用速度模式进行演示。其中1号电机的力矩将被限制到峰值力矩的5%,2号电机将被限制到 80% 峰值力矩。
1 w 0x6060 0 i8 3
2 w 0x6060 0 i8 3
1 w 0x60FF 0 i32 0
2 w 0x60FF 0 i32 0
1 w 0x6040 0 u16 6
2 w 0x6040 0 u16 6
1 w 0x6072 0 u16 50
2 w 0x6072 0 u16 800
等待上述全部写入后,再将控制字写7
最后再写0x0f
此时电机启动使能,目标为 0Rev/s。写入Float32单位的转速即可。这里准备以0.1Rev/s的速度进行测试。
此时两个电机开始以0.1Rev/s的速度旋转,并且两电机的最大力矩不同,其中一个施加较小阻力就会停止,另一个则需要更大的阻力才会停止。

PDO控制测试
显然,使用SDO通信带宽浪费明显。应该尽量使用PDO进行控制,但正如前文所提到的,PDO映射需要根据实际操作的电机数量进行调整,因此本demo仍然只演示控制4个电机的情况,其余情况请根据实际情况调整。
调整PDO Mapping
在CANOpen中,PDO并非只能使用指定的COB-ID,而是可以自由设置。这意味着您可以通过设置多个机器的RPDO的COB-ID为同一个来实现一拖多的功能。但是,原有的RPDO COB-ID是无法满足需求的。因此不仅需要调整所有被控电机的 Mapping,还需要调整 RPDO COB-ID。
听起来有点抽象?
以带力矩上限的速度控制为例,每个电机都需要使用 6072h(最大力矩/Max Torque) 与 60FFh(目标速度/Target Velocity) 这两个对象。因此每个电机都需要六个字节。一共有4个电机,因此需要24字节。
四个电机的CANOpenID分别为0x01, 0x02, 0x03, 0x04。每个电机都控制他们的 6072h(最大力矩/Max Torque) 与 60FFh(目标速度/Target Velocity)。这里我们需要选一个 COB-ID 做所有电机的 RPDO1 COB-ID。
这里我们选择 0x10 节点的 TPDO1 COB-ID(即0x190)。您可以任意选择一个CAN-ID,只要确保不会与其他节点冲突即可。这里推荐选主站的TPDO1,2,3或4。
对于发送的程序来讲,全部24字节的顺序是这样的:
4字节填充对象为 3000h 03h, 2字节填充对象为 3000h 02h
电机1最大力矩(2 Bytes) | 电机1目标速度(4 Bytes) | 电机2最大力矩(2 Bytes) | 电机2目标速度(4 Bytes) | 电机3最大力矩(2 Bytes) | 电机3目标速度(4 Bytes) | 电机4最大力矩(2 Bytes) | 电机4目标速度(4 Bytes)
那么每个电机有两个有效对象。其他字节使用填充即可。我们假定将6072h排在前面,那么对于一号电机,映射应该是这样的:
最大力矩 6072h | 目标速度 60FFh | 4字节填充 | 4字节填充 | 4字节填充 | 4字节填充 | 2字节填充
那么对2号电机来讲,他的RPDO Mapping应该是这样的:
4字节填充 | 2字节填充 | 最大力矩 6072h | 目标速度 60FFh | 4字节填充 | 4字节填充 | 4字节填充
那么对3号电机来讲,他的RPDO Mapping应该是这样的:
4字节填充 | 4字节填充 | 4字节填充 | 最大力矩 6072h | 目标速度 60FFh | 4字节填充 | 2字节填充
那么对4号电机来讲,他的RPDO Mapping应该是这样的:
4字节填充 | 4字节填充 | 4字节填充 | 4字节填充 | 2字节填充 | 最大力矩 6072h | 目标速度 60FFh
保存PDO Mapping
PDO Mapping 映射是可以保存的,避免每次开机都重新设置。具体请查看对象 1010h。保存后每次开机仅需发送NMT指令即可直接开始控制。
关于填充对象
无需拘泥于此形式,得益于PDO的灵活特性,您可以自由安排。假设实际上目标速度需要更高的变动频率,而最大力矩不需要,那么完全可以将所有的最大力矩放到RPDO2,以高频发送目标速度,低频发送最大力矩。
也无需强制所有的电机都处于同一控制模式,完全可以一部分电机处于速度控制模式,一部分电机使用MIT控制模式。只要 Mapping 正确即可。
关于配置自动化与配置持久化
请记住,本质上 canopend 就是发送了一些 can 消息,您完全可以将配置PDO的过程自动化。关于 SDO 协议的具体格式请直接查看丰富的互联网教程。
另外,这些配置除非通过 1010h 对象进行保存,否则每次开机后都会恢复为默认配置。如果您确认不会改变这些配置,那么只要通过 1010h 对象进行保存,即可实现配置持久化。后续开机无需重新配置,仅需发送NMT指令与选择模式,操作控制字。
这里我们需要选一个 COB-ID 做所有电机的 RPDO1 COB-ID。这里我们选择 0x10 节点的 TPDO1 COB-ID(即0x190)。您可以任意选择一个CAN-ID,只要确保不会与其他节点冲突即可。这里推荐选主站的TPDO1,2,3或4。
- 首先给 1400h 01h 写
0x8000_0000 | 0x190失能 RPDO1 - 设置 1400h 02h 传输类型设置为 255
- 设置 1600 00h RPDO 有效映射数为 0
- 设置 1600 01h 应用对象1为 4字节填充 3000h 03h
- 设置 1600 02h 应用对象2为 2字节填充 3000h 02h
- 设置 1600 03h 应用对象3为 最大力矩 6072h 00h
- 设置 1600 04h 应用对象4为 目标速度 60FFh 00h
- 设置 1600 05h 应用对象5为 4字节填充 3000h 03h
- 设置 1600 06h 应用对象6为 4字节填充 3000h 03h
- 设置 1600 07h 应用对象7为 4字节填充 3000h 03h
- 设置 1600 00h 有效映射数为 7
- 最后给 1400h 01h 写
0x0000_0000 | 0x190使能 RPDO1
此时已经完成RPDO配置,接下来输入 2 start 发送 NMT指令,使电机进入 CiA301 的 Operational 状态。
但此时还不能通过 PDO 进行控制,因为还没有配置 CiA402 状态机。因为只需要上电配置一次,也使用 SDO 进行演示。
- 给 6040h 00h 写
0x80清除错误 - 给 6060h 00h 写
0x03设置电机为速度控制模式 - 给 6040h 00h 写
0x06Shutdown - 给 6040h 00h 写
0x07Switch On - 给 6040h 00h 写
0x0fOperation Enable

此时电机可以开始通过 PDO 进行控制。下面以将所有电机最大力矩限制为 80%,目标转速为 1Rev/s 为例。
如果正确配置了所有的电机,此时所有电机都会开始运行。
快速上手:完整控制演示
若您希望先跑通一条从冷启动到持续运转的完整链路,可参考开源仓库 hex-motor-control-test。该仓库提供两个极简 C 语言演示程序(非库),通过 CAN-FD 与 CANopen(CiA301 + CiA402)及 64 字节 PDO 扩展驱动 hexfellow 电机:
| 程序 | 说明 |
|---|---|
demo_mit |
MIT 模式(6060h = 5),以恒定转速运转所有电机 |
demo_velocity |
轮廓速度模式(6060h = 3),以恒定转速运转,并通过每帧 6072h 限制力矩 |
演示覆盖:按电机顺序完成 SDO 初始化、NMT 进入 Operational、CiA402 使能、主站心跳与共享 RPDO 控制循环,以及 TPDO 遥测打印。默认假设电机 CANopen ID 从 1 起连续编号,最多 8 台,固件版本须为 08。
请先按上文完成 CAN 接口的 CAN-FD 配置,再编译运行(以 4 台电机、can0、0.5 rev/s 为例):
更多参数、交叉编译、心跳/RPDO 时序约定等细节见仓库 README。
仅供演示
该仓库仅用于学习与台架验证,非生产级软件;无完善错误恢复与安全联锁。用于任何可能造成伤害或损失的场景前,请自行审计并编写适合产品的驱动。
esp32-c5的控制演示程序
如果您想使用单片机控制电机,可参考hex-motor-esp-control-example。该演示使用了 esp32-c5 以ESP_IDF做为开发框架使用c++,通过 CAN-FD 与 CANopen(CiA301 + CiA402)及 64 字节 PDO 扩展驱动 hexfellow 电机。
该演示程序中封装了一个FreeRTOS电机控制任务类——HexfellowMotorTask。该任务类中包括按电机顺序完成 SDO 初始化、NMT 进入 Operational、CiA402 使能、主站心跳与共享 RPDO 控制循环,以及 TPDO 接收电机运行状态。
并通过串口数据输入输出任务实现实时反馈和调整电机运行状态。默认只输出ID为1的电机状态数据。 通过串口输入如下命令即可实时调整ID为1的电机速度。
默认为只控制一台ID为1的电机,如果你想控制多台电机,你可以通过修改HexfellowMotorController::Config中的成员count,并向HexfellowMotorController::Config的motors成员写入对应的控制参数,得益于PDO的灵活性,可以在一段RPDO中配置不同的电机使用不同的运行模式,只需保证电机的RPDO映射是正确的即可。
比如驱动两台电机,电机0使用MIT模式,电机1使用速度模式。
HexfellowMotorController::Config cfg;
cfg.count = 2; //在此修改需要驱动的电机个数
// 0号电机,默认MIT模式
cfg.motors[0].mode = HexfellowMotorController::HEXFELLOW_MODE_KIND_MIT;
cfg.motors[0].torque_permille = 300;
cfg.motors[0].kp_kd_torque_permille = 770;
HexfellowMotorController::mit_mapping_default(cfg.motors[0].mapping);
// 电机1: 速度模式
cfg.motors[1].mode = HexfellowMotorController::HEXFELLOW_MODE_KIND_VELOCITY;
cfg.motors[1].torque_permille = 300; // 速度模式的最大扭矩限制
该演示中的更多细节请看仓库中的README文档。
上位机的使用
本章节中使用的电机上位机需要配合我们的上位机usb硬件使用,即:USB-CAN HUB。
上位机下载
接线与使用
上位机硬件内已经为每个can接口集成了终端电阻,所以使用上位机时不需要给上位机端的can线末端接终端电阻,只需要给电机末端的can线接口接终端电阻即可。
再使用一条type-c数据线连接到电脑即可。
需初始化can线
Linux或Macos需初始化can线才能连接电机。推荐的开启can线命令参考文档的开头。
使用上位机修改电机ID
- 打开上位机软件,点击Change ID方框,

- 点击connect(连接)按钮(连接按钮左边的输入框表示当前上位机的NodeID,只需保证不与电机的NodeID冲突即可。)

- 然后左边的列表里就会显示当前识别到电机。点击你所需修改的电机

- 在New ID方框中输入你先要修改的ID,后电机Write & Save按钮即可。

注意
写入后给电机重新上电,它会以新 ID 重新出现在下方列表里。
使用上位机驱动电机
- 通过上面介绍的方法接好线后,点击上位机的Motor Control方框。

- 进入 Motor Control 界面后,点击Connect按钮。

- 连接电机成功后会在左边的列表中显示电机的信息。

- 选择你需要控制的电机,然后点击初始化按钮。

- 选择你想要的控制方式,这里以速度模式 ( 0.5rev/s 30%Max torque ) 为例。您可以选择任何的控制方式
按照顺序的操作为:选择控制模式,使能电机,设置当前电机峰值力矩将被限制到峰值力矩的30%,设置速度为0.5rev/s,发送速度。
成功后可以看到电机转动

- 电机运行起来后,可以看到Display窗口实时返回的电机运行数据。也可以电机Chart按钮,切换为图标模式。


- 您也可以选择保存电机运行时的信息,按下Record CSV按钮,下图中标记的2号方框即为存储电机运行时数据的文件地址。

使用上位机设置零点
可以使用上位机设置电机的零点,
选择 Set Zero 模式。

进入之后连接总线。选择你需要修改的电机,先读取当前位置,再输入您需要设置的位置,按下 Save as preset 按钮。无错误警告即为设置成功。

使用上位机体验hex电机的智能力反馈旋钮功能
选择 SmartKnob 模式

连接电机后,选择你想操作的电机,随后在右边选择您想要的模式。

第一个是自定义模式,你可以在仪表盘的下方自定义手感参数。

您也可以在模式的下方调整不同模式的手感强度。

使用上位机的Can数据分析仪
您可以选择 can analyzer模式,来查看所连接的can总线上的消息。

同样需要先点击链接按钮。同时可以点击不同的按钮来操作。
