背景

在使用 SOEM 开源 EtherCAT 主站驱动科盛 KS100E 系列伺服驱动器时(就是淘宝买的普菲德那家的驱动器),遇到了一个棘手问题:单独驱动任意一台驱动器都能正常工作(面板显示 88rn),但混合连接不同固件版本(V1.6、V1.8)的多台驱动器时,部分从站无法进入使能状态(面板显示 88ry),且通过 PDO 发送位置指令无效。

本文记录了完整的调试过程、问题根源分析及最终解决方案,希望对遇到类似问题的开发者有所帮助。

硬件与软件环境

  • 主站:Ubuntu + SOEM (Simple Open EtherCAT Master)
  • 从站:科盛 KS100E 伺服驱动器,固件版本 V1.6、V1.8、V1.9 混合
  • 通信周期:10ms,DC 同步模式
  • 控制模式:CSP (Cyclic Synchronous Position Mode)

问题现象

  1. 单台驱动器:使用 ecx_dcsync0 配置 DC 同步,ShiftTime=20000,能够正常进入 OP 状态并使能(面板 88rn),PDO 位置指令响应正常。
  2. 多台相同固件版本:两台 V1.6 或两台 V1.8 可以同时正常工作。
  3. 混合版本(V1.6 + V1.8):
    • 物理位置靠前的从站(1、2号)正常工作;
    • 靠后的从站(3、4、5号)面板显示 88ry(OP 状态但伺服未使能),PDO 位置指令无效。
    • 增大 ShiftTime 或调整 DC 周期均无效。

调试过程

1. 怀疑 DC 同步参数

由于单台和多台同版本都能工作,混合版本失败很容易想到 DC 同步的 ShiftTime 窗口不重叠。尝试扫描 ShiftTime 从 15000 到 25000,步长 500,未找到公共值;甚至将 ShiftTime 增大到 18ms 也无改善。因此排除 DC 参数问题。

2. 检查 PDO 映射

通过 SDO 读取每个从站的 RxPDO(0x1600)和 TxPDO(0x1A00)映射,发现所有从站的映射完全一致:

  • RxPDO: 0x6040 (16bit) + 0x607A (32bit) + 0x60FF (32bit) —— 没有 0x6060
  • TxPDO: 0x6041 (16bit) + 0x6064 (32bit) + … 多个对象,第一个对象为 0x6041

这意味着 PDO 布局相同,但主站程序使用的结构体必须匹配。

3. 对比成功程序与失败程序

  • 成功程序(双电机88rn.c):使用了包含 mode 的 CSP 结构体(ctrl_word + mode + target_position),假设 RxPDO 包含 0x6060。由于实际映射中没有 0x6060,该结构体实际写入位置错位,但巧合地控制字和目标位置仍然写入了正确偏移?其实不是——检查发现成功程序的目标位置偏移为 3(因为有 mode),而实际映射中 0x607A 在偏移 2。为什么还能工作?因为成功程序可能之前从站被修改过映射,或者齿轮比不同导致步长 100 就有明显位移,但实际位置反馈仍能跟随?通过打印位置发现确实跟随,说明虽然 PDO 布局假设错误,但控制字和目标位置仍然写入了正确位置?这似乎矛盾。深入分析后,关键区别在于状态字读取偏移。

  • 失败程序:最初版本中,读取状态字使用 inputs + 2(假设前 2 字节是 0x603F 错误码),而实际 TxPDO 第一个对象就是 0x6041,导致读到的状态字错误,主站认为从站未使能。修正为 inputs + 0 后,所有从站状态字正常,但位置指令仍无效。

  • 位置指令无效的真正原因:目标位置偏移错误。成功程序假设有 mode,目标位置在偏移 3;实际映射中无 mode,目标位置在偏移 2。虽然偏移错了,但为何位置还能变化?因为写入的目标位置实际上写入了 0x60FF(目标速度)的低 16 位?但从位置反馈来看,确实影响了实际位置,说明 0x607A 也被写入了?分析数据:当目标位置写入 100 时,实际位置变为 88,差值不大,说明写入的值确实影响到了正确的位置寄存器。可能因为 0x607A 和 0x60FF 在驱动器内部有某种关联,或者写入错位后部分数据仍落入了 0x607A 的低位。但无论如何,修正偏移后位置指令完全正常。

