Global Variables

I have been programming for many years now, and for some reason, I have always struggled to get Global variables to work. We’re using global variables to send data to multiple custom VI’s that we made last season, but for some reason, i cannot seem to figure out how to get them to work. I will make a global variable and I cannot seem to connect them to each other.

I could use some help figuring out how to code them. I know how they work I just can’t get them to for some reason

Is this how you are creating your Globals?
http://www.team358.org/files/programming/ControlSystem2015-2019/labview/CreateGlobal.pdf

Ok, I think I was forgetting a few steps. But I am wondering about writing to a global variable from multiple locations at a time, how would you prevent that because we have a lot of global variables. So would we have to like stop one before we send it to the next place? We are using them in custom VI’s that we made for auto and some of them use the variables that other VI’s use, is that ok?

You may want to look at the Command and Control architecture, instead of the basic. We tried to do what it sounds like you are doing to make some semi-autonomous modes in tele-op. It was a lot of work, and we tried making a bunch of global locks (Boolean) to prevent multiple concurrent calls. Eventually we put in a lot of game mode checking to allow or prevent writes to globals, in an attempt to make them exclusive.

When we sat through Greg McKaskle’s C&C presentation at CMP, it was like having heaven open up to shine light on us.

Global variables should be write in only one place, read in many places.
Try to design your code that way.
In any case, insure that the Global cannot be written to from more than one place at a time.

If you have to write from several places, then create a vi (Non-reentrant execution) that performs the write (one place) for other vi’s to call when they need to change the global.
Non-reentrant execution is one of the VI Properties (found from the vi front panel under “File”). In VI Properties it’s under Category Execution.

I second what Mark just said.

Ok, I understand now thank you.

Also, keep these design decisions in mind when you’re doing this. It’s often said the method Mark laid out “eliminates” race conditions. This isn’t accurate. While the VI can only be opened once at any point, you still run into awkward situations when two areas try to write to it.

The suggestion to take a look at Command and Control is a good one. I don’t know the date. But, the FIRST Updates Now Twitch feed is planning to have a stream in the next couple weeks to discuss Command and Control.

Take a look at: Command and Control Tutorial - NI Community if you’d like a primer. I gave this tutorial to my students and within 5 hours they’d completely reprogrammed their robot to use this architecture instead.

I didn’t see this thread prior. It looks like the next stream (command and control) is set for tomorrow.

See https://frclabviewtutorials.com/fgv/ for an example of setting up a VI like this

The internals of LabVIEW prevent the race condition when using non-reentrant VIs. The internal scheduler will only allow one instance to run and all other places attempting to use the Vi will be blocked until execution has been completed. This will effectively serialize your code when accessing a non-reentrant VI from multiple places at the same time.

20+ years as a professional LabVIEW developer
Certified LabVIEW Architect
LabVIEW Champion

That’s not really accurate unless you very loosely define “race condition.”

The internals of LabVIEW prevent the VI from being run simultaneously. With FGVs, you’ll call the VI twice and one call will take priority. The second will be blocked waiting. If you have a read, you’re not guaranteed to read either of the specific values as the read is also blocked by the original write, and potentially the second write.

While you won’t have two places writing at the exact same moment, the behavior you wish to avoid with a race condition is strange behavior that appears when writing to the same value from multiple locations and being unsure of which you are reading.

The typical LabVIEW example of a race condition is a pair of parallel computations with a mixture of local variables being used. If you replace those with FGV, you still don’t guarantee the order they run. You still have multiple potential outcomes. You still have a race condition.

Running in serial does not eliminate race conditions unless you can guarantee the order is constant. With the inherent parallelism, you can’t make that guarantee.

With respect to race conditions this is true. However, non-reentrant VIs eliminate the need for other types of wrappers to prevent simultaneous access to the global variable. It will guarantee that only one writer will have access to the memory space at one time. It will prevent races conditions if the VI does a read than write operation since all of that access will be performed in a single thread and no other outside sources will be able to modify the global (provided all access is through the non-reentrant VI) while the operation is taking place.

If all access to global variable is done through a non-reentrant VI you are guaranteed you will be getting the latest value that has been written to it. There can only ever be a single reader or writer to that value. If using this technique you can eliminate the global variable completely and simply use an uninitialized shift register inside the VI. This construct is known as a Functional Global.

A true race condition is when you have multiple writers to a global variable and your code looks like read global, do something, write global. If there are multiple writers you have no guarantee that some other part of the system didn’t change the value after you had read it. If all of that processing occurred within a non-reentrant VI you would be guaranteed that you were working with the latest value.

However, when using global variables the safest approach is to only have one writer to that global. In the case of the robot code you can violate this rule if restrict the writes to specific code blocks that will never run at the same time. For instance, autonomous and teleop will never run at the same time so it would be safe to have a single writer in each of those blocks of code.

I think we’re starting to derail this thread a bit.

Unless both the read and write take place within the non-reentrant VI, you haven’t eliminated the race condition. That’s a product of a redesign more so than the non-reentrant status. Most FGVs I’ve seen include the same race condition we’d see if there wasn’t a FGV.

Wrapping up the global into a non-reentrant VI doesn’t eliminate the race condition by itself.

Ok so I have been read through the Comand and Control page and I understand a little bit but I’m still confused. So say I want to program my drive motors for teleop play, would I put it in the new Drive vi’s. Or still in teleop. and say I wanted to make a climbing program would I just make a new command and it would automatically do it. And Could I program that command to a button? Because that’s what my mind is making of it.

You’d program an “immediate” command in the drive subsystem. You’d call that command from teleop. When you add these commands, you create subVIs that can be called elsewhere.

If you wanted to make a climbing program, you could do something the architecture calls a “macro.” With the option to run the VI or wait, you could allow this to run without waiting for it to finish. That frees up your teleop loop to come back and check things again while that runs in parallel. If needed, you could send it a command to halt.