State Machine

From LabVIEW Wiki

The state machine is a convenient LabVIEW construct where a case structure is contained with a while loop. Execution of particular cases in the structure is determined by the output from the previous case (or in the instance of the first execution) by the control selector input. The control of the order of case execution is controlled through the use of a shift register. By wiring the output from one case as the determinate 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.

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).

Contents

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.