I wanted to post some formula’s for deriving P and I gains for a velocity PID control loop such as a shooter used in the 2012 Rebound Rumble game.
Assumptions:
a) motor L/R time constant is small relative to motor control frequencies.
b) The system ( motor , gearbox and wheel) first order time constant tau_m is known.
c) The input speeds are normalized to the maximum motor speed, w_max. w_max = 12v/ke*60/2pi rpm which is approx w_free of the motor.
d) The desired motor response time constant, tau_d, is smaller than the motor tau_m by a factor of r.
Then the integral gain KI is given by
KI = 1/tau_d
and the proportional gain KP is given by
KP = r = tau_m/tau_d ;
If the integral computation used in the PID loop doesn’t contain a dt factor (i.e it is just an error accumulation) as is typical of the WPILIB PIDcontroller then the KI must be multiplied by the PID update period.
KI_WPILIB = T/tau_d where T is the PID period.
If you are feeding back RPM then the gains must be divided by w_max.
Example:
The 599 shooter wheel has an open loop time constant tau_m = .68 sec
We want to have a tau_d = .33 sec which means the error should be around 5% of the target by 1 second (three time constants). During autonomous this would be the delay before we can shoot.
KI = 1/tau_d = 3.
KP = tau_m/tau_d = 3*.68 = 2.04 ;
For WPILIB we want KI_WPILIB = T*KI = .05*3 = .15 ; KP remains the same.
The shooter has a w_max = 5614 rpm so if the feedbacks are not normalized then KP and KI must be divided by w_max. or
KP = 2.04/5614 = 3.63 e-4 ; KI_WPILIB = .15/5614 = 2.49e-5 ;
That’s it. The main factor limiting the value of KP is the magnitude of the noise on the RPM feedback signal. Typically after filtering this can get down to 1% of the RPM. KP multiplies the noise so to keep the noise below 5% then the max KP would be 5.
theoretical derivation:
The transfer function G(s) of the motor is 1/(tau_m*s + 1).
The transfer function of the PID compensator GC(s) is (KP + KI/s) or KI*(KP/KI*s + 1)/s
The closed loop transfer function = GC(s)*G(s)/(1+GC(s)*G(s))
Lets look at the product GC(s)*G(s) = (KI/s)*(KP/KI*s +1)*/(tau_m*s +1)
If we place the zero exactly at the motor pole then they will essentially cancel each other and we are left with GC(s)*G(s) = KI/s and now KP/KI = tau_m.
So the resulting closed loop transfer function is now KI/s/(1 + KI/s) = 1/(1/KI*s +1) and since we defined 1/KI as tau_d we have a new closed loop response that looks like a more responsive motor with a transfer function of 1/(tau_d*s + 1).
See this for additional discussion on obtaining tau_m and software implementation of PID loops.