Turinys:

Savaime balansuojantis robotas iš „Magicbit“: 6 žingsniai
Savaime balansuojantis robotas iš „Magicbit“: 6 žingsniai

Video: Savaime balansuojantis robotas iš „Magicbit“: 6 žingsniai

Video: Savaime balansuojantis robotas iš „Magicbit“: 6 žingsniai
Video: Makeblock Untimate Robot Kit Part 1 : Step by Step Assembly Robot of Aram Tank 2024, Lapkritis
Anonim

Ši pamoka parodo, kaip pasigaminti savaime balansuojantį robotą naudojant „Magicbit dev“plokštę. Šiame projekte, kuris grindžiamas ESP32, mes naudojame „Magicbit“kaip kūrimo lentą. Todėl šiame projekte gali būti naudojama bet kuri ESP32 kūrimo plokštė.

Priedai:

  • magija
  • Dvigubo H-tilto L298 variklio vairuotojas
  • Linijinis reguliatorius (7805)
  • „Lipo“7,4 V 700 mAh baterija
  • Inercinis matavimo vienetas (IMU) (6 laipsniai laisvės)
  • pavarų varikliai 3V-6V DC

1 žingsnis: istorija

Istorija
Istorija
Istorija
Istorija

Ei, vaikinai, šiandien šioje pamokoje mes sužinosime apie šiek tiek sudėtingą dalyką. Tai yra apie savaime balansuojantį robotą, naudojantį „Magicbit“su „Arduino IDE“. Taigi pradėkime.

Pirmiausia pažvelkime į tai, kas yra savaime balansuojantis robotas. Savaime balansuojantis robotas yra dviejų ratų robotas. Ypatingas bruožas yra tas, kad robotas gali subalansuoti save nenaudodamas jokios išorinės paramos. Įjungus maitinimą, robotas atsistos, o tada nuolat subalansuos, naudodamas svyravimo judesius. Taigi dabar visi turite šiurkščią idėją apie savaime balansuojantį robotą.

2 žingsnis: teorija ir metodika

Teorija ir metodika
Teorija ir metodika

Norėdami subalansuoti robotą, pirmiausia mes gauname duomenis iš kai kurių jutiklių, skirtų išmatuoti roboto kampą į vertikalią plokštumą. Tuo tikslu mes naudojome MPU6050. Gavę duomenis iš jutiklio, apskaičiuojame pasvirimą į vertikalią plokštumą. Jei robotas yra tiesioje ir subalansuotoje padėtyje, tada pasvirimo kampas yra lygus nuliui. Jei ne, pakreipimo kampas yra teigiama arba neigiama. Jei robotas yra pakreiptas į priekį, tada robotas turi judėti į priekį. Taip pat, jei robotas pasviręs į atbulinę pusę, robotas turėtų judėti atbuline eiga. Jei šis pasvirimo kampas yra didelis, atsako greitis turėtų būti didelis. Priešingai, pasvirimo kampas yra mažas, tada reakcijos greitis turėtų būti mažas. Šiam procesui valdyti naudojome specialią teoremą, vadinamą PID. PID yra valdymo sistema, naudojama daugeliui procesų valdyti. PID reiškia 3 procesus.

  • P- proporcingas
  • I- vientisas
  • D- darinys

Kiekviena sistema turi įvestį ir išvestį. Panašiai ši valdymo sistema taip pat turi tam tikrą įvestį. Šioje valdymo sistemoje tai yra nukrypimas nuo stabilios būsenos. Mes tai pavadinome klaida. Mūsų robote klaida yra pasvirimo kampas nuo vertikalios plokštumos. Jei robotas yra subalansuotas, pasvirimo kampas lygus nuliui. Taigi klaidos vertė bus lygi nuliui. Todėl PID sistemos išėjimas yra lygus nuliui. Ši sistema apima tris atskirus matematinius procesus.

Pirmasis yra daugybos klaida iš skaitinio stiprinimo. Šis pelnas paprastai vadinamas Kp

