Kazalo:

Samoizravnalni robot iz Magicbita: 6 korakov
Samoizravnalni robot iz Magicbita: 6 korakov

Video: Samoizravnalni robot iz Magicbita: 6 korakov

Video: Samoizravnalni robot iz Magicbita: 6 korakov
Video: Prikaz izvedbe samorazlivnega estriha Baumit Alpha 2000 2024, Julij
Anonim

Ta vadnica prikazuje, kako narediti samo uravnotežnega robota s ploščo za razvijalce Magicbit. Kot razvojno ploščo v tem projektu, ki temelji na ESP32, uporabljamo magicbit. Zato je v tem projektu mogoče uporabiti katero koli razvojno ploščo ESP32.

Zaloge:

  • magicbit
  • Dvojni gonilnik motorja L298 z H-mostom
  • Linearni regulator (7805)
  • Lipo 7,4V 700mah baterija
  • Inercialna merilna enota (IMU) (6 stopinj svobode)
  • zobniški motorji 3V-6V DC

1. korak: Zgodba

Zgodba
Zgodba
Zgodba
Zgodba

Hej fantje, danes se bomo v tej vadnici naučili o malo zapletenih stvareh. Gre za samo uravnoteženega robota, ki uporablja Magicbit z Arduino IDE. Pa začnimo.

Najprej poglejmo, kaj je samoizravnalni robot. Samoizravnalni robot je dvokolesni robot. Posebnost je, da se robot lahko uravnovesi brez uporabe zunanje podpore. Ko je moč vklopljena, se bo robot dvignil in nato z nihajnimi gibi nenehno uravnotežil. Torej, zdaj imate grobo predstavo o samo uravnoteženem robotu.

2. korak: teorija in metodologija

Teorija in metodologija
Teorija in metodologija

Za uravnoteženje robota najprej dobimo podatke od nekega senzorja za merjenje robotovega kota do navpične ravnine. V ta namen smo uporabili MPU6050. Ko dobimo podatke iz senzorja, izračunamo nagib v navpično ravnino. Če je robot v ravnem in uravnoteženem položaju, je kot nagiba nič. Če ne, potem je kot nagiba pozitivna ali negativna vrednost. Če je robot nagnjen na sprednjo stran, se mora robot premakniti v sprednjo smer. Tudi če je robot nagnjen nazaj, se mora robot premakniti v obratno smer. Če je ta kot nagiba velik, mora biti hitrost odziva velika. Nasprotno, kot nagiba je nizek, reakcijska hitrost pa mora biti nizka. Za nadzor tega procesa smo uporabili poseben izrek, imenovan PID. PID je nadzorni sistem, ki se uporablja za krmiljenje številnih procesov. PID pomeni 3 postopke.

  • P- sorazmerno
  • I- integral
  • D- derivat

Vsak sistem ima vhod in izhod. Na enak način ima ta nadzorni sistem tudi nekaj vložkov. V tem nadzornem sistemu je to odstopanje od stabilnega stanja. To smo poimenovali kot napaka. Napaka pri našem robotu je kot nagiba od navpične ravnine. Če je robot uravnotežen, je kot nagiba nič. Torej bo vrednost napake enaka nič. Zato je izhod sistema PID nič. Ta sistem vključuje tri ločene matematične procese.

Prva je večkratna napaka iz numeričnega dobička. Ta dobiček se običajno imenuje Kp

P = napaka*Kp

Drugi je ustvariti integral napake v časovnem področju in ga pomnožiti z nekaj dobička. Ta dobiček se imenuje Ki

I = Integral (napaka)*Ki

Tretji je izpeljanka napake v časovni domeni in jo pomnožimo z neko količino dobička. Ta dobiček se imenuje Kd

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

Po dodajanju zgornjih operacij dobimo končni rezultat

IZHOD = P+I+D

Zaradi dela P lahko robot dobi stabilen položaj, ki je sorazmeren z odstopanjem. I del izračuna območje napak v primerjavi s časovnim grafom. Zato poskuša robota vedno natančno postaviti v stabilen položaj. Del D meri časovni naklon in graf napak. Če se napaka povečuje, je ta vrednost pozitivna. Če se napaka zmanjšuje, je ta vrednost negativna. Ko se robot premakne v stabilen položaj, se bo hitrost reakcije zmanjšala, kar bo pomagalo odstraniti nepotrebne prekoračitve. Več o teoriji PID lahko izveste na tej povezavi, prikazani spodaj.

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

Izhod funkcije PID je omejen na območje 0-255 (8-bitna ločljivost PWM) in se bo napajal na motorje kot signal PWM.

3. korak: Namestitev strojne opreme

Namestitev strojne opreme
Namestitev strojne opreme

