Görevler: robot tek başına parkuru geçsin
Bu modül boyunca robotuna adım adım kendi başına hareket etmeyi öğrettin. Otonom fazını açtın, hareketleri fazlara böldün, beklemeyi delay yerine geçen zamanı ölçerek kurdun, bir metrenin kaç saniye sürdüğünü ölçüp katsayıya çevirdin ve değişkenlerini her başta sıfırlayıp telemetriyle izledin. Bugün bunların hepsini tek bir işte birleştiriyorsun: robotun, sen ona hiç dokunmadan bir parkuru geçecek ve bir hedefte duracak. Bu ders bir sınav değil, bir usta günü. Yeni bir kavram yok; olanı en iyi ayarlayan kazanacak. Kural basit: bant parkurda robotu hedefe en yakın durduran kişi birinci olur. Üç deneme hakkın var ve her denemeden sonra kodunu düzeltebilirsin.
Kanca: kod aynı, sonuç neden farklı? (10 dk)
Videoyu dikkatle izle. Robot aynı, yazılım aynı, yol aynı. Kimse tek bir satır değiştirmedi, kimse kumandaya dokunmadı. Ama robot iki turda aynı yerde durmadı. İlk turda hedefi tam tutturdu, ikinci turda geride kaldı. Değişen tek şey pildi: ilk turda doluydu, ikincide yarıya inmişti.
Sınıfça bir dakika tartışın, önce tahmin edin:
- Kod hiç değişmediyse robot neden aynı mesafeyi gitmedi? Pilin gücü robotun ne kadar yol aldığını nasıl etkilemiş olabilir?
- Robot yolu "1.2 metre" diye mi ölçüyor, yoksa "bu güçte şu kadar saniye" diye mi? Bu ikisi aynı şey mi?
Kesin cevabı ana etkinlikten sonra koyacağız. Şimdilik şu kadarını aklında tut: senin robotun mesafeyi bir cetvelle ölçmüyor. Ne kadar ilerlediğini bilmiyor; sadece ne kadar süre motor çevirdiğini biliyor. Pil zayıfsa aynı sürede tekerlek daha yavaş döner, robot daha az yol alır. Bugün tam da bu yüzden üç deneme hakkın var: her turda robotunu o günün piline ve zeminine göre yeniden ayarlayacaksın.
Ana etkinlik: parkur yarışı, üç deneme (20 dk)
Önce sahayı kurun. Yere bantla basit bir parkur çizin: bir başlangıç çizgisi, düz bir yol, bir dönüş köşesi, sonra ikinci bir düz yol ve en sonda bir hedef çizgisi. Bütün robotlar aynı parkuru kullanır. Robotun görevi başlangıçtan çıkıp köşeyi dönmek ve burnunu hedef çizgisine olabildiğince yakın durdurmaktır. Çizgiyi geçmek de, çizgiye ulaşamamak da seni hedeften uzaklaştırır; amaç tam üstünde durmaktır.
Robotunda zaten kalibrasyon dersinden gelen otonom kodun var. Parkuru senin rotana göre fazlara dizersin. Kodun iskeleti şöyle görünür; sayılar senin parkuruna ve senin ölçtüğün katsayılara göre değişir:
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
// kalibrasyon dersinde KENDI olctugun katsayilar
const float SANIYE_PER_METRE = 2.40f; // 0.6 gucte 1 metre kac saniye surer
const float SANIYE_PER_DERECE = 0.012f; // 0.5 donuste 1 derece kac saniye surer
// parkurun senin olctugun degerleri
const float ILK_YOL = 1.20f; // baslangictan koseye kac metre
const float DONUS_ACI = 90.0f; // kosede kac derece donulecek
const float SON_YOL = 0.80f; // koseden hedefe kac metre
int faz = 0;
unsigned long fazBasi = 0;
void autonomousInit() {
faz = 0; // her baslangicta fazi sifirla
fazBasi = millis(); // ve zaman sayacini sifirla
}
void autonomousLoop() {
unsigned long gecen = millis() - fazBasi;
if (faz == 0) { // ilk duz yol
surSasi(0.6f, 0.0f);
if (gecen > (unsigned long)(ILK_YOL * SANIYE_PER_METRE * 1000)) {
faz = 1; fazBasi = millis();
}
} else if (faz == 1) { // kosede saga don
surSasi(0.0f, 0.5f);
if (gecen > (unsigned long)(DONUS_ACI * SANIYE_PER_DERECE * 1000)) {
faz = 2; fazBasi = millis();
}
} else if (faz == 2) { // ikinci duz yol
surSasi(0.6f, 0.0f);
if (gecen > (unsigned long)(SON_YOL * SANIYE_PER_METRE * 1000)) {
faz = 3; fazBasi = millis();
}
} else { // hedefte dur
surSasi(0.0f, 0.0f);
}
probot::clearTelemetry();
probot::printf("faz: %d\n", faz); // robot su an hangi adimda
probot::printf("gecen: %lu\n", gecen); // bu adimda kac ms gectiyi izle
delay(20);
}
Puan sistemini şimdi kur. Kâğıdının üstüne şu tabloyu çiz. Her denemeden sonra robotun burnunun hedef çizgisine kaç santim uzaklıkta durduğunu mezurayla ölç ve yaz. Küçük sayı iyidir; sıfır en iyisidir.
| Deneme | Hedefe kalan mesafe | Kısa mı, uzun mu durdu? | Ne değiştirdin? |
|---|---|---|---|
| 1. deneme | ... cm | (ilk denemede henüz bir şey değiştirmedin) | |
| 2. deneme | ... cm | ||
| 3. deneme | ... cm |
Denemeler şöyle işler. Her sürücü sırayla robotunu başlangıç çizgisine koyar, Driver Station'da otonomu açar ve Start'a basar. Robota hiç dokunmadan izlersiniz. Robot durunca burnunun hedefe uzaklığını ölçüp tabloya yazarsın. Sonra bilgisayarına dönüp bir sonraki denemeye hazırlanırsın: robot kısa kaldıysa SON_YOL ya da ILK_YOL değerini birazcık büyüt, çizgiyi geçtiyse birazcık küçült; köşede az döndüyse DONUS_ACI'yı artır, çok döndüyse azalt. Üç denemenin sonunda en yakın durduğun mesafe senin yarış puanındır. Sınıfça en küçük mesafeyi tutturan birinci olur.
Kavram köprüsü: robot yolu değil, süreyi sayar (7 dk)
Durup nefeslen. Robotunu ayarladın, şimdi bugün gördüğün şeyin adını koyalım.
Senin robotun açık döngü ile çalışıyor. Bu şu demek: robot bir komut verir ("0.6 güçte ileri çevir") ve sonucun ne olduğuna hiç bakmaz. Gerçekten bir metre gitti mi, yarım metre mi kaldı, tekerlek kaydı mı, bunu bilmez. Sadece senin ölçtüğün süre kadar motoru çevirir, sonra durur. Gözü yoktur; kör bir plan uygular. Bu yüzden kanca videosundaki robot pil zayıfken geride kaldı: aynı süre kadar çevirdi ama zayıf pil tekerleği daha yavaş döndürdü, o yüzden daha az yol aldı. Kod yanlış değildi; kodun dünyası değişmişti.
Bir şeyi daha adlandıralım: sapma birikir. İlk yolda robot birazcık sola kaçtıysa, köşeye zaten eğik gelir; dönüşten sonra bu eğiklik büyür ve ikinci yolun sonunda hedeften iyice şaşar. Her fazın küçük hatası bir sonrakine eklenir. Rota ne kadar uzunsa birikme o kadar büyük olur. İşte bu yüzden kısa parkurlar uzun parkurlardan daha güvenilirdir.
Şimdi kancadaki soruların cevabı net: robot mesafeyi metreyle değil, süreyle ölçüyor. Senin SANIYE_PER_METRE katsayın "bu pil, bu zemin, bu güçte bir metre şu kadar saniye" demek. Pil ya da zemin değişince o katsayı da değişir, ama kodun içindeki sayı aynı kalır; işte sapma buradan doğar. Dürüst ol: bu yöntem bir tahmindir. İyi bir tahmindir, ölçerek düzeltilebilir bir tahmindir, ama bir tahmindir. Robotlar bir gün tekerleğin gerçekten kaç tur döndüğünü sayan parçalarla bu tahmini gerçek ölçüme çevirir; sen şimdilik en iyi tahminciyi kuruyorsun ve onu her denemede biraz daha keskinleştiriyorsun.
Uygulama: rotaya bir iş ekle (15 dk)
Bir parkuru geçmek güzel, ama otonomun asıl gücü robotun tek başına bir iş yapmasıdır. Şimdi rotana bir görev fazı ekleyeceksin: robot hedefe varınca durmakla kalmasın, orada mekanizmasını çevirip küçük bir iş yapsın. Böylece bu modülde öğrendiğin otonomu, daha önceki modüllerden gelen sürüş ve mekanizmayla tek bir planda birleştirirsin.
Mekanizma motorun için pinleri ve mekanizma dersinden gelen kontrol satırını kullanırsın. Hedefte durduktan sonra gelen yeni bir faz, mekanizmayı bir süre çevirir ve sonra durdurur:
const int MEK_RPWM = 21, MEK_LPWM = 22; // mekanizma motorunun iki sinyal pini
// ... yukaridaki fazlar aynen durur, "hedefte dur" fazini boyle degistir:
} else if (faz == 3) { // hedefte once dur
surSasi(0.0f, 0.0f);
if (gecen > 500) { faz = 4; fazBasi = millis(); } // yarim saniye bekle
} else if (faz == 4) { // mekanizmayi cevir (isi yap)
surMotor(MEK_RPWM, MEK_LPWM, 0.6f);
if (gecen > 1500) { faz = 5; fazBasi = millis(); }
} else { // her seyi durdur
surSasi(0.0f, 0.0f);
surMotor(MEK_RPWM, MEK_LPWM, 0.0f);
}
Dikkat et: mekanizma fazında da delay ile uzun uzun beklemiyorsun. Faz makinen her turda autonomousLoop'a girip çıkıyor, arada telemetri yazıyor ve süreyi geçen zamandan ölçüyor. Bir güvenlik nedeni var: loop uzun süre bloke olursa robotun güvenliği devreye girer ve robot durur. Mekanizmayı uçta zorlama da; motor inlerse ve akım artarsa bekleme süresini kısalt. İşi biten robot hem sürüşünü hem mekanizmasını sıfıra çeker; bu da otonomun altın kuralıdır: plan bitince her şey durur.
Şimdi pil farkını gözle. Aynı kodu önce dolu, sonra yarıya inmiş pille çalıştır. Robotun aynı yolun sonunda nerede durduğunu iki kez ölç ve karşılaştır. Zayıf pille robot büyük olasılıkla geride kalacak; mekanizma da daha yavaş dönecek. Bunu gördüğünde açık döngünün sınırını kendi gözünle görmüş olursun.
Pekiştirme ve öz-değerlendirme (7 dk)
Görev bitti, şimdi kendine karşı dürüst ol. Kimse not vermiyor; gelişimini sen ölçüyorsun. Her satır için sana en uygun sütunu işaretle.
| Soru | Başlangıç | Gelişiyor | Ustalaştım |
|---|---|---|---|
| Robotu fazlara bölünmüş bir rotayı tek başına geçirebiliyorum | Tek hareket yaptırabildim | Rotayı fazladım ama sapıyor | Robot rotayı düzgün geçiyor |
| Kalibrasyon katsayısını denemeyle düzeltebiliyorum | Rastgele değer denedim | Kısa/uzun kalınca yönü buldum | Az denemede hedefi tutturuyorum |
| Robotun süreyi saydığını, mesafeyi ölçmediğini anlatabiliyorum | Emin değilim | Farkı biliyorum | Pil/zemin etkisini de açıklıyorum |
| Pilin dolu ve zayıf hâlinin farkını görüp anlatabiliyorum | Fark etmedim | Farkı gördüm | Nedenini açık döngüyle açıklıyorum |
| Sürüş, mekanizma ve otonomu tek planda birleştirdim | Sadece sürüş | Mekanizma fazı ekledim | Tam görevi tek başına yaptırdım |
Günlük hayat bağı: Bugün öğrendiğin şey sadece robotla ilgili değil. Bir çamaşır makinesi, içeride kaç kilo çamaşır olduğunu bilmeden önceden ayarlanmış bir süre kadar döner; program aynıdır ama sonuç yüke göre biraz değişir. Bir fırın, yemeğin gerçekten piştiğine bakmadan süreyi sayar; o yüzden tarif "180 derecede 25 dakika" der ama sen yine de kontrol edersin. Hepsi senin robotun gibi açık döngüdür: önceden yazılmış bir plan, sonucu ölçmeden uygulanır. Bir planın ne zaman yeterince iyi, ne zaman kontrol gerektirdiğini bilmek, sadece robotların değil senin de becerindir.
Modül kontrol listesi
Bu ders otonom modülünün sonu. Şu satırların hepsine gönül rahatlığıyla evet diyebiliyorsan modülü bitirdin sayılır:
autonomousInitileautonomousLoop'un ne zaman çalıştığını ve otonomun sürüşten farkını anlatabiliyorsun.- Bir hareket dizisini
int fazve if'lerle fazlara bölüp robotu adım adım kendi başına yürütebiliyorsun. - Beklemeyi
delayile değil, geçen zamanımillisfarkıyla ölçerek kuruyor ve bunun güvenlik nedenini biliyorsun. - Otonom değişkenlerini
autonomousInitiçinde sıfırlıyorsun ve neden sıfırlaman gerektiğini biliyorsun. - Bir mesafeyi ölçtüğün katsayıyla planlayabiliyor, robot kısa ya da uzun kalınca hangi sayıyı değiştireceğini biliyorsun.
- Bu yöntemin bir tahmin olduğunu, pil ve zemin değiştikçe sapacağını fark ettin ve bunu kendi gözünle gördün.
- Sürüş, mekanizma ve otonomu tek bir planda birleştirip robota tek başına küçük bir görev yaptırdın.
Erken bitirene ek görev
Yarışı erken bitirdiysen boş durma, iki meydan okuma seni bekliyor:
- İki noktalı gidiş dönüş: Robot hedefe gidip işini yaptıktan sonra geri dönüp başlangıç çizgisine park etsin. Bunun için rotanı yeni fazlarla uzat: dönüş, geri gidiş, park. Uzayan rotada sapmanın nasıl biriktiğini gözle; başlangıca ne kadar yakın park edebiliyorsun?
- Pile göre iki katsayı: İki
SANIYE_PER_METREdeğeri ölç, biri dolu pil için biri zayıf pil için. Yarıştan önce pilini kontrol et ve koddaki katsayıyı o günün piline göre seç. Aynı robotu iki farklı dünyaya ayarlamayı böyle öğrenirsin.