Encoderlı DC Motorun PID Controller ile Kontrolu ( Ayrık Zaman )

 

Proje Amacı

Microcontroller üzerine yazılmış yazılım ile encoderlı DC motorun PID controller ile kontrol edilmesi amaçlanmaktadır. PID sistemin katsayıları ve motorun çalışmasını istediğimiz RPM değerini bir arayuz ile serial haberleşme kullanarak microcontroller a göndererek o değerlerde çalışmasını istenmektedir.

 

Sistemin Çalışması

Mikro controller olarak Arduino Uno kullanılmıştır. Encoderdan gelen pulseler için interrupt kullanılmıştır. RPM değerini bulmak için ise pulseler arasındaki zaman farkından yararlanarak bulunmuştur.

Arayız tarafından gelen set RPM değeri ile motorumuzun RPM değerini çıkartarak hatayı buluruz. Hatayı gerekli işlemlerden ve katsayılardan geçirerek PID çıkışımızı elde etmiş olunur. Arduinonun pwm çıkışından motor sürücüsüne giderek gerekli değerde motoru çalıştıracaktır.

 

Arayüz olarak Pytq5 kullanılmıştır. Sadece plot çizme işlemi hazır kod ile kullanılmıştır.

 

 

GUI Analiz:

self.KP = QLineEdit(self)  ############################# Kp box için
 
self.KP.resize(50, 50)
 
self.LAYOUT_A.addWidget(self.KP, *  (1, 1)) 

 

hazır kodda sınıf içerisinde oluşturulmuştur. Bu nedenle değerleri alabilmek için Textbox oluşturuldu. Widget fonksiyonundan yararlanarak Textbox ‘ın yerini koordinatı verildi.

self.labelKp = QLabel('Kp', self)
self.LAYOUT_A.addWidget(self.labelKp, * (1, 0))    #

 

Qlabel ile etiket oluşturuldu. Widget ile arayüzdeki bulunacak koordinatı verildi.


self.Set = QPushButton(text='Set')####################setting but
self.Set.setFixedSize(100, 50)
self.Set.clicked.connect(self.SetBtnAction)
self.LAYOUT_A.addWidget(self.Set, *(0, 0))

 

Set butonu oluşturuldu. Tıklandığında SetBtnAction fonksiyonu çağırarak PID parametresini Arduino ‘a serial üzerinden iletecek.

 

def SetBtnAction(self):     # burdan arduinoya
   
Kp =  self.KP.text()
    Ki = 
self.KI.text()
    Kd = 
self.KD.text()
    Rpm =
self.RPM.text()

   
########### değerler girilmediyse bile bu değerleri alsınlar
   
if Kp =="":
        Kp =
"2.0"
   
if Ki == "":
        Ki =
"0.055"
   
if Kd =="":
        Kd =
"0.04"
   
if Rpm =="":
        Rpm =
"2000"

    sendToArduino(Kp
,Ki,Kd,Rpm)
   
return

 

Set butonuna basıldığında Textboxlarda veri yoksa defualt olarak değerleri arduinoya atılcak.


def sendToArduino(Kp ,Ki ,Kd ,Rpm ):
    massage = Kp +
"," + Ki + "," + Kd + "," + Rpm
   
try:
        arduino.write(massage.encode())
       
print("gönderildi", massage)
   
except:
       
print("gönderilmedi",massage)

 

Gidecek olan veriler tek bir mesaj olarak ayarlanır. Byte veri tipine dönüştürerek serialden arduinoya yollanır.

 

while (True):
   
#time.sleep(0.0001)
   
x = arduino_read()
   
if x != None:                   ## gelen data bos değilse yazsın amacı plot  edilcek değerin olması
       
mySrc.data_signal.emit(x)

       
print(x)                           # arduinodan gelen verileri yazıyo

 

arduinodan gelen RPM değerlerini yazıdırmak için hazırlanan arduino_read() fonk çağırlır. Veri eğer uygun ise plot çizimi yapılır.

 



def arduino_read():
    data = arduino.readline()      
# arduinodan line olarak veri çekiyo

   
data = byte_to_int(data)        # byte i integer verisine ceviriiyo
   
return data

def byte_to_int(data):              # integere cevirmek için gerekli işlemleri yapıyor
   
try:
        str_rn = data.decode()
        str = str_rn.rstrip()
        i = int(str)
       
return (i)
   
except:
       
pass

 

ardunino_read() gelen verileri satır şeklinde alarak byte verisini byte_to_int fonksiyonu ile integera çevrilir. Gelen veri plotu çizilmek üzere retrun edilir.

 

 

Arduino kod Analizi:

KP = Serial.readStringUntil(',');

Serial.read();

·         Serial.readStringUntil() fonksiyonu ile gelen veride “,” karakteri öncesindekileri almak için kullanılmıştır.  Böylelikle

if (diff_time <=0)

  now_rpm = 0;

else

  now_rpm =( (60000000/diff_time) /64 ); 

·         60000000 mikro-sn(1dk) ‘dır. Now_rpm de iki yarık arasında interupt zamanı diff_time bölerek dakikadaki pulseleri sayar. Bir turda 64 pulse olduğundan ,64 e bölerek bir turun hesabı yapılır .

 

PID_sistem() fonksiyonunda outputu oluşturmak için katsayıları parametreler ile uygun bir şekilde çarparak outputu oluşturur. Hata toplamı mutlak değerde max_rpm den buyuk ile max_rpm e eşitlenir hatayı sature etmiş oluyoruz.

 

Mapping() fonksiyonunda 0< PID_value <255 arasında ise direk PID_value değerini pwm olarak verilecek. PID_value>255 ise max pwm değeri olan 255 output ( 5V )olarak motor sürücüsüne  verilecek.  PID_value < 0 ise çıkış ise çıkış verilmeyecek.


Çalışma Diyagramı 





























Bağlantı Şeması:


















Kaynakça

GUI için kullanılan kod :

https://thepoorengineer.com/en/motor-speed-control/

https://stackoverflow.com/questions/11874767/how-do-i-plot-in-real-time-in-a-while-loop-using-matplotlib







Yorumlar

Bu blogdaki popüler yayınlar

STM32F4 Discovery İnterupt Buton ( STM32 CUBE MX / IDE ) ve ATOLİC

Analog PID ile Encoderlı Motorun Hız Kontrolu