From 04:00 PM CDT – 08:00 PM CDT (09:00 PM UTC – 01:00 AM UTC) Tuesday, April 16, 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: 

[QMH] Having a state repeat until a condition is met (without blocking)

Solved!
Go to solution

Hello all!

 

I'm using a QMHarchitecture to control a robotic system.  I'm still learning more and more about the QMH programming architecture.  I have a total of 4 queues, currently:

  • UI
  • Serial Data
  • DAQMx Tasks
  • Datalogging

I have some laser sensors that will output a boolean if there is something in front vs nothing in front of them.  I also have a series of commands that I send to the various queues (haven't gotten there yet, but getting close).  My question is: How can I create a state (in the "tasks" queue) that will repeat itself until the lasers' booleans become true (then, move on to the next queued element).

 

Thanks,

Joe

0 Kudos
Message 1 of 14
(5,164 Views)
Solution
Accepted by JoeKellyATI

What I like to do is use the queue's timeout.  You can store what the timeout should be in a shift register.  If you set it to -1, it will wait forever.  So if you do not get a timeout, you can process the message and react to it.  If you do get a timeout, you will get the default state and a Boolean output (Timed Out) will be TRUE.  So when you do get a timeout, you can do something.  If you have multiple things that could be set in a timeout condition, you can store the state to run when you get a timeout in a shift register.  A simple Select will make this simple to choose between the queue's state output and the stored state based on the Timed Out Boolean.


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 14
(5,127 Views)

So I'll admit that crossrulz suggestion above is awesome and I'm definitely going to use that implementation in the future. What I've done in the past is have the repeating state check to see if the Boolean condition is met, and if not, enqueue itself at the front of the queue. That way it would repeat itself. But this only works if nothing else will be enqueuing messages at the front of that specific queue.

dK
0 Kudos
Message 3 of 14
(5,119 Views)

wrote:

So I'll admit that crossrulz suggestion above is awesome and I'm definitely going to use that implementation in the future. What I've done in the past is have the repeating state check to see if the Boolean condition is met, and if not, enqueue itself at the front of the queue. That way it would repeat itself. But this only works if nothing else will be enqueuing messages at the front of that specific queue.


There have been several threads lately about why this is a bad idea.  In short, a QMH should never enqueue its own state because you are causing race conditions with other loops trying to send messages and/or you cause infinite loops.


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 4 of 14
(5,111 Views)

I for one would definitely *not* have a repeating state enqueue itself to the front.  That's an infinite loop waiting to happen!  I *would* consider enqueuing to the back like normal, allowing other messages a chance to break in.

 

I've actually put together a library for QMH's that I call "scheduled messages."   I have a wrapper for the Dequeue function (reentrant of course) which knows about these scheduled messages.  When you wire in a timeout that extends beyond the time when the next scheduled message should fire, the wrapper function handles that and returns the scheduled message at the right time (if no other regular messages arrive before that).

 

It's been a handy way to make sure certain processing or status checking happens at a regular rate, even in the presence of lots of other message processing.  A simple timeout often won't work very cleanly for me because my main loop rarely goes even as much as 100 msec between messages (it's the consumer for a bunch of instrument interface producer loops).

 

 

-Kevin P  

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
Message 5 of 14
(5,108 Views)

Thanks Cruossrulz!

 

I like the idea of the shift register!  Just to clarify (and explain to others that might happen on this thread), here's what I ended up doing (and what seems to be working).

 

I have the while loop that dequeues from the queue every millisecond (then timeout and jumps to the Default case).  One of my cases , when called, checks the statues of the sensors and checks if there is something in front of them.  I have this boolean wired to a Select block.  The True side puts the case string into the shift register.  The False case puts an empty string into the shift register.  Every While loop iteration, if the Dequeue message VI gets timed out, it outputs a True boolean into a case structure.  That case structure just holds an Enqueue Message VI, and it enqueues the message that is stored in the shift register.

 

The VI I have is large, so I can't post it easily.  If anyone wants a simplified version, I can make one up.

 

Thanks!

0 Kudos
Message 6 of 14
(5,077 Views)

wrote:

That case structure just holds an Enqueue Message VI, and it enqueues the message that is stored in the shift register.


Do NOT do the.  As I stated before, a QMH should never Enqueue to itself.  Just go to the state you put in the shift register in a timeout condition.  Use the Select function.


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 7 of 14
(5,060 Views)

Oh!  I see what you're saying now!  Use the timeout boolean as the "Selector" for either the repeated state or the next state.

 

I'll try that, thanks!

0 Kudos
Message 8 of 14
(5,056 Views)

OK, new problem (still related to this though).

 

In one of my User Event cases, I send a bunch of states to my queue at one time.  One of those states is this repeating state. 

 

Here's what I want:

Let's say I'm sending 5 states to the queue.  State 3 is the "wait" stage.  I want the state machine to run state 1, then 2, then 3 (repeat until condition is met), run 4, then run 5.

 

Here's what's happening:

I send 5 states to the queue, and it queues all of the states up at the same time.  So, it runs 1, then 2, then 3, then 4, then 5, then it repeats 3 until the condition is met.

 

I started looking at my method, and I found that in order for the "Dequeue" VI to time out is if it has zero states queued up.  So, it makes sense that the state machine would run through all of the states before coming back to the repeating stage.  Am I missing something?

 

If I need to make a simplified VI to show what I'm doing, I can.

 

Thanks!

0 Kudos
Message 9 of 14
(5,052 Views)

Just enqueue 1, 2, and 3.  Then in 3, you set the timeout state to be 3 until you get that condition and then you can set it to 4.  Then 4 can set it to 5.  5 can state to not timeout.  This way you can still receive messages and react to them even while waiting for the condition.


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 14
(5,008 Views)