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:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)

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.

(end transcription)

VI High 49 - How to Use State Programming and State Machines in LabVIEW

Last time around we asked for ideas on our next series. A bunch of folks signalled louder than Gilligan’s Island castaways during a flyby: State Machines. We’re glad to drop relief bundles of wisdom on state vs. sequential programming, state transition diagrams, and state machine infrastructure.

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)

Hey, I’ve been waiting for you. Ok, let’s get started.

Last time around we asked for ideas on our next series. A bunch of folks signalled louder than Gilligan’s Island castaways during a flyby: State Machines. We’re glad to drop relief bundles of wisdom on state vs. sequential programming, state transition diagrams, and state machine infrastructure.When we ended our File I/O and API Error Handling section, we asked, “what do you want to hear about next?” And you said ‘State Machines’. So here we go.

Now suppose we want to perform a couple of lab tests: a basic test, an advanced test, and then notify the user. How can we program this? Well, it could look like this, where we have four separate subVIs connected by the error clusters, and data being passed between subVIs. We can generalize these steps into states. By definition, ‘A state is a unique configuration of information in a program; it generally performs a test or satisfies a condition’.

Now, we could program this application sequentially, but then we would always need to go in the same order. But what if we wanted to change the order on the fly during runtime? Or stop the code at any time instead of waiting until the end? Or repeat the same step multiple times? Or execute some code only if a certain condition is met? Now, these are difficult or impossible to do with sequential programming, but all really easy with state programming.

We start state programming with a state transition diagram, or state diagram. It represents states and transitions between them. By definition, a transition is a condition that is satisfied when moving between states. Let’s take a look here at that lab test application.

We start here, and we go to the ‘Initialize’ state, and then moving on to the ‘Idle’ state. In the ‘Idle’ state, we’re waiting on the user to do something. The user has two options: either click on ‘Basic Test’ or ‘Stop’. If ‘Basic Test’ is clicked, we go and perform ‘Basic Test’. If that test passes, we go on to the ‘Advanced Test’. But if the test fails, we go to ‘Notify’. If we go onto ‘Advanced Test’, then we’ll always go to ‘Notify’ when we’re finished, and then we always go back to ‘Idle’. And the user can then either click on ‘Basic Test’ again or click the ‘Stop’ button and stop the application.

We always begin in this design phase, and then we go and implement in LabVIEW code with the state machine. So let’s look at it.

I’ll hit the ‘Run’ button, and we see we’ve gone from ‘Initialize’ to ‘Idle’, and if I click on ‘Basic Test’, we move to the ‘Basic Test’, and then ‘Notify’, because it looks like the ‘Basic Test’ failed. Let’s see how this is implemented on the block diagram.

Here’s the infrastructure of a state machine. We have a while loop, with a case structure inside, a shift register with the output of the shift register going to the case selector terminal of the case structure, and we also have this, which is an enum constant.

So to begin with, we initialize the first state of the state machine. In this case, ‘Initialize’. ‘Initialize’ passes in here, and we choose the initialized state, where we are executing the code for ‘Initialize’. When we’re finished, the state machine tells us where we’ll go next: in this case: ‘Idle’. ‘Idle’ will go out of this case to the right shift register; we iterate the loop; and the next iteration, it comes out of the left shift register, and the enum chooses the next state, which is ‘Idle’.

In ‘Idle’, as we see, we’re polling the ‘Basic Test’ Boolean and the ‘Stop’ Boolean. Now in both cases, you see we’re also updating the status on the front panel, so the user knows what state we’re in. Just with a string, ‘Idle’ or ‘Initialize’.

Now, if the user in the ‘Idle’ state does not click on the ‘Basic Test’ button, then we stay in the ‘Idle’ state. ‘Idle’ goes out to the right shift register; iterate, comes out the left; we stay here, and check again. We’re also polling that ‘Stop’ button to see if it’s been pressed. If, on the other hand, the user clicks on the ‘Basic Test’ button, we go to ‘Basic Test’. Goes into the right shift register; comes out the left; and we call the ‘Basic Test’ subVI. As we saw in our state transition diagram, in ‘Basic Test’, we’re checking to see if the test has passed: pass or fail.

So, coming from ‘Basic Test’ will be data here indicating whether the test has passed or not. If the test passed, ‘Advanced Test’ passes out of our select function and chooses the next state. If we fail, we go to ‘Notify, just as we see in our state transition diagram. Pass: go to ‘Advanced Test’. Fail: go to ‘Notify’.

Going to ‘Advanced Test’, we see we just perform that test and always go to ‘Notify’. In the ‘Notify’, we just call the ‘Notify’ subVI. And back to ‘Idle’, where we wait on our user to tell us what to do next.

That’s our overview of state machines, and this particular lab test application addressed with a state machine. Next time, we’re going to actually build the state machine to do this. And just to note, this state machine section is taken right out of our Lucid LabVIEW Fundamentals 1 course; right at the end, in application programming.

To find out more about the course, go to sixclear.com/labview-training.

(end transcription)

VI High 48: How to Use the Error Cluster to Control Execution Order and Dataflow in LabVIEW

This is final episode in our error handling series. We talk about using the error cluster, not only to handle errors, but also to control execution order on the calling VI. If you have suggestions on new topics, just contact us!

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)


Hey, I’ve been waiting for you. Ok, let’s get started.

Last episode, we looked at making an error handler by conditionally executing code based on an error and then making a subVI out of that. Here it is. And we contrasted that with the default action of most native LabVIEW VIs and functions which is to only execute their code in the case of ‘No Error’. And I also said that in a lot of cases, we may want to execute code regardless of an error. So, in this case, if I wanted to change this ‘Compare Two Paths’ to a VI that executed regardless of an error, it’s pretty simple. I can just right-click and ‘Remove the Case Structure’. I’ll delete the stuff in the error case, since there’s nothing really in there, and there we go. But we still like to keep the error cluster going through because we can use it to control the program flow on the calling VI, which is the File IO.

