Teamwork Strategies

I am transitioning to working with a team of 2-3 people on a project, using Pac Control. I’m open to hear peoples opinions about how to do this most efficiently.

More specifically, I’d like to divide an conquer by splitting the work up into separate charts, which different team members are responsible to complete, and then combine into a single program. What is the most seamless way to do this in pac control? In the past I have been able to import charts, but the variables were not included, is there any way to import the variables also?

Thanks in advance!

Importing charts also imports the variables (as long as they’re referenced in the chart). Has it been a while since you tried this?

With PAC Project and PAC firmware 9.5 or newer, you can have a subroutine call another subroutine, so writing re-usable code w/local variables is much easier. Also, by using subroutines, your strategy won’t get all cluttered up with a whole mess of global variables when you start importing.

What kind of application are you building? Is groov in the mix? (If so, you might try using Node-RED for parts of your logic. That could save you some coding if someone has already build and shared some code/flows to do what you want to do!)

Yes, we have not tried to import charts on the new version 9.5, so I will try it out. The app is just PAC control, no groov. Your comment on subroutines got us thinking.

I have another related challenge, we’re working in a team because of the size of the project. There are about 500 I/O points. For each of the analog I/O points, there are 92, we need to assign 12 standard variables. Is there a way to import a .CSV file from excel to name variables? We have an excel spreadsheet with the entire I/O list already.

Or is there some other way to automate the creation of variables? The names are all of the same format

“first string” + “I/O name” + “second string”

If you export an i/o unit from PAC Control, you’ll see the resulting otg file is just text you can edit/re-import. Also, when you add a new module to that strategy tree in the first place there’s an option to autoname in a format like you mentioned.

Mary’s suggestion is great for bringing in IO points, but for variables, I don’t think there is a direct way to do it.

One suggestion I found on here a while back was to use AutoHotKey. I used this to update tuning variables in about 70 PID loops and it worked well and saved me a lot of time. I’m sure it would be capable of taking a list of variables and creating them in PAC control.

I actually use AutoHotKey for some other non-Opto things too — so it is quite a useful tool to have.

Thanks for all of the replies, it seems like I have a few methods to test out when I am back from the holidays.

If you don’t mind, let us know how you end up assigning the team tasks and how it all works out working as a team on a single project (good and bad). Good luck!

I work with Geoff at ISI Water, and we are building this project together. We were talking about how nice it would be if there was an import tool so you could write up a spreadsheet with your variables and PAC Control could import a range of cells from a spreadsheet. Like column 1 would be the name, column 2 would be the type, column 3 would be 0 for global or 1 for persistent, column 4 would be initialization, and 5 would be for initial value. This seems like it would be a very useful tool for integrators.

For the water plants we build, every analog input has an alarming variable set. We have Low Low shutdown alarm, Low warning, Target, High warning, and High High shutdown. All of those points have an alarm triggered I32 variable, an I32 counter for persistence, and a float for the setpoint. This adds up quick!

Not only that but then for say all of our process pumps, we have variable frequency drives that run on Modbus, so each of those has a set of variables as well. This plant has something like 20 drives. We are already using subroutines for Modbus, but still don’t we need actual strategy variables to reference for each?

I wrote an AutoHotkey script to import variables from a spreadsheet (well a csv file). The zip file includes the script and a sample CSV file.

I put the details on how to use it on my blog:

Let me know if you run into any issues, or have any fixes or upgrades! (2.0 KB)

Edit 12/28/2016: Updated the script to prompt for the CSV file and some other improvements.
Edit 2/14/2017: Fixed an issue with duplicate variable detection in newer versions of PAC Control.

Wow, that looks like just what we need!

Thank you Philip, much appreciated! We’ll give this a try and post our results.


I also do water/wastewater projects as well as other types. This project sounds like it would be very efficient to use pointers on this.

Typically I do with one chart what most do with dozens or even 100s of charts. I use a tree top to bottom with branches for specific systems like a pump control logic or a chem feed logic. Each branch typically does a different piece. Within each branch, you will do all logic for similar or identical systems each using a different index number. So it you have 10 pumps systems that are similar, each system with a different index number gets processed in that branch. Therefore, you can have multiple processes, each with the same index number that get processed in each loop of the chart or you can have one process that gets processed on each chart loop. This keeps the number of charts down to a roar and makes troubleshooting much easier. Much less code to wade through.
The keys are uniformity and naming conventions. I did a quarry operation and each system (separate controllers) had 30-60 separate pieces of equipment. Each loop of the chart processed one piece of equipment (such as a conveyor or a shaker). All 60 pieces of equipment were processed by one fairly small chart.
During troubleshooting, if i fixed the problem for one item, I was fixing the problem for all 60 pieces at once.

Thanks Barrett. I should play around with pointers more. In all my years doing this I really can’t say I’ve used pointers for anything but it sounds like it’s high time I did!

Our plants tend to run sequence control, and only some amount of active control logic. Usually, once you start a SWRO plant, it runs itself and the only thing running logic is alarms charts and watching for stop signals, or e-stop. It can get a little more active when you have more complex pretreatment systems with filters that need automatic backwashing, or chemical dosing that needs regulating, etc.

I concur with Barrett’s recommendation. I have some HVAC projects that have many zones, and process the logic in a looping chart. I store the setpoints in float tables and the IO in pointer tables and then loop through them.

To write the code to initialize the pointer tables I actually do this in Excel or LibreOffice Calc. I list each zone on a line and have formulas that write out the Optoscript I need and then copy and paste the column into an Optoscript block. Since I have several pointer tables to initialize, I put the name of the table I want on the top row and grab it with the formula. The formula gets pretty complex, but it only needs written once and then copied and pasted everywhere else. You can see what I mean in the screen grab below. The last column of the sheet will concatenate all the columns together which allows me to copy and paste that final column into my initialization Optoscript block. This saves a lot of time.

The other advantage to having everything in tables is you can copy and paste PAC Display items and perform a quick find and replace on the index for each one.

I also agree with Phillip, sounds like he has a good system. With pointers, you just have to keep in mind that all the pointer names are part of the naming convention and are the names of actual devices and inputs or outputs in the field. Like Phillip said, you initialize all the variables in a init block prior to the loop, then load all the pointers from the pointer table at the top of each loop right after increment of the index value. For instance, the pointer Pump_Run_ptr would be a pointer that is loaded in the pointer table in the init block, then after Pointer_Index value inside the loop is incremented to 1, then you would load the pointer table with Pump_Run1 var and then beyond that in that loop, you can do anything needed with regards to starting or stopping that pump. This goes for essentially any var type in Pac.

I also agree with Phillip on the Excel trick. Been using that one for many years. Essentially, anywhere you have to load pointer tables with vars, you create the script itself in Excel and the copy and paste into a script block. When you paste a 100 lines of script into the block, you’ll have that feeling of euphoria…

As far as your project, it might be wise to have one person be the naming convention guru and that person would keep the master list. I know the Opto way for naming is to put the data type first, but I never found that to be as helpful as listing the device first, such as Pump1_Run. The point of this is when using pointers, you might have hundreds of vars, and this will group all these items together when you are working on the strategy. Another thing I do is use a post fix such as Pump1_Run_do for all my discreet outputs, then use Pump1_Run_dout for my internal variables. Pump1_On_di and Pump1_On_din likewise. This lets me know whether I’m looking at a variable or an IO. Of course you can tell the type typically by what it’s doing. Another set of examples is Pump1_Press_ai/Pump1_Press_ain and, Pump1_Speed_ao/Pump1_Speed_aout. This way, when you type in Pump1, the tree will take you right to the group you’re interested in working on and you can look at this list and see if mistaken names are present, etc…
Using tables like Phillip said is really really compact, but it comes at the price of complexity. I typically use individual like named vars for each IO which makes troubleshooting easier. Also, I almost always use the block read method for reading and writing the IO, for that I use tables and for which the Excel trick is paramount.
I suggest sitting down with your team and working out all the device names and associated variables and IO, or least the most obvious ones. Keep in mind how you’re going to be using them and that will do more to keep your strategy on a sane path.
I have a fairly good size project coming up next month and I will be putting all these things in play, which will be especially interesting since I will be using the integrated redundancy kit and 2 Groov servers (intended as redundancy) to operate 20 - 50hp fans and all the associated alarms, and safety systems. There are hundreds of IO, 2 controllers and 13 brains, 2 server PCs, 2 operator PCs with 65" UltraHD displays, and a dozen other monitor PCs on this system.

Stay tuned for some exciting new command-line options, coming soon in PAC Control, that will make some tasks – like adding new variables – much easier!

That would be wonderful, Mary. Command line in configure mode I assume?

Just an update, I owe a big thanks to Philip, the AHK code was just what I needed, and it worked great.

I think I’ve uploaded around 500 variables to my strategy so far. I’m using excel to add a prefix and a suffix word to the name of each I/O point. Excel is working really well for this step, and it’s handy to have a spreadsheet of all the variables created.


Ok, you’re killng me…when? I could really use it for this project.

Your welcome, Geoff.

Mary, any chance the next version of PAC Control will allow us to organize variables into folders? And while I’m bringing up desired features, I would really like to see chart scoped variables too!

Those two things would really clean up/organize some larger strategies I have and make them easier to maintain.

Hi Philip,

Well, you get both of those things when you use a Subroutine!

The other thing some folks do is use naming conventions, so if you start your variable name with the chart name, then they’re sorted by that name, and you’re less likely to accidentally use a chart-specific variable in another chart.

I want to tell you more about what the next big (10.0?) version of PAC Control is all about, but then I’d have to kill you. :wink: