From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

state machine running out of order

Solved!
Go to solution

I am running Labview 2014 with a USB 6212 board.  My card/code is being used to control a stepper motor and a linear actuator with a built in potentiometer.  I created a state machine to control the sequence of events and timing between the two motors.  The general flow of the program is this. (The program will eventually record data but that function is not written in yet.)

 

1)  Init

2)  Take data

3)  Move actuator out by desired distance.

4)  Increment the actuator position to next desired position.  

5)  Repeat 2-4 until next desired position exceeds a maximum distance. 

6) Return actuator to starting position. 

7)  Raise stage with stepper motor by an increment. 

😎 Repeat 2-7 until a maximum height is reached

9)  Return platform height to zero. 

 

I am having three main issues with my state machine. 

 

Problem 1) The counter mentioned in step 4 (found on the ACTUATOR OUT/RECORD DATA case in the program)  Does not increment consistantly.  Most of the time it ends up incrementing twice the distance it is supposed to.  I can watch the indicator on the front panel increment twice while the linear actuator only moves once.  

 

Problem 2)  The program does not execute in sequence correctly or consistantly.  Usually step 7 occurs before step 6

 

Problem 3)  The program lags a lot and freezes before it finishes.  

 

 

I have been working on this all day and could really use some help.  

 

Thanks in advance. 

0 Kudos
Message 1 of 20
(3,909 Views)

Just a couple of comments and questions.

You could do without a lot of these local variables, and in most cases if you removed the local variables you would be able to remove the sequence structure.

What is the purpose of the Stage Height > 2 = F statement at the end of the RETURN TO ZERO case? Comparing a boolean to a boolean constant is a bit of wasted effort.

Why bother with the Select at the end of the STAGE UP case if you are just going to pass it a constant?

The constant starting and stopping of DAQ tasks might account for some of your lagging and freezing. If you start the channel once on INIT and Close them once the platform returns to zero you should get improved performance. You can pass the tasks through shift registers to allow you to pass them between states easier.

When you say freezing is it stopping or not responding? Your 2000ms waits will cause the program to halt at those waits and not perform any operations while they wait for the wait to elapse, this might be the cause of some of the problem.

0 Kudos
Message 2 of 20
(3,860 Views)

