ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Codesys虚拟手轮调试:SMC_FreeEncoder驱动EtherCAT轴实战

Codesys虚拟手轮调试:SMC_FreeEncoder驱动EtherCAT轴实战 干设备调试这几年我越来越离不开Codesys里的软运动控制。最近用SMC_FreeEncoder给ECAT轴搭了一个虚拟手轮调试工具彻底告别了笨重的物理手轮和按钮点动今天把整个思路和实操过程完整复盘一遍。这个方案对那些经常做单机调试、对刀对基准、机械验机的朋友尤其有用不管你是刚接触软运动控制还是已经在工程上用过手轮都能从中找到可以直接落地的东西。1. 虚拟手轮调试工具的价值定位与方案选型1.1 设备调试台上缺少一个“顺手的旋钮”做过现场调试的人都懂这种尴尬设备出货前操作员想在触摸屏上动轴但按钮点动永远只有固定速度太快怕撞件太慢等到心慌。有的设备机械结构复杂对刀、对基准、检查正负方向这些精细操作靠按钮根本做不出“手感”。物理手轮确实好用但问题也不少。一台设备如果每个需要手动操作的轴都配一个物理手轮成本、安装空间、接线量都上去了。增量编码器手轮要接A/B相脉冲还要考虑5V/24V电平匹配有的手轮自带零点信号接线稍不注意就丢脉冲。更别提有些机柜已经塞得满满当当根本没地方再开一个手轮安装孔。我之前也被这个问题逼得没办法试过用触摸屏上的“软手轮”控件但触摸屏没有真实的旋转反馈操作员根本不知道当前转到哪一格误触风险也大。后来在Codesys里用SMC_FreeEncoder做了个纯软件虚拟手轮效果出乎意料地好调试效率提升了一大截。SMC_FreeEncoder能在软PLC内部模拟出一个增量编码器的输出信号不占用任何物理IO也不需要额外接线只要在程序里触发一下它就能按设定速度、加速度“转”起来并实时输出当前编码器位置。配合SoftMotion的轴跟随功能可以把ECAT轴变成被虚拟手轮驱动的从轴实现真正意义上的“虚拟手轮”。1.2 为什么是SMC_FreeEncoder而不是其它方案可能有人会问Codesys里有MC_MoveJog直接让轴点动不就行了吗为什么还要绕一圈用虚拟编码器MC_MoveJog确实能做手动点动但它本质上是一个速度指令轴按设定速度持续运动。手轮调试的核心诉求不是“以一个速度跑”而是“手轮转多少轴就走多少转得快就走得快停下来就立刻停下”。这种位置跟随关系用Jog很难实现而且Jog的点动速度是固定值没有手轮那种“微调一格”的精细感。还有人会想到用硬件高速计数模块接物理手轮。这个方案能用但成本高、需要额外配置而且我要在软件里做倍率切换、正反向控制、限位互锁全部得写一堆逻辑灵活性远不如纯软件方案。SMC_FreeEncoder在这个问题上是比较优雅的解法。它输出的是一路“虚拟编码器信号流”SoftMotion的轴功能块可以直接把它当成真实编码器的位置来用。我们只需要在程序里调用一次它就会在后台持续生成脉冲计数值不占物理接口、没有接线衰减、可反复启停且不丢位置。用个生活类比来说SMC_FreeEncoder就像一个“虚拟信号发生器”专门给运动控制发脉冲。真实手轮是物理设备手一转动就有A/B相脉冲进来虚拟手轮则是在程序内部模拟出这些脉冲再通过SoftMotion的位置跟随功能块把它“喂”给ECAT轴。结果就是手轮转一圈、脉冲数增加多少、轴跟着走多远全部由参数控制调试起来非常灵活。2. SMC_FreeEncoder功能块内部机制与关键参数2.1 引脚功能的完整解读SMC_FreeEncoder这个功能块上手并不复杂但几个关键参数如果不理解透很容易出现“手轮转了但轴不动”或者“一启动轴就飞车”的情况。以我常用的版本为例核心引脚大致如下参数名类型作用说明bExecuteBOOL启动虚拟编码器。上升沿触发启动置FALSE时停止计数bAccEnableBOOL是否启用加减速斜坡。TRUE时按设定的加速度平滑提速/减速udiAccelerationUDINT加速度值决定速度变化的快慢。单位需根据库版本换算通常按转/分钟²udiInstantSpeedUDINT目标转速单位通常为转/分钟rpmudiResolutionUDINT编码器分辨率即每转输出的脉冲数相当于物理编码器的PPRudiCurrentPositionUDINT当前编码器位置计数值程序里读这个值就知道手轮“转了多少”需要注意不同Codesys版本和SoftMotion库版本里个别引脚名称或单位可能有差异。比如有的版本把udiInstantSpeed叫udiSpeed有的版本输出位置变量叫udiCurrentPosition而不是udiPosition。这类细节建议以你本机安装的库文件说明为准但整体逻辑是一致的。在实际使用中bExecute是比较容易出错的地方。如果只是给它一个很窄的脉冲TRUE保持一个周期就变FALSE功能块会认为是一次性执行请求可能还没转到目标速度就停了。所以如果你拿按钮控制启动需要把按钮信号直接接到bExecute上保持持续使能而不是做上升沿触发。2.2 从“信号发生器”角度理解工作流程理解SMC_FreeEncoder的底层行为我觉得把它当成“信号发生器”最清晰。启动后它内部会有一个计数器从0开始累加累加速度由udiInstantSpeed和udiResolution共同决定每秒钟增加的脉冲数就等于转速乘以每转脉冲数再除以60。如果不启用bAccEnable计数器从0立刻跳到目标速度相当于手动开关一开就全速转这样轴会有冲击。如果启用bAccEnable它会按照udiAcceleration设定的斜率从0逐渐加速到目标速度停下来时也一样这样模拟出来的手轮手感更像真实设备。它输出的udiCurrentPosition本质上是“手轮已经转过的累计脉冲数”。这个值只增不减当然也可以反转方向看库版本支持类型是UDINT无符号整数意味着它会在到达最大值后回绕为0。真实物理编码器也有类似问题但调试时如果不处理回绕位置跟随逻辑就可能出大问题。后面第3章我会讲怎么处理这个坑。还有一点要特别说清楚SMC_FreeEncoder并不读取物理位置它只是一个开环的位置指令发生器。如果轴被机械卡住、被限位挡住或者伺服报错虚拟手轮这边是不知道的它的脉冲数还在继续涨。所以使用虚拟手轮调试时软件限位、急停回路、使能互锁这些东西一个都不能少这个后面实操部分还会展开。2.3 编码器分辨率、速度、位置换算的“算账”方法既然手轮的本质是脉冲那么手轮转一圈轴走多远就取决于分辨率、机械传动比、丝杠导程以及比例因子的综合换算。先建立一个基本公式。虚拟手轮的输出脉冲频率为脉冲频率pps udiInstantSpeedrpm× udiResolution脉冲/转/ 60如果轴侧每转对应的机械位移是D比如丝杠导程10mm减速比1:1则D10mm/转那么在1:1跟随模式下手轮转一圈轴的理论位移是轴位移 手轮脉冲数 / 分辨率× D × fPositionScale举个例子udiResolution1000手轮转了5000个脉冲也就是5圈。轴侧丝杠导程10mmfPositionScale0.1那么轴实际走了手轮转数 5000 / 1000 5转 轴位移 5 × 10mm × 0.1 5mm这就是一个典型的“手轮转5圈轴走5mm”的微调场景非常适合对刀、对基准这类精细操作。如果你希望手轮转1圈轴走1mm就把fPositionScale设为0.1希望手轮转1圈轴走10mm就设为1.0。倍率切换的本质其实就是修改这个比例因子。实际操作中我的经验是分辨率不要设得太小也不要太大。设太小比如100手轮位置每跳一格的步距太大调起来一格一格地冲设太大比如10000同样的手轮转动圈数下脉冲数太多如果不小心倍率切到100x轴会瞬间飞出去。我一般起步先用1000左右倍率从1x开始验证确认方向、行程、限位都没问题再逐步切到10x、100x。3. 完整实操建工程、写程序、接轴联动3.1 工程初始化与SoftMotion环境准备在开始写代码之前先把工程环境搭好。我这里用的是Codesys 3.5 SP系列需要先在包管理器里安装SoftMotion相关库。不同版本名字可能略有差异常见的是SoftMotion或者SoftMotion SoftMotion CNC安装后才能在设备树里添加运动控制相关的轴对象。如果你现在手头没有真实ECAT轴也可以先用仿真轴跑通逻辑。Codesys的PLC仿真模式配合SoftMotion的虚拟轴能完成整个虚拟手轮的逻辑验证这一点非常方便。等逻辑验证没问题了再接上真实EtherCAT主站和伺服轴。以真实ECAT轴为例大致步骤如下在设备树中添加EtherCAT主站扫描并添加从站设备。在运动控制组里新建一个轴轴类型选择与驱动器匹配的ECAT轴类型比如AXIS_REF_ECAT。配置轴的参数包括电机每转脉冲数、电机最大转速、加减速时间、软件正负限位、回零方式等。设置任务周期。EtherCAT同步周期通常设1ms或2msSoftMotion的运动控制任务也建议工作在同样的周期下避免数据不同步。在PLC程序中声明轴变量为AXIS_REF_ECAT并绑定到设备树的轴对象。这里有个新手容易踩的坑SoftMotion轴如果没有完成基本的轴参数配置比如每转脉冲数没有填或者使能逻辑没写后面SMC_FollowPosition就算被调用轴也不会动。我的习惯是先写一个最基础的单轴使能程序让轴能正常使能和回零再开始接虚拟手轮。3.2 核心ST代码实现虚拟手轮信号源下面直接给出一份完整的核心代码。这段代码实现了虚拟手轮信号源的启动、倍率切换、增量位置累加和轴跟随。变量声明如下VAR_GLOBAL // 虚拟手轮控制 bWheelEnable : BOOL : FALSE; // 手轮总使能 bWheelButtonOn : BOOL : FALSE; // 手轮启动按钮保持型 bAccEnable : BOOL : TRUE; // 是否启用加减速斜坡 udiAcceleration : UDINT : 300; // 加速度设定 udiInstantSpeed : UDINT : 30; // 目标转速 rpm udiResolution : UDINT : 1000; // 每转脉冲数 // 倍率切换 iMul : INT : 1; // 当前倍率 1/10/100 fMulScale : LREAL : 1.0; // 倍率对应的比例因子 // 虚拟手轮状态 fbVirtualWheel : SMC_FreeEncoder; udiWheelPos : UDINT; // 当前手轮位置脉冲 udiLastWheelPos : UDINT; // 上次扫描周期的手轮位置 diDeltaPulses : DINT; // 本次周期手轮增量脉冲数 fRefPosSum : LREAL : 0.0; // 轴目标位置累加值 // 轴跟随 fbFollowPos : SMC_FollowPosition; AxisECAT : AXIS_REF_ECAT; END_VAR主程序调用逻辑// 1. 启动虚拟手轮编码器 fbVirtualWheel( bExecute : bWheelButtonOn, bAccEnable : bAccEnable, udiAcceleration : udiAcceleration, udiInstantSpeed : udiInstantSpeed, udiResolution : udiResolution, udiCurrentPosition udiWheelPos ); // 2. 计算手轮增量处理UDINT回绕 IF udiWheelPos udiLastWheelPos THEN diDeltaPulses : DINT_TO_LREAL(udiWheelPos - udiLastWheelPos); ELSE // 计数器回绕处理这里按最大值1000000为例 // 实际应根据UDINT最大值调整 diDeltaPulses : (UDINT_TO_LREAL(udiWheelPos) 1000000.0 - UDINT_TO_LREAL(udiLastWheelPos)); END_IF udiLastWheelPos : udiWheelPos; // 3. 累加目标位置乘以倍率因子 // 除以1000是为了把脉冲换算成“手轮转数”再乘以机械导程10mm IF bWheelEnable THEN fRefPosSum : fRefPosSum (LREAL_TO_REAL(diDeltaPulses) / 1000.0 * 10.0 * fMulScale); END_IF // 4. 用SMC_FollowPosition驱动ECAT轴 fbFollowPos( bExecute : bWheelEnable, fReferencePosition : fRefPosSum, fPositionScale : 1.0, fVelocityScale : 1.0, fAccelerationScale : 1.0, Axis : AxisECAT );这段代码有几个关键设计点要重点解释。首先是增量式累加我没有直接把udiWheelPos丢给SMC_FollowPosition而是先算出手轮当前周期增加了多少脉冲再累加到fRefPosSum里。这样做的好处是切换倍率时不会造成位置跳变。如果直接用绝对位置乘以倍率一倍率从1x切到10x参考位置立刻变成原来的10倍轴会瞬间冲出去非常危险。改用增量累加后切换倍率只影响后续移动的步距当前轴位置完全不受影响。其次是除以1000和乘以10的关系。这里/1000是把脉冲数转换回手轮转数因为分辨率是1000脉冲/转*10是机械导程10mm。这两步合起来手轮转1圈fRefPosSum增加10mm正好对应轴侧的机械位移。如果你的设备机械传动比不是1:1或者导程不同记得改这两个数值。3.3 让虚拟手轮驱动ECAT轴的两条联动路径把SMC_FreeEncoder生成的脉冲转化为轴运动常见有两条路径。我上面用的是SMC_FollowPosition绝对位置跟随这是最常见的一种适合“手轮转多少轴走多少”的位置同步场景。它的好处是SoftMotion内部会按照参考位置的变化自动规划速度比例因子可以灵活调整代码量也少。第二条路径是先把虚拟手轮的增量换算成速度值然后调用MC_MoveVelocity或者自定义的速度斜坡去驱动轴。这条路径适合那些不想用SMC_FollowPosition、希望通过速度环手动控制轴的场景。比如你希望在手轮转动的同时根据某些工艺条件动态调整速度上下限或者需要在手轮模式和其他运动模式之间同时做复杂的切换用速度驱动会更灵活。不过我的实际项目经验是如果只是单纯做手动调试手轮SMC_FollowPosition的绝对位置跟随更省心因为它天然支持位置闭环手轮停了轴就停中间不会累积误差。速度驱动方式一旦速度换算有偏差轴会慢慢漂移必须额外做位置校验。还有一些老项目里可能用到SMC_Interpolator或者CNC插补器来接收外部位置参考。理论上也能接虚拟手轮但我个人觉得杀鸡用牛刀了SMC_FollowPosition完全够用代码可读性也更好后续维护的人不容易看懵。3.4 倍率切换与限位保护的设计细节倍率切换是最容易出问题的地方。我见过同行把倍率切到100x后轴直接撞限位就是因为切换逻辑没有处理好位置基准。用增量累加的方式后倍率切换变得非常简单和安全只需要改变fMulScale的值后续每周期累加的位置增量就会自动按新倍率走而轴当前的位置不会跳变。HMI上的倍率按钮逻辑可以这样写// 倍率切换 IF bMul1 THEN iMul : 1; ELSIF bMul10 THEN iMul : 10; ELSIF bMul100 THEN iMul : 100; END_IF fMulScale : INT_TO_LREAL(iMul);同时要在程序里做一个速度上限保护。不管倍率是多少轴的指令速度不能超过机械允许的最大值。SoftMotion的轴参数里有一个最大速度设定这个一定要设好相当于在系统层面给轴上了保险。我在倍率逻辑里还会加一道软件限制如果计算出来的目标增量超过某个阈值就直接把它截断宁可让操作员觉得手轮“变钝”了也不能让轴飞出去。限位保护方面轴的软件正负限位必须配置正确。当轴运动到软件限位附近时SMC_FollowPosition会怎样表现不同版本可能不太一样。我遇到过的情况是轴到达限位后不再动作但fRefPosSum还在继续增大导致限位解除瞬间轴猛冲一下。这个问题需要单独处理最简单的办法是在累加目标位置之前判断轴是否在限位附近如果在就不累加增量或者同时把fRefPosSum同步到当前轴位置值。另外急停信号要参与虚拟手轮使能链。急停按下时不仅伺服要掉使能还要把bWheelEnable置FALSE同时把fRefPosSum重新同步为轴当前位置避免急停恢复后出现位置突变。4. 实测排查虚拟手轮调试中的高频问题4.1 功能块启动了轴却没有动这是很多人第一次接虚拟手轮时遇到的首个问题。功能块状态看着正常udiWheelPos也在变化但轴就是纹丝不动。排查思路按下面的顺序来第一步检查SMC_FollowPosition的bExecute是不是持续为TRUE。如果只用了一个上升沿信号它可能只执行了一个周期就中止了。第二步看轴是否处于使能状态。SoftMotion的轴必须被正确使能SMC_FollowPosition发出的位置指令才能被真正执行。第三步检查SMC_FollowPosition的fPositionScale、fVelocityScale、fAccelerationScale有没有设成0。这三个比例因子如果是0轴接收到参考位置也是0自然不动。第四步在线监控fbFollowPos.bBusy如果bBusy为FALSE且没有报错说明功能块根本没被触发需要回头查bExecute的信号链。还有一种情况虚拟手轮位置确实在变但增量太小累加到fRefPosSum后根本不足以让轴产生肉眼可见的位移。比如倍率还在1x、丝杠导程也是1mm手轮转一圈轴才走1mm在屏幕上看起来就像没动。这时候先把倍率临时切到10x或者把机械导程换算值调大一点确认逻辑通了你再切回来。4.2 方向反了、倍率不对、轴飞车方向反是最容易发现的异常。手轮往一个方向转轴却往反方向跑。这种情况通常有两个处理点一是在SMC_FollowPosition里把fPositionScale或者fVelocityScale设成负数直接反转指令方向二是查看轴参数的电机旋转方向设置把电机方向反过来。我推荐在轴参数层面改方向因为这样所有运动控制指令的方向都统一了不会出现手轮和回零方向不一致的奇怪现象。倍率不对和轴飞车往往是同一个原因。最常见的是udiResolution和位置换算公式里的分辨率不一致。比如功能块里分辨率设了1000但位置累加时除以的是100那手轮每转一圈累加的位置就变成实际位置的10倍等于无形中多了一个10倍速再加上倍率切到100x不飞车才怪。我自己踩过这个坑所以现在写代码有个习惯所有换算相关的常量尽量不放魔法数字全部定义成全局变量并且在HMI上做一个“位置换算系数显示”方便现场对照。如果轴已经在飞车的边缘最有效的止损动作是先断开bWheelEnable停止累加再让轴停止使能。所以现场调试时我总会在HMI上放一个很大的“停止并清使能”按钮位置放在操作员最容易按到的地方。4.3 与回零、限位、正方向使能冲突设备上不会只有虚拟手轮一个功能它还要和回零、限位、自动程序这些逻辑共存。最常见的冲突是轴还没回零操作员就想用手轮把轴挪到一个安全位置。如果程序中直接允许可能轴一使能就报错因为SoftMotion很多轴模式下要求先回零。我的做法是把虚拟手轮视为“手动模式”的一个子状态。只有当设备处于手动模式、轴已回零、没有急停、没有运行中的自动程序时虚拟手轮才允许切换使能。回零操作和虚拟手轮之间加互锁回零过程中强制关掉虚拟手轮。还有一个容易被忽略的冲突是手轮位置累加值和限位的互相干扰。前面讲过轴撞软件限位后fRefPosSum可能还继续增大解除限位时轴会猛冲。解决思路有两种一种是在轴限位报警触发时把fRefPosSum同步为轴当前实际位置同时清零虚拟手轮增量累积的偏差另一种是每次累加前先检查轴的当前位置如果已经接近限位就只允许向着远离限位的方向累加。这些逻辑虽然看起来多但实际代码量不大只要在编写虚拟手轮程序时把安全互锁当成第一优先级后续调试会省掉很多麻烦。5. 把虚拟手轮玩出花扩展成调试平台5.1 虚拟手轮与HMI动画联动做可视化反馈虚拟手轮既然是一个软件信号那它就不仅能驱动轴还能同时驱动HMI上的动画。我习惯在触摸屏上画一个转盘把SMC_FreeEncoder的udiWheelPos取模后映射为转盘的旋转角度。这样操作员能看到虚拟手轮正在“转”的动画效果即使在没有物理手轮的情况下也能直观感受到手柄的转动方向和速度变化。HMI上还可以同时显示当前倍率、目标速度、手轮位置脉冲数、轴实际位置。这样调试的时候操作员和旁边的人都能很清楚地看到手轮操作和轴运动的对应关系。尤其在对刀、对基准这种需要两人配合的场合一个人操作虚拟手轮另一个人看着HMI报位置效率比纯按钮点动高得多。5.2 虚拟手轮作为运动控制基准源做仿真与测试虚拟手轮还有一个很实用的场景在没有真实物理轴的环境下验证运动控制逻辑。把ECAT轴换成仿真轴SMC_FreeEncoder的脉冲源完全可以作为运动控制算法的输入基准用来验证位置跟随效果、倍率切换逻辑、限位互锁逻辑等等。这时候虚拟手轮实际上是承担了一个“测试信号发生器”的角色你可以用它在实验室里模拟各种操作习惯比如快速转、慢速微调、突然反向、持续低速运行观察轴跟随是否平滑、是否会累积误差、会不会触发保护。这些问题如果等到设备上电后再发现现场会很狼狈但用虚拟手轮在办公室就能提前暴露一大部分。如果再把Codesys自带的3D仿真视图加进来甚至可以做一套简单的数字孪生调试。轴的运动在3D视图里实时可见操作方式和现场一模一样用来做培训、方案演示、客户验收都很有效果。5.3 与其它技术栈结合做监控与数据采集虚拟手轮产生的都是实打实的PLC变量这意味着可以把它接入到各种数据采集和监控系统里。比如使用PLC-Recorder这类工具读取Codesys的实时变量把操作员的每一次手轮操作、轴的位置变化、倍率切换时间戳全部记录下来。后续分析是操作不当导致的撞机还是程序逻辑有缺陷就有客观数据可依而不是靠口头扯皮。我还在一些项目里尝试过把底层通信进一步打通。ECAT总线上的轴状态、虚拟手轮信号、IO状态都可以通过网关汇聚到一个统一的监控平台。比如用libevent这类事件库做CAN通信和EtherCAT数据的统一接入把虚拟手轮的操作记录和驱动器报警数据放到同一个时间轴上分析排查问题会更快。不过这里必须提醒一句虚拟手轮始终是调试辅助工具它不能替代安全回路。设备的安全功能比如急停、安全门锁、安全限位必须是物理回路保证的绝不能因为程序里做了“限位保护”就省掉硬件的安全措施。这个红线任何时候都不能碰。最后再分享一个实操中的小习惯自从用了虚拟手轮之后我每次调试新设备都会先花十分钟把虚拟手轮跑通再去做其他运动控制逻辑。因为手轮代表了最底层的位置操作需求如果手轮能顺滑地驱动ECAT轴说明轴配置、使能、限位、通讯这些基础环节都已经健康了后续写自动程序会顺手很多。还有一点从现场换回办公室调试的时候虚拟手轮能让你迅速定位故障到底是在机械侧、伺服侧还是逻辑侧。曾经有一台设备在客户现场反映“手动点动偶尔会抖”接线和参数反复排查无果最后我用虚拟手轮加上PLC-Recorder同步采集位置指令和实际位置发现是驱动器内部滤波参数偏大导致的位置环滞后问题不到半小时就定位了。所以虚拟手轮不只是替代一个物理硬件它本质上是一个强大的诊断入口。关键参数的换算公式、倍率切换的安全细节、位置回绕的处理这套逻辑搞明白之后你会发现自己对Codesys软运动控制的理解也上了一个台阶。
返回列表