Arduino Denge Robotu-Kaykay

Arduino Denge Robotu-Kaykay

denge

 

Arduino denge robotum iki teker üzerinde mpu 6050 sensörü sayesinde dengede durur.Devrilmemek için ileri geri giderek kendini dengeye alır.

Bu projemde denge robotumu sizlere tanıtıp nasıl yapıldığını adım adım anlatmak istiyorum arkadaşlar.

malzeme

  • Arduino Uno
  • L298N Motor Sürücü Kartı
  • Mpu 6050 6 eksen Gyro-İvmeölçer
  • 8X15 cm 2 adet Mekanik için pleksi levha
  • 2 Adet motor ve tekerlekleri
  • 9v pil
  • 4 adet 1.5 voltluk pil
  • iki anahtar
  • 4 adet 4 cm boyunda vida
  • 10 adet 1.5 cm boyunda vida
  • somun ve pul

20160313_143016

 

 

 

 

video

İlk olarak robotumuzun gövdesini oluşturarak işe başlayalım arkadaşlar.Şunu her zaman dikkate almalıyız ki oda tabikide gövdeyi yaparken malzemeleri gelişi güzel değilde orantılı ve elimizden geldiği kadar dengeli yerleştirmeliyiz ki robotumuz tam verimde çalışsın.

2 adet levhayı üst üste koyarak 4 köşesinden delik açıyoruz.Gövde 2 katlı olacağı için vidalar sayesinde birbirlerine bağlayacağız.Delik lerin genişliği alacağınız vidaya göre farklı olabilir bunu siz ayarlarsınız artık.

Delik açma işleminden sonra levhaların ortası bulunur.

20160313_093239

Foto da göründüğü üzere 8X15 cm lik levhanın ortasından yani 4 cm den çizgi ile ayıralım.Motorları dik bir şekide levhaya takıyoruz sağlam olması için silikon ile birleştirmesini sağlıyoruz.

Üst kısma gelecek olan levhanın motor geleceği yerleri kesiyoruz.

20160313_092126

20160313_093406

Vidalarını da takarak gövdemizi aşağıdaki fotoğraftaki gibi yapıyoruz arkadaşlar.

20160313_094205

20160313_094603

Motorumuzun Gövdesi Bu şekilde son buluyor sıra geldi gövde üzerine kartları yerleştirmeye.

İlk önce uno ve MPU6020 ivme sensörünü alt bölüme takalı.Bunun için küçük vidaları kullanacağız.Kartı ve sensörü levha üzerine koyarak delik açacağımız yerleri işaretleyelim.Ve vidalarını pullarıda kullanarak takalım.

20160313_125052

Yerlerini hazırladığımız arduino uno ve sensörü levhaya takalım.Arduino unonun gerilimi için soket kullanmak yerine direkt altından lehim yaparak kablo çektim.Arduino yu takmadan önce bu bağlantıyı yapalım.Siyah Soket girişi olan yerin alt kısmında + ve – kablosunu çekin.Ve malzemeleri yerlerine takın.

20160313_095812

Sıra geldi üst kısma.Üst kısımda ise motor sürücü kartı ve piller olacak.En uygunu Bu Dizayndı arkadaşlar bi kaç deneme yaptım ama hiç tat almadım en uygunu bu şekilde oldu.Aynı şekilde motor sürücü için vida yerleri açalım.Ve ön tarafa 2 adet anahtar koyalım.

20160313_105448 Pil yerlerimizde ortaya çıktı.4 adet pilin uçları anahtar yardımı ile motor sürücünün vcc pinine,9 voltluk pilin uçları diğer anahtar yardımı ile uno nun altından aldığımız uçlara gidecek.GÖvde ve Malzeme yerleştirmesi bitti şimdi sırada bağlantılarını yapma var.Devre şemasında göründüğü gibi bağlantılarınızı yapınız.

devre

 

denge devre şeması

 

yazilim

 


#include <PID_v1.h>
#include <LMotorController.h>
#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif


#define LOG_INPUT 0
#define MANUAL_TUNING 0
#define LOG_PID_CONSTANTS 0 
#define MOVE_BACK_FORTH 0

#define MIN_ABS_SPEED 30 // Minumum Başlangıç Hızı

//MPU


MPU6050 mpu;

// MPU control/status vars
bool dmpReady = false;  //DMP init başarılı olmuşsa doğru olarak ayarlayın.
uint8_t mpuIntStatus;   // MPU'dan gerçek kesme durumu baytı tutar
uint8_t devStatus;      // Her cihaz çalışmasından sonra dönüş durumu (0 = başarı,! 0 = hata) (0 = success, !0 = error)
uint16_t packetSize;    // Beklenen DMP paket boyutu (varsayılan 42 bayt)
uint16_t fifoCount;     // Şu anda FIFO'daki tüm baytların sayısı
uint8_t fifoBuffer[128]; // FIFO depolama arabelleği


// orientation/motion vars
Quaternion q;           // [w, x, y, z]         Kuarterna konteyner
VectorFloat gravity;    // [x, y, z]            Yerçekimi vektörü
float ypr[3];           // [yaw, pitch, roll]  Yaw / pitch Adım/ roll rulo container ve yerçekimi vektörü



//PID


#if MANUAL_TUNING
  double kp , ki, kd;
  double prevKp, prevKi, prevKd;
#endif
double originalSetpoint = 174.29;
double setpoint = originalSetpoint;
double movingAngleOffset = 0.3;
double input, output;
int moveState=0; //0 = denge ; 1 = geri ; 2 = ileri

#if MANUAL_TUNING
  PID pid(&input, &output, &setpoint, 0, 0, 0, DIRECT);
#else
  PID pid(&input, &output, &setpoint, 70, 240, 1.9, DIRECT);
#endif


//MOTOR SURUCU


int ENA = 3;
int IN1 = 4;
int IN2 = 8;
int IN3 = 5;
int IN4 = 7;
int ENB = 6;


LMotorController motorController(ENA, IN1, IN2, ENB, IN3, IN4, 0.6, 1);


//Zamanlama


long time1Hz = 0;
long time5Hz = 0;


volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high   MPU kesme iğnesinin yüksek mi kaldıysa

void dmpDataReady()
{
    mpuInterrupt = true;
}


void setup()
{
    // join I2C bus (I2Cdev library doesn't do this automatically) I2C veriyoluna katıl (I2Cdev kütüphanesi bunu otomatik olarak yapmaz)

    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (115200 chosen because it is required for Teapot Demo output, but it's
    // really up to you depending on your project)
    // seri haberleşmeyi başlatır
    // (115200, Teapot Demo çıktısı için gerekli olduğu için seçildi, ancak
    // gerçekten projenize bağlı kalabilirsiniz)
    Serial.begin(115200);
    while (!Serial); // wait for Leonardo enumeration, others continue immediately  Leonardo numaralandırmasını bekle, diğerleri hemen devam et


    // initialize device  Cihazı başlat

    Serial.println(F("I2C Kuruluyor..."));
    mpu.initialize();

    // verify connection  Bağlantıyı doğrulamak

    Serial.println(F("Suruculer test ediliyor..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 baglanti basarili") : F("MPU6050 baglanti basarisiz"));

    // load and configure the DMP  DMP'yi yükleyin ve yapılandırın

    Serial.println(F("DMP kuruluyor..."));
    devStatus = mpu.dmpInitialize();

    // supply your own gyro offsets here, scaled for min sensitivity Minyatür hassasiyet için ölçeklendirilmiş, kendi cirosu uzaklıklarınızı burada sağlayın

    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1688); // 1688 factory default for my test chip  Test yongama için 1688 fabrika varsayılanı


    // make sure it worked (returns 0 if so)  Çalıştığından emin olun (eğer öyleyse 0 döndürür)

    if (devStatus == 0)
    {
        // turn on the DMP, now that it's ready  Hazır olduğunda, DMP'yi aç

        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        // enable Arduino interrupt detection Arduino kesme algılamasını etkinleştir

        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        // set our DMP Ready flag so the main loop() function knows it's okay to use it  Ana döngü () işlevi onu kullanmanın iyi olduğunu bilmesi için DMP Hazır bayrağını ayarlayın

        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // get expected DMP packet size for later comparison  Daha sonra karşılaştırmak için beklenen DMP paket boyutunu elde edin

        packetSize = mpu.dmpGetFIFOPacketSize();
        
        //setup PID
        
        pid.SetMode(AUTOMATIC);
        pid.SetSampleTime(10);
        pid.SetOutputLimits(-255, 255);  
    }
    else
    {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)

        
// HATA!
        // 1 = başlangıç ​​bellek yükü başarısız
        // 2 = DMP yapılandırma güncellemeleri başarısız oldu
        // (eğer kırılırsa, genellikle kod 1 olur)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }
}


void loop()
{
    // if programming failed, don't try to do anything Programlama başarısız olursa, hiçbir şey yapmaya kalkışmayın.


    // wait for MPU interrupt or extra packet(s) available MPU kesmesi veya mevcut ek paket (ler) i bekleyin

    while (!mpuInterrupt && fifoCount < packetSize)
    {
        //no mpu data - performing PID calculations and output to motors // no mpu data - PID hesaplamaları yapar ve motorlara çıktılar

        
        pid.Compute();
        motorController.move(output, MIN_ABS_SPEED);
        
        unsigned long currentMillis = millis();

        if (currentMillis - time1Hz >= 1000)
        {
            loopAt1Hz();
            time1Hz = currentMillis;
        }
        
        if (currentMillis - time5Hz >= 5000)
        {
            loopAt5Hz();
            time5Hz = currentMillis;
        }
    }

    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024)
    {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    }
    else if (mpuIntStatus & 0x02)
    {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
        #if LOG_INPUT
            Serial.print("ypr\t");
            Serial.print(ypr[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(ypr[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(ypr[2] * 180/M_PI);
        #endif
        input = ypr[1] * 180/M_PI + 180;
   }
}


void loopAt1Hz()
{
#if MANUAL_TUNING
    setPIDTuningValues();
#endif
}


void loopAt5Hz()
{
    #if MOVE_BACK_FORTH
        moveBackForth();
    #endif
}


//move back and forth


void moveBackForth()
{
    moveState++;
    if (moveState > 2) moveState = 0;
    
    if (moveState == 0)
      setpoint = originalSetpoint;
    else if (moveState == 1)
      setpoint = originalSetpoint - movingAngleOffset;
    else
      setpoint = originalSetpoint + movingAngleOffset;
}


//PID Tuning (3 potentiometers)

#if MANUAL_TUNING
void setPIDTuningValues()
{
    readPIDTuningValues();
    
    if (kp != prevKp || ki != prevKi || kd != prevKd)
    {
#if LOG_PID_CONSTANTS
      Serial.print("kp = ")  Serial.print(kp);Serial.print(", ");Serial.print("ki = ");Serial.print(ki);Serial.print("kd = ");Serial.print(", ");Serial.println(kd);
#endif

        pid.SetTunings(kp, ki, kd);
        prevKp = kp; prevKi = ki; prevKd = kd;
    }
}


void readPIDTuningValues()
{
    int potKp = analogRead(A0);
    int potKi = analogRead(A1);
    int potKd = analogRead(A2);
        
    kp = map(potKp, 0, 1023, 0, 25000) / 100.0; //0 - 250
    ki = map(potKi, 0, 1023, 0, 100000) / 100.0; //0 - 1000
    kd = map(potKd, 0, 1023, 0, 500) / 100.0; //0 - 5
    
}
#endif

sonhali

DENGE ROBOT KÜTÜHANESİNİ TIklayarak indirin.

20160313_143006 20160313_143010 20160313_143016 20160313_143019 20160313_143024 20160313_143033

 

Sosyal Medyada Paylaş Facebook Twitter Google+

Etiketler: , , ,
Eklenme Tarihi: 1 Ağustos 2016

Konu hakkında yorumunuzu yazın

Arduino Denge Robotu-Kaykay (20 Yorum)

  1. HOCAM BÜTÜN BAGLANTILARI YAPDIM AMA ROBOTUM CALISMIYOR NEDEN ÖRENE BİLİRMİYİM ROBOTUMDA HİÇ BİR TEPKİ YOK BÜTÜN BAGLANTILAR DOGRU VE CALISMIYOR NEDEN ?

    • Merhaba;
      Dün tesadüfen bende yaptım devreyi herhangi bir sorun olmadan çalıştı. Devrede ve kodlarda sorun yok defalarca aynı devreyi ve yazılımı kullandım. Devre elemanlarını test ederek devam edin. Mpu6050 yi tek kullanarak 3 eksende değerler görmeye çalışın. Sonra motor sürücüyü tek kullanarak motorlara yön vermeyi deneyin . Adım adım giderseniz hata ben burdayım diyecektir.

  2. Hocam pil ve anahtarlar baglantılarını nası yapıcaz devre şemasında cok karışık yazarmısınız teşekkürler

    • 9v kare pil Arduino yu besleyecek.
      4 adet 1.5v pil . Motorsurucunun 8. Bacağına gidecek.
      Anahtarlama ise bu iki güç kaynağının gnd uçlarına yapılacak.

  3. In file included from C:\Users\Kadir\Documents\Arduino\denge0\denge0.ino:5:0:

    C:\Program Files (x86)\Arduino\libraries\MPU6050/MPU6050_6Axis_MotionApps20.h: In member function ‘uint8_t MPU6050::dmpGetAccel(int32_t*, const uint8_t*)’:

    C:\Program Files (x86)\Arduino\libraries\MPU6050/MPU6050_6Axis_MotionApps20.h:580:31: warning: left shift count >= width of type

    data[0] = ((packet[28] << 24) + (packet[29] << 16) + (packet[30] <= width of type

    data[0] = ((packet[28] << 24) + (packet[29] << 16) + (packet[30] <= width of type

    data[1] = ((packet[32] << 24) + (packet[33] << 16) + (packet[34] <= width of type

    data[1] = ((packet[32] << 24) + (packet[33] << 16) + (packet[34] <= width of type

    data[2] = ((packet[36] << 24) + (packet[37] << 16) + (packet[38] <= width of type

    data[2] = ((packet[36] << 24) + (packet[37] << 16) + (packet[38] <= width of type

    data[0] = ((packet[0] << 24) + (packet[1] << 16) + (packet[2] <= width of type

    data[0] = ((packet[0] << 24) + (packet[1] << 16) + (packet[2] <= width of type

    data[1] = ((packet[4] << 24) + (packet[5] << 16) + (packet[6] <= width of type

    data[1] = ((packet[4] << 24) + (packet[5] << 16) + (packet[6] <= width of type

    data[2] = ((packet[8] << 24) + (packet[9] << 16) + (packet[10] <= width of type

    data[2] = ((packet[8] << 24) + (packet[9] << 16) + (packet[10] <= width of type

    data[3] = ((packet[12] << 24) + (packet[13] << 16) + (packet[14] <= width of type

    data[3] = ((packet[12] << 24) + (packet[13] << 16) + (packet[14] <= width of type

    data[0] = ((packet[16] << 24) + (packet[17] << 16) + (packet[18] <= width of type

    data[0] = ((packet[16] << 24) + (packet[17] << 16) + (packet[18] <= width of type

    data[1] = ((packet[20] << 24) + (packet[21] << 16) + (packet[22] <= width of type

    data[1] = ((packet[20] << 24) + (packet[21] << 16) + (packet[22] <= width of type

    data[2] = ((packet[24] << 24) + (packet[25] << 16) + (packet[26] <= width of type

    data[2] = ((packet[24] << 24) + (packet[25] << 16) + (packet[26] << 8) + packet[27]);

    ^

    Çalışmanız programın 16528 bayt (51 %) saklama alanını kullandı. Maksimum 32256 bayt.
    Global değişkenler belleğin 706 byte kadarını (34%) kullanıyor. Yerel değişkenler için 1342 byte yer kalıyor. En fazla 2048 byte kullanılabilir.

    Hocam bende derlerken böyle bir sorunla karsılasıyorum ne oldugunu anlayamadım kütüphaneden kaynaklı oldugunu düiündüm ivme sensörünün kütüphanesini sürekli degistirdim ama olmadı bi yardımcı olursanız cok sevinirim

  4. PID pid(&input, &output, &setpoint, 70, 240, 1.9, DIRECT);

    bu kısmı

    PID pid(&input, &output, &setpoint, 15, 90, 0.8, DIRECT);

    olarak değiştirdiğinizde titreme sorunu duzeltirseniz araç titreme falan yapmıyor çok dengeli çalışıyor.

  5. Devreyi hazırladım dediğiniz gibi yaptım her şeyi ama eğim sensörü geriye gittiğinde iki tekerlek doğru çalışıyor , sensör öne doğru gittiğinde sadece bir tekerlek dönüyor bu yüzden robot çalıştığında ilk öne geriye hareket yapıp dengede duruyor sonra etrafında dönmeye başlıyor sizin kodunuzun aynısını yaptım ama neden böyle oldu ? kod ile alakalı bir şey diye düşünüyorum ama sizinle aynı kodu kullandım yardım ederseniz sevinirim.

  6. Merhaba. Öncelikle gerçekten çok güzel anlatmışsınız teşekkürler :)) benim anlamadığım bir yer var . Gnd yerleri arduınonun harici güç yerine bağlanmış devrede onu nasıl yapacağım bilmiyorum. ve benim motorlarım 6v 500 rpm sorun olurmu ve tekerleklerim sizinikilerden ince ve biraz daha büyük. şimdiden teşekkürler 🙂

  7. Arduino:1.8.2 (Windows 8.1), Kart:”Arduino/Genuino Uno”

    sketch_apr19a:3: error: #include expects “FILENAME” or

    #include “I2Cdev.h�

    ^

    sketch_apr19a:4: error: #include expects “FILENAME” or

    #include “MPU6050_6Axis_MotionApps20.h�

    ^

    sketch_apr19a:6: error: #include expects “FILENAME” or

    #include “Wire.h�

    ^

    exit status 1
    #include expects “FILENAME” or

    This report would have more information with
    “Show verbose output during compilation”
    option enabled in File -> Preferences.

    nasıl düzeltebilirim

  8. Kodları arduino uyumlu zip şeklinde verebilirmisiniz? Sıkıntı çıkıyor. Teşekkürler.

  9. merhaba hocam kodu kopyala yapıştır yaptığımda hata veriyor kodu zip hainde verme şansınıoz var mı

  10. sketch_oct22f:9: error: #include expects “FILENAME” or

    #include “MPU6050_6Axis_MotionApps20.h�

    bu hatayı veriyor ne yaptıysam çözemedim durumu. arduino da çalışır vaziyetteki programı arduino dosyası olarak yükleseniz olmaz mı kopyala yapıştır yapınca bu tarz hatalar ile karşılaşıyoruz ve düzelmiyor

  11. Selam , ben bu projeyi yapmak istiyorum.Programı arduino’nun programında denedim ama hata verdi.Programdaki kodlar doğru mu acaba?

    • Merhaba Emre.
      Ben sürekli aynı kodlar ile çalışıyorum. Yanlış kod vermektense hiç vermemeyi tercih ederim.Kopyala yapıştır yapınca sorun çıkıyor bazen buna dikkat edin.