Cuprins:

Robot de echilibrare de la Magicbit: 6 pași
Robot de echilibrare de la Magicbit: 6 pași

Video: Robot de echilibrare de la Magicbit: 6 pași

Video: Robot de echilibrare de la Magicbit: 6 pași
Video: Робот-ячейка сваривает гигантские вентиляторы 2024, Noiembrie
Anonim

Acest tutorial arată cum să creați un robot de auto-echilibrare folosind placa de dev Magicbit. Folosim magicbit ca placă de dezvoltare în acest proiect care se bazează pe ESP32. Prin urmare, orice placă de dezvoltare ESP32 poate fi utilizată în acest proiect.

Provizii:

  • magicbit
  • Driver dublu motor H-bridge L298
  • Regulator liniar (7805)
  • Baterie Lipo 7.4V 700mah
  • Unitate de măsurare inerțială (IMU) (6 grade de libertate)
  • motoare cu transmisie 3V-6V DC

Pasul 1: Poveste

Poveste
Poveste
Poveste
Poveste

Bună băieți, astăzi în acest tutorial vom afla despre lucruri puțin complexe. Este vorba despre robot de auto-echilibrare care folosește Magicbit cu Arduino IDE. Deci, să începem.

În primul rând, să vedem ce este robotul de auto-echilibrare. Robotul de auto-echilibrare este un robot cu două roți. Caracteristica specială este că robotul se poate echilibra fără a utiliza suport extern. Când puterea este pornită, robotul se va ridica și apoi se va echilibra continuu utilizând mișcări de oscilație. Deci, acum aveți o idee aproximativă despre robotul de auto-echilibrare.

Pasul 2: Teorie și metodologie

Teorie și metodologie
Teorie și metodologie

Pentru a echilibra robotul, mai întâi obținem date de la un senzor pentru a măsura unghiul robotului în plan vertical. În acest scop am folosit MPU6050. După obținerea datelor de la senzor, calculăm înclinarea pe plan vertical. Dacă robotul este în poziție dreaptă și echilibrată, atunci unghiul de înclinare este zero. Dacă nu, atunci unghiul de înclinare este o valoare pozitivă sau negativă. Dacă robotul este înclinat în față, atunci robotul ar trebui să se deplaseze în direcția frontală. De asemenea, dacă robotul este înclinat pe partea din spate, atunci robotul ar trebui să se deplaseze în direcția inversă. Dacă acest unghi de înclinare este mare, atunci viteza de răspuns ar trebui să fie mare. Invers, unghiul de înclinare este redus, atunci viteza de reacție este mică. Pentru a controla acest proces am folosit teorema specifică numită PID. PID este un sistem de control care a folosit pentru a controla multe procese. PID reprezintă 3 procese.

  • P- proporțional
  • I- integral
  • D- derivat

Fiecare sistem are intrare și ieșire. În același mod, acest sistem de control are și unele intrări. În acest sistem de control, aceasta este abaterea de la starea stabilă. Am numit asta ca eroare. În robotul nostru, eroarea este unghiul de înclinare față de planul vertical. Dacă robotul este echilibrat, atunci unghiul de înclinare este zero. Deci valoarea erorii va fi zero. Prin urmare, ieșirea sistemului PID este zero. Acest sistem include trei procese matematice separate.

Primul este multiplicarea erorii din câștigul numeric. Acest câștig este de obicei numit Kp

P = eroare * Kp

Al doilea este generarea integralei erorii în domeniul timpului și multiplicarea acesteia din o parte din câștig. Acest câștig numit Ki

I = Integral (eroare) * Ki

Al treilea este derivat al erorii din domeniul timpului și multiplicați-l cu o anumită sumă de câștig. Acest câștig este numit Kd

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

După adăugarea operațiilor de mai sus, obținem rezultatul final

IEȘIRE = P + I + D

Datorită piesei P, robotul poate obține o poziție stabilă, care este proporțională cu abaterea. Partea I calculează aria de eroare vs graficul de timp. Așa că încearcă să ajungă robotul într-o poziție stabilă întotdeauna cu precizie. Partea D măsoară panta în timp față de graficul de eroare. Dacă eroarea crește, această valoare este pozitivă. Dacă eroarea scade, această valoare este negativă. Din acest motiv, atunci când robotul se deplasează în poziție stabilă, atunci viteza de reacție va fi redusă și acest lucru va fi util pentru a elimina depășirile inutile. Puteți afla mai multe despre teoria PID din acest link prezentat mai jos.

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

Ieșirea funcției PID este limitată la intervalul 0-255 (rezoluție PWM de 8 biți) și aceasta va fi alimentată la motoare ca semnal PWM.

