Hi, I have implemented a function for a PID controller. I have not had a chance to thoroughly test it, so if anyone use it, please let me know how it works in your system.
'Test program for PID function
'Following the blog post "Improving the Beginner’s PID"
'http://brettbeauregard.com/blog/2011/04/improving-the-beginner%e2%80%99s-pid-reset-windup/
'Date: 2023-11-06
'Program author: John.Hulth@geo.uio.no
'Declare Variables
Public PTemp, Batt_volt
Const SCAN_INTERVAL = 1 'Measurement sample interval in Sec
Public mv_Setpoint = 2500 'Setpoint Value
Const mv_kp = 0.2 'Negative sign for reverse process
Const mv_ki = 0.4 'Negative sign for reverse process
Const mv_kd = 0.01 'Negative sign for reverse process
Const mv_OutMin = 0 'Min Output Value
Const mv_OutMax = 5000 'Max Output Value
Public mv_Input, mv_Output, mv_Error, mv_ITerm, mv_LastInput, mv_DInput
Public AO4A_Response
'Declare Private Variables
'Example:
'Dim Counter
'---Declare functins---
Function PID_Compute (Output As Long, Error As Long, ITerm As Long, LastInput As Long, DInput As Long, Input, Setpoint, kp, ki, kd, OutMin, OutMax)
Dim i, j
!Error = Setpoint - Input
!ITerm = !ITerm + ki * !Error
i = !ITerm 'Use temporary variable for comparison, pointer does not work!
If (i > OutMax)
!ITerm = OutMax
ElseIf (i < OutMin)
!ITerm = OutMin
EndIf
!DInput = Input - !LastInput
!LastInput = Input 'Remember variable
!Output = kp * !Error + !ITerm - kd * !DInput 'Calculate PID output
j = !Output 'Use temporary variable for comparison, pointer does not work!
If (j > OutMax)
!Output = OutMax
ElseIf (j < OutMin)
!Output = OutMin
EndIf
EndFunction 'PID_Compute
'Main Program
BeginProg
Scan (SCAN_INTERVAL,Sec,0,0)
PanelTemp (PTemp,15000)
Battery (Batt_volt)
VoltSe (mv_Input,1,mV5000,U12,True,0,60,1.0,0)
PID_Compute (@mv_Output, @mv_Error, @mv_ITerm, @mv_LastInput, @mv_DInput, mv_Input, mv_Setpoint, mv_kp, mv_ki, mv_kd, mv_OutMin, mv_OutMax)
SDMAO4A (mv_Output,AO4A_Response,3,1,1,2)
NextScan
EndProg
You can also find this example in the help for the PWM() instruction. It is important to note that any PID control program needs some manually tuning for what it is connected to.
Const ScanRate_ms = 1000 'ScanRate in milliseconds
'Pressure Control Variables:
Public Pressureread
Public UseP As Boolean, UseI As Boolean, UseD As Boolean ' Set to Run Control Algorithm
Public PressureSetPt
Public P, I, D
Public P_output, I_output, D_output
Public DutyCycle
Public Pfact, Ifact, Dfact, MaxI
Public PrevPress, IntegrateON As Boolean
'________________________________________
BeginProg
' Pressure Control initialization:
' Declared as public variables as it allows you to tweak
' the control terms whilerunning
DutyCycle = .5
Pfact = 0.0025
Ifact = .000125
Dfact = .001
MaxI = 100000
UseP = true
UseI = true
UseD = true
IntegrateOn = true
Pressuresetpt=10
'_____________________________
Scan (ScanRate_ms,mSec,10,0)
'....Other measurements
'Measure the pressure. Would normally have appropriate MX and offset
VoltDiff (Pressureread,1,mv5000C,1,True ,0,15000,1,0)
'PRESSURE CONTROL
'Proportional term, i.e. the current error from the setpoint
P = Pressureread - PressureSetPt
'Integral term
If P<> NAN AND IntegrateON Then I = I + P
If I > MaxI Then I = MaxI
If I < -MaxI Then I = -MaxI
'Differential term
D = Pressureread - PrevPress
'Apply the gain factors to each term
P_output = P * PFact
I_output = I * Ifact
D_output = D * Dfact
'Update the previous reading
PrevPress = Pressureread
'If any of the terms are in use reset the duty cyle
If UseP OR UseI OR UseD Then
DutyCycle = 0
EndIf
'The add each term to form the new duty cycle.
If UseP Then DutyCycle = DutyCycle + P_output
If UseI Then DutyCycle = DutyCycle + I_output
If UseD Then DutyCycle = DutyCycle + D_output
If DutyCycle > 1 Then DutyCycle = 1
If DutyCycle < 0 Then DutyCycle = 0
'Call the PWM instruction to control the opening of the valve.
'PWM(Src,channel,period,units)
' Src cannot be long or string. it is the duty cycle input
' Duty is fraction from 0.0 -> 1.0
' period, and units must be constants (known at compile time)
PWM(DutyCycle, C1, 200, uSec)
NextScan
EndProg
Hi,
Very usefull. Do you know @JDavis if the PWM function can be used with other instruction than control ports (C1-C8) ?
I would like use the CR Basic script you shared to do PID control of temperature in a heated pipe. The temperature is measured with a PT100 sensor.
The heating of the pipe is done with a heating cable that is powered in 230Vac and activated trought a 230Vac/12Vdc relay with a SW12 port.
best,
The SW12 port does not support PWM output. You could use a solid state relay after the C channel to step it up to 12VDC.
Ok tank you for your quick reply. Do you know what is the output current of a C channel? I used a solid state relay in the past for 24dc output, on C chanel and the 5Vdc otput did not sufficent to activate the relay... I had to use the scitation channel to activate the relay.
All the best,
Hi @JDavis,
I'm trying to understand how a PID controler is working. As I said in my previous post, I'm trying to adjust the air temperature in a air flowing tube. The tube is heated with a heating cable and isolated shield. I do temperature measurement with two TypeT thermocouple inside the air flow. The heating cable is just set ON of OFF using a state relay controled with C1 port.
I try to initiate the P, I and D but I do not succeed. But I think I do not exactly know how the PWD function works.
I set P at 0.2, I and D at 0. I do not know if I need to change MaxI ? (100000 by default)
I set PWD function as following : PWM(DutyCycle, C1,1,Sec)
Any advice on how I can start properly?
Thank you for all your help you give systematically in that very usefull forum.
Best,
Hi all,
Finally and after tests, the temperature control system has a very long inertia. As a consquence, the PWM is set to 30 secondes to avoid too fast control of the system through the intempestive ON/OFF of the relay.
Thanks again for help,
Best