Robot pendulaire !

1) Présentation du robot pendulaire inversé :

Le but de ce projet est de maintenir en équilibre un robot ne possédant que deux roues, ce robot est entièrement imprimé en 3D, possède deux moteurs, plusieurs capteurs ainsi qu’une carte Arduino uno et un Shield moteur.
Ce projet a été fait dans le cadre de notre formation en génie électrique et informatique industrielle à l’IUT de Soissons.
C’est projet est intéressant car il utilise plusieurs matières étudiées en classe : Automatique (asservissement de position), électrotechnique (moteur), informatique embarquée (Arduino + capteur)…
A partir de cette realisation, il est possible de faire un segway, un monowheel…

voici, un poster de presentation

2) Présentation du materiel :

Le chassis est imprimé en 3D. Il possède deux moteurs DC équipés de roue codeuse, une carte Arduino uno avec un Shield moteur ainsi qu’un capteur gyroscopique.

3) Composants :

Lien des moteurs : https://www.lextronic.fr/moteurs-avec-encodeur/3235-moteur-reducteur-avec-encodeur.html

Lien des roues : https://www.lextronic.fr/roues-et-chenilles/3237-paire-de-roue-diametre-65-mm.html

Carte arduino uno : https://www.lextronic.fr/arduino-officiel/2474-platine-arduino-uno-rev-3.html

Lien du shield moteur : https://www.ebay.com/itm/351104147262

Lien des batteries : https://www.cityclope.com/produit/batterie-accus-samsung-18650-2600-mah/

Lien du gyroscope : https://www.amazon.fr/Capteur-MPU-6050-Module-analogique-accéléromètre/dp/B00E1EQXL6

4) Explication physique du système :

La partie orange représente notre robot. Notre robot comme tous objets sur cette terre est soumis à des forces, la force principale est celle qui nous attire vers le sol, c’est la force de gravité noté P sur ce schéma. Bien sur une force de réaction nous retiens sinon nous serions tous attirer au centre de la terre. Deux autres forces sont importantes ici pour notre robot, ce sont les forces A et B, ces forces sont de même direction mais de sens opposé. Pour maintenir notre robot stable il faut que les forces A et B soit de même intensité.

Admettons maintenant que la force B est une intensité plus forte que la force A, on admet donc ces schémas :

On constate donc que le robot se met à tomber du côté de la force B qui a la plus forte intensité. Ce qu’il faudrait donc faire dans ce cas-là c’est augmenter l’intensité de la force A jusqu’à dépasser l’intensité de la force B et ainsi redressé le robot.

Un autre point important que l’on doit prendre en compte est le centre de gravité. « En statique, le centre de gravité est le point d’application du poids. Il s’agit d’une simplification qui consiste à considérer le poids comme une force s’appliquant en un point unique, G, plutôt que de considérer une force volumique s’appliquant en chaque point de l’objet. » En plus de servir pour la simplification des calculs de statique, la connaissance de la position du centre de gravité est indispensable pour déterminer la stabilité d’un objet. Le centre de gravité est souvent situé au point d’un objet qui est la plus lourde.

De plus, plus le centre de gravité d’un objet est bas, plus il sera facile de le redresser prenons par exemple un bâton, si on y accroche un poids de 20 kg en bas, il sera très facile de le redresser du coté ou le poids n’est pas fixé, en revanche si on essaie de le redresser du coté ou le poids est accroché ce sera très difficile. On peut donc admettre que plus le centre de gravité sera bas, plus il sera facile de redresser un objet.

5) Adaptation à notre système pendulaire inversé

Après avoir rappelé quelques règles de physique, il est temps de les adapter à notre robot. Comme expliquer plutôt, si une force à une plus forte intensité d’un côté ou d’un autre cela entraînera la chute de notre robot. Pour compenser le déséquilibre de notre robot, nous allons nous servir de nos moteurs, le but sera d’accélérer assez fort du côté du déséquilibre pour redresser notre robot. Pour vous expliquer ce phénomène nous pouvons prendre l’exemple d’une moto : si l’accélération d’une moto augmente fortement en très peu de temps, l’avant de la moto va se soulever, de même si l’on freine fortement en très peu de temps du frein avant, l’arrière de la moto va se soulever.

L’objectif sera de réaliser la même chose sur notre robot en augmentant très vite la vitesse des moteurs, mais cette technique ne devra être utilisé que si le robot est sur le point de tomber, s’il subit un déséquilibre trop important d’un seul coup.

La seconde méthode pour qu’il reste stable sera de faire des petites oscillations entre son point d’équilibre (à faible vitesse), car il sera très dur voire impossible de le faire s’arrêter sur son point d’équilibre (le point d’équilibre est le point auquel les forces se compensent).

Comme dit précédemment également, le but sera de rabaisser un maximum le centre de gravité de notre robot, c’est-à-dire mettre les composants les plus lourds vers le bas du robot, ce que nous n’avions absolument pas fait au début du projet.

6) Choix des méthodes de programmation

Pour gérer notre système nous avons choisi d’utiliser une carte Arduino, la programmation se fera donc en langage Arduino. Mais pour réguler notre système, nous avons pensé à deux méthodes de régulation.

La première est la méthode de régulation par logique floue, le principe est très simple à comprendre, on fixe une erreur égale à 0 quand notre robot est stable et on incrémente cette erreur en fonction de l’angle que prend notre robot (l’angle nous ai donné par le gyroscope). Puis en fonction de l’erreur on affecte une valeur de vitesse à nos moteurs.

La deuxième méthode est d’utiliser un régulateur PID, pour ceux qui ne connaisse pas le sujet, je vous mets le lien d’une personne ayant réalisé une explication simplifiée mais très complète et très détaillé des régulateurs PID, de plus son article nous a beaucoup aider au début de notre projet car nous ne connaissions absolument rien à ce genre de régulateur.
Le lien : Implémenter un PID sans faire de calculs ! » Sciences et Techniques

Nous avons effectué deux programmes, chacun utilisant l’une des deux méthodes pour essayer de voir laquelle des deux est la plus adapté à notre système.

7) Algorithme

L’algorithme des deux méthodes sont très similaire seul les formules affectant la valeur de la vitesse aux moteurs changent, nous allons donc vous détailler cet algorithme.

Début
 On lit les valeurs du gyroscope pour connaître l’angle
 On filtre ces valeurs en en récupérant quelques-unes et en faisant la moyenne de celles-ci
 On détermine l’erreur
 On détermine la valeur de la vitesse à affecter aux moteurs en fonction de l’erreur
 Si erreur > 0 alors avancer avec la vitesse déterminer ultérieurement
 Si erreur < 0 alors reculer avec la vitesse déterminer ultérieurement
Fin

8) Les programmes :

Programme correcteur proportionnel par table et zone morte :

////////////////////////////////////////////////////////////////////
// Programme du robot pendule_inverse par logique floue   //
////////////////////////////////////////////////////////////////////

#include<Wire.h>  //Intégrer la bibliothéque de l'I2C.

/* On attribue un nom au pin utilisé par les moteurs pour se faciliter la tâche */
#define DIR_A 12
#define FREIN_A 9
#define VIT_A 3

#define DIR_B 13
#define FREIN_B 8
#define VIT_B 11


const int MPU=0x68; // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;      //Variable du gyroscope + accélérométre
int8_t AcX2,AcY2=0,AcZ2,GyX2,GyY2,GyZ2;     //Variable du gyroscope + accélérométre
int moyenne,angle1=0,angle2=0,angle3=0,i=0,erreur,reference,val_vitesse,erreurabs; //Initialisation de toutes les variables 

void setup() {


  /* Initialisation du gyroscope */
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);

  //Initialisation d'une liaison série pour afficher sur le terminal les informations que l'on veut
  Serial.begin(9600);

  //Setup motor A
  pinMode(DIR_A, OUTPUT); //On met la pin pour le moteur A en sortie
  pinMode(FREIN_A, OUTPUT); //On met la pin du frein A en sortie

  //Setup motor B
  pinMode(DIR_B, OUTPUT); //Même opération que pour le moteur A
  pinMode(FREIN_B, OUTPUT);

}

