Yazılım B: düz koda ilk adım
Bloktan yazıya (10 dk)
Geçen ders robotu ilk kez sürdün, üstelik tek satır yazı yazmadan. Blokları sürükledin, motorları tanımladın, joystick'i motora bağladın ve arcade bloğuyla robotu ortada döndürdün. Bu ders aynı işi yapacak, ama bu kez blok yok; her şeyi yazıyla söyleyeceksin.
Neden? Çünkü blok, aslında senin yerine yazılan koddur. Sürüklediğin her blok, arka planda bir ya da birkaç satır metne çevrilir ve ESP32'ye o metin yüklenir. Blok, o metni senden gizler. Bu ders o perdeyi kaldırıyor: hangi bloğun hangi satıra karşılık geldiğini yan yana göreceksin.
Peki blok çalışıyorken neden yazıya geçiyoruz? Çünkü yazı sana daha çok kontrol verir. Blok kutusunun sunduğu seçeneklerle sınırlısın; yazıda ise istediğin satırı istediğin yere koyabilir, kendi kuralını ekleyebilirsin. Bu ders bittiğinde robota "RB'ye basılıyken yavaşla" gibi, hazır blok olarak bulunmayan bir davranışı sen ekleyeceksin. Blok bir başlangıç rampasıdır; yazı ise robotun tüm dilini konuşmaktır.
Başlamadan bir tahmin yürüt: sence Blocks'taki "motor tanımla" bloğunda seçtiğin 16 ve 17 numaralı pinler, yazıya döndüğünde nereye gider? Bir arkadaşınla konuş, sonra kodda ararız.
Hazır kodu yükle ve sür (20 dk)
Önce çalışan bütünü göreceğiz, sonra parçalayacağız. Aşağıdaki kod, geçen ders blokla kurduğun sürüşün tam metin karşılığı. Şimdilik anlamadığın satırlar olacak; sorun değil, önce çalıştığını görelim. Robot askıda, tekerler havada olsun.
Kodu Arduino IDE'ye olduğu gibi yapıştır ve yükle:
#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 motorun iki sinyal pini
const int SAG_RPWM = 18, SAG_LPWM = 19; // sag motorun iki sinyal pini
// 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.getLeftY();
float donus = js.getRightX();
surMotor(SOL_RPWM, SOL_LPWM, ileri + donus);
surMotor(SAG_RPWM, SAG_LPWM, ileri - donus);
delay(20);
}
void autonomousInit() {}
void autonomousLoop() { delay(20); }
Yüklemeden önce bir tahmin yürüt: sol çubuğu tam ileri ittiğinde iki teker de aynı yöne mi döner, ters yönlere mi? Sağ çubuğu ittiğinde ne beklersin? Tahminini aklında tut, birazdan sınayacağız.
Bağlan ve sür. Telefonu robotun açtığı RobotAdi ağına bağla. Tarayıcıya http://192.168.4.1 yaz (https değil). Driver Station açılınca kumandayı telefona bağla ve herhangi bir tuşuna bas; tarayıcı kumandayı ancak bir tuşa basınca tanır. Sonra Init'e, ardından Start'a bas. Sol çubuk ileri geri, sağ çubuk dönüş. Tekerler dönüyorsa robotun yazılımı çalışıyor, tebrikler.
Şimdi tahminini sına. Sol çubuğu ileri it: iki teker de aynı yöne dönüp robotu ileri götürür. Sağ çubuğu it: bir taraf ileri, öbür taraf geri döner ve robot olduğu yerde döner. Diferansiyel sürüşün mantığını gövdede görüyorsun, birazdan aynı mantığı kodda bulacağız.
Şimdi bir şeyi dene ve gözle: Start'a bastıktan sonra Stop'a bas. Tekerler duruyor mu? Duruyorsa, bunu sağlayan bir satır var; birazdan onu bulacağız.
Her blok bir satır (7 dk)
Robot çalıştı. Şimdi kodun haritasını çıkaralım. İşin güzel yanı, buradaki her parçayı geçen ders zaten blokla yaptın. Karşılıkları şöyle:
| Blocks'ta ne yaptın | Koddaki karşılığı |
|---|---|
| Robot kurulum bloğu | void robotInit() içi (bir kez çalışır) |
| Motor tanımla, pin 16 ve 17 seç | const int SOL_RPWM = 16, SOL_LPWM = 17; |
| Teleop loop bloğu | void teleopLoop() içi (saniyede ~50 kez) |
| Joystick ekseni bloğu | js.getLeftY() ve js.getRightX() |
| Arcade sürüş bloğu | ileri + donus ve ileri - donus satırları |
| Motor durdur bloğu | surMotor(..., 0) |
Tahminin doğru çıktı mı? Bloktaki 16 ve 17 pinleri, kodda en üstteki const int satırına gitti. const int, "bu bir sabit sayıdır, değişmez" demektir; pin numaralarını tek yerde tutar ki gerekince kolayca bulasın.
Dört bölgeyi tanıyalım:
- WiFi satırları (ilk üç): Robotun açtığı ağın adını ve şifresini belirler.
#includesatırından önce yazılmak zorundadır, çünkü kütüphane bu değerleri en başta okur. - Hook'lar: probot'ta
setup()veloop()yazılmaz; altı fonksiyon tanımlanır.robotInitInit'te bir kez,teleopLoopsürüş boyunca saniyede yaklaşık 50 kez çalışır.robotEndise Stop'ta çalışır ve iki motoru da durdurur. Az önce Stop'ta tekerlerin durmasını sağlayan satır buydu; bu satır olmasa robot Stop'tan sonra dönmeye devam ederdi. - surMotor: Hazır bir kalıp. Tek motora "şu hızda dön" demenin kısa yolu;
-1geri,0dur,+1tam ileri. İçindekiconstrain, sen ne yazarsan yaz motora-1ile+1dışında bir değer gitmesini engeller, yani bir hata yapsan bile motoru güvende tutar. Nasıl çalıştığını şimdilik açmana gerek yok, sadece kullan. - Sürüş satırları:
ileri + donussol tekere,ileri - donussağ tekere gider. Diferansiyel sürüşün tüm sırrı bu iki satırda: iki taraf arasındaki fark, robotu döndürür.
Kodu kendine göre ayarla (15 dk)
Artık kodu tanıyorsun. Şimdi üstünde bilinçli değişiklikler yapacaksın. Her görevden sonra yükle, dene, ne değiştiğini gözle. Bozmaktan korkma; yukarıdaki kod her zaman burada.
- Robotuna isim ver.
PROBOT_WIFI_AP_SSIDiçindeki"RobotAdi"yazısını kendi robot adınla değiştir. Yükle. Telefonun WiFi listesinde yeni adı gör. Yeni ağa bağlanıp tekrar sür. - Hızı yarıya indir.
teleopLoopiçindeki iki değer okuma satırını şöyle yap:
Robot artık en fazla yarım güçte. Yeni sürücü için birebir.float ileri = js.getLeftY() * 0.5f; float donus = js.getRightX() * 0.5f;0.5fyerine0.25fyazsan ne olurdu, tahmin et, sonra dene. - Tank kontrolüne geç. Arcade'de tek çubuk yönü, tek çubuk dönüşü verir. Tank'ta ise her çubuk kendi tarafını sürer. Sürüş satırlarını şununla değiştir:
İki çubuk, iki taraf. Hangisi sana daha doğal geldi, arcade mi tank mı?float solHiz = js.getLeftY(); float sagHiz = js.getRightY(); surMotor(SOL_RPWM, SOL_LPWM, solHiz); surMotor(SAG_RPWM, SAG_LPWM, sagHiz); - Ters dönen motoru düzelt. Bir teker yanlış yöne dönüyorsa çözüm kodda. O motorun iki pin sabitini yer değiştir. Örneğin sağ motor tersse:
İleri sinyali artık öbür pine gider, motor ters yöne döner. Kabloya dokunmadan yönü düzelttin.const int SAG_RPWM = 19, SAG_LPWM = 18; // 18 ve 19 yer degistirdi
Küçük bir ekleme: yavaş mod butonu. Şimdi hazır koda kendin bir özellik katacaksın. Hedef: RB butonuna basılı tutunca robot yarım hızda sürülsün, bırakınca normale dönsün. Tek bir if ve bir çarpan yeter. teleopLoop'un başına şunu ekle:
float carpan = 1.0f;
if (js.getRB()) carpan = 0.5f;
float ileri = js.getLeftY() * carpan;
float donus = js.getRightX() * carpan;
js.getRB() buton basılıysa true döner; o an çarpan 0.5 olur ve iki eksen de yarıya iner. Düz koridorda RB'li ve RB'siz sürüşün farkını gör. Dar bir yerde yavaş mod ne kadar işine yarıyor, dene.
Ders sonu kontrolü (7 dk)
Kısa bir öz kontrol. Cevabını kendi cümlelerinle ver:
- Hazır kodu yükledin ve robotu Driver Station'dan sürdün mü?
- En az üç değiştirme görevini yaptın mı (isim, hız ve bir tane daha)?
- Yavaş mod eklemesi çalışıyor mu?
- "robotEnd motorları neden durdurur?" sorusunun cevabı hazır mı?
- Arcade satırı ile tank satırı arasındaki farkı bir cümleyle söyleyebiliyor musun?
Günlük hayat bağı. Telefon uygulamalarındaki "sürükle bırak" ekranlar da tıpkı Blocks gibi arka planda kod üretir. Bugün yaptığın şey, o perdenin arkasına geçmek: bir aracın nasıl çalıştığını görmek yerine, ona ne yapacağını doğrudan söylemek. Bir kez metni gördükten sonra, blokların içinde ne olduğunu artık tahmin edebilirsin.
Erken bitirdiysen
- Turbo modu. Bu, bir önceki yavaş mod görevinin tam tersidir. Varsayılan hızı 0.7 yap (çarpan = 0.7f), RB'ye basılıyken tam gaza geç (çarpan = 1.0f). Yani robot normalde sakin gider, RB'ye basınca hızlanır.
- Ölü bölge. Çubuğu bıraktığında robot hafifçe titriyorsa, çok küçük değerleri sıfıra yuvarla.
ileriiçin: değeri-0.1ile0.1arasındaysa0yap. Tek birifile çözülür; nasıl yazacağını düşün, sonra dene.