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.