2. OPC UA核心概念与信息模型

OPC UA 与早期 OPC Classic 最大的区别,在于它不再只是“把 PLC 里的某个寄存器读出来”,而是用一套统一的信息模型来描述设备、数据与行为。理解地址空间、节点、引用、数据类型、变量、方法和事件这几个概念,是后续在实验设备上做集成、建模和调试的基础。本节围绕这些概念展开,并给出一个可直接对照实验设备使用的建模示例。

地址空间:服务器对外暴露的“信息地图”

地址空间(AddressSpace)是 OPC UA 服务器中所有可访问信息的集合,可以把它理解成一张树状的信息地图。客户端浏览服务器时,看到的每一个条目都落在这张地图上。地址空间由节点和节点之间的引用构成,节点是地图上的“点”,引用是连接这些点的“线”。

地址空间不是简单的目录树,它允许一个节点被多个父节点引用,也允许自定义引用类型,因此可以表达设备层级、类型层级、组织层级等多套并行的结构。实验设备集成中,常见的做法是:设备物理结构用一套层级表达,功能分组用另一套引用表达,二者共享同一批变量节点。

节点:地址空间中的基本单元

节点(Node)是地址空间的最小可寻址单元,每个节点由 NodeId 唯一标识。NodeId 由命名空间索引(NamespaceIndex)和标识符(Identifier)组成,标识符可以是数值、字符串、GUID 或字节串。例如 ns=2;s=Reactor.Temperature 表示命名空间 2 中一个字符串标识的节点。

节点本身只是“壳”,它的具体含义由节点类(NodeClass)决定。OPC UA 定义了八种节点类:对象(Object)、变量(Variable)、方法(Method)、对象类型(ObjectType)、变量类型(VariableType)、引用类型(ReferenceType)、数据类型(DataType)和视图(View)。实验设备建模中最常用的是对象、变量和方法三类。

每个节点都有一组属性(Attribute),如 NodeId、BrowseName、DisplayName、Description、WriteMask 等。其中 BrowseName 用于浏览时的显示与去重,DisplayName 用于人机界面展示,二者不要混用。

引用:节点之间的连接关系

引用(Reference)描述两个节点之间的关系,是有方向、有类型的。引用类型本身也是节点,因此可以自定义。常用的标准引用类型包括:

  • Organizes:组织关系,常用于文件夹与内容之间;
  • HasComponent:组合关系,表示整体与组成部分,如设备与它的温度变量;
  • HasProperty:属性关系,表示节点与其属性;
  • HasTypeDefinition:类型定义关系,把实例节点指向它的类型节点;
  • HasSubtype:类型继承关系,用于类型层级。

浏览服务器时,客户端正是沿着引用从一个节点走到另一个节点。理解引用的方向性很重要:HasComponent 从整体指向部分,反向引用是 ComponentOf,二者成对出现。

数据类型与变量:值、类型与访问方式

变量(Variable)是承载数据的节点,它至少包含 Value、DataType、ValueRank、AccessLevel 等属性。DataType 决定值的类型,OPC UA 内置类型包括 Boolean、SByte、Byte、Int16、UInt16、Int32、UInt32、Float、Double、String、DateTime、Guid、ByteString 等,也支持基于这些类型构造的结构体(Structure)和枚举(Enumeration)。

ValueRank 描述值的维度:-1 表示标量,0 表示任意维度数组,1 表示一维数组,以此类推。实验设备中,单个温度点是标量,多通道采集卡的各通道值通常是一维数组。

AccessLevel 决定客户端能否读写,常见取值有 CurrentRead、CurrentWrite、CurrentReadWrite。对于只读的测量值,应设为 CurrentRead;对于设定值,可设为 CurrentReadWrite。写操作还会受 UserAccessLevel 约束,二者需同时满足。

方法与事件:行为与通知

方法(Method)表示服务器上可被客户端调用的操作,例如“启动反应釜”“校准传感器”。方法节点通过 HasComponent 挂在对象下,调用时传入输入参数,返回输出参数。方法调用是同步的,调用结果通过 Call 服务的返回状态码判断。

事件(Event)表示服务器主动向客户端推送的通知,如越限报警、设备状态变化。事件通过 EventNotifier 属性开启,客户端通过订阅(Subscription)和监控项(MonitoredItem)接收。事件类型由事件类型节点定义,常见基类型是 BaseEventType,实验设备中可派生自定义事件类型,如 TemperatureAlarmEvent,并附加 EventId、Time、Message、Severity 等字段。

一个实验设备信息模型示例

下面给出一个反应釜实验设备的简化信息模型,用于对照理解上述概念。命名空间索引设为 2,设备对象为 ns=2;s=Reactor,其下挂温度变量、压力变量、启动方法和报警事件。

Objects
└─ Reactor (Object, ns=2;s=Reactor)
   ├─ Temperature (Variable, ns=2;s=Reactor.Temperature)
   │   DataType=Double, ValueRank=-1, AccessLevel=CurrentRead
   ├─ Pressure (Variable, ns=2;s=Reactor.Pressure)
   │   DataType=Double, ValueRank=-1, AccessLevel=CurrentRead
   ├─ Setpoint (Variable, ns=2;s=Reactor.Setpoint)
   │   DataType=Double, ValueRank=-1, AccessLevel=CurrentReadWrite
   ├─ Start (Method, ns=2;s=Reactor.Start)
   │   InputArguments: RampRate (Double)
   │   OutputArguments: Result (Boolean)
   └─ TemperatureAlarm (EventType, ns=2;s=Reactor.TemperatureAlarm)
       Fields: EventId, Time, Message, Severity, LimitValue

建模时,Reactor 节点通过 HasTypeDefinition 指向一个自定义对象类型 ns=2;s=ReactorType,该类型下定义了同样的变量与方法,实例只需引用类型即可复用结构。这样当实验设备型号增加时,只需新增类型,不必重复定义每个实例的变量。

阅读信息模型时,建议按“对象 → 变量/方法 → 数据类型 → 引用”的顺序逐层展开,先确认 NodeId 与 BrowseName,再核对 DataType 与 AccessLevel,最后检查引用方向是否正确。

建模与阅读的检查要点

构建简单信息模型时,容易出问题的地方集中在命名空间、类型定义和访问权限三处。命名空间索引必须在服务器启动时注册,客户端拿到 NodeId 后要按索引解析,不能硬编码字符串前缀。类型定义要保证实例与类型一致,否则客户端按类型浏览时会找不到节点。访问权限要区分 AccessLevel 与 UserAccessLevel,只读变量若被误设为可写,可能被客户端意外改写。

阅读他人模型时,可先浏览 Objects 文件夹,找到设备对象,再沿 HasComponent 展开变量与方法,最后查看 HasTypeDefinition 确认类型来源。若发现变量没有类型定义或引用方向异常,通常说明模型是手工拼装而非按类型实例化,后续维护成本会明显升高。

反应釜实验设备 OPC UA 信息模型(ns=2) Objects 根文件夹 Reactor Object · ns=2;s=Reactor Organizes ReactorType ObjectType · ns=2;s=ReactorType HasTypeDefinition Temperature Double · 标量 · 只读 ns=2;s=Reactor.Temperature Pressure Double · 标量 · 只读 ns=2;s=Reactor.Pressure Setpoint Double · 标量 · 读写 ns=2;s=Reactor.Setpoint Start Method RampRate→Result HasComponent HasComponent HasComponent HasComponent TemperatureAlarm EventType · ns=2;s=Reactor.TemperatureAlarm EventId · Time · Message · Severity · LimitValue HasEventSource 变量(只读) 变量(读写) 方法 类型 / 事件 引用方向

上图把 Reactor 对象、四个子节点、类型定义和事件类型放在同一张图中,引用方向统一从父节点指向子节点。对照这张图,可以快速确认每个节点的 NodeId、数据类型、访问权限和引用类型,是阅读和构建简单信息模型时最直接的参照。