Now, of course, I’m not going to save this, the changes I made. I’ll delete it from here, so I don’t forget that. But if we have an ‘error in’ and ‘error out’ on the VI, regardless of if we use it under the hood, it’s still very valuable to control the data flow. Now what do I mean? Well, you can go back to VI High 9 and 10 for a full discussion on error flow, but in brief review, a node is any block diagram object connected by wires that performs an operation when called by LabVIEW and a node executes when data at all inputs is received, and data is supplied at outputs when the node finishes execution.

Now, that’s valuable because any VI or function that has the error cluster as an input won’t execute until it receives the error cluster from the previously executing VI. Which means that the execution order of this chain of functions occurs because each function is waiting on the inputs from the previously executed function. And even if we didn’t have the file reference to share between these, the error cluster still acts as an excellent way of deciding which goes first.

And that’s especially valuable between different sets of functions which don’t share other types of inputs. These functions obviously share the file reference, but what if I wanted to open up a file, and then also go and do some DAQmx programming? Well, no problem. I can make sure that the DAQmx programming starts after the File IO programming by just using the same error cluster. There we go.

The error cluster is the grand unifying input and output for most VIs and functions. So across APIs, modules, toolkits, and drivers that you use, the error cluster can be used to control that execution order. Even if we don’t use it under the hood to actually handle errors. So bottom line, whenever you see the error cluster available, link it up. You can almost never go wrong.

That completes our discussion on error handling. Hope you liked it. We’ll start something new. Want to suggest something? Go ahead and just comment on any episode, or subscribe to us and send us a message. We’d love to hear from you. Thanks!

(end transcription)

VI High 47: Learn How to Create Error Handlers and Implement Error Handling in LabVIEW

In this episode, we see how to conditionally execute code based on an error. We do it in a single VI, but then also make a subVI of the new code and create an error handler. We see how native LabVIEW VIs and functions handle errors under the hood, and then chat about best practices for error handling.

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)
In our last episode, we looked at the error handler. And also what happens when a standard LabVIEW VI or function sees an incoming error. It just passes it along while not executing its default action. Today, we’ll use that error cluster to gain even more control over our application. Let’s say I want to do this. If an error occurred, I want a big LED to go off on the front panel alerting me to the error. So I’ll grab an LED; let’s make it square. I’ll make it bigger, go to the properties, and change my color. ‘On’ will be bright red. ‘Off’ will be a muted kind of red. There we go.

Now, here’s my terminal. How do I make it go off in the case of an error? Well, an error cluster is a cluster first of all, so we can always unbundle the contents of a cluster. I’ll go to my Cluster, Class, and Variant palette and pull out Unbundle By Name. I’ll just put it over here and wire the error cluster into the Unbundle By Name. I get out the status. I can also access the code or source, but status is what I want. It’s the green Boolean. Yes or no an error has occurred. So I’ll just wire that in there. So, let’s try it.

I’ll run it. Yes, the error occurred. Let’s double check and put a zero in here, so that there’s no error. Run it. Indeed, no error occurs. Okay. Let’s go a step further. Let’s say I want a custom dialog box to pop up whenever an error has occurred. How would I do that? Well, a custom dialog box is found over here. Maybe this One Button Dialog; that’ll work. So how do I get this to execute in the case of an error? Well, I’ll probably need a case structure. So let’s collapse this down a bit, get it all in one screen.

And I can get rid of this Boolean, and I’ll need a message. There we go. Appropriate gravitas. So I’ll pull this guy over here, and if I want him to run in the case of an error, you’ve got it. Just a case structure. And wire the status right into here. Let’s try it. Once again, I’m going to run it without an error. No dialog box. With the error, -2. There’s the dialog box.

We can go a step further here and just use the polymorphic nature of our case structure and not even have to unbundle this. I can delete this, wire this right into the case selector terminal, and look what happens. I get two cases: ‘No Error’ and ‘Error’. Now, you see that LabVIEW actually took the default case as ‘No Error’, but I want this to pop up in the case of an ‘Error’, so I can right click on it: “Make This Case Error”. There we go. Straighten that wire out a bit, and that’ll behave the same way.

Now, we did something very simple, just this dialog box, but you can imagine, I can now put anything in here. Maybe I need to flip a relay to turn something off in the case of an error. I’ll just put it in there. Maybe I’m originally communicating with a certain port on my computer, and I get an error saying that it’s in use. In here could be the code to change that port and try something new. In essence, we’re branching off from our default operation and doing something different in the case of an error. Now, what if I were to go and make just a SubVI of this, so that this code executes whenever an error has occurred in a variety of situations, maybe not just right here.

Well, a quick and easy way to make this a subVI, click and drag to select all of this, then go to ‘Edit’, ‘Create SubVI’. And there we go. There’s our new SubVI. I open it up. The error cluster of course is assigned, and on the block diagram, there’s our code. Does this work just as well? Sure does.

And now, I can go and take this SubVI and use it wherever I want. So what I’ve just created is an error handler. The code in here will execute in the case of an error, but only in the case of an error. That’s what we want. I mentioned earlier, though, that native LabVIEW VIs and functions don’t execute their default action whenever they see an incoming error, which is of course the opposite of what’s happening here. So let’s actually take a look at a default LabVIEW VI and see what’s happening under the hood. We don’t have to look far. We can go back to our Advanced File Functions palette, and I’ll grab this Compare Two Paths VI. So I’ll double-click, open up its front panel, and go to its block diagram. Let’s take a look.

