Search code examples
pythoncontrol-theory

Getting the last error for a PID controller


I'm trying to build a PID controller on Python. Below is so far my implementation. Although the syntax is coherent, this is still pseudocode.

    def PID(self, Kp, Ki, Kd, reference_velocity, vehicle_velocity, current_time, last_update_time):
        desired_velocity = 0
        Kp = 0
        Ki = 0
        Kd = 0
        error = reference_velocity - vehicle_velocity
        delta_time = current_time - last_update_time

        proportional = Kp * error
        integral = Ki * error
        derivative = Kd * ((error - last_error) / (delta_time))

        desired_velocity = proportional + integral + derivative

        return desired_velocity

I am trying to figure out the last_error through what I already have given here but I couldn't figure it out.


Solution

  • Store the errors or the last error in a container in the function's outer scope.

    errors = []
    def PID(...):
        ...
        errors.append(error)
        return desired_velocity
    

    Then in the function that last error can be retrieved with.

    ...
    last_error = errors[-1]
    

    Or you could make your controller a class whose instances are initialized with constants and starting parameters, and keeps records (a container like a list) of past errors. The calculation for the current/next output control signal would be a method that could be called with current parameter values.

    Using your algorithm - something like this.

    class PID:
        def __init__(self,setpoint,t_now,Kp=0,Ki=0,Kd=0):
            self.setpoint = setpoint
            self.t_last = t_now
            self.Kp = Kp
            self.Ki = Ki
            self.Kd = Kd
            self.last_error = 0
        def adjust(self,process,t_now):
            error = process - self.setpoint
            delta_time = t_now - self.t_last
    
            proportional = self.Kp * error
            integral = self.Ki * error
            derivative = self.Kd * ((error - self.last_error) / (delta_time))
    
            desired_process = proportional + integral + derivative
            self.t_last = t_now
            self.last_error = error
            return desired_process
    

    Usage:

    v_controller = PID(setpoint=66, t_now=0, Kp=.2, Kd=.1, Ki=1)
    # or
    #parameters = {'setpoint':66, 't_now':0, 'Kp':.2, 'Kd':.1, 'Ki':1}
    #v_controller = PID(**parameters)
    
    print(v_controller.adjust(66.1,1))
    print(v_controller.adjust(66.2,2))
    print(v_controller.adjust(65.9,3))
    print('-------------')
    parameters = {'setpoint':66, 't_now':0, 'Kp':.2, 'Kd':.1, 'Ki':1.5}
    v_controller = PID(**parameters)
    print(v_controller.adjust(66.1,1))
    print(v_controller.adjust(66.2,2))
    print(v_controller.adjust(65.9,3))
    print('-------------')
    parameters = {'setpoint':66, 't_now':0, 'Kp':1.25, 'Kd':.2, 'Ki':.5}
    v_controller = PID(**parameters)
    print(v_controller.adjust(66.1,1))
    print(v_controller.adjust(66.2,2))
    print(v_controller.adjust(65.9,3))
    

    Result

    >>> 
    0.12999999999999262
    0.2500000000000043
    -0.1499999999999929
    -------------
    0.17999999999998975
    0.3500000000000057
    -0.19999999999999005
    -------------
    0.1949999999999889
    0.37000000000000666
    -0.2349999999999895
    >>>