第三章 轴组状态机:状态机模型、状态转换条件、状态管理函数

各位工程师朋友,咱们今天聊聊轴组状态机。说实话,这东西是轴组控制的核心骨架。你想想看,一个多轴系统要协调运动,没有一套清晰的状态管理机制,那不乱套才怪。

我个人习惯把状态机比作一个「交通指挥系统」。每个轴组就是一个路口,状态机就是红绿灯和交警。什么情况下能走,什么情况下必须停,什么情况下要紧急刹车——都得有明确规则。

3.1 轴组状态机模型

PLCopen 标准定义了轴组的几个核心状态。我直接画了个图,方便你理解它们之间的关系。

轴组状态机模型 未配置 Not Configured 空闲 Idle 停止 Stopping 运行 Running 错误停止 ErrorStop 故障 Fault MC_Power(TRUE) MC_Stop 停止完成 MC_Move* / MC_GroupEnable MC_Stop / 错误 严重错误 错误 MC_GroupReset MC_Power(FALSE) → MC_Power(TRUE)

这张图我建议你保存下来。每次写轴组程序前,先对照着看一遍,能少踩很多坑。

3.2 状态转换条件详解

每个状态之间的转换,都有明确的触发条件。我按实际项目中的使用频率,给你梳理一下。

当前状态 目标状态 触发条件 常用函数
未配置 空闲 轴组上电成功 MC_Power(TRUE)
空闲 运行 启动运动指令 MC_MoveLinear, MC_MoveCircular
运行 停止 收到停止指令或触发停止条件 MC_Stop
停止 空闲 停止动作完成 MC_Stop.Done
运行 错误停止 检测到严重错误 自动触发
错误停止 故障 错误确认 MC_GroupReset
故障 空闲 重新上电 MC_Power(FALSE)→MC_Power(TRUE)
核心要点:轴组状态机是「单向循环」结构。从空闲到运行,从运行到停止,再从停止回空闲。错误状态是「旁路」,一旦进入,必须手动复位才能回到正常流程。

3.3 状态管理函数

PLCopen 标准里,状态管理函数就那么几个。但每个函数怎么用、什么时候用,这里头有讲究。

3.3.1 MC_Power — 轴组上电/断电

这个函数是轴组控制的「总开关」。我个人习惯在程序启动时,先调用一次 MC_Power(TRUE),把轴组从「未配置」拉到「空闲」状态。

// 轴组上电示例
MC_Power_Instance(
    AxisGroup := AxisGroup_1,
    Enable := TRUE,
    EnablePositive := TRUE,
    EnableNegative := TRUE,
    Status => PowerStatus,
    Busy => PowerBusy,
    Error => PowerError,
    ErrorID => PowerErrorID
);
我的经验:上电时一定要检查 EnablePositive 和 EnableNegative 参数。我曾经在一个项目中,只使能了正方向,结果负方向运动时直接报错。后来我养成了习惯,只要不是特殊需求,两个方向都使能。

3.3.2 MC_Stop — 轴组停止

停止函数分两种:正常停止和紧急停止。正常停止用 MC_Stop,紧急停止我建议用硬件急停信号直接切断驱动器使能。

// 正常停止示例
MC_Stop_Instance(
    AxisGroup := AxisGroup_1,
    Execute := StopTrigger,
    Deceleration := 1000,  // 减速度,单位 mm/s²
    Jerk := 5000,          // 加加速度,单位 mm/s³
    Done => StopDone,
    Busy => StopBusy,
    Error => StopError,
    ErrorID => StopErrorID
);

这里要注意 Deceleration 和 Jerk 的取值。减速度太大,机械结构会「点头」;太小,停止距离过长。我一般先按额定值的 80% 设置,现场再微调。

3.3.3 MC_GroupReset — 错误复位

轴组进入「错误停止」状态后,必须调用 MC_GroupReset 才能回到「故障」状态。注意,它不能直接回到「空闲」。

避坑指南:我曾经在调试时,发现 MC_GroupReset 调用后轴组没反应。查了半天,原来是复位信号只维持了一个扫描周期。记住:Execute 输入必须保持为 TRUE,直到 Busy 变为 FALSE。

3.3.4 MC_GroupEnable / MC_GroupDisable — 轴组使能/禁能

这两个函数用于在「空闲」状态下,临时禁能轴组。比如你要手动点动某个单轴,可以先禁能轴组,操作完再使能。

// 轴组禁能示例
MC_GroupDisable_Instance(
    AxisGroup := AxisGroup_1,
    Execute := DisableTrigger,
    Done => DisableDone,
    Busy => DisableBusy,
    Error => DisableError,
    ErrorID => DisableErrorID
);

3.4 状态机编程实战要点

理论说完了,咱们聊聊实战中怎么用。我总结了几个关键点:

  1. 状态轮询不能停:每个扫描周期都要检查轴组当前状态。我习惯用一个 CASE 语句做状态分发。
  2. 状态转换要加互锁:比如从「运行」到「停止」,必须确认 MC_Stop 的 Done 信号为 TRUE,才能切到「空闲」。
  3. 错误处理要分级:轻微错误可以自动复位,严重错误必须人工介入。我在项目中用了一个错误计数器,连续 3 次自动复位失败就锁定为「故障」状态。
// 状态机轮询示例(结构化文本)
CASE GroupState OF
    IDLE:
        IF StartCommand THEN
            MC_MoveLinear_Instance(Execute := TRUE);
            GroupState := RUNNING;
        END_IF
        
    RUNNING:
        IF StopCommand THEN
            MC_Stop_Instance(Execute := TRUE);
            GroupState := STOPPING;
        END_IF
        IF ErrorDetected THEN
            GroupState := ERROR_STOP;
        END_IF
        
    STOPPING:
        IF MC_Stop_Instance.Done THEN
            MC_Stop_Instance(Execute := FALSE);
            GroupState := IDLE;
        END_IF
        
    ERROR_STOP:
        IF MC_GroupReset_Instance.Done THEN
            GroupState := FAULT;
        END_IF
        
    FAULT:
        IF MC_Power_Instance.Status THEN
            GroupState := IDLE;
        END_IF
END_CASE
最后说一句:状态机写得好不好,直接决定了轴组控制的稳定性和可维护性。我见过太多项目,状态机写得乱七八糟,出问题根本没法查。花点时间把状态机理清楚,后面能省十倍的时间。

好了,轴组状态机的内容就这些。记住那张状态转换图,记住那几个核心函数,再结合你自己的项目经验,很快就能上手。

公众号:蓝海资料掘金营,微信deep3321