Inhoudsopgave:

Zelfbalancerende robot van Magicbit - Ajarnpa
Zelfbalancerende robot van Magicbit - Ajarnpa

Video: Zelfbalancerende robot van Magicbit - Ajarnpa

Video: Zelfbalancerende robot van Magicbit - Ajarnpa
Video: Крепость: щитом и мечом (мультфильм) 2024, Juli-
Anonim

Deze tutorial laat zien hoe je een zelfbalancerende robot maakt met behulp van het Magicbit-ontwikkelbord. We gebruiken magicbit als ontwikkelbord in dit project dat is gebaseerd op ESP32. Daarom kan elk ESP32-ontwikkelbord in dit project worden gebruikt.

Benodigdheden:

  • magie
  • Dubbele H-brug L298 motordriver
  • Lineaire regelaar (7805)
  • Lipo 7.4V 700mah batterij
  • Inertial Measurement Unit (IMU) (6 graden vrijheid)
  • tandwielmotoren 3V-6V DC

Stap 1: Verhaal

Verhaal
Verhaal
Verhaal
Verhaal

Hey jongens, vandaag zullen we in deze tutorial leren over een klein beetje complex ding. Dat gaat over een zelfbalancerende robot die Magicbit gebruikt met Arduino IDE. Dus laten we beginnen.

Laten we eerst eens kijken naar wat een zelfbalancerende robot is. Zelfbalancerende robot is een tweewielige robot. Het bijzondere is dat de robot zichzelf kan balanceren zonder externe ondersteuning. Als de stroom is ingeschakeld, gaat de robot rechtop staan en balanceert hij continu door middel van oscillerende bewegingen. Dus nu heb je alleen een ruw idee over een zelfbalancerende robot.

Stap 2: Theorie en methodologie

Theorie en methodologie
Theorie en methodologie

Om de robot in evenwicht te brengen, krijgen we eerst gegevens van een sensor om de robothoek naar het verticale vlak te meten. Voor dat doel hebben we MPU6050 gebruikt. Nadat we de gegevens van de sensor hebben gekregen, berekenen we de kanteling naar het verticale vlak. Als de robot in een rechte en gebalanceerde positie staat, is de kantelhoek nul. Zo niet, dan is de kantelhoek een positieve of negatieve waarde. Als de robot naar voren is gekanteld, moet de robot naar voren bewegen. Ook als de robot naar de andere kant is gekanteld, moet de robot in de omgekeerde richting bewegen. Als deze kantelhoek groot is, moet de reactiesnelheid hoog zijn. Omgekeerd is de kantelhoek laag, dan zou de reactiesnelheid laag moeten zijn. Om dit proces te beheersen, gebruikten we een specifieke stelling genaamd PID. PID is een controlesysteem dat vroeger veel processen regelde. PID staat voor 3 processen.

  • P-proportioneel
  • I-integraal
  • D- afgeleide

Elk systeem heeft input en output. Op dezelfde manier heeft dit besturingssysteem ook enige input. In dit controlesysteem is dat de afwijking van de stabiele toestand. Dat noemden we een fout. In onze robot is de fout de kantelhoek vanuit het verticale vlak. Als de robot in evenwicht is, is de kantelhoek nul. De foutwaarde zal dus nul zijn. Daarom is de output van het PID-systeem nul. Dit systeem omvat drie afzonderlijke wiskundige processen.

De eerste is de vermenigvuldigingsfout van numerieke versterking. Deze winst wordt meestal Kp genoemd

P=fout*Kp

De tweede is om de integraal van de fout in het tijdsdomein te genereren en deze te vermenigvuldigen met een deel van de winst. Deze winst genoemd als Ki

I= Integraal(fout)*Ki

De derde is de afgeleide van de fout in het tijdsdomein en vermenigvuldig deze met een bepaalde hoeveelheid winst. Deze winst wordt genoemd als Kd

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

Na het toevoegen van bovenstaande bewerkingen krijgen we onze uiteindelijke uitvoer

UITGANG=P+I+D

Vanwege het P-deel kan de robot een stabiele positie krijgen die evenredig is met de afwijking. I deel berekent het gebied van fout versus tijdgrafiek. Dus het probeert de robot altijd nauwkeurig in een stabiele positie te krijgen. D-deel meet de helling in tijd versus foutgrafiek. Als de fout toeneemt, is deze waarde positief. Als de fout kleiner wordt, is deze waarde negatief. Daarom zal de reactiesnelheid afnemen wanneer de robot naar een stabiele positie wordt verplaatst en dit zal helpen om onnodige overshoots te verwijderen. U kunt meer te weten komen over de PID-theorie via deze onderstaande link.

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

De uitvoer van de PID-functie is beperkt tot een bereik van 0-255 (8 bit PWM-resolutie) en dat zal als PWM-signaal naar motoren worden gevoerd.

Stap 3: Hardware-installatie

apparatuur installatie
apparatuur installatie

Dit is het hardware-instellingsgedeelte. Het ontwerp van de robot is afhankelijk van jou. Toen je het lichaam van de robot ontwierp, moet je het symmetrisch beschouwen rond de verticale as die in de motoras ligt. Het batterijpakket hieronder. Hierdoor is de robot gemakkelijk te balanceren. In ons ontwerp bevestigen we het Magicbit-bord verticaal aan het lichaam. We gebruikten twee 12V reductiemotoren. Maar je kunt alle soorten reductiemotoren gebruiken. dat is afhankelijk van de afmetingen van uw robot.

Als we het hebben over het circuit, wordt het aangedreven door een 7,4 V Lipo-batterij. Magicbit gebruikte 5V voor de voeding. Daarom hebben we de 7805-regelaar gebruikt om de batterijspanning te regelen naar 5V. In latere versies van Magicbit is die regelaar niet nodig. Omdat het tot 12V aanstuurt. Wij leveren direct 7.4V voor motorbestuurder.

Sluit alle componenten aan volgens onderstaand schema.

Stap 4: Software-installatie

In de code hebben we de PID-bibliotheek gebruikt om de PID-uitvoer te berekenen.

Ga naar de volgende link om het te downloaden.

www.arduinolibraries.info/libraries/pid

Download de nieuwste versie ervan.

Om betere sensormetingen te krijgen, hebben we de DMP-bibliotheek gebruikt. DMP staat voor Digital Motion Process. Dit is een ingebouwde functie van de MPU6050. Deze chip heeft een geïntegreerde bewegingsverwerkingseenheid. Dus het vereist lezen en analyseren. Nadat het geruisloze nauwkeurige outputs naar de microcontroller genereert (in dit geval Magicbit (ESP32)). Maar er zijn veel werken aan de kant van de microcontroller om die metingen te doen en de hoek te berekenen. Dus om simpelweg dat we de MPU6050 DMP-bibliotheek gebruikten. Download het door naar de volgende link te gaan.

github.com/ElectronicCats/mpu6050

Om de bibliotheken te installeren, gaat u in het Arduino-menu naar tools-> include library->add.zip-bibliotheek en selecteert u het bibliotheekbestand dat u hebt gedownload.

In de code moet u de gewenste hoek correct wijzigen. De PID-constante waarden verschillen van robot tot robot. Dus om dat af te stemmen, stelt u eerst de Ki- en Kd-waarden in op nul en verhoogt u vervolgens Kp totdat u een betere reactiesnelheid krijgt. Meer Kp zorgt voor meer overshoots. Verhoog vervolgens de Kd-waarde. Verhoog het met altijd in een zeer kleine hoeveelheid. Deze waarde is over het algemeen laag dan andere waarden. Verhoog nu de Ki totdat je een zeer goede stabiliteit hebt.

Selecteer de juiste COM-poort en bordtype de. de code uploaden. Nu kun je spelen met je DIY-robot.

Stap 5: Schema's

Schema's
Schema's

Stap 6: Coderen

