☰
PackML状态机与PackTags:从统一状态模型到设备数据标准化的落地指南
2026/10/1 16:19:53 网站建设 项目流程

干了十几年自动化项目,我一直有个特别头痛的事:车间里十台不同厂家的包装机,就有十套完全不一样的状态字定义。有的设备给一个 INT,0 代表运行、1 代表停机;有的给一串 BOOL,哪个亮了大家自己猜。每次做产线级 MES 或 SCADA 对接,光翻译这套"厂家黑话"就能耗掉一两周。后来被一个外资项目逼着学了 PackML,才算是把这块硬骨头彻底啃了下来。

PackML 是 Packaging Machine Language 的缩写,翻成大白话就是"包装机器语言",它的核心内容来自 ISA-TR88.00.02 标准,本质上解决了两个问题:一是给设备定义一套统一的状态模型,让所有人用同一套词描述"机器现在在干嘛";二是给数据接口定义一套标准标签,也就是 PackTags,让上位机不用再对着点表猜半天。这篇笔记我不打算照抄标准原文,而是按我自己从零学到在一套小型灌装线上落地的完整过程来写,重点讲清楚"为什么这样做"以及实际踩过的坑,适合刚开始接触 PackML 的 PLC 工程师、自动化集成商,以及被设备对接搞得焦头烂额的项目经理。

1. PackML 到底是什么:从包装车间的"语言不通"说起

1.1 为什么包装行业需要统一的状态模型

包装产线有个很尴尬的现状:灌装机可能是德国品牌,旋盖机是意大利的,贴标机是国产的,三台设备控制方式、通讯协议、状态定义全都不一样。单机调试没问题,一旦要联线做集中监控,麻烦就来了。

举个我实际遇到的例子:A 品牌的灌装机用整型变量来表示状态,1 是自动运行,2 是手动,3 是故障;B 品牌的贴标机却用一组布尔量,X10 亮代表待机,X11 亮代表生产中。工人在 HMI 上看到的是两套完全不同的画面,MES 取数更得分别写两套解析逻辑。这还只是三台设备,整条线十几台设备的时候,集成工作量完全失控。

PackML 的思路特别朴素:既然大家都要描述"待机、运行、暂停、故障"这些基本状态,那就干脆规定一套统一的说法,谁也别自己发明。这套统一说法就是 PackML 状态模型,它把包装设备的所有运行工况收敛成 17 个标准状态,用 9 个标准命令来控制状态切换。设备厂商按照这个模型写程序,集成商按照这个模型做对接,两边都不用再互相迁就。

1.2 PackML 的出身:ISA-88 标准家族

PackML 全称 Packaging Machine Language,最早其实是美国 OMAC(Organization for Machine Automation and Control,机器自动化与控制组织)为包装行业提出来的一套实践准则,后来被 ISA(国际自动化协会)采纳,发布为 ISA-TR88.00.02 技术报告。

很多人不知道 PackML 和 ISA-88 的关系。ISA-88(对应 IEC 61512)是流程行业的过程控制标准,最出名的就是 S88 批次控制模型。PackML 可以理解为把 S88 的批处理思想"降维"应用到离散的包装机械设备上,把设备当作一个"单元"(Unit)来管理,把一批料的生产过程用"状态 + 命令"来描述。所以学 PackML 之前,如果了解一点 S88 里的设备阶段(Equipment Phase)和控制模块思想,上手会快很多。

顺手说一下,PackML 旁边还有个 PackTags 概念,两者经常被放一起提。状态模型解决"机器在干嘛",PackTags 解决"数据叫什么名字、怎么组织"。一个是动作规范,一个是数据规范,合在一起才是一套完整的东西。

1.3 学 PackML 前需要建立的两个基本认知

第一个认知:PackML 不是一种硬件,也不是一种通讯协议。它和 Profinet、EtherNet/IP 不冲突,相反,它可以跑在任意平台上。PLC 程序里可以按 PackML 写,上位机 C#、Python 里也可以按 PackML 模拟,ARM 单片机上照样能做。它是一套"组织逻辑"的标准,不是设备选型标准。

