LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

reduce code complexity (industrial control application)

I have a machine control application and I need help reducing the complexity of the primary control loop.  

 

  The program starts and stops a recipe controlled machine & temperature controller  (ie... wait for operator: start;  run step 1 (heat part), run step 2 (hold part temperature), run step 3 (power off and wait for cool down)  

 

as a simple function table

 

* primary loop:  (waiting for input to start operating)

    -  Determine operation mode [manual 1, manual 2, automated]

    -  check for start or continue condition [local control, primary control (a GV brough in from the primary HMI screen), conditional statements]

    -  case structure for start operating the prosses  [true(run) or false(don't run)

      > running loop  (used to perform the operations of each loop)

          *  read temperatures & machine status

          *  read recipe step parameters

          *  case structure for operation modes

               - choose input types

               - check various conditions

          *  perform PID control caclulations & generate conditional machine outputs

          *  determine if process step is complete

          *  control process timing (wait until next)

          *  monitor for additional inputs such as operator skips step, operator abort, etc.  

 

there are a lot of additional Global Variables (GVs) so that I can output data to additional recording and display threads.   (I set myself a rule that I wouldn't put any GVs within any of my subvi's of this thread- and would instead read/write them only from the main looping threads.)  

 

code is attached... I am ashamed.   Advice Appreciated!!

 

- K

 

 

 

 

Download All
0 Kudos
Message 1 of 4
(2,538 Views)

Not too bad.

 

As you are already aware global variables must be used carefully to avoid race conditions and to avoid breaking dataflow.  From your images it appears that most or all of them could be replaced by wires and shift registers.

 

From the description of your application and the code you have developed it seems that a state machine architecture would  be a good choice.  Look at the examples and design patterns which come with LV and search the Forum archives for many posts about this topic.  You may want two parallel loops rather than nested loops.  One loop is for the data acquisition and the other is for the user interface and overall control.  This is called the Producer/Consumer pattern.

 

You have at least two Wait functions in parallel in the Start New Step loop.  This may not work as you have intended.

 

Good things: Wiring is mostly left to right.  Free labels are used to indicate what is happening in sections of the code.

 

Lynn

0 Kudos
Message 2 of 4
(2,524 Views)

I'm going to repeat some of the things already suggested by Lynn.

 

All the stuff you use the GV for should be inside shift registers. I would suggest to make a strict type definition cluster with copy-past from you global. Then you only need a single wire/shift register.

You could also encapsulate the bundle/unbundle nodes (SubVIs). This way you get something similar to the OOP concept of Accessor Methods.

 

The second thing I'd criticise your code is, you are not using error wires. It is a bit difficult to judge, because what you've shown is in fact not needing error handling, but I guess that in your subVIs there are functions that could generate errors. I generally suggest errors not to be taken lightly, they are an important part of your code/design. So I normally sit down and check what happens if an error occures at a certain section of the code and how I'd like the could to react.

 

State machine:

Your 'function table' should be translated into a bubble-and-arrow diagram or uml StateMachineDiagram.

Then you can translate this into code very fast.

 

Event Structure:

Are you familiar with it? I suggest you to use it for monitoring user input.

 

Felix

0 Kudos
Message 3 of 4
(2,472 Views)

 


@catsh15 wrote:

* primary loop:  (waiting for input to start operating)

    -  Determine operation mode [manual 1, manual 2, automated]

    -  check for start or continue condition [local control, primary control (a GV brough in from the primary HMI screen), conditional statements]

    -  case structure for start operating the prosses  [true(run) or false(don't run)

      > running loop  (used to perform the operations of each loop)

          *  read temperatures & machine status

          *  read recipe step parameters

          *  case structure for operation modes

               - choose input types

               - check various conditions

          *  perform PID control caclulations & generate conditional machine outputs

          *  determine if process step is complete

          *  control process timing (wait until next)

          *  monitor for additional inputs such as operator skips step, operator abort, etc.  

 

there are a lot of additional Global Variables (GVs) so that I can output data to additional recording and display threads.   (I set myself a rule that I wouldn't put any GVs within any of my subvi's of this thread- and would instead read/write them only from the main looping threads.)  

 


 

As mentioned, your GV doesn't have any real function, more than not using the "hidden control/indicator variable". Just wire them to the loop edge as a shift register and you can get rid of them. As Schubert says you can bundle them all together to have one cluster wire which has all information.

 

You seem to have a clear line of thought of what you want to do, and an event driven state machine sounds like the best solution. With a quick glance at your idea i'd do something like this:

 

Top loop: Events from UI

    -  Determine operation mode [manual 1, manual 2, automated]

    -  check for start or continue condition [local control, primary control (a GV brough in from the primary HMI screen), conditional statements]

    -  case structure for start operating the prosses  [true(run) or false(don't run)

          *  monitor for additional inputs such as operator skips step, operator abort, etc.

 

Bottom loop: Queued State Machine

#State Initialize

   * What you usually start with and set things up

#State Read Data

          *  read temperatures & machine status

          *  read recipe step parameters

#State Checkup

          *  case structure for operation modes

               - choose input types

               - check various conditions

#State PID

          *  perform PID control caclulations & generate conditional machine outputs

          *  determine if process step is complete

(#State redundant)

          *  control process timing (wait until next)

(achieved be timeout to Read from queue)

#State Quit

  * Tidy up and kill the queue

 

The program starts with generating a Initialize state, after which it probably wont be fired again (unless you have some reinitialize button)

One state leads to the next.

Timeout fires #State Read Data.

 

Sounds like it could work?

/Y

 

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

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 4 of 4
(2,463 Views)