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: 

Multiple producer one consumer

Solved!
Go to solution

 


@Mark Yedinak wrote:

You can but you will basically turn it into a polling loop since you will need to use small timeouts so both queues can be checked. However I don't know why you can't use a single queue for the producer. Each consumer posts its message to the single queue and you process the data in the order they were queued. If you truly need the data streams to be independent then you may need to have a processing task for each data stream.

 

As someone mentioned earlier, if you need to identify the source of the data then create a message structure that includes that as part of the data. Your processing task can then take different actions based on the data source.


 

@ Mark: The reason I have two queues is that the data I receive on COM (Serial port from another computer) Producer1 is different from what I read on Producer 2 and the rates are different. I really don't know where to begin trying to synchronize them. (Although I think It can be done. I will tthink abt it)

 

Also, I would like to confirm that data from Producer 1 is the "action" data. Action is performed in Consumer loop based on data from Producer 2. Hope this makes sense.

 

@ Lynn

 

I would like to elaborate more on what I am trying to do, so that you can better judge my trials.

 

The COM port is for 2 way communication between two computers. One computer runs the LabVIEW code and the other computer runs another software that sends commands/status requests and expects "Acknowledgements" .

 

In the code I attached, I am not sure if you can see the subvi after the dequeue of Q1, but that code decides which of the two case structures to run. I either receive a command directive or a feedback directive from the software and both expect ACKS to be sent through the same port. A command will run the first case and a feedback or status request will run the second case structure. Both case structures are mutually exclusive and so are the case structures inside each of them.

 

In effect for each command or status request, the software requires an ACK so that it moves to the next command/ status request. eg. A430303130A330303137C0C1C2 means A4 is a command followed by data 30303130 which in decimal is 10 and A3 is a command followed by 17 in decimal. Now for each of these commands I send ACKS immediately B4 and B3. Status requests are made all the time (except when command orders are sent) so C0C1C2 keeps going on. I keep sending D0   D1 D2 as ACKs. unless I send an ACK, I dont get the next command. Hence, the different case structures.

 

The VISA read inside 163 and 164 is to read the Data following the command as shown above. Basically, the case structures can be said to be COMMAND case structures. For each command, a case is executed and inside each case I do what is appropriate. So is the FEEDBACK case structures.

 

The Boolean CASE=FALSE never occurs. I just put that there for testing. In my application, whatever command/ststus request I get from the COM port, I add it to the queue.

 

The different error wiring: I use the same port to send ACKs, two case structures being mutually exclusive, I get error from just one at a time. Hope this makes sense

 

I know there is too much to read. But, I hope my point is made clear. Otherwise, I have to come up with a better way to explain. A diagram perhaps?

 

V

 

 

I may not be perfect, but I'm all I got!
0 Kudos
Message 11 of 46
(2,076 Views)

 


@Mark Yedinak wrote:

I took a look at your code and you might run into problems with the various ACK messages you send. You send them in parallel based on the data you read. However, there is no guarantee which one will get sent first. If you need to make ensure the order of the ACKs then I don't think you want to process the receive data in parallel like that. Also, as previously noted your consumer loop will ONLY operate when there is data at BOTH queues. For a given consumer task I prefer it to use a single queue and define a more generic message structure that will allow multiple producers to post data of differing types. If you have a limited and finite set of data types you can use a typedefed cluster. This will mean that for each message one or more elements of the cluster will have no meaning. You could use a variant as the data type and the message ID will indicate how that data should be interpreted. If you want to use a LVOOP solution you can define a base message class. Part of this again is the ID. The children classes would have the necessary methods for dealing with the specific messages and data types. Then your elements are an instance of the message class.


 

Part of the problem in people understanding my vis is that I don't elaborate on what I am trying to do. (Or it is difficult to say everything:) 🙂 ) Anyway, I would like to clarify that only one ACK is sent at a time. The two case structures are multually exclusive. The subvi after the dequeue of Q1 decides which case structure to run. either the COMMAND case structure or the STATUS request/ FEEDBACK case structure. Both dont run at the same time. When COMMAND case structure is TRUE, FEEDBAK case is FALSE and vice versa.

 

ANd, what you said regarding typedef cluster is over my head. Would you be able to simplify??

I may not be perfect, but I'm all I got!
0 Kudos
Message 12 of 46
(2,071 Views)

A single state machine can achieve what you want abd would be much easier to read. The subVI which triggers one of two parallel case statements is a very confusing code construct. Also, I suggested a way you can use a single queue with message containing different types of data. This is actually very easy. The easiest and most direct approach is to typedef a cluster with two elements. The first element is the message ID. This can be a string or a typedefed ENUM. The second element is a variant. When you post a message you assign the correct message ID and convert the data you have, which could be a string, a single number, an array, a cluster, or whatever to a variant and assign it to the data element of the message cluster. The receiver would invoke the correct case/state for the given message. Since it knows the type of data associated with that particular message, use the From Variant VI to convert the data back to the correct data type.

 

