05-31-2019 10:02 PM
Hi,
I have the following problem: I created a data acquisition application that runs the data acquisition in a producer loop and passes the data to the consumer loop, main VI that offers all the controls to the user. Data is passed via a Queue. However, I would like to be able to control the producer loop via the consumer. Specifically, the user should be able to stop the producer from the front panel of the main VI. Therefore, he should be able to change the number of data readouts or abort the acquisition. For this, I used a channel wire that allows to update the abort condition of the producer loop from the consumer loop dynamically. However, I have now the problem that I can't run the producer VI anymore independently. Do you have any idea how to make it possible that the producer loop VI can be run as top-level VI? For the data pass queue, I found a solution by using the "Not A Number/Path/Refnum? Function" VI. But how can I deal with the channel wire?
If this is not possible, are there other structures which offer me the functionality I need (and described above) that allow to run the VI independently?
Thanks a lot for any hints!
Peter
05-31-2019 10:18 PM - edited 05-31-2019 10:31 PM
Hi,
Although not a great solution, the simple answer is to have the controlling VI exit its own loop then force close the queue reference. This will cause an error in the other VI's loop when it next tries to use the queue function, which you can connect to the stop condition in the loop.
This is not great because generally it's not an amazing idea to cause errors for normal operations (i.e. stopping). A more robust/safe method might involve using multiple queues and a state machine. You could use one queue to pass the data from producer to consumer, and another queue to pass instructions (perhaps using a typedef'd enum) from your master to the slave (whichever way round you wanted to do this).
You can also then implement (consider using the Not a Queue function you already used) some alternative method of control for the Producer, if you really want this to act as the slave.
A possible example is attached - obviously you could extend this to use more than just a STOP message (and rearrange it to avoid the Case Structure) - I chose to use the CS and String rather than Enum to avoid subVIs or typedefs for the forums.
06-01-2019 01:17 PM
And consider using dynamic events, using as a datatype a cluster of a typedefed enum and a string or variant as dynamic data. You have to register this event in your producer loop, doing all default stuff in the timeout case, with timeout set to zero. From the consumer loop you can send the event with the enum value set to 'stop' or set to 'Set_Aq_Speed' with the actual speed value passed in the dynamic part of the cluster.
I use this a lot and it works very well, LabVIEW handles these events very fast.
06-01-2019 01:21 PM
I think you don't understand the idea of the Producer/Consumer Design Pattern. There may be exceptions to what I'm about to "generalize", but these can (probably) be dealt with easily:
Here's a Snippet of a Producer/Consumer governed by a Stop Button (in an Event Loop, itself a kind of "Producer"). The Producer is simulating a DAQ Device reading a sinusoid, 100 samples at 1 kHz, and sending its output to a Consumer for plotting in a Waveform Chart. Note that the Stop Button is used to stop the Event Loop and (via a Tag Channel) stop the Producer (and signal the Producer to stop the Consumer).
The attached VI is in LabVIEW 2016, so any version supporting Channel Wires should be able to run it.
Bob Schor
06-01-2019 03:59 PM
@pegli wrote:
However, I would like to be able to control the producer loop via the consumer.
You really don't want to do this. If you're starting down that path, stop. Step back. Breathe.
You're looking for ways to control the producer loop. Add that logic to the producer loop. It looks like you're ultimately running into issues where you're acquiring large amounts of data at once and wanting the user to be able to stop that. If that's your actual issue, this isn't something you'll solve cleanly by trying to use the consumer loop to perform this action.
In order to provide meaningful advice, it'd help to understand what your goal is with respect to acquisition. What are expected durations of acquiring? I didn't poke the VI here too much as I'd expect it to be butchered a bit to try to make the circular control thing take place.
06-02-2019 10:53 AM
To followup on @natasftw's notion of guarding against a gross mis-match between Producer and Consumer speed, it is easy to modify the Demo I presented to cause everything to shut down if the Consumer gets too "backed up". I'm going to leave this (in part) as an "Exercise for the Reader", but here are some of the steps you could take:
Bob Schor
06-03-2019 01:43 PM - edited 06-03-2019 01:46 PM
I differ with several responders in that I *don't* particularly think you're on the wrong track.
Much as cbutcher already covered in msg #2, I think the Queued Message Handler (QMH) is a well-accepted architecture that I often use in ways much like you describe.
I tend to have one top-level "main brain" loop and several simpler, single-purpose loops for things like instrument communication, data acq, file logging, etc. Each loop has its own queue to receive messages or commands.
The top level loop is both a "master" (in the sense of coordinating all the other loops) and a "consumer" (in the sense that it receives all the instrument and DAQ data).
I've often set up data acq loops that are both "producers" and "slaves". As a slave, it receives and acts on messages/commands such as "Init", "Exit", "Start Data Acq", "Stop Data Acq". When data acq is active, it primarly acts as a producer, regularly sending data back to the main loop.
So in this way, I see no conflict about the idea of a consumer loop (my main brain loop) that controls a producer loop (my data acq loop) by telling it when to start, stop, and exit.
-Kevin P
P.S. There's a shipping example of a QMH project template available to study or use. You can open it from the menu "File-->Create Project..."