
做工业运动控制的工程师大概率都遇到过这种尴尬程序框架搭到一半伺服电机还在物流路上驱动器没通上电但老板明天就要看demo。硬等硬件会拖慢进度拿假信号强撑又容易把逻辑写成一团浆糊。这种情况下我一直靠CODESYS里的虚拟轴先跑通单轴运动逻辑等项目真正把实物接上电再把轴类型换成真实驱动器整个调试周期至少能压缩三分之一。这篇就把我用CODESYS控制虚拟单轴运动的全过程拆开讲覆盖虚拟轴的创建、运动指令的搭建、单位与加减速的换算方法以及如何把运行数据抓出来分析。不管是刚接触CODESYS的PLC工程师还是准备给项目做功能预研的电气工程师照着这个思路走一遍基本能避开大多数入门坑。1. 虚拟轴凭什么能替代真实伺服跑逻辑1.1 虚拟轴到底虚拟在哪很多人第一次听到虚拟轴时容易把它理解成一种模拟信号或者占位符觉得反正不是真电机随便写写就行。这种理解其实低估了CODESYS里虚拟轴的分量。虚拟轴在运行时同样走完整的轨迹规划器位置给定、速度规划、加减速计算、限位判断、状态机迁移全部都会被执行。不同的地方只有一个轴的实际位置反馈不是来自编码器而是由SoftMotion运行时按照你设定的运动曲线实时生成。也就是说它把一个真实伺服系统里的物理反馈环节替换成了一个软件模拟的理想编码器。我用一个类比解释这就好比用公式算出来车速真实的车还没上路但速度、里程、加减速的变化规律都符合物理直觉。虚拟轴的反馈值和你的指令值之间几乎零延迟、零误差所以在它上面验证的是运动控制逻辑本身有没有问题而不是驱动器调试得好不好。1.2 用它跑逻辑的三个典型场景我长期在项目里保留虚拟轴验证的环节主要是因为它能解决三个非常实际的问题。第一个场景是运动控制主站程序的开发。很多项目里CODESYS作为主站要协调多台伺服、气缸、视觉系统。伺服没有就位时控制程序没法联调HMI画面上的轴状态、报警、定位完成信号全都没办法验证。把虚拟轴挂上去之后工艺流程、互锁条件、手自动切换这些逻辑都可以先跑起来等真伺服到了再无缝切换到实际轴。第二个场景是客户演示和出厂验收。很多设备厂在项目交付前需要给客户演示动作流程但设备可能还没有完成装配或者还在运输途中。虚拟轴可以代替真实轴在屏幕上完成一整条定位流程把节拍时间、动作顺序、异常恢复都演示清楚。我曾经在设备还没组装完的情况下用虚拟轴给客户提前演示了连续定位和回零流程客户当场确认了方案大大减少了后续返工。第三个场景是培训和文档编写。新入职的工程师需要快速理解运动控制程序的逻辑如果用真机让他们练手既危险又容易坏设备。虚拟轴随时可以启停随便写错程序也不会损坏机械非常适合用来演示PLCopen指令的状态变化。1.3 虚拟轴不能替你干什么虚拟轴能验证的是该不该动、该走到哪、什么时候报错但它验证不了走得多稳、多快、多准。真实设备上的驱动器PID参数、机械间隙、负载惯量比、跟随误差、震动抑制这些问题虚拟轴一个都模拟不出来因为它没有惯性也没有电气噪声。所以我不建议在虚拟轴阶段花大量时间去调动态参数。那部分工作必须留到真机调试时做。正确的姿势是在虚拟轴上把状态机、顺序逻辑、异常处理、HMI交互全部跑对动态参数只需设成项目预估范围内的合理值。2. 从新建工程到虚拟轴上线的完整链路2.1 需要哪些软件组件做虚拟轴最少需要两部分组件CODESYS Development System本体以及SoftMotion运动控制工具包。SoftMotion里面封装了PLCopen运动控制指令和轴对象的运行时管理代码没有它你会连MC_Power都找不到。不同版本的CODESYS在工程创建时的表现不同。较新的3.5版本如果正确安装了SoftMotion包新建工程时会出现对勾选项勾选之后会自动在应用节点下生成SoftMotion General Axis Pool对象。如果用的版本比较老或者没有生成轴池对象也可以在库管理器中手动添加SoftMotion相关库然后在程序中声明AXIS_REF变量来引用轴对象。具体菜单路径在不同版本里有差异但你只需要记住一个大原则轴对象要挂在SoftMotion的轴管理容器里面程序里的AXIS_REF本质上只是这个轴对象的引用不是轴本身。把这个关系搞明白后面很多配置问题都不会迷茫。2.2 添加虚拟轴的具体操作在CODESYS Control Win V3这类软PLC环境中我会按下面的步骤把虚拟轴加到工程里新建标准工程设备选择CODESYS Control Win V3 x64或者你实际使用的控制器型号。确认工程下存在SoftMotion General Axis Pool。如果没有在应用节点上右键添加对象选择SoftMotion General Axis Pool。在轴池中右键添加轴驱动器类型选择Virtual虚拟。生成轴对象后程序里通过AXIS_REF引用它。虚拟轴添加完之后它就是一个合法的运动控制轴只是驱动类型是软件模拟。注意一个细节轴对象本身不是PLC程序里的变量如果你在POU里声明了一个AXIS_REF变量需要通过与轴池的对应关系把它绑定上。最常见的做法是在全局变量列表里声明引用或者在程序里把轴池生成的轴对象直接插入到变量声明区。2.3 轴参数里必须搞明白的几个选项轴对象创建好之后双击打开轴配置页面会看到一堆参数。我不建议全部抄默认值有几个选项和后续控制效果直接相关。单位设置决定你在运动指令里写的位置和速度单位是什么。机械上通常用mm旋转台用deg有些特殊机构用自己的用户单位。最好在项目一开始就定下来不然后面单位换算会让你怀疑人生。缩放比例把用户单位映射到内部编码器增量的比例。在真实轴上这个比例由机械传动比和编码器分辨率决定在虚拟轴上它只是一个模拟换算关系。但你仍然要认真配好因为后面换真机时这就是你核对的第一项。软限位正负方向的最大位置限制。虚拟轴虽然没有物理开关但软限位依然生效。我每次都会刻意在虚拟轴阶段验证超限后程序的行为这比到真机上冒着撞车风险去测试要安心得多。动态参数默认速度、加速度、减速度、急动度。这些值会在你写运动指令但没有显式传参时作为缺省值使用。我的建议是把它们设成项目实际可能采用的值而不是给个特别夸张的默认值否则验证出来的工艺节拍会失真。2.4 关于轴引用的新手答疑新手最容易困惑的是AXIS_REF这个类型。它不是轴本身而是一个包含大量字段的结构体变量里面装着轴的状态、位置、速度、错误码等信息。你可以把它的每个实例理解成一根轴控制线的插头插到哪个轴对象上就控制哪个轴。一个容易踩的坑如果直接在局部变量里声明AXIS_REF然后往里面塞了一些初始值看起来没问题但程序重启后轴的状态会丢失或者出现多个程序段引用了同一个轴对象的不同副本导致指令互相覆盖。正确做法是使用轴池生成的轴对象并且在需要访问轴的POU中通过全局变量引用它保证整个工程里只有一个真正的轴实例。3. 单轴运动的核心指令从使能到定位一次说清3.1 先建立PLCopen状态机的心智模型控制CODESYS运动轴本质上是控制它在一个状态机里切换。PLCopen标准定义了轴的状态包括Disabled未使能、Standstill静止、Moving运动、ContinuousMotion连续运动、Stopping停止中、ErrorStop错误停止等。很多新手写运动控制程序时一上来就调MC_MoveAbsolute结果轴不动或者报错根本原因是轴不在期望的状态里。比如轴还在Disabled状态就直接给定位指令指令是不会执行的。所以在写代码之前先在心里有一条状态主线轴从Disabled开始执行MC_Power使能后进入Standstill之后才能接受定位、速度等运动指令运动指令执行中轴进入Moving或ContinuousMotion状态发生错误时进入ErrorStopErrorStop状态下必须先执行MC_Reset清除错误再重新使能。下面这个表总结了单轴控制里常用的指令和状态关系指令需要的前提状态目标状态主要用途MC_PowerDisabled / StandstillStandstill给轴使能MC_HomeStandstillStandstill回零完成建立原点MC_MoveAbsoluteStandstill已回零Moving → Standstill绝对定位MC_MoveRelativeStandstillMoving → Standstill相对定位MC_MoveVelocityStandstillContinuousMotion连续速度模式MC_Stop任意运动状态Stopping → Standstill停止运动MC_ResetErrorStopDisabled / Standstill清除错误3.2 使能与回零MC_Power是整个单轴控制的地基。这个指令需要Enable信号持续为TRUE并且每个扫描周期都要执行不能只在一个上升沿里给一次。Enable断掉之后轴会回到Disabled状态之前的运动状态全部清零。回零这个动作在虚拟轴上比真实设备简单得多。真实轴需要找原点开关、限位开关或者靠编码器零点虚拟轴只要收到MC_Home的Execute上升沿就会立即建立原点。值得注意的是MC_Home指令里的Position参数代表回零完成后把当前位置设为哪个值不是回零速度。虚拟轴上通常设为0。3.3 绝对定位、相对定位与速度模式定位指令里最常用的是MC_MoveAbsolute。它需要一个已经回零的前提条件目标位置是坐标系里的绝对位置。MC_MoveRelative则不管当前在哪只按照指令里的Distance走一段增量距离对是否回零没有强制要求。MC_MoveVelocity和前两者完全不同它没有终点位置轴会以设定的速度一直运行直到收到其他指令打断。这个指令很适合用来做连续送料、材料搜边、手轮跟随之类的功能。在虚拟轴阶段完全可以把速度模式的启停逻辑、状态切换逻辑先验证清楚。这几个定位指令都有BufferMode参数用来决定新指令对当前运动的影响方式。默认的mcAborting是立即打断当前运动然后执行新指令mcBuffered是等当前运动自然结束后再执行新指令。在虚拟轴阶段我建议把这两种模式都试一遍因为你实际项目中究竟用哪种取决于工艺流程是否需要平滑过渡。下面是一个完整的最小控制程序示例使用ST语言实现使能、回零、绝对定位、停止和错误复位PROGRAM PRG_虚拟轴单轴Demo VAR // 轴引用来自全局变量中的虚拟轴 axMain : AXIS_REF : GVL.axVirt; // 使能 fbPower : MC_Power; bEnable : BOOL : TRUE; // 回零 fbHome : MC_Home; bDoHome : BOOL; // 绝对定位 fbMoveAbs : MC_MoveAbsolute; bStart : BOOL; rTarget : LREAL : 500.0; // 速度与加减速 rVel : LREAL : 250.0; rAcc : LREAL : 800.0; rDec : LREAL : 800.0; rJerk : LREAL : 5000.0; // 停止与复位 fbStop : MC_Stop; bStop : BOOL; fbReset : MC_Reset; bReset : BOOL; // 状态输出 bPowerOK : BOOL; bHomeDone : BOOL; bDone : BOOL; bMoving : BOOL; wErrID : WORD; END_VAR// 1. 使能Enable为TRUE时周期执行 fbPower( Enable : bEnable, Axis : axMain ); bPowerOK : fbPower.Status; // 2. 回零上升沿触发虚拟轴会立即建立原点 fbHome( Axis : axMain, Execute : bDoHome AND bPowerOK, Position : 0 ); // 注意Done信号持续时间很短实际项目要用RS触发器锁存 bHomeDone : fbHome.Calibrated OR fbHome.Done; // 3. 绝对定位前提是已使能、已回零 fbMoveAbs( Axis : axMain, Execute : bStart AND bPowerOK AND bHomeDone, Position : rTarget, Velocity : rVel, Acceleration : rAcc, Deceleration : rDec, Jerk : rJerk, BufferMode : mcAborting ); bDone : fbMoveAbs.Done; bMoving : fbMoveAbs.Busy; // 4. 停止需要停止时给一次上升沿 fbStop( Axis : axMain, Execute : bStop, Deceleration : rDec ); // 5. 错误复位轴进入ErrorStop后必须先复位再重新使能 fbReset( Axis : axMain, Execute : bReset ); // 6. 把错误码暴露到外部方便HMI显示或者抓取 wErrID : axMain.ErrorID;代码里的注释已经标注了两个关键点回零完成信号需要锁存运动完成信号同理。很多人在这里吃过亏以为Done会保持一个比较长的时间实际上PLCopen标准里这些单周期脉冲信号往往只持续一个扫描周期如果你不在上位机侧做锁存很容易错过完成标志。3.4 停止、报错与复位MC_Stop用于让轴从当前运动状态快速停下来。它的Deceleration参数指定减速过程的减速度默认情况下轴停在当前位置。MC_Stop停止过程结束后轴回到Standstill状态后续需要重新触发运动指令。虚拟轴状态下也会出现ErrorStop。最常见的原因是逻辑错误比如轴还没有使能就执行了MC_MoveAbsolute或者轴处于错误状态时没有复位就重新给指令。出现错误后轴上的Error位会变TRUEErrorID里会带出错误码。我建议在虚拟轴阶段就把错误码读取、显示、复位这套流程完整做一遍因为真机上的错误更多如果不提前形成习惯到了现场很容易手忙脚乱。4. 位置单位、速度与加减速的换算与整定4.1 三个单位量级的关系在CODESYS运动控制里单位换算至少要涉及三个层面用户单位比如mm、轴内部编码器单位通常是脉冲数或内部增量、以及你在运动指令里使用的单位。很多人只关注位置指令从变量里来速度指令手填一个数而忽略了这三者之间的比例关系结果到了真机上一跑轴的实际位移和设定值差了好几倍。虚拟轴的缩放比例同样有意义。轴参数里设定的比例关系决定了1个用户单位等于多少个内部增量。假设你的机械结构要求1mm对应编码器1000个脉冲那么缩放比例就应该配置成1:1000。虚拟轴虽然没有真实的编码器脉冲流但它会按照这个比例在内部生成模拟的位置反馈所以从这个角度说虚拟轴的单位换算逻辑和真实轴是完全一样的。我见过一个项目虚拟轴阶段位置单位没有统一程序里写的位置是mm轴参数里的用户单位却是度导致整个模拟过程的数值含义完全错乱。这种问题如果你在虚拟轴阶段不仔细到了真机上排查起来会非常痛苦。4.2 速度与加减速怎么选速度和加减速的整定核心是回答一个问题工艺要求多少时间内走多少距离。我常用的计算逻辑是这样的假设目标位置500mm希望2秒内走完并且使用梯形速度曲线。先估算加减速时间比如加速和减速各占0.3秒。如果设定匀速段速度为250mm/s那么加速段位移是0.5乘以加速度乘以加速时间的平方。加速度如果按833mm/s²来算加速段位移约37.5mm减速段同理37.5mm匀速段位移就是500减去75等于425mm需要匀速时间1.7秒。总时间约2.3秒。这个结果略微超时那么可以把速度提高到280mm/s或者减小加速时间再重新核算。在虚拟轴上你不需要担心加速度过大损坏机械可以放心地验证不同参数下的运动时间。但我遇到不少工程师在这里走了弯路在虚拟轴上随便填一个巨大的速度看起来轴嗖一下就到位了但实际上真实设备根本达不到这个速度后面换真机还得全部重算。所以我的建议是虚拟轴阶段的速度、加速度就按项目实际标称值来填把轨迹规划层面的节拍时间验证准确这才是虚拟轴最有价值的用途。4.3 Jerk急动度的作用部分CODESYS运动控制指令支持Jerk参数也就是急动度限制。它的物理意义是加速度的变化率。如果没有急动度限制速度曲线是梯形的加速度在启动和停止瞬间会产生阶跃机械上表现为冲击和震动。加了急动度限制之后速度曲线变得更平滑加速度曲线变成斜坡机械冲击大幅减小。但Jerk不是越大越好也不是越小越好。设得太大相当于没有限制设得太小运动会变得非常平缓到位时间明显拉长。虚拟轴阶段建议做一组对照测试同样的一段行程分别设置不同的Jerk值记录实际的到位时间和速度波形用数据来确定项目里能够接受的急动度范围。这个方法可以给机械工程师提供非常直观的设计依据。5. 让虚拟轴的运行过程看得见5.1 为什么不能只盯最终到了没验证单轴运动是否正常如果只看最终位置到了没那只能证明指令路径没有大错无法发现很多潜在问题。比如轴到位后有没有超调、停止时速度曲线是否平滑、指令状态和实际运动状态是否一致这些都需要把变量随时间变化的过程记录下来。在虚拟轴阶段养成记录波形的习惯到真机调试时会事半功倍。因为你提前知道了运动逻辑层面的正常曲线长什么样真机上一旦出现偏差你就能快速判断是逻辑问题还是机械问题。5.2 CODESYS内置Trace的使用CODESYS开发环境自带Trace软示波器功能用来记录变量随时间变化的曲线。在工程中添加一个Trace对象然后在变量列表里选择要记录的变量比如轴的实际位置、速度、轴状态字、你自定义的工艺状态变量。配置Trace时有两个关键项采样周期和触发条件。采样周期建议设置成任务的扫描周期或者略快一些比如5ms这样能捕捉到速度曲线的细节。触发条件可以设为某个变量达到特定值时开始记录比如轴启动瞬间方便观察完整运动过程。运行程序后Trace会把数据记录在开发环境的缓存中结束后可以导出成CSV文件用Excel分析。判断运动曲线时我一般先看位置曲线是否顺滑再看速度曲线是否存在正负跳变甚至阶跃。如果速度曲线在停止段出现异常尖刺多半是停止指令和定位指令之间存在状态竞争优先排查是否有其他程序段在同时操作同一个轴。5.3 符号配置与第三方录波按毫秒级把轴状态抓出来CODESYS内置Trace适合开发阶段的快速观察但如果要连续记录长时间数据、或者把数据送到上位机做曲线展示我会用符号配置加第三方数据采集工具的方式。在CODESYS工程中启用符号配置功能把需要暴露给外部访问的变量勾选出来也可以生成符号文件。这一步是整个数据通路的前提。很多数据采集软件、OPC UA客户端、HMI系统都依赖这个符号信息才能访问到轴的位置、速度、状态码。如果你发现上位机读不到CODESYS里的运动数据第一个检查点就是符号配置里有没有勾选这些变量、变量是否允许写、访问权限是否正常。我实际用过PLC-Recorder这个工业数据采集工具来读取CODESYS变量它可以按设定的周期把轴位置、速度、状态、自定义工艺变量抓取出来自动生成趋势曲线也可以导出数据文件。相比内置Trace第三方工具的优势是采集周期可以非常短而且数据落地方式更灵活适合长时间记录设备运行状态。如果项目还需要把运动轨迹和工艺记录写入数据库CODESYS有相关的数据库类库社区里也有第三方提供的MySQL等数据库库文件。但我的经验是先别急着纠结用什么库把采什么变量、每秒采多少次、异常时怎么标记这几个问题设计清楚否则数据库里存的都是没用的噪音数据。运动控制的数据量看起来不大但如果你用1ms周期同时记录十几个轴变量一天下来的数据量足够让你重新审视表结构设计。5.4 我看到过的典型波形问题我在虚拟轴调试中遇到过两个高频问题很有代表性。第一个是速度曲线末端出现明显过冲。虚拟轴没有真实机械惯性它的反馈是模拟出来的出现这种过冲说明你在参数里设置的速度和加速度组合本身就不合理。比如加速度太大轨迹规划器算出来的目标速度还没来得及收敛位置就已经到达目标于是产生反向修正。在虚拟轴阶段发现这个问题比在真机上发现要省心得多。第二个问题是定位完成信号被其他指令抢占。位置明明已经到了轴状态也回到了Standstill但上位机就是收不到Done。排查发现是因为程序中另一个功能块也在不断调用同一个轴的指令把完成状态覆盖掉了。这类问题在虚拟轴阶段最容易暴露因为它和机械无关完全是由程序逻辑和指令调度引起的。6. 换到真实轴之前必须完成的几件事6.1 硬件选型和轴类型换型虚拟轴验证通过后把轴对象从Virtual类型改成真实驱动类型是必然的一步。可能是EtherCAT总线伺服、CANopen驱动器也可能是PTO脉冲轴。改类型本身不难但类型切换之后必须重新核对一批参数。我会重点关注四个地方单位缩放比例、软限位范围、回零方式、驱动器使能信号。虚拟轴阶段的缩放比例是按理想几何关系配的真实设备上可能存在传动比误差需要按实际传动机构修正。虚拟轴没有回零开关换到真机后要明确回零方式是找原点开关、限位开关还是绝对值编码器。驱动器使能这块虚拟轴上无所谓真机上就要考虑上电时序、伺服使能信号、急停回路之间的配合。6.2 使能时序与安全逻辑的差异从虚拟轴切换到真实轴最大的变化是真的会动、真的会撞。安全逻辑不能再停留在纸面上。我养成的一个习惯是任何运动指令执行前都要先判断Power.Status和Home.Done这两个条件缺少任何一个都不放行。在虚拟轴阶段这个判断看起来有点多余因为虚拟轴随便怎么折腾都不会出事但到了真机上这两行判断就是一道关键安全屏障。急停逻辑也需要在虚拟轴阶段提前写好框架急停触发后先发MC_Stop让轴尽快停止等轴验证已经停止后再释放使能。不要尝试在急停信号一触发就直接撤使能那样伺服会失去保持力矩反而可能因为重力或外力产生危险动作。6.3 我踩过的一个典型坑说一个我的真实经历。有一个项目虚拟轴阶段所有动作都正常位置、速度、节拍全部验证通过。结果真机第一次定位时轴直接冲过了目标位置速度还明显偏快。查了半天才发现虚拟轴阶段我把单位缩放比例配错了程序里写的是mm但轴参数里的位置单位配置成了脉冲数等于所有位置和速度都差了一个量级。这件事给我的教训是从虚拟轴切换到真实轴必须从头查一遍单位、缩放和反馈分辨率而不是只换轴类型就完事。虚拟轴本身不会告诉你单位配错了因为它在内部会把任何合理的数值都模拟成一个看似正常的运动。只有到了真机上物理世界的距离才会无情地把错误暴露出来。6.4 推荐的项目开发节奏经过几个项目的摸索我现在基本固定了一套节奏先用虚拟轴把运动状态机、工艺流程、HMI交互全部调通。然后在虚拟轴上刻意模拟各种异常场景比如超软限位、轴未回零就执行绝对定位、未使能就发运动指令验证错误恢复流程是不是完备。真机到货后先空载低速验证确认方向和单位正确后再带载跑节拍。整个过程中运动控制代码的主体框架基本不用大改因为虚拟轴阶段已经把逻辑层的坑都填平了。最后再分享一个小技巧在虚拟轴单轴验证阶段把轴的速度、位置、状态码加上你自己的工艺步骤号统一放进一个全局结构体里。不管是后面接触摸屏、上位机、数据采集工具还是数据库存储都从这个结构体取数。这样做的好处是从虚拟轴到真机从demo到正式项目你的外部接口几乎不用变省去大量改变量的时间。