PLC项目架构很重要

工业PLC项目需要仔细的架构规划,以确保可维护性、可扩展性和易于调试。本指南解决基本问题:PLC项目应如何组织?什么构成了"好的"模块化设计?如何在没有正式类的情况下实现类似OOP的模式?

关键原则: 目标不是为了复杂而复杂——而是在凌晨2点调试故障时减少认知负担,能够在项目之间重用,并让团队成员快速浏览不熟悉的代码。

1、基础概念

1.1 三大支柱

概念 定义 PLC实现
抽象 将复杂性隐藏在定义良好的接口后面 接口FB块仅暴露必要的参数
封装 将相关数据和函数分组在一起 功能块包含数据+逻辑作为一个单元
模块化 将系统分解为独立的、可互换的单元 为每个设备/过程功能创建单独的FB

1.2 不要重复自己(DRY)

每个FB/FC应该执行一个专门的任务。如果发现逻辑在部分之间复制,请将其提取为可重用的功能块。

2、项目结构层次

组织良好的PLC项目遵循分层架构:

┌─────────────────────────────────────────┐
│  第5层:应用/主序列                      │
│  (状态机:自动/手动/错误)                │
├─────────────────────────────────────────┤
│  第4层:过程协调                         │
│  (排序器、模式管理器)                    │
├─────────────────────────────────────────┤
│  第3层:设备协调                         │
│  (运动、阀组、安全)                     │
├─────────────────────────────────────────┤
│  第2层:设备驱动程序                      │
│  (伺服接口、单阀、AI)                   │
├─────────────────────────────────────────┤
│  第1层:硬件抽象                         │
│  (I/O映射、现场设备驱动程序)             │
└─────────────────────────────────────────┘

示例:B&R自动化工作室组织

逻辑视图:
├── 接口                 (合同定义)
│   └── IServoDrive        
├── 设备驱动程序          (硬件附近)
│   ├── Servo_Drive       (实现IServoDrive)
│   └── IO_Mapping        (原始I/O处理)
├── 过程逻辑             (技术)
│   ├── Conveyor_Ctrl
│   └── Filling_Station
├── 协调器              (模式管理)
│   └── Main_Sequencer    (此处使用SWITCH CASE)
└── 类型                 (共享数据结构)

3、基于接口的设计(没有类?没问题)

许多PLC平台(B&R、TwinCAT3、CODESYS)支持接口——定义方法签名而没有实现的合同。这实现了多态性而没有OOP继承。

3.1 接口定义(B&R ST)

// 接口定义(不在POU中 - 单独文件)
INTERFACE IServoDrive

METHOD Enable : BOOL
METHOD Disable : BOOL
METHOD MoveAbsolute : BOOL (position : LREAL, velocity : LREAL)
METHOD GetStatus : INT  // 返回:0=禁用,1=就绪,2=移动中,3=错误

END_INTERFACE

3.2 具体实现

// 功能块实现接口
FUNCTION_BLOCK Servo_AKM62 IMPLEMENTS IServoDrive

VAR_INPUT
    AxisID : INT;
END_VAR

VAR_OUTPUT
    Status : INT;
    ErrorCode : UINT;
END_VAR

METHOD Enable : BOOL
    // 硬件特定的启用逻辑
    // 映射到实际驱动器参数
END_METHOD

METHOD MoveAbsolute : BOOL
    // 调用特定驱动器API(B&R伺服库)
END_METHOD

END_FUNCTION_BLOCK

3.3 用法:多态数组

VAR
    myServos : ARRAY[1..4] OF IServoDrive;  // 接口数组
END_VAR

// 初始化
myServos[1] := gAxis1;  // 分配具体FB实例
myServos[2] := gAxis2;

// 通用命令 - 相同代码适用于任何驱动器!
FOR i := 1 TO 4 DO
    myServos[i].Enable();
END_FOR

4、主程序结构:状态机

Main.st(或等效文件)应使用SWITCH CASE架构编排高级模式:

// Main.st - 结构化文本
PROGRAM Main

CASE gSystemMode OF
    modeINIT:
        Initialize_System();
        IF System_Ready THEN
            gSystemMode := modeMANUAL;
        END_IF

    modeMANUAL:
        // 直接操作员控制 - 绕过排序器
        Process_Manual_Commands();
        // 仅在安全时允许转换到自动
        IF gCommand.Start_Auto AND Safe_For_Auto THEN
            gSystemMode := modeAUTO;
        END_IF

    modeAUTO:
        // 执行过程序列
        Process_Auto_Sequence();
        // 捕获错误 - 如果故障活动则不运行排序器
        IF gSystemFault.Active THEN
            gSystemMode := modeFAULT;
        END_IF

    modeFAULT:
        // 停止所有运动,锁定故障详情
        Emergency_Stop_All();
        gFaultLog[gFaultIndex] := gSystemFault;  // 记录到HMI
        // 仅在故障清除后允许转换到手动或初始化
        IF gCommand.Ack_Fault AND NOT gSystemFault.Active THEN
            gSystemMode := modeMANUAL;
        END_IF

    modeSTOP:
        Controlled_Stop_All();
        IF NOT Axes_At_Velocity_Zero() THEN
            // 等待停止
        ELSE
            gSystemMode := modeMANUAL;
        END_IF
END_CASE

// 始终执行这些
Process_Safety();
Update_HMI();

END_PROGRAM

5、变量命名约定

前缀 类型 示例
g 全局 gSystemMode, gRecipeData
i 输入(VAR_INPUT) iAxisEnable, iSensor_01
q 输出(VAR_OUTPUT) qMotorRun, qValve_Open
x 布尔 xAutoRunning, xFaultActive
r REAL rActualPosition, rSetpoint
n INT/DINT nAxisID, nCounter

平台变体: 西门子使用#表示局部变量,"Global"表示全局变量。Allen-Bradley使用基于标签的名称。B&R使用.符号(例如gAxis.xEnabled)。

6. 按功能选择语言

任务 推荐语言 原因
排序、状态机 SFC或ST(SWITCH CASE) 可视化流程,清晰转换
复杂数学、循环 ST 可读性,算法支持
位级逻辑、信号调理 FBD / LAD 可视化AND/OR/NOT链
过程计算 ST 数学表达式
安全逻辑 FBD 显式信号流,可认证性

7、平台特定资源

西门子(TIA Portal)

  • 样式指南: 西门子行业在线支持 - 搜索"编程指南TIA Portal"
  • 参考: SIMATIC S7-1500样式指南(条目ID:67585819)
  • FB容器: 在程序块内使用文件夹分组

B&R自动化工作室

  • 接口支持: 完整接口实现(参见第3节)
  • 库概念: 为每个设备系列创建可重用库
  • 参考: B&R在线帮助 - "功能块"和"接口"

Beckhoff TwinCAT3

  • OOP支持: ST中完整的C++类(METHOD、PROPERTY)
  • 参考: Beckhoff信息系统 - "TwinCAT 3 ST编程"
  • GitHub: 搜索"TwinCAT 3示例项目"

PLCOpen标准

  • IEC 61131-3 - 基础标准
  • PLCOpen TC2 - 运动控制FB库
  • PLCOpen XML - 导入/导出模式

8、验证清单

在称项目为"可维护"之前,请验证:

  1. 新工程师能否在30秒内找到排序器?
  2. 更改一个驱动器类型是否需要在多个地方进行更改?(应该是NO)
  3. 您能否独立模拟每个设备FB?
  4. 所有魔术数字是否已替换为命名常量?
  5. 每个FB是否有单一、明确的职责?

9、结束语

良好的PLC架构不是关于严格的规则——而是关于减少意外。当有人打开您的项目时,结构应与他们对工业机器工作方式的心理模型相匹配:模式在顶部,设备在底部,层之间的清晰合同(接口)。

从简单开始:将一个重复模式提取到FB中。为一个设备系列添加一个接口。将主排序器重构为使用SWITCH CASE。每次改进都会复合为更轻松的维护、更快的调试和更可重用的代码。


原文链接:PLC Project Architecture: Modular Design Patterns and Best Practices for Industrial Controllers

汇智网翻译整理,转载请标明出处