SOEM 驱动多台 KS100E 伺服驱动器(不同固件版本)的完整解决方案
背景
在使用 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)
问题现象
- 单台驱动器:使用
ecx_dcsync0配置 DC 同步,ShiftTime=20000,能够正常进入 OP 状态并使能(面板88rn),PDO 位置指令响应正常。 - 多台相同固件版本:两台 V1.6 或两台 V1.8 可以同时正常工作。
- 混合版本(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. 最终修正
- 移除 mode 字段:结构体只包含
ctrl_word和target_position,目标位置偏移为 2。 - 状态字偏移设为 0:直接从输入区偏移 0 读取
0x6041。 - 动态检测 PDO 映射:为每个从站读取映射条目,自动计算偏移,增强兼容性。
- 增加调试输出:打印输入区原始数据,帮助验证偏移正确性。
核心代码
以下为最终可用的 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 请参考文末附件或联系作者获取。关键函数已在上文给出。
总结
- 不同固件版本的 KS100E 驱动器 PDO 映射相同,不需要特殊处理。
- 状态字偏移必须匹配实际 TxPDO 布局(本例为偏移 0)。
- PDO 结构体不应包含 mode 字段,因为映射中没有
0x6060。模式通过 SDO 设置一次即可。 - DC 同步参数(ShiftTime=20000)对所有版本有效,无需修改。
- 步长小没反应时,先检查齿轮比,不要误判为通信失败。
希望本文能帮助到正在使用 SOEM 和 KS100E 驱动器的开发者。如有问题,欢迎交流。
附件:最终 slaveinfo.c 完整代码(略,可根据上文拼装或私信获取)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)