MODÜL 06 DERS 4 / 5 · 60 DK

Hata avı: telemetriyle teşhis koy

Bu modül boyunca robotunun içindeki sayıları ekrana koymayı öğrendin. Çubuğun değerini gördün, kendi hız çarpanını ekrana yazdın, çubuğu bıraktığında değerin nasıl tam sıfıra oturduğunu izledin. Şimdi o beceriyi gerçek bir işe koşacaksın. Çünkü telemetrinin en güçlü olduğu an, bir şey ters gittiği andır.

Bugün öğretmenin sana bilerek bozulmuş üç kod verecek. Üçü de yüklenir, üçü de çalışır, ama üçü de yanlış davranır. Görevin onları tek tek tamir etmek değil önce; görevin teşhis koymak. Bir doktor gibi: önce ölç, sonra tedavi et.

Kanca: iki dakikada iki yanlış tahmin (10 dk)

🎬 VİDEO · kanca · 50 sn · öğrenci çubuğu ileri itiyor ama robot geri gidiyor; kodu rastgele iki kez değiştiriyor, olmuyor; sonra telemetri panelini açıyor, "ileri: 0.80" ama "sol motor: -0.40" görüyor ve tek satırda düzeltiyor

Videodaki öğrenciye dikkat et. Robotu ileri gitmiyor diye önce koda bakıp bir satırı tahminle değiştirdi. Olmadı. İkinci kez tahmin etti. Yine olmadı. İki değişiklik, iki yanlış tahmin, sıfır ilerleme. Sonra bir şey yaptı: koda bakmayı bıraktı, ekrana baktı. Panelde çubuğun değeri 0.80 yazıyordu, ama motora giden değer -0.40 idi. Artı girmiş, eksi çıkmış. Bunu görünce hangi satırı düzelteceğini saniyede anladı.

Sınıfa sor, cevaplasınlar:

Kesin cevabı şimdi vermiyoruz. Elin üç bozuk koda değince ikisini de kendin göreceksin. Aklında tek cümle kalsın: tahmin etme, ölç.

Ana etkinlik: üç bozuk kodu avla (20 dk)

Öğretmenin sana üç dosya verecek: Bozuk 1, Bozuk 2, Bozuk 3. Üçünün de içinde tanıdığın diferansiyel sürüş kodu ve bir de telemetri paneli var. Panel her turda önce ekranı temizler, sonra dört değeri yazar: çubuğun ileri değeri, çubuğun dönüş değeri, sol motora giden değer ve sağ motora giden değer.

İşte üç dosyanın da ortak telemetri bloğu; robotun içinde ne olup bittiğini sana bu dört satır anlatacak:

  probot::clearTelemetry();                          // once ekrani temizle
  probot::printf("solY (ileri cubugu): %.2f\n", ileri);
  probot::printf("sagX (donus cubugu): %.2f\n", donus);
  probot::printf("sol motor: %.2f\n", sol);
  probot::printf("sag motor: %.2f\n", sag);

%.2f, o değeri iki ondalık basamakla yazar (örneğin 0.80). clearTelemetry her turun başında ekranı siler; yoksa panel eski yazılarla dolar. Bu iki kalıbı geçen derslerde kurdun; bugün onları bir teşhis cihazı gibi kullanıyorsun.

İşte Bozuk 1'in tamamı. Yükle, robotu yükseltiye koy (tekerlekler boşta dönsün), bağlan ve dene:

#define PROBOT_WIFI_AP_SSID     "RobotAdi"
#define PROBOT_WIFI_AP_PASSWORD "sifre1234"
#define PROBOT_WIFI_AP_CHANNEL  1
#include <probot.h>

const int SOL_RPWM = 16, SOL_LPWM = 17;   // sol surus motoru
const int SAG_RPWM = 18, SAG_LPWM = 19;   // sag surus motoru
const float HIZ_CARPANI = 0.5f;           // hizi yariya indiren carpan

