MODÜL 06 DERS 2 / 5 · 60 DK

Joystick değerlerini izle

Şimdiye kadar robotun sana hep hareketle cevap verdi: çubuğu ittin, tekerlek döndü. Ama arada görünmeyen bir şey var. Çubukla motor arasında bir sayı akıyor. Kod o sayıyı okuyor, motora çeviriyor, sen yalnızca sonucu görüyorsun. Bu derste o görünmeyen sayıyı ekrana çıkaracaksın. Robot ne "hissediyorsa" onu kendi gözünle okuyacaksın; ve çubukla oynarken hiç fark etmediğin bir sürprizi yakalayacaksın.

Kanca: robotun gizli sayaçları (10 dk)

🎬 VİDEO · kanca · 45 sn · telemetri panelinde "sol Y" sayısı çubuk itildikçe 0.00'dan 1.00'e tırmanıyor, çubuk bırakılınca bir anda 0.00'a düşüyor

Videoda sürücü çubuğa hiç dokunmuyor. Ekrandaki sayı 0.00. Çubuğu azıcık itiyor: 0.34. Biraz daha: 0.71. Sonuna kadar: 1.00. Bırakıyor: yine 0.00. Robot hareket etmeden önce kafasının içinde işte bu sayı dönüyor.

Sınıfa sor, önce tahmin etsinler:

Kesin cevabı şimdi vermiyoruz. Birazdan bu sayıyı kendi ekranına basacaksın ve tahminlerini teker teker sınayacaksın. İkinci soruyu aklında tut; bu dersin en şaşırtıcı anı orada saklı.

Ana etkinlik: değerleri ekrana bas (20 dk)

Sıfırdan kod yazmayacaksın. Elinde M02'den kalan, çalışan sürüş kodun var. Ona üç yeni satır ekleyeceğiz; sürüş satırlarına hiç dokunmuyoruz.

Robotun sana yazı gönderebileceği bir yeri var: Driver Station ekranının sağ paneli. Oraya yazı göndermek için üç hazır komut kullanacağız:

İşte teleopLoop'a eklenen üç satır. Yeni satırların yanına yorum koydum; gerisi tanıdığın M02 kodu:

#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

// 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 solY = js.getLeftY();
  float sagX = js.getRightX();

  // surus: M02'den aynen kaldi
  surMotor(SOL_RPWM, SOL_LPWM, solY + sagX);
  surMotor(SAG_RPWM, SAG_LPWM, solY - sagX);

  // YENI: degerleri ekrana bas
  probot::clearTelemetry();
  probot::printf("sol Y: %.2f\n", solY);
  probot::printf("sag X: %.2f\n", sagX);

  delay(20);
}
void autonomousInit() {}
void autonomousLoop() { delay(20); }
🎬 VİDEO · ekran-kaydi · 150 sn · teleopLoop'a üç telemetri satırı ekleniyor, kod yükleniyor, panelde çubuk oynatılırken sayıların değişimi ve deadzone atlaması gösteriliyor

Kodu yükle. Robotu yükseltiye koy, tekerlekler serbest dönsün. Bağlantı her zamanki gibi: telefonu robotun WiFi ağına bağla, tarayıcıda http://192.168.4.1 adresini aç, kumandayı telefona bağlayıp bir tuşuna bas, sonra Init ve Start. Şimdi gözünü sağ paneldeki iki satıra dik.

Sırayla dene ve her seferinde önce tahmin et, sonra oku:

  1. Sol çubuğu yavaşça tam ileri it. sol Y kaça çıkıyor?
  2. Tam geri çek. Sayı artı mı kalıyor, eksi mi oluyor?
  3. Sağ çubuğu sağa-sola oynat. Bu sefer hangi satır değişiyor?

Şimdi asıl deney: deadzone'u gör. Sol çubuğu bırak, elini tamamen çek. sol Y ne yazıyor? Tam 0.00. Şimdi çubuğu çok az, milim milim it. Bir süre sayı hâlâ 0.00 kalır. İtmeye devam et; bir noktada sayı aniden 0.00'dan sıçrayıp 0.10 gibi bir değere atlar. Arada 0.03, 0.05 gibi değerleri hiç görmezsin. Bu atlamayı gördüğün an durup arkadaşına göster; birazdan sebebini konuşacağız.

Kavram köprüsü: printf, biçim ve deadzone (7 dk)

Az önce üç yeni fikri çalışır halde gördün. Şimdi adlarını koyalım.

printf, kalıba sayı yerleştirir. printf sözcüğü "print formatted", yani "biçimli yazdır" demektir. Ona bir yazı kalıbı verirsin, kalıbın içine bir işaret koyarsın, o işaretin yerine gerçek sayı geçer. "sol Y: %.2f\n" kalıbındaki %.2f, "buraya ondalık sayı gelecek" işaretidir. Sonundaki \n ise "alt satıra geç" demektir; onu koymazsan bütün satırlar yan yana yapışır.