Zdaj je to del nastavitve strojne opreme. Zasnova robota je odvisna od vas. Ko oblikujete telo robota, morate upoštevati njegovo simetričnost glede na navpično os, ki leži v osi motorja. Baterija se nahaja spodaj. Zato je robota enostavno uravnotežiti. V naši zasnovi pritrdimo ploščo Magicbit navpično na telo. Uporabili smo dva 12V zobniška motorja. Lahko pa uporabite vse vrste zobniških motorjev. to je odvisno od dimenzij vašega robota.

Ko govorimo o vezju, ga napaja 7,4V Lipo baterija. Magicbit je za napajanje uporabil 5V. Zato smo z regulatorjem 7805 uravnavali napetost akumulatorja na 5V. V kasnejših različicah programa Magicbit regulator ni potreben. Ker napaja do 12V. Neposredno dobavljamo 7,4 V za voznika motorja.

Priključite vse komponente v skladu s spodnjo shemo.

4. korak: Namestitev programske opreme

V kodi smo za izračun izhoda PID uporabili knjižnico PID.

Pojdite na naslednjo povezavo, če jo želite prenesti.

www.arduinolibraries.info/libraries/pid

Prenesite najnovejšo različico.

Za boljše odčitke senzorjev smo uporabili knjižnico DMP. DMP pomeni proces digitalnega gibanja. To je vgrajena funkcija MPU6050. Ta čip ima vgrajeno procesno enoto za gibanje. Zato je treba prebrati in analizirati. Potem ko ustvari brezšumne natančne izhode v mikrokrmilnik (v tem primeru Magicbit (ESP32)). Toda na strani mikrokrmilnika je veliko del, ki upoštevajo te odčitke in izračunajo kot. Tako smo preprosto uporabili knjižnico DMP MPU6050. Prenesite ga z gointom na naslednjo povezavo.

github.com/ElectronicCats/mpu6050

Če želite namestiti knjižnice, v meniju Arduino pojdite na orodja-> vključi knjižnico-> knjižnica add.zip in izberite datoteko knjižnice, ki ste jo prenesli.

V kodi morate pravilno spremeniti kot nastavljene vrednosti. Vrednosti konstant PID so različne od robota do robota. Torej, ko to nastavite, najprej nastavite vrednosti Ki in Kd na nič, nato pa povečajte Kp, dokler ne dosežete boljše hitrosti reakcije. Več Kp povzroča več presežkov. Nato povečajte vrednost Kd. Vedno ga povečajte v zelo majhnem obsegu. Ta vrednost je na splošno nizka od drugih vrednosti. Zdaj povečajte Ki, dokler ne dobite zelo dobre stabilnosti.

Izberite pravilna vrata COM in vrsto plošče. naložite kodo. Zdaj se lahko igrate s svojim DIY robotom.

5. korak: Sheme

Sheme
Sheme

6. korak: Koda

#vključi

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = false; // nastavimo na true, če je bil init DMP uspešen uint8_t mpuIntStatus; // vsebuje dejanski bajt stanja prekinitve iz MPU uint8_t devStatus; // vrne stanje po vsaki operaciji naprave (0 = uspeh,! 0 = napaka) uint16_t packetSize; // pričakovana velikost paketa DMP (privzeto je 42 bajtov) uint16_t fifoCount; // štetje vseh bajtov, ki so trenutno v FIFO uint8_t fifoBuffer [64]; // pomnilnik za shranjevanje FIFO Quaternion q; // [w, x, y, z] kvaterionski vsebnik VectorFloat gravitacija; // [x, y, z] plovec gravitacijskega vektorja ypr [3]; // [nihanje, nagib, zvijanje] posoda za nihanje/nagib/zvijanje in vektor gravitacije dvojni originalSetpoint = 172,5; dvojna nastavljena vrednost = originalSetpoint; dvojno premikanjeAngleOffset = 0,1; dvojni vhod, izhod; int moveState = 0; double Kp = 23; // nastavimo P prvi double Kd = 0,8; // ta vrednost je običajno majhna double Ki = 300; // ta vrednost bi morala biti visoka za boljšo stabilnost PID pid (& input, & output, & setpoint, Kp, Ki, Kd, DIRECT); // pid inicializacija int motL1 = 26; // 4 zatiči za motorni pogon int motL2 = 2; int motR1 = 27; int motR2 = 4; hlapna bool mpuInterrupt = false; // označuje, ali je prekinitveni pin MPU previsok. dmpDataReady () {mpuInterrupt = true; } void setup () {ledcSetup (0, 20000, 8); // nastavitev pwm ledcSetup (1, 20000, 8); ledcSetup (2, 20000, 8); ledcSetup (3, 20000, 8); ledcAttachPin (motL1, 0); // pinmode motorjev ledcAttachPin (motL2, 1); ledcAttachPin (motR1, 2); ledcAttachPin (motR2, 3); // pridruži se vodilu I2C (knjižnica I2Cdev tega ne stori samodejno) #če I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin (); Wire.setClock (400000); // Ura I2C 400kHz. Komentirajte to vrstico, če imate težave pri sestavljanju #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400, res); #endif Serial.println (F ("Inicializiranje naprav I2C …")); pinMode (14, VHOD); // inicializiraj serijsko komunikacijo // (izbrano 115200, ker je to potrebno za predstavitev Teapot Demo, vendar je // odvisno od vas, odvisno od vašega projekta) Serial.begin (9600); while (! Serijski); // počakajte na Leonardovo naštevanje, drugi nadaljujejo takoj // inicializirajte napravo Serial.println (F ("Inicializiranje naprav I2C …")); mpu.initialize (); // preverimo povezavo Serial.println (F ("Preverjanje povezav naprav …")); Serial.println (mpu.testConnection ()? F ("Povezava MPU6050 uspešna"): F ("Povezava MPU6050 ni uspela")); // naložimo in konfiguriramo DMP Serial.println (F ("Inicializacija DMP …")); devStatus = mpu.dmpInitialize (); // tukaj vnesete lastne odmike žiroskopov, prilagojene za minimalno občutljivost mpu.setXGyroOffset (220); mpu.setYGyroOffset (76); mpu.setZGyroOffset (-85); mpu.setZAccelOffset (1788); // 1688 tovarniško privzeto za moj preskusni čip // preverite, ali je deloval (vrne 0, če je tako) if (devStatus == 0) {// vklopite DMP, zdaj ko je pripravljen Serial.println (F ("Omogočanje DMP … ")); mpu.setDMPEnabled (true); // omogočimo zaznavanje prekinitev Arduino Serial.println (F ("Omogočanje zaznavanja prekinitev (Arduino zunanji prekinitev 0) …")); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus (); // nastavimo zastavo DMP Ready, tako da funkcija main loop () ve, da je v redu, če jo uporabljamo Serial.println (F ("DMP pripravljen! Čakanje na prvo prekinitev …")); dmpReady = res; // dobimo pričakovano velikost paketa DMP za kasnejšo primerjavo packetSize = mpu.dmpGetFIFOPacketSize (); // nastavitev PID pid. SetMode (AUTOMATIC); pid. SetSampleTime (10); pid. SetOutputLimits (-255, 255); } else {// NAPAKA! // 1 = začetna obremenitev pomnilnika ni uspela // 2 = posodobitve konfiguracije DMP niso uspele // (če se bo prekinil, bo običajno koda 1) Serial.print (F ("DMP Initialization failed (code")); Serial. print (devStatus); Serial.println (F (")")); }} void loop () {// če programiranje ni uspelo, ne poskušajte storiti nič, če se (! dmpReady) vrne; // počakajte na prekinitev MPU ali na voljo dodatne pakete, medtem ko (! mpuInterrupt && fifoCount <packetSize) {pid. Compute (); // to časovno obdobje se uporablja za nalaganje podatkov, zato ga lahko uporabite za druge izračune motorSpeed (izhod); } // ponastavite zastavico prekinitve in dobite INT_STATUS bajt mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus (); // dobimo trenutno število FIFO fifoCount = mpu.getFIFOCount (); // preverimo preliv (to se nikoli ne bi smelo zgoditi, razen če je naša koda preveč neučinkovita) if ((mpuIntStatus & 0x10) || fifoCount == 1024) {// reset, da lahko nadaljujemo čisto mpu.resetFIFO (); Serial.println (F ("FIFO preliv!")); // v nasprotnem primeru preverite, ali so podatki DMP pripravljeni za prekinitev (to bi se moralo pogosto dogajati)} drugače če (mpuIntStatus & 0x02) {// počaka na pravilno razpoložljivo dolžino podatkov, naj bo ZELO kratko čakanje (paket fifoCount 1 je na voljo // (to nam omogoča, da takoj preberemo več, ne da bi čakali na prekinitev) print ("ypr / t"); Serial.print (ypr [0] * 180/M_PI); // euler koti 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; če (PWM> = 0) {// smer naprej L2 = 0; L1 = abs (PWM); R2 = 0; R1 = abs (PWM); če (L1> = 255) { L1 = R1 = 255;}} drugače {// smer nazaj L1 = 0; L2 = abs (PWM); R1 = 0; R2 = abs (PWM); če (L2> = 255) {L2 = R2 = 255; }} // motorni pogon ledcWrite (0, L1); ledcWrite (1, L2); ledcWrite (2, R1*0,97); // 0,97 je dejstvo hitrosti ali ker ima desni motor veliko večjo hitrost kot levi motor, ga zmanjšamo, dokler hitrosti motorja niso enake ledcWrite (3, R2*0,97);

}

Priporočena: