资讯动态

PackML v3.0标准落地指南:状态机、PackTag与PLC实现

发布时间:2026/10/22 13:19:10 来源:尧图企业网站定制
简介这份 PDF 文档是 OMAC 旗下 PackML 子委员会于 2006 年 6 月发布的 PackML v3.0 标准全文面向包装设备制造商、自动化工程师、PLC 程序员与产线集成人员。PackMLPackaging Machine Language旨在为自动化包装机械定义统一的状态与模式描述从而提升设备间互操作性。完整内容共 8 章涵盖执行摘要与背景、关键术语定义、自动运行状态模型、维护/手动/用户三种辅助模式、模式管理器以及与 PackML v2.2 的版本对比和参考文献配合状态转换矩阵与注释可直接用于规划设备状态机、设计 HMI 界面和统一报警逻辑。编制工作由 Bosch Rexroth、BR、Rockwell、Siemens 等厂商代表共同完成权威性较强。包体为单个 PDF共 702KB阅读轻量、便于查找。目前已有 1164 人浏览学习在包装自动化标准资料中持续被检索。研读该标准有助于让包装线不同厂商设备遵循同一套状态语言也为后续 PackML 落地应用打下基础。1. PackML v3.0 标准文件到底是什么一套包装设备的通用对话协议做产线标准化改造时最头疼的不是单台设备的工艺而是同一套包装线上不同厂家设备的程序语言完全不通有的用中间继电器拼状态有的用自定义整数编码有的干脆靠离散的点位让 MES 猜当前在干什么。PackML v3.0 标准文件解决的就是这件事——它把包装设备的运行状态、工作模式、标签命名和对外接口统一成一套公开模型让 PLC、HMI、MES 之间用同一套词汇描述设备。它不是一份可以直接烧录的工程而是定义状态机、模式切换、PackTag 标签体系和数据采集接口的规范。做包装、灌装、贴标、码垛这类单机和整线集成的工程师只要你想减少对接成本、统一 OEE 口径就值得把这份标准读透并落成自己的 PLC 框架。2. 拆解 PackML v3.0 核心模型状态、模式与标签命名规则2.1 状态机的十七个状态哪些必须实现哪些可以简化PackML v3.0 沿用了 ISA-88 工艺设备状态模型的核心概念把一台包装设备在生命周期里的运行状态收敛成十七个状态。很多人第一次打开标准文件会被这张状态机图吓到觉得要全部实现才能叫 PackML。实际上日常产线真正频繁跳动的状态不会超过八个Idle、Starting、Execute、Held、Suspended、Stopped、Aborted、Clearing。其余像 Completing、Resetting、Unsuspending 都是过渡态用来保证状态迁移过程可观测、可做条件判断。我一般会先在需求清单里划出必选状态和可选状态。单体灌装机Execute 与 Idle 是主状态Suspended 在整线联动没有需求时可以不做但 Aborted 和 Stopped 不能省因为安全回路和故障处理永远需要兜底。过渡态建议全部保留哪怕只是原样透传因为后续接 OPC UA 和 MES 时完整的状态迁移事件比只看最终状态的跳变要值钱得多。核心状态典型含义常见触发命令标准里是否必须Idle等待启动无安全风险Start是Starting启动中等待条件满足由 Start 进入过渡态建议保留Execute正常运行/生产Complete 完成是Held异常保持等待人工干预Hold建议保留Suspended受控暂停料流中断Suspend按产线联动需求Stopped停止完成可复位Stop是Aborted故障中止需清除故障触发是真正从标准文件里拿到的不是这张表本身而是状态迁移边界的定义哪些迁移合法、哪些迁移非法。比如 Aborted 状态不能直接进 Execute必须先 Clearing再 Resetting 到 Idle。很多自研状态机跳过了这条链路直接让故障复位按钮把设备带回自动运行这在单机演示时很顺在整线联动时就是隐患。2.2 模式Mode与状态State的关系切换逻辑先于状态逻辑模式在 PackML 里是一组命令的集合常见的有自动、手动、维护、清洗。状态描述设备当前在哪模式描述设备被允许执行哪组命令。两者最核心的约束是模式切换只能在 Idle 或 Stopped 等安全状态进行Execute 运行中切模式属于非法操作。这个约束在标准文件里写得很清楚但落地时经常被忽略。很多 PLC 程序里模式切换只是一个 MOVE 指令把模式号写进寄存器根本不检查当前状态。结果就是操作员在自动运行中误触模式旋钮设备动作逻辑混乱甚至和 HMI 上的使能条件打架。我习惯在 PLC 侧对每个模式请求做前置条件校验。常见做法是在模式切换逻辑前加一个锁存条件// 模式切换脉冲触发 bModeChgAllowed : (usiCurrentState S_IDLE) OR (usiCurrentState S_STOPPED); IF bModeChgReq AND bModeChgAllowed THEN usiActiveMode : usiReqMode; // 只有安全状态才允许更新 bModeChgReq : FALSE; END_IF;这里的usiCurrentState必须来自状态机内部维护的当前状态变量不能从外部输入直接读取usiReqMode是 HMI 或旋钮写入的目标模式号。参数上建议把状态枚举定义成全局常量比如S_IDLE : 1这样模式切换和状态机 CASE 语句用的是同一套编码不会出现一个工程里两种状态码的混乱。模式的另一个作用是决定 HMI 上哪些按钮可见、哪些命令可下发。手动模式下Start 命令应当被禁用否则操作员在手动动作还没结束时点了启动设备在不明状态下开始运行这是典型的翻车现场。2.3 PackTag 命名体系从设备级到产线级可互操作的关键PackML v3.0 的标签体系通常被称作 PackTag它把对外数据接口分成命令、状态、管理信息三类。标准文件给的是命名规则和分组建议不是固定标签表这一点很多人理解反了以为套用标准就等于有了一份现成的点位表。实际上你要做的是按它的结构去组织自己的变量。我通常把 PackTag 分成三个命名空间Command 类用Ctrl.*表示输出命令State 类用Sts.*表示状态反馈Administrative 类用Adm.*表示批次、模式、故障信息。配合设备标识形成完整路径比如灌装机的运行命令是Filler.Ctrl.ExecuteCmd状态反馈是Filler.Sts.CurrentState故障信息是Filler.Adm.FaultCode。分类命名前缀典型字段对接用途CommandCtrlExecuteCmd, StartCmd, StopCmd, ResetCmdHMI 按钮、MES 指令下发StateStsCurrentState, PreviousState, StateStartTimeHMI 状态文本、OPC UA 状态节点AdministrativeAdmActiveMode, FaultCode, ProductId批次管理、OEE 统计标签命名一旦定下来SCADA 和 MES 侧的点位映射就是机械劳动。最怕的是设备厂商自己另起一套缩写状态用RunSts模式用MODE_INT命令用M100这种标签对上位机工程师来说是灾难三年后换人维护更是灾难。PackML 解决这类互操作问题的思路是先定命名规则再定类型和编码最后才实现 PLC 内部逻辑。3. 在 PLC 里落地 PackML v3.0 状态机数据块、函数块与最小可跑代码3.1 先定数据结构再写逻辑状态上下文是最重要的一个 UDT我落地 PackML 的第一步不是写状态迁移逻辑而是先定义一个状态上下文结构体。这个结构体会贯穿状态机、HMI、OPC UA 三个层面避免全局变量满天飞。常见做法是建立一个用户自定义类型命名为PACKML_CONTEXT然后在每个设备 FB 里实例化一份。TYPE PACKML_CONTEXT : STRUCT CurrentState : USINT; // 当前 PackML 状态编码参照状态枚举 PreviousState : USINT; // 上一个状态用于恢复与诊断 CommandRequest : WORD; // 外部命令位故障复位、停止、启动 ActiveMode : USINT; // 当前模式自动/手动/维护/清洗 RequiredMode : USINT; // 请求切换的目标模式 FaultCode : WORD; // 进入 Aborted 时锁存的故障码 StateTimestamp : LWORD; // 状态变化时刻单位 ms bStateChanged : BOOL; // 状态变化脉冲给 HMI 和 OPC UA 用 END_STRUCT END_TYPE这个结构体里最关键的两个字段是CommandRequest和CurrentState。命令字用位是常见做法Bit0 是复位、Bit1 是启动、Bit2 是停止这样一条 INT 型变量就能承载多条命令MES 侧写数据也简单。StateTimestamp看起来是附加项但对 OEE 统计和状态轨迹追溯非常有用没有时间戳的状态变化只能算黑匣子。执行顺序上我坚持先更新状态机再更新 PackTag最后刷新输出和报警。顺序错乱会导致同一扫描周期内 HMI 读到旧状态而 PLC 已经进入新状态画面和实际动作不一致。这个顺序写在程序注释里作为框架约定后来接手的人也不会改错。3.2 用 CASE 语句搭状态机主框架四个分支覆盖百分之九十的流程PackML 状态机用结构化文本实现最直观的就是 CASE 语句。我一般把状态机函数块拆成三层输入命令解析层、状态迁移层、输出反馈层。状态迁移层只干一件事就是根据当前状态和命令决定下一次扫描进哪个状态。CASE ctx.CurrentState OF S_IDLE: // 启动命令到来先进入 Starting 过渡态 IF (ctx.CommandRequest AND CMD_START) 0 THEN ctx.CommandRequest : ctx.CommandRequest AND NOT CMD_START; // 清命令 ctx.CurrentState : S_STARTING; END_IF; S_STARTING: // 启动条件满足后进入 Execute否则停在 Starting 并超时报警 IF bStartConditionsMet THEN ctx.CurrentState : S_EXECUTE; END_IF; S_EXECUTE: // 正常生产状态响应完成、停止、保持三类命令 IF (ctx.CommandRequest AND CMD_COMPLETE) 0 THEN ctx.CurrentState : S_COMPLETING; ELSIF (ctx.CommandRequest AND CMD_STOP) 0 THEN ctx.CurrentState : S_STOPPING; ELSIF bHoldRequest THEN ctx.CurrentState : S_HOLDING; END_IF; S_ABORTED: // 故障状态只响应复位命令且必须经过 Clearing IF (ctx.CommandRequest AND CMD_RESET) 0 THEN ctx.CurrentState : S_CLEARING; END_IF; END_CASE;逻辑说明启动命令经过Starting这个过渡态是为了给启动条件判断留出空间比如气压建立、门闭锁确认、物料到位。Execute里命令判断用 ELSIF 而不是 IF 堆叠保证单次扫描只触发一个迁移避免设备同时响应停止和完成两个命令造成状态错乱。Aborted分支里只允许复位命令这是安全观念上的底线。参数上需要注意命令位写完后立即清除的习惯。我在每个消费命令的分支里先AND NOT清掉命令位防止同一命令重复触发两次迁移。状态枚举建议用全局常量表数值从 1 开始排避免用 0 作为有效状态这样结构体初始化为 0 时就是一个明确的非法状态能被诊断逻辑抓住。3.3 命令与动作的边界状态机只管跳转设备动作由状态驱动状态机最常见的设计错误是什么都想管既要管状态跳转又要管电机启停还要管报警文本。PackML 的职责边界很清晰——状态机只决定设备处于什么状态设备动作由各个状态的处理逻辑驱动。也就是说Execute状态只是告诉变频器启停逻辑“现在已经允许运行了”真正的启动指令应该由独立的设备控制逻辑去执行。我一般把动作逻辑写成状态驱动模式// 设备动作输出只有 Execute 状态才允许主轴运行 bMainDriveEnable : (ctx.CurrentState S_EXECUTE) OR (ctx.CurrentState S_STARTING); // 报警复位输出Clearing 状态下才允许清除故障 bFaultReset : (ctx.CurrentState S_CLEARING);这样做的核心收益是命令的唯一来源被收口。HMI 上的启动按钮只写CommandRequest的启动位不再直接控制输出MES 下发停止命令同样只写命令字。所有动作输出都是从状态推导出来的而不是从命令直接推导的。命令是瞬时的状态是持续的用持续状态去驱动设备动作天然避免了“按钮弹起设备就停”的抖动问题。在过渡状态里超时保护是必需品。Starting、Stopping、Clearing 这类状态不能无限停留否则设备卡在中间谁也看不出来。我通常给每个过渡状态配一个时间寄存器超时后强制进 Aborted 并写入故障码。这个设计在后端 OEE 统计时特别重要否则一次卡死就会污染一整天的可用时间数据。4. 把 PackML v3.0 数据接出去HMI、OPC UA 与 OEE 统计4.1 HMI 侧的状态显示与按钮使能让操作员只看状态不看程序PackML 落地的价值一半体现在 HMI 上。操作员不关心你用了哪套标准他只关心画面上的状态能不能看懂、按钮什么时候能点。常见做法是 HMI 侧做一张状态映射表把状态码映射成固定文本状态文本来自Sts.CurrentState而不是从一堆中间变量里现算。按钮使能逻辑也应该跟着状态走。启动按钮只在Idle和Stopped时可点复位按钮只在Aborted时可点停止按钮在Execute、Starting、Held时可点。把这些使能条件直接写进 HMI 按钮的属性里比在 PLC 里做二次判断更直观但前提是 HMI 读取的状态变量必须和 PLC 状态机同源。HMI 按钮允许点击的状态写入的命令位启动Idle, StoppedCMD_START停止Execute, Starting, Held, SuspendedCMD_STOP复位AbortedCMD_RESET保持Execute, Suspended状态相关 HoldCmd按钮命令下发后HMI 应立即给操作员反馈“命令已收到”而不是等设备进入目标状态才显示提示。PackML 的过渡态正好承担这个角色点击停止后画面显示“停止中”设备进入 Stopped 后画面变成“已停止”操作员就知道命令执行到哪一步了。这种体验是自研状态机不容易做到的。4.2 OPC UA 地址空间与 PackTag 的对应节点设计决定上位机工作量PLC 侧装好 OPC UA 服务器后上位机看到的地址空间通常是一片变量路径。PackTag 的命名体系在 OPC UA 场景下有个实际好处节点名本身就有意义MES 工程师不用查表就能猜出Filler.Sts.CurrentState是什么意思。我一般会额外做一层地址映射结构把 PackML 状态量单独归组形成模拟对象式的节点树。不要把所有状态量直接裸露在Objects层面那样每个变量都是平铺的和裸 PLC 变量没区别。常见做法是按设备分组再按 Command、State、Admin 子节点分层。OPC UA 节点路径对应的 PackTag数据类型PackML/Filler/State/CurrentFiller.Sts.CurrentStateUSINTPackML/Filler/State/PrevFiller.Sts.PreviousStateUSINTPackML/Filler/Command/ExecuteFiller.Ctrl.ExecuteCmdBoolPackML/Filler/Admin/ModeFiller.Adm.ActiveModeUSINT节点路径不要做成中文工业软件对中文路径的支持参差不齐一旦部署到国外设备或者旧版上位机中文节点会变成乱码。统一用英文小写加斜杠的结构后期做报表、做数据分析工具都省事。4.3 OEE 数据从哪来把状态映射成计时类别OEE 统计最怕的是时间口径不一致。有的设备用运行继电器计时有的用产量反推有的干脆估一个。PackML 给了一个相对干净的口径用状态迁移事件累计时间。把每个状态计入 OEE 的类别里比如 Execute 是运行时间Held 是计划外停机Idle 是空闲待料Stopped 是等待操作员。我做一个统一的计时逻辑块每秒根据当前状态累加对应类别的时长// 每秒定时器触发 IF bOneSecondPulse THEN CASE ctx.CurrentState OF S_EXECUTE: fRunTime : fRunTime 1.0; S_HELD: fDownTime : fDownTime 1.0; S_IDLE: fIdleTime : fIdleTime 1.0; S_STOPPED: fStoppedTime : fStoppedTime 1.0; END_CASE; END_IF;这里的累计值建议放在断电保持区或上传到 MES否则一次断电就会丢掉几个小时的产量统计。另一个容易踩的坑是系统启动初期和末期的时间不要计入有效时间需要在统计块里加一个运行许可位只有设备进入自动模式并完成初始化后才开始计时。OEE 统计的结果如果只给管理者看状态机只要迁就成小时的量但如果要给排产系统用就要把每次状态变化的起止时间戳也记录成事件表。PackML 的StateTimestamp字段在这里派上用场每次状态变化生成一条记录包含进入状态、离开状态、时长三列这是最细粒度的设备日志。5. PackML v3.0 落地避坑五个高频故障与排查思路5.1 复位后直接进 Running而不是回到 Stopped状态机跳状态现象操作员在 Aborted 状态按下复位按钮设备没有经过 Clearing 和 Resetting直接进入 Execute设备开始自动运行。这是最危险的一类问题。原因状态机里的复位命令处理分支被写成了“复位完成即启动”也就是复位逻辑和启动逻辑共用了一个判断条件或者 Clearing 状态完成后直接跳到了 Starting跳过了 Stopped 和 Idle。解决严格遵循 PackML 迁移链Aborted 只能进 ClearingClearing 完成后进 Stopped随后由操作员单独发出启动命令才能进 Starting。我在代码里故意在 Resetting 完成后把状态压到 Idle并清零启动命令位确保不可能在复位的同时启动。5.2 Holding 和 Suspended 混用整线联动时连锁失灵现象产线上游设备报故障中游设备没有进入暂停状态而是进入了保持状态结果上游清理完故障后中游还在等待人工确认整线堵料。原因Hold 和 Suspend 在中文语境里都翻译成“暂停”逻辑上却完全不同。Hold 是异常保持需要人工干预Suspend 是受控暂停由联锁信号触发可以自动恢复。解决在定义状态迁移命令时明确来源。联锁信号和上游设备故障只允许触发 Suspend不允许触发 Hold操作员面板上的保持按钮才触发 Hold。我在联锁输入侧加了一个命令映射块把外部信号统一映射到 Suspend 命令位Hold 命令位只接受 HMI 来源。5.3 标签命名不一致SCADA 点位映射要改三年现象设备对接 MES 时点位表里同一个状态有RunSts、Running、State_Act三种写法大小写混用下划线和驼峰混用。MES 工程师每到一个项目就要猜一次语义。原因PLC 程序里变量名没有统一架构PackTag 规范只停留在纸面上HMI 工程师和 PLC 工程师各自起名。解决把 PackTag 命名做成工程模板变量前缀、状态枚举、命令位全部用符号表统一管理。程序编译时直接用符号名发布上位机导入符号表而不是手工敲变量地址。项目验收时加一条检查项所有对外标签必须通过模板生成不允许手写任何设备侧通讯变量。5.4 过渡状态没有超时保护设备卡在 Starting 无人知晓现象设备偶尔启动到一半卡住HMI 画面一直显示“启动中”产量统计为零操作员只能断电重启。原因Starting 和 Stopping 这类过渡态没有超时判断启动条件某个传感器坏了一直没满足状态机就在那里等一辈子。解决给每个过渡态配一个定时器启动时清零进入状态后开始计时超过设定时长仍然在同一个状态就自动进 Aborted 并报“状态超时”故障。超时时间一般取该动作正常持续时间的 3 到 5 倍比如吹瓶吹气建立需要 2 秒超时给 10 秒既要避免正常操作被误判也要避免故障被掩盖。5.5 OPC UA 刷新周期与 PLC 扫描周期错配采集到假状态现象上位机报表里看到的状态和现场画面不一致比如设备已经停了报表还记录着运行状态甚至状态序列有时间上的倒挂。原因OPC UA 采样周期是 200msPLC 扫描周期是 10ms状态在两次采样之间变化了两次上位机只采到了第一次变化后的状态时间戳却是 PLC 侧的状态变化时间和上位机采集时间对不上。解决在 PLC 侧对每个状态量的变化打上时间戳OPC UA 侧把时间戳一并读走上位机以 PLC 的时间戳为准进行事件排序。采样周期改成 50ms 以内至少要和状态机最小驻留时间匹配。如果状态机有特别快的过渡态比如一个扫描周期就完成的迁移就不要把这些过渡态发布成 HMI 可见事件只发布最终稳定状态。6. 用状态轨迹验证 PackML 实现一个离线检查工具状态机写完之后最怕的问题不是逻辑错而是你不知道它错在哪里。我建议每完成一套 PackML 落地先跑一遍状态轨迹记录再结合日志工具做离线检查。具体做法是在程序里加一个环形缓冲区记录每次状态变化的时间、前状态、新状态、触发命令、模式号存成 CSV 格式文件再用常规数据分析工具画状态迁移图。时间戳前一状态新状态命令模式09:15:01.220IdleStartingCMD_STARTAUTO09:15:02.480StartingExecute自动完成AUTO09:15:37.910ExecuteStoppingCMD_STOPAUTO09:15:38.260StoppingStopped自动完成AUTO检查时重点关注三类非法迁移Aborted 直接跳 Execute、Execute 直接跳 Idle、Suspended 直接跳 Starting。这三类一旦出现一定是状态机条件写宽了不要试图用上位机去掩盖。另一个习惯是把状态轨迹和报警记录合并查看设备故障发生在哪个状态、触发的是哪条迁移一眼就能定位。我自己的教训是之前做一套贴标机单机测试全部通过整线联调时却在产品切换时出现状态抖动查了两天才发现是模式切换代码在 Execute 状态被误触发。从那以后模式切换的条件校验和状态轨迹记录就成了我每套 PackML 项目的标配不再省略。这套做法也建议你直接用起来哪怕你拿到的 PackML v3.0 标准文件只当作参考资料状态轨迹验证的思路也完全能迁移到你现有的设备逻辑上。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