PID in MMBasic


Author Message
PhenixRising
Guru

Joined: 07/11/2023
Location: United Kingdom
Posts: 1893
Posted: 09:34pm 14 Jan 2025      

  matherp said  Have a play with this VGARP2350 only for the moment.
C code and example courtesy of Philip Salmony https://github.com/pms67/PID


VGARP2350.zip


Example code - should be self-explanatory

Option explicit
'
' Array positions for PID parameters and working variables
'
Const Kp=0
Const Ki=1
Const Kd=2
Const tau=3
Const limMin=4
Const limMax=5
Const limMinInt=6
Const limMaxInt=7
Const T=8
Const integrator=9
Const prevError=10
Const differentiator=11
Const prevMeasurement=12
Const out=13
'
Dim pid_params(13)
'
pid_params(Kp)=2.0
pid_params(Ki)=0.5
pid_params(Kd)=0.25

' Derivative low-pass filter time constant
pid_params(tau)=0.02

'Output limits
pid_params(limMin)=-10.0
pid_params(limMax)=10.0

'Integrator limits
pid_params(limMinInt)=-5.0
pid_params(limMaxInt)=5.0

'Sample time (in seconds)
pid_params(T)=0.01

'Controller "memory"
pid_params(integrator)=0.0
pid_params(prevError)=0.0 'Required for integrator'
pid_params(differentiator)=0.0
pid_params(prevMeasurement)=0.0 'Required for differentiator

'Controller output
pid_params(out)=0.0


Dim float setpoint=1.0
Dim integer near_enough=0
Timer =0
'
' Initialise a PID loop with a 10mSec loop time
'
Math PID INIT 1,pid_params(),pidint
'
' Start the PID controller
'
Math pid start 1
Do
Loop Until near_enough
Print "test over"
Math pid stop 1
Math pid close 1
End

'
'Subroutine called every 10mSec
'
Sub pidint
 Local float measurement=test(pid_params(out)) 'simulate an input measurement
 Local float output=Math(PID 1,setpoint,measurement) 'update the controller
 Print Int(Timer),Str$(measurement,8,5),Str$(output,8,5)
 If Abs(measurement-setpoint)<0.00001 Then near_enough=1
End Sub

Function test(inp As float) As float
 Static float output=0.0
 Const alpha=0.02
 output=(pid_params(T)*inp + output)/(1.0 + alpha * pid_params(T))
 test=output
End Function


Tested with T at 0.001 seconds and it still works fine. Of course you wouldn't have a print statement in the interrupt routine in a real-world application


Boy do I feel like a rude and ungrateful so-and-so  

My sincere apologies to Peter Matherp.....I totally spaced-out and forgot about this. The very thing that I am obsessed with and I didn't get back to it  

I'm always being pulled in all directions but this I cannot believe.

Need to test this ASAP    

Pete, just curious; it doesn't allow anything < T=0.001 which is fine because 1mS is the standard for most CNCs but is there a reason for this? I achieve this with a SETTICK 1 with ease. Would've thought that compiled C would allow a lower value(?)