I don't think your consumer loop will work the way you want now using the two queues. You will only process data IF and ONLY IF both queues have data. Using a single queue you will always process data that is available and your state machine (actually message processor) would handle the messages serially as they arrive.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
Message 13 of 46
(2,071 Views)

A0 through A4 are commands which require B0-B4 as ACks. C0 through C4 are Feedback requests and D0 through D4 are it's corresponding ACKS.

 

The subvi receives the incoming code and compares whether it falls in the A0 through A4 group or C0 through C4 group. If in A0 - A4 group, it sets Command Boolean = TRUE and FEEDBAK boolean = FALSE . hence first case structure runs and the second one doesn't. and vice versa.

 

Actually, both queues always receive data. Both queues will never be empty until the end of the program when I dump them.

 

To squeeze data from two producers into a single queue makes sense, but will take time for me to understand the rigours of it, since I have two different rates, two different sets and no idea on how to synchronize or is there a need to synchronize. I guess before I think of one queue, I must analyse the data I receive from two producers.

 

So by what you say, I can ID data coming from different producers at Dequueue??

 

Thanks a lot btw, I am really getting into modifying my architecture from my existing "passing REferences" method,.

 

V

I may not be perfect, but I'm all I got!
0 Kudos
Message 14 of 46
(2,067 Views)

Here is an example of the type of message cluster I mentioned. This was an example I posted a while back for someone so it doesn't exactly match your particular application but it illustrates the concepts I was suggesting.

 

You only need to look at the specific command and set the next state to the appropriate command processing state. The mutually exclusive parallel case structures ARE A VERY BAD WAY to go. Even if both queues will be receiving data your consumer loop will only run as fast as the slowest queue. It the slow queue posts one message per minute and the other 100 per second, your consumer loop will only run once per second. I realize this may be an exageration of your specific case but I am using it to illustrate my point. A single queue will run as fast as it can as long as there are messages. The only gating factor will be the execution time for the slowest state.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
0 Kudos
Message 15 of 46
(2,061 Views)

Are you talking about the parallel error case sturctures or the parallel case structures in error structure 1?

 

Also, I was thinking if this method would work! All I am doing is updating front panel controls with data received from two queues. Would the following implementation work? Please refer attached template vi.

 

You program is complicated, but I am looking at it more carefully.

 

V

 

Oh I will have to make sure to stop the loops appropriately. This is just a template. I know that I will have to synchronize that so that all the loops end when the program ends or an error is noticed.

I may not be perfect, but I'm all I got!
0 Kudos
Message 16 of 46
(2,046 Views)

Based on my understanding of your application I am not sure this would accomplish what you want. What controls your "action" loop? You certainly don't want it to be a free running loop polling values of front panel controls. If both of your consumer loops are simply updating the front panel, but with data from different sources, then a single state machine is all that is required. The message sent to it would contain all the necessary information you need to upate the front panel. UI interaction, such as detecting a value change, is best handled using an event structure. Polling is never a good option.

 

Take some time to understand the code I posted. It actually has all of the necesary pieces you need to build your application with the exception of the VISA read and writes. Adding those is really just a matter of creating a couple of tasks.

 

In your application will the device always be sending data to you and based on that you will decide what processing and ACKs are sent? Or is it more of a command/response system where the device is only sending data in response to a command? If it is the first case then you will probably want one task (one loop) that is reading the data continuously and posting the messages to a queue. If the second case is true then you should place both the read and writes in a single state machine.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
0 Kudos
Message 17 of 46
(2,035 Views)

 


@Mark Yedinak wrote:

Based on my understanding of your application I am not sure this would accomplish what you want. What controls your "action" loop? You certainly don't want it to be a free running loop polling values of front panel controls. If both of your consumer loops are simply updating the front panel, but with data from different sources, then a single state machine is all that is required. The message sent to it would contain all the necessary information you need to upate the front panel. UI interaction, such as detecting a value change, is best handled using an event structure. Polling is never a good option.

 

What controls my application is the 3rd party software; the command coming in from the Serial port (Or Producer 1) . If I want speed to go to 2mph, the 3rd party software will send that command with 2mph value through the serial port. I read that and update the Speed control in LabVIEW front panel to 2mph. Now, the "action loop" will read or poll the control and when it sees 2mph, it sets the corresponding analog output  on the DAQ to update the motor speed to 2mph. If no command is read, then what evervalue is on the control, that's the speed the motor runs. Now, to start the test, if I see A0 on the Serial port which means Start Test, I go into Start Test state of SM and stay there until I see A2 or Stop test on the serial port, in which case I go into Stop case of SM. During Start test state, I constantly poll Speed control to see any change in value. ACK's are sent with feedback values from indicators on Front panel through the serial port back to the display of 3rd party softwre.. Feedback is calculated in the SM.

 

