Taula de continguts:

Robot autoequilibrant de Magicbit: 6 passos
Robot autoequilibrant de Magicbit: 6 passos

Vídeo: Robot autoequilibrant de Magicbit: 6 passos

Vídeo: Robot autoequilibrant de Magicbit: 6 passos
Vídeo: Como funciona um Overboard? (Parte 1) 2024, Desembre
Anonim

Aquest tutorial mostra com fer un robot d’equilibri automàtic mitjançant el tauler de desenvolupament Magicbit. Estem utilitzant Magicbit com a tauler de desenvolupament d’aquest projecte basat en ESP32. Per tant, qualsevol placa de desenvolupament ESP32 es pot utilitzar en aquest projecte.

Subministraments:

  • Magicbit
  • Controlador de motor L298 de pont H doble
  • Regulador lineal (7805)
  • Bateria Lipo 7.4V 700mah
  • Unitat de mesura inercial (IMU) (6 graus de llibertat)
  • motors d'engranatges 3V-6V DC

Pas 1: història

Història
Història
Història
Història

Ei, nois, avui en aquest tutorial aprendrem coses poc complexes. Es tracta d’un robot d’equilibri automàtic que utilitza Magicbit amb Arduino IDE. Comencem doncs.

En primer lloc, vegem què és el robot d’equilibri automàtic. El robot d’equilibri automàtic és un robot de dues rodes. La característica especial és que el robot pot equilibrar-se sense utilitzar cap suport extern. Quan la potència estigui en funcionament, el robot es mantindrà dret i es balancejarà contínuament mitjançant moviments d'oscil·lació. Per tant, ara teniu alguna idea aproximada sobre el robot d’equilibri automàtic.

Pas 2: teoria i metodologia

Teoria i metodologia
Teoria i metodologia

Per equilibrar el robot, primer obtenim dades d'algun sensor per mesurar l'angle del robot al pla vertical. Amb aquest propòsit, hem utilitzat MPU6050. Després d’obtenir les dades del sensor, calculem la inclinació al pla vertical. Si el robot està en posició recta i equilibrada, l’angle d’inclinació és zero. Si no, l’angle d’inclinació és un valor positiu o negatiu. Si el robot està inclinat cap al costat frontal, el robot hauria de passar a la direcció frontal. També si el robot està inclinat cap al revés, el robot hauria de moure’s cap a la direcció inversa. Si aquest angle d'inclinació és alt, la velocitat de resposta hauria de ser alta. A l’inrevés, l’angle d’inclinació és baix i la velocitat de reacció és baixa. Per controlar aquest procés hem utilitzat el teorema específic anomenat PID. El PID és un sistema de control que s’utilitzava per controlar molts processos. PID significa 3 processos.

  • P- proporcional
  • I- integral
  • D- derivada

Tots els sistemes tenen entrada i sortida. De la mateixa manera, aquest sistema de control també té certa entrada. En aquest sistema de control es tracta de la desviació de l’estat estable. Vam dir-ho com a error. Al nostre robot, l’error és l’angle d’inclinació respecte al pla vertical. Si el robot està equilibrat, l'angle d'inclinació és zero. Per tant, el valor de l’error serà zero. Per tant, la sortida del sistema PID és zero. Aquest sistema inclou tres processos matemàtics separats.

El primer és multiplicar l’error del guany numèric. Aquest guany se sol anomenar Kp

P = error * Kp

El segon és generar la integral de l'error en el domini temporal i multiplicar-lo a partir d'alguns guanys. Aquest guany s'anomena Ki

I = Integral (error) * Ki

El tercer és derivat de l’error en el domini temporal i multiplica’l per una certa quantitat de guany. Aquest guany s'anomena Kd

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

Després d'afegir les operacions anteriors obtenim la nostra sortida final

SORTIDA = P + I + D

A causa de la peça P, el robot pot obtenir una posició estable que sigui proporcional a la desviació. I part calcula l'àrea d'error vs gràfic de temps. Per tant, intenta que el robot tingui una posició estable sempre amb precisió. La part D mesura el pendent en el temps vs el gràfic d'error. Si l'error augmenta, aquest valor serà positiu. Si l'error disminueix, aquest valor és negatiu. Per això, quan el robot es mou a una posició estable, la velocitat de reacció es reduirà i això ajudarà a eliminar els desbordaments innecessaris. Podeu obtenir més informació sobre la teoria PID en aquest enllaç que es mostra a continuació.

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

La sortida de la funció PID té un límit de 0-255 (resolució PWM de 8 bits) i s’alimentarà als motors com a senyal PWM.

Pas 3: Configuració del maquinari

Configuració del maquinari
Configuració del maquinari

Ara aquesta és la part de configuració del maquinari. El disseny del robot depèn de vosaltres. Quan heu dissenyat el cos del robot, heu de considerar-lo simètric respecte a l'eix vertical que es troba en l'eix del motor. El paquet de bateries situat a sota. Per tant, el robot és fàcil d’equilibrar. En el nostre disseny fixem la placa Magicbit verticalment al cos. Hem utilitzat dos motors d'engranatges de 12V. Però podeu utilitzar qualsevol tipus de motors d'engranatges. això depèn de les dimensions del vostre robot.

Quan parlem del circuit, funciona amb una bateria Lipo de 7,4 V. Magicbit va utilitzar 5V per alimentar-se. Per això, vam utilitzar el regulador 7805 per regular el voltatge de la bateria a 5V. En versions posteriors de Magicbit no es necessita aquest regulador. Perquè alimenta fins a 12V. Subministrem directament 7,4 V per al conductor del motor.

Connecteu tots els components segons el diagrama següent.

Pas 4: Configuració del programari

Al codi hem utilitzat la biblioteca PID per calcular la sortida PID.

Aneu al següent enllaç per descarregar-lo.

www.arduinolibraries.info/libraries/pid

Baixeu-ne l'última versió.

Per obtenir millors lectures de sensors, hem utilitzat la biblioteca DMP. DMP significa procés de moviment digital. Aquesta és una funció incorporada de MPU6050. Aquest xip té unitat de procés de moviment integrada. Per tant, cal llegir i analitzar. Després, genera sortides precises i silencioses al microcontrolador (en aquest cas Magicbit (ESP32)). Però hi ha moltes obres en el costat del microcontrolador per fer aquestes lectures i calcular l’angle. Simplement, hem utilitzat la biblioteca MPU6050 DMP. Baixeu-lo per goint al següent enllaç.

github.com/ElectronicCats/mpu6050

Per instal·lar les biblioteques, al menú Arduino aneu a tools-> include library-> add.zip library i seleccioneu el fitxer de biblioteca que heu descarregat.

Al codi haureu de canviar correctament l'angle de consigna. Els valors de la constant PID són diferents d’un robot a un altre. Així, en sintonitzar això, primer estableix els valors de Ki i Kd a zero i després augmenta Kp fins a obtenir una velocitat de reacció millor. Hi ha més Kp que provoquen més superacions. A continuació, augmenteu el valor de Kd. Augmenteu-lo sempre en molt poca quantitat. Aquest valor és generalment baix que altres valors. Ara augmenti el Ki fins que tingui una estabilitat molt bona.

Seleccioneu el port COM correcte i escriviu la placa. pengeu el codi. Ara podeu jugar amb el vostre robot de bricolatge.

Pas 5: esquemes

Esquemes
Esquemes

Pas 6: Codi

