Arduino’da kendimi geliştirmek istiyorum. Bunun için de kod analizi üzerinde kafa yormaya karar verdim. Bunu da rastgele yapmak yerine, öncelikle bana lazım olan projeler üzerinden yapmak daha mantıklı geliyor. Sıfırdan açıklama beklentisi olan arkadaşlara önerim, ledin yanıp sönmesinden başlasınlar. Maalesef vakit sıkıntısından dolayı benim hızlı olmam gerekiyor.
Konuyu tamamlamak beklediğimden uzun sürecek. Bu yüzden birkaç güne yaymam gerekebilir.
Servo motor ile çizgi izleyen yapımı kodu:
/* Easy Line Follower Robot -DIYhacking.com Arvind Sanjeev Quick and easy line following robot using an IR reflectance array.Connect Vcc and Gnd to the Pololu QTR-8A sensor from the arduino. Connect the pins 1,2,3,... to arduino's analog pins 0,1,2,3,4,5. If the average of the 3 values of the sensors on the left is greater than the average of those on the right, then the robot moves left and vice versa. NOTE : The values in the code for analog voltages would have to be modified if you are not using the Pololu QTR-8A reflectance array sensor. Use trial and error to find out max and min values for your own IR array sensor. */ #include <Servo.h> Servo left; Servo right; int mid = 0; int mn = 0; int mx = 0; void setup() { left.attach(9, 800, 2200); //left servo motor right.attach(10, 800, 2200); //right servo motor Serial.begin(115200); digitalWrite(13, LOW); right.write(90);//stop signal left.write(90);//stop signal for(int i=0; i<5000; i++) { digitalWrite(13, HIGH); int val = 0; for(int j=0; j<=5; j++)//Calibrating the sensor, finding max and { //min reflectance values. val = analogRead(j); if(val >= mx) mx = val; if(val <= mn) mn = val; } delay(1); } mid = ((mx + mn)/2); digitalWrite(13, LOW); right.write(90); left.write(90); } void loop() { int s0 = 0; int s1 = 0; int s2 = 0; int s3 = 0; int s4 = 0; int s5 = 0; s0 = analogRead(0);//Signal pin 1 on the board s1 = analogRead(1);//Signal pin 2 on the board s2 = analogRead(2);//Signal pin 3 on the board s3 = analogRead(3);//Signal pin 4 on the board s4 = analogRead(4);//Signal pin 5 on the board s5 = analogRead(5);//Signal pin 6 on the board Serial.print("Mid: "); Serial.print(mid); Serial.print(" "); Serial.print(s0); Serial.print(" "); Serial.print(s1); Serial.print(" "); Serial.print(s2); Serial.print(" "); Serial.print(s3); Serial.print(" "); Serial.print(s4); Serial.print(" "); Serial.print(s5); Serial.print(" "); Serial.println(); right.write(180);//Move forward left.write(0);//Move forward delay(1); if((((s0+s1+s2)/3)>(((s3+s4+s5)/3)+240)))//Move right { right.write(130);//180 left.write(90);//90 Serial.print(" RIGHT"); delay(abs((((s5+s4+s3)/3)-((s0+s1+s2)/3))/2)); } if((((s0+s1+s2)/3)<(((s3+s4+s5)/3)-240)))//Move left { right.write(40);//90 left.write(0);//0 Serial.print(" LEFT"); delay(abs((((s5+s4+s3)/3)-((s0+s1+s2)/3))/2)); } if((s0 > mid)&&(s5 > mid))//Stop if all the sensors give low { //reflectance values right.write(90); left.write(90); Serial.print(" STOP"); for(int k=0; k<50; k++) { digitalWrite(13, HIGH); delay(100); digitalWrite(13, LOW); delay(100); } delay(5000); } }
Yukarıdaki kodu şuradan aldım: https://maker.pro/projects/arduino/make-line-follower-robot
Bu siteden diğer tüm kaynaklara ulaşabilmeniz mümkün. Gelelim kod analizine;
Çizgi İzleyen Kodu Analizi
#include <Servo.h>
Servo.h kütüphanesini kullanacağız. Bu kütüphaneyi neden kullandığımızı anlamak için kütüphaneyi incelemek lazım. Öncelikle google’da aratarak bu kütüphaneyi bulalım;
İşte şurada: https://github.com/esp8266/Arduino/blob/master/libraries/Servo/src/Servo.h
Kütüphane bize şu kolaylıkları sağlıyor:
// Servo - Class for manipulating servo motors connected to Arduino pins // attach(pin ) - Servo motoru Arduino'nun herhangi bir pinine i/o eklemek için // attach(pin, min, max ) - Mikrosaniye olarak pinleri min ve max eklemek için // default min is 544, max is 2400 // // write() - Servo açısını derece olarak ayarlamak için (invalid angle that is valid as pulse in microseconds is treated as microseconds) // writeMicroseconds() - Servo puls genişliğini mikrosaniye cinsinden ayarlama // read() - Gets the last written servo pulse width as an angle between 0 and 180. // readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release) // attached() - Returns true if there is a servo attached. // detach() - Stops an attached servos from pulsing its i/o pin.
devam edelim;
Servo left; Servo right;
Arduino’da sınıf tanımlanması yapılmış. (class) . Bu sınıfa uygun left ve right (sol ve sağ) diye 2 nesne oluşturulmuş. (sol servo ve sağ servo)
int mid = 0; int mn = 0; int mx = 0;
Yukarıda mid(orta), mn (minimum) ve mx(maksimum) anlamında 3 değişken tanımlanmış. Başlangıç için bunlara sıfır değeri atanmış.
void setup() {
“ void setup bir fonksiyondur ve yeni Arduino IDE lerinde siz yazmadan yeni sayafada karşınıza gelir. bu fonksiyon karta elektrik verdiğimizde sadece bir sefer çaılışır ve sırasını loop fonksiyonuna bırakır. Eğer reset butonuna basarsak yani gücü kesip geri verirsek tekrar çalışır. Sadece bir defa çalıştığı için adından da anlaşıldığı üzere kartın kurulum bilgilerini barındırır. Genelde seri bağlantı başlatılması, pinlerin nasıl çalışacağının belirlenmesi gibi sadece başta ve bir defa yapılması gereken işlemler burada belirtilir. pinlere isim takma yada değişken belirleme işleri ise bu fonksiyon çalışmadan yapılır.”
left.attach(9, 800, 2200); //left servo motor right.attach(10, 800, 2200); //right servo motor
Servo kütüphanesinde attach kullanımı şu şekildeydi:
attach(pin, min, max ) - Mikrosaniye olarak pinleri min ve max eklemek için
left nesnesi 9 nolu pine bağlı, 800-2200 mikro saniye min,max değeri olarak verilmiş. Right ise 10. pine bağlı. (sol taraftaki servonun bilgi ucu ve sağ taraftaki servonun bilgi ucundan bahsediyorum.)
left.attach(9);
Şeklinde de yazabilirdik. Bu sefer de min,max değerleri için default değerler geçerli olacaktı.
Serial.begin(115200);
Serial monitöre yazı yazdıracağız anlamına geliyor. Seri iletişimi 115200 baudrate ile başlat demek.
digitalWrite(13, LOW); //Arduino üzerindeki ledi söndürmekle işe başlamış. right.write(90);//stop signal // sağ servoyu 90 dereceye getirmiş left.write(90);//stop signal Sol servo da 90 derece
devam ediyoruz:
for(int i=0; i<5000; i++) // i tanımla. Bunu sıfır yap. 0'dan 500'e kadar alttaki parantezi tekrarla { digitalWrite(13, HIGH); // ledi yak int val = 0; // val değerini sıfıra ayarla for(int j=0; j<=5; j++)// j yi tanımla. Sıfıra ayarla. 6 kez aşağıdakini yap. { val = analogRead(j); // j değerini oku ve val değişkenine ata if(val >= mx) // val , max. değerden büyük veya eşitse mx = val; // val değerini max. değere ata if(val <= mn) // min. değerden küçük veya eşitse mn = val; // val değerini min. değere ata } delay(1); // 1 milisaniye bekle }
Yukarıdaki kodda QTR sensörünün kalibrasyonunu yapmış. J aslında QTR ‘deki IR alıcı-verici sayısı. (6 tane). Bunu analogread yaptığına göre QTR 8A kullanmış. Sizde QTR 8C varsa siz digitalRead kullanmalısınız.
mid = ((mx + mn)/2); //Orta seviyeyi bu şekilde hesaplatma yoluna gitmiş digitalWrite(13, LOW); // 13. ledi söndirmüş. Demek ki kalibrasyonun bittiğini böyle anlıyoruz. right.write(90); // tekrar seevoları 90 dereceye getirmiş. left.write(90); }
Artık tanımlama ve giriş kısmı bitti. Döngülere geçelim:
void loop() {
int s0 = 0; // s0 sensör değişkenini tanımlamış ve bunu sıfıra eşitlemiş. int s1 = 0; int s2 = 0; int s3 = 0; int s4 = 0; int s5 = 0; s0 = analogRead(0);//Signal pin 1 on the board // Sıfırı analog olarak oku s0'a ata. s1 = analogRead(1);//Signal pin 2 on the board s2 = analogRead(2);//Signal pin 3 on the board s3 = analogRead(3);//Signal pin 4 on the board s4 = analogRead(4);//Signal pin 5 on the board s5 = analogRead(5);//Signal pin 6 on the board
Burada neden (0) gibi ifadeler kullandığını anlamadım.
Serial.print("Mid: "); // Serial monitöre Mid: yaz. Karşısına mid değerini ekle. Boşluk bırak. Serial.print(mid); Serial.print(" "); Serial.print(s0); //s0 değerini ekle boşluk bırak Serial.print(" "); Serial.print(s1); Serial.print(" "); Serial.print(s2); Serial.print(" "); Serial.print(s3); Serial.print(" "); Serial.print(s4); Serial.print(" "); Serial.print(s5); Serial.print(" "); Serial.println();
Yukarıdakinin çıktısı şöyle birşey olacak:
Mid: 300 120 340
right.write(180);//Move forward left.write(0);//Move forward delay(1);
Yukarıdaki kodda öncelikle çizgi izleyenin ileri gitmesi sağlanmış. Çünkü bir çizgi izleyen için ileri gitmek esastır. Sonrasında 1 msn’lik kısa bir gecikme konulmuş ve sonraki satırlarda da sensörlerden alınan değerler hesaplanara, if yapısı ile birlikte sola veya sağa dönmesi sağlanacak.
if((((s0+s1+s2)/3)>(((s3+s4+s5)/3)+240)))//Move right { right.write(130);//180 left.write(90);//90 Serial.print(" RIGHT"); delay(abs((((s5+s4+s3)/3)-((s0+s1+s2)/3))/2)); } if((((s0+s1+s2)/3)<(((s3+s4+s5)/3)-240)))//Move left { right.write(40);//90 left.write(0);//0 Serial.print(" LEFT"); delay(abs((((s5+s4+s3)/3)-((s0+s1+s2)/3))/2)); } if((s0 > mid)&&(s5 > mid))//Stop if all the sensors give low { //reflectance values right.write(90); left.write(90); Serial.print(" STOP");
Yukarıdaki kodlarda if dallanması içinde, sağa dönmesi için gereken koşullar verilmiş. Ardından da sola dönmesi için gereken koşullar verilmiş. En sondaki if dallanması içinde de, hiçbir sensör çizgiyi algılamazsa robotun durması amaçlanmış.
Açıkçası çizgi izleyen robot yapımında servo motor kullanmak hiç iyi bir fikir değil. Aracın yönlenmesini önden servolarla yapmak yerine, arka tekerleklerin diferansiyel sistemle kumanda edilmesi çok daha kullanışlı.
if((s0 > mid)&&(s5 > mid))//Stop if all the sensors give low { //reflectance values right.write(90); left.write(90); Serial.print(" STOP"); for(int k=0; k<50; k++) { digitalWrite(13, HIGH); delay(100); digitalWrite(13, LOW); delay(100); } delay(5000); }
Buraya bir gecikme koymuş. 10 sn kadar. Sonrasında tekrar kod void loop’dan başlayacak. Sanırım araç çizgiden çıktıktan sonra, kişi tarafından tekrar yola konulması için 10 sn zaman tanınmış. Bunu neden sadece delay(10000) diyerek yapmamış acaba?
Buraya kadar.
Not: Bu analizi yapmamdaki amaç kod yazma mantığını bu şekilde daha iyi kavrayacağımı düşünmem. Yoksa bu konuda uzman olduğum gibi bir izlenim oluşturmak istemiyorum. Yanlış olduğunu düşündüğünüz yerler varsa, yorum kısmından bilgilendirme yaparsanız memnun olurum.