Suggestion -- Write a brief document and figure out what States you really need (I'd add a bunch more, see below).  As already has been pointed out, the idea of a State Machine is to segregate the various tasks, particularly those that are done first, second, all-in-the-middle, and last.  The fact that you have a While loop means you have access to Shift Registers where you can store "results" from an earlier State.

 

The Init State is an ideal place to define your channels and open your DAQmx Tasks, which you save in Shift Registers for the loops that you run do "do things" with these Tasks.  In particular, if you are doing Analog Out to a particular device, you generally do not need to, and very much do not want to, close and re-open the Task between every AO call.

 

Once you have things initialized, you want to Wait for a Start Button push, and also check for a Stop Button Push.  This suggests two States -- Wait for Start and Check if Stop.  Wait for Start does just that -- it waits for, say, 100 msec, reads the Start button, and if True, calls the State you want to do first when Start is pressed.  [I notice that as part of your initial Init State, you send a signal out to zero your device -- this should be in its own "Zero Device" state, called after Init (which should only be called once).

 

If the Start Button is pushed, you sent Next State (in a Shift Register) to the Next State.  If Start Button is not pushed, you stay in the same "Wait for Start Button" state.  But how do you handle the Stop Button?  When you exit the Case Statement but are still in the While Loop, check if the Stop Button is pushed.  If not,, pass the "Next State" through to the Next State Shift Register, but if it is pushed, change the Next State to "Finalize", a State where you stop and dispose the DAQ Tasks and output a True that is wired to the While Loop's Stop indicator (use the "Use Default if Unwired" option on the Boolean tunnel so you don't need to wire False for all the other cases).

 

Finally, now that all of your States have much less code, shrink your Block Diagram down to a more compact, neat size to make it easier for you and your colleagues to visualize you code, understand what you are trying to do, find bugs, add additional States to allow for future expansion, etc.

 

Bob Schor

Message 3 of 20
(3,744 Views)
Thanks for the reply.  I have added comments to the code to help clarify things.  
I used the local variables so I could easily change data in multiple places at once (if I want to) and also to send information from one case to another. 
The comparison is used to compare the current stage height against the maxiumum desired stage height (in this case it was 2 inches)
The main reason I passed the select case a boolean is to try to force the sequence of events.  The other is I didn't know a better way to do it. 
I agree that passing a task from one case to another is better but don't know how to make that work.  Do you know where I can find an example? 
And as for the freezing, my program will stop for 10-30 seconds before executing for a few steps and pausing for another 10-30 seconds before eventually stopping all together. 
@ogk.nz wrote:

Just a couple of comments and questions.

You could do without a lot of these local variables, and in most cases if you removed the local variables you would be able to remove the sequence structure.

What is the purpose of the Stage Height > 2 = F statement at the end of the RETURN TO ZERO case? Comparing a boolean to a boolean constant is a bit of wasted effort.

Why bother with the Select at the end of the STAGE UP case if you are just going to pass it a constant?

The constant starting and stopping of DAQ tasks might account for some of your lagging and freezing. If you start the channel once on INIT and Close them once the platform returns to zero you should get improved performance. You can pass the tasks through shift registers to allow you to pass them between states easier.

When you say freezing is it stopping or not responding? Your 2000ms waits will cause the program to halt at those waits and not perform any operations while they wait for the wait to elapse, this might be the cause of some of the problem.


 

0 Kudos
Message 4 of 20
(3,731 Views)

 

Bob:

 

Thanks for the reply.  All of the examples for state machines I have seen are for programs that don't include analog/digital inputs/outputs so I am trying to learn as I go.  

 

If I understand you correctly, I am either calling DAQassist every time I want to use it and I am either closing it every time, or I am opening multiple instances of DAQassist.  So which is the best way to use it?  Do I have it inside my while loop but outside of my case structure or should I have it in one of my cases?  If I have it in one of my cases, how do I read that value while in another case?  

 

And I also don't know how to pass a task between cases.  Again I don't have a good example to work with. 

 

Thanks!

 

0 Kudos
Message 5 of 20
(3,709 Views)

You do not want to use the DAQ Assistant.  You should have an Initialize state to create your DAQmx tasks.  You then store them in shift regiters on your outter loop.  Make sure you pass these task references through all of your state cases or you could lose your reference.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 6 of 20
(3,693 Views)

I attemped to rewrite the actuator code using DAQmx instead of DAQassist.  I attempted to pass tasks, error messages, and the voltage through shift registers. (No idea if I am on the right track)  However, my task to constantly read the analog voltage is not working.  It is giving me an impossible answer (when I run it I get a voltage greater than 5v when my ref is 5 volts) and the voltage it is reading is not changing when clearly the voltage on my potentiometer is chaning. 

 

Thoughts?

0 Kudos
Message 7 of 20
(3,673 Views)

In addition to Bob's excellent advice, I would add one more point:

 

Pare down your program at first.

Make your state machine so that it has three states (FOR EXAMPLE):

--- Move the thing out.

--- Wait 3 seconds

--- Move the thing back.

 

Work on that until it works 100%.  That way you have the output part working.

 

Then add another state.  If it turns to crap, you know where the problem is.  Work on it until that part also works.

 

Keep adding states ONE AT A TIME, until you get them all in and working.

 

Once you get all the states working, then implement your logic that says exactly how you want to operate.

Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 8 of 20
(3,657 Views)

I appreciate all the comments.  I am working on just getting the actuator to do what I want.  As recommended I created an analog input on the init screen (using DAQmx and not DAQassist) and use it to pass voltage to the next cases with a shift register.  The problem I am having is I need the voltage from the potentiometer to constantly update for the computer to know where the linear actuator is at.  Currently on the HOME case, a single voltage value is being passed to the while loop that contains the logic to move the actuator in or out.  The voltage is never updated inside the loop so the actuator starts, but never stops and the program becomes stuck in that loop.  How can I update the voltage continuously inside the loop without having an analog in task inside the loop also? 

0 Kudos
Message 9 of 20
(3,624 Views)

You're not in the spirit of a state machine.  

 

Your code has a loop in the HOME state where you do nothing but wiggle the digital outputs until it gets home.

 

 

You have a Shift Reg comeing in, and that value is passed straight to the output ShiftReg, which means it's doing you no good at all.

 

I wrote an article on this some time ago < State of the Machine >.

 

Here's how I would approach it:

 

You have a master VI which measures the voltage input at some sample rate.

 

Each sample, it calls the STATE machine, passing in the latest reading.

 

Each call to the state machine examines the current state and takes appropriate action.

 

Each state has two objectives:  

1... Return as quickly as possible.

2... See if conditions are met to advance to some other state.

 

 

You have a state called GOING HOME.  You have a state called IDLE AT HOME.  (just for simplicity's sake).

 

 

The IDLE AT HOME state is just that: idle.  It does nothing but retiurn to the caller.

 

The GOING HOME state takes the current voltage (that you passed in). Remember objective #2: see if conditions are met to advance to some other state.

 

So you take that voltage and compute whatever you're computing with it,

 

If you are at position HOME, then you set your next state to IDLE AT HOME, and return.

 

If you're NOT home yet, then you take ONE STEP (flip ONE digital line) and then return.  You STAY in the same STATE.

 

Back in the master, you will take another reading, and call the state machine again.  If it's still in GOING HOME state, it will take another step, and return.  

Whenever it gets home, it will stop and enter the IDLE AT HOME state.

 

Perhaps you need status outputs from the STATE machine, perhaps not.

 

But the idea is very simple:  remember those two rules of a state machine.

 

The point is to take ONE step for each call.

 

 

Maybe you need another state called GO TO POSITION X.  You pass in X.

The rules are the same: you measure the voltage and THEN call the state machine.

This new state compares the current position to the target position, and decides to issue a pulse to move the thing, or that it's already there.

WHen it's already there, it enters another state called IDLE AT TARGET, or maybe another state called LAUNCH MISSLE, or whatever.

 

But the STATE MACHINE should be called OFTEN and should return quickly.

 

 

 

Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


Blog for (mostly LabVIEW) programmers: Tips And Tricks

Message 10 of 20
(3,613 Views)