// hazir yardimci: motoru hizina gore surer (-1 geri, 0 dur, +1 ileri)
void surMotor(int rpwm, int lpwm, float hiz) {
  hiz = constrain(hiz, -1.0f, 1.0f);
  if (hiz > 0) { analogWrite(rpwm, (int)(hiz * 255));  analogWrite(lpwm, 0); }
  else         { analogWrite(rpwm, 0);  analogWrite(lpwm, (int)(-hiz * 255)); }
}

void robotInit() {
  pinMode(SOL_RPWM, OUTPUT); pinMode(SOL_LPWM, OUTPUT);
  pinMode(SAG_RPWM, OUTPUT); pinMode(SAG_LPWM, OUTPUT);
}
void robotEnd() {
  surMotor(SOL_RPWM, SOL_LPWM, 0); surMotor(SAG_RPWM, SAG_LPWM, 0);
}
void teleopInit() {}
void teleopLoop() {
  auto js = probot::io::joystick_api::makeDefault();

  float ileri = js.getLeftX();          // ileri hareketi buradan okuyor
  float donus = js.getRightX();
  float sol = (ileri + donus) * HIZ_CARPANI;
  float sag = (ileri - donus) * HIZ_CARPANI;

  surMotor(SOL_RPWM, SOL_LPWM, sol);
  surMotor(SAG_RPWM, SAG_LPWM, sag);

  probot::clearTelemetry();
  probot::printf("solY (ileri cubugu): %.2f\n", ileri);
  probot::printf("sagX (donus cubugu): %.2f\n", donus);
  probot::printf("sol motor: %.2f\n", sol);
  probot::printf("sag motor: %.2f\n", sag);

  delay(20);
}
void autonomousInit() {}
void autonomousLoop() { delay(20); }
🎬 VİDEO · ekran-kaydi · 150 sn · Bozuk 1 yüklüyken telemetri paneli yakın çekim; çubuk ileri itilince "solY" değişiyor ama motor değerleri sıfırda kalıyor, çubuk yana itilince canlanıyor; sonra tek satır düzeltilip panelin düzelmesi

Belirti: Sol çubuğu ileri itiyorsun, robot kımıldamıyor. Ama çubuğu yana ittiğinde motorlar canlanıyor. Panele bak: çubuğu ileri iterken solY satırı 0.80 gösteriyor olabilir ama sol motor ve sag motor 0.00'da takılı. İleri çubuğunun değeri motorlara hiç ulaşmıyor. İşte teşhis: kod ileri hareketi yanlış eksenden okuyor. Aradaki fark bu üç bozuk kodun her birinde farklı bir iz bırakır.

Şimdi öğretmenin sana Bozuk 2 ve Bozuk 3'ü de versin. İkisi de yukarıdaki kodun neredeyse aynısı; yalnızca teleopLoop'un ilk üç satırı farklı. Diğer her şey (telemetri paneli dahil) birebir aynı. İşte o farklı satırlar:

Bozuk 2 (bu üç satır dışında her şey aynı):

  float ileri = -js.getLeftY();         // ileri degeri boyle hesaplaniyor
  float donus = js.getRightX();
  float sol = (ileri + donus) * HIZ_CARPANI;

Bozuk 3 (bu üç satır dışında her şey aynı):

  float ileri = js.getLeftY();
  float donus = js.getRightX();
  float sag = (ileri - donus);          // sag motora giden deger boyle hesaplaniyor

Üçünü de sırayla yükle, sür ve paneli oku. Cevabı koda bakarak tahmin etme; önce robotu sür, panelde değerin nasıl davrandığını gör, sonra karar ver. Şu tabloyu kağıda çiz ve doldur:

Bozuk kodRobot ne yapıyor?Panelde ne görüyorsun?Teşhis (sorun ne?)
Bozuk 1
Bozuk 2
Bozuk 3

İpucu olarak her birinde ne arayacağını söyleyeyim, gerisini panel anlatır: Bozuk 1'de çubuğun değeri motorlara ulaşıyor mu? Bozuk 2'de çubuğu ileri itince motor değeri artı mı çıkıyor, eksi mi? Bozuk 3'te robotu dümdüz ileri sürerken (dönüş yokken) sol motor ile sag motor eşit mi?

Kavram köprüsü: her hatanın bir izi vardır (7 dk)

Üç bozuk kodu avladın. Şimdi ne yaptığının adını koyalım. Aslında her seferinde aynı yöntemi kullandın: robotun içindeki bir sayıyı görünür yaptın ve onu beklediğin değerle karşılaştırdın. Beklentiyle gerçek arasındaki fark, sana hatanın yerini gösterdi. Buna teşhis denir ve üç hatanın üçü de panelde farklı bir iz bıraktı:

Gördüğün gibi robotun garip davranışı belirsiz bir "çalışmıyor" değildi. Her birinin panelde net bir parmak izi vardı. Kod satırlarını rastgele değiştirip denemek yerine, hangi değerin yanlış olduğunu ölçtün ve doğruca oraya gittin. Bir mühendisin sorun giderme yolu budur: tahmin etme, ölç.

Uygulama: düzelt, sonra bir tuzak kur (15 dk)

İki bölüm. İlkini herkes yapar, ikincisi bir arkadaşınla.

1) Üçünü de düzelt (7 dk). Şimdi teşhisi tedaviye çevir. Her bozuk kodda tek bir şeyi düzelt, yükle ve panelde düzeldiğini doğrula:

Her düzeltmeden sonra koda değil panele bak: değer artık beklediğin gibi mi? Düzelttiğini gözünle görmeden bir sonrakine geçme.

2) Bir arkadaşına tuzak kur (8 dk). Şimdi rolü değiştir. Çalışan kodunu al ve içine kendin küçük bir hata koy: bir işareti çevir, bir ekseni değiştir, ya da bir çarpanı sil. Sonra kodu bir arkadaşına ver, ama ona ne bozduğunu söyleme. O da telemetri panelini kullanarak hatanı avlasın. Sonra sıra sende: onun tuzağını sen avla.

Bunu yaparken şunu fark edeceksin: hatayı gizlemek kolay, ama panel onu ele veriyor. İyi bir telemetri paneli, kodun içinde saklanan hatayı dışarı çıkarır. Bir arkadaşın bulması ne kadar hızlı olduysa, panelin o kadar iyi demektir.

Pekiştirme ve değerlendirme (6 dk)

Kodu kapat, kağıda ya da sözlü cevapla:

Günlük hayat bağı: bir doktor ateşin var mı diye yüzüne bakıp tahmin etmez; termometre koyar, ölçer, sayıya bakar. Bir araba ustası motoru rastgele sökmez; bir cihaz bağlar, sensörlerin değerini okur ve arızayı sayıdan bulur. Sen de bugün aynısını yaptın. Robotunun telemetri paneli, senin termometren ve arıza cihazın. Bir şey ters gittiğinde artık tahmin etmene gerek yok; robota kendi değerini sorup cevabı okuyabiliyorsun.

Erken bitirene ek görev: kendi uyarı satırın (opsiyonel)

İyi bir teşhis paneli sadece sayıları göstermez; bir şey ters gidince seni uyarır. Kendi uyarını ekle.

Fikir şu: robotu dümdüz sürerken iki motor eşit olmalı. Farkı hesaplayıp panele yaz, üstelik fark büyükse bir uyarı bas. Telemetri bloğunun sonuna şunu ekle:

  float fark = sol - sag;                        // iki motor arasindaki fark
  probot::printf("fark: %.2f\n", fark);
  if (fark > 0.05f || fark < -0.05f) {
    probot::println(">> DIKKAT: motorlar esit degil");
  }
}

Yükle ve dene. Robotu dümdüz sürerken (dönüş yokken) fark neredeyse sıfır olmalı ve uyarı çıkmamalı. Şimdi bilerek Bozuk 3'ün hatasını geri koy: bir motorun çarpanını sil. Panelde fark büyür ve >> DIKKAT satırı belirir. Kendi kurduğun panel, kendi hatanı sana bağırarak söyler.

Meydan okuma: 0.05f eşiğini neden seçtik? Çok küçük yaparsan (0.001f) ne olur, çok büyük yaparsan (0.5f) ne olur? Bir arkadaşınla tartış: bir uyarı ne zaman gereğinden çok bağırır, ne zaman gereken uyarıyı kaçırır?