简介:这份CoDeSys运动控制文档面向工业自动化领域的PLC工程师与运动控制开发者,系统介绍CoDeSys SoftMotion中轨迹规划、插补器与驱动器控制的核心实现,帮助读者快速掌握龙门机器人坐标变换与连续轨迹离散化的应用方法。压缩包共1份doc文档,整体约130KB,内容围绕SMC_TRAFO_Gantry3pi与SMC_Interpolator两大功能块展开,详细说明了dOffsetX/dOffsetY、dx/dy、minX/maxX等输入输出变量的含义,以及bExecute、bSlow_Stop、bEmergency_Stop、bWaitAtNextStop等控制信号的使用场景。同时涵盖梯形与S形速度轮廓的区别、dOverride越程控制、dwIpoTime循环时间设置、运行状态枚举值及错误处理机制,并对移动范围、驱动器信息、附加轴S形插补等可视化与执行细节做了说明,可直接用于机器人、数控设备、运动平台等项目的开发调试。目前已有973人浏览学习,适合正在入门CoDeSys运动控制或需要查阅具体功能块定义的工程师作为案头参考。
1. 这份文档不是用来读的:CoDeSys 运动控制先搞清楚它解决什么
做设备调试的人搜“CoDeSys 文档(运动控制)”,多半不是在找 PDF,而是已经站在一台动不了的伺服面前。CoDeSys 是工业自动化里常见的 PLC 编程环境,运动控制则是用它把伺服电机、步进电机变成“能按位置走、能同步跑”的执行机构。很多人第一次打开官方手册被几百个功能块劝退,实际项目里常用的不超过十个。文档真正的作用不是从头读到尾,而是在出问题时告诉你该查哪一页。这篇文章按我自己的调试路径来写:先讲运动控制功能块的状态机主线,再讲设备和轴的配置顺序,然后给出一段能跑通的最小定位程序,最后把电子齿轮、电子凸轮和排查套路补齐。新手照着操作能出结果,熟手可以跳过前半部分直接看避坑记录和凸轮参数。
2. PLCopen 功能块与轴状态机:读文档前先记住的 4 个状态
2.1 状态机先看懂:Disabled、Standstill、Halt、ContinuousMotion 关系
CoDeSys 运动控制里每个轴都有一个逻辑状态,状态切换由功能块触发。官方文档中把这套状态机讲得很细,但调试时真正需要记住的只有四个状态。
Disabled 是轴未使能的状态,此时轴没有力矩,外部可以手动盘动。Standstill 是轴已使能但停止,这时候轴有抱闸和保持力矩。Halt 是轴正在停止过程中的状态,比如执行了 MC_Stop 但还没完全停下来。ContinuousMotion 是轴持续运行的状态,对应速度模式或者正在执行一段长距离定位。
状态之间的切换靠的是功能块。MC_Power 把轴从 Disabled 切到 Standstill,MC_MoveVelocity 把轴从 Standstill 切到 ContinuousMotion,MC_Stop 让轴回到 Standstill,MC_Reset 用来从 ErrorStop 状态恢复。这些切换在功能块的 Busy、Done、Error 输出上都有体现。新手常犯的错误是只看 Done,不看状态机是否允许当前指令执行。比如轴还在 ErrorStop 状态时发任何运动指令都会被忽略,必须先执行 MC_Reset 清除报警。
我一般查文档时会先打开轴状态图那一页,而不是先从功能块列表开始看。状态图决定了程序结构:一个轴的控制逻辑就是有限状态机的流转,每个扫描周期把指令发给当前允许执行的功能块,其他指令全部保持 Execute 为 FALSE。这样写出来的程序不会出现位置乱跑的问题。
2.2 Execute 边沿触发的功能块时序:MC_Power 与 MC_MoveAbsolute 的组合
PLCopen 功能块使用 Execute 上升沿触发,意思是一个指令只在 Execute 从 FALSE 变成 TRUE 的那个扫描周期被接受。执行期间 Busy 输出为 TRUE,执行完成后 Done 输出为 TRUE,出问题时 Error 为 TRUE,ErrorID 给出报警码。
这个边沿触发特性非常关键。有些人用赋值方式把 Execute 持续置 TRUE,指令执行完后不会自动停止,重新给条件时可能因为边沿没产生而无法再次触发。常见的做法是给每个功能块配一个对应的触发变量,在条件满足时先将 Execute 置 TRUE,检测到 Done 后再置 FALSE。
MC_Power 和 MC_MoveAbsolute 的配合需要注意时序。MC_Power 只是将驱动器的使能信号建立起来,到 regualtor 真正上电、抱闸打开需要一段时间。如果 MC_Power 发出后马上发 MC_MoveAbsolute,轴会直接不响应,因为轴状态还在 Disabled,运动指令被内部丢弃。我一般会等 MC_Power 的 Busy 完成后再发定位指令,或者用一个简单的延时状态来保证时序:
// 使能轴 Power(Axis := Axis1, Enable := bPower, bRegulatorOn => bRegOn, bDriveStart => bDriveOn); // 等待使能完成后再触发定位 IF bPower AND bRegOn AND bDriveOn AND NOT bMoveBusy THEN bStartMove := TRUE; ELSE bStartMove := FALSE; END_IF MoveAbs(Axis := Axis1, Execute := bStartMove, Position := rTargetPos, Velocity := rVel, Acceleration := rAcc, Deceleration := rDec, Jerk := rJerk, Done => bMoveDone, Busy => bMoveBusy, Error => bMoveError, ErrorID => dwMoveErrID);上面的代码里 bRegOn 和 bDriveOn 是 MC_Power 的状态输出,只有这两个都为 TRUE 才说明驱动器真正就绪。逻辑上先建立使能,再触发定位,避免轴不响应的问题。Position 和 Velocity 是 LREAL 类型,单位取决于轴配置里的单位换算;Acceleration 和 Deceleration 一般用 mm/s²,JerK 用 mm/s³,如果驱动器或运动库不支持 Jerk 可以填 0。
2.3 ErrorID 报警码查询路径:把出错的位置记得比功能块还清楚
运动控制出了报警,第一件事不是去改程序,而是把 ErrorID 记下来。CoDeSys 官方文档里有一个报警码章节,按功能块分类列出所有可能的错误码。现场经验是:同一个错误码在不同版本的运动库中含义可能有差异,所以查文档时先确认库版本号。
MC_MoveAbsolute 常见的 ErrorID 有几种:轴未使能时触发会报 16#6570 这类状态错误,正负方向限位触发时会报 16#6302 或 16#6303,目标位置超出软限位范围会报 16#6574。这些编号不用背,但要在程序里留一个显示接口,把错误码送到 HMI 上,调试时直接看数值比猜要快得多。
另外很多人在 Error 出现后直接发 MC_Reset,这样把报警清掉继续跑,结果下一次还是同样的问题。正确做法是:先读 ErrorID,查文档确认原因,解决现场问题后再复位。比如限位报警,应该先手动把轴移回行程内,再复位并重新回零。MC_Reset 只是清除内部错误标志,不能替代现场排查。
3. 从设备树到第一段定位代码:轴配置、单位换算与最小可运行程序
3.1 添加 PLCopen 轴:设备树里新增轴的三步操作
在 CoDeSys 里新建一个运动控制项目,先要添加运动控制器相关的设备。常见结构是安装运动控制库(比如 SoftMotion 或 CNC 库)后,在设备树的 Devices 里增加一个“通用运动控制器”设备,然后在这个设备下添加驱动器的 EtherCAT 从站。
驱动器从站添加上后,操作分三步。第一步确认从站识别码和实际硬件一致,这步经常被忽略,但总线扫描后如果识别码不匹配,轴在初始化时会报通讯错误。第二步配置 PDO 映射,标准伺服驱动器至少需要映射控制字、状态字、目标位置、实际位置这几项,有些驱动器还要映射速度、力矩、回零信号。第三步是右键新增“PLCopen 轴”,把逻辑轴和具体的从站通道关联起来。
轴和驱动器的映射关系到后续所有运动指令。每个 AXIS_REF 变量对应设备树里的一个轴实例,MC_MoveAbsolute 通过这个变量找到实物驱动器。常见错误是配好了驱动器但忘了添加轴实例,程序里直接声明 AXIS_REF 空变量,运行时找不大设备。我的习惯是设备树里的轴名和程序变量名保持一致,比如设备树叫 AxisX_V1,程序里也声明同名变量,这样排查逻辑关系时省事。
3.2 单位换算:从编码器分辨率到毫米的 4 个参数
运动控制里最玄学的部分就是单位换算。轴配置界面里有编码器分辨率、减速比、传动机构导程这几个参数,它们组合起来决定了 PLCopen 位置指令和实际物理位置的对应关系。
假设现场配置是 2500 线的增量编码器,驱动器做了四倍频,那么电机每转的脉冲数是 2500 乘以 4,等于 10000 个脉冲。减速比是 10:1,电机转 10 圈负载转 1 圈。丝杆导程 10 mm,负载走 10 mm 需要电机转 1 圈。换算一下,10 mm 对应 10000 乘以 10 等于 100000 个脉冲,每个毫米对应 10000 个脉冲。如果希望 PLCopen 里的单位直接是 mm,那么 Scaling Factor 就填 10000 个脉冲每毫米。
以上换算用表格整理:
| 参数 | 数值 | 说明 |
|---|---|---|
| 编码器线数 | 2500 | 常见增量编码器规格 |
| 驱动器倍频 | 4 | 2500 线四倍频后为 10000 脉冲/转 |
| 减速比 | 10:1 | 电机转 10 圈负载转 1 圈 |
| 丝杆导程 | 10 mm/转 | 负载每转对应移动 10 mm |
| 折算脉冲/单位 | 10000 | 每个毫米对应 10000 脉冲 |
配置好后,轴的位置单位就是 mm。速度单位变成 mm/s,加速度变成 mm/s²。这样程序里写 Position := 100.0 就是 100 mm,写 Velocity := 50.0 就是 50 mm/s。如果现场用的是皮带轮传动而不是丝杆,导程改成“皮带轮周长除以减速比”即可。
这个参数填错是最隐蔽的坑。填错后程序里一切看着正常,轴也能动,但实际位置和显示位置对不上。我每次验收都做一次“点动走 1 mm”测试,用千分表或钢尺确认实际位移和程序显示一致,这一步能挡住绝大多数配置错误。
3.3 第一段可运行程序:使能、回零、绝对定位(ST 代码)
配置完成后的最小程序包含三部分内容:使能轴、回零、执行绝对定位。回零方式根据硬件来选,增量编码器必须回零,绝对编码器如果位置值仍然有效可以跳过 MC_Home。下面这段代码以增量编码器加正限位开关为例:
PROGRAM Main VAR Axis1 : AXIS_REF; Power : MC_Power; bPower : BOOL := TRUE; bRegOn: BOOL; bDrvOn: BOOL; Home : MC_Home; bHomeExec : BOOL := FALSE; bHomeDone : BOOL := FALSE; MoveAbs : MC_MoveAbsolute; bMoveTrig : BOOL := FALSE; bMoveDone : BOOL := FALSE; bMoveBusy : BOOL := FALSE; bErr : BOOL := FALSE; dwErrID : DWORD := 0; rTarget : LREAL := 100.0; // 目标位置,单位 mm rVel : LREAL := 50.0; // 定位速度,单位 mm/s rAcc : LREAL := 500.0; // 加速度,单位 mm/s² rDec : LREAL := 500.0; // 减速度,单位 mm/s² rJerk : LREAL := 0.0; END_VAR// 使能轴,Enable 保持 TRUE 持续输出使能 Power(Axis := Axis1, Enable := bPower, bRegulatorOn => bRegOn, bDriveStart => bDrvOn); // 回零:在使能完成后执行一次,使用当前位置作为原点 IF bRegOn AND bDrvOn AND NOT bHomeExec AND NOT bHomeDone THEN bHomeExec := TRUE; ELSE bHomeExec := FALSE; END_IF Home(Axis := Axis1, Execute := bHomeExec, Position := 0.0, Mode := MC_HOME_ABS, Done => bHomeDone, Error => bErr, ErrorID => dwErrID); // 绝对定位:回零完成后触发一次 IF bHomeDone AND NOT bMoveTrig AND NOT bMoveDone THEN bMoveTrig := TRUE; ELSE bMoveTrig := FALSE; END_IF MoveAbs(Axis := Axis1, Execute := bMoveTrig, Position := rTarget, Velocity := rVel, Acceleration := rAcc, Deceleration := rDec, Jerk := rJerk, Done => bMoveDone, Busy => bMoveBusy, Error => bErr, ErrorID => dwErrID);这段程序里 MC_Home 使用 MC_HOME_ABS 模式,意思是以当前位置作为绝对零位。实际项目中如果有限位开关,通常用 MC_HOME_DIR_POSITIVE 或 MC_HOME_DIR_NEGATIVE 配合开关信号来找原点。回零完成后 bHomeDone 变为 TRUE,之后才能触发定位。如果跳过回零直接发绝对定位,增量和相对编码器会因为机械误差导致位置全部偏移。
程序里 bMoveTrig 的上升沿逻辑要注意:当 bHomeDone 为 TRUE 且 bMoveTrig 为 FALSE 时,本扫描周期把 bMoveTrig 置 TRUE,下一周期又会被置回 FALSE,这样 MC_MoveAbsolute 只收到一个上升沿。等 Done 输出为 TRUE 后,整个过程结束。如果要跑多段定位,把这个逻辑做成功能块或状态机,比每次复制粘贴可靠。
4. 运动控制避坑:5 条能救你项目的报警与位置异常排查记录
4.1 现象:轴不响应运动指令,Busy 一直为 FALSE
新项目第一次上电,发出 MC_MoveAbsolute 后轴纹丝不动,监控里 Busy 输出一直是 FALSE,Error 也是 FALSE。原因是通信和使能其实已经正常,但驱动器的状态字没有到达“准备好”状态,运动指令被 PLCopen 内部状态机拦下。更常见的是 MC_Power 的 Enable 给得太晚,轴还没完成初始化就收到了定位指令。
解决方案是加状态判断:把 MC_Power 的 bRegulatorOn 和 bDriveStart 输出全部作为运动指令的允许条件。控制字和状态字也可以通过读取驱动器状态字变量来判断。用在线监控看 MC_Power 的参数值,确认 bRegulatorOn 从 FALSE 变 TRUE 的时间点,再确认这个时间点的前后两条运动指令行为。程序结构上不要把所有功能块在一个扫描周期内全部触发,用顺序状态机把使能、回零、运动分开。
4.2 现象:程序里走了 100 mm,设备实际走了 10 mm
这种情况典型是单位换算出错。我遇到过把电机每转脉冲数直接填成编码器线数的,2500 线填进去后少了 4 倍,结果所有位移都缩小到四分之一。还有一种是减速比填反了,设备走到目标位置时行程变成设定值乘以减速比。
检查顺序是:先看编码器分辨率是不是四倍频后的数值,再看减速比是不是电机侧比负载侧,最后手动点动走一个已知距离来计算实际脉冲数。用轴的实际位置反馈值除以机械行程,得到的脉冲数如果和理论值对不上,再逐项排查。这里有一个比较实用的方法:在轴配置里把编码器分辨率临时设为 1,手动移动轴看反馈位置变化量,可以直接换算出整个传动链的总减速比。
4.3 现象:回零每次原点位置不一致,方向随机
增量编码器设备每次上电都在不同位置,回零后原点位置也会不同。原因是使用了 MC_HOME_ABS 模式,它直接把当前位置当原点,没有找开关或 Z 相。正确做法是按照硬件安装位置选择回零方向:限位开关在负方向就设 MC_HOME_DIR_NEGATIVE,在正方向就设 MC_HOME_DIR_POSITIVE,并指定开关信号通道。
开关信号需要映射到轴的输入引脚上,通常通过驱动器的 DI 端子接入。如果 DI 映射没配置,MC_Home 会一直等到超时。回零速度也要合理:找开关阶段用较快的速度,碰到开关后减速,再以爬行速度离开开关找 Z 相,这样原点重复精度才稳定。单纯用开关沿做原点,机械间隙会造成每次位置偏差,这是很多设备定位精度不达标的真正原因。
4.4 现象:在线修改轴配置后轴状态异常,位置丢
项目调试时为了省时间,直接在在线状态下修改轴配置,比如改了减速比或编码器分辨率,结果轴报位置丢失,原来设定的坐标系全部错乱。原因是轴配置存放在控制器端,修改时内部运动状态被重新初始化,位置值重置,而机械实际位置并没有变。
解决办法是:改轴配置前先把轴回零坐标记下来或直接回零,离线下载后再重新建立坐标系。下载完程序第一次运行时强制回零,绝对编码器系统可以通过读取编码器当前位置并设定为机械原点来恢复。千万不要在轴运动过程中修改任何 Scaling 参数,改了之后位置反馈和实际机械位置之间的对应关系立即失效。
4.5 现象:凸轮激活后从轴跟丢或两侧速度突变
电子凸轮在多轴设备里经常出问题。现象是从轴进入凸轮一瞬间发生跳变,或在曲线端点处速度突变。原因多半是主从轴位置关系没有做好相位对齐。PLCopen 的 MC_CamIn 在激活时会把从轴位置按照凸轮表的偏移量重新映射,如果激活前从轴没有停在凸轮起始点对应的位置上,就会跳变。
解决方法是分三步:第一步把主轴运行到定义的凸轮起始角度,第二步把从轴移动到该角度对应的凸轮输出位置,第三步再触发 MC_CamIn。凸轮表的起始位置和结束位置必须值一致,否则每次循环在拼接点出现速度阶跃。另一个隐藏坑是凸轮表下载后没有重新激活,运行的是旧表,修改曲线后必须重新下载并触发一次 MC_CamIn。
5. 电子齿轮与电子凸轮:比率参数、CAM 表下载与激活的实操路径
5.1 电子齿轮:MC_GearIn 的比率参数与退出逻辑
电子齿轮让从轴跟随主轴,保持固定的位置比率。MC_GearIn 的功能是建立主轴到从轴的位置耦合,关键参数是 RatioNumerator 和 RatioDenominator。这两个参数都是整数,从轴位置等于主轴位置乘以分子再除以分母。比如主轴每转 100 个单位的距离,从轴只需要转 50 个单位,比率就是 50 比 100,即分子 50 分母 100。
PLCopen 里主从轴不是绑定死的,MC_GearOut 可以解除耦合。解除后从轴进入什么状态取决于参数里的 Deceleration 设置,一般会让从轴按设定减速度停下来。这里有个常见问题:解除耦合瞬间从轴速度如果和主轴不一致,会有机械冲击。解决方式是先把主轴速度降下来,或者用 MC_GearOut 的 Acceleration/Deceleration 做平滑过渡。
电子齿轮适合用在传送带同步、飞剪追剪这类场合,不需要修改主轴的运动轨迹,只要改比率就能适应不同规格的产品。比率切换时机也要注意:产品切换时把从轴脱离,等主轴到达指定位置后再以新比率重新耦合,避免在任意位置切换导致位置突变。
5.2 电子凸轮 CAM 表:导入、编译、下载、激活四步
电子凸轮在 CoDeSys 里的实现路径比较固定,但每一步都有坑。第一步是编辑凸轮表,在凸轮编辑器里可以直接创建曲线点,也可以从 CSV 文件导入数据点。导入时注意表头格式,通常有 x 和 y 两列,x 对应主轴位置,y 对应从轴位置,单位是轴配置里的单位。点太多时曲线编辑器会变卡,几千个点也没问题,但生成的可执行代码会变大。
第二步是编译凸轮表。凸轮编辑器里有一个编译动作,把文本格式的曲线转成控制器能直接执行的二进制表。很多人漏了这步,结果下载到控制器后提示数据无效。第三步是下载,在在线模式下把凸轮表下载到控制器,这一步是把数据写入控制器内存,不是运行时激活。第四步是激活,调用 MC_CamIn 把凸轮表关联到从轴。
MC_CamIn 有几个关键参数:MasterOffset 最终决定主轴从哪个位置开始读取凸轮表,SlaveOffset 决定从轴的起始位置,MasterScaling 和 SlaveScaling 可以修改主从轴的位置缩放比例。教科书上常用的模式是把 MasterOffset 设为主轴的当前角度对应位置,SlaveOffset 设为 0,这样从轴平滑进入凸轮。
5.3 什么时候用 CNC 而不是凸轮:同步与插补的边界
电子凸轮解决的是一个主轴对应一个从轴的同步问题,CNC 解决的是多轴联动插补路径问题。现场做两轴圆弧插补、螺旋插补或者任意轨迹加工,用凸轮表会非常痛苦,因为要事先计算所有位置点,而 CNC 直接支持 G 代码中的直线和圆弧指令。
CoDeSys 的 CNC 模块包含轴组对象,类似 G 代码解释器,可以把 G 代码翻译成各轴的运动指令。它和电子凸轮可以同时使用,一套系统里部分轴走凸轮同步,部分轴走 CNC 插补。判断标准很简单:只要是想让某一个轴按另一个轴的位置成函数关系运动,用凸轮;如果想在平面上走出任意轨迹,让多个轴共同协作,用 CNC。
6. 调轴的一个习惯:手动点动、看跟随误差,再谈自动化
6.1 从手动点动开始验证方向,再写程序
我的调试习惯是配好驱动器后先不写任何运动程序,在 CoDeSys 的轴调试台手动功能里给轴发一个很小的速度指令,比如 10 mm/s,确认电机方向正确。然后反向再点动一次,确认反馈方向也正确。这一步骤能发现编码器方向接反、电机相序错误等安装问题,这些问题如果在全自动运行中暴露,轻则报警,重则撞机。手动点动确认后还要做一次限位验证,正负方向的软限位和硬限位都要触发一次,观察轴是否能停下来。
6.2 Trace 看跟随误差与速度曲线,比反复试快得多
轴动起来后有振动或者定位超调,不要急着去调 PID 参数。先在 CoDeSys 的 Trace 工具里记录目标位置、实际位置和跟随误差三条曲线,手动给一个梯形速度曲线,观察跟随误差峰值出现在加速段还是减速段。如果加速段误差大,说明加速度或增益不足;如果到位后还在振荡,说明速度环或位置环增益偏高。很多情况下,调整加速度参数就能解决问题,根本不用动驱动器内部增益。养成这个习惯后,新轴调试从几天压缩到半天,走弯路的时间几乎都花在配置确认上。第一台设备就因为手动点动时没验证编码器方向,直接跑绝对定位,结果轴反向冲出去撞了限位。那之后我把“先点动、再限位、后自动”写进了自己的排查清单,希望帮到你。
本文还有配套的精品资源,点击获取