From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How do I get control names from within nested clusters? RT

Solved!
Go to solution

I decided that it was cool to have nested clusters. For example, all the analog data I read in my control application is in a single cluster, which is composed of categorical clusters (ie "pressure", "temperature", etc). Now it is time to log data to a .tdms file, and it sure would be convenient to generate a pair of arrays from that 'root' cluster containing the labels of all the numeric controls and their data.

 

I found this thread, http://forums.ni.com/t5/LabVIEW/Is-there-a-quot-Get-Cluster-Names-quot-VI/td-p/666555, which uses a property node to retrieve the labels of the controls in the root cluster. This is great, but I only get the labels of the nested clusters (and none of their elements).

 

My lab-fu isn't strong enough to figure out an elegant solution to this. I can brute force it by unbundling and making indicators, then using the property note separately on them... but I suspect there must be a better way!

 

The attached VI is my best effort at solving this. It works, but I'm concerned that it's not the best code for the following reasons:

 

1. Am I really allowed to point to front panel items when this subvi  will be deployed to RT as part of a startup executable?

2. If the subvi is within a loop, what do I do instead of 'build array' to avoid memory use issues? All the NI examples use this and I've read so much about how I shouldn't.... what is the functional alternative?

 

Many thanks for your time!

Download All
0 Kudos
Message 1 of 12
(4,510 Views)

Sorry I can't open your VI, I only have LabVIEW 2012 available at the moment.

 

No, you cannot use property nodes on front-panel items in a real-time application. I highly recommend using the Variant functions (vi.lib\utility\VariantDataType) instead. Among other things, those functions provide a way to get the names of all elements in a cluster, as well as a variant representing any nested clusters.

 

I assume this is code that runs once at startup (since the cluster can't change during execution), so putting build array inside a loop shouldn't be a major performance hit here. Generate the array of strings once at startup and hold onto it.

Message 2 of 12
(4,500 Views)

Thanks, that sounds like it might take care of it. I'll look at the variant stuff. Here's my vi in 2012 for posterity, i guess.

0 Kudos
Message 3 of 12
(4,492 Views)
Solution
Accepted by topic author matteci

Here's a version that uses the Variant VIs, will handle any level of nesting, and works on RT. The use of Delete from Array and Build Array is not too efficient, but shouldn't be a problem if you only run this once when the program starts. If you use Type Cast to convert from a cluster into an array as shown here, all the numerics should have the same representation (ie don't mix single- and double-precision floating points, nor ints and floating point values), otherwise you'll get weird data without any warning or error.

cluster names scratch2012 modified.vi

 

Also, your original code had an uninitialized shift register. Be careful about that - if you were to run that code twice, the second time the Data Labels Array would be twice as long as it should be, because the shift register would start out containing the values from the first run.

Message 4 of 12
(4,434 Views)

nathand,

You're the man. Thanks for this, it's very informative, exactly what I needed, and I wouldn't have been able to put it together without the example you made. Also, thanks for pointing out the uninitialized shift register. Programming style with regard to proper handling of arrays is still a little mysterious to me. I'd like to iron it out a little better for myself.

Hope it's okay for me to ask some new questions now! They're related:

 

-I went looking through my palette and couldn't find the variant VIs you used in the 'programming-->cluster, class, & variant-->variant' section. I found them where you said they would be (vi.lib). I've since added them to my palette, but I wonder: How do I know about this stuff without the help of wizards sucn as yourself? Did I miss something? How many other functions are already on my machine that would make life easier?

 

-I plan to use these arrays within a subvi. Do I need to make sure that every array in my application is initialized once at startup? I'm guessing so, at least if the size is known at that time. It seems messy to me to run wires and terminals from the toplevel vi into every subvi for this purpose. What other options do I have? Is using 'first call' to initialize an array appropriate? I think I've had some strange behavior result from trying to do this.

 

Maybe you can point me to some reading material specific to these more mundane tasks of managing memory in RT. I'd love to have a good reference.

 

Thanks again. +kudos.

 

Matt

0 Kudos
Message 5 of 12
(4,384 Views)

@matteci wrote:

 

I've since added them to my palette, but I wonder: How do I know about this stuff without the help of wizards sucn as yourself? Did I miss something? How many other functions are already on my machine that would make life easier?


When the question is asked this directly, I have to answer. 😉

 

Check out my Hidden Gems in vi.lib community group, that provides (1) a presentation discussing many of the VIs "already on your machine that would make life easier", and (2) a VIPM install to get all of those VIs in Quick Drop/the palettes.

 

And yes, the VariantDataType VIs are the first thing I discuss in the presentation. 😉

Message 6 of 12
(4,380 Views)

Thanks, Darren, that's amazing. Proves that it doesn't hurt to ask that sort of thing. Between the two of you I feel like I'm rubbing shoulders with celebrities.

 

Matt

0 Kudos
Message 7 of 12
(4,373 Views)

There's no one source fror all the tricks. Browse the forums, read the help files, look at examples, talk to coworkers, attend user group meetings - it all helps.

 

I wouldn't worry about initializing every single array at startup; in many cases LabVIEW will already do that for you if the array size is known at compile-time. However, this is a good example of a situation where you can avoid redundant computation by getting the string array once and then storing it. There are several ways you can do this. One, as you mentioned, is wires. Another option is a Write-Once, Read-Many (WORM) functional global variable. The idea is that you compute a value on the first call and store it in an uninitialized shift register; on every subsequent call you just return the value from the shift register. You can find examples on this forum. There's no problem with the "First Call?" function. If you share your code that seems to have weird behavior, we might be able to explain it. [Side note: One instance I can think of where "First Call" appears to have weird behavior is in a shared-clone reentrant VI, where you don't know until runtime whether you're getting a new instance (in which case it's the first call) or an existing instance (in which case it's not).]

 

The memory management rules for RT are mostly the same as for LabVIEW generally. I can't point you at one specific reference, but searching this forum and the NI site more generally should provide some whitepapers, as well as good (and occasionally confusing) discussions.

0 Kudos
Message 8 of 12
(4,359 Views)

OK, that's mostly as I suspected. I feel like I find a lot of example code that I'd love to incorporate or take ideas from, but this method of learning to program always leaves open the issue of improper context for a 'lifted' solution.

 

The WORM might be good, I've seen it referred to but never quite internalized it. Heh, internalized worms don't sound good.

 

I think the first call situation might've had some other stuff going on, one of those situations where I learned some things and threw away the code instead of spending the time to dig myself out. If I find it again soon I'll be back.

0 Kudos
Message 9 of 12
(4,354 Views)

Hi again,

I'm of the impression that using 'type cast' to get the numeric data out of the cluster is making a new memory buffer every time it's run, and is similar to using 'build array'. I'm on board with the idea of using it to generate the appropriately sized array once, and then keeping the array to modify in the main program loop.

 

A question about this, though, is how should I update this array with the cluster values thereafter? I used 'replace array subset' in the attached VI, but finding the correct position to replace for each subarray seems a little ugly and goldbergish. Is this an appropriate way? Is there something simple that I could do instead, without causing memory fragmentation, etc?

 

 

Thanks in advance, I sort of feel like my brain's just not working right today. Apologies if this is dumb.

 

m

0 Kudos
Message 10 of 12
(4,294 Views)