My LabVIEW application is an intermediary between the 3rd party software and my device because my device currently uses NI products and the 3rd party software is not in LabVIEW.

 

In your application will the device always be sending data to you and based on that you will decide what processing and ACKs are sent? Or is it more of a command/response system where the device is only sending data in response to a command? If it is the first case then you will probably want one task (one loop) that is reading the data continuously and posting the messages to a queue. If the second case is true then you should place both the read and writes in a single state machine.

 

based on the state of the system, I send ACK with feedback values. The system is more like a command/ACK and status check/ACK system. meaning there is a constant request from the 3rd party software for Status of the device.

 

The 3rd party sends commands in two forms: One is a command to do something and one is a command requesting status of the device. Both require separate ACKS and I send them based on my processing.

 

So, eg. for 2mph, a command is sent and I tell the device to go 2mph.. While the required state is being reached, I constantly update the status back to the software. So, I guess I am right in posting messages to the queue continously.


 

I may not be perfect, but I'm all I got!
0 Kudos
Message 18 of 46
(2,027 Views)

When I asked what was controlling your "action" loop I was refering to the LabVIEW application itself, not really the specific command from the device or whatever. Polling loops are generally not the best way to do implement something. The do take extra processing time for no work. Event driven systems are much more efficient. You can achieve event driven systems using the event structure or by using queues/notifiers. Your application sounds fairly straightforward and could easily be accomplished using a single state machine to handle most of your communications. It doesn't sound like you need to continually poll the status of the one device. From what you described you only have to check its status after you have received a command and are waiting for some operation to complete (change speed from 2 MPH to 3 MPH) or when specifically requested for a status update. Unless you are performing background processing based the status of the device there is no need to communicate with it unless directed to. Your default state would be to check for messages from the 3rd party application. Once you receive a message process it. This may require your application to monitor the status of the device until a desired state is met. Once there, you simply go back to listening for messages from the 3rd party application. It sounds like some operations may require you to actively communicate with both the device and the 3rd party application at the same time, such as reading the status of the device and relaying that back to the application. In this case your state machine would iterate over those states. (Get Status from device, send update to application, repeat until condition met.)

 

Unless a user is looking at the front panel of your application there is no need to have a bunch of controls and indicators. You can maintain state information in shift registers. These wires would pass through your state machine. With two-way communication it is generally a good idea to keep both your read and writes within the same state machine/task. This is especially true in a command response type of communications. If you have them in separate tasks it is fairly easy to have the messages get out of sync.



Mark Yedinak
Certified LabVIEW Architect
LabVIEW Champion

"Does anyone know where the love of God goes when the waves turn the minutes to hours?"
Wreck of the Edmund Fitzgerald - Gordon Lightfoot
0 Kudos
Message 19 of 46
(2,017 Views)

Hi Mark,

 

I am trying to have the consumer loop as the state machine itself and dequeuing elements inside the SM while loop, but here is where I face problems.

 

THe data coming in on the serial port has both commands and values. There is no way to distinguish between them unless I do some comparison with values coming in. For eg.  A0A430313030A330303005C0C1C2C0C1C2C0C1C2 and so on...

 

The above stream should be split as (A0)(A4) 30 31 30 30 (A3) 30 30 30 35 (C0)(C1)(C2)(C0)(C1) .... The hex in brackets are commands and ones without brackets are values, i.e. 30 30 30 35 = 0.5 mph. A0 says start, A4 says change elevation, A3 says change speed . What I am unable to do is just have a queue with commands and no data.. Meaning, a queue with just A0 A4 A3 C0 C1 C2 C0 C1 C2 etc..... somehow, I have to separate out the master queue and make a command queue to change states on my State mAchine.

 

The thing is, I already have a LabVIEW vi that can run my device without the third party software. Like Boolean controls to start tests and numeric controls to update speed manually. With this integration, I am receiveing commands on Serial port and for eg. if I see A0, I make Start Boolean = TRUE and the values that accompany A3, I convert them to decimal and use property node to update speed controls. I am not inherently using A0 to start the test if you know what I mean.

 

I hope this makes sense. Please let me know. I could send my vi for your opinion as well. I really appreciate it. I am trying to understand this architecture. Thanks!

 

V

I may not be perfect, but I'm all I got!
0 Kudos
Message 20 of 46
(1,976 Views)