LF2 Line Follower Kit

Yazımızda “Hızlı Çizgi İzleyen Robot “yazılım mantığı anlatılmaktadır.
Kullanılan malzemeler :
LF-2 Taşıyıcı Kart,
Arduino Nano,
TB6612FNG Motor Sürücüsü
(5 kanal / 7 kanal), Analog Sensör Dizisi,
2 adet N20 Dişli Motor (6V 600rpm),
Akrilik Şasi,
Silikon lastikli 2 adet 3D baskılı tekerlek,
Motor Braketleri
Parça montajı için M2 ve M3 vidalar ve altıgen ara parçalar,
Jumper Kabloları,
Tekerlek
2S 360 mAh Li-Po pil veya eşdeğer bir pil kullanmanızı öneririz.
Paylaşılan kod, LF2 Line Follower Kit (genelde TB6612 motor sürücü ve QRE1113 tabanlı sensör barındıran kitler) ile yapısal olarak tam uyumludur ve mantıksal bir hata içermemektedir.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
//Tanımlamalar ve Kütüphaneler #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // Belirli bir biti 0 yapar (Hızlı ADC okuma için) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) // Belirli bir biti 1 yapar (Hızlı ADC okuma için) #endif #include // Motor sürücü kütüphanesi //Robot Ayarları bool isBlackLine = 1; // 1 ise siyah çizgi, 0 ise beyaz çizgi izler unsigned int lineThickness = 25; // Çizgi kalınlığı (mm). 10-35 arası idealdir bool brakeEnabled = 0; // Sert frenleme özelliği (aktif etmek için 1 yapın) // Motor Sürücü Pin Tanımlamaları #define AIN1 4 #define BIN1 6 #define AIN2 3 #define BIN2 7 #define PWMA 9 #define PWMB 10 #define STBY 5 const int offsetA = 1; // Motor A yönü (Ters dönerse -1 yapın) const int offsetB = 1; // Motor B yönü (Ters dönerse -1 yapın) Motor motor1 = Motor(AIN1, AIN2, PWMA, offsetA, STBY); Motor motor2 = Motor(BIN1, BIN2, PWMB, offsetB, STBY); //PID ve Hız Değişkenleri int P, D, I, previousError, PIDvalue, error; int lsp, rsp; // Sol ve Sağ motor hızları int lfSpeed = 120; // Maksimum hedef hız int currentSpeed = 30; // Başlangıç hızı (Yavaş başlayıp hızlanır) float Kp = 0.06; // Oransal katsayı (Çizgiye tepki sertliği) float Kd = 1.5; // Türev katsayısı (Sallanmayı engeller) float Ki = 0; // Integral katsayısı (Sabit hataları giderir) int onLine = 1; int minValues[7], maxValues[7], threshold[7], sensorValue[7], sensorArray[7]; bool brakeFlag = 0; //Setup (Kurulum) void setup() { // ADC (Analog Okuma) hızlandırma ayarları: Robotun hızlı tepki vermesi için kritik sbi(ADCSRA, ADPS2); cbi(ADCSRA, ADPS1); cbi(ADCSRA, ADPS0); Serial.begin(9600); pinMode(11, INPUT_PULLUP); // Başlatma butonu pinMode(12, INPUT_PULLUP); // Kalibrasyon/Mod butonu pinMode(13, OUTPUT); // Durum LED'i } lineThickness = constrain(lineThickness, 10, 35); } //Ana Döngü (Loop) void loop() { while (digitalRead(11)) {} // 11. pindeki butona basılana kadar bekle delay(1000); calibrate(); // Kalibrasyon işlemini başlat (Robot kendi etrafında döner) while (digitalRead(12)) {} // 12. pindeki butona basılana kadar bekle (Yarışa hazır) delay(1000); while (1) { readLine(); // Sensörleri oku ve çizginin konumunu belirle if (currentSpeed < lfSpeed) currentSpeed++; // Hızı kademeli artır (Soft start) if (onLine == 1) { // Eğer robot çizgiyi görüyorsa linefollow(); // PID ile çizgiyi takip et digitalWrite(13, HIGH); brakeFlag = 0; } else { // Çizgi kaybedildiyse (Keskin viraj veya pist dışı) digitalWrite(13, LOW); // Son görülen hataya göre robotu sertçe geri döndür if (error > 0) { motor1.drive(-100); motor2.drive(150); } else { motor1.drive(150); motor2.drive(-100); } } } } //PID Çizgi Takip Algoritması void linefollow() { // Sensörlerden gelen ağırlıklı hata hesabı if (numSensors == 5) { error = (3 * sensorValue[1] + sensorValue[2] - sensorValue[4] - 3 * sensorValue[5]); } // Renk ve kalınlık düzeltmeleri if (lineThickness > 22) { error = error * -1; } if (isBlackLine) { error = error * -1; } P = error; // P bileşeni: Anlık hata I = I + error; // I bileşeni: Toplam hata D = error - previousError; // D bileşeni: Hata değişim hızı previousError = error; lsp = currentSpeed - PIDvalue; // Sol motor hızı ayarlanır rsp = currentSpeed + PIDvalue; // Sağ motor hızı ayarlanır // Hız sınırlandırma (0-255 arası) lsp = constrain(lsp, 0, 255); rsp = constrain(rsp, 0, 255); motor1.drive(lsp); motor2.drive(rsp); } //calibrate() Fonksiyonu (Sensörleri Ortama Alıştırma) //Bu bölüm, robotun pistteki siyah ve beyaz arasındaki farkı anlamasını sağlar. void calibrate() { // İlk değer ataması: Tüm sensörlerin mevcut okumalarını hem min hem max olarak kaydet minValues[i] = analogRead(i); maxValues[i] = analogRead(i); } // Kalibrasyon döngüsü: 10.000 kez tekrar ederek en iyi değerleri bulur motor1.drive(50); // Robotu kendi ekseninde sağa/sola döndürür motor2.drive(-50); // Bu sayede sensörler çizginin her yerini görür // Eğer okunan değer mevcut en küçük değerden küçükse, yeni minimumu kaydet if (analogRead(i) < minValues[i]) { minValues[i] = analogRead(i); } // Eğer okunan değer mevcut en büyük değerden büyükse, yeni maksimumu kaydet if (analogRead(i) > maxValues[i]) { maxValues[i] = analogRead(i); } } } // Eşik değerini (Threshold) belirleme // Siyah ve beyazın tam ortasını bul: (Min + Max) / 2 threshold[i] = (minValues[i] + maxValues[i]) / 2; Serial.print(threshold[i]); // Bilgisayara değerleri gönder Serial.print(" "); } Serial.println(); // Kalibrasyon bittiğinde motorları durdur motor1.drive(0); motor2.drive(0); } //readLine() Fonksiyonu (Çizgi Konumunu Belirleme) //Bu bölüm, analog verileri dijital bir mantığa oturtur ve robotun çizgide olup olmadığını kontrol eder. void readLine() { onLine = 0; // Başlangıçta robotun çizgi dışında olduğunu varsay // 7 Sensörlü mod aktifse if (numSensors == 7) { for (int i = 0; i < 7; i++) { // map: Sensörden gelen karışık analog değeri 0 (beyaz) ile 1000 (siyah) arasına oranlar sensorValue[i] = map(analogRead(i), minValues[i], maxValues[i], 0, 1000); // constrain: Değerin 0-1000 sınırlarının dışına çıkmamasını sağlar sensorValue[i] = constrain(sensorValue[i], 0, 1000); // Çizgi üzerinde miyiz kontrolü: // Siyah çizgi ise ve değer 700'den büyükse (koyuluk fazlaysa) "onLine" yap if (isBlackLine==1 && sensorValue[i] > 700) onLine = 1; // Beyaz çizgi ise ve değer 700'den küçükse (açıklık fazlaysa) "onLine" yap if (isBlackLine==0 && sensorValue[i] < 700) onLine = 1; } } // 5 Sensörlü mod aktifse (Sadece ortadaki 1, 2, 3, 4 ve 5. sensörleri okur) if (numSensors == 5) { for (int i = 1; i < 6; i++) { sensorValue[i] = map(analogRead(i), minValues[i], maxValues[i], 0, 1000); sensorValue[i] = constrain(sensorValue[i], 0, 1000); if (isBlackLine == 1 && sensorValue[i] > 700) onLine = 1; if (isBlackLine == 0 && sensorValue[i] < 700) onLine = 1; } } } |
Paylaşılan kod, LF2 Line Follower Kit (genelde TB6612 motor sürücü ve QRE1113 tabanlı sensör barındıran kitler) ile yapısal olarak tam uyumludur ve mantıksal bir hata içermemektedir. Ancak, koddaki bazı noktalar donanımınıza göre “ince ayar” gerektirebilir.
İşte dikkat etmeniz gereken kritik noktalar:
1. Sensör İndis Hatası (Dizilim)
linefollow() fonksiyonu içinde 5 sensörlü kullanım için şu satır var:
|
1 |
error = (3 * sensorValue[1] + sensorValue[2] - sensorValue[4] - 3 * sensorValue[5]); |
Kontrol et: Eğer 5 sensörlü bir kit kullanıyorsanız, sensörleriniz genellikle sensorValue[0] ile sensorValue[4] arasındadır. Kodda ise sensorValue[5] kullanılmış. Eğer sensörleriniz 0, 1, 2, 3, 4 şeklinde bağlıysa, bu matematiksel hesaplama bir kaymaya neden olur.
Çözüm: Sensörlerinizin hangi analog pinlere (A0-A6) bağlı olduğunu ve readLine içindeki döngüyle eşleşip eşleşmediğini kontrol edin.
2. Kalibrasyon Dönüş Hızı
|
1 2 |
motor1.drive(50); motor2.drive(-50); |
Risk: 50 hızı, bazı yüksek dişli oranlı motorlar için çok yavaş kalabilir ve robot sürtünmeden dolayı dönmeyebilir. Kalibrasyon sırasında robot kendi etrafında dönmüyorsa bu değeri 80-100 civarına çekin.
3. “onLine” Eşiği (Threshold)
|
1 |
if (isBlackLine==1 && sensorValue[i] > 700) onLine = 1; |
Öneri: 700 değeri oldukça yüksek bir eşiktir. Eğer pistteki siyah çizgi tam siyah değilse veya sensörler zemine biraz uzaksa robot çizgiyi “kaybetmiş” sayabilir. Kalibrasyon sonrası seri porttan değerleri izleyip gerekirse bu eşiği 500-600 bandına çekebilirsiniz.
4. Kütüphane Bağımlılığı
Kodun çalışması için SparkFun TB6612 Library kütüphanesinin Arduino IDE’nizde yüklü olması gerekir.
5. PID Katsayıları (Kp, Kd)
Bu kod bir “temel şablon”dur.
Kp (0.06): Çok düşük görünüyor. Robot çizgiden çok geç tepki veriyorsa bu değeri yavaşça artırın.
Kd (1.5): Robot çok titriyorsa bu değeri azaltın.
Genel Karar
Sadece sensörlerin fiziksel bağlantı sırası (0-1-2-3-4 mü yoksa 1-2-3-4-5 mi?) ile koddaki sensorValue indislerinin tutarlı olduğundan emin olmalısınız.
Kalibrasyon: Robot pistte kendi etrafında fırıl fırıl dönerken, “gördüğüm en beyaz yer şu değer, en siyah yer bu değer” diye not alıyor.
Okuma: Yarış sırasında sensörlerden gelen karmaşık sayıları (örneğin 342, 890 gibi), kalibrasyonda öğrendiği verilere bakarak 0 ile 1000 arasında bir puana dönüştürüyor. Eğer puan 700’den yüksekse, “Tamam, şu an çizginin üzerindeyim” diyor.
İpucu: Eğer robotunuz çizgiyi görmekte zorlanıyorsa, 700 olan eşik değerini 500 veya 600 yaparak daha hassas hale getirebilirsiniz.



