LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Upating front panel with shared variable in a consumer/producer loop

Hi,

 

I'm developing a new program for our DAQ. Since it is very event heavy, I decided to go with a producer/consumer loop. One of the issues I've run into is I need to be able to constantly monitor a gauge (and update on the front panel) while running other parts of the code. I decided to use an async. sub-VI to keep the monitor code running, and shared variables to communicate between the main program and the sub-VI. I found a solution to update the front panel in the main VI. I don't particularly like it, but it works. Essentially I put the front panel items that need updated in the consume while-loop but outside the event part and force the code to constantly run the consumer loop via an empty event called "Wait for Command" (this follows an NI example). One area this will approach will fail is when I'm constantly collecting from my cameras. The obvious fix for that would be pasting in the update bit into those loops, but... that feels messy.

 

I have to implement 1 or 2 more elements that will also require this capability. I'm pretty new producer/consumer loops (and Labview programming). I've attached a copy of the code.

0 Kudos
Message 1 of 10
(2,986 Views)

Attach an actual zip file so that no one has to download a 3rd party application to open a rar file.

0 Kudos
Message 2 of 10
(2,931 Views)

What you have here is a bastardization between a Queued Message Handler and a Queued State Machine.  Essentially, you need to decide who can enqueue states: the consumer loop or everybody else.  You will run into very weird race conditions if you mix the two like you currently have.  In my opinion, you should be using the Queued State Machine and just add a state that you need to return to in order to check for messages/events and handle them as needed.

 

I am also not a fan of your use of Shared Variables, especially Network Published Shared Variables (anybody on the network can update them).  If all you want is to update your GUI, then use User Events to send messages to your GUI loop (the one with the Event Structure).  You can then update whatever indicators with data from the events.

 

Ultimately, I think you need to break up your code into more loops.  I like to have each instrument be in its own Queued Message Handler so that it can constantly be reading data (use the Queue's timeout) and sending updates independently of everything else.  You can send them messages to update settings, stop, do a capture, etc.

 

And digging into your GetFlow.vi, DO NOT USE THE BYTES AT PORT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! (not enough emphasis).  Your device appears to be using a termination character, so use that to your advantage.  Just tell the VISA Read to read more bytes than you ever expect in a message and the read will stop when the termination character (defaults to the Line Feed character) is read.  This ensures you read a full message.  This will also eliminate the need for the wait you have in there, making your code more efficient.

 

So that was my 2 minute analysis of your code.  Please learn from the same mistakes I have made.


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 3 of 10
(2,905 Views)

Add me to the list of "not-a-fan" of Shared Variables but since you wrote...

 

"

 constantly monitor a gauge (and update on the front panel) while running other parts of the code. I decided to use an async. sub-VI to keep the monitor code running, and shared variables

"

You can right-click the gauge and got to the data Binding tab and select the shared variable.

 

"look Ma, No Wires!"

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 4 of 10
(2,897 Views)

@NI

 

Hmm can you explain more about a Queued Message Handler vs. Queued State machine? I assumed I'd avoid race conditions by using the que system. Is this because I put the "update front panel" items in the general while loop and not in a specific event (like the "Wait for Command"? That is an easy enough fix to move it, but I didn't want to have to return to "wait for command" after every other "command" that comes in.

 

I actually didn't intend for the shared variables to be network published, though the computer isn't on an network. But that I have already fixed. I wasn't sure how else to constantly update the variables, unless using a Global variable, and tbh I'm not 100% sure of the difference. It seemed like Shared Variables were limited to my project and so I chose those over the globals.


And thanks for the byes at port. Some of this code is legacy from our existing DAQ system (which makes this look pretty and optimized).

 

Thanks for the advice! And definitely trying to learn and optimize this. I'll also look at using more loops as you suggest.

0 Kudos
Message 5 of 10
(2,864 Views)

Hmm...what do you suggest over share variables? And I'll look at the data binding.

0 Kudos
Message 6 of 10
(2,861 Views)

@plasmageek wrote:

Hmm can you explain more about a Queued Message Handler vs. Queued State machine? I assumed I'd avoid race conditions by using the que system. Is this because I put the "update front panel" items in the general while loop and not in a specific event (like the "Wait for Command"? That is an easy enough fix to move it, but I didn't want to have to return to "wait for command" after every other "command" that comes in.


Start here: Difference between QSM and QMH?  The race conditions is more of what state gets enqueued when and where.  It most commonly becomes an issue when trying to shut down.  One trick I have seen is to dequeue from the message queue every iteration of your loop.  Let it have a timeout of 0 (immediate).  If you time out, then progress in your state machine as normal.  If you have a message, do whatever you need to with it, which could include clearing your state queue and/or adding new states.


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 7 of 10
(2,797 Views)

Ok, after reading that post I thought the issue was that both of my loops are queuing items. But then I started looking for more examples and now I'm confused again. I originally started this based off an example NI gives out for prepping for their exam, which is similar to this example I found in the forums:

https://forums.ni.com/t5/Example-Program-Drafts/Queued-State-Machine-with-User-Input/ta-p/3497450

 

I also tried remove the Byes at Port and just putting in a number for the bytes, but it made that section run really long (for a large number) and error out no matter what number I put in....

 

I've also added the .zip version for the person who asked (new name, but not too much has changed).

0 Kudos
Message 8 of 10
(2,723 Views)

@plasmageek wrote:

I also tried remove the Byes at Port and just putting in a number for the bytes, but it made that section run really long (for a large number) and error out no matter what number I put in....


Are you attached to the DAQ system?  If not, you will get timeout errors.  In the old way, the Bytes At Port would return 0 and then your code would read 0 bytes and move on quickly.

 


@plasmageek wrote:

Ok, after reading that post I thought the issue was that both of my loops are queuing items. But then I started looking for more examples and now I'm confused again. I originally started this based off an example NI gives out for prepping for their exam, which is similar to this example I found in the forums:

https://forums.ni.com/t5/Example-Program-Drafts/Queued-State-Machine-with-User-Input/ta-p/3497450


Well, that is not technically an example from NI.  And it is a poor example because of the reasons I already stated.


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 9 of 10
(2,667 Views)

Yes, I am attached to the DAQ. As soon I put the Bytes at Port (which puts out a few different numbers) back it worked.

 

I just posted the forum post as an example. NI has a CDL success package and one of the problems in that uses the same practice (it's what I based my program on). So there's some question about what's considered good or bad practice. Since only one queue can be run at a time, it seems that if you put things in order, you'll always have the order you want and no race condition can occur. Granted, putting as many of the enqueues in the top makes my bottom a bit cleaner, which I'm always for.

 

But back to my original post. It seems unclear to me that there's a better approach to constant real-time monitoring and interactions between parallel loops then what I've implemented?

0 Kudos
Message 10 of 10
(2,392 Views)