The very first thing that happens when this VI executes is it looks at the incoming error cluster from the previously executed VI. If no error has occurred, as we see here, we execute everything this VI does, which is Compare Two Paths. But if it sees an incoming error, then it flips over to the error case, and, in essence, nothing occurs. Now, of course this VI executes, but it doesn’t execute its default action. It just passes that error along to the error out, so that the next VI that’s called in the chain will see that error as well. Now, this is a good practice for when we’re building our own VIs. If we’re going to make a subVI of it, and it should only execute in the case of no incoming error, we just wrap the entire code with a case structure and wire in the error cluster and out the other side. But in the case of an error handler, which should execute only in the case of an error, then we want our code in the error case.

And there may be some other VIs that execute their code regardless of an error, in which case on their block diagram, we may not see this case structure at all. But we would typically still see an ‘error in’ and ‘error out’ control data flow on the calling VI. What do I mean by that? Well, we’ll talk about that next time.

So subscribe to us on YouTube, and you’ll know exactly when that’s posted. See you then!

(end transcription)

VI High 46: Learn How to Use the Error Cluster and Error Handling in LabVIEW

We look at a lot of LabVIEW code. Sometimes we see beginning developers not using the error cluster because they just have no idea how it works. Let’s take a look at what’s in the cluster, the difference between manual and automatic error handling, and the behavior of standard LabVIEW VIs and functions when they see an incoming error. This sets us up for a good discussion on error handling.

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)


Last time around, we ended here. Streaming to disk by appending to the end of the file and writing continuously in a loop. And we threw together these error clusters as well. But we really didn’t talk about what they mean. So let’s do that. To begin the discussion, I’m going to simplify things by removing the While Loop, the timing, and all that other stuff used to stream to disk. And keep it simple. And we’ll first remove the error cluster. Bring these in a bit. And write to the text file as before.

Now, we already saw that I can write something like’ text’ to the file, run it, pull it open, and there it is. Runs very smoothly. But let’s gum it up a bit and create an error. How can I do that? Well, with my Context Help, I can see that one of the inputs to the Set File Position is the offset (in bytes). Now, if I leave the ‘from’ input as default, which means from the start, and then go to ‘offset in bytes’ and put in a ‘-2’ bytes, what does that mean? That means I’ll start writing to the file before the beginning of the file, which doesn’t really make sense. So that should generate an error. So let’s try it. And I run it, and indeed, LabVIEW flashes on this function and pops up an error dialog box. ‘Error 4 occurred at Set File Position in File IO.vi’. Possible reason is “End of file encountered.” Well, we know actually that it was the beginning of the file. So close enough.

So continue or stop? I’ll stop. So let’s take a closer look at what just happened. In fact, I’ll put this in Highlight Execution and run it step by step. Our first function executes; no problem. Our next function executes, but before our next function does, we get the error here. In other words, LabVIEW stops this VI and says, “Wait a minute! You can’t go any further. This function has an error.” And it gives me the error. Now do I continue or stop?

What we see here is called automatic error handling. That means LabVIEW will stop the VI whenever an error occurs, right in its tracks, without going further. Now, in some cases, that’s ok. When we’re developing, and we’re testing, and we have an error, then we may want LabVIEW to stop and then tell us what the error is because we as the developer can fix it. However, in a completed application that’s running in production, we never want LabVIEW to just stop on an error. That could be dangerous. Imagine that we’re using LabVIEW to fly a plane, and an error occurs, and LabVIEW just halts. Dangerous. Or we’re doing some combustion tests, and to initialize, we open up a bunch of burners, and flames are flying, and an error occurs before we shut down. Well, that’s dangerous.

So, good examples of where we don’t want LabVIEW to just halt before an error occurs, but we want something to happen. We want LabVIEW to see that an error occurred, and then allow us to do something as a result. That’s the whole idea behind error handling. Practically determining what types of errors can occur, and then planning out a resolution for those. The first step is to move from automatic error handling to what we call manual error handling. In some cases, we might want to go to ‘File’, ‘VI Properties’, ‘Execution’, and then uncheck ‘Enable Automatic Error Handling’. In most cases, the best way to employ manual error handling is to use the Error Cluster. Let’s do that. At the bottom left and right inputs of most functions and VIs, are these error in and error out. Let’s connect them up. And now we’re still going to have an error occur, but let’s watch what happens.

The first function runs, and it says ok, no error occurred. The next function runs, but it outputs along the Error Cluster the error. Let’s watch this next function. It actually executes. And finally at the end, LabVIEW flashes over here and says “Here’s the error. Error 4 occurred at Set File Position in File IO.vi”. This is the same error, but we received the notification at the end of run time instead of where the error occurred. But before we see why that’s so good, let’s take a look at what’s in the Error Cluster.

In fact, I’ll just go ahead and Create an Indicator right here, and on the front panel, I get out the Error Cluster. There are three elements in an Error Cluster. The status Boolean, which indicates whether yes or no, an error occurred. The I32 code which tells us what the error is by its code. And then the source which is a string, which tells us where the error occurred. So if I run this, then we get that error saying ‘yes that error occurred. It’s error 4. And it happened at the “Set File Position” function in the File IO VI.’ Well, this VI is the File IO VI, and this is the Set File Position.

And notice what happened when the error occurred. Again, reemphasize that LabVIEW does not stop here, but instead passes the error along to all subsequent functions and VIs. Now, those functions and VIs do execute, but they don’t execute their default action. In other words, I’m not actually writing to file. If I see an error has previously occurred, I probably don’t want to write to the file. But what it does is it just says, “Oops. I see an incoming error. I’m just going to pass the error along.” And so it executes, but only just to pass the error. It does not execute its default action. That’s true of most native LabVIEW functions and VIs. They don’t execute their default action in the case of an error.

