Sadržaj:

Samobalansirajući robot iz Magicbita: 6 koraka
Samobalansirajući robot iz Magicbita: 6 koraka

Video: Samobalansirajući robot iz Magicbita: 6 koraka

Video: Samobalansirajući robot iz Magicbita: 6 koraka
Video: DR - Dostavni robot / Delivery robot 2024, Juli
Anonim

Ovaj vodič prikazuje kako napraviti samobalansirajućeg robota koristeći Magicbit dev ploču. Koristimo magicbit kao razvojnu ploču u ovom projektu koji se temelji na ESP32. Stoga se u ovom projektu može koristiti bilo koja razvojna ploča ESP32.

Potrošni materijal:

  • magicbit
  • Dvostruki pogonski sklop motora L298 s H-mostom
  • Linearni regulator (7805)
  • Baterija Lipo 7.4V 700mah
  • Inercijalna mjerna jedinica (IMU) (6 stepeni slobode)
  • zupčasti motori 3V-6V DC

Korak 1: Priča

Priča
Priča
Priča
Priča

Hej momci, danas ćemo u ovom vodiču naučiti o malo složenim stvarima. Riječ je o samo balansirajućem robotu koji koristi Magicbit sa Arduino IDE -om. Pa krenimo.

Prije svega, pogledajmo šta je samobalansirajući robot. Samobalansirajući robot je robot na dva kotača. Posebnost je u tome što se robot može balansirati bez upotrebe vanjske podrške. Kada je napajanje uključeno, robot će ustati, a zatim će kontinuirano balansirati pomoću pokreta oscilacija. Dakle, sada imate grubu ideju o samo balansirajućem robotu.

Korak 2: Teorija i metodologija

Teorija i metodologija
Teorija i metodologija

Da bismo uravnotežili robota, prvo dobijemo podatke od nekog senzora za mjerenje ugla robota prema vertikalnoj ravnini. U tu svrhu koristili smo MPU6050. Nakon dobivanja podataka sa senzora izračunavamo nagib u okomitu ravninu. Ako je robot u pravom i uravnoteženom položaju, tada je kut nagiba nula. Ako nije, tada je kut nagiba pozitivna ili negativna vrijednost. Ako je robot nagnut prema prednjoj strani, tada bi se robot trebao pomaknuti prema naprijed. Takođe, ako je robot nagnut na obrnutu stranu, robot bi trebao krenuti u obrnutom smjeru. Ako je ovaj ugao nagiba veliki, brzina odziva bi trebala biti velika. Obrnuto, kut nagiba je nizak, a brzina reakcije treba biti mala. Za kontrolu ovog procesa koristili smo specifičnu teoremu zvanu PID. PID je sistem upravljanja koji kontroliše mnoge procese. PID označava 3 procesa.

  • P- proporcionalno
  • I- integral
  • D- derivat

Svaki sistem ima ulaz i izlaz. Na isti način ovaj kontrolni sistem takođe ima određeni ulaz. U ovom sistemu upravljanja to je odstupanje od stabilnog stanja. To smo nazvali greškom. U našem robotu greška je kut nagiba iz okomite ravnine. Ako je robot uravnotežen, kut nagiba je nula. Dakle, vrijednost greške bit će nula. Zbog toga je izlaz PID sistema nula. Ovaj sistem uključuje tri odvojena matematička procesa.

Prva je višestruka greška iz numeričkog dobitka. Ovaj dobitak se obično naziva Kp

P = greška*Kp

Drugi je generiranje integrala greške u vremenskom domenu i pomnožavanje s nekim dobitkom. Ovaj dobitak se zove Ki

I = Integral (greška)*Ki

Treća je izvedenica greške u vremenskoj domeni i pomnožena je s nekim iznosom dobitka. Ovaj dobitak se naziva Kd

D = (d (greška)/dt)*kd

Nakon dodavanja gore navedenih operacija dobivamo konačni rezultat

IZLAZAK = P+I+D

Zbog P dijela robot može dobiti stabilan položaj koji je proporcionalan odstupanju. I dio izračunava područje greške u odnosu na grafikon vremena. Stoga pokušava uvijek precizno dovesti robota u stabilan položaj. D dio mjeri nagib u vremenu u odnosu na grafikon greške. Ako se greška povećava, ova vrijednost je pozitivna. Ako se greška smanjuje, ova vrijednost je negativna. Zbog toga, kada se robot pomakne u stabilan položaj, brzina reakcije će se smanjiti i to će pomoći u uklanjanju nepotrebnih prekoračenja. Više o PID teoriji možete saznati sa ove veze prikazane ispod.

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

Izlaz PID funkcije je ograničen na 0-255 raspona (8 bitna PWM rezolucija) i koji će se napajati motorima kao PWM signal.

Korak 3: Postavljanje hardvera

Postavljanje hardvera
Postavljanje hardvera