#incloure

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = fals; // defineix true si DMP init va tenir èxit uint8_t mpuIntStatus; // manté el byte d'estat de la interrupció real de la MPU uint8_t devStatus; // torna l'estat després de cada operació del dispositiu (0 = èxit,! 0 = error) uint16_t paquetSize; // mida prevista del paquet DMP (per defecte és de 42 bytes) uint16_t fifoCount; // recompte de tots els bytes actualment a FIFO uint8_t fifoBuffer [64]; // Buffer d'emmagatzematge FIFO Quaternion q; // [w, x, y, z] contenidor de quaternió Gravetat VectorFloat; // [x, y, z] vector de gravetat flotant ypr [3]; // [yaw, pitch, roll] yaw / pitch / roll container i gravity vector double OriginalSetpoint = 172,5; doble consigna = originalSetpoint; doble movimentAngleOffset = 0,1; entrada doble, sortida; int moveState = 0; doble Kp = 23; // establir P primer doble Kd = 0,8; // aquest valor generalment petit doble Ki = 300; // aquest valor hauria de ser alt per a una millor estabilitat PID pid (& entrada, & sortida, & setpoint, Kp, Ki, Kd, DIRECT); // pid inicialitza int motL1 = 26; // 4 pins per a accionament del motor int motL2 = 2; int motR1 = 27; int motR2 = 4; bool volàtil mpuInterrupt = fals; // indica si el pin d'interrupció de la MPU s'ha anotat alt void 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); // mode pin dels motors ledcAttachPin (motL2, 1); ledcAttachPin (motR1, 2); ledcAttachPin (motR2, 3); // unir-se al bus I2C (la biblioteca I2Cdev no ho fa automàticament) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin (); Wire.setClock (400000); // Rellotge I2C de 400 kHz. Comenteu aquesta línia si teniu dificultats de compilació #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400, true); #endif Serial.println (F ("Inicialització de dispositius I2C …")); pinMode (14, INPUT); // inicialitzar la comunicació serial // (escollit 115200 perquè és necessari per a la sortida de demostració de Teapot, però // depèn del vostre projecte) Serial.begin (9600); mentre que (! sèrie); // espera l'enumeració de Leonardo, altres continuen immediatament // inicialitza el dispositiu Serial.println (F ("Inicialització de dispositius I2C …")); mpu.initialize (); // verificar la connexió Serial.println (F ("Prova de connexions del dispositiu …")); Serial.println (mpu.testConnection ()? F ("connexió MPU6050 correcta"): F ("connexió MPU6050 fallida")); // carregar i configurar el DMP Serial.println (F ("Inicialització de DMP …")); devStatus = mpu.dmpInitialize (); // proporcioneu aquí les vostres pròpies compensacions giroscòpiques, ajustades per a la sensibilitat mínima mpu.setXGyroOffset (220); mpu.setYGyroOffset (76); mpu.setZGyroOffset (-85); mpu.setZAccelOffset (1788); // 1688 predeterminat de fàbrica per al meu xip de prova // assegureu-vos que funcionés (retorna 0 si és així) si (devStatus == 0) {// activeu el DMP, ara que està llest Serial.println (F ("Activació de DMP … ")); mpu.setDMPEnabled (cert); // habilita la detecció d'interrupcions Arduino Serial.println (F ("Activació de la detecció d'interrupcions (interrupció externa Arduino 0) …")); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus (); // configureu el nostre indicador DMP Ready perquè la funció loop principal () sàpiga que està bé utilitzar-la Serial.println (F ("DMP llest! Esperant la primera interrupció …")); dmpReady = cert; // obtenir la mida esperada del paquet DMP per a una comparació posterior packetSize = mpu.dmpGetFIFOPacketSize (); // setup PID pid. SetMode (AUTOMÀTIC); pid. SetSampleTime (10); pid. SetOutputLimits (-255, 255); } else {// ERROR! // 1 = Ha fallat la càrrega inicial de la memòria // 2 = Ha fallat l'actualització de la configuració de DMP // (si es trencarà, normalment el codi serà 1) Serial.print (F ("L'inicialització de DMP ha fallat (codi")); Sèrie. print (devStatus); Serial.println (F (")")); }} void loop () {// si la programació ha fallat, no intenteu fer res si (! dmpReady) torna; // espereu la interrupció de la MPU o els paquets addicionals disponibles mentre (! mpuInterrupt && fifoCount <packetSize) {pid. Compute (); // aquest període de temps s’utilitza per carregar dades, de manera que podeu utilitzar-lo per a altres càlculs motorSpeed (sortida); } // restableix el senyal d'interrupció i obtén INT_STATUS byte mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus (); // obtenir el recompte FIFO actual fifoCount = mpu.getFIFOCount (); // comproveu si hi ha desbordament (això no hauria de passar mai tret que el nostre codi sigui massa ineficient) if ((mpuIntStatus & 0x10) || fifoCount == 1024) {// reset perquè puguem continuar net mpu.resetFIFO (); Serial.println (F ("FIFO overflow!")); // en cas contrari, comproveu si hi ha una interrupció a punt de dades DMP (això hauria de passar amb freqüència)} else if (mpuIntStatus & 0x02) {// espereu la durada correcta de les dades disponibles, hauria de ser MOLT curta espera mentre (fifoCount 1 paquet disponible // (això ens permet llegir més immediatament sense esperar una interrupció) 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) {// direcció cap endavant L2 = 0; L1 = abs (PWM); R2 = 0; R1 = abs (PWM); if (L1> = 255) { L1 = R1 = 255;}} else {// direcció enrere L1 = 0; L2 = abs (PWM); R1 = 0; R2 = abs (PWM); if (L2> = 255) {L2 = R2 = 255; }} // unitat de motor ledcWrite (0, L1); ledcWrite (1, L2); ledcWrite (2, R1 * 0,97); // 0,97 és un fet de velocitat o bé, perquè el motor dret té una velocitat elevada que el motor esquerre, de manera que el reduïm fins que les velocitats del motor siguin iguals ledcWrite (3, R2 * 0,97);

}

Recomanat: