Mundarija:

Magicbit -dan o'z -o'zini muvozanatlaydigan robot: 6 qadam
Magicbit -dan o'z -o'zini muvozanatlaydigan robot: 6 qadam

Video: Magicbit -dan o'z -o'zini muvozanatlaydigan robot: 6 qadam

Video: Magicbit -dan o'z -o'zini muvozanatlaydigan robot: 6 qadam
Video: Learn Coding with MagicBit 2024, Iyul
Anonim

Ushbu qo'llanmada Magicbit dev platasi yordamida o'z -o'zini muvozanatlaydigan robotni yasash ko'rsatiladi. Biz ESP32 -ga asoslangan ushbu loyihani ishlab chiqish paneli sifatida magicbit -dan foydalanmoqdamiz. Shuning uchun, ushbu loyihada har qanday ESP32 ishlab chiqish kartasidan foydalanish mumkin.

Ta'minot:

  • sehrli
  • Ikkita H-ko'prikli L298 dvigatel haydovchisi
  • Chiziqli regulyator (7805)
  • Lipo 7.4V 700mAh batareya
  • Inertial o'lchov birligi (IMU) (6 daraja erkinlik)
  • 3V-6V DC tishli motorlar

1 -qadam: hikoya

Hikoya
Hikoya
Hikoya
Hikoya

Salom bolalar, bugun biz bu darslikda biroz murakkab narsa haqida bilib olamiz. Bu Arduino IDE bilan Magicbit yordamida o'zini balanslaydigan robot haqida. Shunday qilib, boshlaylik.

Birinchidan, o'z -o'zini muvozanatlaydigan robot nima ekanligini ko'rib chiqaylik. O'zini muvozanatlaydigan robot - bu ikki g'ildirakli robot. Xususiyat shundaki, robot hech qanday tashqi yordamisiz o'zini muvozanatlashtira oladi. Quvvat yoqilganda, robot o'rnidan turadi va tebranish harakatlari yordamida u doimo muvozanatlanadi. Shunday qilib, endi siz o'zingizni balanslaydigan robot haqida qo'pol tasavvurga egasiz.

2 -qadam: nazariya va metodologiya

Nazariya va metodologiya
Nazariya va metodologiya

Robotni muvozanatlash uchun avval biz robotning burchagini vertikal tekislikka o'lchash uchun ba'zi sensorlardan ma'lumotlarni olamiz. Buning uchun biz MPU6050 dan foydalanganmiz. Sensordan ma'lumotlarni olgandan so'ng, biz vertikal tekislikka egilishni hisoblaymiz. Agar robot tekis va muvozanatli holatda bo'lsa, burilish burchagi nolga teng. Agar bunday bo'lmasa, burilish burchagi ijobiy yoki salbiy bo'ladi. Agar robot old tomonga egilgan bo'lsa, u holda robot old tomonga siljishi kerak. Agar robot teskari tomonga burilsa, robot teskari yo'nalishda harakat qilishi kerak. Agar burilish burchagi yuqori bo'lsa, javob tezligi yuqori bo'lishi kerak. Nishab burchagi past bo'lsa, reaktsiya tezligi past bo'lishi kerak. Bu jarayonni boshqarish uchun biz PID deb nomlangan maxsus teoremadan foydalanganmiz. PID - bu ko'plab jarayonlarni boshqaradigan boshqaruv tizimi. PID 3 jarayonni anglatadi.

  • P- mutanosib
  • I- ajralmas
  • D- lotin

Har bir tizimda kirish va chiqish mavjud. Xuddi shu tarzda, bu boshqaruv tizimi ham ba'zi ma'lumotlarga ega. Bu boshqaruv tizimida barqaror holatdan chetga chiqish. Biz buni xato deb atadik. Bizning robotimizda xato - vertikal tekislikdan burilish burchagi. Agar robot muvozanatli bo'lsa, burilish burchagi nolga teng. Shunday qilib, xato qiymati nolga teng bo'ladi. Shunday qilib, PID tizimining chiqishi nolga teng. Bu tizim uchta alohida matematik jarayonni o'z ichiga oladi.

Birinchisi, raqamli daromaddan ko'p xato. Bu daromad odatda Kp deb nomlanadi

P = xato*Kp