P = klaida*Kp

Antrasis yra sugeneruoti klaidos integralas laiko srityje ir padauginti jį iš tam tikros naudos. Šis pelnas vadinamas Ki

I = integralas (klaida)*Ki

Trečiasis yra išvestis iš laiko srities klaidos ir padauginama iš tam tikros naudos. Šis pelnas vadinamas Kd

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

Pridėję aukščiau nurodytas operacijas, gauname galutinį rezultatą

IŠVADA = P+I+D

Dėl P dalies robotas gali įgyti stabilią padėtį, kuri yra proporcinga nuokrypiui. I dalis apskaičiuoja klaidų ir laiko grafiko plotą. Taigi jis visada stengiasi, kad robotas būtų stabilioje padėtyje. D dalis matuoja nuolydį laike ir klaidų grafike. Jei klaida didėja, ši vertė yra teigiama. Jei klaida mažėja, ši vertė yra neigiama. Dėl to, kai robotas perkeliamas į stabilią padėtį, reakcijos greitis sumažės ir tai padės pašalinti nereikalingus viršijimus. Daugiau apie PID teoriją galite sužinoti iš šios nuorodos, parodyta žemiau.

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

PID funkcijos išvestis ribojama iki 0–255 diapazono (8 bitų PWM skiriamoji geba) ir varikliai bus perduodami kaip PWM signalas.

3 žingsnis: Aparatūros sąranka

Techninės įrangos sąranka
Techninės įrangos sąranka

Dabar tai aparatinės įrangos sąrankos dalis. Roboto dizainas priklauso nuo jūsų. Kurdami roboto kūną, turite atsižvelgti į jo simetriškumą vertikaliai ašiai, esančiai variklio ašyje. Akumuliatorius yra žemiau. Todėl robotą lengva subalansuoti. Pagal savo dizainą „Magicbit“plokštę pritvirtiname vertikaliai prie korpuso. Mes naudojome du 12 V pavarų variklius. Bet jūs galite naudoti bet kokius pavarų variklius. tai priklauso nuo jūsų roboto matmenų.

Kai diskutuojame apie grandinę, ji maitinama 7,4 V „Lipo“baterija. Maitinimui „Magicbit“naudojo 5 V įtampą. Todėl mes naudojome 7805 reguliatorių akumuliatoriaus įtampai reguliuoti iki 5 V. Vėlesnėse „Magicbit“versijose šio reguliatoriaus nereikia. Nes maitina iki 12V. Mes tiesiogiai tiekiame 7,4 V variklio vairuotojui.

Prijunkite visus komponentus pagal žemiau pateiktą schemą.

4 žingsnis: programinės įrangos sąranka

Kode mes naudojome PID biblioteką PID išėjimui apskaičiuoti.

Eikite į šią nuorodą, kad ją atsisiųstumėte.

www.arduinolibraries.info/libraries/pid

Atsisiųskite naujausią jo versiją.

Norėdami gauti geresnius jutiklių rodmenis, naudojome DMP biblioteką. DMP reiškia skaitmeninio judesio procesą. Tai yra integruota MPU6050 funkcija. Ši mikroschema turi integruotą judesio proceso bloką. Taigi reikia skaityti ir analizuoti. Po to jis sukuria tikslius triukšmo išėjimus į mikrovaldiklį (šiuo atveju „Magicbit“(ESP32)). Tačiau mikrovaldiklio pusėje yra daug darbų, kad būtų galima išmatuoti šiuos rodmenis ir apskaičiuoti kampą. Taigi paprasčiausiai naudojome MPU6050 DMP biblioteką. Atsisiųskite jį apsilankę šioje nuorodoje.

github.com/ElectronicCats/mpu6050

Norėdami įdiegti bibliotekas, „Arduino“meniu eikite į įrankiai-> įtraukti biblioteką-> add.zip biblioteką ir pasirinkite atsisiųstą bibliotekos failą.

Kode turite teisingai pakeisti nustatytos vertės kampą. PID pastovios vertės skirtinguose robotuose skiriasi. Taigi, derindami tai, pirmiausia nustatykite Ki ir Kd reikšmes nuliui, tada padidinkite Kp, kol pasieksite geresnį reakcijos greitį. Daugiau Kp sukelia daugiau viršijimų. Tada padidinkite Kd vertę. Visada padidinkite jį labai mažais kiekiais. Ši vertė paprastai yra mažesnė nei kitos vertės. Dabar padidinkite Ki, kol gausite labai gerą stabilumą.

Pasirinkite tinkamą COM prievadą ir plokštės tipą. įkelti kodą. Dabar galite žaisti su savo „pasidaryk pats“robotu.

5 žingsnis: schemos

Schemos
Schemos

6 žingsnis: kodas

#įtraukti

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = klaidinga; // nustatyti tiesa, jei DMP init buvo sėkmingas uint8_t mpuIntStatus; // turi faktinį pertraukimo būsenos baitą iš MPU uint8_t devStatus; // grąžinti būseną po kiekvienos įrenginio operacijos (0 = sėkmė,! 0 = klaida) uint16_t packetSize; // numatomas DMP paketo dydis (numatytasis yra 42 baitai) uint16_t fifoCount; // visų baitų skaičius šiuo metu FIFO uint8_t fifoBuffer [64]; // FIFO saugojimo buferis Quaternion q; // [w, x, y, z] kvaterniono konteineris VectorFloat gravity; // [x, y, z] gravitacijos vektoriaus plūdė ypr [3]; // [posūkis, žingsnis, ridenimasis] posūkis/žingsnis/ritininis indas ir gravitacijos vektorius dvigubas originalusSetpoint = 172,5; dvigubas nustatymas = originalSetpoint; dvigubas judėjimasAngleOffset = 0,1; dvigubas įėjimas, išėjimas; int moveState = 0; dvigubas Kp = 23; // nustatyti P pirmą dvigubą Kd = 0,8; // ši vertė paprastai maža dviguba Ki = 300; // ši vertė turėtų būti didelė, kad būtų užtikrintas geresnis stabilumas, DIRECT); // pid inicializuoti int motL1 = 26; // 4 kaiščiai variklio pavarai int motL2 = 2; int motR1 = 27; int motR2 = 4; nepastovus bool mpuInterrupt = false; // nurodo, ar MPU pertraukimo smeigtukas tapo labai tuščias 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); // variklių pinmode ledcAttachPin (motL2, 1); ledcAttachPin (motR1, 2); ledcAttachPin (motR2, 3); // prisijungti prie I2C magistralės („I2Cdev“biblioteka to nedaro automatiškai) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin (); Wire.setClock (400000); // 400 kHz I2C laikrodis. Komentuokite šią eilutę, jei turite kompiliavimo sunkumų #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400, tiesa); #endif Serial.println (F ("I2C įrenginių inicijavimas …")); pinMode (14, Įvestis); // inicijuoti nuoseklųjį ryšį // (115200 pasirinktas, nes jis reikalingas arbatinuko demonstracinei išvestims, bet tai // tikrai priklauso nuo jūsų, priklausomai nuo jūsų projekto) Serial.begin (9600); while (! Serial); // laukti Leonardo išvardijimo, kiti iškart tęsti // inicijuoti įrenginį Serial.println (F ("I2C įrenginių inicijavimas …")); mpu.initialize (); // patikrinti ryšį Serial.println (F ("Įrenginio jungčių tikrinimas …")); Serial.println (mpu.testConnection ()? F ("MPU6050 ryšys sėkmingas"): F ("MPU6050 ryšys nepavyko")); // įkelti ir sukonfigūruoti DMP Serial.println (F ("DMP inicijavimas …")); devStatus = mpu.dmpInitialize (); // čia pateikite savo giroskopo poslinkius, pritaikytus mažiausiam jautrumui mpu.setXGyroOffset (220); mpu.setYGyroOffset (76); mpu.setZGyroOffset (-85); mpu.setZAccelOffset (1788); // mano bandomojo lusto gamykla pagal numatytuosius nustatymus 1688 // įsitikinkite, kad ji veikė (grąžina 0, jei taip), jei (devStatus == 0) {// įjunkite DMP dabar, kai jis paruoštas Serial.println (F ("Įjungiamas DMP … ")); mpu.setDMPEnabled (tiesa); // įgalinti „Arduino“pertraukimo aptikimą Serial.println (F („Įgalinti pertraukimo aptikimą („ Arduino “išorinis pertraukimas 0)…“)); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus (); // nustatykite mūsų DMP Ready vėliavą, kad pagrindinė ciklo () funkcija žinotų, jog ją naudoti yra gerai Serial.println (F ("DMP paruošta! Laukiama pirmo pertraukimo …")); dmpReady = tiesa; // gauti laukiamą DMP paketo dydį vėlesniam palyginimui packetSize = mpu.dmpGetFIFOPacketSize (); // sąranka PID pid. SetMode (AUTOMATIC); pid. SetSampleTime (10); pid. SetOutputLimits (-255, 255); } else {// KLAIDA! // 1 = nepavyko įkelti pradinės atminties // 2 = nepavyko atnaujinti DMP konfigūracijos // (jei ji nutrūks, dažniausiai kodas bus 1) Serial.print (F ("DMP inicijavimas nepavyko (kodas))); Serijinis. spausdinti (devStatus); Serial.println (F (")")); }} void loop () {// jei programavimas nepavyko, nebandykite nieko daryti, jei (! dmpReady) grįžta; // laukti MPU pertraukimo arba papildomo paketo (-ų), kol (! mpuInterrupt && fifoCount <packetSize) {pid. Compute (); // šis laikotarpis yra naudojamas duomenims įkelti, todėl galite tai naudoti kitiems skaičiavimams motorSpeed (išvestis); } // iš naujo nustatyti pertraukimo vėliavą ir gauti INT_STATUS baitą mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus (); // gauti dabartinį FIFO skaičių fifoCount = mpu.getFIFOCount (); // patikrinkite, ar nėra perpildymo (to niekada neturėtų nutikti, nebent mūsų kodas yra per neefektyvus) if (((mpuIntStatus & 0x10) || fifoCount == 1024) {// atstatyti, kad galėtume tęsti švariai mpu.resetFIFO (); Serial.println (F ("FIFO perpildymas!")); // kitaip, patikrinkite, ar DMP duomenų paruošimo pertraukimas (tai turėtų nutikti dažnai)} else if (mpuIntStatus & 0x02) {// laukite teisingo turimo duomenų ilgio, turėtų būti LABAI trumpas laukimas, kol (fifoCount 1 paketas prieinamas // (tai iš karto skaitykime daugiau, nelaukdami pertraukos) fifoCount -= packetSize; mpu.dmpGetQuaternion (& q, fifoBuffer); mpu.dmpGetGravity (& gravity, & q); mpu.dmpGetYawPitchRoll (ypr, & q, & gravity); #if Lial. print ("ypr / t"); Serial.print (ypr [0] * 180/M_PI); // euler kampai 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; jei (PWM> = 0) {// kryptis į priekį L2 = 0; L1 = abs (PWM); R2 = 0; R1 = abs (PWM); jei (L1> = 255) { L1 = R1 = 255;}} else {// atgal kryptis L1 = 0; L2 = abs (PWM); R1 = 0; R2 = abs (PWM); jei (L2> = 255) {L2 = R2 = 255; }} // variklio pavara ledcWrite (0, L1); ledcWrite (1, L2); ledcWrite (2, R1*0,97); // 0,97 yra greičio faktas arba dėl to, kad dešiniojo variklio greitis yra didesnis nei kairiojo variklio, todėl jį sumažiname, kol variklio greitis lygus ledcWrite (3, R2*0,97);

}

Rekomenduojamas: