RobotCompetition2014-2 : Différence entre versions

De Wiki de bureau d'études PeiP
(Le robot s'arrête à la vue d'une ligne rouge)
(Conclusion)
 
(55 révisions intermédiaires par 3 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
[[Fichier:Arrête.mp4]]
+
<include nopre noesc src="/home/pedago/ppeip/include/video-RobotCompetition2-2014-iframe.html" />
 +
__TOC__
 +
<br style="clear: both;">
 +
= '''Introduction''' =
 +
Durant le bureau d'étude IMA de cette année, nous avons pour rôle la réalisation d'un robot d'attaque et de défense. Pour la bonne compréhension de ce que nous allons faire au cours de cet enseignement de spécialité nous allons reporter sur cette page tout ce qui sera fait pour atteindre la conception finale de ce robot.
  
Le robot s'arrête quand il voit une ligne rouge ce qui va l'empêcher de sortir du terrain de foot.
+
Ce twiki expliquera en détail nos manières de procéder pour atteindre nos objectifs, présentant également des lignes de codes. Lorsqu'elles sont simples et courtes, ces dernières seront copiées en italique, dans un encadré en pointillé. Les phrases écrites après un double slash (//) signifiant que c'est un commentaire, en langage C.
 +
Pour d'autres programmes, plus longs et compliqués, nous donnerons le fichier texte directement, avec l'explication brève du principe du programme en description du fichier. En plus de ceci, des commentaires sont disposés dans nos programme si nécessaire pour expliquer chaque étape.
 +
 
 +
= '''Le Robot Mindstorm NXC''' =
 +
 
 +
Il y a deux moyens de programmer ce robot : en utilisant le logiciel de programmation par blocs fourni avec la machine, ou en langage de programmation pur.
 +
Nous avons choisi cette dernière option, l'éditeur et compilateur NxcEditor permet d'écrire en NXC, dérivé du langage C.
 +
 
 +
 
 +
== '''Le montage''' ==
 +
 
 +
Voila la dernière version du robot NXC que nous avons réalisé
 +
[[Fichier:thebeast.jpg|200px|thumb|center|vue 1]]
 +
[[Fichier:thebeast1.jpg|200px|thumb|center|vue 2]]
 +
[[Fichier:thebeast2.jpg|200px|thumb|center|vue 3]]
 +
 
 +
== '''Les capteurs''' ==
 +
 
 +
Ils sont l'essence même de notre robot, et ce sont eux qui vont nous permettre de faire ce projet.
 +
Leur utilisation via un programme NXC requiert :
 +
 
 +
- Une initialisation, dans laquelle on indique au robot à quel port ils sont branchés.
 +
 
 +
- Une lecture. C'est-à-dire que le robot ne les utilise pas à tout instant. Il faut déclencher une lecture à un instant t, et à cet instant nous pouvons utiliser les valeurs que nous fournissent ces capteurs.
 +
 
 +
=== Le capteur de couleur ===
 +
 
 +
Ce capteur permet de différencier les couleurs : il peut reconnaître du blanc, du noir, du rouge, du vert, du bleu.
 +
Nous le plaçons sous notre robot (pour une détection correcte, il doit être placé à au moins 1 cm du sol) et il servira à deux buts :
 +
 
 +
- Se replacer sur le garage en suivant les lignes de couleur.
 +
 
 +
- Ne jamais sortir du terrain.
 +
 
 +
 
 +
Côté programmation :
 +
Initialisation grâce à la commande :
 +
''SetSensorColorFull(IN_1); // IN_1 indique que le port auquel il est branché est numéroté 1''
 +
Lecture :
 +
''SV = ReadSensorColorEx(IN_1, cval, rawData, normData, scaledData); // Cette formule bien complète n'est pas si compliquée. A notre niveau, nous ''
 +
''//n'utilisons que la variable cval, un int qui va contenir un chiffre entre 0 et 5. Ce chiffre signifie tout simplement une certaine couleur entre ''
 +
''//Blanc,Bleu, Rouge, Jaune, Vert et Noir. Nul besoin d'apprendre leur correspondance, un simple test du type "if (cval == INPUT_REDCOLOR)" par exemple suffit.''
 +
 
 +
=== Le capteur ultrason ===
 +
 
 +
Ce capteur détecte la présence d'éventuels obstacles et même la distance à laquelle ils se trouvent.
 +
Il nous servira pour remplir la condition du cahier des charges "ne jamais percuter l'adversaire", ainsi que pour détecter la balle.
 +
 
 +
Initialisation :
 +
''SetSensorUltrasonic(IN_3);''
 +
Lecture :
 +
''dist = SensorUS(IN_3); // dist est un byte (octet) contenant une valeur allant de 0 à 255. Cette valeur correspond à une distance. Plus le nombre est grand, plus l'obstacle est loin.''
 +
 
 +
=== Le capteur infrarouge ===
 +
 
 +
Il nous sera utile pour détecter la balle et les buts.
 +
 
 +
Son fonctionnement : 5 capteurs y sont intégrés. Un capteur scanne devant lui, les quatre autres permettent au robot de "voir" sur 180°.
 +
Nous avons accès librement à la valeur de chaque capteur.
 +
 
 +
Initialisation :
 +
''SetSensorLowspeed(IN_2);''
 +
Lecture :
 +
''result = ReadSensorHTIRSeeker2AC(IN_2,dir,s1,s2,s3,s4,s5);''
 +
Les valeurs qui nous intéressent sont celles de s1, s2, s3, s4, s5. Ils captent une valeur entre 0 et 255 selon l'intensité du signal reçu. Chacun correspond à un capteur.
 +
 
 +
[[Fichier:Infrarouge schéma.png]]
 +
 
 +
Notre capteur peut être réglé pour recevoir plus spécifiquement des ondes de fréquence 600 Hz ou 1200 Hz.
 +
 
 +
=== Le capteur de contact ===
 +
 
 +
Lorsque le robot rencontre un obstacle, le bouton est enfoncé.
 +
Nous pensions que ce capteur aurait pu nous être utile pour vérifier la bonne capture de la balle. Mais son enclenchement était bien trop aléatoire pour être utilisé avec notre configuration. Nous avons donc opté pour le capteur ultrason.
 +
 
 +
===== Problèmes =====
 +
 
 +
Le premier problème rencontré avec ce capteur est le fait qu'il n'a pas de phase intermédiaire entre le moment où il touche quelque chose et celui où il ne touche rien. Les valeurs de ce capteur passe de 0 (il ne touche rien) à 33 (valeur maximale atteinte quand le bouton du capteur est enfoncé au maximum).
 +
 
 +
Le deuxième problème rencontré est que le bouton ne s'enfonce pas assez pour activer le moteur quand le robot entre en contact avec la balle. Il faut que la balle soit en mouvement rapide vers le robot pour que le bouton s'enfonce. De plus si la balle arrive sur le côté, bien qu'elle soit entrée dans la pince, elle n'est pas détectée puisque l'enclenchement n'est pas systématique dans ce cas.
 +
 
 +
 
 +
=====Résolution des problèmes=====
 +
 
 +
Nous avons opté pour un remaniement du robot. Pour détecter et attraper la balle, nous avons utilisé l'action simultanée du capteur ultrason et du capteur infrarouge; nous avons dû modifier notre programme afin de faire une distinction entre balle et adversaire puisque que le capteur ultrason est aussi utilisé pour détecter les éventuels obstacles.
 +
 
 +
== '''Le dispositif de capture de la balle''' ==
 +
 
 +
Nous utilisons une pince articulée pour capturer la balle. Cette pince, lorsqu'elle s'ouvre, pousse également la balle en avant; c'est une pince à double action.
 +
En plus de cette pince nous avons installé une pince rigide horizontale pour tenir la balle correctement sur les côtés, et permettre une capture plus précise.
 +
 
 +
 
 +
Nous installons dans la zone de capture le capteur ultrason. Il sert à détecter la balle et l'adversaire. Lorsque le robot détecte la balle assez prêt, il abaisse la pince. Ensuite il vérifie si la balle qui est présente. Dans le cas contraire il rouvre la pince.
 +
 
 +
= '''Le jeu''' =
 +
 
 +
 
 +
 
 +
== '''Le terrain'''==
 +
 
 +
[[Fichier:Terrain.jpg|500px|thumb|center|Les lignes du terrain]]
 +
 
 +
C'est avec plusieurs groupes que nous avons fabriqué le terrain.
 +
Nous avons assemblé 4 plaques de placo de 1m / 1,5m, formant un rectangle de 2m / 3m.
 +
Le terrain en lui-même ne prend pas la totalité de l'espace : une distance est alloué de chaque côté. A chaque bout du rectangle est monté un mur. Ce dernier a pour but d'empêcher la balle de sortir trop loin en dehors du terrain.
 +
 
 +
La structure globale de celui-ci, avec les lignes de couleur est donné sur la page de présentation de la saison 5, et a été proposé par l'enseignant.
 +
L'un des groupes est allé questionner chacun des acteurs pour connaître la taille minimale à réserver pour chaque partie du terrain : emplacement des buts, espace entre limite du terrain et mur, emplacement de garage des joueurs...
 +
Nous avons adapté ces mesures de manière à ce que nos robots joueurs puissent aller jusqu'au bout du terrain sans percuter le mur, et ce pour les 4 côtés.
 +
 
 +
- Les robots joueurs doivent pouvoir avancer jusqu'au lignes latérales et les dépasser jusqu'au roues sans pour autant que leur pince ne touche le mur.
 +
 
 +
- Il doivent avoir la place pour se garer à côté des buts.
 +
 
 +
- Le robot ramasseur doit avoir sa place de garage aussi, donc réserve un emplacement latéral.
 +
 
 +
 
 +
Nous avons donc tracé les lignes du terrain au crayon gris
 +
 
 +
[[Fichier:Trace_crayon.jpg|200px|thumb|center|Tracé au crayon]]
 +
 
 +
Ensuite nous avons pu installer les vraies lignes; nous avons utilisé du scotch de couleur : fort heureusement nous avions toutes les couleurs nécessaires à disposition.
 +
 
 +
[[Fichier:Pose_Scotch_1.jpg|200px|thumb|center|Pose du scotch]]
 +
[[Fichier:Pose_Scotch_2.jpg|200px|thumb|center|Vérification des espaces latéraux]]
 +
[[Fichier:Pose_Scotch_3.jpg|200px|thumb|center|Séparation des plaques]]
 +
 
 +
== '''Les limites du terrain''' ==
 +
 
 +
 
 +
Les robots joueurs n'ont pas le droit de sortir du terrain. Le bord de celui-ci étant matérialisé par une ligne rouge, nous utiliserons le capteur de couleur, pour détecter la couleur en temps réel et faire faire demi-tour au robot lorsqu'il atteint cette ligne.
 +
 
 +
 
 +
[[Fichier:Arrête.mp4]] Le robot s'arrête quand il voit une ligne rouge avec son capteur de couleur, ce qui va l'empêcher de sortir du terrain de foot.
 +
 
 +
[[Fichier:Demi tour.mp4]] Nous avons modifié le programme qui fait s'arrêter le robot et l'avons retravaillé afin qu'il puisse faire demi-tour toujours lorsqu'il voit une ligne rouge.
 +
 
 +
 
 +
Pour ce faire c'est assez simple. Il suffit de vérifier à chaque instant la couleur en-dessous, et dès qu'elle apparaît rouge, de faire demi-tour
 +
''
 +
  while(1)
 +
  {
 +
    SV = ReadSensorColorEx(S1, cval, rawData, normData, scaledData);
 +
    if(arret == 0 && cval == 5) // Variable arrêt utilisée dans un autre programme
 +
    {
 +
      OnFwd(OUT_A, 50);
 +
      OnFwd(OUT_B, -50);
 +
      demitour = 1; // Cette variable nous sert à empêcher certaines actions lorsqu'elle vaut 1
 +
      Wait(2600); // Temps approximatif d'un demi-tour à cette vitesse
 +
      demitour = 0; 
 +
      Off(OUT_AB);
 +
    }
 +
    Wait(250); // Temps de latence entre deux vérifications
 +
  }
 +
''
 +
 
 +
 
 +
 
 +
== '''Ne pas percuter l'adversaire''' ==
 +
 
 +
Il est interdit aux deux joueurs de se rentrer dedans.
 +
Le capteur ultrason, placé bien en évidence sur le robot, détecte les obstacles. Lorsqu'il voit quelque chose de très près, nous ordonnons à notre robot l'arrêt.
 +
 
 +
''
 +
  while (1)
 +
  {
 +
    dist = SensorUS(IN_3);
 +
    if ((balle == 0) && dist <= 25)) // La variable balle vaut 1 si le robot considère qu'elle est juste devant.  Par conséquent le programme ne s'enclenchera pas dans ce cas
 +
    {
 +
      Off(OUT_AB);
 +
      Wait(500);
 +
      OnFwd(OUT_AB, 50);
 +
    }
 +
  }
 +
''
 +
 
 +
 
 +
=='''Rencontre Obstacle'''==
 +
 
 +
Nous avons fusionner le programme qui fait s'arrêter le robot quand il y'a un obstacle et le programme qui l'empêche de sortir du terrain. Notre robot est desormais capable d'éviter les murs ou autres obstacles tout en restant sur le terrain.
 +
Sur le vidéo ci-dessous vous pouvez voir le robot qui évite de se prendre le mur.
 +
[[Fichier:Arrêt_mur.mp4]]
 +
 
 +
 
 +
== '''La Balle'''==
 +
 
 +
Le but du jeu est que le robot attrape la balle pour ensuite marquer des points.
 +
 
 +
 
 +
 
 +
=== '''Chercher la balle''' ===
 +
 
 +
 
 +
La difficulté majeure de notre projet est ici. La balle que nous utilisons émet un rayonnement infrarouge en continu. Les buts, pour qu'ils soient détectés par le robot, émettent un signal qui est intermittent. C'est à partir de ça que le robot doit différencier la balle des buts.
 +
 
 +
Deux solutions furent proposées. Nous avons opté sur le changement de fréquence :
 +
Le rayonnement infrarouge se fait à une fréquence : elle peut être de 600 ou de 1200 Hz. Justement, le capteur infrarouge du robot peut être réglé pour recevoir plutôt du 600 Hz, ou du 1200 Hz. Nous utiliserons cette fonctionnalité pour distnguer la balle des buts.
 +
 
 +
Après initialisation du capteur on peut ajouter
 +
''SetHTIRSeeker2Mode(IN_2, HTIR2_MODE_600); ''
 +
ou
 +
''SetHTIRSeeker2Mode(IN_2, HTIR2_MODE_1200); ''
 +
 
 +
Après avoir effectué des tests avec un autre groupe, nous avons trouvé que le robot détecte mieux les ondes sur le mode 600 Hz. C'est ce mode qui sera utilisé pour la balle. Nous demanderons donc aux constructeurs de buts de régler leur fréquence à 1200 HZ.
 +
 
 +
 
 +
Lorsque le robot est en recherche de balle, il se placera en mode 600 Hz. Une fois la balle attrapée (condition vérifiée par l'activation du capteur ultrason), le robot passe en mode 1200 Hz pour les buts.
 +
 
 +
 
 +
 
 +
=== '''Attraper la balle / Lancer la balle''' ===
 +
 
 +
Le principe pour trouver la balle est de regarder la valeur de chaque capteur : le robot comprendra où la balle peut se trouver. Son but est que le capteur central soit le seul à avoir une valeur significative (supérieur à une valeur précise).
 +
Une fois positionné face à la balle, il avance vers elle, tout en corrigeant sa trajectoire de manière à rester bien en face de celle-ci : son objectif est de l'attraper.
 +
 
 +
 
 +
Une fois arrivé proche de la balle, (le capteur ultrason indique une présence proche), la pince s'abaisse grâce au servomoteur dédié. Si ce capteur voit une faible valeur alors la balle est bien emprisonnée et le robot continue son jeu. Sinon, il relève la pince et réessaie.
 +
 
 +
Le dispositif de tir consiste à ouvrir la pince avec une certaine vitesse. La bout arrière de notre mécanisme pousse la balle à la vitesse souhaitée, et celle-ci se dirige tout droit. Pour peu que le robot soit correctement dirigé, elle avance vers le but.
 +
 
 +
Après plusieurs tests voilà les premiers résultats obtenus dans cette vidéo :[[Fichier:attrape.mp4]]
 +
 
 +
Voici notre programme pour attraper la balle : [[Fichier:Attrape_Balle.txt]]
 +
 
 +
 
 +
 
 +
== ''' Detecter les buts''' ==
 +
 
 +
Voici un autre point compliqué de notre projet. Le robot doit trouver son propre but pour tirer. Les deux buts émettant sur la même fréquence, il convient d'utiliser le clignotement.
 +
Chaque but va être programmé pour rester allumé un certain nombre de secondes, puis s'éteindre, et ainsi de suite.
 +
 
 +
[[Fichier:Cherche_but.txt]]
 +
 
 +
 
 +
 
 +
== '''Se replacer''' ==
 +
 
 +
Lorsque l'arbitre le lui ordonne, le robot se replace sur son garage.
 +
Nous avons modifié l'algorithme précisé dans la partie "Robot de compétition" du twiki de la saison 5.
 +
 
 +
[[Fichier:Garage.txt]]
 +
 
 +
== '''Obéir à l'arbitre''' ==
 +
 
 +
La réalisation de l'arbitre à été faite par le proffesseur responsable de la BE.
 +
Nous avons essayer de réaliser un programme qui permettrai au robot de communiquer avec l'arbitre par bluetooth.
 +
Le mécanisme de la communication entre notre robot joueur et l'arbitre est simple.
 +
 
 +
==='''Les différents codes'''===
 +
 
 +
''
 +
#define CODE_REQTYPE            0 // demander le type de l'acteur
 +
#define CODE_PLACER            1 // ordonne au robot de se garer
 +
#define CODE_JOUER              2 // permet de démarrer la manche
 +
#define TYPE_JOUEUR            1
 +
#define CODE_GARE              1 // un robot est garé
 +
#define MAILBOX_ARBITRE        2
 +
#define MAILBOX_ACTEUR          1
 +
''
 +
 
 +
==='''Les variables'''===
 +
 
 +
* Le "int ''result''" va nous servir à voir si il y'a un message dans la boite mail du boitier. Sa valeur sera "0" si il y'a un message.
 +
 
 +
''
 +
    result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
 +
    if(result==0)
 +
      {notre programme}
 +
''
 +
 
 +
 
 +
* Le "int ''requete''" va nous permettre de savoir ce que l'arbitre demande. Si c'est le type de l'acteur qu'il veut savoir :
 +
 
 +
''
 +
      int requete=StrToNum(buffer);
 +
      if(requete==CODE_REQTYPE)
 +
        {ce que le robot doit faire}
 +
''
 +
 
 +
Dans un autre des cas (se garer ou jouer) il suffit de remplacer la valeur de requete par "requete==CODE_PLACER" ou "requete==CODE_JOUER".
 +
Les messages envoyés par l'arbitre sont de type "string" et notre robot ne lit que des "int" donc il est nécessaire de rentrer cette commande:
 +
 
 +
''
 +
int requete=StrToNum(buffer);
 +
''
 +
 
 +
* Le "string ''type''" sera une string que l'on va envoyer à l'abitre pour donner le type du robot et le "string ''gare''" sera le message envoyé à l'arbitre lorque le robot est bien garé.
 +
 
 +
 
 +
==='''Donner le type du robot'''===
 +
 
 +
Selon le type du robot(ramasseur,joueur,but), l'arbitre sera amené à donner différents ordres.
 +
Donc avant toute chose l'arbitre va demander au robot son type en envoyant le ''CODE_REQTYPE'' et le robot doit être à même de lui répondre correctement.
 +
Dans notre cas, le robot est de type joueur donc il va envoyer à l'arbitre le ''TYPE_JOUEUR''.
 +
Voilà notre programme pour réaliser cet échange:
 +
 
 +
'' int result;
 +
    string buffer;
 +
    while (true)
 +
    {
 +
    result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
 +
    if(result==0)
 +
      {
 +
      int requete=StrToNum(buffer);
 +
      if(requete==CODE_REQTYPE)
 +
        {TextOut(0,LCD_LINE1,"    messagerecu  ");
 +
        string type;
 +
        type=NumToStr(TYPE_JOUEUR);
 +
        SendMessage(MAILBOX_ARBITRE+10,type);
 +
        }
 +
      }
 +
''
 +
 
 +
==='''Se garer'''===
 +
 
 +
L'arbitre va demander au robot de se garer en début de partie ou lorsqu'un but est mis et le robot une fois garer va dire à l'arbitre qu'il est garer.
 +
Si le message envoyé par l'abitre est le ''CODE_PLACER'' pour ordonner au robot de se garer, ce dernier exécute le programme "Garage()".
 +
 
 +
''
 +
    result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
 +
    if(result==0)
 +
    {
 +
      int requete=StrToNum(buffer);   
 +
      if (requete==CODE_PLACER)
 +
      {
 +
      //  SetSensorColorFull(IN_1);
 +
        Garage();
 +
        .....
 +
      }
 +
    }
 +
''
 +
Une fois rentré à son garage le robot va envoyer un message dans lequel sera contenu le CODE_GARE à l'arbitre pour lui dire qu'il est garé et attend de nouveaux ordres :
 +
 
 +
''     
 +
        string gare;
 +
        gare=NumToStr(CODE_GARE);
 +
        SendMessage(MAILBOX_ARBITRE+10,gare);
 +
        }
 +
    Wait(1000);
 +
    }''
 +
 
 +
==='''Jouer'''===
 +
 
 +
Une fois les robots garé et la balle remise au centre par les ramasseurs de balles, l'arbitre va envoyer au robot le ''CODE_JOUER''. Le robot va le lire et va lancer le programme  "jouer()" :
 +
 
 +
''
 +
    result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
 +
    if(result==0)
 +
    {
 +
      int requete=StrToNum(buffer);   
 +
      if (requete==CODE_JOUER)
 +
      {
 +
        jouer();
 +
      }
 +
    }
 +
''
 +
 
 +
Le programme "jouer()" comprend les sous progammes cités plus haut dans notre wiki:
 +
 
 +
''
 +
sub jouer()
 +
{
 +
  attrappe(); //cherche la balle et la capture
 +
  Wait(2000);
 +
  cherche_but(); //cherche le but et tire
 +
 
 +
  }
 +
''
 +
 
 +
==='''Problème'''===
 +
 
 +
Le seul problème rencontré lors de l'élaboration de la communition avec avec l'arbitre est la durée que l'arbitre met pour se connecter au robot. Elle varie entre 2 seconde et 10 minutes. Et parfois quand le message arrive au bout des 10 minutes le robots n'effectue aucune tâche ce qui n'est pas le cas quand le message arrive plus tôt.
 +
 
 +
Voilà notre programme qui effectue le jeu complet en communiquant avec l'arbitre.
 +
 
 +
[[Fichier:Demo_jouer_arbitre.nxc]]
 +
 
 +
='''Conclusion'''=
 +
 
 +
Avec les différents programmes réalisés, notre robot est capable d'effectuer un match presque complet sous les ordre de l'arbitre.
 +
Au bout de ces 5 mois passer à créer notre robot joueur, nous avons pû mieux apprendre le Langage C et les différents aspects du travail de l'ingénieur en IMA tant au niveau de la conception que de la programmation.
 +
Nous avons également appris à travailler en groupe et à élargir nos horizons de recherche, à penser avec des personnes qui ne font pas exactement les choses comme nous.
 +
Tout cela nous a grandement aidé dans le choix de nos voeux d'orientation Polytech.
 +
Ce bureau d'étude nous à été très bénéfique et nous remercions les professeurs qui nous ont supervisés tout au long de cette tâche de création.

Version actuelle datée du 31 mai 2015 à 14:29


Vidéo HD


Introduction

Durant le bureau d'étude IMA de cette année, nous avons pour rôle la réalisation d'un robot d'attaque et de défense. Pour la bonne compréhension de ce que nous allons faire au cours de cet enseignement de spécialité nous allons reporter sur cette page tout ce qui sera fait pour atteindre la conception finale de ce robot.

Ce twiki expliquera en détail nos manières de procéder pour atteindre nos objectifs, présentant également des lignes de codes. Lorsqu'elles sont simples et courtes, ces dernières seront copiées en italique, dans un encadré en pointillé. Les phrases écrites après un double slash (//) signifiant que c'est un commentaire, en langage C. Pour d'autres programmes, plus longs et compliqués, nous donnerons le fichier texte directement, avec l'explication brève du principe du programme en description du fichier. En plus de ceci, des commentaires sont disposés dans nos programme si nécessaire pour expliquer chaque étape.

Le Robot Mindstorm NXC

Il y a deux moyens de programmer ce robot : en utilisant le logiciel de programmation par blocs fourni avec la machine, ou en langage de programmation pur. Nous avons choisi cette dernière option, l'éditeur et compilateur NxcEditor permet d'écrire en NXC, dérivé du langage C.


Le montage

Voila la dernière version du robot NXC que nous avons réalisé

vue 1
vue 2
vue 3

Les capteurs

Ils sont l'essence même de notre robot, et ce sont eux qui vont nous permettre de faire ce projet. Leur utilisation via un programme NXC requiert :

- Une initialisation, dans laquelle on indique au robot à quel port ils sont branchés.

- Une lecture. C'est-à-dire que le robot ne les utilise pas à tout instant. Il faut déclencher une lecture à un instant t, et à cet instant nous pouvons utiliser les valeurs que nous fournissent ces capteurs.

Le capteur de couleur

Ce capteur permet de différencier les couleurs : il peut reconnaître du blanc, du noir, du rouge, du vert, du bleu. Nous le plaçons sous notre robot (pour une détection correcte, il doit être placé à au moins 1 cm du sol) et il servira à deux buts :

- Se replacer sur le garage en suivant les lignes de couleur.

- Ne jamais sortir du terrain.


Côté programmation : Initialisation grâce à la commande :

SetSensorColorFull(IN_1); // IN_1 indique que le port auquel il est branché est numéroté 1

Lecture :

SV = ReadSensorColorEx(IN_1, cval, rawData, normData, scaledData); // Cette formule bien complète n'est pas si compliquée. A notre niveau, nous 
//n'utilisons que la variable cval, un int qui va contenir un chiffre entre 0 et 5. Ce chiffre signifie tout simplement une certaine couleur entre 
//Blanc,Bleu, Rouge, Jaune, Vert et Noir. Nul besoin d'apprendre leur correspondance, un simple test du type "if (cval == INPUT_REDCOLOR)" par exemple suffit.

Le capteur ultrason

Ce capteur détecte la présence d'éventuels obstacles et même la distance à laquelle ils se trouvent. Il nous servira pour remplir la condition du cahier des charges "ne jamais percuter l'adversaire", ainsi que pour détecter la balle.

Initialisation :

SetSensorUltrasonic(IN_3);

Lecture :

dist = SensorUS(IN_3); // dist est un byte (octet) contenant une valeur allant de 0 à 255. Cette valeur correspond à une distance. Plus le nombre est grand, plus l'obstacle est loin.

Le capteur infrarouge

Il nous sera utile pour détecter la balle et les buts.

Son fonctionnement : 5 capteurs y sont intégrés. Un capteur scanne devant lui, les quatre autres permettent au robot de "voir" sur 180°. Nous avons accès librement à la valeur de chaque capteur.

Initialisation :

SetSensorLowspeed(IN_2);

Lecture :

result = ReadSensorHTIRSeeker2AC(IN_2,dir,s1,s2,s3,s4,s5); 

Les valeurs qui nous intéressent sont celles de s1, s2, s3, s4, s5. Ils captent une valeur entre 0 et 255 selon l'intensité du signal reçu. Chacun correspond à un capteur.

Infrarouge schéma.png

Notre capteur peut être réglé pour recevoir plus spécifiquement des ondes de fréquence 600 Hz ou 1200 Hz.

Le capteur de contact

Lorsque le robot rencontre un obstacle, le bouton est enfoncé. Nous pensions que ce capteur aurait pu nous être utile pour vérifier la bonne capture de la balle. Mais son enclenchement était bien trop aléatoire pour être utilisé avec notre configuration. Nous avons donc opté pour le capteur ultrason.

Problèmes

Le premier problème rencontré avec ce capteur est le fait qu'il n'a pas de phase intermédiaire entre le moment où il touche quelque chose et celui où il ne touche rien. Les valeurs de ce capteur passe de 0 (il ne touche rien) à 33 (valeur maximale atteinte quand le bouton du capteur est enfoncé au maximum).

Le deuxième problème rencontré est que le bouton ne s'enfonce pas assez pour activer le moteur quand le robot entre en contact avec la balle. Il faut que la balle soit en mouvement rapide vers le robot pour que le bouton s'enfonce. De plus si la balle arrive sur le côté, bien qu'elle soit entrée dans la pince, elle n'est pas détectée puisque l'enclenchement n'est pas systématique dans ce cas.


Résolution des problèmes

Nous avons opté pour un remaniement du robot. Pour détecter et attraper la balle, nous avons utilisé l'action simultanée du capteur ultrason et du capteur infrarouge; nous avons dû modifier notre programme afin de faire une distinction entre balle et adversaire puisque que le capteur ultrason est aussi utilisé pour détecter les éventuels obstacles.

Le dispositif de capture de la balle

Nous utilisons une pince articulée pour capturer la balle. Cette pince, lorsqu'elle s'ouvre, pousse également la balle en avant; c'est une pince à double action. En plus de cette pince nous avons installé une pince rigide horizontale pour tenir la balle correctement sur les côtés, et permettre une capture plus précise.


Nous installons dans la zone de capture le capteur ultrason. Il sert à détecter la balle et l'adversaire. Lorsque le robot détecte la balle assez prêt, il abaisse la pince. Ensuite il vérifie si la balle qui est présente. Dans le cas contraire il rouvre la pince.

Le jeu

Le terrain

Les lignes du terrain

C'est avec plusieurs groupes que nous avons fabriqué le terrain. Nous avons assemblé 4 plaques de placo de 1m / 1,5m, formant un rectangle de 2m / 3m. Le terrain en lui-même ne prend pas la totalité de l'espace : une distance est alloué de chaque côté. A chaque bout du rectangle est monté un mur. Ce dernier a pour but d'empêcher la balle de sortir trop loin en dehors du terrain.

La structure globale de celui-ci, avec les lignes de couleur est donné sur la page de présentation de la saison 5, et a été proposé par l'enseignant. L'un des groupes est allé questionner chacun des acteurs pour connaître la taille minimale à réserver pour chaque partie du terrain : emplacement des buts, espace entre limite du terrain et mur, emplacement de garage des joueurs... Nous avons adapté ces mesures de manière à ce que nos robots joueurs puissent aller jusqu'au bout du terrain sans percuter le mur, et ce pour les 4 côtés.

- Les robots joueurs doivent pouvoir avancer jusqu'au lignes latérales et les dépasser jusqu'au roues sans pour autant que leur pince ne touche le mur.

- Il doivent avoir la place pour se garer à côté des buts.

- Le robot ramasseur doit avoir sa place de garage aussi, donc réserve un emplacement latéral.


Nous avons donc tracé les lignes du terrain au crayon gris

Tracé au crayon

Ensuite nous avons pu installer les vraies lignes; nous avons utilisé du scotch de couleur : fort heureusement nous avions toutes les couleurs nécessaires à disposition.

Pose du scotch
Vérification des espaces latéraux
Séparation des plaques

Les limites du terrain

Les robots joueurs n'ont pas le droit de sortir du terrain. Le bord de celui-ci étant matérialisé par une ligne rouge, nous utiliserons le capteur de couleur, pour détecter la couleur en temps réel et faire faire demi-tour au robot lorsqu'il atteint cette ligne.


Fichier:Arrête.mp4 Le robot s'arrête quand il voit une ligne rouge avec son capteur de couleur, ce qui va l'empêcher de sortir du terrain de foot.

Fichier:Demi tour.mp4 Nous avons modifié le programme qui fait s'arrêter le robot et l'avons retravaillé afin qu'il puisse faire demi-tour toujours lorsqu'il voit une ligne rouge.


Pour ce faire c'est assez simple. Il suffit de vérifier à chaque instant la couleur en-dessous, et dès qu'elle apparaît rouge, de faire demi-tour

 
 while(1)
 {
   SV = ReadSensorColorEx(S1, cval, rawData, normData, scaledData); 
   if(arret == 0 && cval == 5) // Variable arrêt utilisée dans un autre programme
   {
     OnFwd(OUT_A, 50);
     OnFwd(OUT_B, -50);
     demitour = 1; // Cette variable nous sert à empêcher certaines actions lorsqu'elle vaut 1
     Wait(2600); // Temps approximatif d'un demi-tour à cette vitesse
     demitour = 0;   
     Off(OUT_AB);
   }
   Wait(250); // Temps de latence entre deux vérifications
 }


Ne pas percuter l'adversaire

Il est interdit aux deux joueurs de se rentrer dedans. Le capteur ultrason, placé bien en évidence sur le robot, détecte les obstacles. Lorsqu'il voit quelque chose de très près, nous ordonnons à notre robot l'arrêt.

 while (1) 
 {
   dist = SensorUS(IN_3);
   if ((balle == 0) && dist <= 25)) // La variable balle vaut 1 si le robot considère qu'elle est juste devant.  Par conséquent le programme ne s'enclenchera pas dans ce cas
   {
     Off(OUT_AB);
     Wait(500);
     OnFwd(OUT_AB, 50);
   }
 }


Rencontre Obstacle

Nous avons fusionner le programme qui fait s'arrêter le robot quand il y'a un obstacle et le programme qui l'empêche de sortir du terrain. Notre robot est desormais capable d'éviter les murs ou autres obstacles tout en restant sur le terrain. Sur le vidéo ci-dessous vous pouvez voir le robot qui évite de se prendre le mur. Fichier:Arrêt mur.mp4


La Balle

Le but du jeu est que le robot attrape la balle pour ensuite marquer des points.


Chercher la balle

La difficulté majeure de notre projet est ici. La balle que nous utilisons émet un rayonnement infrarouge en continu. Les buts, pour qu'ils soient détectés par le robot, émettent un signal qui est intermittent. C'est à partir de ça que le robot doit différencier la balle des buts.

Deux solutions furent proposées. Nous avons opté sur le changement de fréquence : Le rayonnement infrarouge se fait à une fréquence : elle peut être de 600 ou de 1200 Hz. Justement, le capteur infrarouge du robot peut être réglé pour recevoir plutôt du 600 Hz, ou du 1200 Hz. Nous utiliserons cette fonctionnalité pour distnguer la balle des buts.

Après initialisation du capteur on peut ajouter

SetHTIRSeeker2Mode(IN_2, HTIR2_MODE_600); 

ou

SetHTIRSeeker2Mode(IN_2, HTIR2_MODE_1200); 

Après avoir effectué des tests avec un autre groupe, nous avons trouvé que le robot détecte mieux les ondes sur le mode 600 Hz. C'est ce mode qui sera utilisé pour la balle. Nous demanderons donc aux constructeurs de buts de régler leur fréquence à 1200 HZ.


Lorsque le robot est en recherche de balle, il se placera en mode 600 Hz. Une fois la balle attrapée (condition vérifiée par l'activation du capteur ultrason), le robot passe en mode 1200 Hz pour les buts.


Attraper la balle / Lancer la balle

Le principe pour trouver la balle est de regarder la valeur de chaque capteur : le robot comprendra où la balle peut se trouver. Son but est que le capteur central soit le seul à avoir une valeur significative (supérieur à une valeur précise). Une fois positionné face à la balle, il avance vers elle, tout en corrigeant sa trajectoire de manière à rester bien en face de celle-ci : son objectif est de l'attraper.


Une fois arrivé proche de la balle, (le capteur ultrason indique une présence proche), la pince s'abaisse grâce au servomoteur dédié. Si ce capteur voit une faible valeur alors la balle est bien emprisonnée et le robot continue son jeu. Sinon, il relève la pince et réessaie.

Le dispositif de tir consiste à ouvrir la pince avec une certaine vitesse. La bout arrière de notre mécanisme pousse la balle à la vitesse souhaitée, et celle-ci se dirige tout droit. Pour peu que le robot soit correctement dirigé, elle avance vers le but.

Après plusieurs tests voilà les premiers résultats obtenus dans cette vidéo :Fichier:Attrape.mp4

Voici notre programme pour attraper la balle : Fichier:Attrape Balle.txt


Detecter les buts

Voici un autre point compliqué de notre projet. Le robot doit trouver son propre but pour tirer. Les deux buts émettant sur la même fréquence, il convient d'utiliser le clignotement. Chaque but va être programmé pour rester allumé un certain nombre de secondes, puis s'éteindre, et ainsi de suite.

Fichier:Cherche but.txt


Se replacer

Lorsque l'arbitre le lui ordonne, le robot se replace sur son garage. Nous avons modifié l'algorithme précisé dans la partie "Robot de compétition" du twiki de la saison 5.

Fichier:Garage.txt

Obéir à l'arbitre

La réalisation de l'arbitre à été faite par le proffesseur responsable de la BE. Nous avons essayer de réaliser un programme qui permettrai au robot de communiquer avec l'arbitre par bluetooth. Le mécanisme de la communication entre notre robot joueur et l'arbitre est simple.

Les différents codes

  1. define CODE_REQTYPE 0 // demander le type de l'acteur
  2. define CODE_PLACER 1 // ordonne au robot de se garer
  3. define CODE_JOUER 2 // permet de démarrer la manche
  4. define TYPE_JOUEUR 1
  5. define CODE_GARE 1 // un robot est garé
  6. define MAILBOX_ARBITRE 2
  7. define MAILBOX_ACTEUR 1

Les variables

  • Le "int result" va nous servir à voir si il y'a un message dans la boite mail du boitier. Sa valeur sera "0" si il y'a un message.

   result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
   if(result==0)
     {notre programme}


  • Le "int requete" va nous permettre de savoir ce que l'arbitre demande. Si c'est le type de l'acteur qu'il veut savoir :

     int requete=StrToNum(buffer);
     if(requete==CODE_REQTYPE)
       {ce que le robot doit faire}

Dans un autre des cas (se garer ou jouer) il suffit de remplacer la valeur de requete par "requete==CODE_PLACER" ou "requete==CODE_JOUER". Les messages envoyés par l'arbitre sont de type "string" et notre robot ne lit que des "int" donc il est nécessaire de rentrer cette commande:

int requete=StrToNum(buffer);

  • Le "string type" sera une string que l'on va envoyer à l'abitre pour donner le type du robot et le "string gare" sera le message envoyé à l'arbitre lorque le robot est bien garé.


Donner le type du robot

Selon le type du robot(ramasseur,joueur,but), l'arbitre sera amené à donner différents ordres. Donc avant toute chose l'arbitre va demander au robot son type en envoyant le CODE_REQTYPE et le robot doit être à même de lui répondre correctement. Dans notre cas, le robot est de type joueur donc il va envoyer à l'arbitre le TYPE_JOUEUR. Voilà notre programme pour réaliser cet échange:

int result;

   string buffer;
   while (true)
   {
   result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
   if(result==0)
     {
     int requete=StrToNum(buffer);
     if(requete==CODE_REQTYPE)
       {TextOut(0,LCD_LINE1,"    messagerecu   ");
       string type;
       type=NumToStr(TYPE_JOUEUR);
       SendMessage(MAILBOX_ARBITRE+10,type);
       }
     }

Se garer

L'arbitre va demander au robot de se garer en début de partie ou lorsqu'un but est mis et le robot une fois garer va dire à l'arbitre qu'il est garer. Si le message envoyé par l'abitre est le CODE_PLACER pour ordonner au robot de se garer, ce dernier exécute le programme "Garage()".

   result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
   if(result==0)
   { 
     int requete=StrToNum(buffer);     
     if (requete==CODE_PLACER)
     {
     //  SetSensorColorFull(IN_1);
       Garage();
       .....
      }
   }

Une fois rentré à son garage le robot va envoyer un message dans lequel sera contenu le CODE_GARE à l'arbitre pour lui dire qu'il est garé et attend de nouveaux ordres :

       string gare;
       gare=NumToStr(CODE_GARE);
       SendMessage(MAILBOX_ARBITRE+10,gare);
       }
   Wait(1000);
   }

Jouer

Une fois les robots garé et la balle remise au centre par les ramasseurs de balles, l'arbitre va envoyer au robot le CODE_JOUER. Le robot va le lire et va lancer le programme "jouer()" :

   result=ReceiveMessage(MAILBOX_ACTEUR,true,buffer);
   if(result==0)
   { 
     int requete=StrToNum(buffer);     
     if (requete==CODE_JOUER)
     {
       jouer();
     }
   }

Le programme "jouer()" comprend les sous progammes cités plus haut dans notre wiki:

sub jouer()

{
 attrappe(); //cherche la balle et la capture
 Wait(2000);
 cherche_but(); //cherche le but et tire
 
 }

Problème

Le seul problème rencontré lors de l'élaboration de la communition avec avec l'arbitre est la durée que l'arbitre met pour se connecter au robot. Elle varie entre 2 seconde et 10 minutes. Et parfois quand le message arrive au bout des 10 minutes le robots n'effectue aucune tâche ce qui n'est pas le cas quand le message arrive plus tôt.

Voilà notre programme qui effectue le jeu complet en communiquant avec l'arbitre.

Fichier:Demo jouer arbitre.nxc

Conclusion

Avec les différents programmes réalisés, notre robot est capable d'effectuer un match presque complet sous les ordre de l'arbitre. Au bout de ces 5 mois passer à créer notre robot joueur, nous avons pû mieux apprendre le Langage C et les différents aspects du travail de l'ingénieur en IMA tant au niveau de la conception que de la programmation. Nous avons également appris à travailler en groupe et à élargir nos horizons de recherche, à penser avec des personnes qui ne font pas exactement les choses comme nous. Tout cela nous a grandement aidé dans le choix de nos voeux d'orientation Polytech. Ce bureau d'étude nous à été très bénéfique et nous remercions les professeurs qui nous ont supervisés tout au long de cette tâche de création.