第二个认知:PackML 不是万能的。它规定的是设备对外呈现的状态框架,但设备内部每个状态里具体怎么动作,你自己说了算。比如 Execute(执行)状态下灌装泵转速多少、旋盖扭矩多大,PackML 不关心;它只关心你对外宣称"我在执行"。所以它解决了"设备间互操作"的问题,但不解决"单台设备怎么控制"的问题。这两件事必须分清楚,否则你会拿着标准去抠不该抠的细节。

2. 状态模型拆解:机器怎么从"只会开停"变成"会说状态"

2.1 状态、命令、转换:三个词看懂状态机

PackML 状态模型看着有一堆术语,其实核心就三个概念:状态、命令、转换条件。

状态就是设备当前所处的工况,比如 Idle(待机)、Execute(执行)、Held(保持)、Aborted(已中止)。命令是你发给设备的控制指令,比如 START、STOP、HOLD、ABORT。转换条件则是状态能不能切换过去的判断依据,比如"启动命令已发,同时安全门关闭、无报警、伺服在原点",满足这些条件,状态机才允许从 Idle 走到 Starting 再走到 Execute。

我习惯把它类比成电梯:楼层是状态,按钮是命令,门关了、没超载、目标楼层到了这些就是转换条件。按了关门按钮不等于马上能走,必须所有条件满足才真的启动。设备控制如果少了"转换条件"这一步,就会出现"按钮都按了设备就是不动"或者"状态乱跳"的灵异现象。

2.2 17 个状态的记忆方法:稳定态与过渡态

PackML 标准的 17 个状态乍一看很多,背下来很痛苦。我的记忆诀窍是先分成两组:稳定态和过渡态。

稳定态是设备会长时间停留的状态,一共 7 个:Idle、Execute、Held、Suspended、Complete、Stopped、Aborted。过渡态是状态切换过程中经过的中间状态,名字基本都是-ING 结尾,一共 10 个:Resetting、Starting、Completing、Holding、Unholding、Suspending、Unsuspending、Stopping、Aborting、Clearing。

类型状态名称简单理解
稳定态Idle待机,允许启动
稳定态Execute正在生产
稳定态Held被操作员/工艺暂停
稳定态Suspended因临时条件挂起
稳定态Complete批次/产量完成
稳定态Stopped正常停机
稳定态Aborted故障中止
过渡态Resetting / Starting / Completing 等切换过程,瞬间掠过

过渡态存在的意义在于:设备从一个稳定态换到另一个稳定态,往往需要执行动作。比如从 Stopped 到 Idle 不是"啪"一下就过去的,中间可能要做复位气缸、回原点、清故障记忆这些动作,这些动作执行的期间就是 Resetting。如果你把复位动作也放在 Idle 里做,那么上位机读到 Idle 时会误以为设备已经准备好,实际上机械还在动,容易出安全问题。所以过渡态不只是为了好看,它是安全语义的一部分。

2.3 模式(Mode)机制:一台机器多种身份

状态模型之外,PackML 还有一个容易被忽略的维度:模式(Mode)。标准里常见模式包括 Automatic(自动)、Semi-Automatic(半自动)、Manual(手动)、Cleaning(清洗)、Maintenance(维护)。

模式和状态是两个正交的概念。打个比方,状态是"车在什么档位",模式是"谁有资格碰方向盘"。全自动模式下,操作员只能按启动停止;手动模式下,维修工可以单动某个气缸;保养模式下,某些安全联锁会被旁路。同一台设备,在不同模式下,同一个状态里执行的动作可能完全不同。

实际工程里,模式和状态要分开存储、分开显示。HMI 上既要看到当前状态(State),也要看到当前模式(Mode)。我见过有的项目图省事,把模式和状态合成一个变量,结果 Manual 模式下运行状态让 MES 误判为自动生产,产量统计全乱了。单独用两个变量,逻辑清爽,后面查问题也方便。

3. PackTags:把变量名和数据结构也变成行业通用语言

3.1 PackTags 到底长什么样

状态模型解决的是"语义统一",但这还不够。假设全厂设备都按 PackML 写了状态机,结果 A 设备把状态放在 DB10.DBW0,B 设备放在 MD20,C 设备放在 %MW100,那对接依然是噩梦。PackTags 的价值就在这里:它把数据访问接口也标准化。

PackTags 说白了就是一套命名规范和数据组织规范。我记得很清楚,第一次在项目文档里看到Line1_Filler_PAC_State这种命名时,整个人都清爽了。看到名字就知道:Line1 区域、Filler 这台设备、反馈的是 PackML 状态。不需要查点表,不需要问设备厂家,这就是标准化的力量。

下面是一个常见的 PackTags 命名例子:

Line1_Filler_PAC_State // 灌装机当前状态 Line1_Filler_PAC_Mode // 灌装机当前模式 Line1_Filler_FAST_ProducedCount // 灌装机总计数 Line1_Filler_FAST_ProducedGoodCount // 灌装机良品计数 Line1_Filler_FAST_OperatingTime // 运行时间累积

命名规律基本是[区域]_[设备]_[标签类型]_[具体含义],区域和设备前缀由项目自己定义,后面跟的核心标签名按标准字段来。这样不同项目、不同厂商的设备,只要遵循同样的命名,上位机程序可以做成完全通用的模板。

3.2 核心 PackTag 分类与含义

PackTags 标准内容很多,真正高频用到的其实就三大类。

第一类是命令类,通常叫PAC_Command系列,包括 PAC_RESET、PAC_START、PAC_STOP、PAC_HOLD、PAC_ABORT 等。上位机或 MES 要控制设备时,不是直接去改设备的内部变量,而是往这些命令标签上写脉冲,由设备内部状态机自己判断这个命令当前允不允许执行。这样就把"命令的合法性判断"留在了设备侧,集成商不用在每次对接到不同设备时重复写一堆防呆逻辑。

第二类是状态类,核心是PAC_State和PAC_Mode。PAC_State 是当前状态编号,PAC_Mode 是当前模式编号。上位机只管读这两个值,再配一张枚举映射表,就能知道全厂设备状态。很多项目甚至直接把这个值往 HMI 的图形控件上绑,状态变颜色自动变,省掉大量脚本。

第三类是绩效类,也就是FAST_系列标签。FAST 在这里是 Factory Automation Standards Team(工厂自动化标准团队)的产物,专门为 OEE 统计准备了累计变量,比如总产量、良品数、次品数、运行时间、故障时间、停机次数等等。这些标签是 OEE 计算的数据地基,如果每个设备都按统一名字提供,MES 端写 OEE 报表就是标准模板插值,不用每个设备单独适配。

3.3 为什么说 PackTags 是 OEE 的数据地基

聊到 OEE,我可以多说几句。OEE 的计算公式是可用率 × 性能率 × 良品率,看着简单,真正统计起来最痛苦的是数据来源不统一。

以可用率为例,OEE 里的"可用时间"是用总时间减去停机时间。问题是"停机"的定义各厂不同:有的厂家把操作员按暂停也算故障,有的把换规格时间不算停机,出来的 OEE 数字根本没法横向比较。PackML 的 FAST 标签把时间类变量拆成 OperatingTime、ProductionTime、FailTime、RestartTime 等标准字段,每种时间的起止边界都有约定。这样大家都在同一把尺子上量,OEE 才有可比性。

我见过一家企业上了 PackML 改造之后,MES 报表从"手动填 Excel"变成"全自动生成",而且各车间数据口径完全一致,老板终于可以拿着同一套指标对比不同产线了。这就是 PackTags 的深层价值:它不只是变量命名规范,更是让管理数据具备可比性的基础设施。

4. 实操落地:一套小型灌装线的 PackML 改造实录

4.1 场景设定:灌装-旋盖-贴标产线

理论说再多,不如动手做一遍。我以一套比较典型的小型灌装线为例:空瓶上料 → 灌装 → 旋盖 → 贴标 → 剔除站,五个工位,用一台 PLC(或软 PLC)控制整线。目标是按 PackML 做状态建模,并向上位机提供标准数据接口。

做这个项目之前,先要明确每个站点的"单元"(Unit)和"控制模块"怎么划分。PackML 里最小单位是"单元",可以是一台机器,也可以是一条生产线。我建议第一次落地的项目,先把整条线当作一个单元,对外只呈现一套状态;内部五个工位的细节状态先不对外暴露。等把 PackML 的状态机跑顺了,再尝试把每个工位建成独立单元,形成多级状态体系。

原因很简单:PackML 落地最大的障碍不是标准难,而是范围和粒度没定清楚。粒度越细,转换条件越复杂,编程量指数上升。先用整线一个单元跑通闭环,建立起信心和模式,比一开始就追求完美建模重要得多。

