LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Requesting Assistance on Design Structure for Moderate Sized Application (Top VI)

DISCLAIMER: First post, have a lot to say 🙂

 

Hello fellow Labview developers, students, and teachers. I have been using Labview on and off over the past year at a defense tech company; I've helped automating box level test sets for radar and automating board level test sets for acceptance testing. I am working on my first program that is entirely my own, so I made sure I went back and made sure my fundamentals were solid. I completed training core 1 and 2, and have read through a solid chunk of core 3. Ton's of great info that I incorporated into my program. I will now give a quick program overview for you guys before asking a few questions.

 

The aim for the program is run a specified test (most of the individual test code has been completed, e.g. a receiver test in which I communicate with a signal generator and the board and check linearity across the dynamic range) and format the data appropriately for a datasheet, all while logging system status with info from constant polling of the board. Implementing this gave me great insight into how to use parallel loops, tricks to prevent read-write-modify issues such as FGVs or encapsulating primitives into non-reentrant VIs, etc.

 

I have created a write config and read config VI.. the Read config VI reads from a config.ini text file which contains the VISA profiles and global constants and writes them to the programs globals. I want the user to be able to press a config button on the main vi front panel, set values for the controls which are the visa profiles and globals, have the values written to the globals, and then write the globals to the config file so its saved for next time the program is ran.

 

I've read that you should stay away from multiple parallel loops in one state, and stay away from multiple event structures in one loop. This was why I put the save graph function in its own unique loop and event structure. Also, its why I am hesitant to keep this structure and throw it into a state machine, with states being Idle, Config, Test&Log, and Done. OR, is this fine and how I should structure this program? (After thinking this through again, I will probably go this route if there aren't any objections).

 

Some other tidbits, I have been reading about different ways to control loops and stop them from a master button or loop. Currently, I have a master stop control directly connected to the test loop stop terminal, and there is an event structure in the other loops that checks for a value change on that master stop control, and then output a True to their loop stop terminals. Is this proper? Or should I possibly use a notifier setup?

 

In terms of one button dialogue true output being used to drive a case structure, is this OK? Or is an event structure better? Most of my tests for the receiver have to look at multiple channels, and I prompt the user to connect to the next channel with a one button dialogue, and the test only enters the test command loop once the button is pressed. I was curious about any issues this may have associated with it.

 

I chose to just share an image since I would have to clean up specific job info before upload, and I believe you guys can answer my questions off an image. I am willing to take recommendations on anything I did not mention as well, such as error handling. Thank you for your time, and I look forward to discussion and learning.

 

0 Kudos
Message 1 of 14
(2,516 Views)