Ovo je dio podešavanja hardvera. Dizajn robota ovisi o vama. Kada dizajnirate tijelo robota, morate uzeti u obzir njegovo simetrično okomito osi koje leži u osi motora. Baterija se nalazi ispod. Zbog toga je robota lako balansirati. U našem dizajnu Magicbit ploču pričvršćujemo okomito na tijelo. Koristili smo dva motora 12V zupčanika. Ali možete koristiti bilo koju vrstu motora sa zupčanikom. to ovisi o dimenzijama vašeg robota.

Kada govorimo o krugu, napaja se Lipo baterijom od 7,4V. Magicbit je koristio 5V za napajanje. Zbog toga smo koristili regulator 7805 za regulaciju napona baterije na 5V. U kasnijim verzijama Magicbita taj regulator nije potreban. Zato što napaja do 12V. Izravno isporučujemo 7,4 V za vozača motora.

Spojite sve komponente prema donjem dijagramu.

Korak 4: Postavljanje softvera

U kodu smo koristili PID biblioteku za izračunavanje PID izlaza.

Idite na sljedeću vezu da biste je preuzeli.

www.arduinolibraries.info/libraries/pid

Preuzmite najnoviju verziju.

Za bolje očitanje senzora koristili smo DMP biblioteku. DMP označava proces digitalnog kretanja. Ovo je ugrađena funkcija MPU6050. Ovaj čip ima integriranu jedinicu za proces kretanja. Zato je potrebno čitanje i analiza. Nakon što generira bešumne točne izlaze na mikrokontroler (u ovom slučaju Magicbit (ESP32)). Ali postoji mnogo radova na strani mikrokontrolera koji uzimaju ta očitanja i izračunavaju kut. Jednostavno, koristili smo MPU6050 DMP biblioteku. Preuzmite ga gointom na sljedeću vezu.

github.com/ElectronicCats/mpu6050

Da biste instalirali biblioteke, u Arduino izborniku idite na Tools-> include library-> add.zip library i odaberite datoteku biblioteke koju ste preuzeli.

U kodu morate ispravno promijeniti kut zadane vrijednosti. Vrijednosti PID konstante razlikuju se od robota do robota. Dakle, pri ugađanju toga, prvo postavite vrijednosti Ki i Kd na nulu, a zatim povećavajte Kp dok ne postignete bolju brzinu reakcije. Više Kp uzrokuje veća prekoračenja. Zatim povećajte vrijednost Kd. Uvijek ga povećavajte u vrlo maloj količini. Ova vrijednost je općenito niska od ostalih vrijednosti. Sada povećavajte Ki dok ne dobijete vrlo dobru stabilnost.

Odaberite ispravan COM port i upišite ploču. otpremite kôd. Sada se možete igrati sa svojim DIY robotom.

Korak 5: Sheme

Sheme
Sheme

Korak 6: Kodirajte

