4. 地址空间基础
OPC UA 的地址空间(AddressSpace)是服务器对外暴露的“信息世界地图”。客户端并不是直接读取 PLC 寄存器,而是通过浏览地址空间发现对象、变量、方法及其语义关系。理解地址空间的结构、节点标识、命名空间以及浏览与查询机制,是设计可维护信息模型的前提。
一、地址空间结构:节点与引用构成的图
地址空间本质上是一张有向图:图中的顶点是节点(Node),边是引用(Reference)。每个节点由 NodeId 唯一标识,并至少属于一个节点类别(NodeClass),常见类别包括 Object、Variable、Method、ObjectType、VariableType、DataType、ReferenceType、View。引用则描述节点之间的语义关系,例如 Organizes、HasComponent、HasProperty、HasTypeDefinition、HasSubtype 等。
地址空间不是简单的树。虽然从 Objects 文件夹出发通常呈现层级结构,但同一节点可以被多个父节点引用,也可以被类型定义、事件源、视图等交叉引用。因此设计时应把它当作“带类型的图”,而不是文件目录。
二、节点标识:NodeId 的四种编码形式
NodeId 是节点在地址空间中的“身份证”,由命名空间索引(NamespaceIndex)、标识符类型和标识符值三部分组成。OPC UA 定义了四种标识符类型:数值(Numeric)、字符串(String)、GUID、字节串(ByteString)。其中数值和字符串最常用。
NodeId 语法示例:
ns=2;i=1001 → 命名空间2,数值标识符1001
ns=2;s=Machine_01 → 命名空间2,字符串标识符Machine_01
ns=1;g=... → GUID 标识符
ns=1;b=... → ByteString 标识符
标准节点(命名空间0):
i=85 → Objects 文件夹
i=2253 → Server 对象
i=47 → HasComponent 引用类型
设计时应遵循一个原则:类型定义和标准引用使用命名空间0,厂商自定义实例使用独立命名空间。数值标识符适合自动生成、紧凑高效;字符串标识符适合人工可读、便于调试,但需注意长度和编码一致性。
三、命名空间:避免语义冲突的隔离层
命名空间(Namespace)是地址空间的逻辑分区,用 NamespaceIndex 在 NodeId 中引用,用 NamespaceUri 在服务器元数据中声明。命名空间0 固定为 OPC UA 规范定义的标准节点;命名空间1 通常保留给服务器本地模型;厂商模型从命名空间2 开始分配。
| 命名空间索引 | 典型用途 | 示例 | 设计建议 |
|---|---|---|---|
| ns=0 | OPC UA 标准节点 | i=85 Objects、i=47 HasComponent | 只读引用,不可修改 |
| ns=1 | 服务器本地模型 | Server 诊断、本地设备 | 由服务器实现决定 |
| ns=2 | 厂商/项目模型 | MachineType、Temperature | 按项目或设备分配 |
| ns=3+ | 扩展模型或子模型 | 行业 Companion Spec | 避免索引硬编码 |
四、浏览与查询:从发现到定位
浏览(Browse)是客户端在地址空间中“沿引用行走”的机制。核心服务是 Browse,输入起始 NodeId、浏览方向(Forward/Inverse)、引用类型过滤器和结果掩码,输出 ReferenceDescription 列表,包含目标 NodeId、BrowseName、DisplayName、NodeClass 和类型定义。
查询(Query)则用于跨节点条件检索,包括 QueryFirst、QueryNext 以及基于视图的过滤。实际工程中,浏览用于层级发现,查询用于按条件筛选,例如“找出所有 NodeClass=Variable 且 BrowseName 以 Temperature 开头的节点”。
五、案例场景:从 Objects 定位到设备温度
假设客户端需要读取 Machine_01 的温度值。典型流程如下:
- 从 i=85(Objects)开始 Browse,方向 Forward,引用类型 Organizes,找到 ns=2;s=Machine_01。
- 对 Machine_01 继续 Browse,引用类型 HasComponent,找到 ns=2;s=Machine_01.Temperature。
- 读取该 Variable 的 Value 属性,同时可读取 DataType、AccessLevel、Historizing 等元数据。
- 若需要调用启动方法,Browse 找到 ns=2;s=Machine_01.Start,再调用 Call 服务。
如果客户端直接硬编码 ns=2;s=Machine_01.Temperature,一旦服务器调整命名空间顺序或节点标识符,通信就会失败。更稳健的方式是:先读取服务器 NamespaceArray,解析出目标 NamespaceUri 对应的索引,再拼接 NodeId。
六、设计复盘与检查清单
- 节点标识是否稳定?数值标识符一旦发布不应随意变更;字符串标识符应避免包含易变信息。
- 命名空间是否隔离?厂商模型不要混入 ns=0;不同项目模型应使用独立命名空间。
- 引用类型是否语义正确?组成关系用 HasComponent,属性用 HasProperty,组织关系用 Organizes,类型定义用 HasTypeDefinition。
- 是否支持浏览发现?关键节点应可从 Objects 或设备对象沿标准引用到达,避免“孤岛节点”。
- 是否避免硬编码?客户端应通过 NamespaceUri 和 BrowsePath 动态解析 NodeId。
地址空间设计的目标不是“把节点堆进去”,而是让客户端能够以标准、可预测、可发现的方式理解设备语义。结构清晰、标识稳定、命名空间隔离、浏览路径完整,这四点决定了信息模型能否被长期维护和跨系统复用。