Arduino Python Seri Haberleşme: pyserial ile Veri Okuma ve Grafik
Arduino Python seri haberleşme rehberi: pyserial kurulumu, port bulma, verileri CSV'ye kaydetme, Python'dan komut gönderme, matplotlib canlı grafik ve Pico.
Arduino Python seri haberleşme, bilgisayarında çalışan bir Python programının Arduino ile USB kablosu üzerinden veri alıp göndermesidir. Arduino sensörü ölçer ve sonucu seri porta yazar; Python bu satırları pyserial kütüphanesiyle okur, CSV dosyasına kaydeder, grafiğe döker ya da bir karar verip Arduino'ya geri komut gönderir. Böylece Arduino'nun hassas donanım kontrolünü Python'un veri işleme, grafik, yapay zekâ ve otomasyon gücüyle birleştirirsin. Bunun için ek bir modül de gerekmez: kodu yüklediğin USB kablosu yeterlidir.
Bu rehberde pyserial kurulumunu, Arduino'nun hangi porta bağlı olduğunu otomatik bulmayı, sensör verisini zaman damgasıyla CSV dosyasına kaydetmeyi, Python'dan Arduino'ya LED ve PWM komutları göndermeyi ve matplotlib ile canlı grafik çizmeyi adım adım öğreneceksin. Ardından veri biçimi ile satır sonu seçimini, en çok kafa karıştıran iki sorunu (port meşgul hatası ve port açılınca kartın resetlenmesi) ve aynı işi Raspberry Pi Pico'da MicroPython ile yapmanın farkını ele alacağız. Örnekler Arduino Uno için yazıldı; ESP32 ve Pico için gereken değişiklikleri ayrıca göreceksin.

