Bu yazıda Python ile yazdığım basit bir arayüz üzerinden Arduinoya(veya herhangi bir mikrodenetleyiciye) veri göndererek 4 adet ledi yakıp söndürme işleminden bahsedeceğim. Basit bir uygulama olsun diye sadece led yakıp söndürme işlemi yaptım. Ama farklı uygulamalarda yapılabilir. Örneğin arayüzden gönderilen yazının 2×16 lcd ekrana yazdırılması. Belki bunu da başka bir zaman yaparım.
Öncelikle Python tarafı daha zor olduğu için anlatmaya oradan başlıyorum. Arayüz için Pythonda Pyqt5 modülünü kullanarak aşağıdaki basit bir arayüz yapmaya çalıştım. Bu arayüz üzerine COM port ve Baudrate hızını seçebilmek için iki adet “combobox” yerleştirilmiştir. Ayrıca seriport üzerinden bağlantı sağlayabilmek ve gerektiğinde bağlantıyı kesebilmek için ve ledleri yakıp söndürebilmek için “pushbutton” lar eklenmiştir.
Arayüz ile seri port üzerinden veri göndermek veri almaya göre daha basit. Programın veri alma işlemini yapabilmesi için sürekli olarak seriportu dinlemesi gerekir. Bu dinlemeyi ise sonsuz bir döngü oluşturarak yapamıyoruz maalesef. Çünkü arayüz sınıfının içerisinde bir yerde sonsuz döngü kullanıldığı zaman arayüzde hiç bir şey görünmüyor. Peki seriporttan gelen verileri nasıl arayüze dahil edeceğiz. Bunun için yine Pyqt5 modülünün sınıflarından biri olan Qthread kullanılmıştır. Qthread basitçe belirlenen bir kaynaktan bir sinyal geldiğinde bunu programın algılaması işlemini yapıyor. Bir nevi RTOS daki task oluşturma işlemi diyebiliriz. Arayüz çalışırken aynı anda arkaplanda seriport dinlenmektedir. Qthread işlemi için ayrı bir “SerialThreadClass” isminde bir sınıf tanımlanmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class serialThreadClass(QtCore.QThread): # Seri Porttan veri okuma işlemi için QThread Kullanıldı. message = QtCore.pyqtSignal(str) def __init__(self,parent = None): super(serialThreadClass,self).__init__(parent) self.serialPort = serial.Serial() self.stopflag = False def stop(self): self.stopflag = True def run(self): while True: if (self.stopflag): self.stopflag = False break elif(self.serialPort.isOpen()): # eğer seri Port bağlı değil iken veri okumayı denersek hata verir. try: # bu hatayı yakalayabilmek için "try" bloğu kullanıldı. self.data = self.serialPort.readline() except: print("HATA\n") self.message.emit(str(self.data.decode())) |
Bu class içersinde sürekli olarak seriport dinlenmekte ve bir mesaj geldiğinde arayüz sınıfının içerisinde başka bir fonksiyona program dallanmaktadır. Bu fonksiyon içerisinde de gelen mesaj arayüzdeki “gelen mesaj” kısmında ekrana yazdırılmaktadır.
1 2 3 | self.mySerial = serialThreadClass() # pencere sınıfının içerisinde serialThreadClass nesnesi oluşturuldu. self.mySerial.message.connect(self.messageTextEdit) # seri porttan mesaj geldiğinde messageTextEdit fonksiyonuna dallan. self.mySerial.start() #thread işlemi başlatıldı. |
Arduinoya veri göndermek için arayüz sınıfının içerisinde “leds” isimli bir fonksiyon oluşturulmuştur. Led butonlarından hangisine tıklanırsa tıklansın program bu fonksiyonun içine girer daha sonra hangi butona tıklandığı belirlenir ve arduinoya karakter olarak bir sayı gönderilir.
1 2 3 4 5 | if led == self.led1on: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("1".encode()) # seri porttan Arduino'ya 1 karakteri gönderildi. else: self.message.append("Seri Port Bağlı Değil.") |
Arduino Kodları
Arduino tarafında 8,9,10,11 nolu pinlere ledler bağlanmıştır. Serial.begin(9600) ile baudrate ayarı seçilmiştir. Arayüz tarafında da baudrate ayarının aynı olması gerekmektedir. Arayüzden 1 ile 8 arası karakterlerler gelmektedir. Bu karakterlere göre ledler yakılıp söndürülmüştür.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | int led1=8,led2=9,led3=10,led4=11; char message; void setup() { pinMode(led1,OUTPUT); pinMode(led2,OUTPUT); pinMode(led3,OUTPUT); pinMode(led4,OUTPUT); Serial.begin(9600); } void loop() { if(Serial.available()>0) { message=Serial.read(); if(message == '1') { digitalWrite(led1,HIGH); Serial.println("Led1 Yandı!"); } if(message == '2') { digitalWrite(led1,LOW); Serial.println("Led1 Söndü!"); } if(message == '3') { digitalWrite(led2,HIGH); Serial.println("Led2 Yandı!"); } if(message == '4') { digitalWrite(led2,LOW); Serial.println("Led2 Söndü!"); } if(message == '5') { digitalWrite(led3,HIGH); Serial.println("Led3 Yandı!"); } if(message == '6') { digitalWrite(led3,LOW); Serial.println("Led3 Söndü!"); } if(message == '7') { digitalWrite(led4,HIGH); Serial.println("Led4 Yandı!"); } if(message == '8') { digitalWrite(led4,LOW); Serial.println("Led4 Söndü!"); } } } |
Python Kodlarının Tamamı
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | ######################################################################### ##### Basit bir arayüz ile Arduino'ya veya herhangi bir mikrodnetleyici## ##### tabanlı geliştrime kartına veri gönderme ve alma uygulaması. ## ##### www.mehmettopuz.net ## ######################################################################### import sys import serial import serial.tools.list_ports from PyQt5 import QtWidgets,QtGui,QtCore class serialThreadClass(QtCore.QThread): # Seri Porttan veri okuma işlemi için QThread Kullanıldı. message = QtCore.pyqtSignal(str) def __init__(self,parent = None): super(serialThreadClass,self).__init__(parent) self.serialPort = serial.Serial() self.stopflag = False def stop(self): self.stopflag = True def run(self): while True: if (self.stopflag): self.stopflag = False break elif(self.serialPort.isOpen()): # eğer seri Port bağlı değil iken veri okumayı denersek hata verir. try: # bu hatayı yakalayabilmek için "try" bloğu kullanıldı. self.data = self.serialPort.readline() except: print("HATA\n") self.message.emit(str(self.data.decode())) class Pencere(QtWidgets.QWidget): # arayüz sınıfı def __init__(self): super().__init__() self.initUi() def initUi(self): ############### Com Port Combo box ############### self.portComboBox = QtWidgets.QComboBox() self.ports = serial.tools.list_ports.comports() # Com portlar listelendi. for i in self.ports: self.portComboBox.addItem(str(i)) ################### Baudrate Combo Box######################## self.baudComboBox = QtWidgets.QComboBox() baud = ["300", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "74880", "115200", "230400", "250000", "500000", "1000000", "2000000"] for i in baud: self.baudComboBox.addItem(i) # baud dizisinin içerisindeki değerler eklendi. self.baudComboBox.setCurrentText(baud[4]) # pencere ilk açıldığında baudrate 9600 olsun. ########################## Butonlar ################################## self.baglan = QtWidgets.QPushButton("Bağlan") self.baglantiKes = QtWidgets.QPushButton("Bağlantıyı Kes") self.led1on = QtWidgets.QPushButton("LED1 ON") self.led1off = QtWidgets.QPushButton("LED1 OFF") self.led2on = QtWidgets.QPushButton("LED2 ON") self.led2off = QtWidgets.QPushButton("LED2 OFF") self.led3on = QtWidgets.QPushButton("LED3 ON") self.led3off = QtWidgets.QPushButton("LED3 OFF") self.led4on = QtWidgets.QPushButton("LED4 ON") self.led4off = QtWidgets.QPushButton("LED4 OFF") ###################################################################### self.label1 = QtWidgets.QLabel('<font color=red>COM port bağlı değil!!!</font>')# böyle yazıldığı zaman yazı rengi kırmızı olacak. portVbox = QtWidgets.QVBoxLayout() portVbox.addWidget(self.portComboBox) portVbox.addWidget(self.baudComboBox) portVbox.addWidget(self.baglan) portVbox.addWidget(self.baglantiKes) portVbox.addWidget(self.label1) self.portGroup = QtWidgets.QGroupBox("Port Seçme") self.portGroup.setLayout(portVbox) buttonHbox1 = QtWidgets.QHBoxLayout() buttonHbox1.addWidget(self.led1on) buttonHbox1.addWidget(self.led1off) buttonHbox2 = QtWidgets.QHBoxLayout() buttonHbox2.addWidget(self.led2on) buttonHbox2.addWidget(self.led2off) buttonHbox3 = QtWidgets.QHBoxLayout() buttonHbox3.addWidget(self.led3on) buttonHbox3.addWidget(self.led3off) buttonHbox4 = QtWidgets.QHBoxLayout() buttonHbox4.addWidget(self.led4on) buttonHbox4.addWidget(self.led4off) self.message = QtWidgets.QTextEdit() self.message.setReadOnly(True) # bu satırda text edit sadece okunabilir olarak ayarlandı. Yani textedit'in içine yazı yazılamaz. self.messageTitle = QtWidgets.QLabel("Gelen Mesaj") self.title1 = QtWidgets.QLabel('<font color=blue>Python-Arduino Uygulaması</font>') self.title1.setFont(QtGui.QFont("Arial",20,QtGui.QFont.Bold)) self.title2 = QtWidgets.QLabel("mehmettopuz.net") self.title2.setFont(QtGui.QFont("Arial", 10, QtGui.QFont.Normal)) vBox = QtWidgets.QVBoxLayout() vBox.addStretch() vBox.addWidget(self.title1) vBox.addWidget(self.title2) vBox.addWidget(self.portGroup) vBox.addLayout(buttonHbox1) vBox.addLayout(buttonHbox2) vBox.addLayout(buttonHbox3) vBox.addLayout(buttonHbox4) vBox.addWidget(self.messageTitle) vBox.addWidget(self.message) vBox.addStretch() hBox = QtWidgets.QHBoxLayout() hBox.addStretch() hBox.addLayout(vBox) hBox.addStretch() self.setLayout(hBox) self.setWindowTitle("ArduPy") self.mySerial = serialThreadClass() # pencere sınıfının içerisinde serialThreadClass nesnesi oluşturuldu. self.mySerial.message.connect(self.messageTextEdit) # seri porttan mesaj geldiğinde messageTextEdit fonksiyonuna dallan. self.mySerial.start() #thread işlemi başlatıldı. self.baglan.clicked.connect(self.serialConnect) # Butona tıklandığında serialConnection isimli fonksiyona dallan. self.baglantiKes.clicked.connect(self.serialDisconnect) self.led1on.clicked.connect(lambda: self.leds(self.led1on)) # hangi led butonuna tıklanırsa tıklansın program self.led1off.clicked.connect(lambda: self.leds(self.led1off)) # tek bir fonksiyona dallanacak. self.led2on.clicked.connect(lambda: self.leds(self.led2on)) # Bu yüzden leds fonksiyonunun içine buton parametresi self.led2off.clicked.connect(lambda: self.leds(self.led2off)) # yazıldı. self.led3on.clicked.connect(lambda: self.leds(self.led3on)) self.led3off.clicked.connect(lambda: self.leds(self.led3off)) self.led4on.clicked.connect(lambda: self.leds(self.led4on)) self.led4off.clicked.connect(lambda: self.leds(self.led4off)) self.show() def serialConnect(self): # "Bağlan" butonuna tıklandığında bu fonksiyona dallanacak. self.portText = self.portComboBox.currentText() # port combobox'ın içinde hangi değer varsa çekildi. self.port = self.portText.split() # combo box'ın içerisinde bize lazım olan sadece "COM13" kısmı. Bu yüzden split ile kelimeler ayrıldı. self.baudrate = self.baudComboBox.currentText()# comboBox'ın içindeki baudrate değeri çekildi. self.mySerial.serialPort.baudrate = int(self.baudrate) # seriport baudrate ayarı tanımlandı. self.mySerial.serialPort.port = self.port[0] try: self.mySerial.serialPort.open() # seri porta bağlanma komutu verildi. except: self.message.append("Bağlantı Hatası!!") if(self.mySerial.serialPort.isOpen()): self.label1.setText('<font color=green>Bağlandı</font>') # bağlantı sağlandıysa label1 yeşile dönsün. self.baglan.setEnabled(False) # Bağlantı varken tekrar bağlan butonuna tıklanmasın diye butonu pasif ediyoruz. self.portComboBox.setEnabled(False) # Bağlantı varken port ve baudrate seçimi yapılmasın diye self.baudComboBox.setEnabled(False) # kullanıcının seçim yapmasını engelliyoruz. def serialDisconnect(self): # "Bağlantı Kes" butonuna tıklandığında bu fonksiyona dallanacak. if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.close() if self.mySerial.serialPort.isOpen()== False: self.label1.setText('<font color=red>Bağlantı Kesildi</font>') self.baglan.setEnabled(True) self.portComboBox.setEnabled(True) self.baudComboBox.setEnabled(True) else: self.message.append("Seriport Zaten Kapalı.") def messageTextEdit(self): # seri porttan mesaj geldiğinde bu fonksiyon çalıştırılacak. self.incomingMessage = str(self.mySerial.data.decode()) self.message.append(self.incomingMessage) def leds(self,led): # led butonlarından herhangi birine tıklandığında bu fonksiyona dallanacak. if led == self.led1on: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("1".encode()) # seri porttan Arduino'ya 1 karakteri gönderildi. else: self.message.append("Seri Port Bağlı Değil.") elif led == self.led1off: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("2".encode()) else: self.message.append("Seri Port Bağlı Değil.") elif led == self.led2on: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("3".encode()) else: self.message.append("Seri Port Bağlı Değil.") elif led == self.led2off: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("4".encode()) else: self.message.append("Seri Port Bağlı Değil.") elif led == self.led3on: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("5".encode()) else: self.message.append("Seri Port Bağlı Değil.") elif led == self.led3off: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("6".encode()) else: self.message.append("Seri Port Bağlı Değil.") elif led == self.led4on: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("7".encode()) else: self.message.append("Seri Port Bağlı Değil.") elif led == self.led4off: if self.mySerial.serialPort.isOpen(): self.mySerial.serialPort.write("8".encode()) else: self.message.append("Seri Port Bağlı Değil.") if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) pen = Pencere() sys.exit(app.exec_()) |
Yazının başında da dediğim gibi bu projede sadece led yakıp söndürdüm. Siz istediğiniz bir uygulamayı yapabilirsiniz. Eğer sormak istediğiniz sorular var ise yorumlarda sormaktan çekinmeyin. Vakit buldukça yorumlarınızı cevaplayacağım. Ayrıca bu uygulamanın acemice çekilmiş videosunu aşağıda bulabilirsiniz. Başka bir yazıda görüşmek üzere.
Herkese iyi çalışmalar..
Merhabalar Mehmet Bey,
Öncelikle proje örneklerinizi paylaştığınız için teşekkür ederim. PyQt kütüphanesi ile arayüz yapıyorum. Yaptığım basit bir devrenin akım ve voltajını sensörler yardımıyla ölçüp Arduino aracılığıyla Python’a aktarıyorum. İki ayrı messageBox’a voltaj ve akım olarak volt ve amper değerlerini yazdırma konusunda sıkıntı yaşıyorum. Yardımcı olabilir misiniz?
Merhaba
Bu sorun birçok sebepten kaynaklanabilir.
1. Serialden veri okuyabilmeniz için Qthread kullanmanız gerek. Yukarıdaki kodlarda “serialThreadClass” isimli sınıfı inceleyebilirsiniz.
2. Baud rate ayarları tutmuyor olabilir. Arduino ile Python baudrate ayarı aynı olmalı.Yoksa arduino bilgisayara veri göndermez.
Bu saydıklarımda hata yok ise kodlarınızı https://paste.ubuntu.com/
Sitesine kopyalayın sonra linkini tekrar bu yoruma yazın kodları bir inceleyeyim.
https://paste.ubuntu.com/p/DYb47MsZNB/
Aslında sizin arayüzünüzde değişikler yapıp ek olarak diğer messageBox’lar oluşturup onlara veri çekme işlemini yaptım. Bu kod bilgisayarımda sorunsuz şekilde verileri çekip yazdırıyor fakat raspberry pi üzerinde çalıştırdığımda ise veri çekme esnasında hata veriyor. Hata da def run(): fonksiyonunda gösteriyor. Araştırma yapmama rağmen açıkçası pek kaynak bulamadım bu hata ile ilgili.
Yorumuma geri döndüğünüz için çok teşekkür ederim 😀
Rica ederim. Bir faydam dokunduysa ne mutlu bana.
Öncelikle run() fonksiyonunun içindeki print(“HATA\n”) satırını silip pass yazıp bir daha deneyin. Raspberry pi da konsola yazı yazdırmada hata veriyor olabilir. Ayrıca hata mesajını görebiliyorsanız yoruma yazarsanız sevinirim.
Raspberry’de python kodlarını çalıştırabileceğim 3 yer bulunuyor.
-Python3 IDLE’da çalıştırdığımda arayüz ekranı geldi ama veri alamadım.
-CMD’den yaptığıms no module named PyQt5 hatası verdi
-Thonny Python’dan denediğimde ise yine arayüz ekranı geldi fakat bağlan butonuna tıkladığımda;
Fatal Python error:Aborted
Current thread 0x69d9a470(most recent call first):
Thread 0x76efe010 (most recent call first):
File “/home/pi/Desktop/urban yeni/pyqt.py”, line 179 in
File “/usr/lib/python3/dist-packages/thonny/shared/thonny/backend.py”, line 588 in execute_source
File “/usr/lib/python3/dist-packages/thonny/shared/thonny/backend.py”, line 427 in _execute_source_ex
File “/usr/lib/python3/dist-packages/thonny/shared/thonny/backend.py”, line 374 in _execute_file
File “/usr/lib/python3/dist-packages/thonny/shared/thonny/backend.py”, line 155 in _cmd_Run
File “/usr/lib/python3/dist-packages/thonny/shared/thonny/backend.py”, line 119 in handle_command
File “/usr/lib/python3/dist-packages/thonny/shared/thonny/backend.py”, line 97 in mainloop
File “/usr/lib/python3/dist-packages/thonny/shared/backend_launcher.py”, line 41 in
Hatasını aldım
Hata Qthread’ tan kaynaklı gibi görünüyor ama çözümü nedir bilmiyorum. Eğer aynı kod bilgisayarda çalışıyorsa sorun raspberry tarafında olmalı diye düşünüyorum. Python dosyaları eksik yüklenmiş olabilir.
Kütüphaneleri yeniden yüklemeyi deneyeceğim. Vakit ayırdığınız için teşekkür ederim. İyi günler dilerim.
Hocam öncelikle emeğinize sağlık çok güzel bir çalışma olmuş. Benim bir sorum olacak. Bu python ekranında butona tıklama yerine klavye tuşlarıyla aynı işlemi nasıl yapabiliriz? Mesela birtanede başlat butonu ekleyip, Bağlan dedikten sonra Başlat butonuna tıkladıktan sonra 1′ e bastığımızda led1 yansın, 2′ ye bastığımızda led1 sönsün. Klavyeden değer gönderme işini fonksiyon altında bir türlü yapamadım. Program kilitlenip kalıyor. Yardımcı olabilirseniz sevinirim iyi günler iyi çalışmalar
Yanlış anlamadıysam klavyeden hangi tuşa basıldığını algılayabiliyorsun. Başlat butonuna bastıktan sonra arayüz kodlarında sonsuz döngü kullanıyorsan programı kitler. Böyle döngüleri thread’ler içine kullanman gerek. Eğer kodları paylaşmanda sakınca yok ise bana https://paste.ubuntu.com/ sitesine kodları yazıp linki gönderebilirsin.