Binome2015-5 : Différence entre versions
(45 révisions intermédiaires par 3 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
+ | <include nopre noesc src="/home/pedago/ppeip/include/video-Robot5-2015-iframe.html" /> | ||
+ | |||
+ | <div class="mcwiki-header" style="float:right;border-radius: 15px; padding-right: 100px; margin-top:22px; font-weight: bold; text-align: center; font-size: 80%; vertical-align: top">[[Image:imagepresentation.jpg|thumb|600px|right|Robot et but]]</div> | ||
+ | |||
+ | __TOC__ | ||
+ | <br style="clear: both;"> | ||
<div class="mcwiki-header" style="border-radius: 15px; padding: 20px; font-weight: bold; text-align: center; font-size: 80%; background: #CBC516; vertical-align: top; width: 97%; font-size: 30px; color: #0AA904">LE RONALDUINO</div> | <div class="mcwiki-header" style="border-radius: 15px; padding: 20px; font-weight: bold; text-align: center; font-size: 80%; background: #CBC516; vertical-align: top; width: 97%; font-size: 30px; color: #0AA904">LE RONALDUINO</div> | ||
Ligne 164 : | Ligne 170 : | ||
===Croquis=== | ===Croquis=== | ||
− | + | [[Image:croquis1.jpg|thumb|right|Croquis barre dentée]] | |
+ | [[Image:croquis2.jpg|thumb|left|Croquis roues dentées]] | ||
+ | [[Image:croquis3.jpg|thumb|center|à remplacer]] | ||
+ | <br> | ||
===Les objectifs de la pince=== | ===Les objectifs de la pince=== | ||
Ligne 195 : | Ligne 204 : | ||
Les deux serres ont dû être décalée l'une de l'autre en hauteur afin de leur permettre de se rapprocher au maximum en largeur et de pouvoir saisir la balle (écartement de 6.5cm). Pour décaler les deux serres en hauteur, il a donc fallut construire un système de taquets permettant d'échelonner les engrenages (bien visible sur le rendu final vu de derrière). | Les deux serres ont dû être décalée l'une de l'autre en hauteur afin de leur permettre de se rapprocher au maximum en largeur et de pouvoir saisir la balle (écartement de 6.5cm). Pour décaler les deux serres en hauteur, il a donc fallut construire un système de taquets permettant d'échelonner les engrenages (bien visible sur le rendu final vu de derrière). | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
==<div class="mcwiki-header" style="border-radius: 15px; padding: 10px; font-weight: bold; text-align: center; font-size: 80%; background: #EEEEFF; vertical-align: top; width: 99%;">Le système de tir</div>== | ==<div class="mcwiki-header" style="border-radius: 15px; padding: 10px; font-weight: bold; text-align: center; font-size: 80%; background: #EEEEFF; vertical-align: top; width: 99%;">Le système de tir</div>== | ||
Ligne 287 : | Ligne 281 : | ||
</gallery> </center> | </gallery> </center> | ||
− | Les circuits imprimés ont ainsi été reçus très rapidement. | + | Les circuits imprimés ont ainsi été reçus très rapidement. |
+ | L'étape de la soudure s'est particulièrement bien déroulée , mais nous a pris une grande partie de notre temps car il nous arrivait de dépasser sur une autre barrette et de devoir refaire plusieurs fois les mêmes pins . Nous avons réalisés des tests au fur et a mesure de la soudure afin d'éviter de tout souder et de nous apercevoir que notre PCB n'est pas fonctionnel . | ||
+ | Le résultat final est le suivant : | ||
+ | <center> | ||
+ | [[Fichier:PCB1.jpg|200px|PCB ]] | ||
+ | [[Fichier:PCB2.jpg|200px|PCB]] | ||
+ | </center> | ||
==<div class="mcwiki-header" style="border-radius: 15px; padding: 13px; font-weight: bold; text-align: center; font-size: 90%; background: #D45162; vertical-align: top; width: 98%;">Problèmes rencontrés et résolution</div>== | ==<div class="mcwiki-header" style="border-radius: 15px; padding: 13px; font-weight: bold; text-align: center; font-size: 90%; background: #D45162; vertical-align: top; width: 98%;">Problèmes rencontrés et résolution</div>== | ||
− | * | + | * Nous avons rencontrés un problème de concernant la taille des fils de cuivre à souder . Ceux-ci étaient trop fins à certains endroits. Nous ne pouvions alors pas souder les composants correctement, ce qui nous parfois amené a dépasser sur les autres pins . |
− | |||
− | * | + | * Lors de la première impression du PCB , l'espacement entre les différentes connexion était trop faible , ce qui provoquait de nombreux court-circuits et nous a donc poussé à imprimer un second PCB avec un plus grand espacement . Celui-ci à été finalisé bien plus rapidement , et permettait une soudure plus aisée. |
=<div class="mcwiki-header" style="border-radius: 15px; padding: 15px; font-weight: bold; text-align: center; font-size: 80%; background: #ACACFC; vertical-align: top; width: 98%;"> Programmation : </div>= | =<div class="mcwiki-header" style="border-radius: 15px; padding: 15px; font-weight: bold; text-align: center; font-size: 80%; background: #ACACFC; vertical-align: top; width: 98%;"> Programmation : </div>= | ||
Ligne 386 : | Ligne 385 : | ||
Dans un premier temps, nous avons relié ces capteurs à une résistance de 330 Ohm et avons simplement utilisé un analogRead afin de recevoir la valeur renvoyée. Cette méthode fut rapidement abandonnée à cause du problème énoncé précédemment. Nous nous sommes alors penchés sur un programme plus complexe qui nous permet de capter simplement les signaux infrarouges pulsés. Le principe est le suivant : <br> | Dans un premier temps, nous avons relié ces capteurs à une résistance de 330 Ohm et avons simplement utilisé un analogRead afin de recevoir la valeur renvoyée. Cette méthode fut rapidement abandonnée à cause du problème énoncé précédemment. Nous nous sommes alors penchés sur un programme plus complexe qui nous permet de capter simplement les signaux infrarouges pulsés. Le principe est le suivant : <br> | ||
Pendant un petit laps de temps, nous réalisons un grand nombre d'acquisitions et enregistrons les valeurs dans un tableau. Sachant que la balle est pulsée (supposons une pulsation à 1200 Hz). Elle renvoie une valeurs chaque milliseconde environ dans le meilleur des cas, ce qui se traduit par une succession de valeurs positives et négatives. La lumière renvoyée par le soleil par exemple, n'est quant a elle, pas pulsée. Il s'agit donc de valeurs continues et très variables. Ainsi, notre programme vérifie si deux valeurs qui se suivent sont très éloignées. Si oui, il s'agit de la balle. Sinon, il s'agit d'une autre source de lumière. | Pendant un petit laps de temps, nous réalisons un grand nombre d'acquisitions et enregistrons les valeurs dans un tableau. Sachant que la balle est pulsée (supposons une pulsation à 1200 Hz). Elle renvoie une valeurs chaque milliseconde environ dans le meilleur des cas, ce qui se traduit par une succession de valeurs positives et négatives. La lumière renvoyée par le soleil par exemple, n'est quant a elle, pas pulsée. Il s'agit donc de valeurs continues et très variables. Ainsi, notre programme vérifie si deux valeurs qui se suivent sont très éloignées. Si oui, il s'agit de la balle. Sinon, il s'agit d'une autre source de lumière. | ||
+ | |||
+ | #define valTableauDetection 200 | ||
+ | |||
+ | int IR(int port) | ||
+ | { | ||
+ | return analogRead(port); | ||
+ | } | ||
+ | |||
+ | int detectionBalle(int a) | ||
+ | { | ||
+ | int tab[valTableauDetection] = {0}; | ||
+ | int i=0; | ||
+ | long int somme = 0; | ||
+ | for(i=0;i<valTableauDetection;i++) | ||
+ | { | ||
+ | int b = IR(a); | ||
+ | tab[i] = b; | ||
+ | } | ||
+ | int boucle; | ||
+ | int tab2[valTableauDetection]; | ||
+ | for(i=0;i<valTableauDetection;i++) | ||
+ | { | ||
+ | if (tab[i]<0) | ||
+ | { | ||
+ | tab2[i]=0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | tab2[i]=tab[i]; | ||
+ | } | ||
+ | } | ||
+ | i=0; | ||
+ | int compteurvar=0; | ||
+ | for(i=0;i<valTableauDetection;i++) | ||
+ | { | ||
+ | somme += tab2[i]; | ||
+ | if(((tab2[i+1]<tab2[i]*0.1)||(tab2[i+1]>tab2[i]*2)) && ((tab2[i+1]+3<tab2[i])||(tab2[i+1]-3>tab2[i]))) | ||
+ | { | ||
+ | compteurvar++; | ||
+ | } | ||
+ | } | ||
+ | if (compteurvar>=30) | ||
+ | { | ||
+ | return (long int)(somme/valTableauDetection); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
Ce code fonctionnait parfaitement lorsque le robot n'était pas en mouvement. Lorsqu'il l'était, les valeurs étaient erronées et le robot tournait sur lui même ou suivait des mauvaises directions.<br> | Ce code fonctionnait parfaitement lorsque le robot n'était pas en mouvement. Lorsqu'il l'était, les valeurs étaient erronées et le robot tournait sur lui même ou suivait des mauvaises directions.<br> | ||
Ligne 398 : | Ligne 444 : | ||
Ce problème était dû au fait que notre programme de détection de la balle était trop lent. Nous avons donc diminué le nombre d'acquisition pour accélérer le programme. | Ce problème était dû au fait que notre programme de détection de la balle était trop lent. Nous avons donc diminué le nombre d'acquisition pour accélérer le programme. | ||
+ | #define varCaptLigne 700 | ||
+ | #define vitesseRobot 50 | ||
+ | |||
+ | void testLignes() | ||
+ | { | ||
+ | if(IR(LineTrackAnalogC)>varCaptLigne || IR(LineTrackAnalogD)>varCaptLigne || IR(LineTrackAnalogG) > varCaptLigne) | ||
+ | { | ||
+ | arret(); | ||
+ | if(IR(LineTrackAnalogC) > varCaptLigne) | ||
+ | { | ||
+ | demarrer(); | ||
+ | avancer(0,0,vitesseRobot); | ||
+ | avancer(1,0,vitesseRobot); | ||
+ | delay(500); | ||
+ | arret(); | ||
+ | demarrer(); | ||
+ | avancer(0,1,vitesseRobot); | ||
+ | avancer(1,1,0); | ||
+ | delay(1300); | ||
+ | } | ||
+ | else if(IR(LineTrackAnalogD)>varCaptLigne) | ||
+ | { | ||
+ | demarrer(); | ||
+ | avancer(1,1,vitesseRobot); | ||
+ | avancer(0,1,0); | ||
+ | delay(800); | ||
+ | } | ||
+ | else if(IR(LineTrackAnalogG)>varCaptLigne) | ||
+ | { | ||
+ | demarrer(); | ||
+ | avancer(1,0,vitesseRobot); | ||
+ | avancer(0,1,0); | ||
+ | delay(800); | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | demarrer(); | ||
+ | avancer(1,1,vitesseRobot); | ||
+ | avancer(0,1,vitesseRobot); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | <center><include iframe src="https://www.youtube.com/embed/wEqO68xO1qA" width="600px" height="400px" frameborder="0" scrolling="yes" /></center> | ||
== Suiveur de ligne == | == Suiveur de ligne == | ||
Ligne 403 : | Ligne 493 : | ||
Cette partie ne fut pas très compliquée à réaliser car nous avions déjà écrit un code similaire dans la détection des bords du terrain. Ce programme est utilisé pour ramener le robot à son garage après le tir. Le code consiste donc à dire au robot d'aller tout droit jusqu'à obtenir une valeur haute (correspondant à une ligne droite) puis après cela, de suivre la ligne en le faisant tourner à droite lorsque le capteur de ligne droit détecte une ligne noir et tourner à gauche lorsque le capteur gauche détecte une ligne noir. | Cette partie ne fut pas très compliquée à réaliser car nous avions déjà écrit un code similaire dans la détection des bords du terrain. Ce programme est utilisé pour ramener le robot à son garage après le tir. Le code consiste donc à dire au robot d'aller tout droit jusqu'à obtenir une valeur haute (correspondant à une ligne droite) puis après cela, de suivre la ligne en le faisant tourner à droite lorsque le capteur de ligne droit détecte une ligne noir et tourner à gauche lorsque le capteur gauche détecte une ligne noir. | ||
− | + | void rentrerGarage() | |
+ | { | ||
+ | if (trouverLigne==0) | ||
+ | { | ||
+ | while(IR(LineTrackAnalogC)<varCaptLigne) | ||
+ | { | ||
+ | demarrer(); | ||
+ | avancer(1,1,vitesseRobot); | ||
+ | avancer(0,1,vitesseRobot); | ||
+ | } | ||
+ | trouverLigne=1; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | while(IR(LineTrackAnalogC)>varCaptLigne) | ||
+ | { | ||
+ | avancer(1,1,vitesseRobot); | ||
+ | avancer(0,1,vitesseRobot); | ||
+ | } | ||
+ | if(IR(LineTrackAnalogG)>varCaptLigne && IR(LineTrackAnalogC)<varCaptLigne) | ||
+ | { | ||
+ | while(IR(LineTrackAnalogC)<varCaptLigne) | ||
+ | { | ||
+ | avancer(1,1,vitesseRobot); | ||
+ | avancer(0,1,0); | ||
+ | dernierTour=0; | ||
+ | } | ||
+ | } | ||
+ | if(IR(LineTrackAnalogD)>varCaptLigne && IR(LineTrackAnalogC)<varCaptLigne) | ||
+ | { | ||
+ | while(IR(LineTrackAnalogC)<varCaptLigne) | ||
+ | { | ||
+ | avancer(0,1,vitesseRobot); | ||
+ | avancer(1,1,0); | ||
+ | dernierTour=1; | ||
+ | } | ||
+ | } | ||
+ | if(IR(LineTrackAnalogD)>varCaptLigne && IR(LineTrackAnalogC)>varCaptLigne && IR(LineTrackAnalogG)>varCaptLigne) | ||
+ | { | ||
+ | if(dernierTour==0) | ||
+ | { | ||
+ | while(IR(LineTrackAnalogG)<varCaptLigne) | ||
+ | { | ||
+ | avancer(1,1,vitesseRobot); | ||
+ | avancer(1,1,0); | ||
+ | } | ||
+ | } | ||
+ | else if(dernierTour==1) | ||
+ | { | ||
+ | while(IR(LineTrackAnalogD)<varCaptLigne) | ||
+ | { | ||
+ | avancer(0,1,vitesseRobot); | ||
+ | avancer(1,1,0); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | } | ||
+ | } | ||
<center><include iframe src="https://www.youtube.com/embed/coUHr1DWMNQ" width="600px" height="400px" frameborder="0" scrolling="yes" /></center> | <center><include iframe src="https://www.youtube.com/embed/coUHr1DWMNQ" width="600px" height="400px" frameborder="0" scrolling="yes" /></center> | ||
+ | |||
+ | == Programme principal == | ||
+ | Le programme principal se base sur l'électronique représentée dans le schèma fritzing suivant : | ||
+ | [[Image:Fritzingfinal.png|thumb|400px|center|Robot et but]] <br> | ||
+ | |||
+ | void loop() { | ||
+ | ValCapteurIRAvG=0; | ||
+ | ValCapteurIRAv=0; | ||
+ | ValCapteurIRArG=0; | ||
+ | ValCapteurIRArD=0; | ||
+ | ValCapteurIRAvD=0; | ||
+ | ValCapteurIRAvG=detectionBalle(capteurIRAvG); | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | ValCapteurIRArG=detectionBalle(capteurIRArG); | ||
+ | ValCapteurIRArD=detectionBalle(capteurIRArD); | ||
+ | ValCapteurIRAvD=detectionBalle(capteurIRAvD); | ||
+ | int tableaucapteurs[5] = {ValCapteurIRAv,ValCapteurIRArG,ValCapteurIRAvG,ValCapteurIRArD,ValCapteurIRAvD}; | ||
+ | tableaucapteurs[0]=ValCapteurIRAv; | ||
+ | tableaucapteurs[1]=ValCapteurIRArG; | ||
+ | tableaucapteurs[2]=ValCapteurIRAvG; | ||
+ | tableaucapteurs[3]=ValCapteurIRArD; | ||
+ | tableaucapteurs[5]=ValCapteurIRAvD; | ||
+ | pinceActionner(ouvrir); | ||
+ | if (maximum(tableaucapteurs,5)==0 && trouverBalle==0) | ||
+ | { | ||
+ | testLignes(); | ||
+ | } | ||
+ | if(ValCapteurIRArG==maximum(tableaucapteurs,5) && ValCapteurIRArG!=0) | ||
+ | { | ||
+ | demarrer(); | ||
+ | trouverBalle=0; | ||
+ | compteurTourner=0; | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | while(ValCapteurIRAv==0) | ||
+ | { | ||
+ | compteurTourner++; | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | tableaucapteurs[0] = ValCapteurIRAv; | ||
+ | avancer(1,1,vitesseRobot+vitesseTourner+Ajust); | ||
+ | avancer(0,0,vitesseRobot+vitesseTourner); | ||
+ | if(compteurTourner>=limiteTourner) | ||
+ | break; | ||
+ | } | ||
+ | arret(); | ||
+ | } | ||
+ | |||
+ | else if(ValCapteurIRArD==maximum(tableaucapteurs,5) && ValCapteurIRArD!=0) | ||
+ | { | ||
+ | demarrer(); | ||
+ | trouverBalle=0; | ||
+ | compteurTourner=0; | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | while(ValCapteurIRAv==0) | ||
+ | { | ||
+ | compteurTourner++; | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | tableaucapteurs[0] = ValCapteurIRAv; | ||
+ | avancer(0,1,vitesseRobot+vitesseTourner); | ||
+ | avancer(1,0,vitesseRobot+vitesseTourner+Ajust); | ||
+ | if(compteurTourner>=limiteTourner) | ||
+ | break; | ||
+ | } | ||
+ | arret(); | ||
+ | } | ||
+ | else if(ValCapteurIRAvD==maximum(tableaucapteurs,5) && ValCapteurIRAvD!=0)/ | ||
+ | { | ||
+ | demarrer(); | ||
+ | trouverBalle=0; | ||
+ | compteurTourner=0; | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | while(ValCapteurIRAv==0) | ||
+ | { | ||
+ | compteurTourner++; | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | tableaucapteurs[0] = ValCapteurIRAv; | ||
+ | avancer(0,1,vitesseRobot+vitesseTourner); | ||
+ | avancer(1,0,vitesseRobot+vitesseTourner+Ajust); | ||
+ | if(compteurTourner>=limiteTourner) | ||
+ | break; | ||
+ | } | ||
+ | arret(); | ||
+ | } | ||
+ | else if(ValCapteurIRAv==maximum(tableaucapteurs,5) && ValCapteurIRAv!=0) | ||
+ | { | ||
+ | demarrer(); | ||
+ | while(ValCapteurIRAv<valeurBalleDansPince) | ||
+ | { | ||
+ | ValCapteurIRAv=detectionBalle(capteurIRAv); | ||
+ | tableaucapteurs[0] = ValCapteurIRAv; | ||
+ | avancer(0,1,vitesseRobot); | ||
+ | avancer(1,1,vitesseRobot+Ajust); | ||
+ | testLignesAvant(); | ||
+ | } | ||
+ | trouverBalle=1; | ||
+ | delay(500); | ||
+ | pinceActionner(fermer); | ||
+ | arret(); | ||
+ | delay(1500); | ||
+ | demarrer(); | ||
+ | ValCapteurIRAvG=detectionBalle(capteurIRAvG); | ||
+ | while(ValCapteurIRAvG<5) //Capteur avant gauche doit détecter le but | ||
+ | { | ||
+ | ValCapteurIRAvG=detectionBalle(capteurIRAvG); | ||
+ | testLignesBalle(); | ||
+ | } | ||
+ | arret(); | ||
+ | delay(200); | ||
+ | pinceActionner(ouvrir); | ||
+ | delay(300); | ||
+ | tir(); | ||
+ | delay(2000); | ||
+ | demarrer(); | ||
+ | trouverBalle=0; | ||
+ | while(trouverBalle==0) | ||
+ | { | ||
+ | rentrerGarage(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
==<div class="mcwiki-header" style="border-radius: 15px; padding: 13px; font-weight: bold; text-align: center; font-size: 90%; background: #D45162; vertical-align: top; width: 98%;">Problèmes rencontrés et résolution</div>== | ==<div class="mcwiki-header" style="border-radius: 15px; padding: 13px; font-weight: bold; text-align: center; font-size: 90%; background: #D45162; vertical-align: top; width: 98%;">Problèmes rencontrés et résolution</div>== | ||
Ligne 456 : | Ligne 723 : | ||
<br> | <br> | ||
− | Les trois émetteurs reliés aux transistors émettent un signal pulsé a 1000 Hz. La motivation du choix de connecter ces émetteurs au transistor est notamment de pouvoir les alimenter par un unique pin de l'Arduino en amplifiant le courant qui en provient afin d'alimenter les trois émetteurs de la même manière. L'utilité de cet aspect sera détaillé dans la partie concernant la programmation. Les trois autres émetteurs sont reliés à différents pins et ne sont pas pulsés : ils émettent en continu. Nous avons choisi de placer ces deux types d'émission dans notre but afin que les autres groupes puissent également l'utiliser. | + | Les trois émetteurs reliés aux transistors émettent un signal pulsé a 1000 Hz. La motivation du choix de connecter ces émetteurs au transistor est notamment de pouvoir les alimenter par un unique pin de l'Arduino en amplifiant le courant qui en provient afin d'alimenter les trois émetteurs de la même manière. L'utilité de cet aspect sera détaillé dans la partie concernant la programmation. Les trois autres émetteurs sont reliés à différents pins et ne sont pas pulsés : ils émettent en continu. Nous avons choisi de placer ces deux types d'émission dans notre but afin que les autres groupes puissent également l'utiliser. En effet, peu de groupes se sont basés sur une émission pulsée.<br> |
Les photo-transistors sont connectés aux entrées analogiques de l'Arduino. Lorsque la balle traverse le but, elle est détectée par ce premier photo-transistor. Le second sert à vérifier si la balle est toujours dans le but afin d'éviter d'incrémenter continuellement le score. <br> | Les photo-transistors sont connectés aux entrées analogiques de l'Arduino. Lorsque la balle traverse le but, elle est détectée par ce premier photo-transistor. Le second sert à vérifier si la balle est toujours dans le but afin d'éviter d'incrémenter continuellement le score. <br> | ||
L'afficheur 7 segments est utilisé en communication série. Nous l'alimentons directement sur la sortie 3.3 V de l'Arduino.<br> | L'afficheur 7 segments est utilisé en communication série. Nous l'alimentons directement sur la sortie 3.3 V de l'Arduino.<br> | ||
Ligne 507 : | Ligne 774 : | ||
Nous importons tout d'abord le module SoftwareSerial qui va nous permettre de mettre en place la communication entre l'afficheur et l'arduino que nous avons connectés au pin 8 . Nous créons trois fonctions clearDisplay , brillance et setDecimals qui vont respectivement supprimer tout affichage de l'écran , ajuster la brillance des caractères , et mettre en place des virgules au cas ou nous voudrions afficher des valeurs décimales . Dans notre cas , nous n'en avons pas besoin mais la fonction est quand même utilisée pour n'afficher aucune virgule . Enfin , la communication est mise en place a 9600 bauds . Dans le loop , la fonction sprintf permet de convertir un entier (int) , qui correspond au counter , en une chaine de 4 caractères (définie par %4d) qui va être stockée dans tempString . Finalement , tempString est envoyée à l'afficheur par le biais de la commande comm.print() . | Nous importons tout d'abord le module SoftwareSerial qui va nous permettre de mettre en place la communication entre l'afficheur et l'arduino que nous avons connectés au pin 8 . Nous créons trois fonctions clearDisplay , brillance et setDecimals qui vont respectivement supprimer tout affichage de l'écran , ajuster la brillance des caractères , et mettre en place des virgules au cas ou nous voudrions afficher des valeurs décimales . Dans notre cas , nous n'en avons pas besoin mais la fonction est quand même utilisée pour n'afficher aucune virgule . Enfin , la communication est mise en place a 9600 bauds . Dans le loop , la fonction sprintf permet de convertir un entier (int) , qui correspond au counter , en une chaine de 4 caractères (définie par %4d) qui va être stockée dans tempString . Finalement , tempString est envoyée à l'afficheur par le biais de la commande comm.print() . | ||
+ | |||
+ | Concernant la partie émission infrarouge , nous avons simplement passé en mode HIGH tout les pins connectés qui sont censés émettre en continu et nous avons utilisé la fonction tone() sur le pin auxquel nous avons connecté les trois émetteurs qui enverront des valeurs pulsées : | ||
+ | |||
+ | void balisestart() | ||
+ | { | ||
+ | digitalWrite(balisehg,HIGH); | ||
+ | digitalWrite(balisehd,HIGH); | ||
+ | digitalWrite(balisehm,HIGH); | ||
+ | digitalWrite(baliseg,HIGH); | ||
+ | digitalWrite(balised,HIGH); | ||
+ | } | ||
+ | void baliseoff() | ||
+ | { | ||
+ | digitalWrite(balisehg,LOW); | ||
+ | digitalWrite(balisehd,LOW); | ||
+ | digitalWrite(balisehm,LOW); | ||
+ | digitalWrite(baliseg,LOW); | ||
+ | digitalWrite(balised,LOW); | ||
+ | } | ||
+ | void loop() | ||
+ | { | ||
+ | if(etat) //la variable état contient normalement une valeur booléenne , dependant du message transmis par la Xbee du robot joueur | ||
+ | { | ||
+ | balisestart(); | ||
+ | tone(pinapulser,1000); | ||
+ | } | ||
+ | else { | ||
+ | baliseoff(); | ||
+ | noTone(baliseg); | ||
+ | } | ||
+ | } | ||
==<div class="mcwiki-header" style="border-radius: 15px; padding: 13px; font-weight: bold; text-align: center; font-size: 90%; background: #D45162; vertical-align: top; width: 98%;">Problèmes rencontrés et résolution</div>== | ==<div class="mcwiki-header" style="border-radius: 15px; padding: 13px; font-weight: bold; text-align: center; font-size: 90%; background: #D45162; vertical-align: top; width: 98%;">Problèmes rencontrés et résolution</div>== | ||
− | + | Nous avons rencontrés deux principaux problèmes lors de la réalisation de la cage de but: le premier concerne la puissance d'émission des infrarouges pulsés. En effet, le robot ne parvient pas à détecter le but a moins d'être a moins de 15 cm de celui-ci. Ce problème peut être réglé par l'utilisation d'un transistor avec un meilleur gain ou l'augmentation de la puissance fournie par les piles.<br> | |
− | + | Finalement, nous avions le problème de pulsation de l'émission au départ: notre robot ne pouvant détecter que des émissions pulsées, nous nous basions sur la fonction tone(), mais celle-ci ne fonctionnait que sur un pin. Ceci est dû au fait que l'Arduino ne possède que trois timers, dont deux sont utilisés par le processeur, ce qui n'en laisse qu'un pour les pin. Il fallait trouver une solution pour pouvoir brancher plusieurs émetteurs sur un même et unique pin: la solution consiste a utiliser un transistor pour amplifier le courant distribué par le pin et placer en série les émetteurs après le transistor. | |
− | |||
=<div class="mcwiki-header" style="border-radius: 15px; padding: 15px; font-weight: bold; text-align: center; font-size: 80%; background: #ACACFC; vertical-align: top; width: 98%;"> Conclusion </div>= | =<div class="mcwiki-header" style="border-radius: 15px; padding: 15px; font-weight: bold; text-align: center; font-size: 80%; background: #ACACFC; vertical-align: top; width: 98%;"> Conclusion </div>= | ||
Ligne 518 : | Ligne 815 : | ||
Ce bureau d'étude sur les robots communicants fut très intéressant. Nous avons beaucoup appris au cours de ces semaines et ces connaissances en informatique et en électronique nous servirons pour nos études. En effet, nous souhaitons tous les deux continuer dans des études d'ingénieur spécialisé en informatique et en robotique. <br> | Ce bureau d'étude sur les robots communicants fut très intéressant. Nous avons beaucoup appris au cours de ces semaines et ces connaissances en informatique et en électronique nous servirons pour nos études. En effet, nous souhaitons tous les deux continuer dans des études d'ingénieur spécialisé en informatique et en robotique. <br> | ||
Ce projet nous a pris beaucoup de temps car nous nous sommes fortement investis. Mais cela ne nous a pas dérangé car nous avons apprécié le travail sur ce robot et voulions obtenir un matériel le plus fonctionnel possible.<br> | Ce projet nous a pris beaucoup de temps car nous nous sommes fortement investis. Mais cela ne nous a pas dérangé car nous avons apprécié le travail sur ce robot et voulions obtenir un matériel le plus fonctionnel possible.<br> | ||
− | Nous sommes satisfait du résultat de notre travail même si lors de la vidéo, nous avons eu certains problèmes de détection de la balle qui étaient réglé précédemment. | + | Nous sommes satisfait du résultat de notre travail même si lors de la vidéo, nous avons eu certains problèmes de détection de la balle qui étaient pourtant réglé précédemment. |
Version actuelle datée du 20 mai 2016 à 12:04
Sommaire
- 1 Introduction
- 2 Objectifs principaux
- 3 Descriptif des séances
- 3.1 Séance 1 : 18/01/16
- 3.2 Séance 2 : 21/01/16
- 3.3 Séance 3 : 25/01/16
- 3.4 Séance 4 : 28/01/16
- 3.5 Séance 5 : 29/01/16
- 3.6 Séance 6 : 01/02/16
- 3.7 Séance 7 : 04/02/16
- 3.8 Séance 8 : 08/02/16
- 3.9 Séance 9 : 11/02/16
- 3.10 Séance 10 : 22/02/16
- 3.11 Séance 11 : 25/02/16
- 3.12 Séance 12 : 03/03/16
- 3.13 Séance 13 : 07/03/16
- 3.14 Séance 14 : 10/03/16
- 3.15 Séance 15 : 14/03/16
- 3.16 Séance 16 : 17/03/16
- 3.17 Séance 17 : 21/03/16
- 3.18 Séance 18 : 18/04/16
- 3.19 Séance 19 : 25/04/16
- 3.20 Séance 20 : 02/05/16
- 4 Réalisation de la pince
- 5 Réalisation du PCB
- 6 Programmation :
- 7 Réalisation de la cage de but
- 8 Conclusion
Introduction
Le projet de cette saison consiste à réaliser un jeu de balle entre des robots que nous allons construire nous même. Notre binôme a choisi de travailler sur le robot joueur ainsi que les cages de buts. La clé pour l'aboutissement du projet consiste a un travail d'équipe afin de pouvoir mettre en commun les avancées de chacun, c'est dans ce but que nous tenons cette page régulièrement actualisée au fil des séances de cours et de recherche personnelle.
Objectifs principaux
Certaines contraintes vont devoir être respectées pour réaliser le robot joueur et la cage de but. Nous allons donc essayer de les respecter pour atteindre les objectifs fixés à la fin de la saison et avoir un matériel fonctionnel :
Pour le robot joueur :
- Construction du châssis fourni à la première séance.
- Disposition des capteurs sur le chassis (capteur IR, ultrason, de ligne)
- Partie programmation :
- Codes liés aux moteurs.
- Code lié a la détection d'obstacles par UltraSon.
- Code lié a la détection de la balle par Infrarouge.
- Code lié a la détection des lignes.
- Mise en place de la communication radio entre les robots et les cages de buts par module Xbee.
- Rassembler tous les codes pour former le programme final.
- Conception mécanique :
- Réalisation du système de pince.
- Réalisation du système de tir.
- Réalisation du PCB pour réduire le nombre de fils et par conséquent les faux contacts.
Pour la cage de but :
- Construction de la structure du but.
- Fixation des capteurs IR et émetteurs IR sur la cage de but.
- Fixation de l'afficheur sur la cage de but.
- Réalisation du programme permettant d'émettre et recevoir un signal infra-rouge en pulser.
L'ordre à suivre pour les différentes étapes a été réfléchi et nous en sommes venu a la conclusion qu'il est primordial de réaliser les tâches dans l'ordre défini précédemment. Celui ci nous permettra de nous adapter progressivement au langage Arduino et de travailler chacun parallèlement en nous répartissant les tâches sur des étapes différentes pour avancer plus rapidement. La mise en commun de nos travaux aboutira ensuite à un robot joueur et des cages de buts fonctionnelles .
Descriptif des séances
Dans un soucis de préserver une trace écrite du contenu de nos séances , nous tenons à jour cette section et décrivons brièvement le contenu de chaque jour. Le travail personnel n'est pas décrit dans cette section .
Séance 1 : 18/01/16
La première séance a principalement consisté à l'établissement du cahier des charges. Nous avons écrit une liste contenant le matériel nécessaire, les contraintes auxquelles sera soumis le robot ainsi que les différentes options possibles pour les résoudre. Nous avons décidé de débattre tout d'abord les contraintes mécaniques, nous avons donc dessiné un premier système de pince, ainsi qu'un système de tir. Les pièces nécessaires à ces systèmes seront imprimées en 3D ou coupées au laser. Nous avons également convenu que le châssis a 2 roues convenait mieux à notre projet, en raison de sa plus grande maniabilité.
Séance 2 : 21/01/16
La seconde séance nous a permis de construire le châssis 2 roues et de commencer à programmer sur l'Arduino Mega. Nous avons pu écrire l'algorithme permettant la mesure de la distance par ultrason ainsi que le contrôle global du servomoteur à utiliser grâce a la librairie associée.
Séance 3 : 25/01/16
- Découverte du logiciel freecad.
- Dessin des engrenages pour la pince du robot.
Séance 4 : 28/01/16
- Impression 3D des engrenages grâce au logiciel Cura.
- Dessin des barres dentées pour la pince grâce au logiciel Freecad.
Séance 5 : 29/01/16
- Création d'une maquette en carton pour tester le système de récepteurs infrarouge avec un arduino UNO.
- Codage du programme contrôlant les récepteurs infrarouge.
Séance 6 : 01/02/16
- Essai d'impression d'une première pince en 3D. Cette impression fut peu concluante mais nous a permis de comprendre le fonctionnement de l'imprimante 3D, mieux maîtriser le logiciel Freecad pour dessiner les pièces et de voir quels étaient les problèmes de notre système. Nous avons donc fait des modifications sur le premier dessin de la pince.
- Installation des récepteurs infrarouge sur le robot.
Séance 7 : 04/02/16
- Travail sur le problème des récepteurs infrarouges qui ne fonctionnent pas. Nous obtenons par moment des valeurs mais n'arrivons pas à faire marcher le système correctement.
- Réalisation sur Freecad d'une nouvelle pince qui doit être plus efficace. Nous attendons donc de pouvoir l'imprimer pour la tester.
Séance 8 : 08/02/16
- Résolution du problème des récepteurs infrarouges ne fonctionnant pas correctement.
Nous avons du démonter tout le circuit pour rebrancher les récepteurs IR un par un et finalement, obtenir un résultat satisfaisant. Nous réglerons le programme pour localiser la balle durant une autre séance.
- Nous avons commencé à utiliser les capteurs noir et blanc mais pour l'instant, ceux-ci ne fonctionnent pas bien sauf en collant les capteurs sur le sol.
Séance 9 : 11/02/16
Séance 10 : 22/02/16
- Impression des derniers composants de la pince. Il ne manque plus que les taquets sur lesquels les roues dentées vont tourner. Nous les réaliserons en bois car l'imprimante 3D n'arrive pas à les imprimer correctement.
Séance 11 : 25/02/16
Début de la réalisation des 2 circuits imprimés. Le premier concerne le contrôleur moteur, le module XBee, les capteurs infrarouges, le capteur ultrason ainsi que les deux servomoteurs qui serviront à actionner la pince et le système de tir. Le second PCB sera placé sous le châssis et il servira a connecter les capteurs de ligne.
Nous avons également pu mettre en avant un problème supplémentaire concernant les capteurs infrarouges : ils renvoient une valeur même lorsque la balle n'est pas présente. Cette contrainte sera abordée à la prochaine séance.
Séance 12 : 03/03/16
La pince est fonctionnelle. Elle a été réalisée grâce a un système d'engrenages, un premier engrenage est connecté à un servomoteur qui met en mouvement les 3 autres engrenages. Deux barres dentées qui actionnent les serres sont reliées aux roues dentées des extrémités.
Séance 13 : 07/03/16
Nous avons fini par résoudre le problème des valeurs incohérentes des capteurs Infrarouge en réalisant un nombre conséquent d'acquisitions (200 acquisitions consécutives), qui sont stockées dans un tableau. Afin de confirmer la présence de la balle et non d'une autre source infrarouge temporaire, on vérifie que lorsqu'une valeur est enregistrée, elle est suivi par une autre valeur plus ou moins élevée. Si c'est le cas, la balle est présente. Sinon, il s'agit de la lumière ambiante qui parasite la détection de la balle. La prochaine séance sera entièrement consacrée a la détection de la balle et au PCB.
Séance 14 : 10/03/16
Cette séance à été entièrement consacrée à la détection de la balle. Nous avons pu mettre au point le système de détection de balle énoncé lors du résumé de la séance précédente. Nous avons rencontrés quelques problèmes notamment dans certains cas à une sortie de la capacité de mémoire de l'Arduino. Dans d'autres cas, certains capteurs continuent de renvoyer des valeurs erratiques dues à la lumière du jour. Le capteur situé à l'avant retourne ainsi continuellement une valeur (petite, mais assez pour faire croire au programme que la balle est présente). Le problème provient surement d'un faux contact dans les branchements.
Séance 15 : 14/03/16
Nous avons continué à mettre au point le programme de détection de la balle. Quelques problèmes liés à la sortie de mémoire ont été réglé en réalisant moins de tours de boucle (ce qui ajoute une petite perte de précision) mais aussi en modifiant le type de valeurs dans le tableau du programme de détection de la balle. Nous sommes passés de "int" à "long int". Concernant les PCBs, nous avons finalement réalisés 2 PCB concernant respectivement les capteurs de lignes, à plaquer sur le châssis inférieur et le PCB principal à utiliser sur l'Arduino et contenant les autres composants.
Séance 16 : 17/03/16
Le programme pour la détection de la balle est au point. Il ne détecte que la balle pulsée a 1200 Hz et aucune source non pulsée (nous avons testé avec une lampe). Il ne manque plus qu'à l'intégrer au programme principal. Le problème rencontré précédemment était simplement dû au fait que la balle n'était pas pulsée (les autres binômes travaillant sans modulation de signal). La gravure du PCB à quant a elle été interrompue en raison d'un problème de format, nous ne l'avons appris qu'à la fin de la séance. Nous allons donc nous pencher sur ce problème pour le faire valider à la prochaine séance.
Séance 17 : 21/03/16
Le problème du PCB était que les fichiers n'étaient pas au bon format. Nos enseignants nous ont expliqué comment envoyer le fichier du PCB sous un bon format, ce qui a été fait. Nous avons alors pu recevoir le PCB principal deux heures plus tard. L'autre PCB rencontre toujours un problème dont la source reste à déterminer car l'aperçu sur le visualiseur Gerber ne montre pas de problèmes pour nous (Le mail de refus précise un problème de drills).
Nous avons terminé le programme visant a orienter le robot selon la puissance du signal envoyé par la balle. Nous nous sommes alors penchés sur les capteurs de lignes que nous avons entièrement finis lors de cette séance : le robot ne sort plus des zones délimitées. A la rencontre d'une ligne noire, il recule puis change d'angle. Cependant un problème majeur a été rencontré : le rafraîchissement des valeurs n'est parfois pas assez rapide et si elle ne se fait pas alors que le robot traverse une ligne, celle-ci n'est pas détectée. Une solution consiste à prendre un des capteurs et le placer a l'arrière du robot. Nous allons en discuter lors de la prochaine séance.
Un autre problème à été mis en avant : du fait du nombre élevé de composants, si les piles ne sont pas entièrement chargées, l'Arduino ne tourne pas. De plus, les piles se déchargent vite durant nos test. Nous allons donc augmenter le nombre de piles alimentant notre robot.
Séance 18 : 18/04/16
La séance à permis de régler quelques incertitudes avec les capteurs infrarouges . Les autres capteurs sont entièrement finalisé . Il ne manque que le PCB et le Xbee sur le robot . Le code régissant le fonctionnement des cages des buts a été mis en place . Il ne manque plus qu'à découper les cages .
Séance 19 : 25/04/16
- Finalisation du but.
- Test de mise en place du Xbee. Sans succés par manque de temps.
- Réalisation du programme permettant au robot de suivre une ligne pour rentrer au garage.
Séance 20 : 02/05/16
Dernière séance, nous avons essayé de régler les derniers problèmes dans le programme avant de tourner la vidéo. Malheureusement, certains problèmes ont persistés comme le système de détection de balle qui marchait pourtant précédemment. Nous tenterons donc de refaire des vidéos par nous même pour montrer l'efficacité de notre programme.
Réalisation de la pince
La pince
Pour fabriquer cette pince, nous avons utilisé les logiciels Freecad pour le dessin 3D; Cura et UP pour l'impression 3D. Nous avons d'abord dessiné des croquis de la pince pour ensuite la réaliser sur Freecad.
Croquis
Les objectifs de la pince
- Pouvoir s'écarter un maximum afin de faciliter la prise de la balle (pas trop non plus pour ne pas gêner le déplacement du robot)
- Se refermer suffisamment pour saisir la balle (6.5cm)
- Permettre au système de tir de lancer la balle lorsque la pince est fermée afin de guider la balle. De plus, le tir doit être assez puissant.
- N'utiliser qu'un seul servomoteur
Les éléments de la pince
- 2 serres
- 4 roues dentées
- 4 taquets servant d'axe de rotation aux roues
- la structure principale de la pince.
Le fonctionnement de la pince
Pour actionner la pince, il suffit de mettre en route 1 servo-moteur (numéro 1 sur le rendu final vu du dessus). Celui ci va alors faire tourner la grande roue dentée de gauche qui va elle même actionner le système d'engrenage composé de 2 petites roues dentées. Celles ci servent à écarter suffisamment les 2 grandes roues dentées ainsi qu'à les faire tourner dans le sens inverse l'une de l'autre. Ce système d'engrenage va alors faire tourner la grande roue dentée de droite. Les deux serres qui sont chacune reliée à une grande roue dentée par un système de crémaillère vont alors pouvoir se rapprocher ou s'écarter.
Les deux serres ont dû être décalée l'une de l'autre en hauteur afin de leur permettre de se rapprocher au maximum en largeur et de pouvoir saisir la balle (écartement de 6.5cm). Pour décaler les deux serres en hauteur, il a donc fallut construire un système de taquets permettant d'échelonner les engrenages (bien visible sur le rendu final vu de derrière).
Le système de tir
Le système de tir est composé de:
- Un propulseur qui est constitué d'une crémaillère ainsi que d'une surface d'appui permettant de tirer la balle. De plus, un ressort a été ajouté dans l'espace vide de la crémaillère (numéro 3 sur le rendu final vu du dessus) afin d'augmenter sa puissance. Ce ressort est piégé entre deux zones d'appui (noté en vert sur le rendu final vu du dessus). Mais cela n'est pas visible car caché par une pièce de couleur rose qui permet de garder le ressort droit lorsqu'il est compressé.
- un support permettant de relier la roue dentée et le propulseur.
- une roue dentée dont certaines dents ont été supprimées. Reliée au moteur, elle permet d'amer le système de tir et de tirer lorsqu'il n'y a plus de dent.
Le tir se déroule donc en deux actions:
- On arme tout d'abord le tir en faisant tourner le moteur (moteur 1 sur le rendu final vu du dessus) collé à la roue dentée jusqu'à la dernière dent de cette roue.
- Puis, on introduit la balle entre les pinces et on fait un tour de roue dentée afin de propulser la balle grâce à l'étirement du ressort se situant dans le propulseur. Le tour de roue permettant aussi de réarmer le propulseur pour le prochain tir.
Le système de tir a été fixé sur la structure basse de la pince en essayant de faire dépasser le moins possible la pince du robot. En effet, celle ci pourrait gêner le robot dans son déplacement.
La pince finale
Les moteurs ne sont pas présents sur la représentation graphique de la pince. Cela permet une meilleure visibilité et une meilleure compréhension du système. ceux-ci sont indiqué à l'aide de numéro sur le rendu final vu du dessus.
le rendu final :
Problèmes rencontrés et résolution
Problèmes liés à la pince
- les 2 serres, les 4 roues dentées ainsi que la structure principale ont pu être dessinées sur Freecad puis imprimées grâce à l'imprimante 3D du Fabricarium. Mais les 4 taquets ne convenaient pas après leur impression car ils étaient déformés. L'imprimante 3D a du mal à réaliser les taquets car ceux ci étaient trop fins et de forme cylindrique.
Les 4 taquets ont donc été réalisés manuellement en découpant un long clou de diamètre voulu (3.5mm) et un tuyau de diamètre légèrement supérieur.
Ce problème nous a permis d'en apprendre d'avantage sur le fonctionnement de l'imprimante 3D et de ces limites.
- L'espace calculé pour faire entrer les serres dans la structure basse au niveau de la crémaillère était légèrement insuffisant. Il a donc fallu poncer la structure basse pour réduire sa largeur. Ce qui a permis aux serres de coulisser le long de la partie élevée de la structure basse.
- Nous avons dû modifier plusieurs fois la taille des roues dentées afin de maximiser la largeur d'écartement des pinces et faciliter ainsi la prise de la balle.
- Il a fallu placer le moteur et le bloquer grâce à la structure haute et à une enveloppe faite en contreplaqué. En effet, si on ne bloquait pas le moteur, celui ci tournait sur lui même plutôt que d’entraîner la roue. Nous avons enfin peint l'enveloppe en noir pour l'esthétique.
Problèmes liés au système de tir
- Nous avons eu un problème de puissance de tir. En effet, nous avions tout d'abord prévu d'utiliser la crémaillère seule. Mais le moteur n'était finalement pas assez rapide et la balle n'avançait que très peu lors du tir. Nous avons donc décidé d'utiliser un ressort et une roue dentée dont nous avons retiré certaines dents. Cela permet donc d'armer le système de tir et de tirer avec une bonne puissance.
- Trouver le bon ressort pour le propulseur fut aussi un problème car certains étaient trop petit, d'autres trop souple. Nous avons finalement collé deux ressorts bout à bout pour obtenir la pression escomptée.
- Il a fallut trouver un moyen pour que le ressort ne puisse pas s'en aller lors d'un tir. Ce problème a été résolu en l'emprisonnant dans la pièce rose entourant le propulseur.
Réalisation du PCB
Le PCB
La réalisation du PCB est une étape majeure de notre projet : elle permet d'éviter les nombreux faux contacts rencontrés sur la plaque d'essai, de rendre plus compacte la disposition des composants et de diminuer le nombre de fils. De plus, sa réalisation nous a permis d'en apprendre plus sur les circuits imprimés et de nous familiariser avec la méthode à suivre.
La première version du PCB n'était pas du tout fonctionnelle car nous ne savions pas que les fils ne peuvent pas se croiser sur la plaque. Cette information nous a rapidement été donnée et nous nous sommes empressés de réaliser un PCB fonctionnel. En une semaine, nous avions fini notre premier PCB principal où étaient disposés tous les composants de notre robot.
Nos enseignants nous ont alors proposé de faire plusieurs cartes afin d'alléger le nombre de fils sur le robot (chose que nous tentions d'éviter).
Le premier envoi de la carte à l'impression s'est soldé par une erreur due au format du fichier. En effet, nous n'avions remplacé que le format du drill par .drd et laissé les autres dans leurs format exporté de Fritzing. Cette erreur a retardé l'impression d'une semaine de plus.
Avant de procéder à la validation de la demande d'impression, nous avons fait vérifier nos fichiers par un visualiseur Gerber. Celui ci permet de s'assurer que notre PCB sera bien interprété par la machine en nous imprimant a l'écran les différents fichiers exportés un a un. Ainsi, nous pouvons voir les positionnement des drills, des pastilles, le plan de masse et les connexions.
Les circuits imprimés ont ainsi été reçus très rapidement. L'étape de la soudure s'est particulièrement bien déroulée , mais nous a pris une grande partie de notre temps car il nous arrivait de dépasser sur une autre barrette et de devoir refaire plusieurs fois les mêmes pins . Nous avons réalisés des tests au fur et a mesure de la soudure afin d'éviter de tout souder et de nous apercevoir que notre PCB n'est pas fonctionnel . Le résultat final est le suivant :
Problèmes rencontrés et résolution
- Nous avons rencontrés un problème de concernant la taille des fils de cuivre à souder . Ceux-ci étaient trop fins à certains endroits. Nous ne pouvions alors pas souder les composants correctement, ce qui nous parfois amené a dépasser sur les autres pins .
- Lors de la première impression du PCB , l'espacement entre les différentes connexion était trop faible , ce qui provoquait de nombreux court-circuits et nous a donc poussé à imprimer un second PCB avec un plus grand espacement . Celui-ci à été finalisé bien plus rapidement , et permettait une soudure plus aisée.
Programmation :
La programmation est une des principales partie du projet. Nous avons utilisé une plateforme Arduino Mega qui a nécessité de se familiariser avec le langage arduino. Celui ci étant une simplification du langage C, nous avons réussi sans trop de difficultés.
Nous avons suivi quelques cours dispensés par plusieurs plateformes d'éducation en ligne afin de connaître les principales subtilités du langage. Pour le reste, nos cours de langage C à l'université nous ont beaucoup aidé.
Contrôle du moteur
Le premier programme que nous avons réalisé fût celui du contrôle moteur. Chaque moteur est connecté à une sortie PWM et digitale. Nous avons dû renvoyer un signal analogique pour le contrôle de la vitesse (valeur allant de 0 à 255), l'entrée digitale étant utilisée pour faire tourner la roue dans le sens horaire ou trigonométrique. Le programme réalisé est très simple et répond a toute nos attentes :
void avancer(int moteur,boolean direct,int vitesse) { //avance par defaut boolean montre = HIGH; boolean trigo = LOW; if(!direct){ //si boolean nul , recule montre = LOW; trigo = HIGH; } if(moteur == 1) //moteur 1 selon les branchement { digitalWrite(AIN1,montre); //AIN1 cntrol le sens du courant digitalWrite(AIN2,trigo); //AIN2 aussi autre sens analogWrite(PWMA,vitesse); //control vitesse analogique pr garder une vitesse stable (asservis) } else { digitalWrite(BIN1,montre); digitalWrite(BIN2,trigo); analogWrite(PWMB,vitesse); } } //Tourner //tourner(0,75); //tourbne a fguahce //tourner(1,75); //tourne a droite void tourner(boolean sens,int vitesse) { if(sens) avancer(1,1,vitesse); avancer(2,1,vitesse); if(!sens) avancer(1,0,vitesse); avancer(2,0,vitesse); } void arret() { digitalWrite(STBY,LOW); //standby off } //démarrer void demarrer() { digitalWrite(STBY,HIGH); //standby on }
Nous avons donc divisé le tout en trois fonctions principales permettant de mettre en marche ou d'arrêter le moteur et d'avancer. Une fonction secondaire, utilisant les précédentes, permet de tourner.
Détection d'obstacles par UltraSon
Nous nous sommes ensuite penchés sur la partie détection ultrason qui s'est également traduite par un code simple mesurant la distance entre un objet et le capteur ultrason par émission d'impulsions :
float distanceUltraSon(int trig,int echo) { digitalWrite(trig,HIGH); delayMicroseconds(10); digitalWrite(trig,LOW); unsigned long pulsation = pulseIn(echo,HIGH);/*duree de l'etat car echo change si il recoit un signal */ if(pulsation>3000)//signal perdu { return 0.0; } else{ pulsation = pulsation/2; //division de laller retour float tmps = pulsation/1000000.0; //conversion en sec float dist = (tmps*340)*100.0; //formule de base en cm return dist;} }
Recherche de la balle
Vient ensuite la partie de détection de la balle InfraRouge par les phototransistor. Cette partie est celle qui nous a posée le plus de problèmes car les phototransistors renvoyaient continuellement des données brouillés par la lumière ambiante : il était donc impossible de différencier ces valeurs de celles de la balle. Sauf si celle-ci était vraiment très proche des capteurs.
Dans un premier temps, nous avons relié ces capteurs à une résistance de 330 Ohm et avons simplement utilisé un analogRead afin de recevoir la valeur renvoyée. Cette méthode fut rapidement abandonnée à cause du problème énoncé précédemment. Nous nous sommes alors penchés sur un programme plus complexe qui nous permet de capter simplement les signaux infrarouges pulsés. Le principe est le suivant :
Pendant un petit laps de temps, nous réalisons un grand nombre d'acquisitions et enregistrons les valeurs dans un tableau. Sachant que la balle est pulsée (supposons une pulsation à 1200 Hz). Elle renvoie une valeurs chaque milliseconde environ dans le meilleur des cas, ce qui se traduit par une succession de valeurs positives et négatives. La lumière renvoyée par le soleil par exemple, n'est quant a elle, pas pulsée. Il s'agit donc de valeurs continues et très variables. Ainsi, notre programme vérifie si deux valeurs qui se suivent sont très éloignées. Si oui, il s'agit de la balle. Sinon, il s'agit d'une autre source de lumière.
#define valTableauDetection 200
int IR(int port) { return analogRead(port); }
int detectionBalle(int a) { int tab[valTableauDetection] = {0}; int i=0; long int somme = 0; for(i=0;i<valTableauDetection;i++) { int b = IR(a); tab[i] = b; } int boucle; int tab2[valTableauDetection]; for(i=0;i<valTableauDetection;i++) { if (tab[i]<0) { tab2[i]=0; } else { tab2[i]=tab[i]; } } i=0; int compteurvar=0; for(i=0;i<valTableauDetection;i++) { somme += tab2[i]; if(((tab2[i+1]<tab2[i]*0.1)||(tab2[i+1]>tab2[i]*2)) && ((tab2[i+1]+3<tab2[i])||(tab2[i+1]-3>tab2[i]))) { compteurvar++; } } if (compteurvar>=30) { return (long int)(somme/valTableauDetection); } return 0; }
Ce code fonctionnait parfaitement lorsque le robot n'était pas en mouvement. Lorsqu'il l'était, les valeurs étaient erronées et le robot tournait sur lui même ou suivait des mauvaises directions.
Puis, lorsque nous avons ajouté le PCB qui évite les faux contacts, notre système s'est mis à très bien fonctionner. La lumière du jour ou d'une lampe n'est pas détectée, cependant avec une télécommande de télévision ou la balle pulsée, on arrive à attirer le robot.
voir vidéo :
Détections des bords du terrain
La partie concernant les capteurs de ligne a été réalisée rapidement. Le capteur de ligne renvoi des valeurs différentes selon qu'il soit positionné au dessus d'une ligne noire ou du terrain blanc. Il suffit ainsi de connaître ces deux valeurs et de faire tourner le robot lorsqu'il renvoi une valeur associée a une ligne noire. Cependant, nous avons rencontré un obstacle majeur : si le robot avance trop rapidement sur une ligne, les valeurs des capteurs de lignes ne sont pas rafraîchies assez rapidement et la ligne n'est donc pas détectée.
Ce problème était dû au fait que notre programme de détection de la balle était trop lent. Nous avons donc diminué le nombre d'acquisition pour accélérer le programme.
#define varCaptLigne 700 #define vitesseRobot 50
void testLignes() { if(IR(LineTrackAnalogC)>varCaptLigne || IR(LineTrackAnalogD)>varCaptLigne || IR(LineTrackAnalogG) > varCaptLigne) { arret(); if(IR(LineTrackAnalogC) > varCaptLigne) { demarrer(); avancer(0,0,vitesseRobot); avancer(1,0,vitesseRobot); delay(500); arret(); demarrer(); avancer(0,1,vitesseRobot); avancer(1,1,0); delay(1300); } else if(IR(LineTrackAnalogD)>varCaptLigne) { demarrer(); avancer(1,1,vitesseRobot); avancer(0,1,0); delay(800); } else if(IR(LineTrackAnalogG)>varCaptLigne) { demarrer(); avancer(1,0,vitesseRobot); avancer(0,1,0); delay(800); } } else { demarrer(); avancer(1,1,vitesseRobot); avancer(0,1,vitesseRobot); } }
Suiveur de ligne
Cette partie ne fut pas très compliquée à réaliser car nous avions déjà écrit un code similaire dans la détection des bords du terrain. Ce programme est utilisé pour ramener le robot à son garage après le tir. Le code consiste donc à dire au robot d'aller tout droit jusqu'à obtenir une valeur haute (correspondant à une ligne droite) puis après cela, de suivre la ligne en le faisant tourner à droite lorsque le capteur de ligne droit détecte une ligne noir et tourner à gauche lorsque le capteur gauche détecte une ligne noir.
void rentrerGarage() { if (trouverLigne==0) { while(IR(LineTrackAnalogC)<varCaptLigne) { demarrer(); avancer(1,1,vitesseRobot); avancer(0,1,vitesseRobot); } trouverLigne=1; } else { while(IR(LineTrackAnalogC)>varCaptLigne) { avancer(1,1,vitesseRobot); avancer(0,1,vitesseRobot); } if(IR(LineTrackAnalogG)>varCaptLigne && IR(LineTrackAnalogC)<varCaptLigne) { while(IR(LineTrackAnalogC)<varCaptLigne) { avancer(1,1,vitesseRobot); avancer(0,1,0); dernierTour=0; } } if(IR(LineTrackAnalogD)>varCaptLigne && IR(LineTrackAnalogC)<varCaptLigne) { while(IR(LineTrackAnalogC)<varCaptLigne) { avancer(0,1,vitesseRobot); avancer(1,1,0); dernierTour=1; } } if(IR(LineTrackAnalogD)>varCaptLigne && IR(LineTrackAnalogC)>varCaptLigne && IR(LineTrackAnalogG)>varCaptLigne) { if(dernierTour==0) { while(IR(LineTrackAnalogG)<varCaptLigne) { avancer(1,1,vitesseRobot); avancer(1,1,0); } } else if(dernierTour==1) { while(IR(LineTrackAnalogD)<varCaptLigne) { avancer(0,1,vitesseRobot); avancer(1,1,0); } } } } }
Programme principal
Le programme principal se base sur l'électronique représentée dans le schèma fritzing suivant :
void loop() { ValCapteurIRAvG=0; ValCapteurIRAv=0; ValCapteurIRArG=0; ValCapteurIRArD=0; ValCapteurIRAvD=0; ValCapteurIRAvG=detectionBalle(capteurIRAvG); ValCapteurIRAv=detectionBalle(capteurIRAv); ValCapteurIRArG=detectionBalle(capteurIRArG); ValCapteurIRArD=detectionBalle(capteurIRArD); ValCapteurIRAvD=detectionBalle(capteurIRAvD); int tableaucapteurs[5] = {ValCapteurIRAv,ValCapteurIRArG,ValCapteurIRAvG,ValCapteurIRArD,ValCapteurIRAvD}; tableaucapteurs[0]=ValCapteurIRAv; tableaucapteurs[1]=ValCapteurIRArG; tableaucapteurs[2]=ValCapteurIRAvG; tableaucapteurs[3]=ValCapteurIRArD; tableaucapteurs[5]=ValCapteurIRAvD; pinceActionner(ouvrir); if (maximum(tableaucapteurs,5)==0 && trouverBalle==0) { testLignes(); } if(ValCapteurIRArG==maximum(tableaucapteurs,5) && ValCapteurIRArG!=0) { demarrer(); trouverBalle=0; compteurTourner=0; ValCapteurIRAv=detectionBalle(capteurIRAv); while(ValCapteurIRAv==0) { compteurTourner++; ValCapteurIRAv=detectionBalle(capteurIRAv); tableaucapteurs[0] = ValCapteurIRAv; avancer(1,1,vitesseRobot+vitesseTourner+Ajust); avancer(0,0,vitesseRobot+vitesseTourner); if(compteurTourner>=limiteTourner) break; } arret(); } else if(ValCapteurIRArD==maximum(tableaucapteurs,5) && ValCapteurIRArD!=0) { demarrer(); trouverBalle=0; compteurTourner=0; ValCapteurIRAv=detectionBalle(capteurIRAv); while(ValCapteurIRAv==0) { compteurTourner++; ValCapteurIRAv=detectionBalle(capteurIRAv); tableaucapteurs[0] = ValCapteurIRAv; avancer(0,1,vitesseRobot+vitesseTourner); avancer(1,0,vitesseRobot+vitesseTourner+Ajust); if(compteurTourner>=limiteTourner) break; } arret(); } else if(ValCapteurIRAvD==maximum(tableaucapteurs,5) && ValCapteurIRAvD!=0)/ { demarrer(); trouverBalle=0; compteurTourner=0; ValCapteurIRAv=detectionBalle(capteurIRAv); while(ValCapteurIRAv==0) { compteurTourner++; ValCapteurIRAv=detectionBalle(capteurIRAv); tableaucapteurs[0] = ValCapteurIRAv; avancer(0,1,vitesseRobot+vitesseTourner); avancer(1,0,vitesseRobot+vitesseTourner+Ajust); if(compteurTourner>=limiteTourner) break; } arret(); } else if(ValCapteurIRAv==maximum(tableaucapteurs,5) && ValCapteurIRAv!=0) { demarrer(); while(ValCapteurIRAv<valeurBalleDansPince) { ValCapteurIRAv=detectionBalle(capteurIRAv); tableaucapteurs[0] = ValCapteurIRAv; avancer(0,1,vitesseRobot); avancer(1,1,vitesseRobot+Ajust); testLignesAvant(); } trouverBalle=1; delay(500); pinceActionner(fermer); arret(); delay(1500); demarrer(); ValCapteurIRAvG=detectionBalle(capteurIRAvG); while(ValCapteurIRAvG<5) //Capteur avant gauche doit détecter le but { ValCapteurIRAvG=detectionBalle(capteurIRAvG); testLignesBalle(); } arret(); delay(200); pinceActionner(ouvrir); delay(300); tir(); delay(2000); demarrer(); trouverBalle=0; while(trouverBalle==0) { rentrerGarage(); } } }
Problèmes rencontrés et résolution
Problèmes liés au capteur ultrason
Le capteur Ultrason en lui même ne présentait pas de problèmes particuliers, ni son code qui renvoyait une valeur adéquate. C'est les faux contacts dû à la plaque d'essai qui faussait le plus souvent les valeurs, soit en ne renvoyant quasiment rien, soit en renvoyant constamment une même valeur. Ce problème est réglé par la mise en place du PCB qui a supprimé les faux contacts.
Problèmes liés aux capteurs infrarouge
La détection de balle par les capteurs infrarouge est la partie qui nous a pris le plus de temps à résoudre en raison de nombreux problèmes que nous n'avions pu résoudre rapidement. En effet, les capteurs infrarouge, comme leur nom l'indique, captent le rayonnement infrarouge. Cependant, ce rayonnement est présent dans toute les sources lumineuses tel que le soleil, la lumière émise par une ampoule ou encore en moindre intensité par le corps humain. Ainsi, à moins que la balle ne se trouve a une distance inférieure a 5 centimètre des capteurs, les valeurs renvoyées par les différents capteurs disposés de part et d'autre du robot sont toutes à peu prés identiques.
Nous nous sommes donc penchés sur un programme ne prenant en compte que les signaux infrarouge modulés afin de ne pas capter les signaux parasites. Ce programme nous a pris près de 5 séances à mettre en place car nous captions toujours quelques valeurs parasites.
Nous avons alors tenté de changer les résistances afin d'obtenir des valeurs adéquates et nous avons conclu que la résistance de 330 Ohm était l'idéale car elle permet de ne pas recevoir de signal trop faible mais le signal renvoyé par la balle est quand même pris en compte par le programme.
Par rapport à la disposition des capteurs : nous avons disposé 5 capteurs. Deux aux extrémités arrière du robot et 3 disposés devant. Deux sont positionnés aux extrémités et un est centré. Ce système permet une bonne précision et une détection de la balle à n'importe quel endroit. En effet, si nous n'avions pas disposés de capteurs à l'arrière, le robot aurait effectué une rotation complète avant de trouver la balle par ses capteurs avant.
Nous avons également disposé des petits caches entre les capteurs afin d'augmenter la précision et éviter que plusieurs capteurs ne reçoivent un signal simultanément.
Problèmes liés aux capteurs de ligne
Le problème majeur par rapport aux capteurs de ligne concerne le temps de rafraîchissement des valeurs. En effet, lorsque nous lancions ce programme seul, le robot détectait parfaitement les lignes. Mais l'ajout du programme de recherche de la balle qui était assez long, réduisait la capacité de détection des lignes en raison du temps qu'il prend à stocker les valeurs dans un tableau de plus de 100 cases. Cependant, ce problème peut être partiellement résolu en limitant la vitesse du robot. Ainsi, il passera sur une ligne plus lentement et aura ainsi le temps de détecter le changement de valeur tout en cherchant la balle par ses capteurs infrarouge. Mais nous avons aussi modifié le programme de détection de la balle afin qu'il soit plus rapide et ne perturbe donc pas la détection des lignes.
Réalisation de la cage de but
Aspect Mécanique
La partie mécanique de la cage de but comprend la réalisation de la forme voulue pour le but en une matière solide et accessible. Nous nous sommes ainsi tourné vers des plaques de bois MDF de 3 mm d'épaisseur en raison de son abondance dans l'établissement.
Nous avons décidés de réaliser le but de forme rectangulaire et d'ajouter des filets afin de parfaire la ressemblance avec de vrais buts. Nous avions tout d'abord réfléchi sur la possibilité de placer un filet couvrant tout le but sauf la partie supérieure, avant de décider d'en placer uniquement sur les côtés. Ce choix est uniquement motivé par l'aspect esthétique.
Nous avons également dessiné des encoches sur les planches de bois lors de la découpe laser afin de pouvoir emboîter les différentes parties du but et éviter d'utiliser de la colle ou encore de visser. La cage de but a été dessinée sur Inkscape afin de pouvoir découper au laser la plaque MDF. Le résultat sur le logiciel était le suivant :
Le rendu après découpe et assemblage est le suivant :
Aspect Electronique
Le matériel utilisé pour la réalisation de la cage de but est constitué de 6 émetteurs infrarouge, un afficheur 7 segments, un transistor et deux phototransistors.
Les deux phototransistors sont positionnés de chaque coté du but de façon à détecter l'entrée de la balle. L'afficheur 7 segments incrémente le score lorsque les phototransistors détectent la balle. Trois émetteurs infrarouge sont positionnés sur le toit, deux sur les cotés afin de délimiter le but, et le dernier est positionné sur le milieu de la partie arrière du but.
Le circuit a été fixé sous le toit du but de manière a ne pas gêner l’accès de la balle. Nous avons schématisé les connections sur Fritzing, à l'exception de l'afficheur 7 segments qui n'est pas disponible sous ce logiciel :
Les trois émetteurs reliés aux transistors émettent un signal pulsé a 1000 Hz. La motivation du choix de connecter ces émetteurs au transistor est notamment de pouvoir les alimenter par un unique pin de l'Arduino en amplifiant le courant qui en provient afin d'alimenter les trois émetteurs de la même manière. L'utilité de cet aspect sera détaillé dans la partie concernant la programmation. Les trois autres émetteurs sont reliés à différents pins et ne sont pas pulsés : ils émettent en continu. Nous avons choisi de placer ces deux types d'émission dans notre but afin que les autres groupes puissent également l'utiliser. En effet, peu de groupes se sont basés sur une émission pulsée.
Les photo-transistors sont connectés aux entrées analogiques de l'Arduino. Lorsque la balle traverse le but, elle est détectée par ce premier photo-transistor. Le second sert à vérifier si la balle est toujours dans le but afin d'éviter d'incrémenter continuellement le score.
L'afficheur 7 segments est utilisé en communication série. Nous l'alimentons directement sur la sortie 3.3 V de l'Arduino.
Enfin, nous avons placé le récepteur Xbee (non représenté sur le schéma), mais il n'est pas utilisé car nous l'avons reçu tardivement.
Partie programmation
La programmation du but se base en grande partie sur celle du robot car nous utilisons le même programme pour détecter l'entrée de la balle . Les seules nouveautés que nous retrouvons concernent l'afficheur 7-segments ainsi que les émetteurs pulsés .
Sur les trois méthodes de communication qu'offre l'afficheur 7 segments , nous avons choisis la communication série car elle offre le plus de simplicité : il suffit d'envoyer une chaîne de 4 caractère qui s'afficheront dessus :
#include <SoftwareSerial.h> const int softTx = 8; const int softRx = 7; SoftwareSerial comm(softRx, softTx); unsigned int counter = 0; char tempString[10]; void clearDisplay() { comm.write(0x76); // Clear display command } void brillance(byte value) { comm.write(0x7A); // Set brightness command byte comm.write(value); // brightness data byte } void setDecimals(byte decimals) { comm.write(0x77); comm.write(decimals); } void setup() { comm.begin(9600); Serial.begin(9600); brillance(255); clearDisplay(); comm.print("0000"); } void loop() { sprintf(tempString, "%4d", counter); comm.print(tempString); setDecimals(0b000000); }
Nous importons tout d'abord le module SoftwareSerial qui va nous permettre de mettre en place la communication entre l'afficheur et l'arduino que nous avons connectés au pin 8 . Nous créons trois fonctions clearDisplay , brillance et setDecimals qui vont respectivement supprimer tout affichage de l'écran , ajuster la brillance des caractères , et mettre en place des virgules au cas ou nous voudrions afficher des valeurs décimales . Dans notre cas , nous n'en avons pas besoin mais la fonction est quand même utilisée pour n'afficher aucune virgule . Enfin , la communication est mise en place a 9600 bauds . Dans le loop , la fonction sprintf permet de convertir un entier (int) , qui correspond au counter , en une chaine de 4 caractères (définie par %4d) qui va être stockée dans tempString . Finalement , tempString est envoyée à l'afficheur par le biais de la commande comm.print() .
Concernant la partie émission infrarouge , nous avons simplement passé en mode HIGH tout les pins connectés qui sont censés émettre en continu et nous avons utilisé la fonction tone() sur le pin auxquel nous avons connecté les trois émetteurs qui enverront des valeurs pulsées :
void balisestart() { digitalWrite(balisehg,HIGH); digitalWrite(balisehd,HIGH); digitalWrite(balisehm,HIGH); digitalWrite(baliseg,HIGH); digitalWrite(balised,HIGH); } void baliseoff() { digitalWrite(balisehg,LOW); digitalWrite(balisehd,LOW); digitalWrite(balisehm,LOW); digitalWrite(baliseg,LOW); digitalWrite(balised,LOW); } void loop() { if(etat) //la variable état contient normalement une valeur booléenne , dependant du message transmis par la Xbee du robot joueur { balisestart(); tone(pinapulser,1000); } else { baliseoff(); noTone(baliseg); } }
Problèmes rencontrés et résolution
Nous avons rencontrés deux principaux problèmes lors de la réalisation de la cage de but: le premier concerne la puissance d'émission des infrarouges pulsés. En effet, le robot ne parvient pas à détecter le but a moins d'être a moins de 15 cm de celui-ci. Ce problème peut être réglé par l'utilisation d'un transistor avec un meilleur gain ou l'augmentation de la puissance fournie par les piles.
Finalement, nous avions le problème de pulsation de l'émission au départ: notre robot ne pouvant détecter que des émissions pulsées, nous nous basions sur la fonction tone(), mais celle-ci ne fonctionnait que sur un pin. Ceci est dû au fait que l'Arduino ne possède que trois timers, dont deux sont utilisés par le processeur, ce qui n'en laisse qu'un pour les pin. Il fallait trouver une solution pour pouvoir brancher plusieurs émetteurs sur un même et unique pin: la solution consiste a utiliser un transistor pour amplifier le courant distribué par le pin et placer en série les émetteurs après le transistor.
Conclusion
Ce bureau d'étude sur les robots communicants fut très intéressant. Nous avons beaucoup appris au cours de ces semaines et ces connaissances en informatique et en électronique nous servirons pour nos études. En effet, nous souhaitons tous les deux continuer dans des études d'ingénieur spécialisé en informatique et en robotique.
Ce projet nous a pris beaucoup de temps car nous nous sommes fortement investis. Mais cela ne nous a pas dérangé car nous avons apprécié le travail sur ce robot et voulions obtenir un matériel le plus fonctionnel possible.
Nous sommes satisfait du résultat de notre travail même si lors de la vidéo, nous avons eu certains problèmes de détection de la balle qui étaient pourtant réglé précédemment.