Arduino ile Wireless Araba ve Kumanda Yapımı

Merhabalar,
Bu projede kendi kumandalı arabamızı yapmayı amaçladık. Uzaktan kumanda etmek için farklı tekniklerden yararlanılabilir. RF bandında yayın yapan verici ve alıcılar Wifi ve Bluetooth bağlantılara göre daha uzak mesafelerde kullanılabildikleri için bu çalışmada düşük maliyetli 2.4ghz bandında çalışan NRF24L01 wireless alıcı/verici modülünü kullandık. 2 adet Joypad butonu kullanarak kendi yaptığımız kumandadan yine kendi yaptığımız aracı kontrol etmeyi amaçladık.

Tüm projelerimde genel olarak düşük maliyetli olmasını tercih ediyorum sonuçta bu bir hobi ve büyük bütçeler ayırmak herkes için (özellikle öğrenciler) mümkün olmayabilir. Ayrıca ben yaptığım hiçbir projemi bozmuyorum, saklıyorum. O yüzden pahalı komponentlerden her bir proje için ayrı ayrı almak çok maliyet etkin olmuyor :)

Gerekli Malzemeler
1 Adet Alıcı (Bu durumda araba) için Arduino Uno / Nano veya Mega
1 Adet verici için Arduino Uno / Nano veya Mega
1 adet L298 Motor sürücü
4 adet 6v 250RPM redüksiyonlu DC motor
Araç Şasesi (Ben dakota levha kullanıyorum)
2 adet NRF24L01 SMA Antenli Wireless modül (alıcı ve verici olarak kullanılabilir)
2 adet Joystick Butonu
1 adet 10 Ohm Potansiyometre (Gerekli değil, ilave bir kontrol sağlamak için kullanılabilir)
Kablo
2s Lipo Pil (9v pil de olur ama çabuk biter)
2 adet ON-OFF switch

Aracın Yapımı
Aracın yapımı için bir önceki projemizdeki işlemlerin aynısını uygulayabilirsiniz. Veya hazır bir şase kullanabilirsiniz.
Bkz: Çizgi İzleyen Araç


NRF24L01 Sensörleri İle İlgili Önemli Bir Nokta !!!
Bu sensörler oldukça hesaplı ancak lanse edildiği şekilde takar takmaz çalıştırmakta oldukça zorlandım. Öncelikle piyasada 2 versiyonu var. İlk versiyon antensiz (anteni PCB üzerinde) olan versiyon ki bunda menzil açık alanda en fazla 50-100 metre ve ev içinde 20 metre civarında. Diğer versiyon  ise üzerinde harici anteni olan versiyon. Bunlarda menzil oldukça yeterli. Ben her ikisini de kullanmış biri olarak size antenli olanı almanızı tavsiye ederim.

Gelelim diğer konuya. Epey araştırmadan sonra bu sensörlerin besleme voltajı olan 3.3V a karşı (Mutlaka Ardu'da 3.3V pinine bağlayın. Eğer 5V'a bağlarsanız yanar !!!!) çok hassas olduğu devredeki en ufak dalgalanma ve gürültüden etkilenip çalışmadığını öğrendim. Nitekim ben de ilk çalıştırmada uzun bir süre haberleşme sağlayamadım. Sonra modülün üzerinde GND ve VCC bacakları arasında 100uf kondansatör bağlayıp filtreleme yaparak çalıştırmayı başardım. Bu hiçbir satıcının sayfasında yazmıyor. Bunun yerine bu modülün üzerine oturduğu ve besleme voltajını filtreleyen bir ara adaptör satılıyor. Yine tavsiyem kondansatör yerine ara adaptörünü almanız yönünde olacaktır. Ancak kondastör modifikasyonu da sorunu çözüyor.
Dahili antenli model
Harici antenli model

Adaptör (buna takınca 5v ile besleyebilirsiniz)



Yaptığım kondanstör modifikasyonu (GND ve VCC pinleri arasına gelecek. DİKKAT : Kondansatörün - bacağı GND'ye, + bacağı VCC ye bağlanacak. 16V'tan büyük ve 100uf bir kapasitör işinizi görecektir.




Araç Bağlantı Şeması (NRF 3.3v !!!!)


Wireless Kumanda Bağlantı Şeması (NRF 3.3v !!!!)





Çalışma Prensibi
Yaptığımız verici ile üzerindeki kumanda unsurlarından alınan bilgileri (joysticklerin x ve y eksenleri ile basma ekseni ki ben buna ihtiyaç duymadığım için bağlamadım) bir Dizi'ye atıyoruz ve NRF kütüphanesini kullanarak rahat ve basit kodlama ile verileri wireless modülün çıkışına yazıyoruz.

Alıcı tarafında ise yine dinliyoruz ve dizideki verileri alarak işliyoruz. Sonrasındaki işlemler zaten standart. Aşağıdaki kodlarda açıklamaları ile mevcut.

Verici Kodu
Alıcı ve vericide kullandığımız NRF kütüphanesi için linki kullanabilirsiniz. Kütüphaneyi indirdikten sonra içindeki her şeyi C:\Program Files\Arduino\Library dosyası içerisine atıyoruz.

/*-----( Gerekli Kütüphaneleri Yüklüyoruz )-----*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
/*-----( Değişkenlerimizi tanımlıyoruz )-----*/
#define CE_PIN   9
#define CSN_PIN 8
#define YEKSEN A0
#define XEKSEN A1
#define POT A2
#define SOLYEKSEN A3 //sol butonu sonradan eklediğim için isimlendirme biraz farklı olmuş
#define SOLXEKSEN A4  //sol butonu sonradan eklediğim için isimlendirme biraz farklı olmuş

// NOT: Sondaki "LL" "LongLong" tipi demek
const uint64_t pipe = 0xE8E8F0F0E1LL; // yayın adresi diyebiliriz iki tarafta da aynı olmalı ki haberleşebilsinler (transmit pipe deniyor)


/*-----( RF24 kütüphanesi ile radio adında bir haberleşme nesnesi yaratıyoruz )-----*/
RF24 radio(CE_PIN, CSN_PIN); // radio yaratıldı
/*-----( Girdileri tutacağımız diziyi tanımlayalım )-----*/
int verilerim[5]; // 

void setup()   /****** SETUP: 1 defa çalışır ******/
{
  Serial.begin(57600); 
  radio.begin(); //iletişimi başlattık
  //kumandadaki pinleri tanımlıyoruz
  pinMode(YEKSEN, INPUT);
  pinMode(XEKSEN, INPUT);
  pinMode(SOLYEKSEN, INPUT);
  pinMode(SOLXEKSEN, INPUT);
  pinMode(POT, INPUT);
  radio.openWritingPipe(pipe); //adrese bağlanıyoruz
}//--(setup kısmı bitimi )---


void loop()   /****** LOOP: sürekli çalışıyor ******/
{
 // int Yhareket, Xhareket;
  verilerim[0]=analogRead(A0); //kumandadan verileri okuyup dizimize yazdırıyoruz
  verilerim[1]=analogRead(A1);
  verilerim[2]=analogRead(A2);
  verilerim[3]=analogRead(A3);
  verilerim[4]=analogRead(A4);
  radio.write( verilerim, sizeof(verilerim) ); //verileri gönderilmek üzere çıkışa yazdırıyoruz

}// loop sonu



//

//BİTTİ


Alıcı Kodu

//wireless araba alıcı kodu
//Mucit Pilot
//Nisan 2020
//mucitpilot.blogspot.com
/*-----( kütüphaneleri yükleyelim )-----*/ 
#define KEY1 0 //diziden gelecek değişkenler için tanımladık
#define KEY2 0
#define KEY3 0
#define KEY4 0
#define KEY5 0

//motor pinleri

#define MotorL1 2
#define MotorL2 4 
#define MotorLE 3

#define MotorR1 6

#define MotorR2 7
#define MotorRE 5

#include <Servo.h>

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//RF modülün pinleri

#define CE_PIN   9
#define CSN_PIN 8

const uint64_t pipe = 0xE8E8F0F0E1LL; // adres

/*-----( radio nesnesi yaratılıyor)-----*/
RF24 radio(CE_PIN, CSN_PIN); // 
/*-----( değişkenler tanımlanıyor )-----*/

// radiodan gelen 5 adet veriyi almak için bir dizi oluşturuyoruz
int verilerim[] = {KEY1, KEY2, KEY3, KEY4, KEY5}; // keylerimiz
int motorilerigeri,motorsagsol,servodegeri; 
Servo servoNesnesi;//servomuz için bir nesne tanımladık.

//ultrasound sensörü kullanmadığım için kodunu gölgeledim.

//int echoPin=A1;  //Ultrasonik sensörün echo pini Arduino'nun 11.pinine
//int trigPin=A0; //Ultrasonik sensörün trig pini Arduino'nun 13.pinine tanımlandı.
//long olcum;
//int leddurum;
//long cm; // sensörümüzden okuduğumuz uzaklık

int led=A3;  //ledi Arduino'nun a3.pinine

//Bu ledi kumanda ile iletişim kurma başarılı ise yakıp kumandayı görmüyorsa söndürüyoruz

void setup()   

{
  Serial.begin(57600);
  delay(1000);

  //pinMode(echoPin, INPUT);

  //pinMode(trigPin, OUTPUT);

  
pinMode(led, OUTPUT);
  pinMode(MotorR1, OUTPUT); 
  pinMode(MotorR2, OUTPUT);

  pinMode(MotorL1, OUTPUT);

  pinMode(MotorL2, OUTPUT);
  
  //servo kullanacaksanız 
  //servoNesnesi.attach(10);//servomuzun sinyal kablosu 10. pwm kanala bağlı
  //////////////////////////////////////////////////////////
 //radio ile iletişim kuruyoruz
  Serial.println("Nrf24L01 Alıcı Başlatılıyor");
  radio.begin();
  radio.openReadingPipe(1, pipe);
  radio.startListening();
  ///////////////////////////////
}//--(setup bitti )---


void loop()   /****** LOOP: sürekli çalışır ******/
{

  if ( radio.available() ) //eğer radyo ile temas kurabilmişse
  {
    // done değişkeni false yapıyoruz ve while içinde verileri toplayacağız
    bool done = false;
    while (!done)
    {
      // veriyi alıyoruz.
      done = radio.read( verilerim, sizeof(verilerim) ); //ne kadar veri varsa al demek
      
      digitalWrite(led, HIGH); //bağlantı kurduğumuz için ledi yaktık
      //delay(50);
      motorilerigeri=map(verilerim[3],0,1023,0,255);//sol joystick ileri geri
       //verilerim=map(verilerim[4],0,1023,0,255);//sol joystick sağ sol //şimdilik bunu kullanmadım
      //verilerim=map(verilerim[0],0,1023,0,255);//sağ joystick ileri geri //şimdilik bunu kullanmadım
      motorsagsol=map(verilerim[1],0,1023,0,255);//sağ joystick sağ sol
      servodegeri=map(verilerim[2],0,1023,255,0);

      //serial monitörden verileri görmek için;

      Serial.print("KEY1 = ");
      Serial.print(motorilerigeri);
      //Serial.print(verilerim[0]);
      Serial.print("-------");
      Serial.print("KEY2 = ");
      Serial.print(motorsagsol);
      //Serial.print(verilerim[1]);
      Serial.println();

    // kumandadan gelen değerlere göre hareketlere karar veriyoruz (burada her joystick için yaklaşık orta noktaya göre +-10 birim nötr alan bırakmak gerek

    //ki parazitten değişince araç istemsiz hareket etmesin
             
             if ((motorilerigeri > 130) && ((motorsagsol > 120) && (motorsagsol < 130) )) // sadece ileri komutu veriliyor ileri gidecek
             {
                 ileri(motorilerigeri);
                 //delay(100);
                 Serial.println("ileri");
              }
             else if ((motorilerigeri < 120) && ((motorsagsol > 120) && (motorsagsol < 130) ))//sadece geri komutu veriliyor
            {
              geri(motorilerigeri);
              //delay(100);
              Serial.println("geri");
             }
              else if ((motorilerigeri > 130) && (motorsagsol < 120) )//ileri ve sola aynı anda veriliyor
              {
                 ilerisol();
                // delay(100);
                Serial.println("ilerisol");
              }
            else if ((motorilerigeri > 130) && (motorsagsol > 130) )//ileri ve sağa aynı anda veriliyor
            {
                  ilerisag();
                 //delay(100);
                Serial.println("ilerisag");
            }
            else if ((motorilerigeri < 120) && (motorsagsol < 120) )//geri ve sol komutu veriliyor
            {
                 gerisol();
                 //delay(100);
                Serial.println("gerisol");
            }
           else if ((motorilerigeri < 120) && (motorsagsol > 130) )//geri ve sag komutu veriliyor
              {
                gerisag();
                //delay(100);
                Serial.println("gerisag");
             }

           else if ((motorsagsol < 120) && ((motorilerigeri >120) && (motorilerigeri < 130) ))//sadece sol komutu veriliyor

             {
                 yerindesol(motorsagsol);
                 //delay(100);
                 Serial.println("yerindesol");
            }

           else if ((motorsagsol > 130) && ((motorilerigeri >120) && (motorilerigeri < 130) )) //sadece sağ komutu veriliyor

            {
               yerindesag(motorsagsol);
               //delay(100);
              Serial.println("yerindesag");
             }

          else {

                 dur();
                 //delay(100);
                Serial.println("DUR");
               }
      
    }//while
  }//ilk if  

  //eğer radyo bulunamazsa
  else
  {
    Serial.println("Verici Bulunamadı");
    verilerim[0] = 0;
    verilerim[1] = 0;
    verilerim[3] = 0;
    verilerim[4] = 0;
   dur();
   servoNesnesi.write(100);
   digitalWrite(led, LOW); //ledimizi de söndürüyoruz

  }

}//--(main loop sonu )---

//hareket fonksiyonlarını tanımlayalım

void ileri(int ilerigeri){  // Robotun ileri yönde hareketi için fonksiyon tanımlıyoruz.

  //ilerigeri değişkeni ile aldığımız 0-255 arası PWM sinyalini hız olarak kullanıyoruz

  digitalWrite(MotorR1, HIGH); // Sağ motorun ileri hareketi aktif

  digitalWrite(MotorR2, LOW); // Sağ motorun geri hareketi pasif
  analogWrite(MotorRE, ilerigeri); // Sağ motorun hızı 

  digitalWrite(MotorL1, HIGH); // Sol motorun ileri hareketi aktif

  digitalWrite(MotorL2, LOW); // Sol motorun geri hareketi pasif
  analogWrite(MotorLE, ilerigeri); // Sol motorun hızı 


}
void ilerisol(){  // Robotun ileri ve sol yönde hareketi için fonksiyon tanımlıyoruz.

  digitalWrite(MotorR1, HIGH); // Sağ motorun ileri hareketi aktif

  digitalWrite(MotorR2, LOW); // Sağ motorun geri hareketi pasif
  analogWrite(MotorRE, 250); // Sağ motorun hızı 

  digitalWrite(MotorL1, HIGH); // Sol motorun ileri hareketi aktif

  digitalWrite(MotorL2, LOW); // Sol motorun geri hareketi pasif
  analogWrite(MotorLE, LOW); // Sol motorun hızı 
  

}

void ilerisag(){  // Robotun ileri ve sağ yönde hareketi için fonksiyon tanımlıyoruz.


  digitalWrite(MotorR1, HIGH); // Sağ motorun ileri hareketi aktif

  digitalWrite(MotorR2, LOW); // Sağ motorun geri hareketi pasif
  analogWrite(MotorRE, LOW); // Sağ motorun hızı 

  digitalWrite(MotorL1, HIGH); // Sol motorun ileri hareketi aktif

  digitalWrite(MotorL2, LOW); // Sol motorun geri hareketi pasif
  analogWrite(MotorLE, 250); // Sol motorun hızı 

  
}

void yerindesag(int sag){ // Robotun yerinde sağa dönme hareketi için fonksiyon tanımlıyoruz.

  
  digitalWrite(MotorR1, LOW); // Sağ motorun ileri hareketi pasif
  digitalWrite(MotorR2, HIGH); // Sağ motorun geri hareketi aktif
  analogWrite(MotorRE, sag); // Sağ motorun hızı 

  digitalWrite(MotorL1, HIGH); // Sol motorun ileri hareketi aktif

  digitalWrite(MotorL2, LOW); // Sol motorun geri hareketi pasif
  analogWrite(MotorLE, sag); // Sol motorun hızı 

  
}
void yerindesol(int sol){ // Robotun yerinde sola dönme hareketi için fonksiyon tanımlıyoruz.

 int soladon=map(sol,0,120,250,120); // bu satırı yazma sebebim joystickler bir yönde 0-120 diğer yönde 130-255 arası veri gönderiyor. 

 //120-0 arası değerleri 120-250 arasına dönüştürüyorum.
  Serial.print("solagit");
  Serial.println(soladon);
  digitalWrite(MotorR1, HIGH); // Sağ motorun ileri hareketi aktif
  digitalWrite(MotorR2, LOW); // Sağ motorun geri hareketi pasif
  analogWrite(MotorRE, soladon); // Sağ motorun hızı 

  digitalWrite(MotorL1, LOW); // Sol motorun ileri hareketi pasif

  digitalWrite(MotorL2, HIGH); // Sol motorun geri hareketi aktif
  analogWrite(MotorLE, soladon); // Sol motorun hızı 
  
}
void dur(){ // Robotun durma hareketi için fonksiyon tanımlıyoruz.

  digitalWrite(MotorR1, HIGH);

  digitalWrite(MotorR2, LOW);
  digitalWrite(MotorRE, LOW);

  digitalWrite(MotorL1, HIGH);

  digitalWrite(MotorL2, LOW);
  digitalWrite(MotorLE, LOW);
  
}
void geri(int ilerigeri){ // Robotun geri hareketi için fonksiyon tanımlıyoruz.

  int gerigit=map(ilerigeri,0,120,250,120);// bu satırı yazma sebebim joystickler bir yönde 0-120 diğer yönde 130-255 arası veri gönderiyor. 

 //120-0 arası değerleri 120-250 arasına dönüştürüyorum. Yoksa kolu ittirdikçe hızlanacağına yavaşlar

  digitalWrite(MotorR1, LOW); // Sağ motorun ileri hareketi pasif

  digitalWrite(MotorR2, HIGH); // Sağ motorun geri hareketi aktif
  analogWrite(MotorRE, gerigit); // Sağ motorun hızı 

  digitalWrite(MotorL1, LOW); // Sol motorun ileri hareketi pasif

  digitalWrite(MotorL2, HIGH); // Sol motorun geri hareketi aktif
  analogWrite(MotorLE, gerigit); // Sol motorun hızı 
  
}
void gerisol(){ // Robotun geri sol hareketi için fonksiyon tanımlıyoruz.

  digitalWrite(MotorR1, LOW); // Sağ motorun ileri hareketi pasif

  digitalWrite(MotorR2, HIGH); // Sağ motorun geri hareketi aktif
  analogWrite(MotorRE, 250); // Sağ motorun hızı 

  digitalWrite(MotorL1, LOW); // Sol motorun ileri hareketi pasif

  digitalWrite(MotorL2, HIGH); // Sol motorun geri hareketi aktif
  analogWrite(MotorLE, LOW); // Sol motorun hızı 
  
}

void gerisag(){ // Robotun geri sağ hareketi için fonksiyon tanımlıyoruz.


  digitalWrite(MotorR1, LOW); // Sağ motorun ileri hareketi pasif

  digitalWrite(MotorR2, HIGH); // Sağ motorun geri hareketi aktif
  analogWrite(MotorRE, LOW); // Sağ motorun hızı 

  digitalWrite(MotorL1, LOW); // Sol motorun ileri hareketi pasif

  digitalWrite(MotorL2, HIGH); // Sol motorun geri hareketi aktif
  analogWrite(MotorLE, 250); // Sol motorun hızı 
  
}

Test Videosu



Yorumlar

Bu blogdaki popüler yayınlar

QTR-8A Kızılötesi Çizgi Sensörü Kullanımı ve Basit PID Çizgi İzleyen Robot Yapımı

A4988 Step Motor Sürücü Kartı ile NEMA Step Motor Kullanımı

Arduino ile ESP8266 Kullanımı ve İnternet Erişimi Serisi -1 (İnternet Üzerinden Veri Çekme)