Overview
The control classes of INOS are responsible for all kinds of control work except axes handling which is documented under Motion. The main focus lies currently on temperature control.
Overview of all classes which are involved in controller handling of INOS. Clicking on a class directs to the corresponding class documentation.
As shown in the class diagram, a control instance is represented by the class CINOSControl. It has two parts :
General
A control instance is created dynamically via the INCO tree and is usually done with our good old stream file mechanism. Refere to the temperature controller for an example.
Definition cinosmcmodule.h:1900
The values have the following meaning :
- Name The controller name
- TrajectoryType The trajectory type. Valid types are INOSJerk, INOSTrapeze or an own customer specific type
- ControllerType The controller type. Valid types are INOSPid, INOSTemp, INOS2Pt or an own customer specific type
- InputName The controller input name
- OutputName The controller output name
Example :
Control.Cmd.Create("Zone0","INOSJerk","INOSTemp","ADP_02.AI_02_00","ADP_02.DO_02_00")
This call creates a control instane named 'Zone0' with a jerk ramp trajectory generator and a controller of type INOSTemp. The name of the input channel (in this case the name of the temperature process image value) is ADP_02.AI_02_00. The name of the command output (in this case a digital output) is ADP_02.DO_02_00.
To be able to use the digital output as a pseudo 'analog' output, one has the possibility tell the system to handle it as a software PWM (pulse wide modulation). This can be done like this :
Example of a pwmoutput.dt2:
The values have the following meaning :
- Name The name of the digital output
- SyncName If the pwm has to be synchronized to the 230V/110V power, one can define here the name of the digital input which provides the power sync signal
- SwitchTime The fastest switching time [us], usually this is 10000us (230V/50Hz) or 8333us (110V/60Hz) if one is working with a solid state relais
- SyncShift If a sync input is involved, this is the time [us] between sync and output set, 2000us is usually a good choice
- Average Smoothen the the power output over this number of cylces (0 if not used)
Temperature control
The temperature controller bases on a standard PID controller with some temperature related optimizations, like
- heat capacity support to improve as fast as possible jumps to a new commanded temperature
- support for the Stefan Boltzmann law (see https://en.wikipedia.org/wiki/Stefan-Boltzmann_law)
- several feed forward possibilities
- alarm temperature support
- asymmetric integrator limitation
- temperature dependent PID parameter sets
- different PID parameter sets for 'run' and 'halt'
- ...
Properties
The properties are described in the following section. To get stared, just copy the section below to a new file, name it something like myzone.stream and put the file into the config section of your project.
Set
ZONE0=
"Control.Entity.Zone0"
Control.Cmd.Create("Zone0","INOSJerk","INOSTemp","ADP_02.AI_02_00","ADP_02.DO_02_00");
#{ZONE0}.Prop.ActOutput=""
#{ZONE0}.ErrorMask=0x00000000
#{ZONE0}.ErrorDis=0xffffffff
#{ZONE0}.WarningMask=0x00000000
#{ZONE0}.Prop.CycleTime=10.0
#{ZONE0}.Prop.EnbOutput=""
#{ZONE0}.Cmd.Test.cmdVal1=100.0
#{ZONE0}.Cmd.Test.cmdVal2=150.0
#{ZONE0}.Ramp.Cmd.cmdV=0.0
#{ZONE0}.Ramp.Cmd.cmdA=0.0
#{ZONE0}.Ramp.Cmd.cmdB=0.0
#{ZONE0}.Ramp.Cmd.cmdJ=0.0
#{ZONE0}.Ramp.Max.minS=40
#{ZONE0}.Ramp.Max.maxS=300
#{ZONE0}.Ramp.Max.maxV=40.0
#{ZONE0}.Control.ErrorMask=0x00000000
#{ZONE0}.Control.ErrorDis=0xFFFFFFFF
#{ZONE0}.Control.WarningMask=0x00000000
#{ZONE0}.Control.Prop.Vfilter=10
#{ZONE0}.Control.Prop.DelayToHalt=1000
#{ZONE0}.Control.Prop.SettleTime=4000
#{ZONE0}.Control.Prop.SettleTimeout=120000
#{ZONE0}.Control.Prop.ActivateTimeout=120000
#{ZONE0}.Control.Prop.haltT=2.0
#{ZONE0}.Control.Prop.alarmT=310.0
#{ZONE0}.Control.Prop.alarmThyst=5.0
#{ZONE0}.Control.Prop.breakT=330.0
#{ZONE0}.Control.Prop.maxOut=100
#{ZONE0}.Control.Prop.minOut=0
#{ZONE0}.Control.Prop.fctOut=1
#{ZONE0}.Control.Prop.minTint=0
#{ZONE0}.Control.Prop.maxTint=100
#{ZONE0}.Control.Prop.maxSerr=2.0
#{ZONE0}.Control.Prop.maxSerrRun=30.0
#{ZONE0}.Control.Flag.EnbBoltzmann=1.0
#{ZONE0}.Control.Flag.IntegratorZeroAtJump=1.0
#{ZONE0}.Control.Prop.blzP=12.0
#{ZONE0}.Control.Prop.blzTmin=20.0
#{ZONE0}.Control.Prop.blzTmax=300.0
#{ZONE0}.Control.Prop.hcpFactor=1.757
#{ZONE0}.Control.Tune.Pulse.Power=100
#{ZONE0}.Control.Tune.Pulse.Time=1000
#{ZONE0}.Control.Tune.Pulse.Timeout=30000
#{ZONE0}.Control.Prop.OutDelta=1.0
#{ZONE0}.Control.Prop.OutTimeout=30000.0
#{ZONE0}.Control.Pid.Halt.Low.Kp=3.0
#{ZONE0}.Control.Pid.Halt.Low.Ki=1400.0
#{ZONE0}.Control.Pid.Halt.Low.Kd=350.0
#{ZONE0}.Control.Pid.Halt.Low.ffS=0.0
#{ZONE0}.Control.Pid.Halt.Low.ffSoffset=0.0
#{ZONE0}.Control.Pid.Run.Low.Kp=0.5
#{ZONE0}.Control.Pid.Run.Low.Ki=1400.0
#{ZONE0}.Control.Pid.Run.Low.Kd=350.0
#{ZONE0}.Control.Pid.Run.Low.ffS=0.0
#{ZONE0}.Control.Pid.Run.Low.ffSoffset=0.0
#{ZONE0}.Control.Pid.Run.Low.ffV=0.0
#{ZONE0}.Control.Pid.Run.Low.ffA=0.0
#{ZONE0}.Control.Pid.Run.Low.ffB=0.0
#{ZONE0}.Control.Pid.Halt.Medium=100.0
#{ZONE0}.Control.Pid.Halt.Medium.Kp=2.5
#{ZONE0}.Control.Pid.Halt.Medium.Ki=1400.0
#{ZONE0}.Control.Pid.Halt.Medium.Kd=350.0
#{ZONE0}.Control.Pid.Halt.Medium.ffS=0.005
#{ZONE0}.Control.Pid.Halt.Medium.ffSoffset=30.0
#{ZONE0}.Control.Pid.Run.Medium=100.0
#{ZONE0}.Control.Pid.Run.Medium.Kp=2.0
#{ZONE0}.Control.Pid.Run.Medium.Ki=1400.0
#{ZONE0}.Control.Pid.Run.Medium.Kd=350.0
#{ZONE0}.Control.Pid.Run.Medium.ffS=0.0
#{ZONE0}.Control.Pid.Run.Medium.ffSoffset=0.0
#{ZONE0}.Control.Pid.Run.Medium.ffV=0.0
#{ZONE0}.Control.Pid.Run.Medium.ffA=0.0
#{ZONE0}.Control.Pid.Run.Medium.ffB=0.0
#{ZONE0}.Control.Pid.Halt.High=200.0
#{ZONE0}.Control.Pid.Halt.High.Kp=3.0
#{ZONE0}.Control.Pid.Halt.High.Ki=1400.0
#{ZONE0}.Control.Pid.Halt.High.Kd=350.0
#{ZONE0}.Control.Pid.Halt.High.ffS=0.001
#{ZONE0}.Control.Pid.Halt.High.ffSoffset=30.0
#{ZONE0}.Control.Pid.Run.High=200.0
#{ZONE0}.Control.Pid.Run.High.Kp=4.0
#{ZONE0}.Control.Pid.Run.High.Ki=1400.0
#{ZONE0}.Control.Pid.Run.High.Kd=350.0
#{ZONE0}.Control.Pid.Run.High.ffS=0.0
#{ZONE0}.Control.Pid.Run.High.ffSoffset=0.0
#{ZONE0}.Control.Pid.Run.High.ffV=0.0
#{ZONE0}.Control.Pid.Run.High.ffA=0.0
#{ZONE0}.Control.Pid.Run.High.ffB=0.0
#{ZONE0}.Param.Cmd.Create("Slow");
#{ZONE0}.Param.Entity.Slow.Ramp.cmdV=0.5;
#{ZONE0}.Param.Entity.Slow.Ramp.cmdA=10.000;
#{ZONE0}.Param.Entity.Slow.Ramp.cmdB=10.000;
#{ZONE0}.Param.Entity.Slow.Ramp.cmdJ=1000.000;
#{ZONE0}.Param.Cmd.Create("Rapid");
#{ZONE0}.Param.Entity.Rapid.Ramp.cmdV=5.0;
#{ZONE0}.Param.Entity.Rapid.Ramp.cmdA=100.000;
#{ZONE0}.Param.Entity.Rapid.Ramp.cmdB=100.000;
#{ZONE0}.Param.Entity.Rapid.Ramp.cmdJ=1000.000;
!
Stream.Entity.zone0.Cmd.Run()
Errors
Long live errors
Warnings
Long live warnings
Setup step by step
This section gives a step by step intro how to setup an temperature controller.
Create the configuration
A temperature controller has a analog input which represents the temperature and either an analog or a digital output for the power stage. If the power stage is controlled over a digital output (e.g. a solid state relais), one has to configure a software pwm for this output, which allows the controller to work with values from 0..100%. See General for an example.
The controller itself is set up with a so called stream file. It is an ASCII file which simply has CallProcedure and PutVariable entries and is executed at booting of the system. An example can be found here Properties.
In short :
- create a *.dt2 file with the pwm configuration (see also General) and put it into the config directory of your project
- create a *.stream file with this content Properties. To get a good starting point, adjust the following values :
Control.Flag.EnbBoltzmann=0
Control.Prop.hcpFactor=0.0
Control.Pid.Halt.Low.Kp=0.0
Control.Pid.Halt.Low.Ki=0.0
Control.Pid.Halt.Low.Kd=0.0
Control.Pid.Run.Low.Kp=0.0
Control.Pid.Run.Low.Ki=0.0
Control.Pid.Run.Low.Kd=0.0
Control.Pid.Halt.Medium.Kp=0.0
Control.Pid.Halt.Medium.Ki=0.0
Control.Pid.Halt.Medium.Kd=0.0
Control.Pid.Run.Medium.Kp=0.0
Control.Pid.Run.Medium.Ki=0.0
Control.Pid.Run.Medium.Kd=0.0
Control.Pid.Halt.High.Kp=0.0
Control.Pid.Halt.High.Ki=0.0
Control.Pid.Halt.High.Kd=0.0
Control.Pid.Run.High.Kp=0.0
Control.Pid.Run.High.Ki=0.0
Control.Pid.Run.High.Kd=0.0
Verify the configuration
After builing and loading the project to your target, let's verify if everything was setup ok. Open the INCO explorer and check if there is a folder
Control.Entity.Zone0 28.05
°C
where 'Zone0' is the name of your controller. If you don't see this folder :
- check if the feature 'General options.Temperature control' in your iDev project is selected
- check with the eventlogger if there are some error traces regarding your controller
Now lets check if the temperature changes if we output power for a short time :
- open a Varlog and select your input and output channels to be logged (set the trigger to the output channel != 0.0). You find these channels under Image.Analog.Input/Output and/or Image.Digital.Output
- start logger
- write e.g. 10% to the output channel, wait some seconds and write 0.0 again
If you see a significant temperature change in your log, everything seems to be fine. If not, try agin with more power or check your config and wiring.
Measure heat capacity
To give the controller a hint regarding the relation between power and temperature delta, you have the possibility to measure the so called hcpFactor (heat capacity factor). This measurement makes only sense if yor heater is some kind of heating plate or similar. It definitely makes no sense for a heater like a hot air gun. Skip this section in this case.
The measurement is done by setting a predefined power for a selected time and measuring the temperature delta.
Measure the hcpFactor :
- ensure the temperature of your heater lies below Ramp.Max.minS. If this is not the case, cool down the system somehow
- set the requested pulse values.
Control.Entity.Zone0.Control.Tune.Pulse.Power = 100
Control.Entity.Zone0.Control.Tune.Pulse.Time = 5000
Control.Entity.Zone0.Control.Tune.Pulse.Timeout = 30000
- activate the controller. The Control.Entity.Zone0.State should now show 'ready' :
Control.Entity.Zone0.Cmd.Activate()
- start measurement and (read the next step before you start) :
Control.Entity.Zone0.Cmd.Tune("Type=Hcp")
- during the measurement the controller state Control.Entity.Zone0.State shows 'tuning'. As soon as the state goes back to 'ready', the mesdurement is done and we suggest to immediately inactivate the controller again, to avoid any overheatings
Control.Entity.Zone0.Cmd.InActivate()
- the measure result can be found here :
Control.Entity.Zone0.Control.Tune.Result.Hcp.Factor = 1.757
- move the measure value to the properties section and don't forget to update your controller stream file as well
Control.Entity.Zone0.Control.Prop.hcpFactor = 1.757
PID factors
To setup PID factors, there is currently no reliable mechanism available. You have to do it by hand, but usually this is not really tricky.
- to avoid any errors during this work, tell the controller to disable value checking and settling supervision :
Control.Entity.Zone0.Control.Flag.ChkVal = 0
Control.Entity.Zone0.Control.Prop.maxSerr = 50
Control.Entity.Zone0.Control.Prop.maxSerrRun = 100
- we start PID adjustment in the predefined low range (#{ZONE0}.Ramp.Max.minS till #{ZONE0}.Control.Pid.Run.Medium, so clear Ki and Kd in this range (Halt and Run) and set Kp to a starting value e.g. 1
Control.Entity.Zone0.Control.Pid.Halt.Low.Kp = 1.0
Control.Entity.Zone0.Control.Pid.Halt.Low.Ki = 0.0
Control.Entity.Zone0.Control.Pid.Halt.Low.Kd = 0.0
Control.Entity.Zone0.Control.Pid.Run.Low.Kp = 1.0
Control.Entity.Zone0.Control.Pid.Run.Low.Ki = 0.0
Control.Entity.Zone0.Control.Pid.Run.Low.Kd = 0.0
- activate the controller and move to a reasonable temperature of the low range (e.g. 10°C below #{ZONE0}.Control.Pid.Run.Medium)
Control.Entity.Zone0.Cmd.Activate()
Control.Entity.Zone0.Cmd.Move(80.00:
d,
"")
- now 'play' around with Control.Entity.Zone0.Control.Pid.Halt.Low.Kp (typically by increasing Kp) till you get a clean temperature oscillation, use varlog to measure/view the oscillation
- after successfu oscillation measurement, set the PID values in the following manner
- you should now have a stable controller for the low range, do the same steps for medium and high range or directly use the low parameters for the other ranges, they usually fit not to bad
Optimizations
There are several possibilities to optimize and therefore 'help' the controller to do its work.
- heat capacity measurement (seen already here Measure heat capacity)
- temperature dependant power feed forward
- Boltzmann law feed forward for heating plates
To reduce the dependancy of the integrator limits
Control.Entity.Zone0.Control.Prop.minTint
Control.Entity.Zone0.Control.Prop.maxTint
you have two possibilities to work with a power feed forward.
1. Power feed forward with ffS
The ffS mechanism is configured with the two parameters (per temperature range) :
Control.Entity.Zone0.Control.Pid.Halt.Low.ffS = 0.02
Control.Entity.Zone0.Control.Pid.Halt.Low.ffSoffset = 30.0
The feed forwarded power is calculated like this
You can either let the system measure this feed forward with
Control.Entity.Zone0.Cmd.Tune("Type=ffS")
or live change the parameters during active control till the current controller integrator tends to be zero
Control.Entity.Zone0.Control.Err.errSint = 14.56
2. Power feed forward with Boltzmann law
The Stefan–Boltzmann law describes the power radiated from a black body in terms of its temperature (see https://en.wikipedia.org/wiki/Stefan-Boltzmann_law) So if your heater is e.g. similar to a heating plate, this feed forward mechanism is probably the right choice.
How to setup :
- activate the controller and move to max. / or near the max. allowed temperature
- check the controller output at this point
Control.Entity.Zone0.Control.Act.actOut = 14.0
In this example, we measured about 14%. Setup the following parameters to get things running
Control.Entity.Zone0.Control.Flag.EnbBoltzmann = 1.0
Control.Entity.Zone0.Control.Prop.blzTmin = 30.0
Control.Entity.Zone0.Control.Prop.blzTmax = 300.0
Control.Entity.Zone0.Control.Prop.blzP = 13.0
The parameters have the following meaning :
- EnbBoltzmann Enable the boltzmann law
- blzTmin Minimum temperature where the law should take effect
- blzTmax Maximum temperature where the law should take effect
- blzP The requested feed forward power at blzTmax (use about 10% less value than measured)
And now happy heating !