Anleitung
Zustandsautomaten
Endliche Zustandsautomaten im Server über Enumerationen und Attribute definieren und ihre Zustände zur Laufzeit wechseln.
Anleitung
Zustandsautomaten
Beteiligte TypenOpcFiniteStateMachineNodeOpcStateMachineStatesAttributeOpcStateMachineTransitionAttributeOpcStateMachineTransitionsAttributeOpcStateMachineInitialStateAttribute
Viele Informationsmodelle beschreiben den Zustand einer Maschine oder eines Ablaufs über einen endlichen Zustandsautomaten (FiniteStateMachineType gemäß OPC UA Teil 16). Ein solcher Automat kennt eine feste Menge von Zuständen (engl. states) und die erlaubten Übergänge (engl. transitions) zwischen ihnen. Seinen aktuellen Zustand stellt er über die Kind-Nodes CurrentState und LastTransition bereit, die Clients lesen und abonnieren können. Im Server definieren Sie einen solchen Automaten über die Klasse OpcFiniteStateMachineNode<T>.
Zustände definieren
Die Zustände legen Sie über eine Enumeration fest. Der Wert eines Eintrags ist die Nummer des Zustands, sein Name der Name des Zustands:
public enum MachineState : uint
{
Stopped = 0,
Starting = 1,
Running = 2,
Stopping = 3
}Public Enum MachineState As UInteger
Stopped = 0
Starting = 1
Running = 2
Stopping = 3
End EnumZustandsautomat-Klasse definieren
Den Zustandsautomaten selbst definieren Sie als Unterklasse der Klasse OpcFiniteStateMachineNode<T> und beschreiben ihn über Attribute:
OpcStateMachineStateslegt die Enumeration der Zustände fest.OpcStateMachineTransitionlegt je einen erlaubten Übergang von einem Zustand in einen anderen fest.OpcStateMachineInitialStatelegt den Zustand fest, den der Automat beim Anlegen im Adressraum einnimmt. Ohne dieses Attribut nimmt er den ersten seiner Zustände ein.
[OpcStateMachineStates(typeof(MachineState))]
[OpcStateMachineTransition(MachineState.Stopped, MachineState.Starting)]
[OpcStateMachineTransition(MachineState.Starting, MachineState.Running)]
[OpcStateMachineTransition(MachineState.Running, MachineState.Stopping)]
[OpcStateMachineTransition(MachineState.Stopping, MachineState.Stopped)]
[OpcStateMachineInitialState(MachineState.Stopped)]
public class MachineStateMachineNode : OpcFiniteStateMachineNode<MachineState>
{
public MachineStateMachineNode(IOpcNode parent, OpcName name)
: base(parent, name)
{
}
}<OpcStateMachineStates(GetType(MachineState))>
<OpcStateMachineTransition(MachineState.Stopped, MachineState.Starting)>
<OpcStateMachineTransition(MachineState.Starting, MachineState.Running)>
<OpcStateMachineTransition(MachineState.Running, MachineState.Stopping)>
<OpcStateMachineTransition(MachineState.Stopping, MachineState.Stopped)>
<OpcStateMachineInitialState(MachineState.Stopped)>
Public Class MachineStateMachineNode
Inherits OpcFiniteStateMachineNode(Of MachineState)
Public Sub New(ByVal parent As IOpcNode, ByVal name As OpcName)
MyBase.New(parent, name)
End Sub
End ClassWenn die Zustände in der Reihenfolge der Enumeration aufeinander folgen, genügt statt der einzelnen Übergänge das Attribut OpcStateMachineTransitions. Es legt die Übergänge von jedem Zustand zum nächsten fest, mit IsLoop zudem den Übergang vom letzten zum ersten Zustand:
// Transitions from each state to the next one and from the last state to the first one.
[OpcStateMachineStates(typeof(MachineState))]
[OpcStateMachineTransitions(typeof(MachineState), IsLoop = true)]
public class MachineCycleNode : OpcFiniteStateMachineNode<MachineState>
{
public MachineCycleNode(IOpcNode parent, OpcName name)
: base(parent, name)
{
}
}'Transitions from each state to the next one and from the last state to the first one.
<OpcStateMachineStates(GetType(MachineState))>
<OpcStateMachineTransitions(GetType(MachineState), IsLoop:=True)>
Public Class MachineCycleNode
Inherits OpcFiniteStateMachineNode(Of MachineState)
Public Sub New(ByVal parent As IOpcNode, ByVal name As OpcName)
MyBase.New(parent, name)
End Sub
End ClassZustandsautomat im Adressraum anlegen
Den Zustandsautomaten legen Sie wie jeden anderen Node im Node-Manager an, zum Beispiel als Kind-Node der Maschine, deren Zustand er beschreibt:
// MyNodeManager.CreateNodes(...)
var machineNode = new OpcObjectNode(new OpcName("Machine", this.DefaultNamespaceIndex));
var machineStateNode = new MachineStateMachineNode(machineNode, "State");'MyNodeManager.CreateNodes(...)
Dim machineNode = New OpcObjectNode(New OpcName("Machine", Me.DefaultNamespaceIndex))
Dim machineStateNode = New MachineStateMachineNode(machineNode, "State")Zustand wechseln
Den Zustand wechseln Sie über die Methode ChangeStateTo. Sie übernimmt die Änderung und informiert alle Clients, die den Zustand abonniert haben. Wenn es keinen Übergang vom aktuellen in den gewünschten Zustand gibt, löst die Methode eine InvalidOperationException aus. Ob ein Wechsel erlaubt ist, ermittelt vorab die Methode CanChangeStateTo. Wenn der Automat bereits im gewünschten Zustand ist, bleibt der Aufruf ohne Wirkung:
if (machineStateNode.CanChangeStateTo(server.SystemContext, MachineState.Starting))
machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Starting);
// Throws an InvalidOperationException, because there is no transition
// from the state Starting to the state Stopped.
machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Stopped);If machineStateNode.CanChangeStateTo(server.SystemContext, MachineState.Starting) Then
machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Starting)
End If
'Throws an InvalidOperationException, because there is no transition
'from the state Starting to the state Stopped.
machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Stopped)Den aktuellen Zustand liefert die Eigenschaft CurrentState, den zuletzt ausgeführten Übergang die Eigenschaft LastTransition. Wenn ein Automat aus einem Informationsmodell den Kind-Node CurrentState nicht unterstützt, kann eine Unterklasse das über die Eigenschaft SupportsCurrentState angeben. Zustandswechsel bleiben dann ohne Wirkung.

