LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Using a Queued Message Handler with a timed consumer loop

I'm trying to set up a queued message handler with a timed loop as the consumer loop. I want the consumer loop to execute a default sequence every second, and to sometimes execute a different sequence depending on the message from the producer loop. 

 

The thing is, the producer loop won't execute unless there is currently a message in the queue -- which is normally great, and by design, but not what I'm going for here. 

 

Currently, I have a workaround where I have three loops: The producer while loop, the consumer while loop, and a timed loop that sends the default command to the consumer loop once every second. The consumer loop is set up with a wait 1s function so that it executes once per second. Whenever the Producer loop sends a message to the Consumer loop, it sends it as a priority message so that it jumps ahead of these 'dummy' commands. 

 

It all functions as I'd like, but I don't love this workaround. Eventually, a lot of  dummy commands will accumulate in memory, and by using the 'priority' tag for all of my messages, I have no real way of sending a truly priority message. It works for now, but it's not robust. 

 

Is there a way to set up some sort of default state or default behavior with the queued message handler? e.g. "Repeat X every second unless I tell you to do Y instead."

 

I'd prefer a solution that still takes advantage of the message queue, so that the program may be easily expanded in the future, but I'm open to other workarounds as well. 

 

For context, the program is a control for two flow regulators. The producer loop includes chart updates and data recording that I want to repeat every second. The two other states change the setpoint of one of the flow regulators, then proceed with the rest of the chart updating and data recording. I could potentially separate this into two loops, but the data collection loop would still require information from functions that execute in other loops, so it would still be receiving messages, so I think it would still hang unless there's something in the queue. Maybe I'm wrong there? 

Message 1 of 7
(3,882 Views)

Would a timeout on the consumer loop solve your problem? 1000ms timeout, so every 1 second, it does one thing. If it gets a command, it does that command, the resumes timeout. You could even have a shift register for the timeout, so that it timed out sooner on the iterations that are a command.

Example:

  • Run
  • 1000ms: Timeout case, 1000ms timeout output
  • 2000ms: Timeout case, 1000ms timeout output
  • 2389ms: Command comes in
  • 2401ms: Command case finishes, calculates 599ms timeout output
  • 3000ms: Timeout case, 1000ms timeout output
  • ...

Cheers


--------,       Unofficial Forum Rules and Guidelines                                           ,--------

          '---   >The shortest distance between two nodes is a straight wire>   ---'


0 Kudos
Message 2 of 7
(3,879 Views)

Thanks so much for your reply! 

 

Using the timeout condition is an excellent suggestion, I hadn't realized its flexibility. I think I've come up with an even simpler solution based on that: 

 

I keep the consumer on its 1s timer, and use the timeout function to send the dummy command. This way, the dummy command is sent only if no other commands have been sent in that second. It won't accumulate in memory, as during program idle it will be produced once per second, and consumed once per second. 

 

Of course, the way I designed my UI Loop, it completes some other functions that don't send messages. I suppose I could set each of those to queue a dummy command. This could still cause accumulation, if two events are triggered within the same second, but it would be less of a problem than before. What I should really do is rework my architecture so that the UI loop only sends commands and doesn't do any legwork. 

 

But, assuming that each user event sends some message to the queue, there would be no issues with my solution of sending the dummy command with the timeout, right? I'm trying to think of circumstances where commands would accumulate in the queue, but I can't think of any. 

 

Also, your suggestion with the shift register is a good one, but I'd have to change the architecture of my program to get it to work correctly so that all of the timing was consistent for the data collection. As-is, in your example, my program would create a data point at 2 seconds, at 2.3 seconds, and at 3 seconds.  

 

I'm also considering separating the setpoint loop and the data collection loop, but I'd still need to pass a value into the data collection loop. I could do that with a property node and it would work how I want -- but is that good practice? I just want to make sure I'm not over-using property nodes or overlooking a more elegant solution. 

0 Kudos
Message 3 of 7
(3,846 Views)

I'm a little confused.  You seem to have the Consumer Loop, in its "default" case, driving the Producer loop, which then produces something that the Consumer loop "consumes".

 

Sounds to me like you have a three-loop situation -- a Timed Loop, whose only purpose is to drive the Producer Loop once/second.  A Producer loop, which generates some data that is handed off to ... a Consumer loop, which "consumes" the data from the Producer and then goes back to waiting for more data from the Producer.

 

Much simpler than having one "Consumer" loop trying to do two rather independent tasks -- the timing could get very tricky (which is why the suggestion of keeping the Timeout in a Shift Register was made).

 

You could probably simplify even more ...

 

Bob Schor

0 Kudos
Message 4 of 7
(3,829 Views)

Bob, my apologies, I mistyped earlier and flip-flopped producer and consumer, the context should read like this: 

 

"For context, the program is a control for two flow regulators. The consumer loop includes chart updates and data recording that I want to repeat every second. The two other states of the consumer loop change the setpoint of one of the flow regulators, then proceed with the rest of the chart updating and data recording. I could potentially separate this consumer loop into two loops, but the data collection loop would still require information from functions that execute in other loops, so it would still be receiving messages, so I think it would still hang unless there's something in the queue. Maybe I'm wrong there?"

 

So I do have three loops: A producer that is based off of user events, a consumer that repeats data collection and changes setpoints, and a dummy loop that repeats every 1s and populates the queue with default commands for the consumer to consume. 

 

Separating the consumer loops into two loops will solve most of my problem: One consumer loop to change the setpoints, and one timed loop to perform the data collection. I'm working on that now. This way, the timed loop will continue to execute because it's not waiting on the message queue, and I don't need any dummy commands. 

 

However, I'm still curious as to if there's a way to used the queued message handler directly with a timed loop. It seems to me that this will only work if there's always a message in the queue, else the timed loop stops to wait for a message. 

 

The way the queued message handler works, it seems as if the optimal way to incorporate a timed loop is with three loops: The usual UI Producer, a state machine consumer that executes the messages from the UI producer, and a timed loop independent from the queued message handler. Any values that need updating in the timed loop would then be passed in with property nodes, not using the message queue. 

 

Is this a correct way of interpreting LabVIEW's intended architecture? 

0 Kudos
Message 5 of 7
(3,707 Views)

You are using the Queued Message Handler as your Consumer (nothing wrong with this).  You have two Producers -- an Event loop that handles the Front Panel (Start, Stop, gain settings, etc) and a Timed Loop that actually takes the data (why not -- if you use DAQmx, you might not even need to use a Timed Loop, as you can let the DAQ device do the timing, in many cases) and generates the Message "New Data Point".  Now that I think about it, if your Message Handler is designed in a clever way, you could put the Data Acquisition right in the QMH, as long as none of the States take more time than "Get More Data" (if you do this, you might want to take data in "chunks", i.e. 1000 points at 1KHz, so you have a second between the time you need to call Get Mre Data).

 

Hmm -- I should try this out ...

 

Bob Schor

0 Kudos
Message 6 of 7
(3,661 Views)

Are you operating with the RTOS or FPGA?  If not, stop trying to incorporate the Timed Loop.  You're adding overhead without benefit.  Just use the While Loop.

0 Kudos
Message 7 of 7
(3,615 Views)