Loading...

The PID Controller

The idea behind the controller is very simple. There is a state we want to achieve for our system, we have a signal telling us what the current state is, and we have an input to effect a change in the system to bring it closer to our desired state. The most commonly used controller is the PID controller (Proportional, Integral , Derivitive).

PID Equation

Where u is the control output, e is the error, Kp, Ki, Kd are the proportional, integral and derivative gain coefficients, respectively.

The proportional part of the controller calculates the error scaled by the proportional coefficient (Kp), the integral part sums the errors and scales the result by the proportional coefficient (Ki), and finally, the derivitave part calculates the change in error and scales it by the derivitave coefficient (Kd). An important point to note here is that the derivative term is very prone to noise, whereas the integral term has a smoothing effect. This is why the Kd coefficient is set to zero for the T-Bot. The controller is named according the non-zero coefficients. For example, if Kd is zero, we are using a PI loop. You can use the Python code below to play with the coefficients to see how the PID output changes. You can also try removing the noise from ydata to see how the derivative term changes.

PID Plot

import numpy as np
import matplotlib.pyplot as plt
plt.ion()

Setup the functions.

##################   Functions  #########################

def integrate(setpoint, Ki, ydata, dt):
    integ = np.cumsum(Ki*(setpoint-ydata)*dt)
    return integ

def derivative(setpoint, Kd, ydata, dt):
    deriv = Kd*((setpoint-ydata[:-1])-(setpoint-ydata[1:]))/dt
    return deriv

Create the Data.

###############   Create data  ########################

xdata = np.linspace(0,360*3.25,360)
noise = (1+((np.random.rand(xdata.shape[0])-0.5)*0.1))
ydata = ((np.cos(xdata*np.pi/180))*(xdata))*noise

setpoint = 0
Kp, Ki, Kd = 0.5,0.01,10

dt = xdata[1] - xdata[0]
py = Kp*(setpoint - ydata)
iy = integrate(setpoint, Ki, ydata, dt)
dy = derivative(setpoint, Kd, ydata, dt)
#upid = py[2:]+iy[2:]+dy[1:]
#upi = py[2:]+iy[2:]

Finally, plot the data!

plt.figure(figsize=(10, 4))

plt.title('PID')
plt.plot(xdata, ydata, c=(91/255.,111/255.,189/255.), label = 'Signal')
plt.fill_between(xdata, 0, ydata,facecolor=(191/255.,211/255.,255/255.),edgecolor=(191/255.,211/255.,255/255.), alpha = 0.6)
plt.plot(xdata, py, c=(56/255.,192/255.,255/255.),label = 'Proportional Kp = '+str(Kp))
plt.plot(xdata, iy, c=(255/255.,0/255.,0/255.),label = 'Integral Ki = '+str(Ki))
plt.plot(xdata[2:], dy[1:], c=(255/255.,150/255.,0/255.),label = 'Derivitave Kd = '+str(Kd))
#plt.plot(xdata[2:], upid, 'g',label = 'u PID')
#plt.plot(xdata[2:], upi, 'b',label = 'u PI')
plt.legend(loc = 'best',prop={ 'size': 8})
plt.xlabel('t (s)')
plt.ylabel('Deviation (Arb. Units)')
plt.axis('tight')
#plt.savefig('PID.svg')