#erbij betrekken

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = false; // stel waar in als DMP init succesvol was uint8_t mpuIntStatus; // bevat actuele interruptstatusbyte van MPU uint8_t devStatus; // retourstatus na elke apparaatbewerking (0 = geslaagd, !0 = fout) uint16_t packetSize; // verwachte DMP-pakketgrootte (standaard is 42 bytes) uint16_t fifoCount; // telling van alle bytes die momenteel in FIFO zijn uint8_t fifoBuffer [64]; // FIFO-opslagbuffer Quaternion q; // [w, x, y, z] quaternioncontainer VectorFloat-zwaartekracht; // [x, y, z] zwaartekracht vector float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container en zwaartekracht vector dubbel originalSetpoint = 172.5; dubbel instelpunt = origineel instelpunt; dubbele bewegendeAngleOffset = 0.1; dubbele invoer, uitvoer; int moveState=0; dubbele Kp = 23;//set P eerste dubbele Kd = 0,8;//deze waarde over het algemeen kleine dubbele Ki = 300;//deze waarde moet hoog zijn voor een betere stabiliteit PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);//pid initialiseren int motL1=26;//4 pinnen voor motoraandrijving int motL2=2; int motR1=27; int motR2=4; vluchtige bool mpuInterrupt = false; // geeft aan of de MPU-interrupt-pin high is geworden 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);//pinmode van motoren ledcAttachPin(motL2, 1); ledcAttachPin(motR1, 2); ledcAttachPin(motR2, 3); // join I2C bus (I2Cdev bibliotheek doet dit niet automatisch) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); Draad.setClock(400000); // 400 kHz I2C-klok. Geef commentaar op deze regel als u compilatieproblemen heeft #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif Serial.println(F("I2C-apparaten initialiseren…")); pinMode (14, INGANG); // initialiseer seriële communicatie // (115200 gekozen omdat het vereist is voor uitvoer van theepotdemo's, maar het is echt aan jou, afhankelijk van je project) Serial.begin (9600); terwijl (!Serial); // wacht op Leonardo-opsomming, anderen gaan onmiddellijk verder // initialiseer apparaat Serial.println(F ("Initialiseren van I2C-apparaten…")); mpu.initialiseren(); // verifieer verbinding Serial.println (F ("Testapparaatverbindingen …")); Serial.println(mpu.testConnection() ? F("MPU6050 verbinding succesvol"): F("MPU6050 verbinding mislukt")); // laad en configureer de DMP Serial.println(F("Initializing DMP…")); devStatus = mpu.dmpInitialize(); // geef hier uw eigen gyro-offsets op, geschaald voor minimale gevoeligheid mpu.setXGyroOffset(220); mpu.setYGyroOffset(76); mpu.setZGyroOffset(-85); mpu.setZAccelOffset (1788); // 1688 fabrieksinstelling voor mijn testchip // zorg ervoor dat het werkte (retourneert 0 als dat zo is) if (devStatus == 0) { // zet de DMP aan, nu deze klaar is Serial.println(F ("DMP inschakelen … ")); mpu.setDMPEnabled(true); // Arduino-interruptdetectie inschakelen Serial.println (F ("Interruptdetectie inschakelen (Arduino externe interrupt 0) …")); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus(); // stel onze DMP Ready-vlag zo in dat de hoofdlus()-functie weet dat het goed is om het te gebruiken Serial.println(F ("DMP ready! Waiting for first interrupt…"")); dmpReady = waar; // haal de verwachte DMP-pakketgrootte op voor latere vergelijking packetSize = mpu.dmpGetFIFOPacketSize(); //setup PID pid. SetMode (AUTOMATISCH); pid. SetSampleTime(10); pid. SetOutputLimits(-255, 255); } anders { // FOUT! // 1 = initiële geheugenbelasting mislukt // 2 = DMP-configuratie-updates mislukt // (als het kapot gaat, is de code meestal 1) Serial.print(F ("DMP-initialisatie mislukt (code")); Serial. print(devStatus);Serial.println(F(")")); } } void loop() { // als het programmeren is mislukt, probeer dan niets te doen als (!dmpReady) terugkeert; // wacht op MPU-interrupt of extra pakket(ten) beschikbaar terwijl (!mpuInterrupt && fifoCount <packetSize) {pid. Compute();//deze tijdsperiode wordt gebruikt om gegevens te laden, dus u kunt dit gebruiken voor andere berekeningen motorSpeed(uitgang); } // reset de interruptvlag en krijg INT_STATUS byte mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus(); // haal de huidige FIFO-telling op fifoCount = mpu.getFIFOCount (); // controleer op overloop (dit zou nooit mogen gebeuren tenzij onze code te inefficiënt is) if ((mpuIntStatus & 0x10) || fifoCount == 1024) { // reset zodat we netjes kunnen doorgaan mpu.resetFIFO(); Serial.println(F("FIFO-overloop!")); // controleer anders op DMP data ready interrupt (dit zou vaak moeten gebeuren) } else if (mpuIntStatus & 0x02) { // wacht op de juiste beschikbare datalengte, zou een ZEER korte wachttijd moeten zijn terwijl (fifoCount 1 pakket beschikbaar // (dit laten we meteen meer lezen zonder te wachten op een interrupt) 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 hoeken 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){//forward richting L2=0; L1=abs(PWM); R2=0; R1=abs(PWM); if(L1>=255){ L1=R1=255;}} else {//achteruit L1=0; L2=abs(PWM); R1=0; R2=abs(PWM); if(L2>=255){ L2=R2=255; } } //motoraandrijving ledcWrite(0, L1); ledcWrite(1, L2); ledcWrite(2, R1*0.97);//0.97 is snelheidsfeit of, omdat de rechtermotor een hogere snelheid heeft dan de linkermotor, verlagen we deze totdat de motorsnelheden gelijk zijn ledcWrite (3, R2*0.97);

}

Aanbevolen: