4、单分支状态机设计:从需求分析到SFC图绘制的完整流程

状态机这东西,说白了就是让PLC按顺序干活。你想想看,一个设备如果同时做三件事,那不乱套了吗?单分支状态机,就是最简单、最基础的那种——一条路走到黑,干完一步再干下一步。

我个人习惯,拿到一个控制需求,先不急着写代码。先画图,把脑子里的逻辑理清楚。今天我就带你走一遍完整的流程,从需求分析到SFC图绘制,每一步我都会说说我踩过的坑。

4.1 需求分析:先搞清楚设备要干什么

我记得刚入行那会儿,有个老工程师跟我说过一句话:「你连设备怎么动都不知道,写什么程序?」这话糙理不糙。需求分析,就是搞清楚设备有几个动作,动作之间什么关系。

举个例子,一个简单的物料搬运系统:

  • 初始状态:机械手在原点,夹爪松开
  • 第一步:机械手下降,抓取物料
  • 第二步:夹爪夹紧,机械手上升
  • 第三步:机械手右移,到放料位置
  • 第四步:机械手下降,夹爪松开放料
  • 第五步:机械手上升,回到原点

你看,这五个步骤是顺序执行的,没有分支,没有跳转。这就是典型的单分支状态机。

关键点:单分支状态机适用于「做完A才能做B,做完B才能做C」的场景。如果设备有多个并行动作,或者需要根据条件选择不同路径,那就得用多分支了。

4.2 状态划分:把动作拆成一个个状态

需求分析完了,接下来就是划分状态。我一般遵循一个原则:一个动作就是一个状态。动作开始到动作结束,算一个完整的状态。

上面那个例子,我们可以划分出这些状态:

状态编号 状态名称 动作描述 转移条件
S0 原点待机 机械手在原点,夹爪松开 启动信号
S1 下降抓取 机械手下降,到位后夹爪夹紧 下降到位 & 夹紧完成
S2 上升搬运 机械手上升,右移到放料位 上升到位 & 右移到位
S3 下降放料 机械手下降,夹爪松开 下降到位 & 松开完成
S4 返回原点 机械手上升,左移回原点 上升到位 & 左移到位

这里要注意,每个状态都要有明确的进入条件退出条件。我曾经在一个项目里,就是因为没定义清楚「下降到位」这个条件,结果机械手还没到位就开始夹紧,直接把工件夹变形了。嗯,从那以后,我对转移条件就特别较真。

4.3 SFC图绘制:把逻辑画出来

状态划分好了,接下来就是画SFC图。SFC(Sequential Function Chart)是PLCopen标准里专门用来描述顺序控制的图形语言。说白了,就是画方块、画箭头。

我画SFC图有个习惯:先画主干,再补细节。主干就是状态和转移条件,细节包括动作输出、定时器、计数器这些。

下面这张图,就是上面那个物料搬运系统的SFC图。我直接用SVG画出来了,你感受一下:

物料搬运系统 - 单分支SFC图 S0 原点待机 启动信号 S1 下降抓取 N 下降输出 N 夹紧输出 下降到位 & 夹紧完成 S2 上升搬运 N 上升输出 N 右移输出 上升到位 & 右移到位 S3 下降放料 N 下降输出 N 松开输出 下降到位 & 松开完成 S4 返回原点 N 上升输出 N 左移输出 上升到位 & 左移到位 循环

画图小技巧:我习惯用不同颜色区分状态和动作。状态用深色边框,动作用浅色背景加虚线框。这样一眼就能看出哪个是状态,哪个是动作。另外,转移条件一定要写在箭头旁边,别写在别处,不然别人看不懂。

4.4 从SFC到代码:怎么把图变成PLC程序

SFC图画好了,接下来就是写代码。PLCopen标准里,SFC可以直接在编程软件里实现。但如果你用的是不支持SFC的PLC,那就得用梯形图或者ST语言来模拟。

我个人比较喜欢用ST语言写状态机,因为逻辑清晰,好维护。下面是一个简单的实现框架:

// 状态定义
CASE state OF
  0: // S0 原点待机
    IF start_signal THEN
      state := 1;
    END_IF
    
  1: // S1 下降抓取
    down_output := TRUE;
    clamp_output := TRUE;
    IF down_sensor AND clamp_done THEN
      state := 2;
    END_IF
    
  2: // S2 上升搬运
    up_output := TRUE;
    right_output := TRUE;
    IF up_sensor AND right_sensor THEN
      state := 3;
    END_IF
    
  3: // S3 下降放料
    down_output := TRUE;
    release_output := TRUE;
    IF down_sensor AND release_done THEN
      state := 4;
    END_IF
    
  4: // S4 返回原点
    up_output := TRUE;
    left_output := TRUE;
    IF up_sensor AND left_sensor THEN
      state := 0;  // 回到原点待机
    END_IF
END_CASE

注意:这里有个坑。每个状态里的输出,一定要在退出状态时复位。不然你从S1跳到S2了,下降输出还开着,那机械手不就一直往下掉了吗?我建议在状态转移之前,先把当前状态的输出全部复位,再进入下一个状态。

4.5 避坑指南:我踩过的那些坑

做单分支状态机,看起来简单,但实际项目中容易出问题的地方不少。我挑几个典型的说说:

  • 转移条件不互斥:我曾经在一个项目里,两个转移条件同时满足了,结果状态机直接跳了两个状态,设备乱套了。后来我加了个互斥逻辑,每次只允许一个转移条件生效。
  • 初始状态没定义:PLC上电后,状态变量默认是0。但如果你定义的第一个状态不是0,那设备就会进入一个未定义状态。我建议把S0定义为原点待机,并且上电后强制进入S0。
  • 超时处理缺失:如果某个状态卡住了,比如传感器坏了,那设备就永远停在那里了。我习惯给每个状态加一个超时定时器,超时了就报警或者回原点。

总结一下:单分支状态机设计,核心就是三步——需求分析、状态划分、SFC图绘制。每一步都要想清楚,尤其是转移条件,一定要定义得清清楚楚。你想想看,如果连条件都没定义清楚,PLC怎么知道什么时候该干什么?

好了,这一章就到这里。记住,画图比写代码更重要。图画好了,代码就是照着图翻译的事。


专注资料整理