Sprint: Kod, Prova ve İyileştir
Prova neden gerekir? (9 dk)
Geçen derste robotunun bütün parçalarını tek koda topladın. Sürüyor, mekanizması ya da gripper'ı çalışıyor, ekrana durum yazdırıyor. Yani robotun hazır. Peki sen hazır mısın?
Bir pilot uçağa binmeden önce görevi yerde baştan sona prova eder: hangi anda hangi düğmeye basacağını sırayla dener. Bir basketbolcu maçtan önce aynı atışı defalarca tekrarlar. İkisi de yeni bir şey öğrenmez; bildiklerini akıcı hale getirir. Bu ders tam olarak bu: yeni komut yok, sadece görevi o kadar çok prova edeceksin ki robotun her hareketi düşünmeden gelecek.
Kanca videosundaki takıma bak. İlk denemede robot kötü olduğu için değil, sürücü hangi tuşun yükü aldığını hatırlamadığı için başarısız oldu. Sınıfça tek soru: sürücü, robotun bir turdaki her hareketini şu an ezbere sayabilir mi? Sayamıyorsa bu dersin sonunda sayabilecek.
Eşle ve prova et (20 dk)
İşin iki bölümü var: önce her hareketi bir tuşa eşle, sonra görevi baştan sona prova et.
1. Tuş haritasını çıkar
Robotun bir tur boyunca şunları yapar: başlangıçtan çık, yükü al, hedefe taşı, bırak, park et. Şimdi bu hareketlerin her birini bir kontrole bağla. Önce tahmin et: hangi hareket hangi tuşta olmalı? Sürücünün eli karışmasın diye sürüş çubuklarda, mekanizma tuşlarda durur. Takımınla şu tabloyu kağıda doldurun, sonra kodunuzdakiyle karşılaştırın:
| Görev hareketi | Kontrol | Kodda karşılığı |
|---|---|---|
| İleri / geri git | Sol çubuk yukarı / aşağı | js.getLeftY() |
| Sağa / sola dön | Sağ çubuk sağa / sola | js.getRightX() |
| Yükü al (mekanizmayı ileri sar) | RB tuşu | js.getRB() |
| Yükü bırak (mekanizmayı geri sar) | LB tuşu | js.getLB() |
Gripper'lı robotun varsa alma/bırakma satırları js.getA() (kapat) ve js.getB() (aç) olur. Kodunda bu eşleme zaten teleopLoop içinde duruyor; şimdi ona bilerek bak ve haritanla birebir aynı mı diye kontrol et:
void teleopLoop() {
auto js = probot::io::joystick_api::makeDefault();
// surus: sol cubuk ileri/geri, sag cubuk saga/sola
float ileri = js.getLeftY();
float donus = js.getRightX();
surSasi(ileri, donus);
// mekanizma: RB yuku al, LB yuku birak, ikisi de basili degilse dur
if (js.getRB()) surMotor(MEK_RPWM, MEK_LPWM, 0.6f);
else if (js.getLB()) surMotor(MEK_RPWM, MEK_LPWM, -0.6f);
else surMotor(MEK_RPWM, MEK_LPWM, 0.0f);
// durum panosu: surucu ne yaptigini ekrandan gorur
probot::clearTelemetry();
probot::printf("ileri: %.2f donus: %.2f\n", ileri, donus);
if (js.getRB()) probot::println("mekanizma: yukluyor");
else if (js.getLB()) probot::println("mekanizma: birakiyor");
else probot::println("mekanizma: bekliyor");
delay(20);
}
2. Görevi baştan sona prova et
Şimdi robotu başlangıç karesine koy, telefonu bağla, Init ve Start'a bas. Tahmin et: bir tam tur sizce kaç saniye sürer? Sayıyı kağıda yaz. Sonra kronometreyi başlat ve görevi baştan sona bir kez sür: çık, al, taşı, bırak, park et.
Bu ilk provada tek işin akışı görmek. Takım şöyle çalışsın: bir kişi sürer, bir kişi "şimdi RB", "biraz sola" diye gözcülük eder, bir kişi de nerede takıldığınızı not eder. En önemli iş bu not: robot nerede duraksadı, hangi hareket beceriksizce oldu, hangi tuşa yanlış basıldı? Süreyi ve takıldığın yeri yaz.
Görev bitince tahmininle gerçek süreyi karşılaştır. Çoğu takımın ilk provası tahmininden uzun sürer ve en az bir yerde takılır. Bu normaldir; o takılma senin bir sonraki bölümde düzelteceğin şeydir.
Kavram: kontrol eşlemesi ve iterasyon (7 dk)
Az önce yaptığın iki şeyin adı var.
Birincisi kontrol eşlemesi: her görev hareketini belli bir çubuğa ya da tuşa bağlamak. İyi bir eşleme sürücünün elini rahatlatır; kötü bir eşlemede sürücü doğru tuşu ararken robot yanlış yere gider. Kod aynı olsa bile hangi hareketi hangi tuşa koyduğun görevin ne kadar akıcı geçtiğini belirler. Profesyonel takımlar bu haritayı saatlerce tartışır.
İkincisi ve bu dersin asıl fikri: iterasyon. İterasyon "dene, gözle, bir şeyi değiştir, tekrar dene" döngüsüdür. Mühendis işi ilk seferde mükemmel yapmaya çalışmaz; çalışan bir şeyi alır, bir denemede nerede aksadığını görür, tek bir şeyi düzeltir ve yeniden dener. Her tur biraz daha iyi olur. Senin ilk provan ile ikinci proban arasındaki fark yeni bir parça değil, bir iterasyon turudur.
Buradaki altın kural: bir turda tek bir şey değiştir. İki üç şeyi birden değiştirirsen, robot iyileştiğinde hangi değişikliğin işe yaradığını bilemezsin.
Otonom bonus ve bir iyileştirme (15 dk)
Şimdi iki iş var. Önce görevin bir parçasını robota tek başına yaptır, sonra provandaki takılmalardan birini seçip düzelt.
Otonom bonus rutini
Otonom, görevin başında çalışır. Driver Station'da otonom açıkken Start'a basınca robot ilk 30 saniyede kumandaya hiç dokunmadan kendi başına iş yapar; süre bitince kumandayı sen alırsın. Bu yüzden otonoma en doğal parça görevin ilk adımıdır: başlangıç karesinden çıkıp yüke doğru ilerlemek. Otonom kodun, autonomousLoop içinde bir faz makinesiyle çalışır. Fazları önceki modülden tanıyorsun; burada yeni bir şey yok:
int faz = 0;
unsigned long fazBasi = 0;
void autonomousInit() {
faz = 0; // her calismada bastan basla
fazBasi = millis(); // onceki calismadan kalan degeri temizle
}
void autonomousLoop() {
unsigned long gecen = millis() - fazBasi;
if (faz == 0) { // ~2 saniye ileri git (baslangictan cik)
surSasi(0.6f, 0.0f);
if (gecen > 2000) { faz = 1; fazBasi = millis(); }
} else if (faz == 1) { // ~0.8 saniye don (yuke hizalan)
surSasi(0.0f, -0.5f);
if (gecen > 800) { faz = 2; fazBasi = millis(); }
} else { // dur
surSasi(0.0f, 0.0f);
}
delay(20);
}
Bu rutin bir tahmindir: "0.6 güçte ileri gidince 2 saniyede yüke yaklaşırım" dedin. Gerçekte kaç saniye gerektiğini ölçerek bulursun. Robotu başlangıç karesine koy, süreyi dene, kısa kalırsa 2000'i büyüt, uzun giderse küçült. Bu sayılar millisaniyedir. Dikkat: autonomousLoop içine delay(2000) gibi uzun bir bekleme koyma; loop iki saniye kilitlenirse güvenlik devreye girer ve robot durur. Beklemeyi hep millis() farkıyla say, yukarıdaki gibi.
Dürüst ol: bu yöntem her seferinde birebir aynı olmaz. Pil zayıfladıkça robot daha az gider, zemin değişince kayar, her fazın küçük sapması bir sonrakine eklenir. Otonomun görevi mükemmel olmak değil, kumanda olmadan işin bir parçasını götürmektir.
Bir iyileştirme seç ve uygula
Provada tuttuğun nota dön. Orada birden çok takılma olabilir: robot dönüşte fazla savruluyor, mekanizma yükü tam kavramıyor, sürücü LB ile RB'yi karıştırıyor, otonom park karesini ıskalıyor. Bir tanesini seç ve sadece onu düzelt. Örnekler:
- Dönüş çok sert:
surSasi'ye gidendonusdeğerini çubuğun yarısıyla çarp (koddadonus * 0.6fgibi) ki robot daha yumuşak dönsün. - Mekanizma yükü zor alıyor: RB satırındaki
0.6fgücünü biraz artır (0.75f), ama uçta zorlama. - Otonom kısa/uzun: faz sürelerini ölçtüğün değere göre değiştir.
Değişikliği yap, aynı görevi tekrar prova et ve süreyi yeniden tut. İkinci süre birinciden iyi mi? İyiyse iterasyon işe yaradı. Değilse değişikliği geri al ve başka bir şeyi dene. Tek turda tek değişiklik; kural bu.
Kendini kontrol et (6 dk)
Aşağıdakileri takımınla cevapla:
- Robotunun bir turdaki her hareketini, sıra ve tuşuyla, ezbere sayabiliyor musun?
- İlk provanla ikinci proban arasında süre farkı ne oldu? Farkı hangi tek değişiklik yaptı?
- Otonom rutinindeki bir faz süresini neye göre değiştirdin: tahminle mi, ölçerek mi?
autonomousLoopiçine nedendelay(2000)koymuyoruz?
Günlük hayat bağı: Pilotlar, cerrahlar, dansçılar, oyun geliştiricileri hepsi aynı işi yapar: çalışan bir şeyi alıp defalarca prova eder, her turda tek bir şeyi düzeltir. Buna iterasyon denir ve bir işi iyi yapmanın neredeyse tek yoludur. Senin bugün robotla yaptığın şey, bir mühendisin her gün yaptığı şeyin aynısı.
Erken bitirene ek görev
- Süre avı: Görevi üç kez üst üste prova et ve her turda tek bir şey değiştir. Üç süreyi kağıda yaz; en iyi turunda ne değiştirmiştin?
- Gözcü senaryosu: Sürücünün gözlerini kapamasını sağla ve görevi sadece gözcünün "ileri, dur, RB, sola" komutlarıyla sürmeyi dene. Tuş haritanız gerçekten net mi anlarsın.
- Otonomu uzat: Otonom rutinine bir faz daha ekle; örneğin yüke vardıktan sonra mekanizmayı kısa bir süre çalıştırıp yükü almayı da otonoma yaptır.