4. OPC UA信息模型

OPC UA 信息模型是工业物联网数据语义化的核心。它不仅仅是一个数据通道,更是一套完整的、面向对象的类型系统,用于描述现实世界中的设备、传感器、工艺参数及其相互关系。理解信息模型,是构建可互操作、可扩展的数据采集方案的前提。

4.1 类型系统概述

OPC UA 的类型系统采用严格的层次化结构,所有类型都继承自一个基类。这种设计确保了地址空间中所有节点的行为一致性,并允许客户端通过类型信息自动理解数据的含义。

类型类别基类核心作用实例
对象类型BaseObjectType定义对象的属性、变量和方法的结构MotorType、PumpType
变量类型BaseVariableType定义变量的数据类型、语义和属性AnalogItemType、PropertyType
引用类型BaseReferenceType定义节点之间的语义关系HasComponent、Organizes
数据类型——定义数据值的结构和编码方式Int32、String、Structure
关键概念: 类型系统是“模板”,节点是“实例”。例如,MotorType 定义了电机应有的所有属性(转速、温度、状态),而地址空间中具体的 Motor_001 节点则是该类型的一个实例,拥有具体的数值。

4.2 引用类型:语义关系的基石

引用类型定义了节点之间如何连接。没有引用,地址空间只是一堆孤立的节点。OPC UA 预定义了几种核心引用类型,并允许用户自定义扩展。

  • Hierarchical References(层次引用): 用于构建地址空间的树形结构。
    • Organizes:用于将子节点组织到父节点下,常用于对象与文件夹之间。
    • HasComponent:表示父对象包含子组件,是强包含关系。
    • HasProperty:表示节点拥有某个属性。
  • Non-Hierarchical References(非层次引用): 用于在树形结构之外建立跨分支的语义关联。
    • HasTypeDefinition:指向节点的类型定义,是实例化关系的核心。
    • HasSubtype:用于定义类型之间的继承关系。
    • HasEventSource:表示节点是事件的来源。
实战要点: 在采集数据时,客户端通常通过 HasComponent 和 Organizes 引用遍历地址空间树,找到目标变量节点。而 HasTypeDefinition 引用则用于获取变量的元数据(如量程、单位),这是实现智能仪表盘的关键。
OPC UA 引用类型关系图 Root (Objects Folder) Motor_001 Temperature Speed Status MotorType (ObjectType) Organizes HasComponent HasComponent HasTypeDefinition 说明:实线箭头表示层次引用(Organizes / HasComponent),虚线箭头表示非层次引用(HasTypeDefinition)。

4.3 对象类型:设备的抽象模板

对象类型是信息模型中最常用的类型,用于定义现实世界中的物理或逻辑实体。一个对象类型可以包含变量、方法、事件和其他对象。

  • 预定义对象类型: OPC UA 规范定义了 BaseObjectType,所有自定义对象类型都继承自它。
  • 自定义对象类型: 通过 HasSubtype 引用从 BaseObjectType 派生。例如,定义一个 TemperatureSensorType,包含 CurrentTemperature(变量)、AlarmLimit(属性)和 Reset()(方法)。
常见误区: 初学者容易混淆“对象类型”和“对象节点”。对象类型是定义在类型字典中的模板,而对象节点是地址空间中实际存在的实例。修改对象类型会影响所有未覆盖该属性的实例。

4.4 变量类型:数据的语义标签

变量类型为数据值赋予了丰富的语义信息,使得客户端无需预先知道设备细节就能正确解析数据。

变量类型用途关键属性
PropertyType描述节点的静态属性Value、DataType、AccessLevel
AnalogItemType表示模拟量(连续值)EURange(量程)、EngineeringUnits(工程单位)
DiscreteItemType表示离散量(枚举或整数值)EnumValues、ValuePrecision
ArrayItemType表示数组数据ArrayDimensions、AxisInformation
仪表盘集成价值: 当仪表盘读取一个 AnalogItemType 变量时,可以直接从节点的 EURange 属性获取量程(如 0-100°C),从 EngineeringUnits 获取单位,自动配置 Y 轴范围和标签,无需人工干预。

4.5 数据编码:二进制与 JSON

OPC UA 支持多种数据编码方式,以适应不同的网络环境和应用场景。编码方式决定了数据在网络上传输时的字节格式。

  • UA Binary(二进制编码): 默认编码,高效紧凑,适用于高实时性、低带宽的工业现场。所有 OPC UA 服务器和客户端都必须支持。
  • UA JSON(JSON 编码): 基于文本,可读性强,易于与 Web 应用、云平台集成。常用于物联网网关和 REST API 场景。
  • UA XML(XML 编码): 主要用于配置和交换信息模型文件(NodeSet),不常用于运行时数据采集。
OPC UA 数据编码对比 数据编码方式对比 UA Binary 字节流,紧凑高效 延迟低,带宽占用小 (工业现场首选) UA JSON 文本格式,可读性强 易于 Web/云集成 (物联网网关首选) UA XML 结构化,自描述 用于模型交换 (NodeSet 文件) 选择建议:现场总线层使用 UA Binary;边缘网关到云端使用 UA JSON;模型设计与交换使用 UA XML。 现代 OPC UA 客户端通常支持自动协商编码方式。

4.6 实战:使用 Python 读取类型信息

在 Python 中,使用 opcua-asyncio 或 opcua 库可以轻松获取节点的类型信息。以下代码展示了如何读取一个变量的类型定义及其属性。

import asyncio
from opcua import Client

async def read_type_info():
    client = Client("opc.tcp://localhost:4840")
    await client.connect()
    try:
        # 获取一个变量节点
        var_node = client.get_node("ns=2;s=Temperature_001")
        
        # 读取变量的数据类型
        data_type = await var_node.read_data_type()
        print(f"数据类型: {data_type}")
        
        # 读取变量的类型定义节点 (HasTypeDefinition)
        type_def_node = await var_node.read_type_definition()
        print(f"类型定义节点: {type_def_node}")
        
        # 读取类型定义节点的 BrowseName
        type_name = await type_def_node.read_browse_name()
        print(f"变量类型名称: {type_name}")
        
        # 如果是 AnalogItemType,读取量程和单位
        if "AnalogItemType" in str(type_name):
            # 读取 EURange 属性
            eu_range_node = var_node.get_child("0:EURange")
            eu_range = await eu_range_node.read_value()
            print(f"量程: {eu_range}")
            
            # 读取 EngineeringUnits 属性
            unit_node = var_node.get_child("0:EngineeringUnits")
            unit = await unit_node.read_value()
            print(f"工程单位: {unit}")
            
    finally:
        await client.disconnect()

asyncio.run(read_type_info())
代码解读: 上述代码通过 read_type_definition() 获取变量的类型节点,然后通过 get_child() 方法读取类型定义中预定义的属性(如 EURange)。这是实现“自描述仪表盘”的基础——仪表盘无需硬编码任何设备参数,完全通过信息模型动态获取。

4.7 本章小结

OPC UA 信息模型通过严谨的类型系统,将工业数据从“裸数值”提升为“语义对象”。引用类型定义了节点间的关系,对象类型和变量类型提供了结构和语义模板,而数据编码则确保了数据在不同场景下的高效传输。掌握这些概念,是构建可互操作、可维护的工业物联网系统的关键一步。