4.2 第一步:状态映射与转换条件表

落地第一步,不是写代码,而是做状态映射。把你现有程序里的所有工况,逐个对应到 PackML 的 17 个状态里。下面是我按灌装线做的映射表:

PackML 状态灌装线实际含义进入该状态的判定条件
Stopped停机待复位上电初始,或按下停止后停稳
Idle待机,等待启动无报警、安全门关、参数加载完成
Starting启动中收到 START,伺服回零开始
Execute正常生产启动完成,灌装阀、旋盖头、贴标头联动
Held操作员暂停按下 HOLD,且当前批次产品未完成
Suspended挂起等待贴标机标签卷用完自动等待换卷
Stopping正常停机中收到 STOP,设备按减速曲线停稳
Stopped已停机停稳完成
Aborting故障中止中收到 ABORT 或安全急停触发
Aborted已中止故障停止动作完成
Complete批次完成产量达到目标值 5000 瓶

这张表做完,先别急着写状态机,逐条检查转换条件是否完备。这里我有个经验:转换条件最容易漏的是"初始位置"类条件。比如从 Idle 到 Starting,很多新手只判断"无报警",结果启动时灌装头没在原点,直接撞机械。所以转换条件表里,每个伺服轴的"回原点完成信号"必须列进去。

4.3 第二步:PLC 程序里怎么写状态机

状态映射做完,就可以写程序了。PLC 里写 PackML 状态机,我推荐用 CASE 语句配合显式的转换条件,而不是用一堆 SET/RESET 位区绕来绕去。下面是一段结构化文本风格的伪代码:

CASE g_State OF ST_STOPPED: IF rqReset AND TC_ResetOK THEN g_State := ST_RESETTING; END_IF; ST_RESETTING: IF TC_ResetDone THEN g_State := ST_IDLE; END_IF; ST_IDLE: IF rqStart AND TC_StartOK THEN g_State := ST_STARTING; END_IF; ST_STARTING: IF TC_StartDone THEN g_State := ST_EXECUTE; END_IF; ST_EXECUTE: IF rqStop THEN g_State := ST_STOPPING; ELSIF rqHold THEN g_State := ST_HOLDING; ELSIF rqAbort THEN g_State := ST_ABORTING; END_IF; // ... 其他状态类似 END_CASE;

写这段代码有几个要点。第一,命令变量(rqStart、rqHold 等)和状态变量(g_State)必须分开定义。命令是上位机或按钮触发的一次性脉冲,状态是设备内部持续保持的工况,二者不可混用。第二,每个过渡态(如 RESETTING、STARTING)都要有明确的完成条件,否则状态机会卡在过渡态。第三,ABORT 命令在几乎所有状态下都应该被响应,它是最优先级的命令,优先级判断要在其他命令之前。

如果你项目用的是 Python、C# 做上位机模拟,也可以用字典加条件判断实现同样的状态机。无论什么语言,思想都是一样的:状态只允许在合法转换路径上移动,不允许随意跳转。这个约束看起来死板,实际上保证了设备行为的可预测性,出问题时也容易回溯。

4.4 第三步:PackTags 配置与 HMI/上位机对接

状态机程序在 PLC 里跑起来之后,下一步就是把这些状态映射到 PackTags 上。

我通常的做法是在 PLC 里定义一个全局数据块,统一存放所有对外接口标签。这个数据块就像设备的"对外窗口":上位机只读这里,不读里面的工艺细节。数据结构大概长这样:

// 对外接口 DB ALine_Filler_PAC_State : DINT; // 当前状态编号 ALine_Filler_PAC_Mode : DINT; // 当前模式编号 ALine_Filler_FAST_TotalCount : DINT; // 总产量累计 ALine_Filler_FAST_ProducedGoodCount : DINT; // 良品累计 ALine_Filler_FAST_OperatingTime : LREAL; // 运行时间累计(小时)

对接 HMI 的时候,可以把整个数据块做成一个 UDT 类型,画面里的状态显示、按钮、报警灯全部绑定到标准标签上。这样以后接第二台设备,直接把 HMI 画面复制一份,改一下设备前缀就行,画面模板可以做到一套通用,这是 PackML 在工程实施里最直观的效率提升。