I really hate looking at images unless (a) the Image has no "hidden" parts (i.e. no Case Structures) and (b) the Image components "look big" (I don't have sophisticated Image Viewer software that lets me blow up parts of your Image so I can read it).  So these comments are more "generic".

 

I recommend that you take a look at the Queued Message Handler example that ships with LabVIEW.  Open LabVIEW (almost any recent version), click "New Project", and look for Queued Message Handler in the right pane.  You might find that your program fits this design nicely.  Note that if you have independent processes, you can also have independent QMHs (you just need to think who generates the Messages).

 

When stopping a routine with multiple loops, a technique that I use is to have a single "Stop" button in an Event loop that (in the case of Message Handlers) sends a Stop Message to QMH-1.  When QMH-1 process the Stop message, it sends its own Stop requests to any parallel loops that it is controlling.

 

In the case of a Producer/Consumer pair of loops, the Producer generally "knows" when to stop.  What it does is stop its loop, and then send to the Consumer a "Stop" command (leaving the Communication Path intact!).  The way to do this is to use a "Sentinel", a special "reserved" datum that means "Stop".  For example, if you are sending an Array of data to the Consumer, send an Empty Array.  The Consumer checks for this Sentinel -- if present, it knows not to process any data, but to stop itself (and, if necessary, destroy the Communication Path), otherwise it "consumes" the data.

 

If you have LabVIEW 2016 or higher, you might look at Asynchronous Channel Wires, which were designed to allow communication among and between parallel loops.  I use them all the time, including as the mechanism (instead of Queues) for the Queued Message Handler (I call this the Channel Message Handler).

 

Bob Schor

Message 2 of 14
(2,483 Views)

1. I much prefer having all of my GUI handling done in a single loop (my GUI loop).  All it has in it is an event structure to handle all of the controls.  I often will also use User Events to send data to this loop from parallel loops/VIs in order to have it update indicators.

2. If you are constantly polling data from an instrument, you really should look into putting all interactions with said instrument into a parallel loop.  The design of this loop should be similar to a QMH, but use the timeout of the queue to perform a periodic task such as read status.  Send the status to somewhere (typically the logging loop) via a User Event or Queue.

3. For your logging, you should really get away from using the Write To Delimited Text File.  By using that VI, you are constantly opening and closing the file.  That will make your loop SLOW.  Open the file before the loop and close it after the loop.  You can write inside of the loop all you want.  Use the Array To Spreadsheet String in order to format your data the same as what you currently have and then the Write To Text File to write to the file.

4. In my opinion, only the GUI loop should be dependent on the front panel.  Every other loop should be able to be turned into a subVI and still work just fine.  As was already stated, the Queued Message Handler (QMH) is your friend.  If you want to dive into the deep end by adding Object Oriented Programming (OOP), have a fun look at the Actor Framework.


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 14
(2,481 Views)

My apologies for the image, it was my best bet for quick turnaround. I would have had to scrub more and check with someone who wasn't around.. I will certainly upload actual VI's in the future, and I will for this one Monday if its beneficial. 

 

I sincerely appreciate the reccomendations.. I will check out the QMH example. The other tidbits about producer consumer and sentinels was interesting too. In terms of asynchronous channel wires, it looks like they are definitely worth exploring. I have some work to do!


@Bob_Schor wrote:

I really hate looking at images unless (a) the Image has no "hidden" parts (i.e. no Case Structures) and (b) the Image components "look big" (I don't have sophisticated Image Viewer software that lets me blow up parts of your Image so I can read it).  So these comments are more "generic".

 

I recommend that you take a look at the Queued Message Handler example that ships with LabVIEW.  Open LabVIEW (almost any recent version), click "New Project", and look for Queued Message Handler in the right pane.  You might find that your program fits this design nicely.  Note that if you have independent processes, you can also have independent QMHs (you just need to think who generates the Messages).

 

When stopping a routine with multiple loops, a technique that I use is to have a single "Stop" button in an Event loop that (in the case of Message Handlers) sends a Stop Message to QMH-1.  When QMH-1 process the Stop message, it sends its own Stop requests to any parallel loops that it is controlling.

 

In the case of a Producer/Consumer pair of loops, the Producer generally "knows" when to stop.  What it does is stop its loop, and then send to the Consumer a "Stop" command (leaving the Communication Path intact!).  The way to do this is to use a "Sentinel", a special "reserved" datum that means "Stop".  For example, if you are sending an Array of data to the Consumer, send an Empty Array.  The Consumer checks for this Sentinel -- if present, it knows not to process any data, but to stop itself (and, if necessary, destroy the Communication Path), otherwise it "consumes" the data.

 

If you have LabVIEW 2016 or higher, you might look at Asynchronous Channel Wires, which were designed to allow communication among and between parallel loops.  I use them all the time, including as the mechanism (instead of Queues) for the Queued Message Handler (I call this the Channel Message Handler).

 

Bob Schor


 

0 Kudos
Message 4 of 14
(2,466 Views)

@crossrulz wrote:

1. I much prefer having all of my GUI handling done in a single loop (my GUI loop).  All it has in it is an event structure to handle all of the controls.  I often will also use User Events to send data to this loop from parallel loops/VIs in order to have it update indicators.

2. If you are constantly polling data from an instrument, you really should look into putting all interactions with said instrument into a parallel loop.  The design of this loop should be similar to a QMH, but use the timeout of the queue to perform a periodic task such as read status.  Send the status to somewhere (typically the logging loop) via a User Event or Queue.

3. For your logging, you should really get away from using the Write To Delimited Text File.  By using that VI, you are constantly opening and closing the file.  That will make your loop SLOW.  Open the file before the loop and close it after the loop.  You can write inside of the loop all you want.  Use the Array To Spreadsheet String in order to format your data the same as what you currently have and then the Write To Text File to write to the file.

4. In my opinion, only the GUI loop should be dependent on the front panel.  Every other loop should be able to be turned into a subVI and still work just fine.  As was already stated, the Queued Message Handler (QMH) is your friend.  If you want to dive into the deep end by adding Object Oriented Programming (OOP), have a fun look at the Actor Framework.


Thank you very much for your insight and tips! 

 

1. Makes sense, I was beginning to stray away from keeping it simple and smart. I need to look into user events again and really cement my understanding.

2.All of the status polling occurs in the upper loop at this point, which I made parallel to my testing loop. I pass the polled data from the sub vi in the bottom left corner (which i diagram disable structured out due to it having a sensitive name) and then displays it as an indicator on the main VI front panel, and associates a time stamp with the entry and writes to delimited text file. Besides the write to delimited text file part, are you saying that this format isn't ideal? The event structure inside is designed to toggle the timeout based on a polling switch, so that polling of status can be disabled by 'pausing' the loop.

3. Rookie mistake, I should have been using lower level VIs, I didnt realize that it was constantly opening and closing the file. Will fix! 

4. I really want to make sure I am understanding the concept. the GUI loop, really should be the top VI loop, and any parallelism should occur a level below (at least) and can and should be represented as a sub VI?

 

I have another question about accessing the same communication path from parallel loops. Polling as well as some test related commands are sent and received over a serial connection with the board, communicating with a bare metal sys control C program. Therefore, I was concerned that data would be lost from either test commands/data or polling info. So, I encapsulated all my a visa read, write, and flush into a subvi that is non-reentrant type, called Serial Comm. It is a simply a case structure with error in out, enum type for read, write, flush and read string in and out for writing or reading. This is to prevent simultaneous read/writes from occurring in separate loops. Thoughts? There wont be any issues from the testing end with a command being slightly delayed, nothing is timing critical.

0 Kudos
Message 5 of 14
(2,462 Views)

@TommyElectric wrote:

I have another question about accessing the same communication path from parallel loops. Polling as well as some test related commands are sent and received over a serial connection with the board, communicating with a bare metal sys control C program. Therefore, I was concerned that data would be lost from either test commands/data or polling info. So, I encapsulated all my a visa read, write, and flush into a subvi that is non-reentrant type, called Serial Comm. It is a simply a case structure with error in out, enum type for read, write, flush and read string in and out for writing or reading. This is to prevent simultaneous read/writes from occurring in separate loops. Thoughts? There wont be any issues from the testing end with a command being slightly delayed, nothing is timing critical.


Yep, done that plenty in my time as well.  It does not exactly scale well though.  For instance, maybe you need that poll data in multiple places (logging loop, data processing loop, error checking loop, GUI loop, etc).  It does not make any sense for all of those loops call the same subVI to constantly request the data.  This is where I got into the mode of using a loop that does all of the communications with the instrument and sends out any measured data using whatever method is reasonable.  In the exact application I am thinking of, I use an User Event.  If you only care about the latest data, then a Notifier would work as well.


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 6 of 14
(2,409 Views)

A good template to start from is the Queued Message Handler template.  It comes with built in central error handling and has a project builder helper to get started.  You can then add loops for monitoring instruments etc.  

 

From the LabVIEW start screen, click on Create Project>Queued Message Handler

 

 

Message 7 of 14
(2,393 Views)

Hey guys, I have reviewed the QMH design architecture and have started the QMH template and have migrated my sub VIs to this new project. I am a bit unsure how to continue though. Based on the application I described, should I have 1 EHL (GUI) and 2 MHLs; one for logging and one for testing, or should I have at least 3, the additional being a system manager or UI loop?

 

Few notes:

- I edited the obtain message queue VI to have a control input for queue name so I can use queues via name reference instead of wire.

- I want a configure pop up window (I believe this can be taken care of via VI property/invoke nodes to control the window). The configuration sub vi must be ran before logging or testing, as it loads info from config file, and then has the user make possible edits to VISA references and globals. I was considering having the UI MHL have a config state, with logging switch and start test button disabled and greyed out until config is ran. Following the config state, I will have a serial connection init state, that uses the board visa reference. I want this reference available to the logging  and testing loop as well, whats the best way to pass around the visa reference to parallel loops?

- in the QMH template, why is the reg events error out and the create all message queues error outs merged into the UI Loop? Is this because the primary message handler loop acts as the brains in the simple QMH setup? It seems like if there is an error at either node, it propagates through the case for whatever message is de-queued, and makes it to the error handler sub VI which provides flexibility to ignore the error or go to an exit state.

- When adding additional MHLs, what is the best way to receive an exit message on its queue? Should it come from the 'brains' UI loop, basically in its exit state enqueue a exit message on the additional MHL's queue (daisy chained I guess), or add an additional enqueue message on the additional MHL's queue via the event EHL? (@Bob_Schor after reading your comment again, it seems that having the primary consumer loop send the exit message to the parallel loops is a good practice. BUT, does that mean it will contain an exit state with multiple queue references and multiple enqueue exit messages, or do the parallel loops chain together, sending exit messages to one another?)

0 Kudos
Message 8 of 14
(2,367 Views)

I only have a couple minutes so will focus on just one thing:

 

I will have a serial connection init state, that uses the board visa reference. I want this reference available to the logging  and testing loop as well, whats the best way to pass around the visa reference to parallel loops?

No you don't.  What you *actually* want is a loop dedicated to your serial-connected device that manages all the communication back and forth.  You *don't* want multiple loops trying to communicate with the device in parallel.

 

Otherwise, you generally seem to have a good start with the right kinds of thoughts and questions.  I don't have time to comment in great detail, but you'll probably hear from others.

 

 

-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 9 of 14
(2,351 Views)

Thank you for your comment Kevin. Your recommendation is similar to a previous poster, but I have some issues with redesigning that portion of my program. Maybe its just inexperience and I can't see how your solution would work well for my problem.

 

The serial read and writes occur in the individual test sub VIs, as well as in the CRE status sub VI which I want to use in a parallel logging loop. With the serial comm encapsulation I mentioned in a previous post, it seemed easier and still OK with my level of complexity to use the visa reference in two locations to take care of parallel comm over the same interface.

 

I will now attempt to understand the method you recommended. I would have a serial communications loop, with one board VISA reference,  that receives messages from the other parallel loops via queues, that tells the Serial Comm VI to continually request status (what logging does right now) OR query or command to do something. My immediate thoughts on possible issues.. I want logging to occur at consistent (or near consistent) time intervals. I am unsure how this can be setup if the serial comm loop is receiving messages to log - log - log - send query - read query.. would I have to put the wait ms delay in that loop? And if I did that, it would slow down the test related commands to the logging interval as well. Now I am thinking how I will access the queue from a test subvi within the testing loop.. instead of serial read writes, would I simply enqueue what command message I need with the queue name reference? I am unsure how I would pass back the received message from the board to the lower level test sub vi though.

 

 


@Kevin_Price wrote:

I only have a couple minutes so will focus on just one thing:

 

I will have a serial connection init state, that uses the board visa reference. I want this reference available to the logging  and testing loop as well, whats the best way to pass around the visa reference to parallel loops?

No you don't.  What you *actually* want is a loop dedicated to your serial-connected device that manages all the communication back and forth.  You *don't* want multiple loops trying to communicate with the device in parallel.

 

Otherwise, you generally seem to have a good start with the right kinds of thoughts and questions.  I don't have time to comment in great detail, but you'll probably hear from others.

 

 

-Kevin P


 

0 Kudos
Message 10 of 14
(2,333 Views)