4. 用户自定义数据类型(UDT)设计

在Studio 5000中,用户自定义数据类型(User-Defined Data Type,UDT)是程序复用与模块化设计的基础构件。它的核心价值在于:把一台设备、一个工位或一类对象的全部相关数据,从零散的标签中收拢为一个有名字、有结构、可整体传递的数据单元。当同一类设备出现多次时,UDT让程序只需编写一次逻辑,就能通过不同实例复用。

一、UDT的本质:从“散点标签”到“设备对象”

传统做法中,一台电机的运行命令、运行反馈、故障状态、电流值、启动次数往往被定义为五个互不相关的标签,例如 M1_RunCmd、M1_RunFb、M1_Fault、M1_Current、M1_StartCnt。这种命名方式在设备数量少时尚可维护,一旦产线扩展到几十台电机,标签数量呈线性膨胀,程序复用几乎无从谈起。

UDT的做法是定义一个名为 UDT_Motor 的数据类型,把上述成员全部纳入其中。此后,每台电机只需声明一个该类型的标签,例如 Motor_01,其内部成员通过 Motor_01.RunCmd、Motor_01.Fault 访问。设备对象由此形成,程序逻辑可以针对“电机”这一抽象对象编写,而不是针对“M1”这一具体实例。

二、成员命名规范:让UDT自解释

UDT的成员命名直接决定程序的可读性。建议遵循以下约定:成员名使用英文或拼音缩写,采用大驼峰或下划线分隔,保持全项目一致;布尔量以状态或命令语义命名,如 RunCmd、RunFb、Fault;模拟量以物理量加单位或语义命名,如 Current_A、Speed_RPM;计数器以 Cnt 结尾,如 StartCnt;定时器成员使用 TON 或 Timer 前缀,如 RunTimer。

更重要的是,成员命名应避免与设备实例名重复。例如 Motor_01.Motor_01_Fault 就是冗余命名,正确写法是 Motor_01.Fault。UDT名称本身已经表达了设备类型,成员只需表达该类型内部的属性。

三、嵌套UDT:用组合表达复杂设备

当设备由多个子系统构成时,嵌套UDT是自然的选择。例如一台输送机可能包含电机、气缸、光电传感器三个子对象。可以分别定义 UDT_Motor、UDT_Cylinder、UDT_PhotoEye,然后在 UDT_Conveyor 中嵌入这三个UDT作为成员:

UDT_Conveyor
├─ Motor      : UDT_Motor
├─ Stopper    : UDT_Cylinder
├─ PartSensor : UDT_PhotoEye
├─ RunCmd     : BOOL
└─ Fault      : BOOL

嵌套的层次不宜过深,一般建议不超过三层。过深的嵌套会让标签浏览器中的路径变得冗长,也会增加HMI绑定时的寻址复杂度。嵌套UDT的真正优势在于:子对象可以独立复用,例如 UDT_Motor 既可用于输送机,也可用于搅拌机、风机,无需重复定义。

四、数组UDT:批量设备的统一管理

当同一类设备数量较多时,数组UDT比逐个声明实例更高效。例如一条装配线上有12个相同的压装工位,可以声明 PressStation : UDT_Press[0..11]。程序中用 FOR 循环遍历数组,对每个工位执行相同的逻辑:

FOR i := 0 TO 11 DO
    PressStation[i].RunCmd := LineRun;
    PressStation[i].Fault   := PressStation[i].FaultFb;
END_FOR;

数组UDT的成员访问方式为 PressStation[i].Member,在HMI中可以通过索引切换显示不同工位。需要注意的是,数组UDT的每个元素都占用独立内存,12个工位意味着12份完整的数据副本,设计时应评估控制器内存余量。

五、UDT在程序与HMI中的复用方法

在程序中,UDT的复用通过“参数化例程”实现。将针对 UDT_Motor 的逻辑封装为一个Add-On自定义指令(AOI)或子例程,输入输出参数声明为 UDT_Motor 类型。调用时传入不同的实例标签,即可实现同一逻辑驱动多台设备。例如 Motor_Control(Motor_01) 和 Motor_Control(Motor_02) 共用同一段代码。

在HMI中,FactoryTalk View等上位软件支持直接绑定UDT成员。以 Motor_01.RunFb 为例,在画面中创建一个电机状态指示器,将其动画连接指向该成员即可。若使用数组UDT,可通过参数化画面或间接寻址,用一个画面模板显示任意工位,大幅减少画面数量。

建议在UDT设计完成后,先在标签数据库中创建至少一个测试实例,验证成员访问路径、HMI绑定和AOI参数传递是否正常,再批量复制到实际设备。这样可以避免因UDT结构变更导致的大范围返工。

六、UDT设计检查要点

一个可复用的UDT应满足以下条件:成员命名一致且无冗余前缀;布尔量、模拟量、定时器、计数器分区清晰;嵌套层次不超过三层;数组UDT的索引范围与设备编号对应;所有成员在程序或HMI中都有明确用途,不存在“预留但从未使用”的僵尸成员。UDT一旦投入生产使用,修改结构会影响所有实例,因此设计阶段应尽量考虑周全,必要时通过新增成员而非删除成员来演进。

UDT 面向设备对象的数据结构设计 从基础类型 → 嵌套组合 → 数组批量 → 程序/HMI 复用 UDT_Motor RunCmd : BOOL RunFb : BOOL Fault : BOOL Current_A : REAL Speed_RPM : REAL StartCnt : DINT RunTimer : TIMER UDT_Cylinder ExtendCmd : BOOL RetractCmd : BOOL ExtendedFb : BOOL RetractedFb : BOOL UDT_PhotoEye Detect : BOOL Blocked : BOOL Debounce : TIMER UDT_Conveyor(嵌套 UDT) Motor : UDT_Motor Stopper : UDT_Cylinder PartSensor : UDT_PhotoEye RunCmd : BOOL Fault : BOOL 数组 UDT:PressStation : UDT_Press[0..11] PressStation[0] PressStation[1] ... PressStation[11] FOR i := 0 TO 11 DO → 统一逻辑遍历 程序 / HMI 复用 AOI 参数:UDT_Motor 类型 → 传入实例 HMI 绑定:Motor_01.RunFb / PressStation[i].Fault 基础UDT 子对象UDT 嵌套/复用 数组UDT

上图展示了从基础UDT到嵌套UDT、数组UDT,再到程序与HMI复用的完整关系。基础UDT(如 UDT_Motor)是构建块,嵌套UDT(如 UDT_Conveyor)通过组合子对象表达复杂设备,数组UDT(如 UDT_Press[0..11])实现批量管理,最终在AOI参数传递和HMI绑定中完成复用。设计时应始终围绕“设备对象”这一核心,让UDT成为程序模块化的数据骨架。