LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Convert single while loop with variable Timing literal to consumer producer

Solved!
Go to solution

I've got a controller for a biological system that updates every n minutes or every 2n minutes, depending on certain conditions. My implementation has a timing controller that computes whether or not the current iteration is n or 2n, and feeds the output of that computation into a "Timing" VI in my while loop. As I understand it, this is akin to issuing a sleep() command in a C-like language, and must be avoided. I'm refactoring my code, and I've heard they're well suited for this kind of stuff. Here's how it should work:

 

  1. Loop begins at time T, T is recorded.
  2. Timing controller runs, and computes whether loop will get n minutes or 2n minutes. This controller will take some number of milliseconds to complete, so we are no longer at time T.
  3. Now that the update interval (n or 2n, let's call it u) is known, the loop has until T+u to complete.
  4. The main controller is run, it takes some number of milliseconds to run.
  5. The remainder of the time until the next loop iteration should yield the CPU to other processes.

This sounds to me like it's kind of a real-time system, although as long as we're within 1 minute of the original deadline, nothing bad will happen.

 

What would the consumer-producer loop look like? Assume the Timing controller and Main controller are separate VI's.

0 Kudos
Message 1 of 20
(2,267 Views)

It is not apparent that the Producer/Consumer architecture would be any advantage for you. It seems to me that a simple state machine should be adequate. One state implements the timing controller. The main controller is in another state or possibly several states, depending on its complexity. The main timing function would be in a Wait  or Idle state. That state would wait about 100 ms and then compare the current time to T+u. If greater, then reset T and go to the main contrller state. Otherwise retturn to the Wait state again. You probably also need an Initialization state, an error handling state, and a Shutdown state.

 

Lynn

0 Kudos
Message 2 of 20
(2,258 Views)

@ijustlovemath wrote:

I've got a controller for a biological system that updates every n minutes or every 2n minutes, depending on certain conditions. My implementation has a timing controller that computes whether or not the current iteration is n or 2n, and feeds the output of that computation into a "Timing" VI in my while loop. As I understand it, this is akin to issuing a sleep() command in a C-like language, and must be avoided. I'm refactoring my code, and I've heard they're well suited for this kind of stuff. Here's how it should work:

 

  1. Loop begins at time T, T is recorded.
  2. Timing controller runs, and computes whether loop will get n minutes or 2n minutes. This controller will take some number of milliseconds to complete, so we are no longer at time T.
  3. Now that the update interval (n or 2n, let's call it u) is known, the loop has until T+u to complete.
  4. The main controller is run, it takes some number of milliseconds to run.
  5. The remainder of the time until the next loop iteration should yield the CPU to other processes.

This sounds to me like it's kind of a real-time system, although as long as we're within 1 minute of the original deadline, nothing bad will happen.

 

What would the consumer-producer loop look like? Assume the Timing controller and Main controller are separate VI's.


One of the significant things about LabVIEW (in addition to Data Flow and the ability to execute code in parallel) is the importance of Time as a primary data type.  There are certain Time-related questions that arise from the scenario you outline which make it difficult to suggest an algorithm.

  • What information does the Timing Controller need to make its decision?  In particular, is it "time-dependent", i.e. is it based on "the current value of the data" or can you "pre-compute" it, say 10 seconds before the next call to the Main Controller?

Hmm, that may be the only question that I have.  Let me assume that you can compute the time between calls to the Main Controller some fixed time (say 10 seconds) before calling the Main Controller.  If so, here's one way to proceed:

 

  • Set up a Producer/Consumer pattern, with the Time Controller being the Producer and the Main Controller being the Consumer.  You can connect them with a Queue, and pass the "Between Time" (which the Consumer may or may not need) as a synchronization method.
  • Compute the first "Between Time" and pass that into your Producer Loop (Timing Controller), starting the Producer.
  • The Producer consists of two Frames (I generally don't like/use Sequences, but this is a good example of a use for them).  In the first Frame, enqueue the Between Time, starting one cycle of the Consumer, and place a Wait for (Between Time - 10 seconds).  In the second Frame, compute the next Between Time and place a Wait for 10 seconds.
  • The Consumer loop dequeues the Between Time (which it may or may not need to use) and does one whatever-it-needs-to-do.

Note that we never need to actually record the Starting Time (though we can) and never use it.  The Producer has two sequential Waits of BT-10 and 10, for a total of BT (Between Time), exactly what you want.  Because the Waits take place in parallel with the computation in the Frame, this effectively means the computation is done and then the remaining Wait takes place -- the amount of time the computation takes does not matter as long as the Wait is longer than this time.  Finally, the Consumer will do one "Control" operation and then wait, getting the next "Go" command when the Producer's Between Time finishes and it starts the next loop.

 

Bob Schor

Message 3 of 20
(2,240 Views)

Because the Waits take place in parallel with the computation in the Frame, this effectively means the computation is done and then the remaining Wait takes place -- the amount of time the computation takes does not matter as long as the Wait is longer than this time.  Finally, the Consumer will do one "Control" operation and then wait, getting the next "Go" command when the Producer's Between Time finishes and it starts the next loop.

 

Bob Schor


Is this really how it works?! That's awesome! So as long as I use the Timing literal, this is the behavior? To clarify your question:

 

The main controller AND the Time controller depend on the most current sensor value, which is obtained in the same while loop from a Sensor VI. This value is then passed via a cluster into both the Timing Controller and the Main Controller, so they may do their respective computations. I thought this was an okay way to handle it, as the Sensor VI is event-based, so it will not output a value to the cluster until the value has changed from the previous loop iteration. I have run this controller, and it works just as expected in its setup, but I'm always looking to improve its internal structure. Race conditions like these make my head spin sometimes, so any guidance is very helpful!

0 Kudos
Message 4 of 20
(2,235 Views)

@ijustlovemath wrote:

Because the Waits take place in parallel with the computation in the Frame, this effectively means the computation is done and then the remaining Wait takes place -- the amount of time the computation takes does not matter as long as the Wait is longer than this time.  Finally, the Consumer will do one "Control" operation and then wait, getting the next "Go" command when the Producer's Between Time finishes and it starts the next loop.

 

Bob Schor


Is this really how it works?! That's awesome! So as long as I use the Timing literal, this is the behavior? To clarify your question:

 

The main controller AND the Time controller depend on the most current sensor value, which is obtained in the same while loop from a Sensor VI. This value is then passed via a cluster into both the Timing Controller and the Main Controller, so they may do their respective computations. I thought this was an okay way to handle it, as the Sensor VI is event-based, so it will not output a value to the cluster until the value has changed from the previous loop iteration. I have run this controller, and it works just as expected in its setup, but I'm always looking to improve its internal structure. Race conditions like these make my head spin sometimes, so any guidance is very helpful!


To answer your question, yes, this is really how it works.  Without seeing the code, I admit to being confused about how the Controllers really work, and how their timing is determined, but I'm going to assume you have this now well under control.

 

BS

0 Kudos
Message 5 of 20
(2,223 Views)

P.S. -- among other things, I'm a Dues-paying member of the MAA ...

 

BS

0 Kudos
Message 6 of 20
(2,219 Views)

As am I, if you couldn't tell 🙂 Here are two screenshots that give a little more detail. The second image is the inside of "ALL CTRL'R"Capture.PNG

Capture2.PNG

0 Kudos
Message 7 of 20
(2,209 Views)

It looks like a state machine would do nicely.  One loop with everything inside.

 

Generally wiring False to the stop terminal of a while loop is not a good idea. Forcing the program to stop by hitting the Abort button can leave the hardware in an unknown state, files open, and so on. Either calculate the end of the operation or include a Stop button or an Application Close event so that you can shut everything down in an orderly manner.

 

Lynn

0 Kudos
Message 8 of 20
(2,204 Views)

I actually had an event-driven stop button built in, but it was causing problems as it would hang the program from moving on. The Timeout couldn't be too low, or you'd never register an event, and it couldn't be -1 as it would never move to the next iteration. If you've got advice for how to handle that, I'd love to hear it!

0 Kudos
Message 9 of 20
(2,200 Views)

ijustlovemath wrote:The Timeout couldn't be too low, or you'd never register an event,

Where did you hear that?

 

Events will always register.  You can make your timeout 0 on an event structure.  Any code inside the timeout case would immediately execute assuming that no other event has already happened.

0 Kudos
Message 10 of 20
(2,193 Views)