İçindekiler:

Magicbit'ten Kendi Kendini Dengeleyen Robot: 6 Adım
Magicbit'ten Kendi Kendini Dengeleyen Robot: 6 Adım

Video: Magicbit'ten Kendi Kendini Dengeleyen Robot: 6 Adım

Video: Magicbit'ten Kendi Kendini Dengeleyen Robot: 6 Adım
Video: Su Şişesi Taşıyan ve Kendi Kendini Dengeleyen Robot-Part 2 | | www.cukurovarobotics.com 2024, Temmuz
Anonim

Bu eğitim, Magicbit geliştirme kartını kullanarak kendi kendini dengeleyen bir robotun nasıl yapıldığını gösterir. ESP32 tabanlı bu projede geliştirme kartı olarak magicbit kullanıyoruz. Bu nedenle bu projede herhangi bir ESP32 geliştirme kartı kullanılabilir.

Gereçler:

  • sihirli bit
  • Çift H-köprü L298 motor sürücüsü
  • Lineer Regülatör (7805)
  • Lipo 7.4V 700mah pil
  • Atalet Ölçüm Birimi (IMU) (6 derece serbestlik)
  • dişli motorlar 3V-6V DC

1. Adım: Öykü

Hikaye
Hikaye
Hikaye
Hikaye

Merhaba arkadaşlar, bugün bu dersimizde biraz karmaşık şeyleri öğreneceğiz. Bu, Arduino IDE ile Magicbit kullanan kendi kendini dengeleyen robotla ilgili. Öyleyse başlayalım.

Öncelikle kendi kendini dengeleyen robotun ne olduğuna bakalım. Kendi kendini dengeleyen robot iki tekerlekli robottur. Özelliği, robotun herhangi bir harici destek kullanmadan kendini dengeleyebilmesidir. Güç verildiğinde robot ayağa kalkacak ve daha sonra salınım hareketlerini kullanarak sürekli olarak dengelenecektir. Artık kendi kendini dengeleyen robot hakkında kabaca bir fikriniz var.

Adım 2: Teori ve Metodoloji

Teori ve Metodoloji
Teori ve Metodoloji

Robotu dengelemek için önce robotun dikey düzleme açısını ölçmek için bir sensörden veri alıyoruz. Bu amaçla MPU6050 kullandık. Sensörden veri aldıktan sonra dikey düzleme eğimi hesaplıyoruz. Robot düz ve dengeli konumda ise eğim açısı sıfırdır. Değilse, eğim açısı pozitif veya negatif bir değerdir. Robot öne doğru eğiliyorsa robot öne doğru hareket etmelidir. Ayrıca robot ters yöne eğiliyorsa robot ters yöne hareket etmelidir. Bu eğim açısı yüksekse tepki hızı da yüksek olmalıdır. Tersine, eğim açısı düşükse, reaksiyon hızı düşük olmalıdır. Bu süreci kontrol etmek için PID adı verilen özel bir teoremi kullandık. PID, birçok işlemi kontrol etmek için kullanılan kontrol sistemidir. PID, 3 işlem anlamına gelir.

  • P-orantılı
  • ben- integral
  • D-türevi

Her sistemin girişi ve çıkışı vardır. Aynı şekilde bu kontrol sisteminin de bazı girdileri vardır. Kararlı durumdan sapma olan bu kontrol sisteminde. Biz buna hata dedik. Robotumuzda hata, dikey düzlemden eğim açısıdır. Robot dengeli ise eğim açısı sıfırdır. Yani hata değeri sıfır olacaktır. Bu nedenle PID sisteminin çıkışı sıfırdır. Bu sistem üç ayrı matematiksel süreç içermektedir.

Birincisi sayısal kazançtan çarpma hatasıdır. Bu kazanç genellikle Kp olarak adlandırılır

P=hata*Kp

İkincisi, zaman alanındaki hatanın integralini oluşturmak ve onu kazancın bir kısmından çarpmaktır. Ki olarak adlandırılan bu kazanç

I= İntegral(hata)*Ki

Üçüncüsü, zaman alanındaki hatanın türevidir ve onu bir miktar kazançla çarpar. Bu kazanç Kd olarak adlandırılır

D=(d(hata)/dt)*kd

Yukarıdaki işlemleri ekledikten sonra nihai çıktımızı alıyoruz

ÇIKTI=P+I+D

P parçasından dolayı robot, sapma ile orantılı olarak kararlı bir pozisyon alabilir. I bölümü, hata alanı ile zaman grafiğini hesaplar. Böylece robotu her zaman doğru bir şekilde sabit konuma getirmeye çalışır. D kısmı, zaman ve hata grafiğindeki eğimi ölçer. Hata artıyorsa bu değer pozitiftir. Hata azalıyorsa bu değer negatiftir. Bu nedenle robot sabit pozisyona geçtiğinde reaksiyon hızı düşecek ve bu gereksiz aşırılıkları ortadan kaldırmaya yardımcı olacaktır. Aşağıda gösterilen bu bağlantıdan PID teorisi hakkında daha fazla bilgi edinebilirsiniz.

www.arrow.com/en/research-and-events/articles/pid-controller-basics-and-tutorial-pid-implementation-in-arduino

PID fonksiyonunun çıkışı 0-255 aralığı (8 bit PWM çözünürlüğü) ile sınırlıdır ve bu, motorları PWM sinyali olarak besleyecektir.

Adım 3: Donanım Kurulumu

Donanım Kurulumu
Donanım Kurulumu

Şimdi bu donanım kurulum kısmı. Robotun tasarımı size bağlı. Robotun gövdesini tasarlarken, onu motor ekseninde bulunan dikey eksene göre simetrik olarak düşünmelisiniz. Aşağıda bulunan pil takımı. Bu nedenle robotu dengelemek kolaydır. Tasarımımızda Magicbit kartını gövdeye dikey olarak sabitliyoruz. İki adet 12V dişli motor kullandık. Ancak her türlü dişli motor kullanabilirsiniz. bu robot boyutlarınıza bağlıdır.

Devre hakkında konuştuğumuzda, 7.4V Lipo pil ile çalışıyor. Magicbit, güç sağlamak için 5V kullandı. Bunun için akü voltajını 5V'a ayarlamak için 7805 regülatör kullandık. Magicbit'in sonraki sürümlerinde bu düzenleyiciye ihtiyaç yoktur. Çünkü 12V'a kadar güç veriyor. Motor sürücüsü için doğrudan 7.4V sağlıyoruz.

Tüm bileşenleri aşağıdaki şemaya göre bağlayın.

Adım 4: Yazılım Kurulumu

Kodda PID çıktısını hesaplamak için PID kütüphanesini kullandık.

İndirmek için aşağıdaki bağlantıya gidin.

www.arduinolibraries.info/libraries/pid

Bunun en son sürümünü indirin.

Daha iyi sensör okumaları elde etmek için DMP kütüphanesini kullandık. DMP, dijital hareket süreci anlamına gelir. Bu, MPU6050'nin dahili özelliğidir. Bu çip, entegre hareket işlem birimine sahiptir. Bu yüzden okuma ve analiz gerektirir. Mikrodenetleyiciye gürültüsüz doğru çıktılar ürettikten sonra (bu durumda Magicbit(ESP32)). Ancak mikrodenetleyici tarafında bu okumaları almak ve açıyı hesaplamak için birçok çalışma var. Yani basitçe MPU6050 DMP kütüphanesini kullandık. Aşağıdaki bağlantıya giderek indirin.

github.com/ElectronicCats/mpu6050

Kütüphaneleri kurmak için Arduino menüsünde araçlar-> kütüphaneyi dahil et->add.zip kütüphanesine gidin ve indirdiğiniz kütüphane dosyasını seçin.

