My team is currently developing a script to run autonomous routines and need to use recursion in LabVIEW (calling the same sub-VI). All of the programmers on our team are used to object-oriented programming and are a little confused on how to make an instance variable in LabVIEW. We currently have a feedback node running through a while loop and need each node to be unique to each instance. Right now, all of the feedback nodes point and use only one instance (chosen in a race condition…whichever is hit first). Is there a way to change this/make instance variables/nodes in LabVIEW with recursion?
The “group” command in the script looks like this and is intended to run multiple commands at the same time (or as close to the same time as possible):
I think what you are looking for is how to make your sub-VI re-entrant.
Go to your VI’s front panel and right-click on the VI’s icon in the upper right corner of the window. Select “VI Properties”.
When the properties dialog pops up, change to the “Execution” properties. Switch from the default to one of the re-entrant execution models. Our team usually uses non-shared pre-allocated clones, which use more memory, but seem to have less issues. De-select anything that is now indicating conflicting settings (like debugging support). Apply the change.
I’m recalling this from memory, so I may not have all of the correct words above. Because of having to disable debugging, you obviously want to think hard about this, and only do this for code that needs to be re-entrant with lots of instances running within the same thread.
You need to look into a state machine architecture. I will give you what you are looking for. There are examples in LabVIEW. This is how we do auto every year. We build an array of steps and the state machine takes care of the rest. It is easy to change and easy to take care of.
If you look inside of the navX LabVIEW code you will see an example of how this works. I will answer any questions you have if you choose to move down this path.
Unfortunately the vi is already reentrant. As far as I know in order to make a recursive vi this is already a requirement. However the problem is that labVIEW does not allow the use of preallocated clones in a recursive vi because it does not know how many clones are needed. Thus the vi must use shared clone reentrancy. And it is here where the issue arises; because the vi uses shared clone reentrancy the value of the feedback node is shared between different instances of the vi.
Perhaps you might want to reconsider the design of your program.
Feedback nodes are great if you want the NEXT iteration of a program to have the value calculated by the PREVIOUS iteration of the program. Think about if you want to count the number of times a math function came up with the answer 5 - you’d compare the answer to 5, and if it matches you’d feed into the feedback node a value that was incremented (otherwise, you’d feed a value that didn’t get incremented). The feedback node prevents you from having to perform tricks like uninitialized loop inputs or other methods of keeping a local-persistent-value-storage (without resorting to global variables) - because that’s what a Feedback node REALLY is, it’s local persistant storage within the scope of the VI.
Shift Registers in a loop are another form of Feedback Node, where in a loop each iteration of the loop can get the previous values calculated/output by the loop in previous iterations (because, maybe, you want to average the last 3 iterations of the loop but you want LabVIEW to manage all that for you). The Feedback Node is a way to do that, just without the presence of the loop. In that case, the shift register node in the loop itself manages all of the persistent storage of data it receives.
My biggest rule when programming in LabVIEW is that if I see a Feedback Node, I’m probably doing things wrong. I don’t mean that there aren’t very valid and useful ways of using the Feedback Node - it solves a lot of very specific problems really well - but when I use the Feedback Node I’m usually using it wrong (even though I can usually convince myself otherwise for the time being).
When you program a recursive function in a text language, you don’t use persistent storage within the function - you pass values via input/output parameters. Do the same in LabVIEW. Here’s an article that may help:
Thank you for all of the responses; to address a few of them, the code is in fact a state machine - the vi shown in the screenshot posted is in a loop and the order and parameters of states the code executes is determined by a text file allowing quick changes to the auto routine without redeploying. The recursion of the code exists in order to allow multiple states to run simultaneously.
This is the solution that we originally though of (and have since executed), but didn’t want to use as it would convolute the code. We hope to find a way to make the vi shown something akin to a method in a class, with each level of recursion instantating a new class.
Sounds to me like you want to use LabVIEW Object Oriented Programming (LVOOP), which IMHO is an advanced topic when programming in LabVIEW (likely something you’ll want to learn in the offseason, definitely not something you’d want to start using right now). However, I believe what you want to do is possible in that architecture. Here’s a really good set of documentation/examples that can get you started with LVOOP.
I have two thoughts…
I wonder if using command and control could help eradicate the problem you are trying to solve. My thought here is that perhaps if you separated the mechanisms (drive, intake, lift, etc) you control, they could update independently and save some headache.
Could you use a formula node combined with your text file to outsource your recursion to another app (or a rasperry pi, arduino, or something)? In looking at your screenshot, it seems a, you have already done some of this, and b, it is difficult to see exactly what your end goal is. We have had some success with using the formula node to embed some basic text based programming functions into labview. I am aware that that is a clunky work around.