The State Machine is one of the fundamental architectures LabVIEW developers frequently use to build applications quickly. State Machine architecture can be used to implement complex decision-making algorithms represented by state diagrams or flow charts. A state machine can be implemented using innate LabVIEW functions; no additional toolkits or modules are required for the architecture.
This article walks through what a state machine is, example use cases, some conceptual examples of a state machine, and walking through code example of a state machine.
A state machine is a programming architecture that allows dynamic flow to states depending on values from previous states or user inputs.
This architecture is suitable for applications that can be described as a combination of:
A state can be defined as the status within the program while accomplishing the overall task of the program; examples of states may be initializing, waiting, running a calculation, checking status, etc.
Logical statement help determine when to move to a new state and what state to move to. Events can be used to trigger moving from one state to the next; these can be programmatic events or user-defined, like pressing a button.
Each state in a State Machine does something unique and calls other states. State communication depends on some condition or sequence. To translate the state diagram into a LabVIEW programming architecture, you need the following infrastructure:
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. A State Machine relies on user input or in-state calculation to determine which state to go to next. Many applications require an “initialize” state, followed by a default state where many different actions can be performed. The actions performed can depend on previous and current inputs as well as states. A “shutdown” state can then be used to perform clean up actions.
Besides its powerful ability to implement decision-making algorithms, state machines are also functional forms of application planning. As the complexity of applications grow, so does the need for adequate design. State diagrams and flowcharts are useful and sometimes essential for the design process. Not only are State Machines advantageous in application planning, they are also easy to create.
For example, the following applications can benefit from the state machine pattern:
There is another design pattern that can be used to implement a user interface, the Queued Message Handler. A Queued Message Handler is a more sophisticated version of the State Machine and offers additional flexibility, but it also adds additional complexity.
Creating an effective State Machine requires the designer to (1) make a list of possible states. With this list, the designer can (2) plan how each state is related to another. Then, the state diagram can (3) be translated to LabVIEW graphical programming architecture.
In this example, we want to generate an application that fires a cannon continuously without allowing it to get dangerously hot.
(1) List Possible States
To begin, we make a list of all possible states for our task. To accomplish the task of continuously fire the cannon will need to:
(2) Map States’ Relationships in a State Diagram
Next, we will consider how these states are related to each other and create a state diagram. When creating the state diagram, consider what would cause the program to move from one stat to the next – is it an automatic transition? Is there an external trigger from the user? Is the transition based on the outcome of a calculation?
For example, let’s consider the relationships between the initialization state and other states.
Notice that while thinking through how states relate to one another, we have started to define the logic for moving between these states. The programming logic that we will use in code depends on (1) the number of possible transition states, and (2) the number of inputs being considered in the logic. Options for code transition are discussed below in the Transition Code Examples section.
Continue working through how the states relate to one another until you have a full state diagram. The state diagram will include all states and the relationship between them (Figure 1). Notice that in this diagram, the states (oval nodes) describe the actions that are performed when the control process is in that state, whereas the transitions (arrows) simply describe when and how the process can move from one state to another.
Figure 1: State Diagram of Firing a Cannon
The relationship between each state will help you in programming the logic needed to move from one state to the next.
(3) Build a State Machine in LabVIEW
After defining the states and their relationship in a state diagram, you can translate this to coding architecture in LabVIEW (Figure 2). The flow between states of the state diagram (Figure1) is implemented by the loop. The individual states are replaced by cases in the case structure. Each state in the diagram above corresponds to a subdiagram of the Case Structure. Each state:
A shift register on the while loop keeps track of the current state, which is fed into the case structure input.
Figure 2: State Machine
Refer to the Single Shot Measurement sample project, available from the Create Project dialog box, for an example of adapting this template to a measurement application.
1. Shutdown code runs only when the user wants to stop the application.
2. Shutdown code always runs to completion.
Consult the Modify the Simple State Machine LabVIEW Template tutorial for how to get started with.
Before you customize the template, ask yourself the following questions:
There are different methods to determine which state to transition to next, discussed below.
Note that while the examples images show the “Init” state, these transition possibilities could apply to any state.
One-to-one: If you always transition from State A to State B, there is no need to program any logic, just output the name of the next case (Case B) of to the shift register.
Figure 3a: Only One Possible Transition State
One-to-two: If you could transition from State A to State B or State C, you can use a Select function to assess the status of an indicator. You should assess something that determines which State you want to move to. For example, in Figure 3b we see that the user input of the Stop Button determines whether we move from the Power Up state or proceed to Shut Down.
Figure 3b: Two Possible Transition States
One-to-multiple using Arrays: If you have multiple states that you could transition to, you could use a Boolean area associated with an enum constant to program the transition. For example, in Figure 3c, some code is conducted where the outcome of the code determines the transition, the output of which is an array of Booleans. The Boolean array correlates with an Enum constant which contains a list of possible states that could be transitioned to. Using the Index Array function, the index of the first “True” Boolean in the Boolean array is output. Then, using the Array Subset function, you can pull out the appropriate from the Enum constant it correlates with.
Tip: Recall that arrays are 0-indexed and Enums are 1-indexed. To correlate the Boolean Array with the Enum constant, use the Increment function to correct that offset.
One-to-multiple using While Loop: Another option if you have multiple possible transition states is to use a while loop inside of a case. The code inside of the while loop will continue until a Boolean status is set to true, triggering the stop button. This will effectively allow code to run until a triggering event occurs.
Figure 3d demonstrates an “Init” state using an inner loop and case structure to transition to the next state. The inner case structure contains one diagram for each transition that leaves the current state. Each of the cases in the inner case structure has two outputs – a Boolean value, which specifies whether or not the transition should be taken, and an enumerated constant, which specifies the state to which the transition goes. By using the loop index as an input to the case structure, this code effectively runs through each transition case one by one, until it finds a diagram with a “True” Boolean output. After the “True” Boolean output is found, the case outputs the new state to which the transition goes. Though this method may appear slightly more complicated than the previous methods, it does offer the ability to add names to transitions by “casting” the output of the loop index to an enumerated type. This benefit allows you to add “automatic documentation” to your transition code.
Problem: The hardest part of creating a State Machine is to differentiate between possible states in the state diagram. For example, in the Coke Machine state diagram (Fig.4), we could have had 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 cent states rather than having a “wait for response” state that goes from one state to another depending on which type of coin is dropped. That would create 11 different states with the exact same case diagram. Redundant code can create a big problem in a larger application.
Solution: If different states have the same case diagram, try to combine them into one state. For example, the “wait for response” state is created to avoid code redundancy.
Problem: Enums are widely used as case selectors in State Machines. If the user attempts to add or delete a state from this enum, the remaining connected wires to the copies of this enum will break. This is one of the most common obstacles when implementing State Machines with enums.
Solution: Two possible solutions to this problem are:
1. If all the enums are copied from the changed enum, the breaks will disappear.
2. Create a new control with the enum, and select “typedef” from the submenu. By selecting typedef, all of the enum copies will be automatically updated if user adds or removes a state.
If you are interested in learning more about State Machines and other advanced architectures in LabVIEW, consider taking the LabVIEW Core 2 customer education course.