Ikkinchisi - vaqt sohasidagi xatoning integralini yaratish va uni daromadning bir qismidan ko'paytirish. Bu daromad Ki deb nomlanadi

I = Integral (xato)*Ki

Uchinchisi, vaqt sohasidagi xatolardan kelib chiqadi va uni ma'lum miqdorda daromadga ko'paytiradi. Bu daromad Kd deb nomlanadi

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

Yuqoridagi operatsiyalarni qo'shgandan so'ng biz yakuniy natijani olamiz

Chiqish = P+I+D

P qismi tufayli robot barqaror pozitsiyani egallashi mumkin, bu esa burilishga mutanosib. I qism xato va vaqt grafigini hisoblab chiqadi. Shunday qilib, u har doim robotni barqaror holatga keltirishga harakat qiladi. D qismi nishabni vaqt va xatoliklar grafigida o'lchaydi. Agar xato ko'payayotgan bo'lsa, bu qiymat ijobiy bo'ladi. Agar xato kamayayotgan bo'lsa, bu qiymat manfiy bo'ladi. Shu sababli, robot barqaror holatga o'tganda, reaktsiya tezligi pasayadi va bu keraksiz ortiqcha zarbalarni olib tashlashga yordam beradi. PID nazariyasi haqida ko'proq ma'lumotni quyida ko'rsatilgan havola orqali bilib olishingiz mumkin.

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

PID funktsiyasining chiqishi 0-255 oralig'ida (8 bitli PWM o'lchamlari) cheklangan va u motorlarga PWM signali sifatida beriladi.

3 -qadam: Uskuna sozlamalari

Uskunani sozlash
Uskunani sozlash

Endi bu apparat o'rnatish qismi. Robotning dizayni sizga bog'liq. Siz robot korpusini loyihalashda uni motor o'qida joylashgan vertikal o'qga nosimmetrik deb hisoblashingiz kerak. Batareya to'plami quyida joylashgan. Shunday qilib, robotni muvozanatlash oson. Dizaynimizda biz Magicbit taxtasini korpusga vertikal ravishda o'rnatamiz. Biz 12V kuchlanishli ikkita dvigatelni ishlatdik. Ammo siz har qanday tishli dvigatellardan foydalanishingiz mumkin. Bu sizning robot o'lchamingizga bog'liq.

Tizim haqida gapirganda, u 7.4V Lipo batareyasi bilan ishlaydi. Magicbit 5V kuch ishlatish uchun ishlatilgan. Batareya kuchlanishini 5V ga sozlash uchun biz 7805 regulyatoridan foydalanganmiz. Magicbit -ning keyingi versiyalarida bu regulyator kerak emas. Chunki u 12Vgacha quvvat oladi. Biz to'g'ridan -to'g'ri dvigatel haydovchisiga 7,4 V etkazib beramiz.

Quyidagi diagramaga muvofiq barcha komponentlarni ulang.

4 -qadam: dasturiy ta'minotni sozlash

Kodda biz PID chiqishini hisoblash uchun PID kutubxonasidan foydalanganmiz.

Yuklab olish uchun quyidagi havolaga o'ting.

www.arduinolibraries.info/libraries/pid

Uning so'nggi versiyasini yuklab oling.

Sensorni yaxshiroq o'qish uchun biz DMP kutubxonasidan foydalanganmiz. DMP raqamli harakat jarayonini anglatadi. Bu MPU6050 ichki xususiyatidir. Bu chipda harakatlanish jarayonining birligi mavjud. Shuning uchun o'qish va tahlil qilish kerak. U mikrokontrolderga shovqinsiz aniq chiqishni yaratgandan so'ng (bu holda Magicbit (ESP32)). Ammo mikrokontroller tomonida bu o'qish va burchakni hisoblash uchun juda ko'p ishlar mavjud. Shunday qilib, biz MPU6050 DMP kutubxonasidan foydalanganmiz. Uni goint orqali quyidagi havola orqali yuklab oling.

github.com/ElectronicCats/mpu6050

Kutubxonalarni o'rnatish uchun Arduino menyusida asboblar-> kutubxona qo'shish-> add.zip kutubxonasiga o'ting va siz yuklagan kutubxona faylini tanlang.

Kodda siz belgilangan burchak burchagini to'g'ri o'zgartirishingiz kerak. PID doimiy qiymatlari robotdan robotga farq qiladi. Shunday qilib, sozlashda, avval Ki va Kd qiymatlarini nolga qo'ying, so'ngra reaktsiya tezligi yaxshilanmaguncha Kp ni oshiring. Kp -ning ko'proq bo'lishi ortiqcha zarbalarni keltirib chiqaradi. Keyin Kd qiymatini oshiring. Uni har doim juda oz miqdorda oshiring. Bu qiymat odatda boshqa qiymatlarga qaraganda past bo'ladi. Endi juda yaxshi barqarorlikka ega bo'lmaguningizcha Ki -ni oshiring.

To'g'ri COM portini tanlang va taxtaning turini kiriting. kodni yuklang. Endi siz DIY robotingiz bilan o'ynashingiz mumkin.

5 -qadam: sxemalar

Sxemalar
Sxemalar

6 -qadam: kod

#qo'shing

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = noto'g'ri; // agar DMP boshlang'ichi muvaffaqiyatli bo'lsa, rostni belgilang uint8_t mpuIntStatus; // MPU uint8_t devStatus -dan haqiqiy uzilish holati baytiga ega; // har bir qurilma ishidan keyin holatni qaytarish (0 = muvaffaqiyat,! 0 = xato) uint16_t packetSize; // kutilgan DMP paket hajmi (standart 42 bayt) uint16_t fifoCount; // hozirda FIFOda mavjud bo'lgan barcha baytlar soni uint8_t fifoBuffer [64]; // FIFO saqlash buferi Quaternion q; // [w, x, y, z] quaternionli konteyner VectorFloat gravitatsiyasi; // [x, y, z] tortishish vektori float ypr [3]; // [yaw, pitch, roll] yaw/pitch/roll konteyner va tortishish vektori juft originalSetpoint = 172.5; er -xotin o'rnatish nuqtasi = originalSetpoint; double moveAngleOffset = 0.1; ikki tomonlama kirish, chiqish; int moveState = 0; er -xotin Kp = 23; // P birinchi er -xotin Kd = 0,8; // bu qiymat odatda kichik er -xotin Ki = 300; // yaxshi barqarorlik uchun bu qiymat yuqori bo'lishi kerak PID pid (& input, & output, & setpoint, Kp, Ki, Kd, // DIRECT); // pid initialize int motL1 = 26; int motR1 = 27; int motR2 = 4; o'zgaruvchan bool mpuInterrupt = false; // MPU uzilish pimi yuqori bo'shliqqa aylanganligini ko'rsatadi dmpDataReady () {mpuInterrupt = true; } void setup () {ledcSetup (0, 20000, 8); // pwm ni sozlash ledcSetup (1, 20000, 8); ledcSetup (2, 20000, 8); ledcSetup (3, 20000, 8); ledcAttachPin (motL1, 0); // dvigatellarning pinmode ledcAttachPin (motL2, 1); ledcAttachPin (motR1, 2); ledcAttachPin (motR2, 3); // I2C avtobusiga qo'shilish (I2Cdev kutubxonasi buni avtomatik ravishda qilmaydi) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin (); Wire.setClock (400000); // 400 kHz chastotali I2C. Kompilyatsiya qilishda qiyinchiliklar bo'lsa, bu qatorga izoh bering #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400, true); #endif Serial.println (F ("I2C qurilmalarini ishga tushirish …")); pinMode (14, INPUT); // ketma -ket aloqani ishga tushirish // (115200 tanlangan, chunki u Choynak Demo chiqishi uchun kerak, lekin bu sizning loyihangizga qarab // sizga bog'liq) Serial.begin (9600); while (! Seriyali); // Leonardo ro'yxatini kuting, boshqalar darhol davom ettiradilar // Serial.println qurilmasini ishga tushiring (F ("I2C qurilmalarini ishga tushirish …")); mpu.initialize (); // ulanishni tekshirish Serial.println (F ("Qurilma ulanishlarini sinab ko'rish …")); Serial.println (mpu.testConnection ()? F ("MPU6050 ulanishi muvaffaqiyatli"): F ("MPU6050 ulanishi bajarilmadi")); // DMP Serial.println -ni yuklash va sozlash (F ("DMP ishga tushirilmoqda …")); devStatus = mpu.dmpInitialize (); // bu erda minimal sezgirlik uchun o'lchangan, o'z gyro ofsetlarini etkazib bering mpu.setXGyroOffset (220); mpu.setYGyroOffset (76); mpu.setZGyroOffset (-85); mpu.setZAccelOffset (1788); // sinov chipim uchun 1688 zavod standarti // uning ishlaganligiga ishonch hosil qiling (agar shunday bo'lsa 0 qaytariladi), agar (devStatus == 0) {// DMP -ni yoqsa, hozir u tayyor Serial.println (F ("DMP -ni yoqish… ")); mpu.setDMPEnabled (haqiqiy); // Arduino uzilishni aniqlashni yoqish Serial.println (F ("Uzilishlarni aniqlashni yoqish (Arduino tashqi uzilish 0) …"))); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus (); // DMP Ready bayrog'ini o'rnating, shunda asosiy loop () funktsiyasi uni ishlatishni biladi Serial.println (F ("DMP tayyor! Birinchi uzilish kutilmoqda …")); dmpReady = rost; // keyinchalik taqqoslash uchun kutilgan DMP paket hajmini oling packetSize = mpu.dmpGetFIFOPacketSize (); // sozlash PID pid. SetMode (AUTOMATIC); pid. SetSampleTime (10); pid. SetOutputLimits (-255, 255); } boshqa {// XATO! // 1 = xotira yuklanmadi // 2 = DMP konfiguratsiyasini yangilab bo'lmadi // (agar u buzilsa, odatda kod 1 bo'ladi) Serial.print (F ("DMP ishga tushirilmadi (kod")); Seriya. chop etish (devStatus); Serial.println (F (")")); }} void loop () {// agar dasturlash muvaffaqiyatsiz bo'lsa, (! dmpReady) qaytsa, hech narsa qilishga urinmang; // MPU uzilishi yoki qo'shimcha paketlar mavjud bo'lishini kuting (! mpuInterrupt && fifoCount <packetSize) {pid. Compute (); // bu vaqt ma'lumotlarni yuklash uchun ishlatiladi, shuning uchun uni boshqa hisoblar uchun ishlatishingiz mumkin motorSpeed (chiqish); } // uzilish bayrog'ini tiklang va INT_STATUS baytini oling mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus (); // joriy FIFO sonini oling fifoCount = mpu.getFIFOCount (); // to'ldirishni tekshiring (agar bizning kodimiz juda samarasiz bo'lmasa, bu hech qachon bo'lmasligi kerak) if ((mpuIntStatus & 0x10) || fifoCount == 1024) {// reset, biz toza davom etishimiz uchun mpu.resetFIFO (); Serial.println (F ("FIFO to'lishi!")); // aks holda, DMP ma'lumotlarining tayyor uzilishini tekshiring (bu tez -tez sodir bo'lishi kerak)} aks holda (mpuIntStatus & 0x02) {// ma'lumotlarning to'g'ri uzunligini kuting, juda qisqa kutish kerak (fifoCount 1 to'plami mavjud //) uzilishni kutmasdan darhol ko'proq o'qishga ruxsat beramiz) fifoCount -= packetSize; mpu.dmpGetQuaternion (& q, fifoBuffer); mpu.dmpGetGravity (& gravity, & q); mpu.dmpGetYawPitchRoll (ypr, & q, & grif) chop etish ("ypr / t"); Serial.print (ypr [0] * 180/M_PI); // euler burchaklari 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 motorSpeed (int PWM) {float L1, L2, R1, R2; agar (PWM> = 0) {// oldinga yo'nalish L2 = 0; L1 = abs (PWM); R2 = 0; R1 = abs (PWM); agar (L1> = 255) { L1 = R1 = 255;}} boshqa {// orqaga yo'nalish L1 = 0; L2 = abs (PWM); R1 = 0; R2 = abs (PWM); if (L2> = 255) {L2 = R2 = 255; }} // motorli haydovchi ledcWrite (0, L1); ledcWrite (1, L2); ledcWrite (2, R1*0,97); // 0,97 - bu tezlik faktidir yoki, chunki o'ng dvigatel chap dvigateldan yuqori tezlikka ega, shuning uchun biz uni tezlikni tenglashtiramiz ledcWrite (3, R2*0.97);

}

Tavsiya: