State Machine

From LabVIEW Wiki
Jump to: navigation, search

The State Machine is one of the fundamental design patterns in LabVIEW. State machines are used to implement complex decision-making algorithms represented by state diagrams or flow charts. State machines are used in applications where distinguishable states exist. Each state can lead to one or multiple states, and can also end the process flow.

State machines consists of a case structure contained in a while loop. The first state executed is determined by the input to the case selector. User input or in-state calculations determines which state to transition to next. The transition to the next state to execute is controlled through the use of a shift register. By wiring the output from one case to the subsequent case (wiring to the shift register on the right hand side) and wiring the input to the case selector from the left hand side shift register, operations can be ordered according to which state is executed.


Simple State Machine.png

The state machine has the advantage of allowing several steps to be linked in series so that each individual step can be executed (or debugged) easily. The trap for the inexperienced programmer is the use of the state machine to step in a haphazard fashion through the cases in the loop. This can lead to complicated pathways through the state machine reminiscent of convoluted goto statements in conventional text based languages. However state machines are a valuable tool and can be used very effectively with this in mind.

State machines can be based around integers, strings or enumerated types. The relative merits of each have been discussed in detail elsewhere. In summary an enumerated type state machine has the advantage of being automatically updated when the enum is changed (if the enum is a Type Definition) but has the disadvantage of requiring careful checking of all the code if new states (enums) are added or redundant states deleted. A string state machine has the advantage of easily added or removed states, but has the disadvantage of spelling mistakes causing programming errors (Note: this can be reduced by including the "Default" state showing the misspelled case in a pop up dialog box, as seen below).
String Based State Machine Default Case.png

Controlling Order of State Execution

There are three possible ways to order a LabVIEW state machine. The first and easiest method (although NOT recommended) is to use an integer. The integer output from one case is wired as the selector for the subsequent case. The disadvantage of this method is that the numbers themselves are not very helpful in tracking through the code and the case selector becomes somewhat meaningless. Either of the following methods are preferred and there are pros and cons for each of them. Debate (strong at times) arises on the list quite frequently as to the best of these methods, but in practice either will work very nicely.

The second method is to use a string as the case selector. With the correct choice of string states, this has the advantage of labeling each case so that your state machine becomes self documenting. A further advantage of this method is that all cases need not be written in the first instance and it is somewhat easier to include new states should the need arise (especially in earlier versions of LabVIEW (< 6.0)). The disadvantage is that it is easy to misspell a state and have the state machine buggy because of his. An easy way to overcome this disadvantage is to include a default case that pops up a warning including the spelling of the failed case.

The third method is to use an enumerated type as the case selector. In preference this enum should be a Type Definition so that changes to the states are reflected easily and transparently when new states are added to the enum (via the LabVIEW auto update from Type Definition setting). Note that there are reports where this method causes problems in version of LabVIEW prior to 6.0, because the enum auto updating did not correctly handle newly inserted cases. This method has the advantage of the string method in code documentation, but requires the use of a default case if not all the cases are required to be written when the code is first created.

Passing Data Between States

Data is commonly passed between the states of a state machine using a Shift Register, similar to how the state variable is passed between states. It is a common practice to use a single Cluster (preferably a Type Definition) to hold all the data in a single Shift Register, rather than multiple shift registers for multiple data elements.

Variations

Sequencer Pattern

The Sequencer Pattern is a variation of the State Machine. Instead of a state leading to one or multiple states, the sequencer states are hard-coded in an array which dictates the order of execution. Only a state producing an error changes the sequence of operation by stopping the state machine. A state can be executed more than once by including it in multiple places in the hard-coded state array. See more on the Sequencer Pattern.

VI Scripting Pattern

The VI Scripting Pattern is a variation of the State Machine design specifically for writing VI Scripting code. It uses an enum as the definition of the sequence of events in which to traverse incrementing through the enum for each state. Therefore the sequence of state execution is hard-coded. The VI Scripting Pattern will not repeat a state due to an enum not being able to have two entries of the same name unless two enum values are used for the same state. An error occurring in any state will cause the state machine to end. See more on the VI Scripting Pattern.

Natt Sequence Pattern

The Natt Sequence is a mini-pattern used for executing LabVIEW code sequentially. It has multiple benefits over other sequential code constructs (like the Flat Sequence, the Stacked Sequence, or the Sequence Loop), including:

  • Self-documenting via the sequence enum
  • No extra tooling required, just edit the sequence enum to add/remove/modify/rearrange sequence steps
  • Code breakage when the case structure doesn't have frames for all steps defined in the sequence enum
  • Minimal extra code
  • Shift registers to share data between sequence steps
  • Optional early break with For Loop conditional terminal

The Natt Sequence template VI and its supporting VIM can be used in LabVIEW 2017 SP1 and later. See more on the Natt Sequence

Uses

More to Come

See Also

External Links