再往上对接 MES 或 SCADA,我推荐用 OPC UA 把数据块暴露出去,节点树直接按 PackTags 命名映射。MES 端写一个通用读取客户端,扫描全厂所有设备的 PAC_State、FAST 系列标签,就能实现全厂状态总览和 OEE 报表,遇到新设备进来不需要改上位机代码。

5. 常见问题与排查技巧实录

5.1 高频问题速查表

做 PackML 落地这一年多,我遇到过的问题不少,整理了一个排查速查表,分享给大家:

现象可能原因排查方法
状态一直卡在 Starting 无法到 Execute转换条件(TC_StartDone)不满足逐条检查伺服回零、安全、压力等条件信号
按了 ABORT 设备没进 AbortedABORT 命令优先级被其他逻辑覆盖检查 ABORT 是否在状态程序最前面被无条件响应
上位机状态和 HMI 显示不一致地址映射错误或两个端在读不同变量确认两边读的是同一个 PAC_State 变量
复位后直接进入 Execute,没经过 Idle复位的目标状态设置错误确认 RESET 的目标统一为 Idle
MES 统计的产量比实际少FAST_ProducedCount 没有被正确累计检查计数脉冲是否只在 Execute 状态下有效
HOLD 后设备还在继续走HOLD 命令被下降沿误判HOLD 应使用电平或带确认的脉冲,不能用简单边沿

5.2 状态"卡死"的三种典型原因

"状态卡死"是我被问得最多的问题,现象就是设备显示停在某个过渡态不动,比如一直 Starting、一直 Resetting。按我排查下来的经验,绝大多数卡死就三种原因。

第一种是过渡态没有完成条件。写状态机的时候只写了进入过渡态的逻辑,忘了写"什么时候算完成"。比如从 Stopped 进 Resetting 后,程序里没有 TC_ResetDone,状态自然永远困在 Resetting。这种问题代码评审时最容易抓出来,用状态转换表逐条核对就能避免。

第二种是完成条件信号被前面环节吞掉了。最常见的是边沿问题:完成信号是转瞬即逝的脉冲,PLC 扫描周期慢一点,CASE 语句就错过了。解决办法是把这个脉冲锁存一拍,或者状态机采用"扫描周期内多次判断"的方式,别让一个脉冲信号直接决定生死。

第三种是安全逻辑和状态机逻辑打架。设备本身有急停回路,急停按钮一按,安全继电器直接把输出切断,状态机程序还在按部就班跑。这种情况不是状态机的错,是外围安全回路没和状态机做好交互。我的处理方式是:把安全电路的急停信号同时映射成一个 ABORT 触发条件,让安全事件既切断输出,也通知状态机实施转向 Aborting,两边保持一致。

5.3 新手最容易搞混的概念:HOLD 和 SUSPEND

最后单说一个我见过无数人搞混的点:HOLD(保持)和 SUSPEND(挂起)到底有什么区别。

从直觉上看,这两个状态都是"暂停生产",很多项目图省事只用一个。但它们的设计意图完全不同。HOLD 是操作员或工艺主动介入的暂停,比如发现灌装量精度异常,操作员按 HOLD 停一下去检查,此时产品还留在设备里,工艺数据要保持住。SUSPEND 是设备自己感知到临时外部条件而挂起,比如提升机里没瓶子了、贴标标签纸用完了,等条件恢复后自动回来,通常不需要操作员参与。

换句话说,HOLD 偏"人",SUSPEND 偏"系统"。设计状态机时一定要和工艺人员确认清楚哪些情况用 HOLD,哪些用 SUSPEND。我见过一个项目把缺料设计成 HOLD,导致操作员频繁去复位,给生产添了不少乱。后来改成 SUSPEND,缺料自动挂起、有料自动恢复,操作员彻底解放出来了。

实战里如果要选一个词先学透,我觉得不是状态机本身,而是这一组"命令-转换条件-稳定态"的三层关系。把这套思维模式建立起来,就算不背 17 个状态的名字,看到任何设备的管控逻辑也能很快套进 PackML 的框架里。以后碰到新项目,我的习惯是第一件事先画状态转换表,第二件事定义标签命名,逻辑想清楚了再动 PLC,这比埋头写代码有效率得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询