Table des matières:

Robot auto-équilibrant de Magicbit : 6 étapes
Robot auto-équilibrant de Magicbit : 6 étapes

Vidéo: Robot auto-équilibrant de Magicbit : 6 étapes

Vidéo: Robot auto-équilibrant de Magicbit : 6 étapes
Vidéo: Карл Фристон: «Мета» принцип свободной энергии [ЧАСТЬ 1!] 2024, Juillet
Anonim

Ce tutoriel montre comment créer un robot auto-équilibré à l'aide de la carte de développement Magicbit. Nous utilisons magicbit comme carte de développement dans ce projet basé sur ESP32. Par conséquent, n'importe quelle carte de développement ESP32 peut être utilisée dans ce projet.

Fournitures:

  • peu magique
  • Pilote de moteur double pont en H L298
  • Régulateur linéaire (7805)
  • Batterie Lipo 7.4V 700mah
  • Unité de mesure inertielle (IMU) (6 degrés de liberté)
  • moteurs à engrenages 3V-6V DC

Étape 1: Histoire

Histoire
Histoire
Histoire
Histoire

Hé les gars, aujourd'hui, dans ce tutoriel, nous allons en apprendre davantage sur des choses un peu complexes. Il s'agit d'un robot à équilibrage automatique utilisant Magicbit avec Arduino IDE. Alors commençons.

Tout d'abord, regardons ce qu'est un robot auto-équilibré. Le robot auto-équilibré est un robot à deux roues. La particularité est que le robot peut s'équilibrer sans utiliser aucun support externe. Lorsque le courant est allumé, le robot se lève et s'équilibre en continu en utilisant des mouvements d'oscillation. Alors maintenant, vous avez une idée approximative du robot auto-équilibré.

Étape 2: Théorie et méthodologie

Théorie et méthodologie
Théorie et méthodologie

Pour équilibrer le robot, nous obtenons d'abord des données d'un capteur pour mesurer l'angle du robot par rapport au plan vertical. Pour cela, nous avons utilisé le MPU6050. Après avoir obtenu les données du capteur, nous calculons l'inclinaison par rapport au plan vertical. Si le robot est en position droite et équilibrée, l'angle d'inclinaison est nul. Sinon, l'angle d'inclinaison est une valeur positive ou négative. Si le robot est incliné vers l'avant, alors le robot doit se déplacer vers l'avant. De plus, si le robot est incliné vers l'arrière, le robot doit se déplacer dans la direction inverse. Si cet angle d'inclinaison est élevé, la vitesse de réponse doit être élevée. Vice versa, l'angle d'inclinaison est faible, alors la vitesse de réaction doit être faible. Pour contrôler ce processus, nous avons utilisé un théorème spécifique appelé PID. PID est un système de contrôle utilisé pour contrôler de nombreux processus. PID signifie 3 processus.

  • P- proportionnel
  • I- intégrale
  • D- dérivée

Chaque système a une entrée et une sortie. De la même manière, ce système de contrôle a également une certaine entrée. Dans ce système de contrôle, c'est l'écart par rapport à l'état stable. Nous avons appelé cela une erreur. Dans notre robot, l'erreur est l'angle d'inclinaison par rapport au plan vertical. Si le robot est équilibré, l'angle d'inclinaison est nul. La valeur d'erreur sera donc zéro. Par conséquent, la sortie du système PID est nulle. Ce système comprend trois processus mathématiques distincts.

Le premier est l'erreur de multiplication à partir du gain numérique. Ce gain est généralement appelé Kp

P=erreur*Kp

La deuxième consiste à générer l'intégrale de l'erreur dans le domaine temporel et à la multiplier à partir d'une partie du gain. Ce gain appelé Ki

I= Intégrale (erreur)*Ki

La troisième est dérivée de l'erreur dans le domaine temporel et multipliée par une certaine quantité de gain. Ce gain est appelé Kd

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

Après avoir ajouté les opérations ci-dessus, nous obtenons notre sortie finale

SORTIE=P+I+D

En raison de la partie P, le robot peut obtenir une position stable proportionnelle à la déviation. I part calcule la zone d'erreur en fonction du graphique du temps. Il essaie donc d'amener le robot dans une position stable toujours avec précision. La partie D mesure la pente dans le temps en fonction du graphique d'erreur. Si l'erreur augmente, cette valeur est positive. Si l'erreur diminue, cette valeur est négative. Pour cette raison, lorsque le robot se déplace vers une position stable, la vitesse de réaction sera réduite et cela aidera à éliminer les dépassements inutiles. Vous pouvez en savoir plus sur la théorie PID à partir de ce lien ci-dessous.

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

La sortie de la fonction PID est limitée à la plage 0-255 (résolution PWM 8 bits) et qui alimentera les moteurs sous forme de signal PWM.

Étape 3: configuration du matériel

configuration materielle
configuration materielle

Maintenant, c'est la partie configuration matérielle. La conception du robot dépend de vous. Lorsque vous avez conçu le corps du robot, vous devez le considérer symétrique par rapport à l'axe vertical qui se trouve dans l'axe moteur. La batterie située ci-dessous. Par conséquent, le robot est facile à équilibrer. Dans notre conception, nous fixons la carte Magicbit verticalement au corps. Nous avons utilisé deux motoréducteurs 12V. Mais vous pouvez utiliser n'importe quel type de motoréducteur. cela dépend des dimensions de votre robot.

Lorsque nous discutons du circuit, il est alimenté par une batterie Lipo de 7,4 V. Magicbit a utilisé 5V pour l'alimentation. C'est pourquoi nous avons utilisé le régulateur 7805 pour réguler la tension de la batterie à 5V. Dans les versions ultérieures de Magicbit, ce régulateur n'est pas nécessaire. Parce qu'il alimente jusqu'à 12V. Nous fournissons directement 7.4V pour le pilote de moteur.

Connectez tous les composants selon le schéma ci-dessous.

Étape 4: Configuration du logiciel

Dans le code, nous avons utilisé la bibliothèque PID pour calculer la sortie PID.

Allez sur le lien suivant pour le télécharger.

www.arduinolibraries.info/libraries/pid

Téléchargez la dernière version de celui-ci.

Pour obtenir de meilleures lectures de capteur, nous avons utilisé la bibliothèque DMP. DMP signifie processus de mouvement numérique. Il s'agit d'une fonction intégrée du MPU6050. Cette puce a une unité de traitement de mouvement intégrée. Il faut donc lire et analyser. Après cela, il génère des sorties précises et silencieuses vers le microcontrôleur (dans ce cas, Magicbit (ESP32)). Mais il y a beaucoup de travaux côté microcontrôleur pour prendre ces lectures et calculer l'angle. Donc pour simplement dire que nous avons utilisé la bibliothèque DMP MPU6050. Téléchargez-le en cliquant sur le lien suivant.

github.com/ElectronicCats/mpu6050

Pour installer les bibliothèques, dans le menu Arduino, accédez à outils-> inclure la bibliothèque-> bibliothèque add.zip et sélectionnez le fichier de bibliothèque que vous avez téléchargé.

Dans le code, vous devez modifier correctement l'angle de consigne. Les valeurs constantes PID sont différentes d'un robot à l'autre. Donc, pour régler cela, définissez d'abord les valeurs Ki et Kd à zéro, puis augmentez Kp jusqu'à ce que vous obteniez une meilleure vitesse de réaction. Plus de Kp entraîne plus de dépassements. Augmentez ensuite la valeur Kd. Augmentez-le de toujours en très petite quantité. Cette valeur est généralement plus faible que les autres valeurs. Augmentez maintenant le Ki jusqu'à obtenir une très bonne stabilité.

Sélectionnez le bon port COM et saisissez le type de carte. télécharger le code. Vous pouvez maintenant jouer avec votre robot DIY.

Étape 5: Schémas

Schémas
Schémas

Étape 6: Coder

#comprendre

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = false; // défini sur true si l'initialisation DMP a réussi uint8_t mpuIntStatus; // contient l'octet d'état d'interruption réel du MPU uint8_t devStatus; // renvoie l'état après chaque opération de périphérique (0 = succès, !0 = erreur) uint16_t packetSize; // taille de paquet DMP attendue (la valeur par défaut est de 42 octets) uint16_t fifoCount; // compte de tous les octets actuellement dans FIFO uint8_t fifoBuffer[64]; // Tampon de stockage FIFO Quaternion q; // [w, x, y, z] conteneur de quaternions VectorFloat Gravity; // [x, y, z] vecteur de gravité float ypr[3]; // [lacet, tangage, roulis] conteneur lacet/tangage/roulis et vecteur de gravité double originalSetpoint = 172,5; double point de consigne = point de consigne d'origine; double MovingAngleOffset = 0,1; double entrée, sortie; int moveState=0; double Kp = 23;//set P premier double Kd = 0.8;//cette valeur généralement petite double Ki = 300;//cette valeur doit être élevée pour une meilleure stabilité PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);//pid initialize int motL1=26;//4 pins for motor drive int motL2=2; int motR1=27; int motR2=4; volatile bool mpuInterrupt = false; // indique si la broche d'interruption MPU est devenue haute 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 des moteurs ledcAttachPin(motL2, 1); ledcAttachPin(motR1, 2); ledcAttachPin(motR2, 3); // rejoindre le bus I2C (la bibliothèque I2Cdev ne le fait pas automatiquement) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); Wire.setClock(400000); // Horloge I2C 400 kHz. Commentez cette ligne si vous rencontrez des difficultés de compilation #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif Serial.println(F("Initialisation des périphériques I2C…")); pinMode(14, ENTRÉE); // initialiser la communication série // (115200 choisi car il est requis pour la sortie Teapot Demo, mais c'est // vraiment à vous de décider selon votre projet) Serial.begin(9600); tandis que (!Série); // attendre l'énumération Leonardo, les autres continuent immédiatement // initialiser le périphérique Serial.println(F("Initializing I2C devices…")); mpu.initialize(); // vérifier la connexion Serial.println(F("Testing device connections…")); Serial.println(mpu.testConnection() ? F("Connexion MPU6050 réussie"): F("Connexion MPU6050 échouée")); // charge et configure le DMP Serial.println(F("Initializing DMP…")); devStatus = mpu.dmpInitialize(); // fournissez vos propres décalages de gyroscope ici, mis à l'échelle pour une sensibilité minimale mpu.setXGyroOffset(220); mpu.setYGyroOffset(76); mpu.setZGyroOffset(-85); mpu.setZAccelOffset(1788); // 1688 par défaut d'usine pour ma puce de test // assurez-vous que cela a fonctionné (renvoie 0 si oui) if (devStatus == 0) { // activez le DMP, maintenant qu'il est prêt Serial.println(F("Enabling DMP… ")); mpu.setDMPEnabled(true); // activer la détection d'interruption Arduino Serial.println(F("Activation de la détection d'interruption (interruption externe Arduino 0)…")); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus(); // définit notre indicateur DMP Ready pour que la fonction principale loop() sache qu'il est possible de l'utiliser Serial.println(F("DMP ready! Waiting for first interrupt…")); dmpReady = vrai; // obtenir la taille de paquet DMP attendue pour une comparaison ultérieure packetSize = mpu.dmpGetFIFOPacketSize(); //configuration du PID pid. SetMode(AUTOMATIC); pid. SetSampleTime(10); pid. SetOutputLimits(-255, 255); } else { // ERREUR ! // 1 = échec du chargement initial de la mémoire // 2 = échec des mises à jour de la configuration DMP // (en cas de panne, le code sera généralement 1) Serial.print(F("DMP Initialization failed (code ")); Serial. print(devStatus);Série.println(F(")")); } } void loop() { // si la programmation a échoué, n'essayez pas de faire quoi que ce soit si (!dmpReady) return; // attend l'interruption du MPU ou des paquets supplémentaires disponibles pendant que (!mpuInterrupt && fifoCount < packetSize) { pid. Compute();//cette période de temps est utilisée pour charger les données, vous pouvez donc l'utiliser pour d'autres calculs motorSpeed(sortir); } // réinitialiser l'indicateur d'interruption et obtenir l'octet INT_STATUS mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus(); // obtenir le nombre FIFO actuel fifoCount = mpu.getFIFOCount(); // vérifier le débordement (cela ne devrait jamais se produire sauf si notre code est trop inefficace) if ((mpuIntStatus & 0x10) || fifoCount == 1024) { // réinitialiser afin que nous puissions continuer proprement mpu.resetFIFO(); Serial.println(F("débordement FIFO !")); // sinon, vérifiez l'interruption de disponibilité des données DMP (cela devrait arriver fréquemment) } else if (mpuIntStatus & 0x02) { // attend la longueur de données disponible correcte, devrait être une attente TRÈS courte pendant que (fifoCount 1 paquet disponible // (ceci permet de lire immédiatement la suite sans attendre une interruption) 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);//angles d'euler 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){//direction avant L2=0; L1=abs(PWM); R2=0; R1=abs(PWM); if(L1>=255){ L1=R1=255; } } else {//direction arrière L1=0; L2=abs(PWM); R1=0; R2=abs(PWM); if(L2>=255){ L2=R2=255; } } //entraînement du moteur ledcWrite(0, L1); ledcWrite(1, L2); ledcWrite(2, R1*0.97);//0.97 est le fait de vitesse ou, parce que le moteur droit a une vitesse élevée par rapport au moteur gauche, nous le réduisons donc jusqu'à ce que les vitesses du moteur soient égales ledcWrite(3, R2*0.97);

}

Conseillé: