Rehberler · 13 dk okuma

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 Uno R3 kartı ve USB soketi
Arduino Uno: USB soketi hem kod yüklemek hem de Python ile seri haberleşmek için kullanılır; TX ve RX LED'leri veri akarken yanıp söner.

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:

AyarArduino tarafıPython tarafıDikkat
PortUSB kablosuyla kendiliğinden oluşurserial.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çeve8 veri biti, parite yok, 1 stop biti (8N1)pyserial varsayılanı da 8N1Genellikle değiştirmen gerekmez
Satır sonuSerial.println() sona \r\n eklerreadline() \n görene kadar okurPython'dan gönderirken \n eklemeyi unutma
Zaman aşımıSerial.setTimeout(), varsayılan 1000 mstimeout=1 (saniye)timeout=None ile readline() sonsuza kadar bekler

pyserial kurulumu (Windows, macOS, Linux)

  1. 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.
  2. 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.
  3. Kurulumu doğrula: python -c "import serial; print(serial.__version__)" komutu 3.5 gibi bir sürüm numarası yazmalı.
  4. Canlı grafik bölümü için matplotlib de gerekir: python -m pip install matplotlib.
  5. 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.
PyPI'de serial adında, seri portla hiçbir ilgisi olmayan başka bir paket vardır. pip install serial yazarsan kodun import serial satırını geçer ama ardından AttributeError: module 'serial' has no attribute 'Serial' hatası verir. Doğru paket pyserial'dir; yanlışını pip uninstall serial ile kaldırıp pyserial'ı yeniden kur. Aynı hata kendi dosyana serial.py adını verdiğinde de çıkar, çünkü Python kütüphane yerine senin dosyanı içe aktarı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.

CH340 USB-TTL dönüştürücü modülü
CH340 yongası: klon Arduino kartların çoğunda USB ile seri port arasındaki köprüyü bu yonga kurar; üretici kimliği (VID) 1A86'dır.
USB yongasıNerede bulunur?VID:PIDWindows'ta görünen adLinux port adı
ATmega16U2Orijinal Uno R3, Mega 25602341:0043 (Uno)Arduino Uno (COMx)/dev/ttyACM0
CH340Klon Uno, Nano ve Mega kartlar1A86:7523USB-SERIAL CH340 (COMx)/dev/ttyUSB0
CP2102ESP32 DevKit, NodeMCU10C4:EA60Silicon Labs CP210x USB to UART Bridge (COMx)/dev/ttyUSB0
FT232REski Nano'lar, FTDI kablolar0403:6001USB Serial Port (COMx)/dev/ttyUSB0
RP2040 (yerleşik USB)MicroPython yüklü Raspberry Pi Pico2E8A:0005USB 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.

Python
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:

C++ (Arduino IDE)
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

Python
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.

CSV dosyası Excel'de tek sütun hâlinde açılıyorsa sebep bölge ayarıdır: Türkçe Windows'ta Excel liste ayırıcı olarak noktalı virgül, ondalık ayırıcı olarak virgül bekler. csv.writer(dosya, delimiter=";") kullan ve volt değerini str(round(volt, 3)).replace(".", ",") ile yaz ya da Excel'de Veri > Metinden/CSV'den seçeneğiyle içe aktarıp ayırıcıyı elle seç. Verileri Excel'e aktarmanın diğer yolları için Arduino Excel veri aktarma yazısına göz at.

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.

C++ (Arduino IDE)
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}
Python
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 OFF

Python 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ırArtısıEksisi
Tek değer512En basit biçim; Arduino Seri Çizici de doğrudan çizerBirden çok değer gönderince hangisinin ne olduğu karışır
CSV2573,512,23.5Kısa; Excel ve pandas doğrudan okurSütun sırası iki tarafta aynı kalmalı
Anahtar:değersicaklik:23.5,nem:41Okunaklı; Seri Çizici etiketleri gösterirDaha uzun, ayrıştırması biraz daha zahmetli
JSON{"t":23.5,"h":41}Python'da json.loads() ile tek satırda çözülürEn uzun biçim; Uno'nun sınırlı RAM'ini zorlar
İkili (binary)2 bayt: 0x02 0x00En 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 / saniyeNe zaman kullanılır?
960096080Yavaş sensörler, uzun kablolar, eski örnek kodlar
576005 760480Orta hızlı ölçümler
11520011 520960Canlı 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

Python
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.

10 µF kondansatör takılıyken Arduino IDE kod yükleyemez, çünkü yükleme de aynı otomatik reset devresine dayanır; yüklemeden önce kondansatörü çıkar. Python device reports readiness to read but returned no data hatası veriyorsa kart bağlantıyı kaybetmiştir ya da portu iki program aynı anda kullanıyordur. Kart çalışırken kendiliğinden resetleniyorsa sebep çoğu zaman güç yetersizliğidir; servo ve motorları USB'nin 5V'u yerine ayrı bir kaynaktan besle.

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?

Raspberry Pi Pico geliştirme kartı
Raspberry Pi Pico: RP2040'ın yerleşik USB birimi sayesinde ayrı bir USB-seri yongaya ihtiyaç duymaz; MicroPython yüklüyken bilgisayara doğrudan seri port olarak görünür.

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.

ÖzellikArduino + bilgisayarda PythonPico + MicroPython (tek başına)Pico + bilgisayarda Python
Python nerede çalışır?Yalnızca bilgisayarda; kartta C++ çalışırPico'nun içindeİki tarafta da: Pico'da MicroPython, bilgisayarda Python
Bilgisayar gerekir mi?Evet, veri bilgisayarda işlenirHayır, USB'den ya da pilden çalışırEvet
Kullanılabilen kütüphanelerpyserial, matplotlib, pandas, numpy, OpenCVmachine, time gibi sınırlı modüllerBilgisayardaki 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 resetUno, Nano ve Mega'da evetYokHayır
Ne zaman seçilir?Arduino zaten elindeyse, hazır kütüphaneler gerekiyorsaBağı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.

MicroPython
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 belirtiSebepÇö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 olabilirAynı 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.pypip 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 betikDiğ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ğilpython -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 yoksudo usermod -a -G dialout $USER, ardından oturumu kapatıp aç
Anlamsız karakterler ya da UnicodeDecodeErrorBaud 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üyorArduino satır sonu göndermiyor (println yerine print), port yanlış ya da kart hâlâ açılıyorprintln kullan, portu ve hızı kontrol et, timeout süresini artır
ValueError: invalid literal for int() with base 10Yarı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şlenmiyorPort açılınca Uno resetlendi, komut bootloader'a gittiHAZIR satırını bekle ya da portu açtıktan sonra 2 saniye bekle
Grafik gerçek zamanın gerisinde kalıyorHer karede tek satır okunuyor, veri tamponda birikiyorin_waiting döngüsüyle bütün satırları oku, gönderim sıklığını azalt
Betik açıkken Arduino'ya kod yüklenmiyorPython portu tutuyorBetiği Ctrl+C ile durdur, sonra yükle
Bir sorunla karşılaştığında önce Python'u devreden çıkar ve Arduino kodunu Seri Port Ekranı'nda aynı baud hızıyla dene. Satırlar orada düzgün akıyorsa sorun Python tarafındadır (port adı, hız, satır sonu ya da ayrıştırma); orada da bozuksa önce Arduino kodunu düzelt. Kod hiç yüklenmiyorsa Arduino kod yüklenmiyor rehberindeki adımları izle. Seri haberleşmenin donanım tarafını, yani TX, RX ve UART'ı merak ediyorsan UART seri haberleşme yazısına göz at.

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.

Tüm projeleri gör
Ldr İle Işık Şiddeti Okuma
#11Başlangıç

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

4.6(81)
139
HC-SR04 Mesafe Ölçme (Serial Ekran)
#27Başlangıç

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

4.6(46)
71
DHT11 İle Sıcaklık Ve Nem
#55Orta

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

4.7(47)
73
ESP32 LDR Modülü ile Işık Şiddeti Okuma
#113Başlangıç

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.

4.6(36)
55
2 Arduino Tek Yönlü Haberleşme
#57Orta
Premium

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

4.4(37)
50
2 Arduino Çift Yönlü Haberleşme
#58Orta
Premium

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

4.5(20)
26
Bluetooth İle Telefondan Led Yakma
#34Başlangıç
Premium

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

4.8(68)
89
ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)
#144İleri
Premium

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,

4.7(7)
12