TN0002 CANopen 通信功能扩展说明
| 项目 | 信息 |
|---|---|
| 文档编号 | TN0002 |
| 文档版本 | Rev. 1.0 |
| 适用产品 | JxServo 模组 / 一体化通讯模组 |
| 适用场景 | CANopen 参数配置、恢复默认参数、电角度校准、版本读取、故障读取与故障项控制、节点复位 |
| 语言 | 简体中文 |
| 最后更新 | 2026-06-05 |
本文整理近期新增或扩展的 CANopen 通信功能,适用于产品交付、现场调试、系统集成和项目维护。除特别说明外,示例均以节点 ID 为 1 的设备为例。
涉及恢复默认参数、故障屏蔽/使能、故障参数覆盖清除、通信速率修改、电角度校准和节点复位的操作会影响设备参数、保护能力、通信状态或电机动作。执行前请确认设备处于安全位置,伺服未使能,主站具备重新连接和断电恢复手段。
1. SDO 与 NMT 约定
CANopen SDO 示例统一采用以下 ID:
| 方向 | COB-ID | 说明 |
|---|---|---|
| 主站 -> 节点 | 0x600 + NodeID | 节点 1 为 0x601 |
| 节点 -> 主站 | 0x580 + NodeID | 节点 1 为 0x581 |
常用 SDO 命令字:
| 命令字 | 方向 | 含义 |
|---|---|---|
0x40 | 主站 -> 节点 | SDO Upload,读取对象 |
0x23 | 主站 -> 节点 | SDO Download,写入 4 字节对象 |
0x60 | 节点 -> 主站 | SDO Download 成功响应 |
0x60 | 主站 -> 节点 | 分段上传续传请求 |
0x43 | 节点 -> 主站 | SDO Upload 返回 4 字节数据 |
0x80 | 节点 -> 主站 | SDO Abort,命令被拒绝 |
SDO 帧中的索引按小端顺序填写。例如对象 0x2540:00 的读取帧为:
CAN ID: 0x601
DLC: 8
DATA: 40 40 25 00 00 00 00 00
2. CAN 通信速率配置 0x2540
支持通过 CANopen SDO 修改 CAN 通信速率,使用厂家自定义对象 0x2540:00。
2.1 速率取值
| 写入值 | 通信模式 |
|---|---|
0 | Classic CAN 500K |
1 | Classic CAN 1M |
2 | CAN FD 1M/1M,不启用 BRS |
3 | CAN FD 1M/2M,启用 BRS |
4 | CAN FD 1M/5M,启用 BRS |
2.2 读取与写入示例
读取当前速率:
CAN ID: 0x601
DLC: 8
DATA: 40 40 25 00 00 00 00 00
设置为 Classic CAN 500K:
CAN ID: 0x601
DLC: 8
DATA: 23 40 25 00 00 00 00 00
设置为 CAN FD 1M/5M,启用 BRS:
CAN ID: 0x601
DLC: 8
DATA: 23 40 25 00 04 00 00 00
写入成功响应:
CAN ID: 0x581
DLC: 8
DATA: 60 40 25 00 00 00 00 00
2.3 生效条件
0x2540 配置会写入 BootPublic。设备不会在线热切换当前 CAN 通信速率,需要复位、重启或重新上电后生效。
执行前请注意:
- 修改速率时建议保持伺服非使能状态。
- 写入成功后,主站仍需继续使用旧速率完成当前通信。
- 设备复位或重新上电后,主站应切换到新速率重新连接。
3. 恢复默认参数 0x1011:03
支持通过 CANopen 标准对象 0x1011:03 恢复应用默认参数。写入 32 位签名 0x64616F6C,也就是 ASCII 字符串 "load",即可触发恢复默认参数。
3.1 执行行为
该操作等价于巨蟹USB上位机中的“恢复系统默认 set_boot=1”功能:
- 固定覆盖
DEFAULT(1)参数组。 - 设置启动参数组为
DEFAULT(1)。 - 不通过切换当前 active/staging 参数组完成;恢复后运行参数会直接切换到默认参数并立即生效。
- 生效不需要重启。
3.2 门禁条件
- 仅允许在伺服未使能状态下触发。
- 如果伺服已使能,设备会直接返回 SDO abort。
- 未使能状态下,设备会自动授予本次恢复所需的二级权限,不需要额外先发授权命令。
3.3 写入示例
节点 ID 为 1 时,主站发送:
CAN ID: 0x601
DLC: 8
DATA: 23 11 10 03 6C 6F 61 64
字段说明:
| 字节 | 含义 |
|---|---|
23 | SDO expedited download,写 4 字节 |
11 10 | index = 0x1011,小端 |
03 | sub-index = 0x03 |
6C 6F 61 64 | value = 0x64616F6C,小端,即 "load" |
成功返回:
CAN ID: 0x581
DLC: 8
DATA: 60 11 10 03 00 00 00 00
判断方式:
0x581 = 0x580 + NodeID(1)。- 首字节
0x60表示 SDO download success。 - 后面的
11 10 03表示确认写入0x1011:03。
3.4 伺服已使能时的返回
如果设备仍处于伺服使能状态,返回:
CAN ID: 0x581
DLC: 8
DATA: 80 11 10 03 22 00 00 08
判断方式:
- 首字节
0x80表示 SDO abort。 - abort code 为小端
22 00 00 08,即0x08000022。 - 含义:当前设备状态不允许执行,需先失能伺服后再发送。
4. 启动电角度校准 0x2654:00
支持通过 CANopen SDO 对象 0x2654:00 启动电角度校准,并通过同一个对象读取校准状态。
4.1 启动命令格式
写入值为 uint32,字段定义如下:
bits 31..24 = 0xCA
bits 23..16 = mode
bits 15..0 = align_current_mA
| 字段 | 含义 |
|---|---|
mode=0 | 直接检出 |
mode=1 | 双向拟合 |
align_current_mA=0 | 使用固件内部默认校准电流 |
align_current_mA != 0 | 指定 d 轴对齐电流,单位为 mA |
4.2 启动示例
节点 ID 为 1,使用双向拟合、默认电流:
CAN ID: 0x601
DLC: 8
DATA: 23 54 26 00 00 00 01 CA
节点 ID 为 1,使用双向拟合、6 A 对齐电流:
CAN ID: 0x601
DLC: 8
DATA: 23 54 26 00 70 17 01 CA
写成功响应:
CAN ID: 0x581
DLC: 8
DATA: 60 54 26 00 00 00 00 00
4.3 读取校准结果
读取 0x2654:00:
CAN ID: 0x601
DLC: 8
DATA: 40 54 26 00 00 00 00 00
返回值格式:
bits 31..24 = 0xAC
bits 23..16 = mode
bits 15..8 = status
bits 7..0 = error_code
| 字段 | 含义 |
|---|---|
status=0 | 校准失败 |
status=1 | 校准成功 |
status=2 | 校准中 |
error_code | 失败错误码,校准成功或校准中时通常为 0 |
返回示例:
校准中:
CAN ID: 0x581
DLC: 8
DATA: 43 54 26 00 00 02 01 AC
校准成功:
CAN ID: 0x581
DLC: 8
DATA: 43 54 26 00 00 01 01 AC
校准失败,错误码 0x03:
CAN ID: 0x581
DLC: 8
DATA: 43 54 26 00 03 00 01 AC
4.4 门禁与错误返回
| 条件 | 返回 |
|---|---|
| 伺服已使能时启动 | SDO abort 0x08000022 |
mode 非法或命令标识非法 | SDO abort 0x06090030 |
说明:
- 该功能只通过
0x2654:00一个 SDO 对象完成启动和结果读取。 - 校准模块本身不主动发送结果,主站应通过 SDO 读取
0x2654:00获取状态。 - 电角度校准可能驱动电机产生动作,执行前请确认设备固定可靠、运动空间安全。
5. 故障读取和故障项控制 0x4500
通过 CANopen SDO 访问 0x4500,可以实现故障读取、故障项屏蔽/使能、覆盖清除和持久化保存。
| 对象 | 用途 |
|---|---|
0x4500:00 | 读取历史报错码 |
0x4500:01 | 写入故障控制命令 |
读取当前活跃/实际发送的报错码时使用 0x603F:00。0x4500:00 与 0x603F:00 的解析差异请参考 FC0001 V2.0报错代码&SDO读取。
5.1 32 位命令格式
写入 0x4500:01 的控制命令为 32 位,小端放入 SDO 数据区;命令字段定义如下:
[31:24] op
[23:16] flags
[15:0] fault code
| 字段 | 含义 |
|---|---|
op=0x01 | 屏蔽指定故障 |
op=0x02 | 使能指定故障 |
op=0x03 | 清除 Flash 中的故障参数覆盖,并重新加载程序默认保护参数到 RAM |
op=0x04 | 保存当前 RAM 故障表到 Flash 覆盖区 |
flags bit0=1 | 屏蔽时同时清除该故障 runtime 状态 |
flags bit0=0 | 屏蔽时不清 runtime |
5.2 速度误差过大示例
速度误差过大的完整故障 ID 为:
0x02000507
SDO 命令中只使用低 16 位故障码:
code = 0x0507
通过 SDO 写 0x4500:01 的常用命令值:
| 写入值 | 作用 | SDO 数据字节 |
|---|---|---|
0x01010507 | 屏蔽速度误差过大,并清除该故障 runtime 状态 | 07 05 01 01 |
0x01000507 | 屏蔽速度误差过大,不清除 runtime | 07 05 00 01 |
0x02000507 | 重新使能速度误差过大 | 07 05 00 02 |
0x03000000 | 清除 Flash 故障参数覆盖,并恢复程序默认保护参数到 RAM | 00 00 00 03 |
0x04000000 | 保存当前 RAM 故障表到 Flash 覆盖区 | 00 00 00 04 |
示例:屏蔽速度误差过大并清除 runtime 状态。
CAN ID: 0x601
DLC: 8
DATA: 23 00 45 01 07 05 01 01
写入成功响应:
CAN ID: 0x581
DLC: 8
DATA: 60 00 45 01 00 00 00 00
5.3 读取报错
读取历史报错码:
CAN ID: 0x601
DLC: 8
DATA: 40 00 45 00 00 00 00 00
读取当前活跃/实际发送的报错码:
CAN ID: 0x601
DLC: 8
DATA: 40 3F 60 00 00 00 00 00
5.4 执行说明
op=0x01/0x02/0x03/0x04均要求伺服处于非使能状态。- 若伺服已使能,SDO 写入会被拒绝,不会修改 RAM 或 Flash。
- 写入后设备会先校验
op和code,非法故障码不会访问故障表。 - 屏蔽或使能会直接修改当前 RAM 故障表中的
enabled字段。 - 设置
flags bit0=1时,只清除指定故障的 runtime 状态,不影响其他故障。 op=0x03等同于巨蟹USB上位机“故障参数存/载”中的P0=3清除覆盖:清除 Flash 覆盖区并重新加载程序默认保护参数到 RAM。op=0x04保存的是当前 RAM 故障表,用于让屏蔽/使能结果掉电保持。- 屏蔽故障会降低保护能力,仅建议用于明确原因、明确风险边界的调试或项目配置场景。
周立功工具 .list 示例:故障读取/屏蔽/使能/清除覆盖/保存
<?xml version="1.0"?>
<SendList m_dwCycles="1">
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="100" iTimes="1" len="1" szname="01_读取0x4500历史报错_确认节点1通讯" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="010600000801000040004501000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="100" iTimes="1" len="1" szname="02_屏蔽速度误差过大_不清runtime_code0507" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="010600000801000023004501070500010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="100" iTimes="1" len="1" szname="03_使能速度误差过大_code0507" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="010600000801000023004501070500020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="100" iTimes="1" len="1" szname="04_屏蔽速度误差过大_并清runtime_code0507" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="010600000801000023004501070501010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="300" iTimes="1" len="1" szname="05_清除Flash故障参数覆盖并恢复默认" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="010600000801000023004501000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="300" iTimes="1" len="1" szname="06_保存当前RAM故障表到Flash覆盖区" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="010600000801000023004501000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="100" iTimes="1" len="1" szname="07_重新读取0x4500历史报错_确认SDO正常" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="010600000801000040004501000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
</SendList>
6. CANopen 版本号读取
标准兼容版本对象保持不变,新增 Boot 和主线版本扩展在 0x3100 firmwareVersion 中读取。
6.1 读取对象
| OD | 名称 | 当前示例值 |
|---|---|---|
0x1008:00 | Device Name 设备名称 | JXZN |
0x1009:00 | Hardware Version 硬件版本 | V2.0.0 |
0x100A:00 | Software Version 软件版本 | V2.0.1 |
0x3100:04 | Boot Version 启动版本 | V1.1.0 |
0x3100:05 | Mainline Version 主线版本 | V2.1.0 |
版本字符串按 ASCII 返回。长度超过 4 字节时,CANopen 会使用分段上传,主站需要在收到首段后继续发送 0x60 续传请求,直到字符串读取完成。
6.2 读取帧示例
读取设备名称 0x1008:00:
CAN ID: 0x601
DLC: 8
DATA: 40 08 10 00 00 00 00 00
读取硬件版本 0x1009:00:
CAN ID: 0x601
DLC: 8
DATA: 40 09 10 00 00 00 00 00
读取软件版本 0x100A:00:
CAN ID: 0x601
DLC: 8
DATA: 40 0A 10 00 00 00 00 00
读取 Boot 版本 0x3100:04:
CAN ID: 0x601
DLC: 8
DATA: 40 00 31 04 00 00 00 00
读取主线版本 0x3100:05:
CAN ID: 0x601
DLC: 8
DATA: 40 00 31 05 00 00 00 00
分段上传续传请求:
CAN ID: 0x601
DLC: 8
DATA: 60 00 00 00 00 00 00 00
周立功工具 .list 示例:读取设备、硬件、软件、Boot 和主线版本
<?xml version="1.0" encoding="UTF-8"?>
<SendList m_dwCycles="1">
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="01_读取厂家设备名_1008" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100004008100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="02_读取硬件版本_1009" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100004009100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="03_硬件版本续传请求" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="04_读取软件版本_100A" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="0106000008010000400A100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="05_软件版本续传请求" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="06_读取Boot版本_3100_04" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100004000310400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="07_Boot版本续传请求" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="08_读取主线版本_3100_05" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100004000310500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
<tagSendUint bIncreaseID="0" bIncreaseData="0" start_index="0" byte_length="0" iInterval="50" iTimes="1" len="1" szname="09_主线版本续传请求" select="1" transmitas="2" e2e="0" e2eDataId="0" obj="01060000080100006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" is_canfd="1"></tagSendUint>
</SendList>
7. CANopen NMT 安全复位
支持通过标准 CANopen NMT 指令复位指定节点 MCU。复位请求会进入通用安全复位流程,不会在收到报文后立即重启。
7.1 复位帧格式
发送 11-bit 标准帧:
| 字段 | 值 |
|---|---|
| CAN ID | 0x000 |
| DLC | 2 |
| Byte0 | 0x81,Reset Node |
| Byte1 | 目标 Node ID,1..127;0 表示广播 |
复位节点 1:
CAN ID: 0x000
DLC: 2
DATA: 81 01
当前也支持:
CAN ID: 0x000
DLC: 2
DATA: 82 01
0x82 是 CANopen Reset Communication。目前该指令和 Reset Node 一样进入安全 MCU 软重启流程;“仅重启 CAN 通信栈”的行为后续再单独拆分。
7.2 复位门禁
复位请求的处理流程如下:
- 收到 NMT reset 指令。
- 判断当前是否处于 operation-enabled。
- 如果仍处于 operation-enabled,拒绝复位。
- 如果不是 operation-enabled,受理复位请求。
- 执行复位前准备:关闭 PWM;有抱闸配置时执行抱闸释放命令。
- 启动
100 ms延迟复位任务。 100 ms后再次检查 operation-enabled。- 如果期间重新进入 operation-enabled,取消本次复位。
- 否则执行 MCU 软复位。
7.3 复位后确认
普通 CANopen 复位不会写备份域,不会进入 Bootloader。只有 Bootloader 复位 reason 才会在最终复位前写入备份域 magic。
节点复位后会重新启动,主站应等待 0x700 + NodeID 的 Boot-up heartbeat,数据字节为 00。
节点 1 的 Boot-up heartbeat 为:
CAN ID: 0x701
DLC: 1
DATA: 00
默认上电后为 Pre-Operational。若需要 PDO 运行,主站再发送:
CAN ID: 0x000
DLC: 2
DATA: 01 01
该帧会让节点 1 进入 Operational。