Pasul 3: Configurare hardware

Configurare hardware
Configurare hardware

Acum aceasta este partea de configurare hardware. Proiectarea robotului depinde de tine. Când ați proiectat corpul robotului, trebuie să îl considerați simetric în raport cu axa verticală care se află în axa motorului. Acumulatorul situat mai jos. Prin urmare, robotul este ușor de echilibrat. În proiectarea noastră fixăm placa Magicbit pe verticală pe corp. Am folosit două motoare de 12V. Dar puteți folosi orice fel de motoare cu angrenaje. asta depinde de dimensiunile robotului dvs.

Când discutăm despre circuit, este alimentat de o baterie Lipo de 7.4V. Magicbit a folosit 5V pentru alimentare. Prin urmare, am folosit regulatorul 7805 pentru a regla tensiunea bateriei la 5V. În versiunile ulterioare ale Magicbit, regulatorul nu este necesar. Deoarece alimentează până la 12V. Furnizăm direct 7.4V pentru șoferul motorului.

Conectați toate componentele conform schemei de mai jos.

Pasul 4: Configurare software

În cod am folosit biblioteca PID pentru calcularea ieșirii PID.

Accesați linkul următor pentru al descărca.

www.arduinolibraries.info/libraries/pid

Descărcați cea mai recentă versiune a acestuia.

Pentru a obține citiri mai bune ale senzorilor, am folosit biblioteca DMP. DMP reprezintă procesul de mișcare digitală. Aceasta este o caracteristică integrată a MPU6050. Acest cip are unitate de proces de mișcare integrată. Deci este nevoie de lectură și analiză. După ce generează ieșiri precise fără zgomot către microcontroler (în acest caz Magicbit (ESP32)). Dar există o mulțime de lucrări în partea microcontrolerului pentru a lua aceste citiri și a calcula unghiul. Deci, pur și simplu, că am folosit biblioteca MPU6050 DMP. Descărcați-l prin goint la următorul link.

github.com/ElectronicCats/mpu6050

Pentru a instala bibliotecile, în meniul Arduino accesați instrumentele-> include biblioteca-> add.zip biblioteca și selectați fișierul bibliotecă pe care l-ați descărcat.

În cod trebuie să modificați corect unghiul de referință. Valorile constante PID sunt diferite de la robot la robot. Deci, reglând acest lucru, setați mai întâi valorile Ki și Kd zero și apoi creșteți Kp până când obțineți o viteză de reacție mai bună. Mai multe Kp cauzează mai multe depășiri. Apoi creșteți valoarea Kd. Măriți-l cu întotdeauna în cantitate foarte mică. Această valoare este, în general, scăzută decât alte valori. Acum măriți Ki-ul până când aveți o stabilitate foarte bună.

Selectați portul COM corect și tastați placa. încărcați codul. Acum puteți juca cu robotul dvs. DIY.

Pasul 5: Scheme

Scheme
Scheme

Pasul 6: Cod

