3. 信息模型建模方法论

OPC UA 信息模型不是“把变量堆进地址空间”,而是用面向对象的方式,把一台设备、一条产线乃至一个车间的可交换语义固化成可复用、可继承、可组合的类型系统。本节要解决的核心问题是:拿到一份设备手册和一份工艺文档后,如何一步步推导出 TypeDefinition、InstanceDeclaration,再通过实例化、继承与组合形成可上线的地址空间。

一、从文档到模型:先抽取“对象—属性—关系”

设备手册通常给出铭牌参数、接口清单、状态字与故障码;工艺文档则给出工位、工序、物料流与节拍。建模的第一步不是打开建模工具,而是做语义抽取:把文档中的名词识别为 Object 或 Variable,把可执行动作识别为 Method,把设备之间的物理连接、工位顺序、物料流向识别为 Reference。例如某伺服驱动器手册中,“额定电流 4.2 A”“额定转速 3000 rpm”“使能状态”“故障码”分别对应 Variable、Variable、Variable、Variable;而“使能”“复位”对应 Method;“驱动器—电机”对应 HasComponent 或 HasMotor 之类的引用。

抽取时建议维护一张“语义—节点类—数据类型—引用”的映射表,避免后续反复返工。下表给出一个简化示例(参数为教学假设值):

文档条目节点类BrowseNameDataType引用
额定电流 4.2 AVariableRatedCurrentDoubleHasProperty
使能状态VariableEnableStateBooleanHasComponent
使能动作MethodEnable—HasComponent
故障码VariableFaultCodeUInt16HasComponent
驱动器—电机ObjectMotor—HasComponent

二、类型定义:把共性抽成 TypeDefinition

类型定义的目标是“一次定义、多处复用”。在 OPC UA 中,常用基类型包括 BaseObjectType、BaseVariableType、BaseDataVariableType、PropertyType 等。对于设备,通常从 BaseObjectType 派生自定义 ObjectType;对于可复用参数,从 BaseDataVariableType 或 PropertyType 派生 VariableType。

以“伺服轴”为例,可定义 ServoAxisType,其 InstanceDeclaration 包含:RatedCurrent(Double,Property)、RatedSpeed(Double,Property)、EnableState(Boolean,Component)、FaultCode(UInt16,Component)、Enable()(Method)。这些声明在类型层只定义“有什么”,不绑定具体值;具体值在实例化时写入。

类型定义阶段要特别关注两点:一是 DataType 与 ValueRank 必须与手册量纲一致,例如电流用 Double、故障码用 UInt16、状态用 Boolean;二是 ModellingRule 要明确,Mandatory 表示实例必须存在,Optional 表示可选,MandatoryPlaceholder 用于占位。若把可选参数误设为 Mandatory,后续实例化会因缺项而失败。

三、实例化:把类型变成现场对象

实例化是把 TypeDefinition 挂到具体对象上,并填充现场值。以一台实际伺服轴 Axis_01 为例,在 Objects 下创建 Object,TypeDefinition 指向 ServoAxisType,然后为 RatedCurrent 写入 4.2、RatedSpeed 写入 3000、EnableState 初始为 false、FaultCode 初始为 0。此时地址空间中 Axis_01 自动获得类型中声明的所有子节点,无需手工逐个创建。

实例化时还要处理 NodeId 分配策略。工程上常用两种:一是按路径生成,如 ns=2;s=Line1.Axis_01.RatedCurrent;二是按随机 GUID。前者可读性好,适合调试;后者稳定但不可读。建议在车间层采用“命名空间 + 层级路径”的可读方案,便于运维定位。

四、继承与组合:两种复用方式的选择

继承用于“是一种”的关系。例如 ServoAxisType 继承自 MotionDeviceType,则自动获得后者的 SerialNumber、Manufacturer 等属性,再追加伺服特有属性。继承的优点是语义清晰、类型层次稳定;缺点是单继承限制,且父类型变更会影响所有子类型。

组合用于“有一个”的关系。例如 WorkstationType 组合了 ServoAxisType、GripperType、SafetyDoorType。组合通过 HasComponent 或 HasProperty 引用实现,实例化时子对象独立存在,可单独替换。工程上,设备内部强耦合部件用组合,设备分类用继承,二者配合才能既复用又灵活。

从文档到地址空间:类型定义 → 实例化 → 继承/组合 设备手册 铭牌参数 / 接口 状态字 / 故障码 动作 / 方法 工艺文档 工位 / 工序 物料流 / 节拍 设备连接关系 语义抽取 Object / Variable Method Reference DataType ModellingRule 映射表驱动 TypeDefinition ServoAxisType RatedCurrent: Double EnableState: Boolean Enable(): Method 继承 MotionDeviceType → ServoAxisType 组合 WorkstationType ├ ServoAxisType ├ GripperType 实例化 Axis_01 4.2 A 3000 rpm FaultCode=0 地址空间(AddressSpace) Objects └ Line1  └ Axis_01 : ServoAxisType  ├ RatedCurrent = 4.2  ├ EnableState = false  └ Enable()

五、落地检查:类型与实例的一致性

建模完成后,必须做一致性检查。第一,检查所有 Mandatory 子节点是否在实例中存在;第二,检查 DataType 是否与手册量纲一致,例如把电流误设为 Int16 会丢失小数;第三,检查 NodeId 是否唯一且可读;第四,检查 Method 的 InputArguments 与 OutputArguments 是否与工艺动作匹配。若使用 UaModeler 或 SiOME 等工具,可导出 NodeSet2.xml 并用 UaExpert 浏览验证。

建议在类型层只放“共性”,把“现场差异”留给实例层。例如把额定电流放在类型层作为 Property,把实际电流放在实例层作为 Variable,这样同一类型可复用于多台不同功率的伺服轴。
不要把设备手册中的每一个寄存器都直接映射为 Variable。应先按语义聚类,把同一功能的多个寄存器合并为一个结构化 Variable 或 Object,否则地址空间会迅速膨胀且难以维护。

总结来看,从设备手册与工艺文档到可运行的信息模型,路径是:语义抽取 → 类型定义 → 实例化 → 继承与组合 → 一致性检查。掌握这条路径,才能在后续车间接入中把“设备能连上”推进到“语义能互通”。