#include

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = false; // postavljanje true ako je DMP init bio uspješan uint8_t mpuIntStatus; // sadrži stvarni bajt statusa prekida iz MPU -a uint8_t devStatus; // vraća status nakon svake operacije uređaja (0 = uspjeh,! 0 = greška) uint16_t packetSize; // očekivana veličina DMP paketa (zadano je 42 bajta) uint16_t fifoCount; // broj svih bajtova trenutno u FIFO uint8_t fifoBuffer [64]; // FIFO memorijski bafer Quaternion q; // [w, x, y, z] kvaterionski kontejner VectorFloat gravity; // [x, y, z] plovak gravitacije vektora ypr [3]; // [skretanje, nagib, kotrljanje] spremnik za skretanje/nagib/kotrljanje i vektor gravitacije dvostruki originalSetpoint = 172,5; dvostruka zadata vrijednost = originalnaSetpoint; dvostruko pomicanjeAngleOffset = 0,1; dvostruki ulaz, izlaz; int moveState = 0; double Kp = 23; // set P first double Kd = 0,8; // ova vrijednost je općenito mala double Ki = 300; // ova vrijednost bi trebala biti visoka za bolju stabilnost PID pid (& ulaz, & izlaz, & zadana vrijednost, Kp, Ki, Kd, DIRECT); // pid inicijalizuje int motL1 = 26; // 4 pina za motorni pogon int motL2 = 2; int motR1 = 27; int motR2 = 4; volatile bool mpuInterrupt = false; // označava da li je pin za prekid MPU -a otišao visoko void dmpDataReady () {mpuInterrupt = true; } void setup () {ledcSetup (0, 20000, 8); // pwm postavljanje ledcSetup (1, 20000, 8); ledcSetup (2, 20000, 8); ledcSetup (3, 20000, 8); ledcAttachPin (motL1, 0); // pinmode motora ledcAttachPin (motL2, 1); ledcAttachPin (motR1, 2); ledcAttachPin (motR2, 3); // pridruživanje I2C sabirnici (biblioteka I2Cdev to ne radi automatski) #iko I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin (); Wire.setClock (400000); // 400 kHz I2C sat. Komentirajte ovaj redak ako imate poteškoća pri sastavljanju #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400, istina); #endif Serial.println (F ("Inicijalizacija I2C uređaja …")); pinMode (14, INPUT); // inicirali serijsku komunikaciju // (115200 odabrano jer je potrebno za Teapot Demo izlaz, ali // ovisi o vama ovisno o vašem projektu) Serial.begin (9600); while (! Serijski); // čekamo Leonardovo nabrajanje, drugi nastavljaju odmah // inicijaliziramo uređaj Serial.println (F ("Inicijalizacija I2C uređaja …")); mpu.initialize (); // provjeravamo vezu Serial.println (F ("Testiranje veza uređaja …")); Serial.println (mpu.testConnection ()? F ("Veza MPU6050 uspješna"): F ("Veza MPU6050 nije uspjela")); // učitavanje i konfiguriranje DMP Serial.println (F ("Inicijalizacija DMP …")); devStatus = mpu.dmpInitialize (); // ovdje unosite vlastite pomake žiroa, prilagođene za minimalnu osjetljivost mpu.setXGyroOffset (220); mpu.setYGyroOffset (76); mpu.setZGyroOffset (-85); mpu.setZAccelOffset (1788); // 1688 tvornički zadani za moj testni čip // provjerite je li radio (vraća 0 ako je tako) if (devStatus == 0) {// uključite DMP, sada kada je spreman Serial.println (F ("Omogućavanje DMP … ")); mpu.setDMPEnabled (true); // omogućujemo otkrivanje prekida Arduino Serial.println (F ("Omogućavanje otkrivanja prekida (Arduino vanjski prekid 0) …")); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus (); // postavljamo zastavu DMP Ready tako da funkcija main loop () zna da je u redu koristiti je Serial.println (F ("DMP spreman! Čeka se prvi prekid …")); dmpReady = true; // dobiti očekivanu veličinu DMP paketa za kasnije poređenje packetSize = mpu.dmpGetFIFOPacketSize (); // postavljanje PID -a pid. SetMode (AUTOMATIC); pid. SetSampleTime (10); pid. SetOutputLimits (-255, 255); } else {// GREŠKA! // 1 = početno učitavanje memorije nije uspjelo // 2 = ažuriranje DMP konfiguracije nije uspjelo // (ako će se prekinuti, obično će kôd biti 1) Serial.print (F ("DMP inicijalizacija nije uspjela (kod")); Serijski. print (devStatus); Serial.println (F (")")); }} void loop () {// ako programiranje nije uspjelo, ne pokušavajte ništa učiniti ako se (! dmpReady) vrati; // čekamo na prekid MPU -a ili dodatne pakete koji su dostupni dok (! mpuInterrupt && fifoCount <packetSize) {pid. Compute (); // ovaj vremenski period se koristi za učitavanje podataka, pa ga možete koristiti za druge izračune motorSpeed (izlaz); } // resetirati zastavicu prekida i dobiti INT_STATUS bajt mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus (); // dobivamo trenutni broj FIFO fifoCount = mpu.getFIFOCount (); // provjeravamo ima li prelijevanja (to se nikada ne bi trebalo dogoditi osim ako je naš kod previše neučinkovit) if ((mpuIntStatus & 0x10) || fifoCount == 1024) {// reset kako bismo mogli nastaviti čisto mpu.resetFIFO (); Serial.println (F ("FIFO prelijevanje!")); // u suprotnom, provjerite ima li prekida za spremanje DMP podataka (to bi se trebalo često događati)} inače ako (mpuIntStatus & 0x02) {// sačeka ispravnu raspoloživu dužinu podataka, trebalo bi biti VRLO kratko čekanje ((fifoCount 1 paket dostupan // (ovo omogućava nam da odmah pročitamo više bez čekanja na prekid) fifoCount -= packetSize; mpu.dmpGetQuaternion (& q, fifoBuffer); mpu.dmpGetGravity (& gravity, & q); mpu.dmpGetYawPitchRoll (ypr, & q, & gravity); #IF LOG_ print ("ypr / t"); Serial.print (ypr [0] * 180/M_PI); // euler uglovi 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) {// smjer naprijed L2 = 0; L1 = abs (PWM); R2 = 0; R1 = abs (PWM); ako (L1> = 255) { L1 = R1 = 255;}} else {// smjer unatrag L1 = 0; L2 = abs (PWM); R1 = 0; R2 = abs (PWM); ako (L2> = 255) {L2 = R2 = 255; }} // motorni pogon ledcWrite (0, L1); ledcWrite (1, L2); ledcWrite (2, R1*0,97); // 0,97 je činjenica brzine ili, jer desni motor ima veću brzinu od lijevog motora, pa ga smanjujemo dok brzine motora ne budu jednake ledcWrite (3, R2*0,97);

}

Preporučuje se: