ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于PACKML与西门子CPG的包装机械状态机编程框架解析

基于PACKML与西门子CPG的包装机械状态机编程框架解析 包装机械的控制程序十个项目里至少有八个最后都会变得很难维护逻辑散落在不同程序段里每个电机的启动条件、每个气缸的到位信号、每台设备的故障复位都各写一套。一旦设备要联机人机界面状态、上层 MES 状态和 PLC 内部状态经常对不上。这种局面不是单个程序员的水平问题而是程序结构本身缺少一个行业通用的状态语义。PACKML 就是为解决这个语义问题而出现的而西门子 CPG 则可以看作是在 TIA Portal 环境里落地 PACKML 的一套编程框架。这篇内容会从 PACKML 的用途讲起再落到西门子 CPG 框架的组织方式给出状态机核心代码、Host 联动、批次计数、HMI 映射、模拟验证和排错路径。适合三类人看正在做包装线电气设计的工程师、想把单机程序做成可复用标准库的自动化团队、以及刚接触西门子 PLC 编程并想在项目里引入状态机思想的学习者。1. 先理清 PACKML 到底解决包装机程序的什么问题1.1 没有标准状态时包装机程序会遇到的典型现象先看一个很常见的现场一位工程师打开别人写过的包装机程序试图找到“按下启动按钮后到底发生了什么”。结果启动按钮背后可能直接置位了电机接触器可能还带了一长串“如果……并且……那么……”的启动条件。启动条件不满足时程序没有明确提示现场只能靠万用表逐个信号排查。类似的问题还有操作按钮含义不统一。有的设备“启动”是一键复位后自动运行有的是先手动复位再单独启动。故障复位流程混乱。按下复位键可能同时清报警、移动气缸、禁止安全门打开逻辑之间没有顺序。HMI 页面和 PLC 逻辑脱节。PLC 内部状态与画面显示的文字完全依赖工程师手工维护漏改一个地址就显示错。整线联机困难。每台单机都有一套自己的“准备好”“运行中”信号上位机必须针对不同设备写不同地址表。这些问题本质上是缺少统一的状态模型。程序里所有的“状态”都散落在中间变量和标志位里没有人能说清楚当前设备处于哪个阶段。1.2 PACKML 提供的标准状态语义PACKML 的全称是 Packaging Machine Language最早来源于 ISA-TR88 技术报告以及 OMACOrganization for Machine Automation and Control发布的 PackML Implementation Guide。它定义一个包装自动化设备应该有哪些状态、模式、命令和标签为设备控制、HMI 显示和上层信息系统提供一个统一语义。PACKML 不是一套具体硬件也不是西门子专属。它是一套状态机约定。一套比较常用的 PACKML 核心状态包括 Idle、Starting、Execute、Holding、Held、Unholding、Stopping、Stopped、Aborting、Aborted、Clearing、Cleared、Resetting 等。这些状态围绕一个明确闭环运行Idle 表示设备复位完成允许被启动。Starting 表示已接收启动命令正在建立运行条件。Execute 表示设备正在正常执行生产动作。运行中收到停机命令后进入 Stopping直到设备真正停下来进入 Stopped。Stopped 状态通过 Reset 命令回到 Idle。发生严重故障时进入 Aborting进入 Aborted 后需要 Clear再经过 Cleared 和 Resetting 回到 Idle。这套语义给程序带来的最大价值是设备在任何时刻都能被明确归类到某个状态HMI 可以基于状态表显示上层单元可以基于状态表联动调试人员可以基于状态表定位问题。1.3 CPG 是框架不是新的控制原理西门子 CPG 编程框架在技术社区里经常和 PACKML 一起出现。可以把它理解为在 TIA Portal 环境中把 PACKML 的状态机、命令、模式、批次计数和 HMI 标签组织成一份可复用的工程框架或模板库。CPG 不改变 PACKML 的控制逻辑也不替代设备和工艺逻辑。它解决的是“怎么在西门子 PLC 里统一组织这些状态机和变量”的问题。使用 CPG 后程序里不再是一堆零散的 M 点或 DB 点而是每个设备单元都有一套相同的结构比如维度手工各写各的程序使用 PACKML / CPG 框架状态名称每个项目一套定义统一状态语义复位流程分散在按钮逻辑里标准 Reset、Clear 流程HMI 对接大量地址手工映射按状态寄存器统一读取整线联机额外开发通信点表上层按 Unit 读取状态新项目复用从旧程序复制再删除从标准库中派生实例学习成本初期低后期高初期略高后期稳定这里要说明一点不同项目里拿到的 CPG 库可能来自不同渠道有的由设备厂商维护有的由自动化集成商开发有的基于西门子官方库二次定制。具体到某一家公司的库它的块名、DB 编号、功能码可能不一样。下面示例统一采用“用于说明思路”的方式实际项目落地时建议以自己拿到的库文件和版本说明为准。2. 认识 CPG 在西门子 TIA Portal 里的定位与结构2.1 一个 Unit 的组成在 PACKML 中一台包装机、一个工作站甚至一整条包装线都可以看作机器层级中的一个 Unit。Unit 是一个具备独立状态机的设备单元有自己的命令、状态、模式和批次数据。在 CPG 框架中Unit 通常对应到程序里的一个 FB 实例加上一个存放运行时数据的 DB。Unit 内部包含状态寄存器。保存当前 PACKML 状态。模式寄存器。保存当前操作模式例如自动、手动、维护。命令寄存器或命令输入点。接收来自 HMI、MES 或上级 Unit 的 Start、Stop、Hold、Reset、Abort、Clear 等指令。就绪条件。表示机械、电气、安全条件是否允许当前状态转换。反馈信号。表示设备实际是否已经运行、是否已经停止。批次相关数据。例如合格品计数、废品计数、批次号、事件记录。一个典型的数据流是操作员在 HMI 上按 Start。命令写入 Unit 的命令接口。状态机接收命令判断当前状态是否允许 Start。满足条件后进入 Starting。设备驱动层响应指令机械开始动作。运行反馈到位后状态机进入 Execute。状态寄存器通过 HMI 接口显示“运行中”。2.2 状态机、命令和模式的关系三个概念容易混淆状态表示设备当前实际情况例如正在运行还是正在停机。命令表示外部对设备提出的请求例如“请启动”“请停机”。模式表示允许执行哪些命令。例如手动模式下自动启动命令无效维护模式下安全门允许打开调试模式下允许单步动作。PACKML 的模式层也很重要。通常一台包装机会有自动模式、手动模式、维护模式、清洗模式等。模式切换必须在安全状态下进行不能在 Execute 运行过程中直接切模式或者切换后要立即停机。在具体程序里命令不应被直接接到状态转换条件上。命令更合理的写法是模式检查。当前模式是否允许该命令。状态检查。当前状态是否允许该命令。边沿检查。命令是否为一次有效的脉冲。执行状态转换。CPG 框架的价值就在于把这一套先后关系预先定义好避免每个人在项目里重新设计一遍。2.3 CPG 库的数据流和调用关系在一个使用 CPG 的西门子项目中常见调用关系是OB1 或循环中断程序里调用设备状态机 FB。状态机 FB 使用 UDT 类型的 InOut 参数访问 Unit 数据块。设备驱动 FB 根据状态机输出的命令去控制电机、气缸、变频器或伺服。设备驱动 FB 把实际反馈写回 Unit 数据。HMI 直接读取 Unit 数据块中的状态、模式、计数和报警。上层父 Unit 读取子 Unit 的状态并向下分发命令。这种分层的好处是状态机不直接关心某个电机由哪个 QB 控制设备驱动也不负责定义整机状态。两边通过 Unit 数据块接口对接可以把控制逻辑和机械工艺解耦。3. 搭建运行环境版本、库和项目骨架3.1 软件和硬件要求学习环境和生产环境的要求不一样。先看一张环境对照表项目学习环境生产环境编程软件TIA Portal V16 及以上具体以库要求为准与工厂维护团队一致避免乱升级目标 PLCS7-1200 或 S7-1500也可以使用 S7-PLCSIM常见为 S7-1500 系列CPG 库示例库或自己写的状态机库受版本管理的正式库HMI博途 WinCC 仿真Comfort Panel / Unified Comfort Panel通信测试OPC UA 模拟客户端、Modbus 仿真与 MES、变频器、机器人实机联调重点确认三点CPG 库文件版本是否与 TIA Portal 版本匹配。目标 CPU 固件版本是否在库的支持范围内。项目中是否同时使用了其他标准库比如驱动库防止地址和命名冲突。如果原始材料没有给出明确版本落地前要先确认依赖版本。不要直接把 V15 的项目库拖进 V18 里使用容易因为编译规则变化导致接口不兼容。3.2 获取 CPG 包和建立初始项目获取 CPG 库通常有几种渠道公司内部已有标准库由电气负责人统一发布。自动化集成商提供的项目框架。西门子技术社区或行业解决方案案例中的公开框架。项目合作伙伴提供的专用库。无论从哪个渠道获取都要保留一份库说明和版本号。库版本应记录在项目版本台账里否则几个月后程序出现问题连当前跑的是哪个版本都查不到。在当前 TIA Portal 中建立初始项目的常规步骤新建项目指定项目名称和保存路径。添加设备选择 CPU 型号和固件版本。在“全局库”区域打开 CPG 库。将库中的 UDT、FB、FC 复制到项目“程序块”下。建立全局 DB按 Unit 创建数据块实例。在 OB1 中调用状态机 FB并传入对应 DB。配置 HMI 变量表把状态寄存器映射到画面。启动首个程序前先编译项目确认没有缺少库块、接口不匹配或版本冲突。编译报错优先处理不要带着黄感叹号继续开发。3.3 需要预先规划的数据结构在实际项目中Unit 数据块通常不会只有一个状态变量因为还要包含命令、模式、就绪条件和计数。下面用 SCL 写一个简化的 UDT用来说明 CPG 里一个 Unit 通常要管理哪些数据。TYPE UDT_PackMLUnit VERSION : 1.0 STRUCT State : INT; // 当前状态编号 Mode : INT; // 当前模式1自动 2手动 3维护 ModeReq : INT; // 请求模式 CmdStart : BOOL; // 启动命令 CmdStop : BOOL; // 停止命令 CmdHold : BOOL; // 保持命令 CmdReset : BOOL; // 复位命令 CmdAbort : BOOL; // 急停/中止命令 CmdClear : BOOL; // 清除故障命令 Ready : BOOL; // 允许启动条件 RunFeedback : BOOL; // 设备实际运行反馈 StopFeedback : BOOL; // 设备实际停止反馈 Fault : BOOL; // 故障标志 CountGood : UDINT; // 合格品计数 CountBad : UDINT; // 废品计数 BatchID : DINT; // 批次号 END_STRUCT END_TYPE这个结构只是为了展示层次不是某一款 CPG 库的官方定义。真实 CPG 库中的 UDT 通常更长还会包含报警句柄、模式切换状态、命令确认状态、事件缓冲等。但核心思路一致通过一个结构体把一个 Unit 的输入、输出、状态和数据集中管理。这样设计以后HMI、上层 Unit 和调试者都只需要面对同一个 DB 结构。后续程序扩展时增加一个 Unit 就是增加一个 DB 实例并复制一个 FB 调用而不是重新定义一套变量。4. 用 SCL 实现一个可运行的 PACKML 状态机核心4.1 状态编号常量在实际项目中状态编号需要在项目范围内统一。例如可以把 PACKML 状态定义成一组常量避免在代码里直接写魔法数字。CONSTANT cIdle : 0; cStarting : 1; cExecute : 2; cHolding : 3; cHeld : 4; cUnholding : 5; cStopping : 6; cStopped : 7; cAborting : 8; cAborted : 9; cClearing : 10; cCleared : 11; cResetting : 12; END_CONSTANT这个列表不是 PACKML 全量状态只是用来说明状态机写法。完整状态表还要看项目采用的规范版本有些项目会加入 Complete、Completing、Suspending、Suspended 等状态用于处理批次结束和暂停场景。4.2 状态机处理逻辑下面用 SCL 写一个最简单的 PACKML 状态机核心。它接收 Unit 数据处理 Start、Stop、Hold、Reset、Abort、Clear 命令并且保证命令只在特定状态下有效。FUNCTION_BLOCK FB_PackMLUnit VAR_IN_OUT ioUnit : UDT_PackMLUnit; END_VAR VAR rTrigStart : R_TRIG; rTrigStop : R_TRIG; rTrigHold : R_TRIG; rTrigReset : R_TRIG; rTrigAbort : R_TRIG; rTrigClear : R_TRIG; END_VAR先处理命令边沿。使用 R_TRIG 可以保证电平信号只在上升沿触发一次。rTrigStart(CLK : ioUnit.CmdStart); rTrigStop(CLK : ioUnit.CmdStop); rTrigHold(CLK : ioUnit.CmdHold); rTrigReset(CLK : ioUnit.CmdReset); rTrigAbort(CLK : ioUnit.CmdAbort); rTrigClear(CLK : ioUnit.CmdClear);再写状态转换逻辑。状态机中每个状态只处理允许进入的下一状态。CASE ioUnit.State OF cIdle: // 空闲状态允许启动 IF rTrigStart.Q THEN ioUnit.State : cStarting; ioUnit.CmdStart : FALSE; END_IF; // 发生故障则进入中止流程 IF ioUnit.Fault THEN ioUnit.State : cAborting; ioUnit.CmdAbort : FALSE; END_IF; cStarting: // 启动过程中等待运行条件建立 IF ioUnit.Ready AND ioUnit.RunFeedback THEN ioUnit.State : cExecute; ELSIF ioUnit.Fault OR rTrigAbort.Q THEN ioUnit.State : cAborting; END_IF; cExecute: // 正常运行 IF rTrigHold.Q THEN ioUnit.State : cHolding; ioUnit.CmdHold : FALSE; ELSIF rTrigStop.Q THEN ioUnit.State : cStopping; ioUnit.CmdStop : FALSE; ELSIF ioUnit.Fault THEN ioUnit.State : cAborting; END_IF; cHolding: // 这里模拟保持动作完成实际项目要等待设备真正停住 ioUnit.State : cHeld; cHeld: // 保持状态下可以继续停止也可以解除保持 IF rTrigStop.Q THEN ioUnit.State : cStopping; ioUnit.CmdStop : FALSE; ELSIF NOT ioUnit.CmdHold THEN ioUnit.State : cUnholding; END_IF; cUnholding: // 解除保持完成后回到 Execute IF ioUnit.Ready THEN ioUnit.State : cExecute; END_IF; cStopping: // 等待停止反馈 IF ioUnit.StopFeedback THEN ioUnit.State : cStopped; ELSIF ioUnit.Fault THEN ioUnit.State : cAborting; END_IF; cStopped: // 停止后允许复位 IF rTrigReset.Q THEN ioUnit.State : cResetting; ioUnit.CmdReset : FALSE; END_IF; cAborting: // 中止过程进入中止完成状态 ioUnit.State : cAborted; cAborted: // 清除故障后才能进入 Clearing IF rTrigClear.Q THEN ioUnit.State : cClearing; ioUnit.CmdClear : FALSE; END_IF; cClearing: // 清除动作完成后进入 Cleared ioUnit.State : cCleared; cCleared: // 清除完成后复位到 Idle IF rTrigReset.Q THEN ioUnit.State : cResetting; ioUnit.CmdReset : FALSE; END_IF; cResetting: // 复位动作完成回到 Idle ioUnit.State : cIdle; ELSE // 未定义状态强制回到 Idle避免卡死在未知编号 ioUnit.State : cIdle; END_CASE;这段代码有三个关键点命令处理完成后立即把命令位清掉。这样即使 HMI 按钮一直按住也只会触发一次。状态转换都有明确前提条件。例如 Starting 不能直接跳 Execute必须等 Ready 和 RunFeedback 都到位。故障路径统一走 Aborting。不要在每个状态里写一堆杂乱的自复位逻辑。4.3 在 OB1 中调用状态机调用方式如下FB_PackMLUnit_Instance(ioUnit : Unit1);然后把 Unit1 的状态值传给 HMI 区Hmi_UnitState : Unit1.State;推荐把 HMI 变量集中放在一个独立的 HMI 接口 DB 里不要直接让触摸屏画面读取几十个设备 DB 里的散点。这样换触摸屏工程或接上位机时只需要改一组接口变量。4.4 为什么命令不能做成普通电平信号这是新手最容易踩的坑。如果把 Start 直接接到电机启动继电器上那么只要 Start 为 TRUE设备就会一直要求启动。但状态机场景下命令通常是一次性请求不是持续条件。假设设备从 Execute 回到 Idle如果 Start 仍然为 TRUE设备就会立刻再次启动。正确的做法是使用边沿触发或者在状态机内部处理完命令后清除命令。上面的示例中同时做了两件事外部使用 R_TRIG 检测上升沿内部处理结束后把命令位复位。这样命令既不会被重复触发也不会因为状态机回到 Idle 而自动再启动。5. 多工位与批次从单机状态机到整线协同5.1 上级 Unit 和下级 Unit 怎么联动单机状态机跑通以后下一个问题是如何把多台设备组成一条线。典型包装线结构是开箱机、填充机、封箱机、贴标机等设备组成一条联动线。在 PACKML 框架中每条线可以看作一个父 Unit各单机是子 Unit。父 Unit 并不直接控制电机和气缸它只做状态汇总和命令分发。父子 Unit 联动的基本逻辑父 Unit 收到 HMI 的 Start 命令。父 Unit 先检查所有子 Unit 的模式和状态。满足联机启动条件后父 Unit 向子 Unit 发布 Start 命令。子 Unit 收到 Start 后各自执行启动流程。所有子 Unit 都进入 Execute 后父 Unit 才进入 Execute。任一子 Unit 报故障父 Unit 根据策略进入 Stopping 或 Aborting。这套逻辑可以对应到 CPG 中的“父状态机”和“子状态机”两级结构。现场调试时最怕的是父子同时独立置位命令造成命令冲突。推荐父 Unit 只下发一次命令之后通过子 Unit 状态变化判断是否成功。5.2 命令分发与启动顺序不是所有设备都适合同时启动。比如填充机必须等待输送带运行反馈后再启动封箱机必须等待填充机进入 Execute 后再启动。这时需要在父 Unit 中按顺序分发命令。设备启动顺序示例顺序设备启动条件启动反馈1输送带变频器 Ready运行反馈2填充机输送带运行反馈填充主轴运行反馈3封箱机填充机运行反馈气缸到位、输送带运行反馈4贴标机封箱机运行反馈贴标头运行反馈在父 Unit 中不能把 Start 命令一次性广播给所有子 Unit而是要等一个子 Unit 进入 Execute 后再发下一个。这个过程本身也可以用一个小型状态机管理例如父 Unit 的状态不只是 Execute还包含“启动等待中”。5.3 批次计数与生产数据批次数据在 PACKML 中通常独立管理。状态机不负责数数但状态机要提供“当前处于 Execute”这个窗口批次计数模块才有资格累加数量。一个安全做法是在状态机里输出一个 IsExecute 布尔量。在外围逻辑中使用传感器脉冲触发计数。只有在 IsExecute 为 TRUE 时传感器脉冲才会计入合格品。示例逻辑IF ioUnit.State cExecute AND #bSensorPulse THEN ioUnit.CountGood : ioUnit.CountGood 1; END_IF;不要用扫描周期累计计数不要用普通上升沿替代真正的物料检测信号。批次开始前对 CountGood 清零批次结束后把计数写入归档区再清当前批次计数。这样即使程序重启也能保留上一批次数据。6. 运行验证与调试6.1 用 S7-PLCSIM 做最小状态机验证没有实物 PLC 时可以先使用 S7-PLCSIM 验证状态机逻辑。步骤概括如下在 TIA Portal 中编译并下载到 PLCSIM。打开监控表或 Watch Table。给 Unit1.CmdStart 写 TRUE再写 FALSE。观察 Unit1.State 从 cIdle 变为 cStarting。给 Unit1.Ready 和 Unit1.RunFeedback 写 TRUE。观察 Unit1.State 从 cStarting 变为 cExecute。给 Unit1.CmdStop 写 TRUE。给 Unit1.StopFeedback 写 TRUE观察进入 cStopped。给 Unit1.CmdReset 写 TRUE观察回到 cIdle。预期状态变化表操作输入信号预期状态Idle 启动CmdStart 上升沿Starting启动完成ReadyTRUERunFeedbackTRUEExecute执行中保持CmdHold 上升沿Holding保持完成保持到位信号Held解除保持CmdHoldFALSE 或 Unhold 命令Unholding恢复运行ReadyTRUEExecute执行中停止CmdStop 上升沿Stopping停止完成StopFeedbackTRUEStopped停止后复位CmdReset 上升沿Resetting复位完成复位到位信号Idle故障中止FaultTRUEAborting中止完成内部逻辑Aborted清除故障CmdClear 上升沿Clearing清除完成内部逻辑Cleared清除后复位CmdReset 上升沿Idle这个验证过程的关键是“每个转换都要有明确输入条件”不能只验证设备能启动。启动、停止、保持、故障、清除、复位整条链路都要跑一遍。6.2 调试时重点观察哪几个信号先用时间顺序去看命令是否产生上升沿。如果只是电平置位状态会乱跳。状态是否按预期跳变。如果卡住优先看该状态需要什么反馈。反馈信号是否真实反映机械动作。RunFeedback 不能是启动命令的延时它应来自接触器辅助触点、变频器状态字或驱动器准备信号。故障信号是否会导致 Abort。若故障时不进 Abort上层联机无法判断设备到底停没停。使用 S7-1500 时可以利用 Web Server 或 OPC UA 快速读取状态变量。也可以把状态变量导入 HMI 的文本列表让画面直接显示“启动中”“运行中”“保持中”等文本。6.3 HMI 联动验证HMI 上通常需要放置当前状态文本。当前模式文本。Start、Stop、Hold、Reset、Abort、Clear 按钮。自动/手动模式切换按钮。合格品计数显示。联动验证时重点检查按钮是否只在允许状态下有效。例如设备在 Execute 状态下按 Reset 不应有任何响应在 Stopped 状态下按 Start 也不应有效。这些限制既可以在 PLC 状态机里做也可以结合 HMI 属性“可见性”和“使能”一起做。但最可靠的做法是 PLC 侧判断状态HMI 侧只负责发送命令。7. 常见问题排错7.1 状态卡在 Starting 或 Stopping现象设备命令已经发出但状态始终停在 Starting 或 Stopping。这是反馈信号没有满足导致的。可能原因Ready 条件没有满足例如安全门未关、气压不足、伺服未使能。RunFeedback 或 StopFeedback 信号没有接对。命令发出后又被外围逻辑清掉状态机根本没收到。排查步骤在监控表中查当前状态编号。查看该状态的进入条件是什么。逐项检查 Ready、RunFeedback、StopFeedback。确认这些信号来自实际设备反馈而不是 HMI 按钮自复位延时。问题现象常见原因检查方式处理建议状态卡在 StartingRunFeedback 未到位监控反馈信号检查接触器辅助触点、变频器状态字状态卡在 StoppingStopFeedback 未到位监控停止反馈检查机械限位或接触器断开反馈状态反复跳回 Start命令是电平信号查看命令波形/状态变化改为 R_TRIG 触发处理完成后清命令HMI 状态一直是 0HMI 变量未连接正确对比 PLC 变量和 HMI 变量地址重新建立 HMI 变量连接7.2 状态机在不同状态之间反复跳常见原因是命令没有清除。例如 Start 为 TRUE 导致从 Idle 进入 Starting但启动条件不满足同时 Start 一直为 TRUE下一次扫描又重复触发。严重时会出现状态从 Starting 跳到 Idle再跳回 Starting。处理方案是命令必须一次性有效。推荐统一做法所有外部命令进入状态机前先做边沿检测状态机处理完成后立刻清除命令位。7.3 HMI 显示文本和 PLC 状态对不上状态编号本身没有含义必须依靠 HMI 的文本列表或脚本转换成文字。如果 PLC 里状态号是 3HMI 文本列表里 3 号却叫“运行中”而 PLC 中 3 号是 Holding那么显示必然错。排查路径在 PLC 监控表中确认当前 State 值。打开 HMI 文本列表确认该编号对应的文本。与状态常量表对照。统一由项目负责人维护一份状态编号表。最佳做法是把状态编号表同时用于 PLC 常量和 HMI 文本列表保证两份表出自同一份文档。7.4 DB 块优化访问导致的通信问题TIA Portal 中 DB 块默认可能是优化访问。优化块访问时DB 变量没有固定偏移地址CPU 内部通过符号访问。如果 CPG 中部分 DB 需要被 Modbus TCP、OPC UA 或第三方上位机读取可能遇到地址无法映射的问题。现象程序能正常监控但外部通信读取 DB 某个变量没有数据或报地址无效。处理方案在 DB 属性中关闭“优化的块访问”。或者使用 GetInstruction 和 SetInstruction 指令由 PLC 主动将数据写入通信数据区。也可以使用 OPC UA 的符号访问方式不依赖绝对偏移地址。注意关闭优化访问后变量的地址分配方式会变化影响通信配置。修改前先备份原程序并确认 CPG 库中该 DB 是否允许关闭优化访问。7.5 一个子 Unit 故障导致整条线全部 Abort故障联动策略要区分故障等级。不是所有故障都需要 Abort。例如输送带堵料应该先停机再人工清理而安全门打开或急停按下才需要立即 Abort。CPG 框架中通常不会用同一个故障位直接触发所有 Unit 的 Abort。更合理的做法是设备级故障分等级。普通故障进入 Stopping。严重故障进入 Aborting。父 Unit 根据子 Unit 最终状态来决定联动策略。联机调试时这个故障等级表最好在项目启动前就定义清楚并且写进调试文件。8. 工程落地最佳实践把 CPG 用成标准库而不是一次性程序8.1 把状态机做成库而不是复制粘贴很多团队第一次引入 CPG 时会把整个框架复制到项目里然后项目结束、入库、归档。等下一个项目来了再把上一个项目的程序复制出来改。这种做法会导致库在不同项目之间逐渐分化状态号、变量名、HMI 文本开始不一致。正确做法是把 CPG 作为统一库维护。项目工程中被修改的只有“工艺数据”和“设备实例”不修改库里的状态机和 UDT。如果确实需要扩展状态应该在库里提版本并通知使用该库的全部项目更新。一个好的库至少要包含状态机 FB。Unit UDT。HMI 标准画面模板。状态编号表。版本说明文档。已知问题和修改记录。8.2 统一 HMI 文本列表和状态常量在整机项目中状态文本由同一个表维护。开始编程时就把状态表定下来不要等到 HMI 画面做完后再补。HMI 画面上“当前状态”文本直接挂在状态编号变量上通过文本列表映射。这样即使状态逻辑修改只要编号不变HMI 不用返工。8.3 联调前检查清单现场联调并不是从按下启动按钮开始。联调前先完成以下检查状态机所有状态是否可以通过 PLCSIM 模拟走通。每个状态下命令是否只允许在合法窗口内生效。所有命令是否通过边沿触发并处理完清除。手动模式和自动模式切换是否不会造成状态跳变。安全门、急停、气压低压等信号是否接入 Fault 路径。故障确认后是否必须经过 Clear 和 Reset 才能回到 Idle。父 Unit 与子 Unit 的状态汇总策略是否明确。设备启动顺序是否符合机械工艺要求。变频器和伺服通信是否在设备驱动层不影响状态机。HMI 文本列表和 PLC 状态编号表一一对应。DB 块的访问方式是否满足后续 OPC UA 或 Modbus TCP 接入。CPU 的循环时间是否满足状态机调用周期要求。库版本和程序版本已经备份并记录。8.4 扩展方向CPG 和 PACKML 的价值不只是单机状态机。它很适合继续扩展把变频器、伺服驱动器的通信做成设备驱动层状态机只关心 Ready 和 RunFeedback。用 OPC UA 把 Unit 状态和批次数据发布到 MES。结合视觉系统和机器人把视觉结果作为子 Unit 的合格/不合格信号。在 HMI 中做统一的整线总览页面直接读取父 Unit 和子 Unit 状态表。使用标准库后同一套程序可以快速复制到不同规格的包装机只需调整工艺参数和轴配置。现场调试时如果状态机能在任何时刻明确回答“设备当前处于哪个状态为什么不能启动需要满足什么条件才能继续”程序就已经赢了一半。PACKML 给的是这套回答的语法CPG 给的是在西门子环境下的可复用工程模板两者结合起来才能真正把包装机程序从“堆逻辑”变成“做标准”。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进