Presentation on theme: "Five Techniques for Better LabVIEW Code"— Presentation transcript:
1Five Techniques for Better LabVIEW Code Peter BlumePresidentThis presentation is inspired by the customers and employees of Bloomy Controls.
2Five techniques with examples OverviewIntroductionFive techniques with examplesSpecificationsData flowState machinesError handlingDocumentationConclusionThis presentation was motivated by some common mistakes we’ve seen repeatedly by the consulting and training customers of Bloomy Controls. The primary cause of the mistakes is the desire for instant gratification, by developing and running our applications as quickly as possible. In many ways, LabVIEW entices us to develop our applications quickly because of the graphical nature, and the many features that expedite programming tasks. However, LabVIEW is a programming language, and computer science practices commonly applied to conventional programming languages also apply to LabVIEW. This presentation illustrates several such practices.We will focus on LabVIEW programming and documentation techniques. My introduction discusses some undesirable tendencies, or bad habits, that I’ve observed with LabVIEW programmers, and how people justify them. The techniques involve Specifications, Data Flow, State Machines, Error Handling, and Documentation. I’m going to compare one or more good and bad LabVIEW programs of significant complexity, throughout this presentation.
3LabVIEW facilitates fast development cycles IntroductionMost LabVIEW applications begin with an industrial measurement and/or control challengeLabVIEW facilitates fast development cyclesEasy to connect and control instrumentationFast solutions to industrial challengesInstant gratification for developersLabVIEW developers adopt fast habitsSloppy wiringNo documentationComputer science fundamentals are ignoredFast habits = bad habitsMany developers choose LabVIEW because of how fast we can develop our test, measurement, and control applications. LabVIEW developers receive instant gratification by quickly connecting and controlling a wide variety of instrumentation, displaying the results, generating reports, etc. Many of us are confronted by a scientific or technical challenge in our business or industry, and we expect to develop some experiments, tests, or measurements using LabVIEW, and solve the problem the same day.What is the temperature gradient across this fuel cell membrane?How can we optimize the mass flow velocity of a chemical through a distillation column?Can we increase the throughput of our high volume production line?A good LabVIEW developer knows that she can wire up a few sensors, some PXI, SCXI or FieldPoint instruments, and throw together some LabVIEW code in short order. Many such industrial measurement and control challenges can be solved in a matter of days, sometimes hours.(How many of you apply conventional computer science techniques, such as specifications, pseudocode, flow charts, use cases, documentation, etc. to your LabVIEW applications?) Many LabVIEW developers ignore everything they learned about computer science.
4LabVIEW is a graphical language Justifying Bad HabitsLabVIEW is a graphical languageComputer science fundamentals don’t applyBlock diagram is self-documentingWe don’t have time to write good codeIntense time pressuresLabVIEW is a secondary responsibilityRequirements continuously changeEquipment availability constraintsI’m the only developer / end-userNobody else needs to use or understand my programsBad habits are justified in a variety of ways. Some believe that computer science fundamentals either don’t apply to graphical programming, or it’s not clear how to apply them. Others believe that LabVIEW is self-documenting because its graphical nature may resemble a flow chart. Other people will tell you they bought LabVIEW because they’re engineers, not programmers, and they’re exempt from computer science practices.Many customers work in a very dynamic environment with intense time pressures. They like to use their intense time pressures to justify bad LabVIEW programming habits. In a production environment there may be limited availability of the equipment in which to deploy and test your LabVIEW applications.Finally, some people justify their bad habits because they’re writing programs that only they will use.
5Issues Resulting from Bad Habits Application requirements expandLabVIEW code becomes messyInefficientBuggyDifficult to troubleshoot, expand, and maintainNot reusableOverall development time is increased(How many of you have ever written a LabVIEW application that never required any modifications, new features, or enhancements after it was first completed?) i.e. you wrote the application perfectly satisfying all the intended objectives (both explicit and implied), deployed it, and never had to make any further changes or enhancements? In practice, our application requirements expand. LabVIEW’s flexibility and capability to serve many different uses and departments within an organization – from laboratory R&D, design validation, manufacturing automation, production test, and reliability testing – and many different users – operators, technicians, engineers, scientists, managers – means that application requirements can expand just as rapidly as the developer can implement them. A simple laboratory experiment may evolve into much more complicated experiments involving many instruments. In some cases, a new product design is validated, and the same software is migrated into production test.Even worse, your application requirements may expand after you’ve forgotten how your program works, or after you’ve moved on to bigger and better things. (Bloomy Controls is often contracted by companies after a lead developer has left the company.)When application requirements expand, the diagram complexity increases, and depending on your programming style, it can become difficult to understand, maintain, troubleshoot, and modify your application.Because your code is messy, it is not reusable. Therefore, you’re always starting from a blank slate with each and every project.Overall development time is actually increased over the life of the project when fast (bad) tendencies are employed.
6Bad Code ExampleWhat do you think of the LabVIEW program? Does it look like spaghetti? This is what happens when you have bad programming habits, and your application requirements expand.Why is this LabVIEW code bad?Examine: Specification, data flow, architecture, error handling, and documentation.Experienced LabVIEW developers refer to this diagram as “spaghetti.” It exhibits an inappropriate architecture, insufficient modularity, and a haphazard wiring scheme. Error handling is incomplete, and documentation including VI descriptions, is nonexistent.Specifically, the wiring was performed haphazardly, with data flowing left-to-right, right-to-left, up, down, and all around. Several local variables are improperly initialized outside the while loop in parallel with code that is reading the values from the corresponding control terminals within the while loop. Since there is no data dependency between the initialization operations and the while loop, the order of execution is not known. Therefore, these controls may not be correctly initialized before they are accessed within the looping structure. Several subVI icons contain text that was drawn free-hand, one unique trait that I would not consider common.
7Good Code ExampleThis LabVIEW program is actually far more complex than the last. It actually contains 5 asynchronous while loops, and a fairly sophisticated messaging scheme. What are a few things that strike you as improvements versus the bad code?
8Let’s Write Better LabVIEW Code! Follow these five techniquesMore up-front time and effortAttention to detailDisciplineDramatically save time in the long runLabVIEW developers can improve their source code to best adapt to these short and long-term challenges by applying the techniques presented here. This will entail more up-front time and effort and attention to detail, but will provide dramatic improvements in the long-term maintainability of the application.These techniques are applicable to LabVIEW programs (versus text-based languages) and can be implemented quickly!
91. Write a Functional Specification Understand the application’s requirementsInterview operators, developers, engineers, managers, bean countersDocument the requirementsStatement of high-level objectivesSpecific requirements for I/O, analysis, GUITimetable and budgetDesign prototype screen shotAssign priorities to each requirementTest methodologyThe most common problem I see, is that people begin developing their LabVIEW applications without a full understanding of the requirements. This results in poor choices for the top-level architecture, incorrect data structures, inadequate error handling, etc. Moreover, it often results in wasted effort when significant portions of the application must be rewritten to accommodate new definitions of poorly understood requirements. Documenting the specifications and having them reviewed by all contributors ensures that the requirements are understood, agreed upon, and approved. Documenting the requirements should be the first step in any LabVIEW application development effort.Without a specification, it can be very difficult to determine when the application’s requirements have been satisfied. Verbally dictated specifications are most prone to misinterpretation and/or scope creep. This may result in frequent redevelopment, unnecessarily long development cycles, missed deadlines and budget overruns. Use a word processor to document the requirements. Have them reviewed by all parties involved, and agreed upon prior to starting the LabVIEW coding process.
10Functional Specification (Continued) Avoid designing the systemDon’t prolong specification phase by including too much detail such as how to implement the systemMake the specification readily accessibleHave all contributors review and approveRevise when requirements changeKeep it somewhere that you and others can quickly reference itWhen you circulate a written specification, you’re often able to flush out assumptions and miscommunications. Revisions are usually necessary. Also, new requirements often arise after the project has started. Hence, the specification must be a living document.I keep an electronic copy of my specification in the root directory of the source code, and a hard copy in my project binder.
11Simple Specification Example Most people agree that a specification is necessary for a large project, but many people may overlook the utility in a small project. This slide shows an example of a specification for a very simple functional test application that may only take a few days to implement. The moral of the story is, start with a specification for all projects, no matter how small they may appear in the beginning.
12Bad Code ExampleWhen Bloomy Controls was contacted to debug this application, our first request was “please forward us the documentation for our review”. Not too surprisingly, there was no documentation ever written for this application. Even worse, the developer has long since left the company and is no longer available to answer questions.
13Good Code ExampleWhat do you think of the LabVIEW program, of similar complexity? What are a few things that strike you as improvements versus the bad code?
14Parallel paths are permitted and desirable 2. Use Proper Data FlowData flow definition:“A block diagram node executes when all its inputs are available. When a node completes execution, it supplies data to its output terminals and passes the data to the next node in the dataflow path.”Parallel paths are permitted and desirableEfficiency is optimized when LabVIEW determines the execution orderReadability is optimized when source terminals, wires, and destination terminals are visibleData flow is the fundamental principle of LabVIEW. Data flows along wires from source terminals to destination terminals. Programs execute most efficiently when data dependency determines the execution order. Hence, parallel data paths are desirable.
15Local and global variables Coercions Sloppy wiring Data Flow ImpedimentsSequence structuresExcessive nestingLocal and global variablesCoercionsSloppy wiringExcessive bendsOverlapping wires with other objectsMultidirectional data flowSequence structures force the order of execution where data dependency doesn’t exist. Sequence structures are undesirable because they undermine data flow principals, and reduce the efficiency of LabVIEW’s compiler.Local and global variables also undermine data flow by duplicating terminals on the diagram. Each Read Local or Global variable makes a copy of the data in memory. Each Write Local or Global variable has the potential to overwrite a value written from another Write operation, resulting in a race condition. Hence, local and global variables are slow to access, memory consuming, and add complexity and potential misbehavior. These issues become increasingly important when the type of data is large or complex, or many variables are used. However, experienced LabVIEW programmers generally avoid them unless absolutely necessary.Coercions appear as gray dots at the junction of wires and nodes. They indicate that the data type carried by the wire is being converted, or upgraded to a different data type. This adds an extra operation, and creates an extra memory buffer. Similar to Read local and global variables, the additional overhead depends on the number of coercions, as well as the size and complexity of the data. Note that in many instances, a coercion is unavoidable, and the extra overhead may be negligible.Data flow appears sloppy if there are many unnecessary bends in the wires, if data flows in multiple directions, such as right to left as well as left to right, and if wires are routed underneath other objects or structures.
16Simple Data Flow Example ImpededUnnecessary sequenceCoercionLocal variablesBetter data flowThis is an oversimplified example of two equivalent diagrams. The top diagram uses a flat sequence structure to dictate the execution order. The flat sequence is a new feature of LabVIEW 7.0 that shows each frame side to side instead of stacked. This improves the readability versus legacy sequence structures. However, sequence structures are generally undesirable, unless it’s critical that the code executes in a specific order and no data dependency exists between the respective nodes.Also, notice that local variables are used to replicate the control terminals for Number 1 and Number 2 in the second frame of the sequence. This is also undesirable because unnecessary local variables increase memory usage, execution time, and complexity.Finally, the top diagram contains coercion dots because the control storing Number 2 has dissimilar data representation (single precision float) than the others.The bottom diagram allows LabVIEW to efficiently process parallel data paths.
17Bad Code ExampleWhat data flow mistakes were made in this application?Error cluster not used with DAQ VIs.No data dependency between local variable initializations and while loop.There are (x) local and global variables, most of which aren’t necessary.Shift registers can be used to reduce local and global variables.Data flows left to right, right to left, up, down, and all around.Sloppy wiring is often the result of inadequate specification, inappropriate architecture, and expanded requirements.(No coercions and no sequence structures)
18Bad Code – Zoom In on Wiring What data flow mistakes were made in this application?Error cluster not used with DAQ VIs.No data dependency between local variable initializations and while loop.There are (x) local and global variables, most of which aren’t necessary.Shift registers can be used to reduce local and global variables.Data flows left to right, right to left, up, down, and all around.Sloppy wiring is often the result of inadequate specification, inappropriate architecture, and expanded requirements.(No coercions and no sequence structures)
19Data Flow Enhancements Artificial data dependencyUse error cluster and/or task IDShift registersReduce local and global variablesClustersReduce the overall number of wiresNeat wiringLeft-to-right data flowStraight wiresConsistent data typesComments with “>” indicating data flow directionWhen the order of execution must be specified, an experienced LabVIEW developer will create artificial data dependency using an error cluster or other common data type, as an alternative to a sequence structure. Additionally, shift registers can be used to dramatically reduce the required number of local variables. Clusters can be used to combine multiple data elements, and thereby reduce the overall number of wires required. Finally, be sure to practice neat wiring practices.Use alignment tools to align nodes and straighten wires!!!
20Good Code ExampleIn the good code example, data flows strictly left to right, and occasionally up or down. All long wires contain comments with the direction of data flow indicated using “>” symbols. Shift registers are employed instead of local and global variables (although some locals are used where necessary).(If you’re passing data between two loops, you have to decide between local and global variables, and notifiers and queues. If the data will be displayed in an indicator, and no synchronization is required, then we simply use a local variable. However, if synchronization is required, then a notifier or queue is preferred.
213. Use a State Machine Top-Level Architecture Define application as a series of statesGo to any state from any other stateEasy to modify, maintain, and debugSelf-documentingScalableThe diagram of all top-level VIs, except for very simple applications, should contain a state machine architecture. This provides the most flexibility and efficiency, while maintaining the natural data flow of LabVIEW.
22Classic State Machine Is everyone familiar with a state machine? This is a classic state machine, as defined in the LabVIEW Basics hands-on course. It consists of a single case structure within a while loop. A shift register passes the next state as an integer data type wired to the condition terminal. The default case polls a menu of boolean controls. If a button is pressed, Search 1D Array returns the array element (cluster order number) of the first control that matches the True boolean constant, and passes this number to the shift register on the right border of the While loop. Upon the next iteration of the While loop, the state number is read from the shift register on the left border of the while loop and passes it to the condition terminal of the case structure to select the corresponding frame number. Hence, each button in the menu cluster corresponds to a frame of the case structure numbered in order of the cluster order number of the control within the cluster.It is important to note that the state machine is not limited in number of states by the number of boolean controls in the menu. Rather, any number of states may be defined, and called from any previous state. Furthermore, the state to execute next can be programmatically determined within the previous state. Therefore, state machines provide powerful flexibility.
23State Machine Enhancements Use enumerated or string for case selectorPoll user interface events in “No Event, Default” frame or in separate event structure in parallel loopUse intuitive state namesInclude “Initialize” and “Shutdown” statesAn enumerated or string case selector, with intuitive state names, serves to document the state machine. Avoid numeric selector types that display numbers in the case selector instead of text. “Initialize” and “Shutdown” frames are used for functions like initializing or closing instruments and hardware, setting control properties, and reading or writing to configuration files. Using “Initialize” and “Shutdown” states also reduces inefficient block diagram real estate that would otherwise contain these functions outside the state machine.
24Enumerated State Machine Here is an enumerated state machine. Notice the intuitive state labels in the case structure selector, and in the enumerated constants.
25Event-Driven State Machine States typically are derived directly from the steps of a test, measurement, or control sequence. However, consideration should be given to how long each state takes and how quickly the program needs to respond to GUI events. For example, if your VI needs to execute a Shutdown sequence within two seconds of the user clicking the Abort button, then the process should be divided in states with enough granularity such that no state takes more than two seconds. Queues may be used to store multiple user events and pass those events between parallel structures for processing.The diagram shown above is functionally equivalent to the previous state machine example. However, it uses a separate parallel event structure to optimize its ability to detect user interface events, and it stores the events in a queue for processing by the state machine. It has the advantage in that it can capture and process multiple user interface events.
264. Incorporate Proper Error Handling Trap and report any I/O related errors in all VIsI/O functions include DAQ, file I/O, instrument I/O, communicationTrapping is facilitated by propagation of error clusterReporting methods include dialog prompt or log to fileError handling consists of trapping and reporting any undesirable behavior that may cause the program to malfunction. We are primarily concerned with input/output errors, where LabVIEW is calling a device driver, operating system, or any application or resource external to the LabVIEW environment. Examples include querying an instrument that is not powered on or hung up, or reading or writing to a file or network path that does not exist, and so on. All such I/O functions contain the standard error-in and error-out clusters. These terminals must be wired and propagated among I/O functions and terminated with an appropriate error handler VI.
27Error TrappingAny subVI or function call that performs an Input or Output operation must contain standard LabVIEW error input and error output type definition controls assigned to the lower left and lower right connector terminals, respectively. These functions must check the status of the error and not execute their input and/or output operation if the error status is true.If the function performs a DLL call, the call library node must be enclosed in the false frame of a case structure with the error cluster wired to the condition terminal. If the function calls a LabVIEW primitive that has error input and error output connector terminals (such as VISA functions), then the case structure may be omitted if the error cluster is propagated to these terminals, because the primitive will check the error status internally. However, it is preferable to have the I/O primitives inside a case structure to reduce overhead due to unnecessary calls to the primitive as well as any additional string parsing or other operations that the subVI may perform.
28What’s Wrong With This Picture? The diagram above traps an error only if it is present upon completion of the last iteration of the While Loop. Any errors that are generated by the DAQmx Read VI or the Write File function before the user clicks the Stop button will be ignored. Therefore, many errors could go unnoticed!
29Better Error HandlingThis diagram contains several enhancements. The error cluster is propagated between both DAQ and File I/O VIs, such that an error generated by one will cause all subsequent I/O operations to be bypassed. Additionally, the While Loop terminates immediately upon detecting an error and displays the error information in a dialog box through the Simple Error Handler.vi. Finally, if a warning occurs, it will be trapped and propagated by the shift register.
305. Document Your Source Code Assume every VI will be used and maintained by other developersBest time to document your source code is while you develop itBy documentation, I’m referring to source code documentation.
31LabVIEW Documentation Techniques Control labelsUse succinct, intuitive labelsIndicate units in parentheses or use free labelsEnter descriptions or online help where further text is neededIconsIntuitive text or graphic10-point small fontsColor-coding for icons of related subVIsThe importance of control and indicator labels in documentation cannot be overstated.
32Documentation Techniques (cont’d) DiagramLeave the background color whiteSet all control labels visibleLiberally document with free labelsEnter descriptions for every subVI
33Bad Code ExampleNone of the VIs in this application contain any VI descriptions, including Fault Reporter.vi. Furthermore, this subVI’s only indicator doesn’t have any label at all, consequently the context help window doesn’t have a label.
35Write a specification for all projects before you begin coding SummaryWrite a specification for all projects before you begin codingUse proper data flowUse a state machine top-level architectureIncorporate proper error handlingDocument your source code while you code
36Techniques can be implemented quickly if you make them habits ConclusionTechniques improve:ReadabilityRobustnessEfficiencyMaintainabilityReusabilityTechniques can be implemented quickly if you make them habitsApply to every project, starting nowApply consistently throughout each projectDramatic reduction in overall time and effort
37Test, measurement, automation, and control specialists since 1991 About Bloomy ControlsTest, measurement, automation, and control specialists since 1991Systems integration, software development, and training providerNI Select Integrator and Certified Training Center3 Certified LabVIEW Architects8 Certified LabVIEW Developers1 Certified TestStand Architect2 Certified TestStand Developers8 Certified Professional InstructorsOffices in Windsor, CT; Milford, MA; and Mahwah, NJ
38Contact Bloomy Controls Write or visitCT, Western MA, Eastern NY:Eastern MA, RI, Northern New England:Greater NYC, NJ:839 Marshall Phelps Rd.100 Medway Rd., Ste 202Windsor, CT 06095Milford, MA 01757Mahwah, NJ(860)(508)(201)