But there are some cases where we’ll want to execute code regardless of an error, and even some cases where we want to execute only in the case of an error. Those VIs that we make to do that are typically called Error Handlers. So if we go back to the combustion test example we gave earlier, we would want our application to see that an error occurred and then shut down safely. So, go down the normal shutdown procedure to turn off the burners and be safe if an error occurs. Or, in the case of flying the plane, if an error occurs, we may want an error handler to come in and see what the error is and try and fix it, so we don’t crash.

But again, the default action of most VIs and functions is to not execute their normal action in the case of an incoming error. So now we have a good understanding of what general error handling is, the difference between automatic and manual error handling, what’s in the error cluster, and what error handlers do, as well as the default action of most native LabVIEW functions and VIs when they see an incoming error.

In our next episode, we’ll understand how to architect our applications to respond effectively to errors by using that Error Cluster. And as always, we deliver this type of training live, in the classroom, or online. Just check it out at Sixclear.com/labview-training.

(end transcription)

VI High 45: Learn How to Append to a File and Stream to Disk in LabVIEW

Last time we looked at writing a very simple file to disk. Now we’ll see how to append new data to the end of the file, how we might write data to a spreadsheet, and discuss how to stream to file and when that’s appropriate.

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)


Hey, welcome back. Last time around, we kept it pretty simple and just wrote to a file. ‘New file’, right here. And then pulled that open and then showed it. Now, let’s say I want to go and add to this file. Well, is it just as simple as writing new text? Let’s try it. I’ll write ‘New text’ and run the VI, make sure we close this existing notepad. And open it up again. What do we see?

‘New text’ has overwritten the beginning of the last text we wrote. Well, that’s no good. So let’s append ‘new text’. Close this out again. And to do that, I’ll need to go to my File I/O, and then Advanced File Functions, and Set File Position. Context Help, and we’re going to be changing right here the ‘from’. Right now, it’s at the ‘start’, but we’re going to change that to the ‘end’. And a good place to put this is right in between where we open the file and where we write to the file. So I’ll just take this and drag it over here. I’ll hold down SHIFT to keep it in one axis. And put this right in here.

Create a Constant. Go to the end, and there we go. Now, I’ll run it again, and of course I’m going to have ‘new text’ already at the beginning, so I’ll change this to ‘stuff at the end’. Run the VI. Pull open our file again. There we go. ‘Stuff at the end’. Perfect.

Now, on many applications, we’ll want to do something like this over and over, so an instance would be data logging. Maybe I’ll be taking data once a second and writing it to the end of a file. So I can edit this to write repeatedly to the file with a While Loop. Now where do I put it? Right around here. So, I’ll grab out a While Loop, wrap it around this portion, and I’m going to want a way to stop this, so I’ll Create a Control off the Conditional Terminal of my While Loop, and I’m just going to use the numbers coming from my Iteration Terminal and write those into the file.

Now, of course, this is a number, and I’m writing text, which means I need to change that. Let’s get rid of this text. Straighten this wire, and go to a function that’s going to change a numeric into text. So we’ll go to our String palette. String/Number Conversion. And here we go. Number To decimal string. That’s good. Let’s make a little space. I’ll hold down CTRL, click and drag, gives me some extra space, and I’ll wire in the number, and out comes the decimal integer string. Perfect.

And of course, we’ll want some timing, so let’s say I’m data logging once a second. I’ll go to my Timing palette, put a Wait Function in. 1000ms, or once a second. And before I begin, let’s go back to this file and just delete everything. ‘CTRL-A’, delete, ‘CTRL-S’ to save, close it. And before we run this, let’s grab our Stop Button. Pull it into the view here and run it.

And we’ll let it go for a few seconds, because we’re logging once a second. That feels good. I’ll hit the Stop Button. And let’s go back and open this up. There we are. The numbers from my Iteration Terminal. Zero through eight. Now, if I’m writing to a spreadsheet file, I’ll probably want to put something in between these, maybe a delimiter like a comma or a tab, or an end of line, carriage return; whatever I may be using.

But let’s take a look now at these functions, and those of you again familiar with LabVIEW, will be screaming at me: “Why aren’t you using the Error Cluster?” Well, we’re getting to that because what we should have is something like this, where we connect up these Error Clusters, through here, and even use the Error Cluster to stop the loop in the case of an error, which I would do like this. There we go. Now, this loop stops with the user Stop Button or an error. But what does this mean, this error?

Well, we’re going to talk about it. But we should say, before we go, that this type of pattern is known as Streaming to Disk’ or ‘Streaming to File’ because we open and configure the file once, pass references into a loop, and then write continuously within the loop. When we’re done, we close the file. And we contrast that to a situation where we wouldn’t put the While Loop just around the write portion, but perhaps around the entire portion, where we’d open, configure, write, and close each time we’d write something to the file.

Now, obviously, that’s slower, but it has some advantages, namely in file integrity. At slow write speeds, like once a second, then having all of this in a loop is typically ok. And if our system crashes, or maybe our apparatus gets hit by a lightning bolt, we won’t lose any data, assuming that our hard drive isn’t frazzled.

But for faster writes – maybe I’m writing 100 times a second – well, then streaming to disk makes more sense. But that’s entirely dependent on your system and how much you’re writing. So in those cases, you typically just have to benchmark it.

But for now, we’re done. Next time, we’ll talk about Error Handling. So subscribe to our Youtube Channel if you want to know exactly when the next episode is posted.

(end transcription)

VI High 44: Learn How to Write to a Text File with LabVIEW

