Components

cancel
Showing results for 
Search instead for 
Did you mean: 

Current Value Table (CVT)

Hi all--I've been working on an update to the CVT which attempts to address the feedback provided in this thread, along with feedback generated from our own internal use. The result of that work has just been posted on the community as a beta version:

https://decibel.ni.com/content/docs/DOC-25841

 

The changes to the code are described in some detail on the community, so I won't prattle on about them here unless people have questions. The short version is that I tried to improve the performance of the code, add more data types, add some minor features, and make the basic API a little more friendly. It doesn't do is change any of the core design decisions of the original (switching from functional global variables to data value references, as an example), but it tries to improve on those choices (using attribute lookup rather than a linear search).

 

What I'm hoping to get out of you guys is some feedback on the code as well as any thoughts/bugs/features/designs that might come to mind.

 

Besides the core set of code, I am also interested in any issues that come up when attempting to use our other libraries, like the CVT Client Communication, CVT Data Logger, CVT IO Engine, and Tag Configuration Editor, with this beta update. As an example:In the process of streamlining certain things I also broke backwards compatibility with old tag files. To make up for this terrible crime I've included a compatibility layer which should make all code using version 2.x of the CVT work flawlessly with version 3.x. Is that usable? Is that enough? Should I change things to use the older files? These are the sort of questions I'm hoping I can get some help in answering.

 

Thanks!

0 Kudos
Message 41 of 164
(11,674 Views)

Hi everybody,

 

I am working in a machine control system where I am using around 50 vi's and around 400 I/O's. The machine is an assembly machine using 5 Fanuc Robots, 3 Torque Stations and 2 Leak Test Stations. Basically, this is my main components hardware:

 

-One cRIO-9076 as the SCADA

-One TPC-2515 for HMI

-Five Fanuc LR-Mate 200iC Robotics arms

-Fine SMC EX600 series distributed I/O manifolds with Ethernet/IP

 

I have all my phisical I/Os connected to the EX600 series manifolds from SMC and I Read the inputs and write to the outputs from the cRIO through Ethernet/IP. Actually, I have a main vi that call all the other sub-vi's in my application. What I do was connect all the inputs and outputs from the Ethernet/IP function to Network Share Variables to use them as required in the different sub-vi's. For my HMI, I bound the controls and indicators to the network share variables.

 

I develop the application and run the code from under my computer in the project explorer and everything work perfectly. The problem came up when I build an specification and deploy the application to the cRIO. Doing this the application do not run and I can't read any value in the HMI or execute any command to run the machine. In a previous call to NI technical support, after some troubleshooting we end up discovering that the cRIO resources are not enough to run my application because of the amount of network share variables that I am using. Since I connect all my I/O's to network share variables in order to distribute the through the different vi's as required and the machine have around 450 I/O's, I end up with the same amount of network share variables.

 

NI technical support told me that network share variables are a very resource demanding structure and that it is not recommended to use more than 25 or 30 (I am using around 450). So they recommend me to change to a more performance improved structure like nekwork streams or something like that. After some research and readings I found that CVT could be my best and easy option to make the change to my application.

 

Well, I change all my network share variables with static read or write tags upon the case. With the TCE I create all the tags. Now, I have the following questions:

 

1. In the TCE I add a controller create the tags under it using "Local Tags". Is local tags ok or I should use "CIE Tags" or something else?

 

2. In my research I found, and I am not sure if this is correct, that I have to create tags for my HMI also. Is this correct?

 

3. If answer to question 2 is correct, Do I have to create a nother tag file or it should be the same tag file as the one for the controller?

 

4. For the HMI tags, Should I use Local or Network tags?

 

5. If answer to question 4 is network tags, taking into account that I can have for example a numeric control in my HMI, I connect that control to a write tag called numeric, to get the value in my controller, Should I create another tag called numeric in my controller and attach the numeric tag in the HMI to the numeric tag in the controller? Can both tags (the one in the controller and the one in the HMI) have the same name or should they have different names?

 

 

I will appreciate any support in this matter. Thanks to everybody in advance.

