PID Control

When robustness is required

Feedforward control is great because it requires no sensor inputs. It however is not necessarily robust to disturbances and cannot perform accurate position control on its own. This is where PID (proportional intergral derivative) control comes into play.

I will assume you are familiar with the overall concepts, if not I've explained it more thoroughly here. The core principle is that at each iteration we calculate the deviation between the desired state and the measured state and generate the appropriate corrective command to minimize this error.

In sunset we recommend for position control systems to use a PD controller (no Integral term). This is because most disturbances can be accounted for by a simple feedforward term such as the static friction feedforward from the previous section. Additionally, issues such as integral windup often result in oscillatory behavior which can damage your system.

Here is an example on how to use the sunset PID controller

Kp = 3
Ki = 0
Kd = 0.3
controller = PID(Kp, Ki, Kd)
desired = 10
while True: 
    measurement = get_position()
    # use the scheduler timer to ensure replay mode works.
    msg = scheduler.sysTimeTopic().message
    dt = msg["DeltaTimeSeconds"]
    power = controller.calculate(desired, measurement, dt)
    motor.setPower(power)

Tuning Enhancements

We derived an equation that states given kP, kA, and kD the critically damped (fastest, zero overshoot) gain for kD is:

A proper derivation can be found here

We provide two functions to perform this calculation for you.

kd = calculateDerivativePositionControl(kp,kv,ka)

# or if you already have feedforward 
# note that static will not effect kD calculation.
feedforward = SimpleFeedforward(kv, ka, static)
kd = derivativeFromFeedforward(kp, feedforward) 

Last updated