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 poll case structures to event help

Matt,

 

I am going to confuse you even more!  You might be better off with three loops. One loop would handle all the User events - when the user presses a button or enters a value on the front panel. This is a Producer (Events) loop. Another loop might be the one which communicates with the Arduino. This is a Producer (Data) loop.  The third loop is the Consumer and it gets commands from the User Interface loop and it gets data from the Arduino loop. It updates displays and saves to files.

 

The basic idea of the Producer/Consumer concept is to separate functions which might need to operate at different speeds. The user interface needs to "feel" responsive to users - which typically means that it should respond within about 100 ms to user actions. With an even structure and a queue being the only code inside the loop, the response is very fast with almost no CPU overhead. Suppose the Arduino needs to have a response within 10 ms. Having a loop which only communicates with the Arduino and passes the data to the consumer via a (different) queue means that it can run much faster than the other loops. Meanwhile the save to file loop can run once every few seconds. If the OS decides to defragment or reallocate the files and takes hundreds of milliseconds to do it, the other loops continue to run at their usual rates.  The queues act as buffers so data is not lost.

 

Lynn

Message 11 of 34
(967 Views)

@johnsold wrote:

Matt,

 

I am going to confuse you even more!  You might be better off with three loops. One loop would handle all the User events - when the user presses a button or enters a value on the front panel. This is a Producer (Events) loop. Another loop might be the one which communicates with the Arduino. This is a Producer (Data) loop.  The third loop is the Consumer and it gets commands from the User Interface loop and it gets data from the Arduino loop. It updates displays and saves to files.

 

The basic idea of the Producer/Consumer concept is to separate functions which might need to operate at different speeds. The user interface needs to "feel" responsive to users - which typically means that it should respond within about 100 ms to user actions. With an even structure and a queue being the only code inside the loop, the response is very fast with almost no CPU overhead. Suppose the Arduino needs to have a response within 10 ms. Having a loop which only communicates with the Arduino and passes the data to the consumer via a (different) queue means that it can run much faster than the other loops. Meanwhile the save to file loop can run once every few seconds. If the OS decides to defragment or reallocate the files and takes hundreds of milliseconds to do it, the other loops continue to run at their usual rates.  The queues act as buffers so data is not lost.

 

Lynn


My wife expects a quicker response than that, and as a result, my queue is always full.  😉

 

It takes a little while to sort out the three loop thingy, but believe me, it's such a pleasure to drive once you've implemented it.  Sometimes I will even implement a fourth loop to handle errors.  😉

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
0 Kudos
Message 12 of 34
(962 Views)

I ran into the problem a while back with my code when laoding stuff.  My solution was a 3 panel flat sequence structure.  1st panel disabled and grayed out the front panel, 2nd panel loaded and moved everything to that location, and 3rd panel reactivated everything.  It was pretty, but it worked (That is the solgan of my code right now... I guess it is time for upgrades).  

 

Hopefully there is sample P-C code out there that I can look at and play with to understand it better.

 

On a side note, I started using clusters and my code looks a lot nicers.  Woo hindsight 😄

 

Matt

 

EDIT:

 

I did not realize there was a 2nd page in the thread and did not read those posts as of my original post.  

 

The Arduino is being controlled over Labview in a massive while loop (making sure it's connected) with a case structure (choosing normal, save, or load).  When a front panel control is moved, LV sends a command to the Arduino, where it updated its value and sends an "all good" back to Labview.  This seems instananous, even though I know its not, but its faster than I can detect.  That code was written by Sammy_K (LIFA creator), except I changed it from serial to ethernet.  I guess I should have stated that ealier...  This case structure thing is inside a giant while loop that can only be exited by clicking a big red "STOP" button or aborting execution

0 Kudos
Message 13 of 34
(954 Views)

Bill,

 

The Dequeue on the wife queue does not reduce the number of items in the queue. The timing is irrelevant.

 

Lynn

0 Kudos
Message 14 of 34
(934 Views)

@Uke88 wrote:

I got to reading about the Consumer/Producer loops from here.  I don't think that's what I'm looking for.  From my understanding, Consumer/Producer loops are broken down into 2 separate loops - Consumer and Producer.  The Producer creates a queue and the consumer takes the queue and processes it.  The queue works on shift registers.  To me, that means that each loop something has to be passed into the queue or the consumer won't know what to do.  

 

For my code, every loop LabVIEW sets/gets 5 data points to an Arduino.  2 servo pulse widths and 3 pot voltage values.  When a save/load button is pressed, LabVIEW takes that data and stores/loads it from a save file.  I think event structures would be better for me here.  The way I'm looking at things, once a Boolean changes, save/load.  Otherwise, keep chugging away at the data.

 

Matt


You're not wrong, you can implement it as a event structure (just add some user events), but as already mentioned, if some actions take >100ms it'll start being sluggish, that's the beuty of moving the actions to the consumer loop.

In your case, the situations you describe are excellent commands to send to the consumer, and "otherwise" is a timeout-event of the queue. (or to make it more correct, in case of timeout, generate a "Chug data"-command)

 

For the UI, gather all of those Save-button as a Save-cluster, and use a value change-event on the cluster (or use a Ring/Enum-selector and 1 save-button)

 

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
Message 15 of 34
(920 Views)

Question.  So consumer consumes data, producer produces data.  The C-P loop sends data to each other's loop.  So if that's the case, I can send the values from the consumer loop (get/set Arduino) to the producer loop to save them when a save button is pressed or I can load the data from the save file and send the data and a flag to the consumer.  All of this being done in the producer loop.  Then in the consumer loop, I can have a case structure controlled by a flag.  True would be the normal get/set while false would be a load. 

 

I'm now thinking of the C-P design as two separate loops where the producer takes care of the LV stuff and consumer takes care of the arduino stuff.  Am I on the right track or waaaay off?

 

Matt

0 Kudos
Message 16 of 34
(909 Views)

I'd say information is one way, only to consumer, although there are different designs. It can however be produced from both. 

Wait, what? 
Well, it's to avoid interdependancies between loops and other strange solutions i've found. I'll explain:

The consumer loop holds all needed information in a shift registered main cluster, the program ofc starts by queing an init-command.

 

" I can send the values from the consumer loop (get/set Arduino) to the producer loop to save them when a save button is pressed" - No, when you press the save button you generate a save-event, which in the consumer uses the data running in the consumer loop and saves it.

 

"I can load the data from the save file and send the data and a flag to the consumer.  All of this being done in the producer loop" - Could be done that way, but easier is to generate a load-command which in the consumer loads the file and stores in the main cluster. 🙂

 

"Then in the consumer loop, I can have a case structure controlled by a flag.  True would be the normal get/set while false would be a load. " - Not needed as it's different commands executed.

 

"I'm now thinking of the C-P design as two separate loops where the producer takes care of the LV stuff and consumer takes care of the arduino stuff.  Am I on the right track or waaaay off?" - Yes and no, one loop handles buttons, one loop handles all else. If "all else" takes too long (for example repeated slow serial communication) it can actually go into a 3rd loop, requiring a 2nd queue, or user events.

 

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 17 of 34
(893 Views)

Darn, thought I had it that time >.<

 

I don't get how to have the producer send a different command to the consumer.  I'm looking at a P-C event design.  The Producer waits for a button to be pressed on the front panel, say the save button.  That sends a queue command to the consumer.  The consumer gets the values and saves them.  Then, nothing happens on the front panel for a while and the whole time the consumer loop is still updating the Arduino.  A load button is pressed and the producer sends a queue to the consumer to laod the data.  

 

The only way I can think of these things to happen is have 3 flags being sent through the queue.  One for nothing, save, and load.  And a case structure in the consumer to do the proper function. There would have to be a time out for the "nothing" flag.  I don't get how the queue can send different commands to the consumer without some sort of value being passed to the consumer loop which tells the consumer what to do.  

 

Matt

0 Kudos
Message 18 of 34
(882 Views)

Matt,

 

Now you are getting the idea. What you are calling "flags" is what I meant by "commands." Typically I use a typedefed enum for the commands.  Sometimes it is necessary to also send parameters. For example your 10 Preset Save booleans might be replaced by a Save command and a numeric (1..10) representing which button was pressed. 

 

If the Consumer is implemented as a state machine (which I do about 99% of the time), one of the states is usually an Idle state.

 

Lynn

Message 19 of 34
(869 Views)

Lynn,

 

By flags, I mean something like a case structure (haven't looked into state machines, I'll get on that), where I was going to have an event structure in the producer with 3 events, 0 for nothing, 1 for save, and 2 for load.  The consumer would have a case structure where it would have 3 case, 0 for normal action, 1 for save action, and 2 for load action.  For the save and load function, it would send the 1 or 2 (save or load) along with a 1-10 to determine which save/load was pressed.  When a time out happened, I would just send a 0.  However, all of that would depend on the 0 being sent fast enough so nothing seemed like it is taking too long (1ms?).  I know that would load the queue pretty bad so when a save/load was pressed, I'd restart the queue and then send the load/save command.  

 

Like I said, haven't looked into state machines, so I'll get on that.

 

Matt

0 Kudos
Message 20 of 34
(857 Views)