Ferdinand Martinez
FMO Automation LLC
0 Kudos
Message 42 of 164
(11,642 Views)

Hello Ferdinand,

 

I'm not sure that I 100% agree with the theory that 450 shared variables is too many, although it may not be able to satisfy other performance requirements you may have. The engine itself is expensive, and any subscribers can add CPU and memory cost, but I know I've seen over 1000 variables loaded on a target. I'd be curious as to what specific troubleshooting was performed to prove that the shared variable engine was the problem.

 

Putting that aside for now, the CVT is a good choice, although it is a little lower level than shared variables. This, I think, is what is causing the confusion. The CVT achieves good performance by separating tasks. Rather than attempting to do everything, its purpose is to store and retrieve data. This purpose can be augmented using different tools, including the tag configuration editor you have already found, the cRIO I/O Engine (CIE), CVT Data Logger (CDL), and the CVT Client Communicaition (CCC) libraries. The tag configuration editor is designed to provide the various libraries' loaders with the information it needs to begin running. For example, using the tag configuration editor and selecting a tag as a CIE tag means that, when you use the CIE library, it will map scan engine variables (AI0) to CVT tags ("pressure 0" for example). This editor also allows you to configure tags as being controller tags (for the cRIO) or HMI tags.

 

To specifically answer your questions:

1) If you are using any scan engine tags, you can bring these directly into your program using the CIE, in a similar manner to the way scan engine tags are automatically imported into the shared variable engine. If you wish to use this library, you would mark those I/O items as CIE tags, and specify the address path (mod1/ai0 for example). Otherwise, you would use local tags.

2) This is correct, your HMI will need all the tags you intend to transfer across the network, along with any other tags you wish to use locally (a global stop, for example).

3) The tag file is the same. However, you will be loading that tag file using different parameters on each system (the "Target Name" parameter). Each reference library will also interpret the tags differently. For example, the CVT will load all tags but the CCC will only look at items configured as network tags.

4. Those tags you wish to read from the cRIO should be configured as network tags, with the "Bind to tag path" configured to look at the cRIO controller. I would like to note that the file format of the tag editor is fairly straightforward, so you may save time by opening the file in notepad and copying/pasting subsections of code (be sure to back up any files, just in case).

5. You are correct about the procedure, and the names can be the same. As described above, the controller will create a tag named numeric, the HMI will make a tag called numeric, and the copy of the CCC running on your HMI will copy the controller value of "numeric" to the local value of "numeric".

 

Hopefully this clarifies the set-up process for you. I would highly recommend the following resources:

-An architecture quite similar to your overall goal: http://www.ni.com/white-paper/6145/en

-A similar article: http://www.ni.com/white-paper/6181/en

-The "scan loop" described here: http://www.ni.com/white-paper/6121/en#toc3

 

Thanks,

Daniel

Message 43 of 164
(11,622 Views)

Ferdinand,

 