4. 最终修正

  1. 移除 mode 字段:结构体只包含 ctrl_word 和 target_position,目标位置偏移为 2。
  2. 状态字偏移设为 0:直接从输入区偏移 0 读取 0x6041。
  3. 动态检测 PDO 映射:为每个从站读取映射条目,自动计算偏移,增强兼容性。
  4. 增加调试输出:打印输入区原始数据,帮助验证偏移正确性。

核心代码

以下为最终可用的 slaveinfo 函数关键部分(完整代码见文末)。

PDO 结构体(无 mode)

typedef struct __attribute__((packed)) {
    uint16_t ctrl_word;
    int32_t  target_position;
} CSP_RPDO;

动态偏移检测

for (cnt = 1; cnt <= ctx.slavecount; cnt++) {
    // 读取 RxPDO 映射,找到 6040 和 607A 的字节偏移
    uint16_t rx_pdo = 0x1600;
    // ... 读取 1C12 和 1600 映射条目
    // 默认值:ctrl_off=0, target_off=2
    // 读取 TxPDO 映射,找到 6041 和 6064 的偏移
    // 默认值:status_off=0, pos_off=2
}

访问宏

#define SET_CTRL(slave, val)  (*(uint16_t*)(ctx.slavelist[slave].outputs + offsets[slave].ctrl_off) = (val))
#define SET_TARGET(slave, val) (*(int32_t*)(ctx.slavelist[slave].outputs + offsets[slave].target_off) = (val))
#define GET_STATUS(slave)      (*(uint16_t*)(ctx.slavelist[slave].inputs + offsets[slave].status_off))

调试中发现的关键点

1. 电子齿轮比

通过读取 0x6091 发现,所有从站默认齿轮比为 1:1,即 1 指令单位 = 1 编码器脉冲。电机旋转一圈需要 131072 指令单位。因此步长 100 仅产生约 0.27° 转动,肉眼难以察觉。而原成功程序可能齿轮比不同,导致步长 100 有明显位移。这不是程序错误,而是参数差异。

2. 位置反馈正常

即使步长很小,按 P 打印实际位置,可以看到 actual 值随 target 同步变化,说明 PDO 通信完全正常。

3. 增大步长即可

在交互模式下按 + 键增加步长到 10000 以上,电机转动明显可见。

最终程序功能

  • 支持任意数量从站(最多 5 个,可扩展)
  • 动态检测 PDO 偏移,兼容不同固件版本
  • 交互命令:
    • 1-5 选择电机
    • W/S 点动(步长可调)
    • +/- 调整步长
    • P 打印所有电机位置(SDO 读取)
    • T 安全 SDO 相对运动测试
    • R 读取电子齿轮比
    • D 调试信息(输入区原始数据)
    • Q 退出

完整代码

由于篇幅,完整 slaveinfo.c 请参考文末附件或联系作者获取。关键函数已在上文给出。

总结

  1. 不同固件版本的 KS100E 驱动器 PDO 映射相同,不需要特殊处理。
  2. 状态字偏移必须匹配实际 TxPDO 布局(本例为偏移 0)。
  3. PDO 结构体不应包含 mode 字段,因为映射中没有 0x6060。模式通过 SDO 设置一次即可。
  4. DC 同步参数(ShiftTime=20000)对所有版本有效,无需修改。
  5. 步长小没反应时,先检查齿轮比,不要误判为通信失败。

希望本文能帮助到正在使用 SOEM 和 KS100E 驱动器的开发者。如有问题,欢迎交流。


附件:最终 slaveinfo.c 完整代码(略,可根据上文拼装或私信获取)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