MC_Halt与MC_Stop的区别:运动控制中“停下来”的学问
运动控制入门这个系列写到第四篇前面几篇把轴的点动、回零和绝对定位都过了一遍。按正常节奏现在应该能写出第一段能跑的程序了。但后台和群聊里收到的提问反而越来越多集中在“停下来”这件事上同一个停止按钮用MC_Halt写的轴能停用MC_Stop写的轴也能停可真到现场就会撞上怪事——按完停止再给Move指令轴像睡着了一样纹丝不动或者停是停了可停下来的那一下整台机器都跟着抖。这些问题十有八九不是轴坏了而是MC_Stop和MC_Halt的语义没搞清楚。在iFA平台的运动控制库里这两个块都放在停止类指令下但它们在执行优先级、参数来源和停完后的状态上走的是完全不同的路子。这篇文章就专门把这两个块放在一起拆开讲重点回答标题里的问题停下来以后到底有什么不同。1. 停的方式不同一个按既定曲线减速一个按独立参数接管1.1 MC_Halt正常工艺里的“有序刹车”MC_Halt这个块名字本身就带着“暂停”的气质而不是“急停”。触发后轴会按照运动配置里的减速度或者你显式传入的Deceleration参数从当前速度平滑地降到零。它在停止过程中不会主动去踢掉别的运动块也不会改变轴的使能状态。你可以把它理解成开车看见红灯后的正常刹车车速随着你踩刹车的力度线性下降车停住后发动机还在运转随时可以重新起步。在程序里一个正在执行的运动指令比如MC_MoveAbsolute会被Halt“覆盖”轴从动态运动状态平滑进入Standstill。这里要特别注意Halt不是瞬间锁停。它受配置的减速度和jerk限制所以停下来的距离和时间是算得出来的而不是靠刹车片硬扛。对大多数不需要急停的工艺场景用Halt做“暂停”最合适。1.2 MC_Stop带独立停车参数、还要接管轴控制权MC_Stop同样是让轴受控减速到零但它的定位不是“礼貌地让行”而是“强制接管”。它有自己独立的Deceleration和Jerk输入可以不使用轴运动配置里给正常定位用的减速度。换句话说你可以给正常运动配一个很缓的S曲线却给Stop配一个很陡的减速度让它比Halt更快停下来。更重要的是MC_Stop在“命令体系”里的优先级当一个轴上有任意运动指令正在执行时Stop的Execute一上来这些运动指令全部会被打断。被打断的功能块会拉高自己的CommandAborted输出。而Stop本身会一直保持着对轴的控制直到你把它的Execute拉低。这种“我需要你停你就必须停并且停后还得听我口令才能动”的语义才是它和Halt最本质的区别。1.3 先泼盆冷水它俩都不是“急停”聊到这里必须说清楚一个常见误解。有人一看MC_Stop名字里有Stop就觉得它等于急停把硬件安全回路的动作也委托给它。这是很危险的。MC_Stop和MC_Halt都属于运动控制层的“受控停止”它们都依赖伺服驱动还能正常出力轴也是保持使能的。真正的急停通常要走安全模块、伺服驱动器STO端子或者外部接触器回路直接把力矩和功率切断。运动控制里的Stop更多是用来做逻辑联锁、异常流程打断、顺序停机它不是安全层级的东西。理解这一点后面排错时才不会把问题扯到电机控制板上去。2. 扫描时序上的差异谁会被顶掉谁需要释放2.1 Halt可以被新指令“顶掉”停在半路也能重新跑MC_Halt的时序特征是“可以被覆盖”。轴正带着一个Move指令往目标位置跑你让Halt执行轴开始减速减速还没结束你又发起一个新的MC_MoveAbsolute新指令一旦被运动引擎接受原来的Halt会立即把CommandAborted置TRUEHalt退出接管轴会从中途的当前速度重新按新指令加速。这个特性非常重要比如操作员按了暂停发现时机不对又马上按启动程序可以非常自然地做一个“半路返回”不需要把轴彻底停下再重新走一遍流程。很多初学者怕在Halt执行中间发新指令会出问题实际上在标准语义下这是合法的“命令切换”。现场做连续定位时我甚至见过老工程师特意利用这个特性做“下一个位置预判”轴还没完全停住就切进下一段速度省掉一停一起的时间。2.2 Stop会顶掉别人且在释放前一直“锁住”轴MC_Stop的时序完全不同。它的Execute变TRUE后除了让轴减速还会在内部维持一个停止指令状态。这个状态下轴即便已经走到Standstill、Done已经变TRUE新的运动指令仍然不被接受。为什么标准要这么设计很简单Stop通常用于联锁或异常如果停完还能立刻被别的指令续上那联锁就不联锁了。你需要用一个明确的外部信号——通常是把Stop的Execute拉低——来解除这个“锁”。有些实现里还需要在拉低之后再等一个扫描周期或者先清除Error才能让后续的Move开始执行。把话说直白一点Halt停完了就没事了Stop停完了还要负责“看着”轴直到你场外办完“交接手续”。2.3 同一个轴同一时刻只能有一个“主导命令”不管是Halt还是Stop在运动引擎眼里所有作用于同一个轴的功能块是互斥的。新命令的Execute上升沿会让旧命令收到CommandAborted。这里容易踩的坑是一个轴上有几十个运动FB实例你只在梯形图里同时把几个Block的Execute都置TRUE以为“后写的能自动覆盖前面的”其实运动引擎的处理顺序和程序扫描顺序有关覆盖关系很可能和你想象的不一样。所以我的习惯是同轴的Move、Halt、Stop在上位逻辑里明确排优先级Stop最高Move和Halt之间用互锁保证不打架。下面这段ST伪代码可以直接当模板用PROGRAM MAIN_StopHaltDemo VAR fbStop : MC_Stop; fbHalt : MC_Halt; bStopBtn : BOOL; // 来自联锁或急停逻辑 bPauseBtn : BOOL; // 来自操作面板暂停 bMoveOK : BOOL; // 给Move指令的使能许可 END_VAR (* Stop优先级最高且只有在Stop释放后才能允许新运动命令 *) fbStop.Execute : bStopBtn; fbStop.Deceleration : 2000.0; // 单位按轴配置常用mm/s^2 fbStop.Jerk : 20000.0; (* Halt只在没有Stop请求时才生效 *) fbHalt.Execute : bPauseBtn AND NOT bStopBtn; fbHalt.Deceleration : 500.0; (* Move许可既要有Move本身的启动信号也要Stop已释放 *) bMoveOK : bMoveCommand AND NOT fbStop.Execute;注意最后一行bMoveOK并不是把新Move直接接上去而是作为后续MC_MoveAbsolute.Execute的互锁条件。这样即使你在Stop还未释放时误发了一次Move它也不会真正进入运动引擎。3. 停下来之后状态、使能和再启动行为对照3.1 状态机落点都在Standstill但“锁”不一样轴在减速过程中这两个块都会让轴进入Stopping或类似的中途状态速度降到0后轴的状态回到Standstill。如果你只看状态字的最后两位你很可能看不出区别。真正的区别在外围Halt停完后轴控制权是“开放”的任何新运动指令的Execute边沿都会被接受Stop停完后轴控制权被Stop这个实例捏在手里直到Execute下降沿。所以判断“停完没有”不要只看状态字还要看Stop.Done和Execute的配合。3.2 再启动的两种代码写法用Halt时再启动代码极简单MC_MoveAbsolute.Execute : bStartCommand; // 轴会直接从中途或停止状态启动用Stop时必须做一次释放IF bStopBtn THEN fbStop.Execute : TRUE; ELSE fbStop.Execute : FALSE; // 至少要一个扫描周期的低电平 END_IF (* 等Stop.Done变TRUE后再拉低Execute然后再等一小段时间给新Move *)为什么强调“至少一个扫描周期”因为很多库要求在Execute下降沿之后内部停止标志才能清掉。你如果在一个扫描周期内又立刻拉高Move指令运动引擎可能还处在“停止残留”状态新指令会被静默丢弃。我自己调试时习惯在Stop释放和新Move起动之间加一个R_TRIG或定时器延迟500ms宁可多等半秒也不去猜库的内部时序。3.3 一张表把“停完以后”讲透对比项MC_HaltMC_Stop减速参数来源正常运动配置或传入Deceleration独立Deceleration/Jerk可与正常配置不同对其他运动指令会被新指令覆盖并输出CommandAborted主动打断其他指令且在释放前阻止新指令停完后的轴状态Standstill控制权开放Standstill但停止锁存在马上再发Move可以新指令直接接管不行必须先把Execute拉低是否改变驱动器使能不改变不改变典型用途工艺暂停、手动停止、半路切速度门联锁、异常打断、顺序停机Done输出含义轴已完成减速到0轴已完成减速且停止条件已建立这张表建议贴在调试手册第一页。“停完以后能不能立刻动”这一条基本就能筛掉80%的误用。4. 参数怎么给减速度、jerk和停下来这段路4.1 单位先弄对再谈数值在运动控制库里面Deceleration的单位一般是“用户单位/秒²”。如果你的轴用户单位是毫米速度设为500mm/s减速度2000mm/s²那么从500mm/s减到0需要0.25秒停下距离是v²/(2a)250000/400062.5mm。这个公式现场算时特别管用。遇到过有人把减速度当成“百分比”填了5结果轴要跑半天才停下。任何平台都一样参数是物理量不是玄学。4.2 为什么MC_Stop的减速度通常要比MC_Halt狠正常工艺里Move的加减速曲线往往按产品振动和机械寿命来配比较柔和。但MC_Stop处理的是“情况不对要尽快停下来”的场景这时优先考虑的是停止距离和反应时间而不是舒适度。比如同样500mm/s用500mm/s²减速停止距离125mm把减速度加到5000mm/s²停止距离只有25mm时间缩短到0.1秒。差别就是5倍的距离。当然减速度不是越大越好机械结构能承受多大冲击、负载会不会因为惯性滑移这些都要算进去。你可以给MC_Stop单独配一个“紧急但仍在受控范围内”的减速度比如正常减速的3到5倍同时用一个较大的jerk把冲击逐步加上去。4.3 jerk加速度不能突变jerk加加速度描述的是加速度变化率。没有jerk限制时减速度一上来就是最大值相当于猛一脚踩死刹车机械冲击全部打在丝杠、联轴器和工件上。有了jerk限制加速度从0线性爬升到设定值刹车过程更柔和。实际波形上速度曲线会从直线变成S形。MC_Halt如果直接调用轴配置里的曲线往往已经带了平滑但MC_Stop可以单独设置jerk很多人在这一步图省事不填结果停一次机器就响一次。我的建议是MC_Stop的jerk不要设得比正常定位的jerk大太多。虽然停止更着急但机械冲击的代价同样要付通常取正常值的2倍以内比较稳妥。4.4 参数填0时的坑很多库的默认逻辑是Deceleration/Jerk填0就使用轴配置里的默认停靠参数。也就是说“0”通常不代表“不减速”而是“听轴的”。问题是不同项目、不同轴类型轴的默认配置可能完全不一样。上个月我调一台设备电机改过编码器方向后没有同步修改Stop减速度结果Stop一触发轴直接驱动过流报警。排查到最后才发现不是参数写错了是我一直以为“0会用一个默认安全值”其实它用的是某一次现场手填的默认配置。所以我现在的习惯是只要用到Stop/HaltDeceleration和Jerk永远显式传值并且把数值在注释里写明物理单位。这能省掉大半“为什么停不下来”的夜间电话。iFA平台的手册也一样值得你翻到停止类指令那一页把默认值规则抄到程序注释里。5. 场景选型给你四个可以直接照抄的结论5.1 工艺暂停、手动停止优先MC_Halt操作员按下暂停、单步停止或者你只是想临时打断当前Move用Halt。它停得平滑再启动时也灵活即使停在半途新Move也能接管。这种情况如果用Stop强制要释放、要复位最后操作员会很别扭每次暂停之后再启动都要多等一拍。我的经验是凡是操作员面板上的普通暂停键默认都接Halt不要动Stop。5.2 传感器联锁、门开关、后工序异常用MC_Stop当一个外部条件到达要求轴无论正在干什么都必须停并且这个条件没有解除之前不允许再跑直接用Stop。它能打断正在执行的Move并且把“不能动”的状态保持住。注意这说的是逻辑联锁不是安全级联锁真正涉及人身安全的门开关请走硬件安全回路。逻辑联锁里Stop就是最顺手的那把锁。5.3 Stop之后的复位顺序别急着给Move我总结的一套通用复位顺序置位MC_Stop.Execute让轴受控停下并等待fbStop.Done为TRUE。确认所有联锁条件恢复再把MC_Stop.Execute置FALSE。额外等待一个扫描周期或者用一个Delay保证脉冲宽度。处理被Stop打断的Move/Home块的CommandAborted和Error必要时给Error复位。最后才发起Home或Move。第4步很多人会漏。Stop把正在跑的Home打断之后那个Home块会带着ErrorID停在现场你如果不做错误复位就算轴能动了程序还可能因为旧块的Error残留而继续锁定。这个逻辑我写在每一个用到Stop的工程里基本不会再出“停完起不来”的哑弹。5.4 同轴上Stop和Halt共存的写法如果你既需要“暂停”又需要“联锁停”两个块可以同时保留但一定要在逻辑上做互锁。最简单的写法就是Halt的Execute前面串一个NOT Stop条件Move指令的Enable前面也串一个NOT Stop条件。不要幻想运动引擎会自己处理优先级你写代码时把优先级显式化后面换人维护才不会翻车。另外Halt因为被Stop“顶掉”而产生的CommandAborted是正常现象不是故障。调试时看到这个输出为TRUE先检查是不是有更高优先级的Stop在动作别急着清Error。6. 现场调试记录四个最容易踩的坑和完整排查思路6.1 停是停了驱动器还嗡嗡响正常吗正常。MC_Stop和MC_Halt都不管使能轴停住后伺服仍然处于使能状态电机保持额定力矩“吸”住位置有轻微电流声是正常现象。如果你要彻底断电或者松力需要另外用MC_Power把使能拉掉或者给驱动器发控制字里的Disable。别在MC_Stop里面找“断电”功能找不到的。6.2 按完停止再发Move没反应完整排查链路我在现场最常被叫去看的故障就是这个。可以把排查步骤固定下来先看Stop.Done和Busy。如果Stop.Done一直为TRUE且Execute还高这就是“没释放”把条件解开。再看正在发起的Move块的Busy和Error。如果Busy为FALSE、Error有值说明它的Execute边沿根本没进运动引擎大概率是前面的互锁条件没满足。把互锁条件逐个看一遍NOT fbStop.Execute是不是真的为TRUE有些PLC对BOOL上升沿非常挑剔你在同一个扫描周期里既拉低Stop又拉高Move新指令没准只“看”到了原来的停止状态。最后看轴的Error状态。很多情况下Stop的减速度设置过大导致驱动器跟随误差报警轴已经被控制器Disable了。这时发Move当然不动。按这个顺序查基本不用开机就能定位。遇到问题先看信号状态再动代码这是调试的铁律。6.3 Done和Busy看反导致联锁永远不成立有个项目调试时写逻辑的人用了fbHalt.Busy去当“轴已停稳”的信号结果轴明明停住了程序还在等。Halt的Busy在减速过程中为TRUE到达Standstill后变为FALSEDone才变TRUE。Busy表示“命令还在执行”Done表示“执行成功完成”。这两个输出含义完全不同。MC_Stop也一样Busy在Stop执行期间可能一直为TRUE或直到Done前才变FALSE。我的习惯是需要等待命令完成就只看Done需要判断轴当前是否被某个块占用才看Busy。两个信号别混着用。6.4 把“急停”做成MC_Stop后果是什么有一类问题不是程序bug是概念错误。有人把面板急停按钮直接接到MC_Stop.Execute上以为这样就能“急停”。实际效果是轴按你设的“比较陡”的减速度受控停下驱动器继续保持使能按钮不松开轴就一直锁着。如果伺服本身已经因为别的故障失去力矩这个Stop什么都停不住。硬件急停要接到安全回路运动控制里的Stop只负责把轴停到Standstill。这两层不能互相替代。现场如果看到急停之后轴还保持使能这本身就是一种异常信号应该回头检查急停接线而不是改MC_Stop参数。6.5 我的个人调试习惯最后分享一个我自己坚持了很多年的习惯任何运动控制设备第一次上电调试前一定要先做一次“减速参数验证”。把空白轴的当前速度设到50%额定分别触发MC_Halt和MC_Stop用示波器或控制器自带跟踪功能记录速度曲线和跟随误差。不仅要看能不能停还要看停下来用了多长距离、最大冲击多大。把这些数值记录下来写进图纸的调试附表。这样以后不管是改负载还是改速度你都能第一时间发现“这版的停止参数不对劲”。两个Stop块的区别说到底不是纸面上的定义区别而是你现场能不能预测它停完以后每一步会怎么走。