%.2f sayının kaç basamak görüneceğini seçer. .2 kısmı "virgülden sonra iki basamak" der. Çubuk sana aslında 0.7134... gibi uzun bir sayı verir; %.2f bunu 0.71 diye kısaltıp gösterir, okuması kolaylaşsın diye. İki kardeş işaret daha var: %d bir tam sayıyı yazar (ondalık yok), %.2f ise ondalıklı sayıyı. Uygulama bölümünde %d'yi de kullanacaksın.

Deadzone: sıfır civarı ölü bölge. Çubuğu ittiğinde sayının bir türlü 0.00'dan kalkmamasının, sonra birden atlamasının sebebi şu: kumanda çubukları hiçbir zaman tam ortada durmaz, elini çektiğinde bile içinde ufak bir titreşim, 0.01-0.02 gibi bir gürültü kalır. Kütüphane bunu bilir ve 0.08'den küçük her değeri tam 0 sayar. Bu ölü bölgeye deadzone denir. Sayesinde robot, sen dokunmazken tek başına kıpırdamaz. Milim ittiğinde 0.00 görmenin, sonra eşiği geçince aniden sıçramanın sebebi bu eşiktir.

Her turda önce temizle. teleopLoop saniyede yaklaşık 50 kez döner. clearTelemetry olmasaydı her turda iki yeni satır eklenir, panel saniyeler içinde yüzlerce satırla dolup taşardı. Bu yüzden kural şu: her turda önce paneli temizle, sonra taze değerleri yaz.

Uygulama: hangi buton hangi isim? (15 dk)

Çubukların sana kayan bir sayı verdiğini gördün. Şimdi butonlara bakacaksın. Bir buton kayan sayı vermez; sana yalnız iki şey söyler: basılı (1) ya da değil (0). Bunu ekranda görmek için %d işaretini kullanacağız, çünkü buton değeri tam sayıdır.

teleopLoop'taki telemetri bölümünün altına şu iki satırı ekle:

  probot::printf("A:%d B:%d X:%d Y:%d\n", js.getA(), js.getB(), js.getX(), js.getY());
  probot::printf("RB:%d LB:%d\n", js.getRB(), js.getLB());

Yükle. Panelde şimdi bir de buton satırı var, hepsi 0. Bir tuşa bas: o tuşun sayısı 0'dan 1'e döner, bırakınca geri 0 olur.

İşte görevin. Kumandandaki tuşları teker teker bas ve ekranda hangi ismin 1 olduğunu gözle. Sonra aşağıdaki tabloyu doldur: her satırda, kumandanın üstündeki fiziksel tuşun yanına kodadaki ismini yaz. Farklı kumandalarda tuşların yeri değişebilir; bu tablo senin kumandanın haritasıdır.

Kumandadaki fiziksel tuşEkranda 1 olan isim
Sağ alttaki tuş
Sağdaki tuş
Soldaki tuş
Üstteki tuş
Sağ omuz tuşu
Sol omuz tuşu

Bu tabloyu doldurduğunda, bundan sonraki modüllerde "A tuşuna bas" dendiğinde parmağının nereye gideceğini bileceksin. Kodadaki getA, getRB gibi isimlerin kumandanda tam olarak neye denk geldiğini artık deneyle biliyorsun; tahminle değil.

Pekiştirme ve değerlendirme (6 dk)

Kısa öz-kontrol. Kodu kapat, kağıda ya da sözlü cevapla:

Günlük hayat bağı: bir arabanın gösterge paneli de aynı işi yapar. Motorun içinde dönen sayıları (hız, devir, sıcaklık) sürücünün göreceği biçimde ekrana basar. Sürücü motorun içini görmez; ama panele bakarak ne olup bittiğini anlar. Sen de az önce robotuna bir gösterge paneli taktın. Bir sonraki derste bu panel, bir sorunun nerede olduğunu bulmanın en güçlü aracı olacak.

Erken bitirene ek görev: kendi etiketini yaz (opsiyonel)

Şu an panelde ham eksen sayıları var. Bunları daha okunur yap. İki fikir dene:

  1. Türkçe etiket koy. printf kalıbındaki yazıyı değiştir; "sol Y: %.2f\n" yerine "ILERI-GERI: %.2f\n" yaz. Sayı aynı kalır, ama başlığı artık ne işe yaradığını anlatır. sag X satırını da "DONUS: %.2f\n" yap.
  2. Sol çubuğun yan eksenini de ekle. Şu an js.getLeftY() ve js.getRightX() var. Bir de js.getLeftX() diye üçüncü bir eksen var. Onu bir değişkene al ve panele bas:
       float solX = js.getLeftX();
       probot::printf("sol X: %.2f\n", solX);
    Bu ekseni sol çubuğu sağa-sola iterek dene. Aynı deadzone'u burada da görüyor musun?

Meydan okuma: Panelde tek bir satırda hem sol Y hem sag X değerini yan yana gösterebilir misin? Tek bir printf içine iki tane %.2f koyup iki değeri arka arkaya vererek dene. İpucu: "ileri:%.2f donus:%.2f\n" kalıbına iki değişkeni sırayla ver.