Pointers used for PID loop input


Hello everyone,

I am programming a system to utilize PID control for pressure in multiple vessels. As the system cycles through stages, different vessels will be monitored and controlled for pressure via a PID loop.

This looks like a prime opportunity to utilize a pointer variable as the process input to a PID loop.

I have never used pointers so would like some direction as to how I should do this.

The PID loop configuration does not give me the option to point the input to a variable, just HOST. So I presume I will need to run a chart that will move the pointer variable to the input of the PID loop, at least as fast as the loop is running.

This chart will also need to look at the system and determine what pressure signal should be moved to the pointer variable. This will be based on a digital valve on each vessel. If the valve is open, move the pressure reading to the pointer variable, otherwise check the next vessel.

There should not be a situation where multiple vessels are open at the same time. Even if they are, they will equilibrate to the same pressure so either pressure signal should be OK to use.

If someone has done something like this before, I would love to be able to peek at your code to adapt to my application. Otherwise any suggestions how I might approach this would be most welcome.

Thank You


Depending on the number of vessels you have, one option is to create multiple pids to cover the different situations you need to control, and choose the appropriate one by accessing it with a pointer. To save processor time, the inactive PID’s can be disabled until they are needed. I have some code-in-progress where I’ve done something like this… if you are interested, I would need a few days to clean it up and I could share it.


Not sure this is a good idea… or perhaps I don’t understand the system.

Opto racks have 96 PID loops, so there are plenty to around.
Each (I’m assuming) pressure vessel will have an analog input and either an analog or digital output. So its a simple matter of dropping a PID loop in the middle of those two points.

It would be really really really unusual for each pressure vessel to have the EXACT same PID settings for optimal tuning.
In this case, you need to switch not just the input, but also the P-term, I-term and probably the D-term as well. (And perhaps setpoint).
This is where you really get into trouble, the PID is a math formula that takes time (the I-term at the least) into account.
If you switch inputs between the one PID, you are going to have some trouble tuning the loop and thus the pressure in the vessel.

You say that the pressure should be the same across all vessels?

Im just trying to get a clear picture in my head of the inputs (pressure), the vessels (PID Loops) and outputs.

The other thing to remember is that the PID loops do not need a chart to run.
Also, the PID loops do not take any processing power from the controller/strategy at all.
They run on a different ‘cpu’.

You simply set the input and output and go from there. Its all done on the brain/rack/controller.
Once you have them all set up, just click the ‘save PID’ button and its all locked into your strategy.
You can also go into PAC Manager and save the configuration to Flash (there is a long forum post on this that we would need to review if you go this way). Doing this means that as long as that rack has power, the PID loops are running and are using the tuned parameters you put into each loop.

Did this help?

I think the short version of what I am trying to say is just be careful about switching inputs to a PID loop. The formula has a time aspect to it that will be difficult to manage and you may end up causing more work managing the fall out from that than simply having one loop per vessel.

Lets know if you have any thoughts, be interesting to figure out the best way to get the best control.



Thanks for the comments. I suppose I could set up each vessel on independent PID loops. I only have 3 in this system. They are all tied together via a common exit valve that I am controlling with the PID.

Think 3 air tanks with individual on/off valves to a common manifold. Then a proportional valve at the discharge of the manifold. One of the tanks will be open to the manifold at a given time and I want to control pressure in the line via a transducer located in each individual tank. If two tanks are open to the manifold at the same time, they will equilibrate with each other. Given the current operating scheme we should not have that situation happening anyway. When open to the manifold the tank will be evacuated to vacuum (1-3 psia) with a small purge flow at the inlet. When first opened, vacuum will need to pull down quickly, then the control valve will need to close down to maintain pressure at the setpoint.

Because all three tanks will be controlling a single outlet control valve is why I was considering using pointers for the input of the PID.

If each tank is set up on its own PID, I should be able to direct the output of the appropriate PID loop to the control valve when I switch between the tanks.

I could simply switch the “offline” loops to manual mode, then back to “auto” mode when they are active. Instead of directly sending the output of the PID to the analog output channel, I can write it to HOST and then move the output value of the active loop to the output channel.

I am aware of the challenges to getting each loop to control appropriately, as this progresses, I expect I may need to explore other control schemes besides PID.

I will try to let you know how things turn out and how I ultimately get things to control.



This is a tough one. I had previously observed that when an analog output is set up as the output of a PID, any changes to that AO need to be done through the PID commands. Because the PID resides in the rack, it controls the XVAL there, and direct writes to the AO’s XVAL from the strategy don’t affect it. When in debug mode, you can’t just double click on the analog output and manually set the XVAL as you can for analog outputs that are not associated with PID’s. Manual changes need to be done through the (awesome) PID debugger, by double-clicking the PID in the tree. This is true whether or not the mode is manual or auto. To programmatically change an analog output that is the output of a PID (in manual mode), the correct action is “Set PID Output”, or in optoscript: SetPidOutput(PID Loop, Output).

It looks like if two PID’s are set to have the same analog output as an output, whatever PID has the highest PID number in the list “wins”. (PID_1 writes over PID_0, for instance). If a watch is set on the analog output, it will always read the value that the highest number PID is calling for, whether or not that PID is in manual or auto mode. Perhaps the analog output momentarily achieves the value called for by the lower number PID (depending on the scan rate), but I haven’t played with scan rates or hooked up a scope to see.

If the tanks and piping are similar enough, perhaps Ben’s concerns about coming up with PID tuning that works for all three can be set aside. Then a PID could be setup with a host input and have strategy logic to loop and write the appropriate vessel pressure into the PID using the Set PID Input command. I would guess the chart loop rate should be faster than the PID scan rate, so the PID math doesn’t see stagnant data and react incorrectly to a condition that no longer is accurate.

Otherwise, you could still go with a separate PID for each tank, and set the output to the host. Then use a looping chart that writes the appropriate PID output to the proportional valve analog output (using the Get PID Output command). Here again, the chart loop speed should be faster than the PID scan rate. To keep it clean, I would put those PID’s into a pointer table so that I could avoid branching the rest of the strategy logic and keep them indexed to their on/off valves, but it isn’t necessary if you’re not comfortable with pointers.

My comment on processor power was incorrect… regardless of whether the PID is in manual or auto, it is still running… the mode setting just determines whether or not the output gets updated. As Ben said, the PID processor is on the rack, but I would guess that if you had enough PID’s running at fast enough scan rates, you could start to slow down I/O’s communication back to the controller. I haven’t tried it though, so I could be wrong.


i had a kind-of similar scenario a few months ago. the equipment was for a water treatment installation, not compressed air. there were 3 different circumstances (resulting in 2 different input sources) that an common output (a 30kW pump VSD) was to be controlled under. normal situation was to control the pump on the % of the tank level, the other situations were to control the pump on the volume of water required (m3/h). as m3/h was calculated, the natural thing was to have the input set as host. so the pid loop would go from controlling the tank at 50% to then controlling the volume to either 35m3/h to 60m3/h. so in auto, if you suddenly change the setpoint from 50 to 35 or 60 and your input from say 20(%) to 35(m3/h), depending on your PID values, this could cause an undesirable change in output.
to make the transition seamless (ie stop the pump from jumping dramatically due to the PID changes) the PID was put into manual mode, setpoint and input updated and then put back into auto.

the configuration was to have 1 PID loop configured on the brain with the input from host and the P,I,D,sp and scan rate values were configured as variables. depending on the situation, the appropriate input and PID values were written to the brain. the only catch was to make sure the transition from the old set of values to the new set of values bumpless, hence the reason the loop was put into manual, the new values were updated and then the control loop put back into auto. the pump has some major power about it and if it jumped suddenly, the rest of the upstream/downstream pumps and control loops would jump around (which was undesirable)

if you wanted to keep the PID loop autonomous, (ie keep going if comms are lost to the I/O unit) instead of writing the input to the PID loop, you could simply write the mem map location of the input the PID loop should be using.
eg: say your PID loop is configured in slot 0. to change the location of the input, write to mmp address 0xF2100044 (MemMap Address for Input) the memmap address of the input (say module 4, input 0’s scaled units ) 0xF0264000. unless power is cycled to the unit or you resend the I/O unit configuration, this will stay persistent (ive used this method as well and it works great)

then coding would be to monitor the situation, if you detect a change is required, put the PID into manual, update the inputs MMP location and PID values, and then put back into auto. if your system expands, then you just have to add the appropriate new variables. no pointers required. if the situation occurs where there are 2 tanks running, then you just have to decide on the default input.

in the case you have identified, my inclination would be have a single PID loop with the output to be the common exit valve and to store the MMP locations of the vessels inputs. when the tank is called for, put the PID into manual, write the new PI&D values to the loop, write the new mmp location for the PID loop input and then put the loop back into auto. this should hopefully make switching between PID loops seamless.

the obvious problem is the default. what to use? depending on your program, if there is a power cycle, the outputs go to 0 anyway and the program starts ‘afresh’. you specify what you want as default from the beginning and alls good. if the unit loses comms (or you do a strategy update), you don’t want the I/O unit to be reinitialized as this will write the default values to the PID loop. a couple of tricks around this (make sure you have the default configuration already stored to flash before you do this) is to untick the checkbox ‘Enable Communications from Control Engine’ under the Edit I/O Unit dialog (this will stop the IO unit getting a configuration sent to it when the strategy is started). you will have to manually enable the comms to the IO unit when the strategy runs.
then if the unit goes offline, before getting it back online issue the command SetIoUnitConfiguredFlag(IO Unit) so when you issue EnableCommunicationsToIoUnit(IoUnit); the configuration will stay present (same PID loop settings).

i hope this makes sense and helps you in your process.


We have a setup where we control one TPO valve with the output of several different PID loops with different inputs and tuning values. We just set the output of each of these PID loops to be a scratchpad float and write the float to the TPO value for the valve’s output whenever the output for that loop is required on the valve. We use digital events on the brain to do the swapping, but it would also be easy to do the same with a strategy on a controller.


Hello again everyone.

Thank you for the suggestions. I have gotten things working on this project. (At least this portion of it)

I ran with my original idea of using a pointer variable to provide the input to the PID loop. Then used a bit of chart logic to point the correct input and away I went.

The logic works quite smoothly and I’m able to control my system as needed. The dynamics are such that tight control is not a real issue. The system cycles every 30-120 seconds and the pressure swings require several seconds for the vacuum pump to pull it down to the desired pressure.

I will keep this trick in mind for other applications, but also some of your suggestions if I have any problems with its implementation or operating stability.