07-09-2021 08:38 AM
Anyone who has read any forums about LabView knows that Global variables are typically frowned upon. I have a use case which seems common enough that I'd imagine most users have come across it once or twice, but GVs are rarely mentioned in those threads, so my intuition tells me I might be missing something.
I need to store hardware calibration data and some context data somewhere, and it's likely going to be referenced multiple places in nested VIs. I have some motorized travel stages which will have physical offsets set by the user only when assembling the system for the first time, and some context data that will impact algorithms. This context data will ideally be stored in the program's config file, and will never be changed except in situations where execution of everything else should be stopped. Having this data as a wire passing through many sub-VIs seems like a way to clutter the entire program.
Is this the mythical correct application for Global Variables?
07-09-2021 09:09 AM
Are Global Variables Truly Evil?
In your case, I would probably have a class for each stage. The class would include these offsets, current positions, communication port, etc.
07-09-2021 09:35 AM
@Nokaroa wrote:
Anyone who has read any forums about LabView knows that Global variables are typically frowned upon. I have a use case which seems common enough that I'd imagine most users have come across it once or twice, but GVs are rarely mentioned in those threads, so my intuition tells me I might be missing something.
I need to store hardware calibration data and some context data somewhere, and it's likely going to be referenced multiple places in nested VIs. I have some motorized travel stages which will have physical offsets set by the user only when assembling the system for the first time, and some context data that will impact algorithms. This context data will ideally be stored in the program's config file, and will never be changed except in situations where execution of everything else should be stopped. Having this data as a wire passing through many sub-VIs seems like a way to clutter the entire program.
Is this the mythical correct application for Global Variables?
This would be an appropriate use of globals, but if you can manage it, I like crossrulz's solution better.
07-09-2021 09:49 AM
Thank you for the video, I will watch it when I get the chance.
I am confused by the suggestion to use a class though. My goal is to be able to set these from outside of the program and store them in a file which can be edited during setup of the program. If I have a class for each stage, and I need to reference that data in multiple places, I still need to wire that class through every relevant VI which brings leaves me with the original problem, unless I make those classes global.
07-09-2021 10:15 AM - edited 07-09-2021 10:21 AM
It's not that using Locals/Globals are always wrong (Like the Stacked Sequence.. 😛 ) but they are too often misused and cause race conditions.
I tend to put things like Calibration values, sailing factors, and etc. in a Type-Def Cluster and pass it through my sub-vi's, the use Unbundle by name to get the values out.
Similar to what you want, I store all my instruments specifications, scaling factors, and lots of other information in an XML file that is parsed and puts everything into my "instrument cluster" and passed through the VI's as needed
07-09-2021 11:05 AM
@Nokaroa wrote:
If I have a class for each stage, and I need to reference that data in multiple places, I still need to wire that class through every relevant VI which brings leaves me with the original problem, unless I make those classes global.
Are you not already doing that for your stage references?
Additionally, unless something in your object gets changed in a method, you do not really need to "wire it through" a VI. You just need to wire it into the VI. This makes it more obvious where objects get updated and therefore easier to debug. Look up Darren Natinger's "End Brainless Programming" presentation. He hits on this.
And one more thing I'll add. I tend to use an Action Engine to store my objects or DVRs to objects for a particular device type. The AE stores them in a Map, allowing me to perform the actions on a particular object by a name. This does add an additional level of wrapping, but I have found it to help in test sequences. And, yes, all settings are managed by a file of some type (currently JSON or XML).
07-09-2021 11:43 AM
@Nokaroa wrote:
Anyone who has read any forums about LabView knows that Global variables are typically frowned upon. I have a use case which seems common enough that I'd imagine most users have come across it once or twice, but GVs are rarely mentioned in those threads, so my intuition tells me I might be missing something.
I need to store hardware calibration data and some context data somewhere, and it's likely going to be referenced multiple places in nested VIs. I have some motorized travel stages which will have physical offsets set by the user only when assembling the system for the first time, and some context data that will impact algorithms. This context data will ideally be stored in the program's config file, and will never be changed except in situations where execution of everything else should be stopped. Having this data as a wire passing through many sub-VIs seems like a way to clutter the entire program.
Is this the mythical correct application for Global Variables?
I have used globals in this manner in the past, without too much issue. As said previously some care needs to be taken to ensure no problems or race conditions. Here are a couple of things I do that are helpful with global variables:
For something like calibration data where you want to ensure that that the value is not changed while a process is running, I do this below:
The False Case is wired straight through.
In the above case, the Global Variable (GV) is read on the first call of the process and that value is used throughout the lifetime of the process. If the user in this case wants to change FFT Units, then only new asynchronously called processes will have this change, currently running processes are unaffected.
The other thing I like to do is store all GVs in a single file. This makes it easy to write and read preferences at the beginning of a program. (If you allow your user to change options, this makes updating an INI file easy.) You can do something like below:
Read file with all global variables. Get the names and values programmatically.
Write file with all global variables. Get the names and values programmatically.
Write subVI: Use the variant pallete for data type parsing. Make a case for each data type.
Read subVI: Use the variant pallete for data type parsing. Make a case for each data type.
07-13-2021 09:02 AM - edited 07-13-2021 09:09 AM
I typically build a class in these situations, but by reference using a type-def control packaged in a Data Value Reference (DVR) as the class' private data. I then have setters and getters for all of the main elements within the DVR. This allows me to manage read and write access and track down which methods, functions etc. use the data. You can still end up with race conditions, but I much prefer by-ref than by-value classes for ease of use when wiring. I know this generally goes against the whole LabVIEW by-value paradigm, but I've been using it for years with good success.
You could also have a read-only class type which doesn't expose any of the setters and then have a write class inherit from this or have it as a component of the write class. That way you can prevent calibration data being inadvertently modified by VIs that should only ever be consuming the data.