Arduino ile Python nasıl haberleşir?
Arduino Uno'nun üzerindeki USB-seri yonga (orijinal kartlarda ATmega16U2, klonlarda çoğunlukla CH340) bilgisayara bir sanal seri port olarak görünür: Windows'ta COM3, COM4 gibi; macOS'ta /dev/cu.usbmodem… ya da /dev/cu.usbserial-…; Linux'ta /dev/ttyACM0 ya da /dev/ttyUSB0. Arduino tarafında Serial.print() ile yazılan her karakter bu porttan bayt olarak bilgisayara akar; Python tarafında pyserial portu bir dosya gibi açar, okur ve yazar. Önemli bir ayrım var: Arduino Uno Python kodu çalıştırmaz. Kartta C++ ile yazılmış Arduino kodu, bilgisayarda Python çalışır ve ikisi yalnızca seri hat üzerinden anlaşır. İki tarafın aynı dili konuşması için şu ayarların eşleşmesi gerekir:
| Ayar | Arduino tarafı | Python tarafı | Dikkat |
|---|---|---|---|
| Port | USB kablosuyla kendiliğinden oluşur | serial.Serial("COM3", ...) | Port adı işletim sistemine göre değişir |
| Hız (baud) | Serial.begin(115200) | serial.Serial(port, 115200) | Farklıysa anlamsız karakterler gelir |
| Çerçeve | 8 veri biti, parite yok, 1 stop biti (8N1) | pyserial varsayılanı da 8N1 | Genellikle değiştirmen gerekmez |
| Satır sonu | Serial.println() sona \r\n ekler | readline() \n görene kadar okur | Python'dan gönderirken \n eklemeyi unutma |
| Zaman aşımı | Serial.setTimeout(), varsayılan 1000 ms | timeout=1 (saniye) | timeout=None ile readline() sonsuza kadar bekler |
pyserial kurulumu (Windows, macOS, Linux)
- Bilgisayarında Python 3 kurulu olsun. Windows'ta Python'un resmi sitesinden indirdiğin kurulum programının ilk ekranındaki Add python.exe to PATH kutusunu işaretle; macOS ve Linux'ta Python 3 çoğunlukla hazır gelir.
- Terminali (Windows'ta Komut İstemi ya da PowerShell) aç ve python -m pip install pyserial yaz. Windows'ta python komutu tanınmazsa py -m pip install pyserial dene; macOS ve Linux'ta komut python3 -m pip install pyserial şeklinde olabilir.
- Kurulumu doğrula: python -c "import serial; print(serial.__version__)" komutu 3.5 gibi bir sürüm numarası yazmalı.
- Canlı grafik bölümü için matplotlib de gerekir: python -m pip install matplotlib.
- Linux'ta portu açabilmek için kullanıcını dialout grubuna ekle: sudo usermod -a -G dialout $USER, ardından oturumu kapatıp yeniden aç. Raspberry Pi OS ve yeni Ubuntu sürümlerinde pip externally-managed-environment hatası verirse sudo apt install python3-serial komutunu kullan ya da python3 -m venv ile bir sanal ortam oluşturup pip'i onun içinde çalıştır.
Arduino hangi portta? Python ile port bulma
En kolay yol Arduino IDE'deki Araçlar > Port menüsüne bakmaktır, ama Python'un kendisi de portları listeleyebilir. Terminalde python -m serial.tools.list_ports -v yazınca her port için ad, açıklama ve donanım kimliği (VID:PID) görünür. Hangi satırın Arduino olduğunu anlamadıysan kartı çıkar, komutu yeniden çalıştır ve kaybolan portu not et. macOS'ta aynı kart hem /dev/tty… hem /dev/cu… olarak görünür; Python'da cu ile başlayanı kullan.

| USB yongası | Nerede bulunur? | VID:PID | Windows'ta görünen ad | Linux port adı |
|---|---|---|---|---|
| ATmega16U2 | Orijinal Uno R3, Mega 2560 | 2341:0043 (Uno) | Arduino Uno (COMx) | /dev/ttyACM0 |
| CH340 | Klon Uno, Nano ve Mega kartlar | 1A86:7523 | USB-SERIAL CH340 (COMx) | /dev/ttyUSB0 |
| CP2102 | ESP32 DevKit, NodeMCU | 10C4:EA60 | Silicon Labs CP210x USB to UART Bridge (COMx) | /dev/ttyUSB0 |
| FT232R | Eski Nano'lar, FTDI kablolar | 0403:6001 | USB Serial Port (COMx) | /dev/ttyUSB0 |
| RP2040 (yerleşik USB) | MicroPython yüklü Raspberry Pi Pico | 2E8A:0005 | USB Seri Cihaz (COMx) | /dev/ttyACM0 |
Aşağıdaki fonksiyon bütün portları listeler ve VID değerine bakarak tanıdık bir kart bulursa onun port adını döndürür. Kodu port_bul.py adıyla kaydedersen diğer betiklerinde from port_bul import port_bul yazıp PORT = port_bul() şeklinde kullanabilir, port adını her seferinde elle değiştirmekten kurtulursun.
1import serial.tools.list_ports
2
3# Bilinen USB yongalarının üretici kimlikleri (VID) / Vendor IDs of common USB chips
4BILINEN = {
5 0x2341: "Arduino (orijinal / genuine)",
6 0x2A03: "Arduino (orijinal / genuine)",
7 0x1A86: "CH340 (klon / clone)",
8 0x10C4: "CP210x (ESP32, NodeMCU)",
9 0x0403: "FTDI",
10 0x2E8A: "Raspberry Pi Pico",
11}
12
13
14def port_bul():
15 portlar = sorted(serial.tools.list_ports.comports())
16 for p in portlar:
17 print(p.device, "|", p.description, "|", p.hwid) # tüm portları listele / list every port
18 for p in portlar:
19 if p.vid in BILINEN:
20 print("Bulundu / found:", p.device, "->", BILINEN[p.vid])
21 return p.device
22 return None
23
24
25if __name__ == "__main__":
26 if port_bul() is None:
27 print("Kart yok: kabloyu ve surucuyu kontrol et / no board: check cable and driver")Arduino'dan veri göndermek: ilk kod
Örneklerde A0 pinine bağlı bir potansiyometre kullanıyoruz: orta ucu A0'a, kenar uçlarından biri 5V'a, diğeri GND'ye gider. Potansiyometre yerine bir LDR ile 10 kΩ'luk dirençten oluşan bir gerilim bölücü de bağlayabilirsin. Kod her 200 ms'de bir ölçüm yapar ve sonucu zaman,değer biçiminde tek satır olarak gönderir:
1// A0 değerini "millis,deger" CSV satırı olarak gönderir / Sends the A0 reading as a "millis,value" CSV line
2const int SENSOR_PIN = A0; // potansiyometrenin orta ucu / potentiometer wiper
3const unsigned long ARALIK = 200; // gönderim aralığı, ms / send interval, ms
4unsigned long sonGonderim = 0;
5
6void setup() {
7 Serial.begin(115200); // Python'daki hızla aynı olmalı / must match the baud rate in Python
8}
9
10void loop() {
11 if (millis() - sonGonderim >= ARALIK) { // delay() olmadan zamanlama / timing without delay()
12 sonGonderim = millis();
13 int deger = analogRead(SENSOR_PIN); // 0-1023
14 Serial.print(sonGonderim); // zaman damgası / timestamp
15 Serial.print(','); // ayırıcı / separator
16 Serial.println(deger); // sonuna \r\n ekler / appends \r\n
17 }
18}Kodda delay() yerine millis() kullanmak, ileride aynı döngüye Python'dan gelen komutları okuma işini eklemeyi kolaylaştırır; ayrıntılar için millis ve delay yazısına bakabilirsin. Kodu yükledikten sonra Seri Port Ekranı'nı 115200 baud hızında açarsan 2573,512 gibi satırların aktığını görürsün. Bu yalnızca bir kontrol adımıdır: Python betiğini çalıştırmadan önce Seri Port Ekranı'nı mutlaka kapat, yoksa port meşgul olur. Seri Port Ekranı'nı ilk kez kullanıyorsan Arduino Serial Monitor rehberi işini kolaylaştırır.
Python ile Arduino verisini okumak ve CSV'ye kaydetmek
1import csv
2import time
3from datetime import datetime
4
5import serial
6
7PORT = "COM3" # macOS: /dev/cu.usbmodem14101, Linux: /dev/ttyACM0
8BAUD = 115200 # Arduino'daki Serial.begin ile aynı / same as Serial.begin on the Arduino
9
10with serial.Serial(PORT, BAUD, timeout=1) as ser, \
11 open("olcumler.csv", "w", newline="", encoding="utf-8") as dosya:
12 time.sleep(2) # Uno port açılınca resetlenir / the Uno resets when the port opens
13 ser.reset_input_buffer() # yarım kalmış eski veriyi at / drop stale, partial data
14 yazici = csv.writer(dosya)
15 yazici.writerow(["tarih", "zaman_ms", "deger", "volt"]) # başlık satırı / header row
16 print("Kayit basladi, durdurmak icin Ctrl+C / logging, press Ctrl+C to stop")
17 try:
18 while True:
19 satir = ser.readline().decode("utf-8", errors="ignore").strip()
20 parcalar = satir.split(",")
21 if len(parcalar) != 2:
22 continue # boş ya da beklenmeyen satır / empty or unexpected line
23 try:
24 zaman_ms, deger = int(parcalar[0]), int(parcalar[1])
25 except ValueError:
26 continue # bozuk satır / corrupted line
27 volt = deger * 5.0 / 1023 # Uno ADC: 0-1023 -> 0-5 V
28 yazici.writerow([datetime.now().isoformat(timespec="seconds"),
29 zaman_ms, deger, round(volt, 3)])
30 dosya.flush() # satırı hemen diske yaz / write the row to disk now
31 print(zaman_ms, deger, f"{volt:.2f} V")
32 except KeyboardInterrupt:
33 print("Durduruldu / stopped")Bu betik portu timeout=1 ile açar: readline() satır sonu gelene kadar en fazla 1 saniye bekler, veri gelmezse boş bir bayt dizisi döndürür ve döngü takılmaz. Gelen veri bytes türündedir; decode() onu metne çevirir, strip() sondaki \r\n karakterlerini atar, split(",") de satırı sütunlara böler. Port açıldıktan sonraki time.sleep(2) ve reset_input_buffer(), Uno'nun yeniden başlaması sırasında gelen yarım satırları atmak içindir; bunun sebebini aşağıda göreceksin. Dosyayı newline="" ile açmak Windows'ta satırların arasına boş satır girmesini önler, flush() ise program aniden kapansa bile o ana kadarki ölçümlerin diskte kalmasını sağlar. Kaydı durdurmak için terminalde Ctrl+C'ye bas.
Python'dan Arduino'ya komut göndermek
Haberleşme çift yönlüdür. Aşağıdaki Arduino kodu satır satır gelen komutları bekler: LED ON ve LED OFF dahili LED'i yakıp söndürür, PWM 128 pin 9'a bağlı LED'in parlaklığını ayarlar, READ ise A0'daki değeri geri gönderir. Her komuta kısa bir cevap verilir; böylece Python komutun gerçekten işlendiğini anlar. Pin 9'daki LED için doğru direnç değerini LED direnç hesaplayıcı ile bulabilirsin; PWM'in nasıl çalıştığını PWM nedir yazısı anlatıyor.
1// Python'dan gelen satır komutlarını işler / Handles line-based commands from Python
2const int LED_PIN = LED_BUILTIN; // Uno'da pin 13 / pin 13 on the Uno
3const int PWM_PIN = 9; // 220 ohm dirençli LED / LED with a 220 ohm resistor
4
5void setup() {
6 pinMode(LED_PIN, OUTPUT);
7 pinMode(PWM_PIN, OUTPUT);
8 Serial.begin(115200);
9 Serial.setTimeout(50); // readStringUntil en fazla 50 ms bekler / waits at most 50 ms
10 Serial.println("HAZIR"); // Python bu satırı bekler / Python waits for this line
11}
12
13void loop() {
14 if (Serial.available() > 0) {
15 String komut = Serial.readStringUntil('\n'); // satır sonuna kadar oku / read up to the newline
16 komut.trim(); // \r ve boşlukları sil / strip \r and spaces
17
18 if (komut == "LED ON") {
19 digitalWrite(LED_PIN, HIGH);
20 Serial.println("OK LED ON");
21 } else if (komut == "LED OFF") {
22 digitalWrite(LED_PIN, LOW);
23 Serial.println("OK LED OFF");
24 } else if (komut.startsWith("PWM ")) {
25 int deger = komut.substring(4).toInt(); // "PWM 128" -> 128
26 deger = constrain(deger, 0, 255); // 0-255 aralığında tut / keep it within 0-255
27 analogWrite(PWM_PIN, deger);
28 Serial.print("OK PWM ");
29 Serial.println(deger);
30 } else if (komut == "READ") {
31 Serial.println(analogRead(A0)); // A0 ölçümünü gönder / send the A0 reading
32 } else if (komut.length() > 0) {
33 Serial.print("ERR "); // bilinmeyen komut / unknown command
34 Serial.println(komut);
35 }
36 }
37}1import time
2
3import serial
4
5
6def komut_gonder(ser, komut):
7 ser.write((komut + "\n").encode("ascii")) # satır sonu şart / the newline is required
8 return ser.readline().decode("ascii", errors="ignore").strip() # cevabı bekle / wait for the reply
9
10
11with serial.Serial("COM3", 115200, timeout=2) as ser:
12 bitis = time.time() + 3 # en fazla 3 sn bekle / wait at most 3 s
13 while time.time() < bitis:
14 if ser.readline().strip() == b"HAZIR": # Arduino açıldı / the Arduino is up
15 break
16 print(komut_gonder(ser, "LED ON")) # OK LED ON
17 time.sleep(1)
18 print(komut_gonder(ser, "PWM 128")) # OK PWM 128
19 print("A0 =", komut_gonder(ser, "READ")) # A0 = 512
20 print(komut_gonder(ser, "LED OFF")) # OK LED OFFPython tarafında en sık yapılan hata komutun sonuna \n koymamaktır: Arduino readStringUntil('\n') satır sonunu bulamayınca Serial.setTimeout() ile verilen süre kadar bekler ve komutu ancak ondan sonra işler. Bu kodda süre 50 ms'dir; varsayılan 1000 ms ile her komut bir saniye gecikirdi. write() yalnızca bayt kabul eder, bu yüzden metni encode() ile ya da başına b koyarak (b"LED ON\n") bayta çevirmen gerekir. Betik başta HAZIR satırını en fazla 3 saniye bekler: Uno port açılınca yeniden başladığı için ilk komutu hemen gönderirsen bootloader'a gider ve kaybolur. Her komuttan sonra cevabı okumak, yani istek ve cevap düzeni, iki tarafın senkron kalmasını sağlar ve tamponların dolmasını önler; Uno'nun gelen veri tamponu yalnızca 64 bayttır.
Veri biçimi ve satır sonu: hangisini seçmeli?
Seri hat sana yalnızca bir bayt akışı verir; bir ölçümün nerede bitip diğerinin nerede başladığını senin belirlemen gerekir. Bunun en sağlam yolu her ölçümü tek bir satıra yazmak ve satırları \n ile bitirmektir. Satırın içinde hangi biçimi kullanacağın projenin büyüklüğüne bağlıdır:
| Biçim | Örnek satır | Artısı | Eksisi |
|---|---|---|---|
| Tek değer | 512 | En basit biçim; Arduino Seri Çizici de doğrudan çizer | Birden çok değer gönderince hangisinin ne olduğu karışır |
| CSV | 2573,512,23.5 | Kısa; Excel ve pandas doğrudan okur | Sütun sırası iki tarafta aynı kalmalı |
| Anahtar:değer | sicaklik:23.5,nem:41 | Okunaklı; Seri Çizici etiketleri gösterir | Daha uzun, ayrıştırması biraz daha zahmetli |
| JSON | {"t":23.5,"h":41} | Python'da json.loads() ile tek satırda çözülür | En uzun biçim; Uno'nun sınırlı RAM'ini zorlar |
| İkili (binary) | 2 bayt: 0x02 0x00 | En hızlı ve en kısa yol | İnsan okuyamaz; struct modülü ve başlangıç baytı gerekir |
Satır sonları da sık kafa karıştırır. Serial.println() her satırın sonuna iki karakter ekler: satır başı (\r, CR) ve satır besleme (\n, LF). Python'un readline() metodu yalnızca \n'yi bekler, bu yüzden satırın sonunda bir \r kalır; strip() ikisini birden temizler. Arduino IDE'nin Seri Port Ekranı'ndaki satır sonu listesinde Satır Sonu Yok, Yeni Satır, Satır Başı ve NL ve CR ile Birlikte (İngilizce arayüzde No Line Ending, New Line, Carriage Return, Both NL & CR) seçenekleri vardır; Arduino kodunu Python'dan önce Seri Port Ekranı'nda denerken Yeni Satır seç ki Python'un gönderdiğiyle aynı karakter gitsin. Ondalık sayılarda Serial.print(sicaklik, 1) gibi basamak sayısını belirt; Uno'da sprintf ondalık sayı biçimini (%f) desteklemediği için sprintf ile ondalık yazmaya çalışmak sayı yerine soru işareti üretir.
| Baud hızı | Saniyede bayt (8N1) | 12 baytlık satır / saniye | Ne zaman kullanılır? |
|---|---|---|---|
| 9600 | 960 | 80 | Yavaş sensörler, uzun kablolar, eski örnek kodlar |
| 57600 | 5 760 | 480 | Orta hızlı ölçümler |
| 115200 | 11 520 | 960 | Canlı grafik, ESP32 ve yeni projelerin çoğu |
Seri hatta her bayt, başlangıç ve bitiş bitleriyle birlikte 10 bit olarak gider; bu yüzden 115200 baud saniyede yaklaşık 11 520 bayt demektir. 25730,1023 ve satır sonundan (\r\n) oluşan 12 baytlık bir satır için saniyede 960 satıra kadar yer var. Hız iki tarafta aynı değilse hatta bozuk karakterler akar ve Python'da UnicodeDecodeError görürsün. Saniyede 5 ile 20 arasında ölçüm, insan gözü ve sensörlerin çoğu için fazlasıyla yeterlidir; gereksiz yere çok sık göndermek grafiği yavaşlatır, dosyayı da şişirir.
matplotlib ile canlı grafik çizmek
1from collections import deque
2
3import matplotlib.pyplot as plt
4import serial
5from matplotlib.animation import FuncAnimation
6
7ser = serial.Serial("COM3", 115200, timeout=0.1)
8N = 200 # ekrandaki ölçüm sayısı / readings on screen
9veri = deque([0] * N, maxlen=N) # eskiler kendiliğinden düşer / old values drop out
10
11fig, ax = plt.subplots()
12cizgi, = ax.plot(range(N), list(veri))
13ax.set_ylim(0, 1023) # Uno ADC aralığı / Uno ADC range
14ax.set_xlabel("Ornek / sample")
15ax.set_ylabel("A0")
16
17
18def guncelle(_):
19 while ser.in_waiting: # biriken bütün satırları oku / read every queued line
20 parca = ser.readline().decode("utf-8", errors="ignore").strip().split(",")
21 if len(parca) == 2 and parca[1].isdigit():
22 veri.append(int(parca[1]))
23 cizgi.set_ydata(list(veri))
24 return (cizgi,)
25
26
27ani = FuncAnimation(fig, guncelle, interval=50, blit=True, cache_frame_data=False) # ani silinmemeli / keep ani
28plt.show()
29ser.close()Grafik, son 200 ölçümü tutan bir deque üzerine kurulu: yeni değer sağdan eklenir, en eski değer soldan kendiliğinden düşer. FuncAnimation, guncelle fonksiyonunu her 50 ms'de bir çağırır. Fonksiyondaki while ser.in_waiting döngüsü önemlidir: Arduino şimdilik saniyede 5 satır gönderiyor, ama hızı artırdığında her karede tek satır okumak grafiğin gerçek zamanın gerisinde kalmasına yol açar; bu döngü birikmiş bütün satırları okuyup grafiği hep güncel tutar. ani değişkenini silme: animasyon nesnesine bağlı bir değişken kalmazsa Python onu çöpe atar ve pencere donuk kalır. ESP32 için set_ylim(0, 4095), Pico için set_ylim(0, 65535) yaz. Yalnızca hızlıca bakmak istiyorsan Arduino IDE'deki Seri Çizici (Serial Plotter) da iş görür; Python'un farkı grafiği kaydedebilmen, birden çok kaynağı birleştirebilmen ve veriyi aynı anda işleyebilmendir.
Port meşgul hatası ve otomatik reset sorunu
Bir seri portu aynı anda yalnızca tek bir program açabilir. Python betiği çalışırken Arduino IDE'nin Seri Port Ekranı ya da Seri Çizici açıksa, başka bir Python betiği portu tutuyorsa ya da 3D yazıcı programları gibi portları tarayan bir yazılım arka planda çalışıyorsa Windows'ta could not open port 'COM3': PermissionError(13, 'Access is denied.', None, 5), macOS ve Linux'ta ise Resource busy ya da Device or resource busy hatasını alırsın. Tersi de geçerlidir: Python betiği portu açık tutarken Arduino IDE kod yükleyemez. Bu yüzden betiklerinde with serial.Serial(...) as ser: yapısını kullan; blok bitince ya da hata çıkınca port kendiliğinden kapanır. Kod yüklemeden önce betiği Ctrl+C ile durdurmayı alışkanlık hâline getir.
İkinci sorun daha sinsidir: Arduino Uno, Nano ve Mega'da USB yongasının DTR hattı 100 nF'lık bir kondansatör üzerinden işlemcinin RESET pinine bağlıdır. Bu devre IDE'nin kod yüklerken kartı kendiliğinden yeniden başlatabilmesi için vardır, ama pyserial portu her açtığında da DTR değişir ve kart resetlenir. Kart önce bir iki saniye bootloader'da bekler, sonra senin kodunu baştan çalıştırır. Bu sürede gönderdiğin komutlar kaybolur, Arduino'nun setup() içinde yazdığı ilk satırları da kaçırabilirsin. Çözüm, portu açtıktan sonra time.sleep(2) ile beklemek ya da daha sağlamı Arduino'nun HAZIR gibi bir satır göndermesini beklemektir; yukarıdaki komut örneği böyle yapar. Portu programın başında bir kez açıp sonuna kadar açık tut: her ölçüm için portu açıp kapatan bir döngü kartı sürekli resetler.
Reseti tamamen engellemek istersen iki yol var. Yazılımla: ser = serial.Serial() ile portu kapalı oluştur, ser.port ve ser.baudrate değerlerini ver, ser.dtr = False yaz ve ardından ser.open() çağır. Bu Windows'ta çoğunlukla işe yarar; Linux ve macOS'ta ise işletim sistemi port açılırken DTR'yi yine de değiştirebilir. Donanımla: Uno'nun RESET ve GND pinleri arasına 10 µF'lık bir kondansatör tak, artı bacağı RESET'e gelsin. Leonardo, Micro ve Raspberry Pi Pico gibi yerleşik USB'li kartlar ise port açılınca yeniden başlamaz; bu kartlarda kodun Python bağlanmadan önce yazdığı satırlar kaybolabilir, o yüzden önemli mesajları bir komut geldiğinde göndermek daha güvenlidir.
ESP32 ile Python seri haberleşme
Buradaki Python kodlarının hepsi ESP32 ile de çalışır; yalnızca Arduino tarafında birkaç şeyi değiştirmen gerekir. Analog giriş için ADC1 pinlerinden birini (ör. GPIO 34) kullan. ESP32'nin ADC'si 12 bittir ve 0–3,3 V aralığını 0–4095 olarak verir, bu yüzden Python'da gerilimi deger * 3.3 / 4095 ile hesapla. ESP32 açılırken 115200 baud'da rst:0x1 (POWERON_RESET),boot:0x13 gibi kendi açılış mesajlarını basar; yukarıdaki betikler sayıya çevrilemeyen satırları atladığı için bu mesajlar sorun çıkarmaz. Kartın otomatik reset devresine ve işletim sistemine göre ESP32 de port açılınca yeniden başlayabilir, bu yüzden bekleme ve HAZIR satırı burada da işe yarar. USB yongası çoğunlukla CP2102 ya da CH340'tır. Kablo istemiyorsan ESP32 aynı veriyi Wi-Fi üzerinden de gönderebilir; bunun için ESP32 WebSocket ve ESP32 Google Sheets rehberlerine göz at. Kartı ilk kez kullanıyorsan önce ESP32 nedir yazısını oku.
Raspberry Pi Pico ve MicroPython: farkı ne?

Python'u donanımla buluşturmanın bir yolu da onu doğrudan kartın üzerinde çalıştırmaktır. Raspberry Pi Pico MicroPython ile programlanabilir: sensör okuma, LED yakma ve zamanlama gibi işler Python söz dizimiyle Pico'nun içinde yapılır. Ancak MicroPython, bilgisayardaki Python'un küçültülmüş bir sürümüdür; matplotlib, pandas ya da OpenCV Pico'da çalışmaz. Bu yüzden veriyi kaydetmek, grafik çizmek ya da yapay zekâyla işlemek istiyorsan Pico'yu da bilgisayardaki Python'a bağlarsın. Bu yazıdaki pyserial kodları Pico ile de çalışır; yalnızca port adını, değer aralığını ve komut cevaplarının okunuşunu aşağıda anlattığımız gibi uyarlaman gerekir.
| Özellik | Arduino + bilgisayarda Python | Pico + MicroPython (tek başına) | Pico + bilgisayarda Python |
|---|---|---|---|
| Python nerede çalışır? | Yalnızca bilgisayarda; kartta C++ çalışır | Pico'nun içinde | İki tarafta da: Pico'da MicroPython, bilgisayarda Python |
| Bilgisayar gerekir mi? | Evet, veri bilgisayarda işlenir | Hayır, USB'den ya da pilden çalışır | Evet |
| Kullanılabilen kütüphaneler | pyserial, matplotlib, pandas, numpy, OpenCV | machine, time gibi sınırlı modüller | Bilgisayardaki bütün kütüphaneler |
| Baud hızı | Önemli, iki tarafta aynı olmalı | Seri port kullanılmaz | Önemsiz, veri USB hızında akar |
| Port açılınca reset | Uno, Nano ve Mega'da evet | Yok | Hayır |
| Ne zaman seçilir? | Arduino zaten elindeyse, hazır kütüphaneler gerekiyorsa | Bağımsız çalışan basit cihazlar | İki tarafta da tek dil (Python) isteyenler |
Aşağıdaki MicroPython kodu, yukarıdaki Arduino örneğinin Pico karşılığıdır: GP26'daki potansiyometreyi her 200 ms'de bir okur, sonucu aynı zaman,değer biçiminde gönderir ve aynı LED komutlarını kabul eder. Arduino'daki Serial'ın karşılığı burada print() ve sys.stdin'dir; select.poll() sayesinde komut beklerken ölçüm döngüsü durmaz.
1# Pico'ya main.py adıyla kaydet / save it on the Pico as main.py
2import sys
3import select
4import time
5from machine import ADC, Pin
6
7led = Pin("LED", Pin.OUT) # Pico ve Pico W dahili LED / onboard LED on Pico and Pico W
8pot = ADC(26) # GP26 = ADC0, potansiyometre orta ucu / potentiometer wiper
9okuyucu = select.poll()
10okuyucu.register(sys.stdin, select.POLLIN) # USB'den veri gelince haber ver / notify when USB data arrives
11
12son = time.ticks_ms()
13while True:
14 if okuyucu.poll(0): # bekleyen komut var mı? / is a command waiting?
15 komut = sys.stdin.readline().strip()
16 if komut == "LED ON":
17 led.on()
18 print("OK LED ON")
19 elif komut == "LED OFF":
20 led.off()
21 print("OK LED OFF")
22 if time.ticks_diff(time.ticks_ms(), son) >= 200: # 200 ms'de bir ölçüm / one reading every 200 ms
23 son = time.ticks_ms()
24 print("{},{}".format(son, pot.read_u16())) # zaman,değer (0-65535) / time,value (0-65535)Kodu Thonny ile Pico'ya main.py adıyla kaydet, ardından Thonny'yi kapat ve Pico'nun USB kablosunu çıkarıp yeniden tak: Thonny Pico'nun seri portunu kendisi kullandığı için açıkken Python betiğin portu açamaz, ayrıca bağlanırken çalışan programı durdurur; kart yeniden başlayınca main.py kendiliğinden çalışır. Pico'nun USB portunda baud hızı önemsizdir; Python'da hangi değeri yazarsan yaz veri USB hızında akar. read_u16() 0–65535 arasında değer verdiği için gerilimi deger * 3.3 / 65535 ile hesapla. Pico ölçüm satırlarını durmadan gönderdiği için yukarıdaki komut betiğinde readline() cevap yerine bir ölçüm satırı döndürebilir; Pico ile çalışırken OK ile başlayan satırı görene kadar okumaya devam et. Bu örnekte HAZIR satırı ve PWM ile READ komutları yoktur; gerekirse Pico koduna ekleyebilirsin. Bilgisayardan ikili veri gönderiyorsan dikkat et: 0x03 baytı MicroPython'da Ctrl+C anlamına gelir ve programını durdurur; bunu micropython.kbd_intr(-1) ile kapatabilirsin. Pico'ya yeni başlıyorsan Raspberry Pi Pico nedir ve MicroPython temelleri yazıları iyi bir başlangıçtır.
Arduino ve Python ile proje fikirleri
- Sıcaklık ve nem kaydedici: DHT11 ile ölçtüğün değerleri dakikada bir CSV'ye yaz, odanın bir haftalık iklimini Excel'de ya da pandas ile grafiğe dök.
- Bilgisayardan lamba kontrolü: Python'dan gönderdiğin ON ve OFF komutlarıyla bir röle modülünü sür; bunu bir zamanlayıcı ya da sesli komutla birleştir.
- Canlı mesafe grafiği: HC-SR04 ile ölçülen mesafeyi matplotlib ile çiz. Sensörü bir servoyla döndürürsen aynı yöntemle bir radar ekranı da çizebilirsin.
- Bilgisayar durum ekranı: Python psutil kütüphanesiyle işlemci ve bellek kullanımını okuyup Arduino'ya göndersin, Arduino da bunları bir OLED ekranda göstersin.
- Yüz takip eden kamera: OpenCV yüzün görüntüdeki konumunu bulur, Python bunu bir açıya çevirip gönderir, Arduino da bir servo motorla kamerayı çevirir.
- Kendi kısayol klavyen: Arduino'ya bağlı butonlara basılınca bir satır gönderilsin, Python bunu okuyup bilgisayarda program açsın ya da bir kısayol çalıştırsın.
Sık yapılan hatalar ve çözümleri
| Hata ya da belirti | Sebep | Çözüm |
|---|---|---|
| ModuleNotFoundError: No module named 'serial' | pyserial, betiği çalıştıran Python yorumlayıcısına kurulmamış; VS Code ya da Thonny başka bir Python kullanıyor olabilir | Aynı yorumlayıcıyla python -m pip install pyserial çalıştır, editörde doğru yorumlayıcıyı seç |
| AttributeError: module 'serial' has no attribute 'Serial' | Yanlış serial paketi kurulmuş ya da dosyanın adı serial.py | pip uninstall serial ve pip install pyserial; dosyanı yeniden adlandır |
| could not open port 'COM3': PermissionError(13, 'Access is denied.', None, 5) | Port başka bir programda açık: Seri Port Ekranı, Seri Çizici ya da ikinci bir betik | Diğer programı kapat; betikte with yapısını kullan |
| could not open port 'COM5': FileNotFoundError(2, 'The system cannot find the file specified.', None, 2) | Port adı yanlış ya da kart takılı değil | python -m serial.tools.list_ports -v ile doğru adı bul |
| [Errno 13] Permission denied: '/dev/ttyACM0' | Linux kullanıcısının seri porta erişim izni yok | sudo usermod -a -G dialout $USER, ardından oturumu kapatıp aç |
| Anlamsız karakterler ya da UnicodeDecodeError | Baud hızları farklı ya da açılış sırasında gelen gürültü | İki tarafta aynı hızı kullan; decode(errors="ignore") ve reset_input_buffer() ekle |
| readline() hep b'' döndürüyor | Arduino satır sonu göndermiyor (println yerine print), port yanlış ya da kart hâlâ açılıyor | println kullan, portu ve hızı kontrol et, timeout süresini artır |
| ValueError: invalid literal for int() with base 10 | Yarım, boş ya da beklenmeyen bir satır sayıya çevrilmeye çalışıldı | Dönüştürmeyi try/except içine al, sütun sayısını kontrol et |
| İlk komutlar işlenmiyor | Port açılınca Uno resetlendi, komut bootloader'a gitti | HAZIR satırını bekle ya da portu açtıktan sonra 2 saniye bekle |
| Grafik gerçek zamanın gerisinde kalıyor | Her karede tek satır okunuyor, veri tamponda birikiyor | in_waiting döngüsüyle bütün satırları oku, gönderim sıklığını azalt |
| Betik açıkken Arduino'ya kod yüklenmiyor | Python portu tutuyor | Betiği Ctrl+C ile durdur, sonra yükle |
Arduino ile Python'u seri port üzerinden konuşturmak, basit bir sensör projesini veri kaydeden, grafik çizen ve bilgisayardan yönetilebilen bir sisteme dönüştürmenin en kısa yoludur. Önce tek bir değeri okuyup ekrana yazdır, sonra CSV'ye kaydet, en son komut ve grafik ekle; her adımda iki tarafın baud hızının ve satır sonunun eşleştiğinden emin ol. BlueGrays uygulamasında LDR ile ışık ölçme, DHT11 ile sıcaklık ve nem, HC-SR04 ile mesafe ölçme ve iki Arduino arasında seri haberleşme projelerini devre şemaları ve kodlarıyla adım adım bulabilir, Python ile okuyacağın verinin kaynağını hazır projelerle hızla kurabilirsin.
Sıkça sorulan sorular
Arduino Python ile programlanabilir mi?
Arduino Uno, Nano ve Mega'nın içinde Python çalışmaz; bu kartlar Arduino IDE'de C++ tabanlı Arduino diliyle programlanır. Python bilgisayarda çalışır ve kartla pyserial aracılığıyla seri port üzerinden konuşur; StandardFirmata örneğini yükleyip pyFirmata2 gibi bir kütüphaneyle pinleri Python'dan doğrudan yönetmek de mümkündür. Python'u kartın içinde çalıştırmak istiyorsan MicroPython destekleyen Raspberry Pi Pico ya da ESP32 seç.
pyserial nasıl kurulur?
Terminalde python -m pip install pyserial komutunu çalıştır, kodda ise import serial yaz. Paketin adı pyserial, içe aktarılan modülün adı serial'dır; pip install serial ise bambaşka bir paket kurar ve AttributeError hatasına yol açar. Linux'ta ayrıca kullanıcını dialout grubuna eklemen gerekir.
Arduino'nun hangi COM portta olduğunu nasıl bulurum?
Arduino IDE'de Araçlar > Port menüsüne bakabilir ya da terminalde python -m serial.tools.list_ports -v komutunu çalıştırabilirsin. Windows'ta Aygıt Yöneticisi'ndeki Bağlantı noktaları (COM ve LPT) başlığı da portu gösterir. Emin değilsen kartı çıkarıp listeyi yeniden al; kaybolan port Arduino'nundur.
Python'dan Arduino'ya veri nasıl gönderilir?
Portu serial.Serial ile açıp ser.write(b"LED ON\n") gibi bayt olarak gönderirsin; metni encode() ile bayta çevirmeyi ve sonuna satır sonu eklemeyi unutma. Arduino tarafında Serial.available() ile veri gelip gelmediğine bakar, Serial.readStringUntil('\n') ile satırı okursun. Port açılınca Uno resetlendiği için ilk komutu göndermeden önce yaklaşık 2 saniye beklemelisin.
Arduino Seri Port Ekranı ve Python aynı anda kullanılabilir mi?
Hayır, bir seri portu aynı anda yalnızca bir program açabilir; ikinci program Access is denied ya da Resource busy hatası alır. Gelen veriyi Python'da hem işleyip hem de print ile ekrana yazdırabilirsin. İki ayrı kanal gerekiyorsa Arduino'ya ikinci bir USB-TTL dönüştürücü bağlayıp SoftwareSerial ile ikinci bir seri port oluşturabilirsin.
Python portu açınca Arduino neden resetleniyor?
Uno, Nano ve Mega'da USB yongasının DTR hattı bir kondansatörle RESET pinine bağlıdır ve port her açıldığında kart yeniden başlar; bu devre IDE'nin kod yükleyebilmesi için gereklidir. Portu açtıktan sonra 2 saniye bekle ya da Arduino'nun hazır olduğunu bildiren bir satırı bekle. Reseti tamamen engellemek için RESET ile GND arasına 10 µF kondansatör takabilirsin, ama yüklemeden önce çıkarman gerekir.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
Ldr İle Işık Şiddeti Okuma
Odanın ne kadar aydınlık olduğunu sayıyla görmek ister misin? Işığa duyarlı küçük bir parça olan LDR ortam ışığını ölçer ve Arduino bu değeri yarım saniyede bir bilgisayar ekranına yazar. Elinle üstün

HC-SR04 Mesafe Ölçme (Serial Ekran)
Yarasalar karanlıkta yollarını nasıl buluyorsa HC-SR04 sensörü de öyle çalışır: duyamadığın bir ses gönderir, yankısını dinler ve önündeki cismin ne kadar uzakta olduğunu ölçer. Arduino bu mesafeyi sa

DHT11 İle Sıcaklık Ve Nem
Odan kaç derece, hava nemli mi, kuru mu? DHT11 sensörü sıcaklığı ve nemi ölçer, Arduino da bu değerleri iki satırlık LCD ekrana yazar ve birkaç saniyede bir yeniler. Sensöre bir şey olursa ekranda hat

ESP32 LDR Modülü ile Işık Şiddeti Okuma
LDR modülünün ham ADC değerini ve karanlık/aydınlık referanslarına göre hesaplanan göreli ışık yüzdesini Serial Monitor'da gerçek zamanlı izleme. Bu yüzde lux ölçümü değildir. Modülün kalibrasyon mantığını öğretir. Proje 10'un öncesinde yapılması ideal; çünkü eşik değerini belirlemek için kullanılır.

2 Arduino Tek Yönlü Haberleşme
İki Arduino'yu tek bir kabloyla konuşturursun: birindeki butona basınca öbüründeki LED yanar, bir daha basınca söner. Gönderen kart butona basıldığını kısa bir mesajla bildirir, alan kart bu mesajı du

2 Arduino Çift Yönlü Haberleşme
İki Arduino kabloyla birbirine bağlanıp konuşur: birinin butonuna basınca öbürünün ışığı yanar, yeniden basınca söner. İki kartta da aynı program çalışır, yani ikisi de hem haber gönderir hem haber al

Bluetooth İle Telefondan Led Yakma
Telefonundan odadaki ışıkları açıp kapatmanın küçük bir provası. Bluetooth modülü telefondan gelen harfleri Arduino'ya iletir; bir harf kırmızı LED'i, başka bir harf yeşil LED'i yakar, aynı harflerin

ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)
ESP32 ile zamanlı sıcaklık ve nem kayıt sistemi kur! Bu projede DHT22 sensörü ile dakikada bir sıcaklık/nem okuyup DS1307 RTC modülünden aldığın gerçek zaman etiketiyle microSD karta CSV formatında kaydediyoruz. OLED ekranda büyük font ile son sıcaklık değeri, nem yüzdesi, timestamp ve toplam kayıt sayısı canlı gösterilir. SD kart üzerindeki /temp_log.csv dosyası Excel/Google Sheets/Python pandas ile açılıp analiz edilebilir — sera monitörü, ev/oda sıcaklık takibi, laboratuvar veri toplama,
Diğer yazılar
BlueGrays uygulaması
Bu devreyi telefonunda adım adım kur
Devre şeması, kod ve parça listesi tek ekranda. 200'den fazla Arduino, ESP32 ve Pico projesi seni bekliyor.
Telefonunla tara
Kamerayı koda tut; telefonunun uygulama mağazası açılır.
ya da mağazada aç

