This project demonstrates how to implement a PID based DC motor controller using Raspberry Pi. DC motor controller program is developed using Python. It consists of a GUI, RPM measuring, error detector, PID controller functions, and PWM generation function. The PID based closed-loop DC motor control system is one that determines a difference in the required speed and actual motor speed and creates a correction control signal to remove the error. To learn more about PID controller and DC Motor, go through PID based DC motor controller using Raspberry Pi and Motor Control 1 articles.

Required hardware:

Raspberry Pi

Raspberry Pi Display:

  • Farnell code: 2473872
  • Newark code: 49Y1712

RPM sensors:

   Slotted sensor:

  • Farnell code: 1386613
  • Newark code: 21M5159

Or

  PNP type proximity sensor: PR12-4DP

  • Farnell code: 1736862
  • Newark code: 10R6734

Procedure:

  • RPi.GPIO.22 is configured to get the feedback signal from the RPM sensor (voltage should less than 3.3V).
  • RPi.GPIO.23 is configured as an output. It provides PWM pulses for DC motor driver.
  • Connect the Raspberry Pi display and Input-Output pins.
  • Connect the Power adapter and power up the raspberry pi
  • Downloaded and install the GUIZERO library.
  • Download and run the DC motor controller code
  • GUI will open
  • If you are not connected feedback sensor to RPI, you can’t be able to set the PID gain values while running.
  • Adjust the required RPM using the sliders, now click the Start button.
  • Increase the P gain value.
  • The motor speed gradually increases, it will take some time to reach set RPM.
  • Increase the I-gain and D-gain values and see the system performance.
  • The speed of response depends on the PID gain values.
  • Load the motor using mechanical loading arrangement, and observe the set-RPM and run-RPM values, note load values to calculate the speed-torque characteristics of the motor.
  • Change the inputs (RPM and PID gain values) and observe the response of the motor.
  • After completion of your work press Stop button and close the project.

 

 

 

DC motor controller code:

 

"""
       PID based DC motor controller
        thisproject is designed to control the DC motor at a constant speed
        Connect  one PPR(Pulse Per Rotation sensor to RPi.GPIO 22
        GPIO.23 providees PWM pulses to drive DC motor (DC motor drive between motor and RPi) 
"""

import threading
import RPi.GPIO as GPIO
import time
from guizero import App, Box, Text, TextBox, PushButton, Slider
""" Input Output  configaration """
GPIO.setmode(GPIO.BCM)
GPIO.setup(22, GPIO.IN, GPIO.PUD_DOWN)
GPIO.setup(23, GPIO.OUT)                  # PWM pulse for MOSFET/IGBT 
GPIO.output(23, 0)
""" Global variabels  """
Set_RPM =500                              # SET RPM value
feedback=0.0                          
previous_time =0.0
previous_error=0.0
Integral=0.0           
D_cycal=10
Kp=0                                       # Proportional controller Gain (0 to 100)
Ki=0                                       # Integral controller Gain (0 to 100)
Kd=0                                       # Derivative controller Gain (0 to 100)
RunRPM=0
Loop_value=0
a=0
avr=0
i=0
GatePulse = GPIO.PWM(23, 100)
""" PID control function """
def PID_function():
    
    global previous_time
    global previous_error
    global Integral
    global D_cycal
    global Kp
    global Ki
    global Kd
    
    error = int(Set_RPM) -feedback                    # Differnce between expected RPM and run RPM
    
    if (previous_time== 0):
         previous_time =time.time()
         
    current_time = time.time()
    delta_time = current_time - previous_time
    delta_error = error - previous_error
    
    Pout = (Kp/10 * error)              
    
    Integral += (error * delta_time)
    
    
    if Integral>10:      
        Integral=10
        
    if Integral<-10:
        Integral=-10
    
    Iout=((Ki/10) * Integral)
    
    
    Derivative = (delta_error/delta_time)         #de/dt
    previous_time = current_time
    previous_error = error
    
    Dout=((Kd/1000 )* Derivative)
    
    output = Pout + Iout + Dout                  # PID controller output
    
    if ((output>D_cycal)&(D_cycal<90)):           
        D_cycal+=1
        
    if ((output<D_cycal)&(D_cycal>10)):           
        D_cycal-=1
        
    return ()
"""   RPM calculation function   """
 
