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