返回
支持国产踩到雷了:禾川 X3E 伺服通过 EtherCAT 接汇川 PLC 跑轴控制。 电机是 23 位绝对值编码器的。 在 PLC 里监控它的实际反馈位置(Actual Position),发现一个
发布

支持国产踩到雷了:禾川 X3E 伺服通过 EtherCAT 接汇川 PLC 跑轴控制。 电机是 23 位绝对值编码器的。 在 PLC 里监控它的实际反馈位置(Actual Position),发现一个

129阅读 1 回复 2026-06-30 23:12发布
关注Ta

1562486690196普通会员楼主

电话/手机:联系客服

支持国产踩到雷了:禾川 X3E 伺服通过 EtherCAT 接汇川 PLC 跑轴控制。 电机是 23 位绝对值编码器的。 在 PLC 里监控它的实际反馈位置(Actual Position),发现一个致命 Bug: 电机单向连续转动时,PLC 读到的位置脉冲数总体是递增的,但是在某些固定的关口(比如累计脉冲到 65536、131072 这些 216 的整倍数时),数值会瞬间向上或者向下‘蹦跳’个几十个脉冲,然后又继续正常递增。 导致我的闭环控制系统每次到了这个地方就会因为‘瞬时速度过大’而发生机械抖动。 这绝对是驱动器往 EtherCAT 总线上传数据时,高低 16 位拼接逻辑写错了,厂商打死不承认,有大佬能提供补丁或者解决办法吗?

以下内容回复后可见

优质评论内容

  • 明扬工控技术客服

    明扬工控技术客服2026-06-30 23:20:30

    亲,这个先别急着认定是禾川驱动器 EtherCAT 高低 16 位拼接 Bug。
    你说跳点固定在:

    65536
    131072
    196608
    ……

    这个特征太明显了:这是 2^16 边界,不是 23 位绝对值编码器的边界。

    23 位编码器单圈边界应该是:

    2^23 = 8388608 脉冲/圈

    所以它每到 65536、131072 这种关口跳一下,更像是PLC 侧、PDO 映射侧、数据类型侧、位置展开算法侧碰到了 16 位边界,而不是编码器本体或驱动器绝对位置原始数据坏了。

    CiA402 里常用的 0x6064 Position actual value 本来就是 32 位 DINT 位置实际值,不应该拆成两个 16 位去自己拼;很多 EtherCAT/CiA402 资料也把 0x6064 定义为 32-bit / DINT 的实际位置对象。

    一、第一嫌疑:PLC 把 32 位位置拆成两个 WORD 读了

    最常见写法是这样:

    LowWord  := PDO_Word0;
    HighWord := PDO_Word1;
    ActualPos := HighWord * 65536 + LowWord;

    看起来没问题,但如果 LowWord 和 HighWord 不是同一个 EtherCAT 周期的快照,就会出事。

    尤其在低 16 位从:

    65535 → 0

    翻转的瞬间,如果 PLC 读到:

    低字已经更新
    高字还没更新

    或者反过来,就会造成一个很短暂的错误位置。

    你说“只蹦几十个脉冲”,不是蹦 65536 个脉冲,也很像这种情况:

    PLC 读数周期
    EtherCAT PDO 更新周期
    速度计算周期
    三者不同步

    低字翻转附近,位置被采到一个“半新半旧”的组合,速度差分就被放大成尖峰。

    正确做法是:

    不要拆 WORD
    直接把 0x6064 映射成 DINT / LINT
    在同一个任务周期里一次性读取
    不要在不同程序段、不同任务里分别取高低字
    二、第二嫌疑:PDO 映射长度错了,只映射了低 16 位

    要检查汇川 PLC 的 EtherCAT 配置里,Actual Position 到底是不是:

    Index: 0x6064
    Subindex: 0
    Length: 32 bit
    Type: DINT / INT32

    如果配置成了:

    WORD
    UINT
    INT
    16 bit

    那到 65535 附近一定会出怪事。

    有些软件界面会把 PDO 显示成两个 WORD,这不代表你应该在程序里按两个 WORD 用。要看最终变量类型是不是 32 位有符号整型。

    三、第三嫌疑:符号扩展或 UINT / DINT 转换错了

    位置实际值通常按有符号 32 位处理。
    如果 PLC 程序里用了:

    UINT
    WORD
    INT
    DWORD
    REAL

    再转来转去,很容易在 16 位边界出毛刺。

    尤其要查这些写法:

    WORD_TO_INT
    INT_TO_DINT
    UINT_TO_DINT
    SHL(HighWord, 16)
    HighWord * 65536
    LowWord + HighWord

    安全写法应该是:

    ActualPos_DINT : DINT;

    然后 EtherCAT PDO 直接绑定到这个 DINT 变量。
    速度计算也用:

    DeltaPos := ActualPos_DINT - LastActualPos_DINT;

    不要先转 INT,也不要用 REAL 做原始位置差分。

    四、第四嫌疑:你用的是绝对编码器“单圈/多圈拼接值”,不是 CiA402 0x6064

    很多伺服除了 0x6064,还会提供厂家对象,例如:

    单圈位置低位
    单圈位置高位
    多圈圈数
    编码器原始值
    机械位置
    反馈位置

    如果你读的是厂家扩展对象,而不是标准 0x6064,那 PLC 可能真的在读两个分开的量:

    单圈低 16 位
    单圈高 16 位
    多圈计数

    这类数据如果没有驱动器内部一次性锁存,主站自己拼接时就容易在 16 位进位点跳动。

    所以建议先做一个对比:

    A:PLC 当前读到的 Actual Position
    B:驱动器调试软件里显示的实际位置
    C:SDO 直接读 0x6064:0 的值
    D:PDO 映射进 PLC 的 0x6064 值

    如果 B、C 都平滑,只有 D 或 PLC 程序变量跳,那就是 PLC 映射/程序问题。

    五、第五嫌疑:速度计算没有做边界保护

    你说“闭环系统因为瞬时速度过大而机械抖动”,这里也要小心。

    很多人速度计算是:

    Velocity := ActualPos - LastActualPos;

    如果 ActualPos 偶发毛刺几十个脉冲,速度就会被放大。
    如果再拿这个速度直接进闭环,会把机械打一下。

    即使最终查明是映射问题,闭环程序也应该加保护:

    如果 DeltaPos > 本周期最大可能位移 × 2
    则判为异常采样,不参与速度计算
    保持上一周期速度
    记录一次 position glitch

    这不是掩盖问题,而是运动控制里必须有的输入防毛刺逻辑。

    六、怎么快速证明是不是驱动器 Bug?
    1. 用 EtherCAT 抓包或主站在线监控看原始 PDO

    重点看 0x6064 的 4 个字节。

    比如位置在 65536 附近,正常应该是:

    65535 = 16#0000FFFF
    65536 = 16#00010000
    65537 = 16#00010001

    EtherCAT 小端显示时,字节顺序会是:

    65535:FF FF 00 00
    65536:00 00 01 00
    65537:01 00 01 00

    如果抓包里原始 4 字节是连续的,而 PLC 变量跳,那就是 PLC 映射或程序问题。

    如果抓包里 4 字节本身就跳,那才有资格怀疑驱动器固件。

    2. 把 0x6064 直接映射成 DINT

    临时建一个最简单工程:

    只映射:
    6041 Statusword
    6064 Position actual value
    606C Velocity actual value

    不做高低字拼接
    不做缩放
    不做闭环
    只记录原始 DINT

    让电机慢慢单向转过 65536、131072。

    如果这个原始 DINT 不跳,说明原程序错了。

    3. 用 SDO 周期读 0x6064 对照 PDO

    虽然 SDO 不适合实时控制,但用来诊断很好:

    PDO ActualPos
    SDO 0x6064 ActualPos
    驱动器软件 ActualPos

    三者对照。

    结果判断:

    PDO 跳,SDO 不跳:PDO 映射/主站解析问题
    PDO 和 SDO 都跳:驱动器实际对象有问题
    只有 PLC 闭环变量跳:程序处理问题
    七、现场临时解决办法

    如果现在项目急着跑,可以先这样做:

    1. 0x6064 直接映射为 DINT,不再拆 WORD
    2. EtherCAT 任务和运动控制任务放同一周期
    3. 只在 EtherCAT 数据更新后读取位置
    4. 速度差分加最大位移限幅
    5. 遇到 1 个周期异常跳变,丢弃该周期速度
    6. 闭环控制不要直接吃未滤波的 Actual Position 差分速度

    例如逻辑上可以这样:

    Delta := ActualPos - LastPos;

    IF ABS(Delta) > MaxDeltaPerCycle THEN
        Velocity := LastVelocity;
        GlitchCounter := GlitchCounter + 1;
    ELSE
        Velocity := Delta / CycleTime;
        LastPos := ActualPos;
    END_IF;

    这个能先防止机械抖动,但根因还是要继续查。

    八、我会优先判断的结论

    这个案例最像:

    第一:
    0x6064 的 32 位位置值被 PLC 拆成高低 16 位处理,低 16 位进位时采样不同步。

    第二:
    EtherCAT PDO 映射长度或 PLC 变量类型错,把 32 位 DINT 当成 WORD/UINT/INT 用。

    第三:
    程序里做了高低字拼接、符号扩展或 REAL 转换,在 65536 边界出错。

    第四:
    读的不是标准 0x6064,而是厂家单圈/多圈/低高字扩展对象,主站自己拼接时没有锁存。

    第五:
    速度差分没有异常采样保护,一个几十脉冲的小毛刺被放大成瞬时速度冲击。

    一句话:

    23 位编码器不会在 65536 这种 16 位边界天然出问题;65536、131072 固定关口跳动,第一反应应该查 32 位位置值在 PLC 侧有没有被拆 WORD、错类型、错同步。先抓原始 PDO 的 4 个字节,如果 EtherCAT 帧里的 0x6064 连续,厂商驱动器就不是第一嫌疑。