05-24-2011 08:21 AM
You're bringing up a topic that we have been looking at and planning to implement for a while. Our plan is to use variant attributes to store all of the meta data about the tags, but keep the values stores in a array in a shift register.
The binary search in the variant attributes is much faster than the current Search Array implementation, but accessing the values by Array Index is faster than getting them from the variant attributes (assuming that it is okay to group them by data type). We have benchmarked the different solutions on a slower cRIO controller since that is our least efficient processor platform targetted by the CVT solution.
The nice thing about the current implementation and API is that we can easily change the implementation under the hood without affecting the API and the application built using the CVT. So down the road we can continue to optimize the implementation and not require users to update their code, other than installing a newer version of the CVT.
One reason that we like the variant attributes as compared to a sorted list is that we would like to add the ability to create or add new tags after the Initialize function is called. This means adding more tags while the application is running, which would be difficult with a sorted list of tags.
06-23-2011 03:16 AM
Ok, that sounds good. Is this something that is right around the corner?
I can do the modification very quickly myself, but it's always nicer to have it in an "official" version so that we do not need to distribute and maintain a customized version.
07-08-2011 10:28 AM
I recently stumbled upon the CVT/CCC/TCE reference libraries and am interested in learning about them. They seem like a very scalable solution, however I'm not sure how to go about implementing it.
I'm in the process of designing a SCADA system for my company to manage cRIO controlled manufacturing cells. I'll briefly describe the scenario:
-cRIO running a custom setpoint profile that controls oil/water heating units (via MODBUS)
-Records/monitors TC data
-Handles user pushbuttons/indicators and StackLights
-Controls Hydraulics systems
-Contains a Citadel Database/uses DSC module (already bought this) to log values (ex: Thermocouples) from each manufacturing cell
-Has a application (VI compiled as a stand-alone .exe) running for each manufacturing cell
-this app monitors for alarm conditions, sends out messages/alerts/e-mails
-manages who is "logged in" to process, who has write control/read-only
-connects to the Central server (Citadel Database) to display relevant information
-allows user to input data (ex: part #s and job #s) and start cycles on the cRIO
This is the basic design of the system, it is not currently in existence. The theory behind it is making the manufacturing cells "PC independent" in that the HMI PC is NOT required for anything other than initially telling the cRIO to run, and giving it the appropriate cycle information. Once this happens, the HMI could blow up, and in theory the operator could go to another HMI and log into the process (since they are always connecting directly to the central server).
So I guess my question is, in what parts of this could the CVT/CCC/TCE libraries be most beneficial? (as an aside, I have used shared variables extensively in the past, and also the cRIO Scan Engine)
08-26-2011 11:24 AM
I have been using the CVT at the core of an embedded controller test project for a few months now, and I just found what I consider to be a flaw in the CVT design. I have several different controllers that I want to test, each with a different section in the Tag Configuration file. So far so good. The user selects the section according to the controller that needs to be tested. Awesome. I had set up my program to load one of the sections, run the tests, then end the program. Still good. I now tried to loop the main program so that I can exit one control test and load another without having to end the main program. PROBLEM!
The problem is that the CVT StaticRead VIs use that damn thing called First Call? that returns True the first time the subVI is called and does not reset until the highest level caller is "idle" (has ended). It took me awhile to figure out that this damn thing was causing the StaticRead funtion to use "outdated" indices in the CVT memory block and loading bogus data for all of the values that I reference "statically" throught he CVT StaticRead VIs (the ones with the same static name across different sections of the configuration file).
I would recommend exposing an "Initialize" terminal that is OR'ed with the First Call? primitive that resets the static index link to the data in the memory block. That way, the user can decide when to update the reference. I have made this modification to my CVT functions, but I would expect others to experience similar problems if they tried to do a similar thing.
I think that using First Call? is, in general, always a terrible idea. Especially when it is used as the only means to initialize something. In my code, I always have a manual initialize input (or a separate init VI, as appropriate). I can see how using the First Call? prim could be a good way to force an update if the coder fails to wire the init terminal, but it should never be the only means of initialization.
CLD, LabVIEW 2011
08-26-2011 12:49 PM
After messing around some more with the issue above, I'm finding it highly impractical to manually initialize these VIs. Perhaps a dreaded global initialization flag could be used, but you would have to keep up with all the tags used and who has been initialized, etc. What a mess...
I guess the CVT just doesn't lend itself to this type of looped application. It' a shame to have to exit the main application every time I want to change Tag Configuration sections.
08-26-2011 01:46 PM
So for my particular application, using the StaticRead and StaticWrite functions would not be the recommended way to go. I am now using the normal Read/Write VIs that look up the index every time. For my tigher loops that have to run faster than those VIs can support, I look up all of the indices when the VI loads and place them in an array. I then use the indices to update all of the values in a loop. This method can update about 50 Read values and 30 Write values in about 5-10 ms.
The only problem now is the CVT Client Communication (CCC) loop. The CCC Client Write and CCC Client Read functions use that cursed First Call? prim to initialize the indices of the values to synchronize over the network and then never looks back. I added an "initialize" terminal to these two functions and OR'ed it with the First Call? as I suggested above, and now everything works great. I see now that this fix was recommended by StevePVI in the CCC forum.
I guess I jumped the gun with my complaining earlier, but it can be a little confusing when to use the Static VIs versus when to use the "dynamic" VIs to read and write data with the CVT.
02-08-2012 08:41 AM
Hi, Could someone please tell me if there is a way to print all in TAGS in the tag editor for documentation purposes. If I open the Tag file as an XML there is a lot of garbage. Thanks
02-13-2012 02:18 PM
CVT vs. Shared Variable Enginer
Given some constraints....My application requires no network comms to another NI product.
What would be a 'pro' argument for implementing CVT vs using the shared variable engine? Because as far as I can tell they are a dead heat in CPU usage.
cRIO-9074 Chassis w/
2 NI 9213
1 NI 9205
2 NI 9425
1 NI 9476
Talking via ModbusTCP to (3) Slaves
Talking via Ethernet/IP to (1) SCADA
In early coding, I had established ModbusTCP to the 3 slaves: Came to discover that CPU usage was @ 100%!!. As I have since found out, this was because I had all project tags set to Network Published. Why? Being new to NI, I read that this was necessary for NI distributed system manager to see variables - and I wanted visibility into the data when the project deployed 'run as startup'.
CVT was suggested as a good scalable solution but in my testing it is no better than the shared variable engine with network publishing turned OFF.
Entire Project SVE w/NP: 99% vs. No NP = 31%
Single Slave SVE w/NP: 36% vs. No NP = 18.8% vs CVT Implemented for that slave = 18.5 %.
All were deployed as 'run as startup' to avoid front panel coms effecting measurement.
As I see it CVT has some cons associated with it compared to the Shared Variable Engine...
A rough estimate of 200 tags in half dozen libraries currently - expect tag count to grow a bit say 350 - 400 tags when done.
02-13-2012 02:54 PM
A couple of things (not directly related to CVT).
1) What version of NI RIO and Modbus IO Server are you running on the cRIO-9074? There is a bug in all versions prior to NI-RIO 4.0 and Modbus I/O Server 1.8.0 that will push the CPU use to 100% if a TCP/IP MODBUS Slave is not plugged in. Sometimes it takes a few minutes to happen, but this was an issue I ran into.
2)You can decrease your Scan Engine Speed and Network Variable publishing speed by right-clicking on the cRIO-9074 in the project->Properties then clicking "Scan Engine". I usually set mine to 100ms scan period, and 1000ms Network publishing rate (default is 10ms and 100ms respectively). If your application will allow for this, it will decrease CPU %. Your hardware is basically the same as what I use, so if you are not doing high-speed Digital IO switching, you should be able to get away with this.
3) Can you decrease any of your loop speeds (I'm assuming you have multiple loops on your cRIO application)? This will also reduce CPU usage.
If you use the "Timed Loop", you can easily set loop times and priorities of execution (relative to other loops). You can also view how long it takes each loop to execute, and get a better idea of how much time your code really needs to execute (see also the "Real-Time Trace Execution Tool" for more detailed debugging/timing).
-I have chosen to stick with the Shared Variable (network, single process, and IO Alias) for most data passing, mainly because I communicate with other NI products (i.e.. the DSC module for SCADA). The IO Alias is particularly handy for reading data from the Scan Engine, as it lets you put a meaningful name to a physical IO point (i.e.. DI0 = "Green button") that you can change/update once in the project, and have it propagate throughout the code automatically (no static IO references).