Most folks in our courses want to know how to take their data and write it to a simple text file. So, today we start with the very basics of writing to a file. We’ll continue this topic over the next few episodes.

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)

So you want to do File I/O. Well, I do too. Let’s do it together. But let’s first be clear about acronyms. What is File I/O? Nothing more than File Input and Output. In other words, just reading to and writing from files. Pretty simple.

Before we see how to do it in LabVIEW, let’s look at types of files. A plain text file, which is typically just an ASCII character file. Spreadsheet files, which are typically plain text, but the data fields are delimited by tabs or commas. And binary files, which are arbitrary files typically not human readable. In other words, if you opened up the file in something like Notepad, it would be indecipherable. But these files are good if you have a proprietary format or lots of data or data coming in fast. For our purposes, we’ll focus on plain text files. So let’s open LabVIEW and see how to do it.

I’ll just open up a new VI and tile these left to right: ‘CTRL-T’. Let’s say I’m going to write a simple file in LabVIEW. So I’ll head to my block diagram, right click to bring up my Functions palette, and head to my File I/O palette. Now there are some higher level VIs at the top which encompass a lot of functions, but we’ll go down to these functions which give us more control over how to read and write in LabVIEW. I’ll tack this palette down and first pull up the ‘Open/Create/Replace’ file.

The name gives you a pretty good indication of what it does, and ‘CTRL-H’, or my ‘Context Help’, will give me more information. I see these little stubs here which are optional inputs, but I typically like to show those, so I’ll click the ‘Show Optional Terminals and Full Path’. Much better.

So the first thing I’ll do to write to the file is to make a file path. I’ll right click, and I’m going to create a control on the front panel. I’ll go yank this into view, expand it a bit, and click on the ‘Browse’ button. Now if I’m going to be creating a new file, then I might want to call it ‘new file.txt’. Just a text file. Okay. But Windows says, ‘Wait a minute! The file’s not found.’ So what do I need to do?

Well, first off, let’s right click on this button and go to ‘Browse Options’. And in ‘Selection Mode’, I want to not only choose an existing file but a new file as well. So ‘New or Existing’. Okay. Let’s try that again and call it ‘new file.txt’. Okay. Now coming back to my ‘Open/Create/Replace’ file, I see that the operation right now for default is ‘Open’ which means to open an existing file. Since I don’t have a file, I’ll need to change that. So I’ll right- whoops. So I’ll right click and create a constant off of it and change it to ‘open or create’ since it doesn’t exist. Clean up that wire, and ‘access’ being ‘read/write’ is okay.

Now coming out from this ‘Open/Create/Replace’ file function will be the refnum. This is my file handle, so that all subsequent functions know which file they’re manipulating. So our next function in our chain will be the ‘Write to Text’ file. And we’ll connect up the refnum across the top. And as we can see that we have a text input. In fact, that’s the only bolded or required input to this function. So I’ll just create a control off of this. And expand it a bit. And we’ll just write in here something completely arbitrary, like, I don’t know, “VI High has recently been named as one of NI News top 5 LabVIEW blogs! Thanks!” I don’t know. Just came to me.

So that’s what we’ll write, and since we’ve opened the file, written to the file, then it’s appropriate now to close that file reference. So going back to my File I/O palette, I’ll grab the ‘Close File’ and just take that file refnum and wire it in. And to keep it dead simple, we’ll go ahead and run it here. But before we do, let’s glance at that folder where we’re writing the file and see that there’s no magic behind my back. There’s nothing in the folder before I run the VI. So I run it. Now let’s take a look at that folder.

There it is; ‘new file.txt’, and I open it up and “VI High has recently been named as one of NI News top 5 LabVIEW blogs! Thanks!” Well, that’s good news. I’ll go ahead and close it. As I said, dead simple. Now, there’s a lot more we can do here, like learning how to stream to file, and appending more text to the same file, and seasoned LabVIEW users will see we didn’t even use the error cluster. But we’ll talk about those things; don’t worry. In the next episodes. We’ll be back next time. Thanks!

(end transcription)

VI High 43: Learn How to Make and Implement a LabVIEW Functional Global Variable

In our last episode we saw how race conditions occur and how data encapsulation and hiding can fix that problem, specifically through using functional global variables. In this episode we actually make those variables and integrate them into our robot arm code.

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)

In our last episode of VI High, we talked about Functional Global Variables and how they are a form of information hiding and data encapsulation. We showed how this VI, which moves a robot arm through global variables, is prone to race conditions and can be corrected by replacing this critical section of code with a Functional Global Variable. Like this. And I promised this time I’d actually do it. So let’s do it.

This VI resides in a project, ‘Robot Project - Global’, and we see that we have the global variable here. So to fix it, I’m going to make a copy of this project. File, Save As, Duplicate this project. And I’ll call it ‘Robot Project - Fixed’. And I’ll open this up and close the old project. This position global is still a dependency, but we’ll see that we’ll remove that. Let’s get rid of it on the block diagram so that it’s no longer a dependency, and there we go. No longer a dependency.

Now, I’ll open up a new VI. Save it as ‘New FGV’ for Functional Global Variable. On the front panel, I’ll put down an Enum, which I’ll call ‘Command’, and in here will be all the commands for this Functional Global Variable. Init, Process 1, Process 2, Read. And then an indicator on the front panel telling me the position. I’ll change it to an I-32.

And now to control data flow, on the calling VI, I’ll put down some error clusters. Error In, Error Out. Going to the block diagram, let’s get these out of the way for now, I’ll put down the infrastructure of a Functional Global Variable, which is a While Loop surrounding a Case Structure with my command Enum going to the Case Selector Terminal.

And then right click on the border of the While Loop, add a Shift Register. Into my Conditional Terminal, I’ll create a constant, which is True because we only want this While Loop to execute one time. I’ll first flip over to the Initialize, and the Initialize we’ll put in the initial position. So I’ll need that in the front panel. I’ll just copy the position since it’s already the right data type. Right click on it, change to control, and call it ‘Initial Position’. And align these all nicely to the left. Very nice.

And I’ll wire this into a Shift Register because I want that initial value being placed in the Shift Register. In Process 1, I want to take that value out and add a ‘10’ to it. And also write it out to the position. Now, the position can be inside or outside the While Loop. It doesn’t matter since it’s only running one time, but I’ll put it in here so we have fewer tunnels.

Process 2 is essentially going to be exactly the same, so I’ll just click on the Case Structure, Duplicate Case, and there we go. Change this to ‘5’, good. And then we’ll right click and add a case after to Read and at this point, we just wire this to the position out, and then also wire it to the hollow tunnel. We have one more case to fill in the value for, the position right here, and that will be whatever the initial position is.

So that’s the guts of a Functional Global Variable. Again, While Loop, with a Shift Register uninitialized, nothing going into it, in other words, so that it retains values between runs of the VI, a Case Structure inside with the command Enum going to the Selector Terminal, and a True constant going to the While Loop Conditional Terminal so that it only runs one time. For good data flow, I’ll now wrap this whole thing in a Case Structure, and my Error In Terminal will go here. Error Out over here. Hold down CTRL and use my mouse wheel to flip to the next case. There we go. That’s all done.

I’ll save it, head to the front panel, and assign the connector pane. We always like to keep the error clusters in the lower left and right, and then to edit the icon, I’ll just double click on it. I’ll select the whole thing, delete, put down a new border, go to the icon text, put down FGV, I don’t want to center it vertically, and then a nice glyph. Maybe something about a variable. Ok this looks good. Grab it and pull it on. That looks nice. Save.

Now that my Functional Global Variable is finished, I need to get it on the block diagram of the calling VI, so I’ll just go to the icon, click and drag it onto here. Very easy. And now we just call it in the appropriate place. I’ll put one instance over here, and in the command, I’ll right click and create a constant, initialize. That’s good. And the initial position will be wired into the initial position input here. So probably actually better put it up top. That’s smarter. Good. And since we want this to run before both of these, we were previously using this wire to control data flow. But now that we have this error cluster, we’ll use that instead.

That’s prettier.

We’ll need an instance over here in Process 1, so hold down CTRL, click and drag, and bring it over here. I’ll get rid of this ‘+’ since it’s already in there. And in fact so is the ‘10’.

Call Process 1. Good. Down below, same thing. Actually, I will need to keep that ‘5’. Clean that up. And create a ‘10’ again here. Just so we can do our validation at the end. Make a copy of this. Call this Process 2. Good. And then at the end we’re going to want to call this again over here, Read. And what comes out will be the final position. Again, we won’t need this piece of data flow because we’ll just use the error clusters again. Since I have two errors coming in, I’ll need the Merge Errors function. Right here.

Wire in my errors. This could be prettied up a bit, but you get the idea. Hmm, I wish I could get the idea, but my OCD won’t let me. That’s nicer. Ok. It’s time to test it out. Back to the front panel, and we run it. They match, that’s good, they match again. And just like before, I’m going to go grab some dinner while this runs for a while.

I’m back. I ate a lot of dinner, especially since I recorded these back to back. But let’s stop them, and just as we suspected, they’re exactly equal, no matter how large the number.

Well, that’s it for our Functional Global Variable implementation of information hiding and data encapsulation. As I mentioned in the last episode, there are other ways of doing this. Ask your nearest certified LabVIEW developer or architect, and they’ll have at least a dozen opinions. But if you’re just interested in the fundamentals, we have a whole course for that: Sixclear Lucid LabVIEW Fundamentals training. Check it out at sixclear.com/try. That’s T-R-Y.

(end transcription)

VI High 42 - Learn About LabVIEW Functional Global Variables & Data Encapsulation/Hiding

Here’s a big knowledge bomb lobbed at you: how race conditions occur and how to prevent them using data encapsulation and data hiding. We use a tried and tested method: functional global variables. There are other methods as well that we mention in the video. Enjoy!

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)

Let’s talk about Functional Global Variables. We get asked: What are they? Why would I use them? Are they similar or better than single element queues or even actor engines in LabVIEW object-oriented programming?

Let’s first understand why they’re valuable. And to do that, let’s have a case study. We’re going to peek into the life of a robot arm. This robot arm is being controlled by two different processes in an application. Both of these processes would like to move the arm at certain times. Process One moves the arm ten units, and Process Two moves the arm five units. How can we program this?

Let’s first look at a problematic way to program it. Here’s my robot main. The robot arm starts in some initial position. I run it for a certain amount of time, and then I stop it. This final position will show the final position of the arm, in arbitrary units. 49,095.

Let’s look at the block diagram. You see that I have two loops, Process One and Process Two. And this global variable, you can tell from the globe, is keeping track of the position. We’ll start over here. Because of data flow, we see that this section is going to execute first because it has inputs to these nodes. So we set the initial position of the variable, and then when Process One executes, it takes the position, whatever it is, adds ten to it, and writes it back. So in essence it is moving the robot arm ten units and keeping track of that.

Process Two, on the other hand, also moves the robot arm, but it only moves it five units. So it reads the value of the position, wherever it is, adds five to it, and writes it back.

Let’s peek at this global variable, just by double clicking on it. And we have our global VI with just a numeric value. Pretty simple. When we’re finished, we’ll go and display the final position over here just by reading the variable.

Now what else are we doing? As you can see here, I’m looking at the iteration terminal, adding one to it since it’s zero-indexed, and multiplying it by the ten that Process One moves the arm. So in other words, at the end of run time, Process One will have moved the robot arm ten times the number of iterations of this loop, and that’s what output here.

Similarly, Process Two will do the same thing, except it will be multiplying its number of iterations times five. At the end, we’ll add together the total distance that Process One and Process Two has moved the robot arm, and that will be the loop sum.

This should be equal to the global position because all we’re doing is adding up the total distance Process One moved the arm and the total distance Process Two moved the arm.

Going back to the front panel, we see that that’s typically true. I run it, stop, it’s true. I run it, true. Okay.

Let’s run it for a little longer, and I’ll pause the recording, so you don’t have to wait, and I’ll go get a snack. I’m hungry.

Okay, let’s stop it. Interesting. As you can see, the final position here is 343,625. However, the sum of both loops is 343,635. In other words, ten more. Hmm. Let’s run that again a few times. Well, they’re still equal in most cases. I’ll let it run again and pause it again for you. I’m still hungry. I’ll go get something to eat.

Okay, that was tasty. Let’s check this. Hmm. Now look at this. This time, they’re off by five. A little different. If I keep running this, in this manner, we’ll see that over time, these will change, and the value will change, but it’s inconsistent. Sometimes, they’ll be exactly the same. Sometimes, they’ll be off by five, or fifteen, or twenty.

What we see is a Race Condition. A race condition occurs when we have two processes trying to access the same shared resource. In this case, this position global variable. To see why the error is occurring, let’s first look at what should occur. Well, in the beginning, we should write a zero to here. Maybe Process One goes first, reads zero, adds ten to it, writes ten. Then maybe Process Two goes. It reads ten, adds five to it, fifteen. Process One goes. It reads fifteen, adds ten to it, puts twenty-five. Process Two reads twenty-five, adds five to it, gets thirty. And so on, back and forth, each adding their units whenever the process executes.

And we can see that for the most part, that works. I can run this many times, and that value will agree. But then once in a while, as we see here, it doesn’t. Well, what’s happening then? What may happen, let’s go back again, and let’s say we’re…let’s say the position is at thirty. Process One reads thirty, adds ten to it, but before it writes the forty, Process Two comes along and reads thirty. Adds five to it. And now the final value of the position will be whatever one of these writes last.

So in essence, one of their iterations will be lost. And so we see that when there is a discrepancy between the loop sum and the final position, the loop sum is always higher because it’s always accounting for every iteration. So how can we fix this?

This leads us to the topic of Information Hiding and Data Encapsulation. If we go to our friend Wikipedia, we can see that Information Hiding and Data Encapsulation is the ‘segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed’.

Very clear. You should donate to Wikipedia. What does this mean in the context of our LabVIEW program? What we’d like to do is protect a certain area of code so that there’s one and only one way to access it. Since we have two processes trying to access the same shared resource, this position, let’s encapsulate the section where we write to it.

So what we have is a critical section of code, right here and right here, that need to be protected. And we can do that with a Functional Global Variable. Now there are other ways to do that, as we mentioned earlier. Actor engines in object-oriented programming, are an excellent way of doing this, and there are many other ways. We are simply exploring one way.

I’m going to rewrite this program so that every time I access this shared resource, I have to go through a Functional Global Variable instead of this global variable.

Here’s the robot application rewritten with a Functional Global Variable. This is our Functional Global Variable, and we use it in the four places where we previously accessed the global variable: where we initialize at the beginning, execute Process One, Process Two, and then read the final value at the end.

Let’s look inside this Functional Global Variable. As you can see, it’s a subVI, and if I go to my block diagram, I see that the code is pretty simple. Inside of my error handling Case Structure, I have a While Loop with a Shift Register, and the Shift Register is uninitialized, so it maintains whatever value is in the Shift Register between runs of the VI, even though the VI is stopped.

And in my Case Structure, I have four different cases:

- Initialize, where I put the initial position into the Shift Register.

- The Read case, where I take the position out of the Shift Register and display to the user or pass it out of the VI, and then

- Process One, which takes the robot arm position, adds ten to it, and writes it back to the Shift Register and also passes it out of the VI, and as you guessed

- Process Two, does exactly the same thing except adds five to it.

Each time this While Loop is called, it runs only one time because I have a ‘True’ constant going to the conditional terminal.

So, as we can see, I’m calling this Enum, and first initializing, then within Process One, I call Process One, within Process Two, I call Process Two, and then in the end, I read it.

Now recall the problem of the previous application, involving global variables, was when both processes were inside of this critical section of code at the same time. You see now that with the Functional Global Variable implementation, that never happens because the subVI is a non-re-entrant VI meaning it does not create duplicate memory spaces for itself.

If Process One calls the variable in order to move the robot arm ten, Process Two cannot access the variable at that time. It has to wait until this is finished, and then Process Two can call it, and then Process One. The problem has been solved because of Data Encapsulation, or Information Hiding.

Now I think you should believe me that the problem is solved, but just in case you’re curious, let’s do it. Run it, stop. Run, stop. And I’ll run it, and I’ll wait for a while. In fact, I’ll go make a whole dinner because I’m kinda hungry again, and we’ll see that when I come back, this loops some, and the final position no matter how large they are, will be exactly the same. So hang on a minute.

Okay, I’m back. And that was delicious. Let’s stop it. Wow, big numbers. And they’re exactly the same. That’s very validating.

Well, that’s it for this episode. Stick around next time, and I’ll make the Functional Global Variable and put it into the first robot arm application, to see exactly how it’s implemented.

And remember, we have a whole course full of this. It’s Sixclear Lucid LabVIEW Training. It’s about a week’s worth of me teaching you LabVIEW. So check it out at sixclear.com/labview-training.

(end transcription)

VI High 41: Learn How to Use a LabVIEW Case Structure

This is a direct excerpt from Sixclear Lucid LabVIEW Fundamentals Training and shows the core concepts of how a case structure works. To get access to the manual, solution code, and video mentioned at the end, go to sixclear.com/try.

You can also keep up with us at:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

Experience level: Basic

(start transcription)

A Case Structure can conditionally determine blocks of code to execute based on an input. For you text based programmers out there, this is similar to an if/then, if/then/else, switch, or case statement.

Now what determines what will execute? In this case, it’s this Boolean Control that we see right here, and here’s the corresponding Boolean Switch on our front panel. Now let’s head into LabVIEW and see how to program this.

I have a new blank VI, and I’ll hit CTRL+T to tile these and head to my block diagram. I’ll right-click, go to my Structures subpalette, and head to Case Structures. You see, when I click on that, my cursor shows a little miniature case structure. So I’ll click in the upper-left corner or where I want to build my case structure, drag and release, and I have my case structure.

Now the cases in a case structure are stacked like a deck of cards, so I don’t see the underlying cards when I’m looking at the top-most one. Let’s think of a simple use case. Sometimes, I need to take two numbers and add them together. And sometimes, I need to take the same two numbers and subtract them from each other. So let’s do that.

I’ll head to my front panel, bring up my Controls palette, and go to a default Numeric Control. And it’s called ‘Numeric’ by default, but I’ll change it to ‘Number 1’. Then I’ll select it, hold down CTRL, and now I have ‘Number 2’. So I’ll click, drag, highlight both of them, go to my Align Objects tool, here in the Toolbar, and align them to the left. That looks great.

And I’ll head over here to my Numeric Indicator to put down a result, which I’ll cleverly name ‘Result’.

Heading to the block diagram, I’ll take ‘Number 1’ and ‘Number 2’ and put them here to the left of the Case Structure. And I’ll take ‘Result’ and put it right here to the right of the Case Structure. Now this green thing right here is called the Case Selector Terminal, and it determines which case will execute. I’m just going to click directly on it to move it down here, out of the way for right now.

Our requirements are to sometimes add these two numbers together and sometimes subtract them from each other. So I’ll go to my False case, and let’s say in my False case, I’m going to go to my Numeric Palette, to my Add function, and add these two together. And now I’ll wire ‘Number 1’ to the top terminal of my Add function, and ‘Number 2’ to the bottom terminal.

Now, we can just flip over to the other case, just by clicking this little arrow, and we notice that in the True case, we don’t see what’s in the False case. Again, deck of cards; we don’t see what’s in the other cards. So in this True case, I’m going to again go to my Numeric Palette and pull out the Subtract function. Put that there.

Now, to subtract these two numbers, I’m going to wire from these tunnels. You see these orange blocks here are called tunnels. Whenever I wire into or out of a structure, I automatically get a tunnel. So I’ll just click on the output of a tunnel and wire to the inputs of my Subtract function. The color, of course, of any tunnel will indicate the data type it represents, just like the wire. And since we have orange blocks and wires, we know that’s a fractional number, the default being a double.

And now to finish, I’ll just wire out from the output of my subtract function to my Result Indicator. Now as I wire through the border of this structure again, you see a different type of tunnel arises. And it’s a hollow tunnel. Now what do you think that means? It means that we’ve supplied an input to the tunnel in one case of the case structure, but not the other. So let’s do that. Wire directly to the tunnel, so it’s flashing. There we go.

Now we’re almost ready to run this, but we have a broken run arrow because we haven’t yet told the case structure which case to execute by supplying an input to the Case Selector Terminal. The color is green, so we know that that’s a Boolean data type. So I’ll head to my front panel, go to my Boolean subpalette, and put down a Vertical Toggle Switch. On my block diagram, I’ll take that terminal and wire it directly to the Case Selector Terminal. We have a solid run arrow, so we’re ready to go. So let’s test this out.

First, in our False case, we should be adding these two numbers together. So I’ll fill in some values. ‘Number 1’ gets 3, ‘Number 2’ gets 2. I’ll keep the Boolean as False, and run my VI. As we can see, 3+2=5. I’ll go back to my Boolean using my operate tool hovering directly on it, click, turn it to True, run again, and now they’re being subtracted, ‘Numeric 2’ from ‘Numeric 1’, as we see over here.

Now let’s see this in action. I’ll slow this down using Highlight Execution, which is the light bulb. Click on that. And change this Boolean back to False; run it. And we see that we execute one and only one case. The Boolean is read, telling us we’re going to the False case. We execute the False case, and then we’re done. Now what we’ve just done is exactly equivilent to an if/then statement in text-based coding.

And we’ll see that in the future, I’ll be able to wire different data types to the Case Selector Terminal, and it’ll change my available cases to run. And instead of just having True and False, I can have multiple cases, maybe numbered, or maybe with different labels. This is based on the polymorphism of our Case Structure. And we can see that with those different data types, we can have as many cases as we like offering us quite a bit more flexibility in our coding.

But for now, you’ll do our next exercise. If you have a copy of LabVIEW, go ahead and open that up, and then open up the Test Drive PDF manual. In there will be instructions on how to complete the exercise. When you’re finished, there’s solution code in LabVIEW for the completed VI.

Additionally, there’s a solution video, which has me walking through each step of the exercise and showing you how to do it, so there’s never a chance for frustrating confusion or delay. Additionally, in the solution videos, there are other tips and tricks as well as productivity tools which will help you become a more efficient LabVIEW developer. So take a look and good luck.

(end transcription)