在OPC UA中,最重要的节点类别是对象,变量和方法。
节点类别为对象的节点用于(构成)地址空间结构。
节点类别为变量的节点代表一个值。
节点类别为方法的节点,代表服务器中一个由客户端调用并返回结果的方法。
如图,是一个对象包含对象、变量、方法和生成事件的概念。
当不止存在一个电机时,则需要定义一个复杂的对象类型,通过实例化对象类型来产生具有共同属性的电机对象。
那么上图中的Motor对象,则可使用HasTypeDefinition引用,指向MotorType对象类型,通过实例化,产生多个电机。此时MotorType对象类型变成了一个自定义的类型节点,但MotorType下的对象、方法和变量,仍旧还是继承自基本节点类型。
小结
在地址空间中创建节点,实际就是操作基本节点类,从对象类型节点,变量类型节点继承,并修改属性,得到对象和变量节点。然后指定节点间的引用,来指定各节点间的关系,以及组织节点在地址空间中的结构。
对于复杂的对象,可以在基本对象类型的基础上创建复杂的对象类型。与创建对象类似,复杂基本类型下包含其他基本的或自定义的类型节点。再通过实例化,产生所需的复杂对象。
一个对象节点,是具有实际意义的,它可以映射到现实中的一个设备,而对象类型,并不具有与实物的映射关系,类似于一种概念模型,可以描述设备,但不能代表设备。对象类型中设定的数值,会被继承到对象中去,作为初始值。
如第一张图(变量,类型和方法)中所示,Motor对象下的节点,其节点类别都是对象、变量或方法,这些节点都是实例而不是类型。而第二张图(复杂对象类型及其继承)中所示的MotorType对象下的节点,是不具有真正的实际值的实例,被称为实例声明。
实例声明是命名的实体,用来定义复杂的对象类型。通常实例声明被定义为对象类型下的变量,对象和方法。更专业的定义是:实例声明是被对象类型通过正向层次引用,直接引用的节点或者通过另一个实例声明间接地引用的节点。
实例声明的特点是,相对对象类型,实例声明需要被唯一的标识。NodeId不能用于这一目的,因为实例声明通常与其在实例上的对应部分是不同的节点,NodeId也就不同。可以使用浏览名称替代,对间接引用的实例声明,则使用浏览路径。
(客户从对象类型开始,顺着层次化引用前进,检测实例声明的浏览路径。达到目标实例声明之前,添加每一个节点的浏览名称)
简言之,实例是从类型定义节点实例化来的对象,变量和方法,具有实际意义(可认为是映射到具象事物)。实例声明是类型定义节点下的对象,变量和方法,是一种不具有实际值的实例。
类型定义(对象类型或变量类型)引用的每一个实例,如果它有建模规则,它就成了实例声明。建模规则指定了关于对象类型的实例会怎么处理该实例声明。
简言之,建模规则就是实例声明到实例过程中的实例化规则。
建模规则有三种选择,也称为建模规则的命名规则:
建模规则使用ModellingRule类型的对象表示,每个ModellingRule有一个变量NamingRule(建模规则的命名规则)。
实例声明通过HasModellingRule引用类型引用一个ModellingRule对象来指定建模规则,如下图所示:
可选的和强制的建模规则并不指定当创建类型定义的新实例时,服务器如何处理实例声明。它可以为该实例创造新的节点,或只是引用现有的节点。类型定义的实例只需要引用一个具有相同浏览路径的相同类型的实例。在服务器运行时,节点可以改变,只要保证对该类型的每一个实例,始终有一个正确的浏览名称和类型的节点存在。
如下图,Address1中的创建了AddressType中全部实例声明的实例;Address2中只创建了引用Mandatory规则的实例声明的实例。在Address3和Address4中,共用了一个City,但是在两个对象中都存在与类型定义中相同的浏览路径,以及相同类型的实例声明的实例(即City),所有都是正确的。
Address1中的两个实例都有建模规则,只要它们不被其他类型定义引用(作为其他类型定义下的实例声明),它们就不是实例声明。Address3和Address4共用的City实例,当删除Address3时,Street必须被删除,但不能删除共用的City,它仍被Address4使用着。
一般建模规则可以改变,但命名规则必须保持不变。唯一例外的是,可选的可以被替换成强制,即允许建模规则被替换成约束更为严格的
一种复杂建模规则的例子
包含两种情况:
全继承层次结构如下图:
一般最好使用单一继承来简化地址空间
对于复杂建模,存在多个路径引用,要考虑两方面的问题:
作为约束的建模规则
存在另一种实例声明,用来定义对规则的约束,在它们的建模规则里,称有命名规则约束(NameingRuleConstraint)。
OPC UA规范中唯一定义了约束的建模规则叫做暴露内部数组(ExposesItsArray),可以被包含数组数据类型的变量类型使用,语义是数组内的每一项也可以作为一个子变量来暴露。
复杂类型被子类型化时,父类型的基本特性需要满足,因此强制的实例声明必须在每个子类型的实例上都可用,父类型的约束在子类型都旅行,并且只能进一步加以限制(即,可选的实例声明可以在子类型变成强制的,但强制的实例声明不能在子类型变成可选的)。
复杂类型的子类型化,一般有两种方式:
另外,实例完全继承的实例声明,所有实例声明必须有唯一的浏览路径(即子类型不能为不同实例声明使用同一浏览路径),不过子类型能够覆盖父类型现有的实例声明(如更严格的建模规则)
父级概念 ModelParent
一个节点可能被多个节点共享,例如一个静态类变量包含了所有实例相同的值。客户只是读取该节点数据,不关心节点是不是共享的。但是当客户准备变更节点时,客户端最好知道节点在什么范围内可以被改变。(否则其他所有引用了该节点的节点都会发生改变,而这些改变对其他节点来说是不应发生的)
OPC UA的HasModelParent引用从被包含的节点指向定义其范围的父节点,用于指示客户更改的范围,这样就不会影响其他实例。
上图左边,两个Device实例共享一个特性Icon(指向同一个节点),如果为其中一个实例对象如Device1更改图标,这会影响到类型定义以及其他实例对象如Device2.
为了避免这种问题,可以创建一个新的Icon,如在上图右边为Device2引用了新图标,这样就可以控制变化只发生在Device2中,当修改Device2下的Icon特性时,不会影响Device1.
如有错误,欢迎指正 [email protected]