Our full technical support staff does not monitor this forum. If you need assistance from a member of our staff, please submit your question from the Ask a Question page.


Log in or register to post/reply in the forum.

PID Controller


--dd-- Nov 8, 2023 08:59 AM

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

 


JDavis Nov 10, 2023 11:59 PM

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

 

Log in or register to post/reply in the forum.