void loop() {  

  /* On récupére toutes les informations du gyroscope et on ne se sert que de celles qui nous intéréssent */
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,14,true); // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)

  
  /* On filtre les valeurs reçues depuis le gyroscope en faisant la moyenne de 4 valeurs pour en avoir une plus précise */
  angle3 = angle2;
  angle2 = angle1;
  angle1 = AcY2;
  AcY2=map(AcX,-32768,32767,-256,255);    // On change d'échelle la variable AcX 
  moyenne = (angle3 + angle2+ angle1 + AcY2)/4;
  
  /* Initialisation de la valeur de référence du robot (valeur de stabilité), puis calcul de l'erreur */
  reference = 10;   //Valeur du capteur quand le robot est stable  
  erreur = reference - moyenne ;   

  
  
  //Programmation par logique floue :

  Serial.print(erreur);

  if(erreur == 1 || erreur == -1) val_vitesse = 0;
  if(erreur == 2 || erreur == -2) val_vitesse = 20;
  if(erreur == 3 || erreur == -3) val_vitesse = 30;
  if(erreur == 4 || erreur == -4) val_vitesse = 40;
  if(erreur == 5 || erreur == -5) val_vitesse = 50;
  if(erreur == 6 || erreur == -6) val_vitesse = 60;
  if(erreur == 7 || erreur == -7) val_vitesse = 80;
  if(erreur == 8 || erreur == -8) val_vitesse = 90;
  if(erreur == 9 || erreur == -9) val_vitesse = 100;
  if(erreur > 10 || erreur < -10) val_vitesse = 110;


  /* Cette partie sert à dire au moteur dans quel sens tourner */
  if(erreur<0)
  {
  digitalWrite(DIR_B, LOW); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_B, LOW);   //désactive le frein du moteur
  analogWrite(VIT_B, val_vitesse);   //mise au maximum de la vitesse du moteur

 
  digitalWrite(DIR_A, HIGH); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_A, LOW);   //désactive le frein du moteur
  analogWrite(VIT_A, val_vitesse);   //mise au maximum de la vitesse du moteur
  }

  if(erreur>0)
  {
  digitalWrite(DIR_B, HIGH); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_B, LOW);   //désactive le frein du moteur
  analogWrite(VIT_B, val_vitesse);   //mise au maximum de la vitesse du moteur

 
  digitalWrite(DIR_A, LOW); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_A, LOW);   //désactive le frein du moteur
  analogWrite(VIT_A, val_vitesse);   //mise au maximum de la vitesse du moteur
  }
}

Programme avec un P.I (proportionnelle intégrale)

////////////////////////////////////////////////////////////////////
// Programme du robot pendule_inverse avec PI               //
////////////////////////////////////////////////////////////////////


#include<Wire.h>  //Intégrer la bibliothéque de l'I2C.
#include<TimerOne.h> //Intégrer la bibliothéque permettant de réaliser une routine d'interruption


/* On attribue un nom au pin utilisé par les moteurs pour se faciliter la tâche */
#define DIR_A 12
#define FREIN_A 9
#define VIT_A 3

#define DIR_B 13
#define FREIN_B 8
#define VIT_B 11


const int MPU=0x68; // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;      //Variable du gyroscope + accélérométre
int8_t AcX2,AcY2=0,AcZ2,GyX2,GyY2,GyZ2;     //Variable du gyroscope + accélérométre
int moyenne,angle1=0,angle2=0,angle3=0,i=0,Ki=1,correctinteg1,correctinteg,correctprop,erreur,reference,val_vitesse,erreurabs; //Initialisation de toutes les variables 


void setup() {

  /* Initialisation du gyroscope */
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);

  //Initialisation d'une liaison série pour afficher sur le terminal les informations que l'on veut
  Serial.begin(9600);

  //Setup motor A
  pinMode(DIR_A, OUTPUT); //On met la pin pour le moteur A en sortie
  pinMode(FREIN_A, OUTPUT); //On met la pin du frein A en sortie

  //Setup motor B
  pinMode(DIR_B, OUTPUT); //Même opération que pour le moteur A
  pinMode(FREIN_B, OUTPUT);


  Timer1.initialize(10000);         // On initialise le timer 1, pour avoir une période de 0,1s il faut mettre 100000, on a donc ici 10ms de période 
  Timer1.attachInterrupt(callback);  // On crée une fonction appelé ici "callback" qui s'active à chaque fois que le timer 1 dépasse la valeur attribué


  /* On change ensuite la fréquence de la PWM pour rendre plus fluides l'utilisation des moteurs */
  //TCCR2B = TCCR2B & 0b00111000 | 1; // pour pin 3 et 11 -> 31.3 KHz mais ne fonctionne pas, moteur fonctionne seulement de 180 à 255(valeur de PWM)
    TCCR2B = TCCR2B & 0b00111000 | 2; // 5KHz



}

void callback()  {  

  /* On filtre les valeurs reçues depuis le gyroscope en faisant la moyenne de 4 valeurs pour en avoir une plus précise */
  angle3 = angle2;
  angle2 = angle1;
  angle1 = AcY2;
  AcY2=map(AcX,-32768,32767,-256,255);    // On change d'échelle la variable AcX 
  moyenne = (angle3 + angle2+ angle1 + AcY2)/4;
  

  /* Initialisation de la valeur de référence du robot (valeur de stabilité), puis calcul de l'erreur */
  reference = 6;   //Valeur du capteur quand le robot est stable  
  erreur = reference - moyenne ;    
  erreurabs = abs(erreur);
  
  /* Calcul de la valeur de la vitesse en fonction de l'erreur */
  correctinteg1 = correctinteg;
  correctprop = erreurabs * 2;
  correctinteg = Ki * erreurabs + correctinteg1 ;
  val_vitesse = correctprop + correctinteg; //zone morte des motorisations


}//fin routine

void loop() {

  
 
  /* On récupére toutes les informations du gyroscope et on ne se sert que de celles qui nous intéréssent */
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,14,true); // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)


  
  /* Cette partie sert à dire au moteur dans quel sens tourner */
  if(erreur<0)
  {
  digitalWrite(DIR_B, LOW); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_B, LOW);   //désactive le frein du moteur
  analogWrite(VIT_B, val_vitesse);   //mise au maximum de la vitesse du moteur

 
  digitalWrite(DIR_A, HIGH); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_A, LOW);   //désactive le frein du moteur
  analogWrite(VIT_A, val_vitesse);   //mise au maximum de la vitesse du moteur
  }

  if(erreur>0)
  {
  digitalWrite(DIR_B, HIGH); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_B, LOW);   //désactive le frein du moteur
  analogWrite(VIT_B, val_vitesse);   //mise au maximum de la vitesse du moteur

 
  digitalWrite(DIR_A, LOW); //Etabli le sens du moteur, ici en avant
  digitalWrite(FREIN_A, LOW);   //désactive le frein du moteur
  analogWrite(VIT_A, val_vitesse);   //mise au maximum de la vitesse du moteur
  }
 
}

[u]9) Etudes réalisées :[/u]

[u]Etude du capteur gyroscopique MPU 6050 :[/u]

Pour réaliser cette étude, nous avons tracé des angles sur une feuille et nous avons récupéré la valeur du capteur pour chaque angle, nous avons ensuite rempli un tableau puis tracé la courbe :

Normalement cette courbe devrait être une droite mais l’imprécision du capteur nous donne ce résultat. Cela peut être dû au programme que nous utilisions ou juste à une mauvaise précision du capteur.

[u]Etude de la dynamique de chute du robot :[/u]

Cette étude a pour but de déterminer en combien de temps le robot tombe, ainsi que déterminer le point à partir duquel nous ne pouvons plus relever le robot à l’aide des moteurs.

Cette courbe représente le temps de chute du robot, pour connaître ce temps nous avons fait une routine d’interruption dans notre programme qui se répète toutes les 10 minutes en affichant la valeur du capteur gyroscopique. Sur la courbe nous pouvons voir qu’il y a un pic au bout de 510 ms, c’est encore une fois dû à l’imprécision du capteur gyroscopique quand il y a des vibrations. Nous pouvons donc déterminer que le robot met 430 ms à tomber, ce qui est très court.

[u]Etude des moteurs :[/u]

Nous avons complété ce tableau avec toutes les mesures réalisées sur les moteurs. Ces mesures ont été réalisées sur un seul des deux moteurs, alimenté en 12V.

[u]Problèmes rencontrés :[/u]

Durant le projet nous avons rencontré plusieurs problèmes, de différentes ampleurs. Le premier problème rencontré, c’est l’imprécision du gyroscope en effet, comme tout notre système nécessite la valeur récupérée par le gyroscope, si celle-ci n’est pas fiable, le projet ne peut-être fiable. Un deuxième problème rencontré auquel nous n’avions pensé au début était le centre de gravité. En effet nous avions fixé les piles qui sont les objets les plus lourds sur le haut du robot. Ce problème a vite été corrigé. Pour ce faire nous avons démonté les moteurs, les avons inversés et nous avons placer les piles à la place des ceux-ci. Puis le dernier problème qui est aussi l’un des plus perturbants pour notre système, nous nous sommes rendu compte que les moteurs avaient un retard. Ce dernier était plus important que la dynamique de chute de notre robot, donc quand le robot atteint un certain angle nous ne pouvons le rattraper à temps.

[u]Conclusion :[/u]

Dans l’ensemble nous pensons que nous avons assez bien gérer et réalisé notre projet. Celui-ci a été riche en apprentissage car il réunissait beaucoup de matières étudiées en cours. Ainsi nous avons par la même occasion pu consolider nos bases de connaissances dans certains domaines. Ce projet nous aura également permis d’accroitre notre capacité de travail en autonomie et de recherche. Il nous aura aussi conforter dans notre idée de poursuivre nos études dans une branche plus spécifique du génie électrique : l’informatique embarquée. Encore une fois nous remercions tous les professeurs pour leur participation et leur aide dans ce projet.

Vraiment chouette ça. J'adorerais une vidéo, ces robots se meuvent avec une certaine grâce J'ai l'impression qu'il manque un peu de code, non?