def RPM_function():      
    global feedback
    tc=time.time()
    
    
    while (GPIO.input(22)==False):               
        v=0
        ts=time.time()
        time_count=ts-tc
        
        if (time_count>7):
            print("Feedback failed, Please make proper feedback connection")
            feedback=0
            return ()         
               
    
    while (GPIO.input(22)==True):                  
        i=0
        ts=time.time()
        time_count=ts-tc
        if (time_count>7):
            print("Feedback failed, Please make proper feedback connection")
            feedback=0
            return ()
    
    v = time.time()                              # Stores the first pulse time
    while (GPIO.input(22)==False):               
        s=0                                     
    while (GPIO.input(22)==True):                  
        h=0                                            
    h=time.time()                                # Stores the next pulse time
                                        
    w=(60/(h-v))                                 # MOTOR speed in RPM  
    feedback = w
    
    return ()
def main_function():
    global D_cycal
    
    if Loop_value==1:
        
        t1 = threading.Thread(target=RPM_function)
        t1.start()
        t1.join()
        t2 = threading.Thread(target=PID_function)
        t2.start()
        t2.join()
        
        GatePulse.ChangeDutyCycle(D_cycal)
        
    else:
        GatePulse.ChangeDutyCycle(0)
print("Welcome To The Element14 Community!")
"""     GUI Functions     """
app = App(title="Welcome To The Element14 Community", height=700, width=500)
def change_Kp_value(slider_value):
    global Kp
    Proportional.value = slider_value
    Kp=int(slider_value)
    
def change_Ki_value(slider_value):
    global Ki
    Intregral.value = slider_value
    Ki= int(slider_value)
    
def change_Kd_value(slider_value):
    global Kd
    Deravative.value = slider_value
    Kd=int(slider_value)
def change_SetRPM_value(slider_value):
    global Set_RPM
    SetRPM.value = slider_value
    Set_RPM=int(slider_value)
      
def update_rpm():
    global avr
    global i
    global a
    global feedback
    if(Loop_value==1):
        if i<6:
            a+=feedback
            i+=1
        else:
                        
            Run_RPM.value = int(a/6)
            a=0
            i=0
    else:
        Run_RPM.value = 0
    
def start_funcdtion():
    global Loop_value
    print("MOTOR controller is ON ")
    GatePulse.start(25)
    Loop_value=1
    Startbutton.toggle()
    Startbutton.toggle()
    Startbutton.repeat(1, main_function)
        
def Stop_function():
    
    global Loop_value
    Loop_value=0
    Startbutton.cancel(main_function)
    Run_RPM.value=00
    D_cycal=0
    Stopbutton.toggle()
    Stopbutton.toggle()
    GatePulse.ChangeDutyCycle(0)
    print("Motor controller is Off")
def close_window():
    Stop_function()
    app.hide()
message = Text(app, text="PID based DC motor controller", color="saddle brown", size= 20)
Startbutton = PushButton(app, command = start_funcdtion, text="Start")
Startbutton.text_color="dark green"
Startbutton.text_size=15
Spase = Text(app, text= "  ")
SetRPM = Text(app, text= "Set_RPM")
SetRPM.text_color="blue"
SetRPM = Text(app, text= Set_RPM)
text_value = Slider(app, command=change_SetRPM_value, start=500, end=2000)
Spase = Text(app, text= "  ")
Proportional = Text(app, text= "Kp")
Proportional.text_color="DarkOliveGreen4"
Proportional = Text(app, text= Kp)
text_value = Slider(app, command=change_Kp_value, start=0, end=100)
pase = Text(app, text= "  ")
Intregral = Text(app, text= "Ki")
Intregral.text_color="DarkOliveGreen4"
Intregral = Text(app, text= Ki)
text_value = Slider(app, command=change_Ki_value, start=0, end=100)
pase = Text(app, text= "  ")
Deravative = Text(app, text= "Kd")
Deravative.text_color="DarkOliveGreen4"
Deravative = Text(app, text= Kd)
text_value = Slider(app, command=change_Kd_value, start=0, end=100)
pase = Text(app, text= "  ")
Run_RPM = Text(app, text= "RunRPM")
Run_RPM.text_color="tomato"
Run_RPM = Text(app, text= RunRPM)
Run_RPM.repeat(1, update_rpm) 
pase = Text(app, text= "  ")
Stopbutton = PushButton(app, command = Stop_function, text="Stop")
Stopbutton.text_color="red"
Stopbutton.text_size=15
pase = Text(app, text= "  ")
close_button = PushButton(app, text="Close Project", command=close_window)
#close_button.text_coller="yellow"
close_button.text_size=20
app.display()