RobotRamasseur2014-2

De Wiki de bureau d'études PeiP

Introduction

Dans le cadre de notre bureau d'étude IMA, nous avions le choix entre plusieurs projets. Les différents projets étaient des robots joueurs, ramasseurs de balles, des buts ainsi qu'un arbitre, la finalité étant d'effectuer un match de football où les différents projets interviendraient. Ayant pris le projet "ramasseur de balle", notre but était de réaliser un robot en Lego, puis de le programmer en NXC (Not eXactly C), afin qu'il aille chercher la balle et la ramène au centre du terrain.

La construction

La construction du robot est la première chose que nous avons faites. Cette étape nous semblait importante pour commencer car nous allions avoir une base matérielle sur laquelle travailler. En effet, savoir où sont placés les capteurs, et sur quelle entrée de notre micro-contrôleur était nécessaire avant de commencer a programmer. Les éléments à notre dispositions étaient :

  • 3 servomoteurs
  • Un capteur de couleurs, un d'ultrasons, un d'infrarouge et un de pression
  • Un micro-contrôleur MindStorm
  • Des pièces de Lego

Le châssis

Nous avons commencé par monter le "corps" de notre robot, en optant rapidement pour les chenilles étant donné que nous avions entendu que l'utilisation des roues poser problème dans certains cas. Le poids du micro-contrôleur nous a forcé à renforcer notre robot par le bas, en ajoutant des fixations. Nous avons au final réussi à trouver un bon compromis pour l'équilibre du robot, en répartissant uniformément toutes les charges à mettre sur le robot et en compensant le poids de la pince vers l'avant à l'aide d'une base arrière lourde. Nous avons veillé également à ne pas trop espacer les deux chenilles pour éviter que le robot ne s'écrase sous le poids du micro-contrôleur, que nous avons placé au centre du châssis, de façon verticale et légèrement incliné pour pouvoir faire les branchements aux différents capteurs sans encombres.

La pince sous sa première forme

La pince

Notre robot étant un ramasseur de balle, il fallait qu'il soit équipé d'un système pour attraper la balle et la garder. Deux servomoteurs était déjà utilisés pour la mobilité du robot, nous avons alors opté pour une pince dont une partie serait articulée par le servomoteur restant, l'autre partie étant fixe. Par la suite, nous avons ajouté sur la pince des capteurs pour que le robot puisse interagir avec le monde extérieur, à savoir :

  • Un capteur infrarouge
  • Un capteur d'ultrasons
  • Un capteur de pression

La pince avait alors la forme ci à droite.

Après quelque essais, nous nous sommes rendu compte que lorsque le robot avait la balle, cette dernière nous empêchait d'utiliser le capteur d'ultrasons. Il a donc fallu décentrer la pince pour laisser le champ libre au capteur d'ultrasons. Dans sa version finale, la pince se referme de telle façon que la balle se retrouve légèrement sur la gauche du robot en laissant le champ libre au capteur d'ultrasons.

Au final, le robot, avec la nouvelle pince, ressemble donc à cela :

Pince final

Les capteurs

Les capteurs sont très importants. En effet, ils nous permettent de faire réaliser des actions au robot en fonction de ce qu'ils "voient". Tout les capteurs doivent être initialisé :

 SetSensorLowspeed(IN_1) et SetHTIRSeeker2Mode(IN_1, HTIR2_MODE_600)   
  • pour le capteur infrarouge. (MODE_1200 si on veut capteur du 1200Hz).
 SetSensorUltrasonic(IN_2)   
  • pour le capteur d'ultrasons.
 SetSensorMSPressure(IN_4)   
  • pour le capteur de pression.
 SetSensorColorFull(IN_3)   
  • pour le capteur de couleur.

Voici donc les différent capteurs que nous utilisons.

Le capteur de couleur dans sa place finale

Capteur de couleurs

C'est le seul capteur qui se retrouve sur le châssis. Il nous permet de basculer dans la partie du programme voulue en détectant une certaine couleur. Par exemple, le robot peut suivre une bande de couleur grâce à ce capteur.

Nous l'avions dans un premier temps fixé sur l'arrière du robot. Cependant, lorsque ce dernier tournait, le capteur n'arrivait plus à détecter la ligne et le robot n'avançait plus. Le capteur de couleurs est donc passé à l'avant du robot. Afin de la placer correctement, nous avons du en plus prendre en compte la hauteur du capteur : en effet, si le capteur est trop haut, il a du mal a détecter les bonnes couleurs, ce qui pose un problème évident à l’exécution du programme.

Nous avons finalement ajouté une collerette sur le capteur afin que ce dernier puissent détecter les couleur avec encore plus de précision.

Le capteur d'Ulstrasons

Capteur d'ultrasons

Ce capteur-ci offre la possibilité de détecter des obstacles qui pourraient se dresser sur le chemin du robot, comme les barrières qui délimitent le terrain. Pour nous, le capteur a une double utilisation étant donné qu'il est complémentaire avec le capteur infrarouge pour attraper la balle. En effet, comme le capteur infrarouge est défaillant à faible distance (il détecte la balle dans plusieurs direction et nous ne pouvons pas l'utiliser), le capteur à ultrasons voit alors si la balle est assez proche ou non pour être capturée.

Au départ, le capteur était placé verticalement sur le bout de la partie fixe de la pince, juste pour détecter les obstacles, puis nous l'avons par la suite replacé horizontalement sur la base de la pince, à l'endroit du servomoteur et légèrement incliné vers l'avant, pour qu'il puisse détecter si la balle est au bon endroit. Nous avons choisi un angle spécial en faisait plusieurs essai : le capteur devait voir la balle assez proche, et en même temps ne pas détecter le sol.

Capteur Infrarouge

Capteur infrarouge

Le capteur infrarouge détecte la position de la balle et des buts à l'aide signaux envoyés par ceux-ci. Son rôle est d'orienter le robot vers la balle pour pouvoir aller ensuite la ramasser. La difficulté de cette tâche est de savoir distinguer les signaux envoyés par la balle de ceux envoyés par les buts, qui devront normalement être d'une fréquence différente (1200Hz pour les buts et 600Hz pour la balle).

Nous avions initialement placé le capteur à la place finale du capteur d'ultrasons, c'est-à-dire au centre de la pince, cependant nous avons pensé qu'il pourrait être gêné par ce qu'il y avait devant. Nous l'avons donc surélevé, en le laissant au centre de la pince, à l'aide d'une tige pour augmenter sa distance de détection. Nous avons placé comme pour le capteur de couleur, une collerette autour du capteur, car dans certains de nos essais, nous avons remarqué que le capteur captait bien la balle, mais les buts venait gêner lorsqu'ils étaient trop près. Le capteur ressemble donc à ceci :

Capteur de pression

Ce capteur permet d'annoncer au robot lorsqu'une pression est exercée sur celui-ci ou non. Il n'était pas indispensable au bon fonctionnement du robot, cependant il permet de créer des raccourcis au niveau de la programmation et d'avoir un robot plus complet au moment d'attraper la balle. En effet, le capteur permet de savoir si la balle est attrapée ou non lorsque le programme tourne, et le fait de pouvoir continuer à chercher la balle si le capteur ne détecte aucune pression permet d'éviter au robot d'entamer la suite du programme sans balle. Le capteur de pression renvoie la valeur 0 lorsqu'il n'y a rien qui appuie dessus. Il renvoie 33 si une pression est exercée sur lui.

Pour le placement, nous avons réussi à le coincer dans la partie fixe de la pince pour que la balle vienne appuyer dessus lorsque la pince se referme. Cependant c'est un capteur un peu capricieux qui demande de la rigueur, nous avons donc renforcé l'attache du capteur pour limiter le recul de celui-ci au maximum.

Robot final

Le robot final

La programmation

La programmation du robot a été réalisée exclusivement en langage NXC car on nous a déconseillé d'utiliser le langage graphique propre au micro-contrôleur, qui est assez limité.

Actions réalisées sans balle

La fonction "Balle"

La fonction balle est celle qui permet au robot de trouver la balle, grâce à l'infrarouge. Premièrement, il faut mettre le capteur en mode 600Hz. Ensuite, nous allons tester la valeur "dir" (voir partie sur le capteur IR), suivant cette valeur, le robot va s'orrienter dans une direction ou l'autre pour avoir la balle en face de lui. Une fois ceci fait, il va avancer et basculer dans la sous fonction "Attrape".

 sub Balle()                   
 { 
   SetSensorLowspeed(IN_1);
   SetHTIRSeeker2Mode(IN_1, HTIR2_MODE_600);
   int dir;
   byte s1, s3, s5, s7, s9;
   while(1)
   {  
     int bVal = ReadSensorHTIRSeeker2AC(IN_1, dir, s1, s3, s5, s7, s9);
     if (dir<5)
     {
       while (dir !=5)
       {
         bVal = ReadSensorHTIRSeeker2AC(IN_1, dir, s1, s3, s5, s7, s9);
         OnFwd(OUT_A,-70);
         OnFwd(OUT_B,70);
       }
     OnFwd(OUT_AB,100);
     Attrape();
     }
     else
     {
       while (dir != 5)
       {
         bVal = ReadSensorHTIRSeeker2AC(IN_1, dir, s1, s3, s5, s7, s9);
         OnFwd(OUT_A,70);
         OnFwd(OUT_B,-70);
       }
     OnFwd(OUT_AB,100);
     Attrape();
     } 
   }
 }

La fonction "Attrape"

Cette sous-fonction est celle qui permet à notre robot d'attraper la balle : l'action principale qui doit être réalisée. Dans un premier temps, nous utilisons la valeur renvoyée par le capteur d'ultrasons : de cette manière, dès que le robot se trouve assez proche de la balle (moins de 10cm), nous activons le moteur C, qui correspond à la pince, et cette dernière capture la balle.

 sub Attrape()                 
 {
   SetSensorUltrasonic(IN_2);
   int x = SensorUS(IN_2);
   SetSensorMSPressure(IN_4);
   int val = SensorMSPressure(IN_4);
   if (x<10)
    {
       OnFwd(OUT_C,-50);
       OnFwd(OUT_AB,0);
       Wait(1000);
       val = SensorMSPressure(IN_4);

Enfin, nous testons la valeur renvoyée pas le capteur de pression pour déterminer si le robot à la balle. Si la balle est attrapée, nous passons dans le sous programme suivant. Sinon, la pince se rouvre.

       if (val>0)
       {
       Trouve();
       }
       else
       {
       OnFwd(OUT_C,50);
       }   
    } 
 }

Actions réalisées avec balle

La fonction "Trouve"

La fonction Trouve permet au robot, une fois la balle attrapée, de retrouver les lignes bleues du centre et basculer dans la fonction "Suivre". Le robot se contente juste de tourner légèrement à chaque fois qu'il se trouve face à un mur, et retombe donc forcément au bout d'un moment sur les lignes bleues. A la base, nous avions programmé le robot pour qu'il se dirige vers l'un des buts grâce à l'infrarouge, fasse demi-tour sur lui-même et qu'il détecte ensuite le but opposé pour avancer dans sa direction et ainsi retombe sur les lignes du centre. Mais à cause d'un problème de capteur, nous avons opté pour une solution plus simple.

 sub Trouve()                   
 {
   SetSensorUltrasonic(IN_2);
   while (1)
   {
     int x = SensorUS(IN_2);
     int bVal = ReadSensorHTIRSeeker2AC(IN_1, dir, s1, s3, s5, s7, s9);
     int cval;
     unsigned int rawData[], normData[];
     int scaledData[];
     SetSensorColorFull(IN_3);
     int result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
     if(x<22)
      {
         OnFwd(OUT_A, -50);
         OnFwd(OUT_B, 50);
         Wait(1800);
      } 
     if (cval==2)
      {
        Suivre();
      }  
   }
 }

La fonction "Suivre"

Ici, le robot est capable de suivre une des lignes bleues médianes. Une fois la pastille jaune détectée (centre du terrain), le robot va effectuer un angle droit pour se retrouver sur la ligne bleue perpendiculaire. Cette opération est répétée jusqu'au moment où le robot retombe sur sa base (détection du noir) pour basculer dans la fonction Place. Lors de cette manoeuvre, si à un quelconque moment le robot dévie de la ligne qu'il doit suivre, il bascule dans la fonction ChercheCouleur pour revenir sur celle-ci.

 sub Suivre()                   
 {
   while (1)
   {
    int cval;
    unsigned int rawData[], normData[];
    int scaledData[];
    SetSensorColorFull(IN_3);
    int result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
    if (cval == 2)                  
     {
     while (cval == 2)
            { 
             result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
             OnFwd(OUT_AB, 100);
             if (cval == 4)                   
              {
                OnFwd(OUT_AB, 100);       
                Wait(1000);
                OnFwd(OUT_A,-70);         
                OnFwd(OUT_B,70);
                Wait(1000);
                result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
                while (cval != 2)
                {
                  result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
                  OnFwd(OUT_A,-70);
                  OnFwd(OUT_B,70);
                }
              }
             result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
             if (cval == 1)
               {
                 Place();
               } 
            }
     }     
     else
     {
      ChercheCouleur();
     }
   }
 return;
 }

La fonction "ChercheCouleur"

 sub ChercheCouleur()                    
 {  
   int cval;
   unsigned int rawData[], normData[];
   int scaledData[];
   SetSensorColorFull(IN_3);
   int i;
   int n = 1; 
   int p = 1000;
   int result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData); 
   while (cval != 2)                    
    {
     for(i=0;i<10;i++)                   
    {
     OnFwd(OUT_A, 60);
     OnFwd(OUT_B, -60);
     Wait((n*p)/10);
     result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
     if (cval==2)                   
      {break;}      
     }
     if (cval==2)                  
      {break;}
     for(i=0;i<20;i++)                  
     {
      OnFwd(OUT_B, 60);
      OnFwd(OUT_A, -60);
      Wait((n*p)/10);
      result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);     
      }
     n=n+1;
    }
 }

La fonction "Place"

 sub Place()                   
 {                               
   int cval;
   unsigned int rawData[], normData[];
   int scaledData[];
   SetSensorColorFull(IN_3);
   int result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
   while(cval == 2)
     {
       result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
       OnFwd(OUT_AB, 70);
       if (cval == 4)
         {
           OnFwd(OUT_A, 0);
           OnFwd(OUT_B, 0);
           OnFwd(OUT_C, 50);
           OnFwd(OUT_A, -50); 
           OnFwd(OUT_B, -50);
           Wait(2000);
           OnFwd(OUT_A, -50); 
           OnFwd(OUT_B, 50);
           Wait(1000);
         }
       if (cval == 1)
         {
           while (cval == 1)
             {
               result = ReadSensorColorEx(IN_3, cval, rawData, normData, scaledData);
               OnFwd(OUT_AB,100);
             }
           OnFwd(OUT_A, -50);
           OnFwd(OUT_B, 50);
           Wait(4800);
           while (1)
             {
               OnFwd(OUT_AB, 0);                  
             }
         }
     }
 }

Construction du terrain

Terrain final

Conclusion

A FAIRE