LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Statemachines and Polling of Inputs for Motion Control

Solved!
Go to solution

Working on a motion control experiment and I'm following some advice of planning out all of the functionality before writing code, so sorry if this is a little abstract. 

 

The system would consist of a motor that, once the user clicks a button; moves to a position, takes a measurement, moves to another position, takes another measurement, then waits for the user to click the button again. The whole system would be in an interlocked box, so that when the system is not going through the "move-measure" loop, the box can be open for loading/unloading, but that box must be closed in order to start the loop. Additionally there would be an E-Stop such that once pressed, everything stops. Even though the motor controller returns a move successful command, I would have a timeout to stop motion in-case communication was lost with the controller.

 

I laid out the basic states in the attached diagram. My basic approach would be a producer consumer to handle all of the user events, which would then kick-off a state machine in the consumer to handle moving to the various postions/measurements. The two things I'm unsure on are: 

 

1) Does it make sense to make a "sub-state machine" to control the positioning task, as shown? There is an obvious transition between states that all happens without user intervention. I'm not sure if making this a state machine as well over complicates things? 

 

2) What is the best way to handle polling of the E-Stop/Box Interlock? (In reality they would both be tied to the motor controller so no labview is needed to stop motion, but I prefer a belt and suspenders approach). I could check the status of those devices in each and every state but that seems cumbersome. I also considered having a parallel producer loop to check their status and en-queue a "fault" message if something goes awry, but that is complicated by the fact that the box interlock is allowed to be open when the machine is in the "not moving" state. 

 

 

0 Kudos
Message 1 of 12
(2,607 Views)

What I like to do is to use the queue's timeout.  If the queue times out, do whatever is next in the state machine.  If it does not time out, then you do whatever the message says to do (Abort Motion, Restart, Go to a different position, etc.).  The key here is that you can change the timeout time by storing it in a shift register.  Default it to be -1 so that it never times out.  Then when the "Start" message is received, set the timeout to be 0 (timeout immediately).  When the command is complete or aborting is complete, set the timeout back to -1.  So all of the state machine is actually done in the "Timeout = TRUE" case and any received messages are done in the "Timeout = FALSE" case.


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 2 of 12
(2,580 Views)

I think what you have flow charted looks like a good starting point.

 

As for the safety interlock, I would have the interlock check ruining in its own loop independent of the move and measure state machine. Use one of the common methods of sending data between loops to direct your state machine to the stop case should the interlock open during a run

 

But if you can reuse that "sub-state machine" as its own " move state" and just pass position values to the state, I would do so

========================
=== Engineer Ambiguously ===
========================
Message 3 of 12
(2,525 Views)

Thank you both. Cross, is the attached an accurate representation of what you're describing? It makes sense, but I'm looking for hidden "gotchas". The one issue I am having is how the Consumer loop can kill the Producer loop (I.E. to shut down the program). I know I need to stop the producer, but any local/global/other transfer I've tried either doesn't work or causes weird behavior. 

 

RTSLVU, would the interlock check essentially be a second "producer" loop? In my mind, it runs in parallel with the loop monitoring for user input, but instead periodically polls for the interlock check. If anything is bad it sends a "stop" command, that I'd probably enqueue at the opposite end so it is "seen" immediately. Does that seem to be correct? That's the biggest issue I have, understand exactly where a specific loop should run when plotting things out ahead of time. 

0 Kudos
Message 4 of 12
(2,491 Views)
Solution
Accepted by topic author Glibby1234

@Glibby1234 wrote:

Cross, is the attached an accurate representation of what you're describing? 


Not quite.  You should not have a loop inside of your QMH.  The idea, after all, is to be able to constantly listen for messages.  So move your state information to the outside loop.

 

Another note: your consumer should be the one to maintain the queue.  It should release the queue inside of it's stop or exit case.


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
0 Kudos
Message 5 of 12
(2,485 Views)

Forgot to attach the update I did...


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
0 Kudos
Message 6 of 12
(2,458 Views)

Thank you! 

 

So am I wrong in having the "finish" state en-queue the "Stop" message? My thought was that there are (or will be) cases where the state machine will trigger an action that exactly mirrors something the user would do (clicking the stop button for example). 

0 Kudos
Message 7 of 12
(2,440 Views)

@Glibby1234 wrote:
My thought was that there are (or will be) cases where the state machine will trigger an action that exactly mirrors something the user would do (clicking the stop button for example). 

You really should avoid having a QMH enqueue something onto itself.  It can cause all kinds of weird race conditions.  So after "Finish" is run, just go into the idle state (waiting forever for a message).  From the user perspective, there should be an Abort button (stops the motion when something bad happens) and a Close/Exit button (tell the loop to stop).


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
0 Kudos
Message 8 of 12
(2,431 Views)

Understood, thank you! 

 

One other thing I noticed, since the state machine has to finish before that loop can respond to a new message (simulated by a wait command in the "Wait" state), it means the user buttons will be un-responsive while the program is in certain states. I think that invalidates the idea that there would be a secondary "interlock monitoring loop" since even if it queued an emergency message, it would have to wait. 

 

Is that just a side effect of this architecture?  

0 Kudos
Message 9 of 12
(2,410 Views)

@Glibby1234 wrote:

One other thing I noticed, since the state machine has to finish before that loop can respond to a new message (simulated by a wait command in the "Wait" state), it means the user buttons will be un-responsive while the program is in certain states. I think that invalidates the idea that there would be a secondary "interlock monitoring loop" since even if it queued an emergency message, it would have to wait.


With what you initially did, yes the state machine would have to finish.  Look at what I did in the correction.  The message queue is actually being checked with each state transition.  Even with a 0ms timeout, if there is a message there you will get it and not time out.  Now what you can do with your "Wait" state is not even have a Wait state and instead set the timeout for the queue to be however long you want to wait and set the next state to be whatever should come after the wait.  Again, if you get a message in that time, you will process it immediately and act accordingly.


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
0 Kudos
Message 10 of 12
(2,406 Views)