0

I want to create a PID controller.

As input, I have two csv files, one with my desired behavior I want to achieve and the other with the actual values of current and voltage of a DC motor. I can read the data on the csv files and then use a PID controller (with the code below).

Since I just start using Python, I would like to know how to use this class (PID) for each value of current and voltage of the csv files and plot the two different trajectories (the desired trajectory from one of my input files along with the actual trajectory with the PID controller).

class PID:
    """
    Discrete PID control
    """

    def __init__(self, P=2.0, I=0.0, D=1.0, Derivator=0, Integrator=0, Integrator_max=500, Integrator_min=-500):

        self.Kp=P
        self.Ki=I
        self.Kd=D
        self.Derivator=Derivator
        self.Integrator=Integrator
        self.Integrator_max=Integrator_max
        self.Integrator_min=Integrator_min

        self.set_point=0.0
        self.error=0.0

    def update(self,current_value):
        """
        Calculate PID output value for given reference input and feedback
        """

        self.error = self.set_point - current_value

        self.P_value = self.Kp * self.error
        self.D_value = self.Kd * ( self.error - self.Derivator)
        self.Derivator = self.error

        self.Integrator = self.Integrator + self.error

        if self.Integrator > self.Integrator_max:
            self.Integrator = self.Integrator_max
        elif self.Integrator < self.Integrator_min:
            self.Integrator = self.Integrator_min

        self.I_value = self.Integrator * self.Ki

        PID = self.P_value + self.I_value + self.D_value

        return PID

    def setPoint(self,set_point):
        """
        Initilize the setpoint of PID
        """
        self.set_point = set_point
        self.Integrator=0
        self.Derivator=0

    def setIntegrator(self, Integrator):
        self.Integrator = Integrator

    def setDerivator(self, Derivator):
        self.Derivator = Derivator

    def setKp(self,P):
        self.Kp=P

    def setKi(self,I):
        self.Ki=I

    def setKd(self,D):
        self.Kd=D

    def getPoint(self):
        return self.set_point

    def getError(self):
        return self.error

    def getIntegrator(self):
        return self.Integrator

    def getDerivator(self):
        return self.Derivator
Jonas
  • 121,568
  • 97
  • 310
  • 388
Juliana
  • 13
  • 1
  • 1
  • 4

2 Answers2

1

I know this is an old question , but I will try to complement @tom10 answer for reference

If you are trying this on a Raspberry pi , I'm assuming you want a Velocity PID controller , you could use this code

you can read how Interrupts work on this excelent tutorial

http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-2

Also you can see how to use PWM class on this link

https://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/

import pid
import time

dc_pid = pid.PID(2.5, .1, 1.5)


GPIO.setmode(GPIO.BOARD)
GPIO.setup(self.pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(22, GPIO.FALLING, callback=self.interrupt_function,bouncetime=5) #GPIO where encoders signal is conected


def interrupt_function():

    """on this function you make calculations depending on what PID you are planning to use , for example if you are planning to do a Velocity PID , and the encoder signal is connected to a GPIO pin you should take time stamps and convert signal frecuency to velocity , save it as a variable and then update that value to the PID controller"""
   error = dc_pid.update(velocity) 
   #once you get your error you actuate it to your DC motor , via PWM , previously mapped function depending on your dc motor voltage and velocity it has depending on the PWM's duty cycle
   pwm.ChangeDutyCycle(error/15) # or whatever your convertion is 


readings = [1, 3, 5, 7, 12, 15, 17, 19, 27, 24, 24, 26]
initial_time = time.time
for reading in readings:
    dc_pid.setPoint(reading)
    time.sleep(10)

Using this code on a new file , it will set a new setPoint based on csv readings every 10 seconds , and actuating that velocity , or position , or whatever you want your PID to control , updating its values every interruption on pin 22

hope it helps future people wanting to know how to implement a PID using python ,

Taking in count that you should first design your control loop , defining your PID inputs , and how to manage outputs

Luis Borbolla
  • 73
  • 1
  • 9
0

Basically, it looks like it's designed to be run by first instantiating it with some parameters, and then calling update(val) repeatedly. I think, something like this:

readings = [1, 3, 5, 7, 12, 15, 17, 19, 27, 24, 24, 26]
x = PID(2.5, .1, 1.5, Integrator_min=-100)

for reading in readings:
    current_pid = x.update(reading)
    # if you want to know something else, like the error, you do
    err = x.getError()

By the way, it's not written in great Python style. For example, all these setter and getter methods are distracting.

tom10
  • 67,082
  • 10
  • 127
  • 137