I agree, the NI recommendation of 25-30 shared variables is VERY conservative, especially if you are talking about simple data like Booleans and numeric. I have multiple systems running (cRIO-9022's) with 800-1000 Network Shared Variables, many timed loops, and 10+ MODBUS IO Servers (which increases the Shared Variable Count, as they are run off the SVE). I only see about 45-50% CPU use.

 

However, one thing I have done to help reduce CPU use on the cRIO is to decrease the Network Publishing Period (ms) option under the cRIO properties page (see attached screenshot) to 1000ms. (Also note: when using the scan engine, all of the IO points on the cRIO are created automatically as Network Shared Variables, which are updated based on this setting. See screenshot). Reducing this publishing period decreases the resources needed from the CPU, as variable updates are only being published (to the network level) once per second, instead of the default 10 times/second. I have also reduced my scan engine time from 10ms to 100ms.

 

Note: these are the settings that work for my application, yours may be different, but you can experiment with changing them.

 

 

Personally, I don't see a good reason to re-invent the wheel using the CVT VIs. The Shared Variable engine has seen a number of changes since it first came out, and it works well (in my applications). To me, it is more in line with traditional PLC programming "Tags", which is an industry standard. You can take someone who has only programmed Allen Bradley PLCs, show them what a NSV is, and they understand how to work with it as a Tag.

--------------------------------------------------------------------------------------------------

--CLD--
LV 6.1 to 2015 SP1
Download All
Message 44 of 164
(11,613 Views)

This is great! It was about time CVT got updated to use the variant to store the array indeces. Performance gains look impressive. The group API looks extremely useful! A much better way of how I did group reads with CVT 2.0- an action engine/ LV2 style global where indeces where looked up on first call and Index API used for subsequent calls. 

0 Kudos
Message 45 of 164
(11,600 Views)

Daniel & JimMacD,

 

Thanks a lot for your replies and clarifications. I going to go ahead and read the articles referenced by Daniel. Now that I am submerged in the CVT I want to learn more and try it, so I will complete my conversion and once done compare both programs performance. However, share variables are definetely more easier and faster to create, configure and use them through a code.

 

In the other hand, taking into consideration that I have to put this machine to run from the cRIO ASAP, JimMacD has given me hope. My application runs perfectly from my development computer, so maybe with this modifications it runs from the cRio also, I'm goint to try that tomorrow and post the results.

 

Also, maybe this has nothing to do but, I am using "wait until next millisecond multiple" in all my while loops, do you guys thinks that is ok aor do you recomend the wait function or something else?

 

 

Ferdinand Martinez
FMO Automation LLC
0 Kudos
Message 46 of 164
(11,588 Views)

Ferdinand,

 

For timing loops on the cRIO, typically I use the "Timed Loop Structure" at the top-most VI (ex: main.VI). See here: http://zone.ni.com/reference/en-XX/help/371361G-01/lvconcepts/con_timed_structures/

 

Timed Loops are designed to enable deterministic code with minimal jitter from loop-to-loop. You can also do things like set loop timing, set priorities (so certain loops execute with higher priority than other loops), read how long iterations are taking, and monitor if loops are executing late,etc..

 

I HIGHLY recommend reading the "cRIO Developer Guide" here: http://www.ni.com/compactriodevguide/    It goes into a lot of detail about best practices, configurations, etc... Download the whole guide as  PDF and read through it. Chapter 3 talks about designing your application with timing considerations for deterministic behavior.

 

Also, there is a tool NI provides called the "RealTime Trace Execution Toolkit" (included in the Developers Suite) that lets you benchmark your application and see how long loops are taking to execute, if they are over-lapping, etc...http://sine.ni.com/nips/cds/view/p/lang/en/nid/209041   If you have it, it is worth learning to use.

 

 

One other thing you may want to consider to conserve CPU resources is to slow your loops down on "background tasks" (ex: logging to file, updating variables to display on an HMI, etc), things that can execute every 500ms or 1000ms and not suffer. If you use the Timed Loops, it is easy to set these to lower priorities, and longer Timing periods.

--------------------------------------------------------------------------------------------------

--CLD--
LV 6.1 to 2015 SP1
Message 47 of 164
(11,571 Views)

This is great! It was about time CVT got updated to use the variant to store the array indeces. Performance gains look impressive. The group API looks extremely useful! A much better way of how I did group reads with CVT 2.0- an action engine/ LV2 style global where indeces where looked up on first call and Index API used for subsequent calls. 


Thanks :). I think the item you are looking for is the "Get Index Set" and "Read Index Set" under "Bulk Tag Access". It is limited to a single data type, but the group API does the same thing under the hood if you need multiple data types.

 

 


Personally, I don't see a good reason to re-invent the wheel using the CVT VIs. The Shared Variable engine has seen a number of changes since it first came out, and it works well (in my applications). To me, it is more in line with traditional PLC programming "Tags", which is an industry standard. You can take someone who has only programmed Allen Bradley PLCs, show them what a NSV is, and they understand how to work with it as a Tag.


The big advantages the CVT provides are read/write performance (not an issue on your PC, but a big issue on some of our older embedded targets) and dynamic creation/access. The shared variable engine allows for dynamic access to variables from a string URL, but (a) that only works for shared variables, not single process shared variables and (b) performance is very slightly slower for that API. There are also some confusing points if using both the static and dynamic APIs, as described in this document.

 

 


Also, maybe this has nothing to do but, I am using "wait until next millisecond multiple" in all my while loops, do you guys thinks that is ok aor do you recomend the wait function or something else?


For most loops, use wait until next ms multiple rather than wait. Behavior is closer to what you expect for a loop.

 

 


I HIGHLY recommend reading the "cRIO Developer Guide" here: http://www.ni.com/compactriodevguide/    It goes into a lot of detail about best practices, configurations, etc... Download the whole guide as  PDF and read through it. Chapter 3 talks about designing your application with timing considerations for deterministic behavior.


+1 the whole thing is very good and was updated about a year ago.

 

 


For timing loops on the cRIO, typically I use the "Timed Loop Structure" at the top-most VI. Timed Loops are designed to enable deterministic code with minimal jitter from loop-to-loop. You can also do things like set loop timing, set priorities (so certain loops execute with higher priority than other loops), read how long iterations are taking, and monitor if loops are executing late,etc..

 

One other thing you may want to consider to conserve CPU resources is to slow your loops down on "background tasks" (ex: logging to file, updating variables to display on an HMI, etc), things that can execute every 500ms or 1000ms and not suffer. If you use the Timed Loops, it is easy to set these to lower priorities, and longer Timing periods.


This is one point that needs clarification. Timed loops are very good at doing what they are designed to do. That is, they provide very explicit priority control, timing control, and runtime diagnostics. They are intended for very specific use cases, as outlined in "Ch 3: Implementing..." of the cRIO dev guide. Specifically:

  • Closed loop control (+decision making logic--any decision-making logic that needs determinism is probably related to control, so I am lumping it here).
  • Safety logic

It also lists scanned I/O access--for that, I personally prefer using a while loop with "Synchronize to scan engine.vi" unless I am using closed loop control using that data (so I want all outputs to be updated simultaneously and deterministically). 

 

It is not recommended for the following (same location in the dev guide):

  • File I/O
  • Network communication
  • Tasks involving large data allocations (like some processing tasks)
  • calls to non-deterministic dlls and drivers

The reason for this comes from the behavior of timed loops. Besides having additional overhead compared to while loops, timed loops are higher priority than the rest of your code and can lock down your processor for as long as they take to execute. The key concept here is bounded vs unbounded operations. While file I/O may be fast right now, there is no part of the code that says it will always be fast. There is not even a timeout. File I/O takes however long it takes, so if you have that code inside of a timed loop, that loop will lock down the processor for however long it takes. Networking, memory allocation, and non-deterministic driver calls have the same core issues, which is why they should not be used in timed loops. For a more in-depth discussion, this help document explains some of the same concepts, although it doesn't directly apply it to the caveats of the timed loop.

 

Short version of the above is this: the timed loop is a great tool, but you should think of it as a tool. It is not better than a while loop, it is different than a while loop and should be used only when you need the tools that it provides. Otherwise you can get yourself into weird situations.

 

 

 

Message 48 of 164
(11,563 Views)

Daniel,

 

Thanks for the clarification on the caveats of the Timed Loop.

 

Most of what I have used them for is control loops. I do have file IO occurring in a timed loop, but can change that to a standard while loop easily. Maybe the reason it has not hung up my code is I only have Timed Loops (not while loops), so they all run at that higher priority.

 

 

 

--------------------------------------------------------------------------------------------------

--CLD--
LV 6.1 to 2015 SP1
0 Kudos
Message 49 of 164
(11,556 Views)

I figured that was probably the case from your description, but it was still worth clarifying for future readers. 🙂 I think the other point where you would run into trouble is if you were getting close to a maximum CPU usage and loops started running late, but it sounds like you were doing fine there. 

 

Thanks,

Daniel

0 Kudos
Message 50 of 164
(11,547 Views)