#include

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = fals; // setați true dacă inițierea DMP a avut succes uint8_t mpuIntStatus; // deține octetul actual de stare de întrerupere de la MPU uint8_t devStatus; // returnează starea după fiecare operație a dispozitivului (0 = succes,! 0 = eroare) uint16_t pachet Dimensiune; // dimensiunea așteptată a pachetului DMP (implicit este de 42 de octeți) uint16_t fifoCount; // numărul tuturor octeților aflați în prezent în FIFO uint8_t fifoBuffer [64]; // buffer de stocare FIFO Quaternion q; // [w, x, y, z] cuaternion container VectorFloat gravity; // [x, y, z] vector de gravitație float ypr [3]; // [yaw, pitch, roll] yaw / pitch / roll container și gravity vector double originalSetpoint = 172,5; setpoint dublu = originalSetpoint; dublu movingAngleOffset = 0,1; intrare dublă, ieșire; int moveState = 0; dublu Kp = 23; // setați P primul dublu Kd = 0,8; // această valoare în general mică dublă Ki = 300; // această valoare trebuie să fie ridicată pentru o stabilitate mai bună PID pid (& intrare, & ieșire, & setpoint, Kp, Ki, Kd, DIRECT); // pid initialize int motL1 = 26; // 4 pini pentru motorul int motL2 = 2; int motR1 = 27; int motR2 = 4; volatile bool mpuInterrupt = false; // indică dacă pinul de întrerupere a MPU a scăzut ridicat 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); // pinmode al motoarelor ledcAttachPin (motL2, 1); ledcAttachPin (motR1, 2); ledcAttachPin (motR2, 3); // Alăturați-vă autobuzului I2C (biblioteca I2Cdev nu face acest lucru automat) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin (); Wire.setClock (400000); // Ceas I2C 400kHz. Comentează această linie dacă ai dificultăți de compilare #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400, true); #endif Serial.println (F ("Initializarea dispozitivelor I2C …")); pinMode (14, INPUT); // inițializați comunicarea în serie // (115200 ales pentru că este necesar pentru ieșirea Demo Teapot, dar // depinde de dvs. în funcție de proiect) Serial.begin (9600); while (! Serial); // așteptați enumerarea Leonardo, alții continuă imediat // inițializați dispozitivul Serial.println (F („Initializarea dispozitivelor I2C …”)); mpu.initialize (); // verificați conexiunea Serial.println (F ("Testarea conexiunilor dispozitivului …")); Serial.println (mpu.testConnection ()? F ("conexiunea MPU6050 reușită"): F ("conexiunea MPU6050 a eșuat")); // încărcați și configurați DMP Serial.println (F ("Inițializarea DMP …")); devStatus = mpu.dmpInitialize (); // furnizați aici propriile dvs. compensări giroscopice, scalate pentru sensibilitate minimă mpu.setXGyroOffset (220); mpu.setYGyroOffset (76); mpu.setZGyroOffset (-85); mpu.setZAccelOffset (1788); // 1688 implicit din fabrică pentru cipul meu de testare // asigurați-vă că a funcționat (returnează 0 dacă da) dacă (devStatus == 0) {// porniți DMP, acum că este gata Serial.println (F ("Activarea DMP … ")); mpu.setDMPEnabled (adevărat); // activează detectarea întreruperilor Arduino Serial.println (F ("Activarea detectării întreruperilor (întreruperea externă Arduino 0) …")); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus (); // setați steagul DMP Ready astfel încât funcția buclă principală () să știe că este în regulă să o utilizați Serial.println (F („DMP gata! Se așteaptă prima întrerupere …”)); dmpReady = adevărat; // obțineți dimensiunea așteptată a pachetului DMP pentru o comparație ulterioară packetSize = mpu.dmpGetFIFOPacketSize (); // setup PID pid. SetMode (AUTOMAT); pid. SetSampleTime (10); pid. SetOutputLimits (-255, 255); } altfel {// EROARE! // 1 = încărcarea inițială a memoriei a eșuat // 2 = Actualizările de configurare DMP au eșuat // (dacă se va sparge, de obicei codul va fi 1) Serial.print (F ("Inițializarea DMP a eșuat (cod")); Serial. print (devStatus); Serial.println (F (")")); }} void loop () {// dacă programarea a eșuat, nu încercați să faceți nimic dacă (! dmpReady) revine; // așteptați întreruperea MPU sau pachetele suplimentare disponibile în timp ce (! mpuInterrupt && fifoCount <packetSize) {pid. Compute (); // această perioadă de timp este utilizată pentru a încărca date, astfel încât să o puteți utiliza pentru alte calcule motorSpeed (ieșire); } // resetează steagul de întrerupere și obține INT_STATUS octet mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus (); // obțineți numărul FIFO curent fifoCount = mpu.getFIFOCount (); // verificați depășirea (acest lucru nu ar trebui să se întâmple niciodată cu excepția cazului în care codul nostru este prea ineficient) dacă ((mpuIntStatus & 0x10) || fifoCount == 1024) {// reset, astfel încât să putem continua curat mpu.resetFIFO (); Serial.println (F ("FIFO overflow!")); // în caz contrar, verificați dacă există o întrerupere pregătită pentru date DMP (acest lucru ar trebui să se întâmple frecvent)} altfel dacă (mpuIntStatus & 0x02) {// așteptați lungimea corectă a datelor disponibile, ar trebui să fie o AȘTEPTARE foarte scurtă în timp ce (pachetul fifoCount 1 este disponibil //) ne permite să citim imediat mai multe fără a aștepta o întrerupere) 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); // euler angles 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; if (PWM> = 0) {// direcție înainte L2 = 0; L1 = abs (PWM); R2 = 0; R1 = abs (PWM); if (L1> = 255) { L1 = R1 = 255;}} else {// direcție înapoi L1 = 0; L2 = abs (PWM); R1 = 0; R2 = abs (PWM); if (L2> = 255) {L2 = R2 = 255; }} // unitate motor ledcWrite (0, L1); ledcWrite (1, L2); ledcWrite (2, R1 * 0,97); // 0,97 este un fapt de viteză sau, deoarece motorul drept are viteză mare decât motorul stâng, deci îl reducem până când turațiile motorului sunt egale ledcWrite (3, R2 * 0,97);

}

Recomandat: