LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

PIDs in Reentrant VIs and Class Inheritance

Hello, 

 

I'm trying to make a simple class to use PIDs with our existing system. It seems that the clones are randomly switching between the class instances which causes the PID to jump of course. It didn't seem to matter if the VI is setup for preallocated clones or shared. The Run.VI has a loop to get data from the larger system, run the PID VI, then write data back to the system. The PID works great if only one is on at a time or if I use one for "PID Advanced Auto Tuning" and the other on "PID Auto Tuning (Temperature)". But ultimately I want to have 5 PIDs running in parallel so I want to solve this clone issue. Previous posts from 2014 suggest launching the clones as asynchronous will call and collect but I'm not sure that is applicable in this situation. My background is in PLCs so maybe I'm just using Labview's PIDs completely wrong. I've also failed to get the auto tune feature to spit out anything useful. 

 

Why would the class instance not use the dedicated clone when it's preallocated?  I'm not sure how to work around this issue besides making absolutely everything "in-line", which sounds obnoxious.

Furbs_0-1737152572913.png

Furbs_1-1737152874014.png

 

 

0 Kudos
Message 1 of 8
(121 Views)

Hi,

 

From the symptoms and partial code screenshots you gave, it seems the code you are trying to run in multiple parallel tasks is using a resource that is shared among the tasks, typically a non-reentrant or shared clone VI. You will have issues if that non-reentrant or shared clone VI is stateful (meaning: holds data from its previous execution), because the data may be mixed up between your tasks.

 

A VI is stateful when it contains:

 - an uninitialized shift register;

 - a feedback node (except when its initializer terminal is tied at the border of a loop);

 - a "First Call" node;

 - a stateful subVI (like the PID functions, any "Point by Point" mathematical function, ...)

 

So, make sure all the VIs (and subVIs) that run in the parallel tasks are configured as "preallocated clone reentrant execution", unless you are sure they are not stateful.

 

Then, issues can also come from the using of other types of shared resources like global variables, shared variables, any kind of refnum, files, calling a stateful dll, ... 

 

Otherwise, please attach your code so we can investigate in more details (save for previous version, max 21.0).

 

Regards,

Raphaël.

Message 2 of 8
(109 Views)

Everything is a clone besides the main VI that calls the loop I posted. That loop is a shared clone, part of the PID class. The PID itself seems stateful, since it's calculating error and change in error. I assumed the VIs would always use the same clone instances, but they are randomly swapping, which is confusing.

 

I think I posted all relevant code. I didn't want to weight it down with all the dependencies, but here you go. 

 

Furbs_0-1737159394692.png

 

0 Kudos
Message 3 of 8
(98 Views)

@Furbs wrote:

I assumed the VIs would always use the same clone instances, but they are randomly swapping, which is confusing.


Nope, a shared clone VI is like a pool of anonymous clones. When LabVIEW needs to call the VI, it will take the first available clone in the pool. If none is available, LabVIEW allocates a new one. Then, when the clone finishes executing, it goes back to the pool to be reused later by possibly another process.

 

This is just how a shared clone VI works. Note that without this behavior, making a recursive VI would be much less easy.

 

In your case, every method of your class should be a preallocated clone VI instead.

0 Kudos
Message 4 of 8
(91 Views)

The shared clone is not suited for statefulness as in a shared clone any of the available clones can be used in a instance to satisfy the dependency. Since there is no guarantee that the same clone will be used, you will end up with data mix-up.

 

The ideal implementation should use a pre-allocated clone for each instance (PID loop) to store its unique data whereas the rest of the logic are stateless and can be shared clone.

Santhosh
Soliton Technologies

New to the forum? Please read community guidelines and how to ask smart questions

Only two ways to appreciate someone who spent their free time to reply/answer your question - give them Kudos or mark their reply as the answer/solution.

Finding it hard to source NI hardware? Try NI Trading Post
0 Kudos
Message 5 of 8
(88 Views)

The advanced PID with Autotuning is set to Shared Clone. Do I need to change NI's version as well?

 

For classes, it only allows you to use Shared Clones for VI's that are inherited. I never understood why this would be but it seems like a significant obstacle for the use of the inherited class model. Is there a better way? I can make modifications so the relevant VIs are only Preallocated but it would be good to know for future use of the classes. 

0 Kudos
Message 6 of 8
(75 Views)

From the attached code, "Cont PID Temp.vi" must be configured to preallocated clone (just as "Cont PID.vi"), but I guess this will prevent you from making it an inherited method...

 


@Furbs wrote:

The advanced PID with Autotuning is set to Shared Clone. Do I need to change NI's version as well?


Unless you mistakenly modified NI's VIs, they should have the right reentrancy configuration.

For example, VI "PID Advanced Autotuning" is a preallocated clone VI.

 


@Furbs wrote:

For classes, it only allows you to use Shared Clones for VI's that are inherited. I never understood why this would be but it seems like a significant obstacle for the use of the inherited class model. Is there a better way? I can make modifications so the relevant VIs are only Preallocated but it would be good to know for future use of the classes. 


Yes, that is a limitation for method overrides. If it was not the case, LabVIEW would have to pre-allocate a clone for each possible override, just for a single call. Even if it would be possible for simple cases, for big class hierarchies this would make huge impacts on memory consumption. And we are not even talking about dynamically loaded classes, which by definition are impossible to preallocate. On the contrary, shared clone VIs are allocated only when needed at runtime.

 

An alternative is to not use stateful elements at all. Store every data in your private class data. Since all PID VIs are stateful, you would have to copy their code and make your own versions that do not use the stateful elements I listed in my first comment.

 

I agree that NI should provide both stateful and stateless versions of the PID VIs...

Maybe that could be suggested in the idea exchange...

0 Kudos
Message 7 of 8
(71 Views)

I think you can guarantee one clone per object by opening a reference to the VI and bundling the reference in the private data and calling by reference. I would only do that for 3rd party stateful VIs that are complicated (so the PID VIs count...).

0 Kudos
Message 8 of 8
(29 Views)