VI High 50 - How to Implement a State Machine in LabVIEW
Last episode we were heavy in theory and looked at a demo, this time we’re actually programming the state machine, complete with a type defined enum for the states.
You can also keep up with us at:
Experience level: Basic
Hey, I’ve been waiting for you. Ok, let’s get started.
In our last episode, we saw how the state machine addressed our simple lab test application and we showed the completed code. Now, let’s go ahead and build it. For simplicity’s sake, I’m going to keep it in the same LabVIEW project, so that I can use all these subVIs and just make a new main level VI.
Head to the block diagram, and let’s build the infrastructure for the state machine. As we said in the last episode, we’ll want a while loop with a case structure inside, a shift register, and we also want an enum constant, which is found in our numeric palette: Enum Constant.
I’m going to right click on it, and I’m going to make this a type def. Avery good idea to always make a type def of the enum constant controlling the states of our state machine. So I just go to Make Type Def, like that. Right click, open the type def, and I’ll save it as ‘states type def’. And I’ll right click and edit the items in here. So I’ll write the states here. Enter between each one, and then hit ‘OK’. And I can drop them down and see the five states that I created. Save the type def, close it, and now this little glyph in the upper left indicates that it’s a type def. And the tip strip also tells me that. Very handy. Thanks LabVIEW.
So wire this into the shift register, and from the shift register, into the case selection terminal of the case structure. And the first two cases have been assigned: Init and Idle. So we’ll first go to our Init state, which is our default, and from here, I’ll go my project and I’ll just pull out the Initialize subVI. And then I want to make a copy of my enum, which contains my states, and wire that to the right shift register. And choose the next state, which in this case is Idle.
We also want to have that status on the front panel, which I’ve done nothing with so far, so let’s put that down. A string indicator. ‘Status’. And we want our two Booleans, one of which is an OK button, which we’ll rename to ‘Basic Test’. Double click on the Boolean text and write the same thing. And then we want a stop button. Now both of these I can remove the labels, and I’m gonna make one of them bigger, and then highlight them both, and make them the same width and height, and align them across the top, and smash them together. Move them over like that. There we go. That is a beautiful user interface.
Head back to my block diagram. Take ‘Status’ outside of the case structure but still inside the while loop so each case can update the status. Get a string constant and write Init in here. Wire it to the status. We’ll go to our next state: Idle.
In Idle, we’re seeing if the user clicked on the Basic Test and the stop button. So the stop button we can just wire out to the case selector terminal. Okay. And we can also, on our hollow tunnel, right click and use the default if I’m wired because the default in all cases will be ‘False’, which means it won’t stop the loop because the Idle case is the only state where we’re actually checking to see if the user has clicked the stop button. So that works well.
A case structure, and in it, or rather inside of it, not to be confusing, if it’s Basic Test, True, we go to Advanced Test. If, on the other hand, it’s False, we just stay in the Idle state. ‘Idle’. On to our next state.
Add a case after, and we have our Basic Test. Let’s grab our Basic Test subVI, and we used the data coming out of here with an Unbundle by Name to get whether that test is passed. And we use a select function. Incidentally, I could have used a select function here as well. Two ways of doing that.
Make another copy of the enum. Wire it in here. If the test passes, we go onto Advanced Test. And I just realized I made a little error. This should be Basic Test. Thanks for catching that, Brian. There we go.
Advanced Test, if the test passes. If the test fails, we notify the user. Cue the tunnel, move this whole thing down because we like straight wires. ‘Basic Test’. And finally, add the last case, Advanced Test, grab the Advanced Test subVI, and we don’t actually take the data out of this one. We just perform it and then always go to the Notify. ‘Advanced Test’.
Back to Notify, or to Notify, and we make our final case. And once we’ve notified, we go back to the Idle state. We also want to include some timing in here. How fast are we moving between states? Now, there’s a few ways we can do this, but we’re doing this really simply, so I’m just going to use a Wait Function and say it takes one second per state. Now there are better ways to do this: employing execution timing and software control timing, which we can talk about later. But for now, we have our five cases, which are states, and we’ll go run it.
I run it, and we first go to the Initialize state, and on to Idle, where we’re waiting. I click on Basic Test, we go to Basic Test, then back to Notify, which means the test fails. Now how do I know that? Well, obviously we had a False here, to come out of Notify, but if I go into Basic Test, we’ll see that it’s actually really simple, nothing much on the block diagram, and the data out is a pass to False. So that will always come out as False passing the test.
Now, it’s a good idea to test the functionality of a pass as well, so that’s pretty easy. I can just go to this block diagram of Basic Test and use a Bundle by Name. Go to the Boolean, which is whether it’s passed, and write a ‘True’. Okay.
Now let’s run it, Basic Test, on to Advanced Test, and back to Notify, and back to Idle. Perfect. Now we’ve gone over a lot here, from the infrastructure of a state machine, to programming this particular lab test application. But there’s a lot we didn’t go over, like the Notify state, what we’ll notify the user of. If both tests pass, if one test fails and the other passed, how does it know that?
Well, we can take a look at that in future episodes when we take a look at error handling, and passing the data between states. So come on back next time, and also, check out our full LabVIEW course, of which this is an excerpt, at sixclear.com/labview-training.