Kodda ayar noktası açısını doğru şekilde değiştirmeniz gerekir. PID sabit değerleri robottan robota farklılık gösterir. Yani bunu ayarlarken önce Ki ve Kd değerlerini sıfırlayın ve ardından daha iyi reaksiyon hızı elde edene kadar Kp'yi artırın. Daha fazla Kp, daha fazla aşmaya neden olur. Ardından Kd değerini artırın. Her zaman çok az miktarda artırın. Bu değer genellikle diğer değerlere göre düşüktür. Şimdi çok iyi bir stabilite elde edene kadar Ki'yi artırın.

Doğru COM bağlantı noktasını seçin ve kart tipini seçin. kodu yükleyin. Artık DIY robotunuzla oynayabilirsiniz.

Adım 5: Şemalar

şemalar
şemalar

6. Adım: Kod

#Dahil etmek

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = yanlış; // DMP başlatma başarılıysa true olarak ayarla uint8_t mpuIntStatus; // MPU uint8_t devStatus'tan gelen gerçek kesme durumu baytını tutar; // her cihaz işleminden sonra durumu döndür (0 = başarı, !0 = hata) uint16_t packageSize; // beklenen DMP paket boyutu (varsayılan 42 bayttır) uint16_t fifoCount; // şu anda FIFO'da bulunan tüm baytların sayısı uint8_t fifoBuffer[64]; // FIFO depolama arabelleği Quaternion q; // [w, x, y, z] dörtlü kap VectorFloat yerçekimi; // [x, y, z] yerçekimi vektörü kayan nokta ypr[3]; // [yaw, pitch, roll] yaw/pitch/yuvarlanma kabı ve yerçekimi vektörü çift orijinalAyar noktası = 172.5; çift ayar noktası = orijinal Ayar noktası; çift hareketAçıOffset = 0.1; çift giriş, çıkış; int moveState=0; double Kp = 23;//set P birinci double Kd = 0.8;//bu değer genellikle küçük double Ki = 300;//daha iyi kararlılık için bu değer yüksek olmalıdır PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);//pid initialize int motL1=26;//4 motor sürücü için pin int motL2=2; int motR1=27; int motR2=4; uçucu bool mpuInterrupt = false; // MPU kesme pininin yüksek void olup olmadığını gösterir dmpDataReady() { mpuInterrupt = true; } void setup() { ledcSetup(0, 20000, 8);//pwm setup ledcSetup(1, 20000, 8); ledcSetup(2, 20000, 8); ledcSetup(3, 20000, 8); ledcAttachPin(motL1, 0);//motorların pin modu ledcAttachPin(motL2, 1); ledcAttachPin(motR1, 2); ledcAttachPin(motR2, 3); // I2C veriyoluna katıl (I2Cdev kitaplığı bunu otomatik olarak yapmaz) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); Wire.setClock(400000); // 400kHz I2C saati. Derleme sorunları yaşıyorsanız bu satırı yorumlayın #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif Serial.println(F("I2C cihazları başlatılıyor…")); pinMode(14, GİRİŞ); // seri iletişimi başlat // (Çaydanlık Demo çıktısı için gerekli olduğu için 115200 seçildi, ancak // projenize bağlı olarak gerçekten size kalmış) Serial.begin(9600); while (!Seri); // Leonardo numaralandırmasını bekleyin, diğerleri hemen devam eder // device Serial.println(F("I2C cihazları başlatılıyor…"); mpu.initialize(); // bağlantıyı doğrula Serial.println(F("Cihaz bağlantılarını test ediyor…")); Serial.println(mpu.testConnection() ? F("MPU6050 bağlantısı başarılı"): F("MPU6050 bağlantısı başarısız")); // DMP'yi yükleyin ve yapılandırın Serial.println(F("DMP Başlatılıyor…")); devStatus = mpu.dmpInitialize(); // burada minimum hassasiyet için ölçeklendirilmiş kendi gyro ofsetlerinizi sağlayın mpu.setXGyroOffset(220); mpu.setYGyroOffset(76); mpu.setZGyroOffset(-85); mpu.setZAccelOffset(1788); // Test çipim için 1688 fabrika varsayılanı // çalıştığından emin ol (eğer öyleyse 0 döndürür) if (devStatus == 0) { // DMP'yi aç, artık hazır Serial.println(F("DMP Etkinleştiriliyor… ")); mpu.setDMPEnabled(true); // Arduino kesinti algılamayı etkinleştir Serial.println(F("Kesme algılamayı etkinleştirme (Arduino harici kesme 0)…")); AttachInterrupt(14, dmpDataReady, YÜKSELİYOR); mpuIntStatus = mpu.getIntStatus(); // DMP Ready bayrağımızı, ana loop() işlevinin onu kullanmanın uygun olduğunu bilmesi için ayarlayın Serial.println(F("DMP hazır! İlk kesme bekleniyor…")); dmpReady = doğru; // sonraki karşılaştırma için beklenen DMP paket boyutunu al packageSize = mpu.dmpGetFIFOPacketSize(); //kurulum PID pid. SetMode(OTOMATİK); pid. SetSampleTime(10); pid. SetOutputLimits(-255, 255); } başka { // HATA! // 1 = ilk bellek yüklemesi başarısız // 2 = DMP yapılandırma güncellemeleri başarısız // (bozulacaksa, kod genellikle 1 olur) Serial.print(F("DMP Başlatma başarısız (kod ")); Seri. print(devStatus); Serial.println(F(")")); } } void loop() { // programlama başarısız olursa, (!dmpReady) dönerse hiçbir şey yapmaya çalışmayın; // MPU kesintisini veya mevcut ekstra paket(ler)i bekleyin while (!mpuInterrupt && fifoCount < packageSize) { pid. Compute();//bu süre veri yüklemek için kullanılır, böylece bunu diğer hesaplamalar için kullanabilirsiniz motorSpeed(çıktı); } // kesme bayrağını sıfırla ve INT_STATUS baytını al mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus(); // mevcut FIFO sayısını al fifoCount = mpu.getFIFOCount(); // taşmayı kontrol et (kodumuz çok verimsiz olmadıkça bu asla olmamalı) if ((mpuIntStatus & 0x10) || fifoCount == 1024) { // temiz bir şekilde devam edebilmemiz için sıfırla mpu.resetFIFO(); Serial.println(F("FIFO taşması!")); // aksi takdirde, DMP veri hazır kesmesini kontrol edin (bu sık sık yapılmalıdır) } else if (mpuIntStatus & 0x02) { // doğru kullanılabilir veri uzunluğunu bekleyin, ÇOK kısa bir süre olmalıdır (fifoCount 1 paket kullanılabilir // (bu kesinti beklemeden hemen daha fazlasını okumamızı sağlar) fifoCount -= packageSize; mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); #if LOG_INPUT Serial. print("ypr\t"); Seri.print(ypr[0] * 180/M_PI);//euler açıları Seri.print("\t"); Seri.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 motorSpeed(int PWM){ float L1, L2, R1, R2; if(PWM>=0){//ileri yön L2=0; L1=abs(PWM); R2=0; R1=abs(PWM); if(L1>=255){ L1=R1=255; } } else {//geri yön L1=0; L2=abs(PWM); R1=0; R2=abs(PWM); if(L2>=255){ L2=R2=255; } } //motor sürücü ledcWrite(0, L1); ledcWrite(1, L2); ledcWrite(2, R1*0.97);//0.97 hız gerçeğidir veya, sağ motor sol motordan daha yüksek hıza sahip olduğundan, motor hızları eşit olana kadar azaltıyoruz ledcWrite(3, R2*0.97);

}

Önerilen: