RobotiqueCoupeGEII : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
(Alimentation / Régulation)
(Algorithme)
 
(201 révisions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
 
[[Catégorie:Projets]]
 
[[Catégorie:Projets]]
  
=Présentation du projet : Robot joueur de tennis=
+
=Présentation du projet=
  
Le but du robot est d'envoyer le plus de balle possible dans le camps adverse, sans jamais franchir la ligne médiane qui sépare les deux camps et en ne contrôlant qu'une balle à la fois
+
==Notre équipe==
 +
Nous sommes 5 étudiants venant de l’IUT de Troyes en formation d’un DUT Génie électrique et informatique industrielle (GEII), lors de cette formation nous avons eu l’opportunité de réaliser un projet de robotique durant l’année 2020-2021, avec l’objectif de participer à la Coupe Robot GEII.<br>
 +
Notre groupe est composé de Dan Boilleau, Luca Giocondo, Mathieu Beauvois, Louis Foucher et Loris Baroni.<br><br>
  
== Cahier des charges de la compétition ==
+
Durant le projet nous nous sommes répartis les tâches à effectuer au fur et à mesures :
 +
  - Dan Boilleau : utilisation des moteurs de déplacements avec les ponts en H / réalisation de la partie permettant de lancer et d'attraper la balle.
 +
 
 +
  - Luca Giocondo : réalisation de la partie de détection de la ligne médiane.
 +
 
 +
  - Louis Foucher : réalisation de la partie Crève-ballon / élaboration de support pour différents capteurs.
 +
 
 +
  - Mathieu Beauvois : réalisation de la partie détection de la balle avec la caméra Pixy2 / réalisation de la partie boussole (magnétomètre).
 +
 
 +
  - Loris Baroni : Réalisation de la partie des télémètres / Assemblages du robot / réalisation de la carte électronique de contrôle.
 +
 
 +
==Objectifs==
 +
Nous avons pour but de réaliser un robot pouvant jouer au tennis de manière autonome en vue de participer à la coupe robotique GEII. Durant la compétition, deux robots s’affrontent. Notre robot doit se déplacer sur le terrain sans toucher les murs ou encore franchir la ligne médiane de séparation des camps. Il doit également attraper et renvoyer un maximum de balles de tennis standard dans le camp adverse en contrôlant une balle à la fois. De plus, Il doit avant la fin du temps imparti (90 secondes : durée du match) crever un ballon accroché à lui-même. Une fois le ballon crevé, le robot doit être immobile sur la ligne médiane (Pour rapporter des points bonus). Nous devons également respecter des contraintes de taille, de composants tels que la batterie ou encore les moteurs.
 +
 
 +
== Cahier des charges / règlement de la compétition ==
 
[[Fichier:Aire.png|thumb|upright=0.95|alt=texte alternatif|Aire de jeu]]
 
[[Fichier:Aire.png|thumb|upright=0.95|alt=texte alternatif|Aire de jeu]]
  
 
=== L'aire de jeu ===
 
=== L'aire de jeu ===
L'aire de jeu a pour dimension 8 x 4 m avec une ligne médiane de 67 cm de large.
+
L'aire de jeu a pour dimension 8 x 4 m avec une ligne médiane de 67 cm de large soit un espace de 16 m² pour le déplacement de notre robot.
  
 
=== Les balles ===
 
=== Les balles ===
Les balles utilisées sont des balles de tennis standard. Elles sont placées aléatoirement sur le terrain à l'exception de 3 balles placées systématiquement aux 3 intersections des lignes de notre terrain (points jaunes sur le schéma).
+
Les balles utilisées sont des balles de tennis standard.<br>
 +
Elles sont placées aléatoirement sur le terrain à l'exception de 3 balles placées systématiquement aux 3 intersections des lignes de notre terrain (points jaunes sur le schéma).
 
[[Fichier:BaliseTerrain.png|vignette|droite|schéma aire de jeu]]
 
[[Fichier:BaliseTerrain.png|vignette|droite|schéma aire de jeu]]
  
 
=== Le Robot ===
 
=== Le Robot ===
Le robot doit être autonome. Il peut utiliser les moteurs, la transmission, les roues, le châssis et la batterie officielle de l'événement, mais il est possible d'utiliser aussi ses propres composants. Le robot peut également utiliser un système propulseur. Lors du lancement d'un match, le robot doit être démarré à l'aide d'un bouton qu'un utilisateur viendra actionner.
+
Le but du robot est d'envoyer le plus de balle possible dans le camps adverse à l'aide d'un système propulseur, sans jamais franchir la ligne médiane qui sépare les deux camps et en ne contrôlant qu'une balle à la fois.
 +
Lors du lancement d'un match, le robot doit être démarré à l'aide d'un bouton qu'un utilisateur viendra actionner, ensuite il sera autonome. Le robot gagnant est celui qui aura le moins de balle dans son camp à la fin du match.
  
 
=== Les Balises ===
 
=== Les Balises ===
Ligne 24 : Ligne 42 :
 
Le robot doit répondre aux exigences fixées.<br>
 
Le robot doit répondre aux exigences fixées.<br>
 
Ces exigences sont les suivantes :<br>
 
Ces exigences sont les suivantes :<br>
- Un ballon de baudruche est fixé à 30 cm du sol et doit être percé avant la fin du temps imparti des matchs (90 secondes).<br>
+
- Le robot rentre dans une boite de 40 x 30 x 30 cm.<br>
 +
- Un ballon de baudruche est fixé à 30 cm du sol et doit être percé sur la ligne médiane avant la fin du temps imparti des matchs (90 secondes).<br>
 
- Le robot ne présente aucun danger, ni au repos, ni en fonctionnement (pas de pièces coupantes...).<br>
 
- Le robot ne présente aucun danger, ni au repos, ni en fonctionnement (pas de pièces coupantes...).<br>
- Un dispositif permettant de couper le courant doit être mit en place.<br>
+
- Un dispositif permettant de couper le courant doit être mit en place (bouton d'arrêt d'urgence).<br>
 
- Un dispositif mécanique de mise en marche doit être présent.<br>
 
- Un dispositif mécanique de mise en marche doit être présent.<br>
- Un système permettant de contrôler une seule balle à la fois
 
  
=Fonctionnement du robot=
+
=== Règlement complet de la compétition ===
 +
Pour plus d'information sur les règles, je vous invite à aller regarder la réglementation complète:
 +
[[Media:Coupe_GEII_-_Règlement_-_2020.pdf| Règlement]]
 +
 
 +
=Recherche et développement=
 +
 
 +
==Schéma fonctionnel==
 +
Ci-dessous le schéma fonctionnel qui nous a servi de base dans notre projet.
 +
 
 +
[[Fichier:Schema_fonctionnel.PNG|vignette|gauche|Schéma fonctionnel]]
 +
<br><br><br><br><br><br><br><br><br><br><br>
 +
 
 +
==Algorithme==
 +
Ici l'algorithme qui nous a servi de point de départ pour avoir chaque étape de se que devra faire le robot durant le match, celui-ci a été décomposé en plusieurs parties que nous avons ensuite réparties entre les membres du groupe.
 +
[[Fichier:Algo.PNG|vignette|gauche|Schéma fonctionnel]]
 +
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
  
 
==Prototype==
 
==Prototype==
[[Fichier:prototype_robot1A.JPG|200px|thumb|upright|Prototype robot avec actionneur fonctionnel]]
+
[[Fichier:prototype_robot1A.JPG|200px|thumb|Prototype robot avec actionneur fonctionnel]]
Dans un premier temps, nous avons utilisés un robot existant afin de pouvoir tester, configurer ou encore programmer différente partie du robot à l'aide d'un Arduino.
+
Dans un premier temps, nous avons utilisés un robot existant afin de pouvoir tester, configurer ou encore programmer différente partie du robot à l'aide d'un Arduino UNO. Dans un premier il a fallut piloter les moteurs permettant un déplacement du robot sur notre terrain à l'aide de pont en H permettant de piloter les moteurs dans les deux sens de rotation, On a programmer la base de notre code. Par la suite nous avons pu coupler au robot la caméra Pixy2 afin que notre robot puisse suivre une balle de tennis en déplacement, après plusieurs test les essais fut concluant, ces étapes de test sont indispensables pour le bon fonctionnement de notre futur robot. On a également pu tester la détection d'un obstacle afin de l'éviter ... (etc) 
<br><br><br><br><br><br><br><br><br><br><br><br><br><br>
+
<br><br><br><br><br><br><br><br><br><br><br>
==Schéma fonctionnel / Algorithme==
+
 
 +
=Solution adoptée=
  
 
==Alimentation / Régulation==
 
==Alimentation / Régulation==
[[Fichier:BatterieRobot.jpg|300px|right|Batterie fournie]]
+
[[Fichier:BatterieRobot.jpg|300px|thumb|Batterie fournie]]
 +
[[Fichier:abaisseur_de_tension.png|300px|thumb|abaisseur de tension]]
 
===La batterie===
 
===La batterie===
Notre robot comprend un pack de piles rechargeables 4x 18650 LiFePO 4 Emmerich 4A12318650RK 12.8 V 1100 mAh pour permettre d'alimenter les différents éléments.
+
Notre robot comprend un pack de piles rechargeables 4x 18650 LiFePO 4 Emmerich 4A12318650RK 12.8 V 1100 mAh pour permettre d'alimenter les différents éléments.<br>
 
+
Une tension minimum de 9V est nécessaires pour le bon fonctionnement de notre robot.<br>
 +
<br><br><br><br>
 
===Abaisseur de tension===
 
===Abaisseur de tension===
 +
La batterie fournie délivre 12.8V, hors nous avons besoin d'une alimentation 5V pour le bon fonctionnement de certain capteur ou actionneur. <br>
 +
C'est pourquoi nous avons utilisée un abaisseur de tension réglable.<br>
 +
<br><br><br><br><br>
  
 
==Gérer==
 
==Gérer==
  
 
===ATmega 2560===
 
===ATmega 2560===
 +
[[Fichier:Conecteur ISP schéma eagle.PNG|200px|vignette|droite|Schéma eagle connecteur ISP]]
 +
[[Fichier:Atmega2560.PNG|200px|vignette|gauche|Microcontroleur ATmega 2560 16MHz]]<br>
 +
Ce microcontrôleur qui est présent sur les Arduino Méga possède un grand nombre de port ce qui nous est utile pour l'élaboration d'une carte complète avec un grand nombre de capteur et d'actionneur.<br>
 +
Il est programmable à l'aide du logiciel Arduino ainsi qu'un programmateur brancher sur un connecteur ISP, le connecteur ISP sert également à brancher la caméra Pixy 2 au microcontrôleur.
 +
[[Fichier:schéma atmega2560.jpg|200px|vignette|gauche|Schéma ATmega2560]]
 +
[[Fichier:Programmateur.JPG|vignette|centré|Programmateur connecté à la broche ISP ]]
  
===Carte Capteur===
+
===Carte électronique de contrôle===
 +
Pour la réalisation de notre robot, afin de ne pas avoir de fil volant qui pourrait se débrancher nous avons réaliser une carte électronique sur le logiciel Eagle. Cette carte qui comporte le microcontrôleur permet de connecter et contrôler les capteurs et actionneur qui sont tous reliés à la carte. Grâce à cette carte cela nous permet d'alimenter facilement tous les composant à la tension voulue.<br>
 +
*[[Média:SchemaROBOT2021_V4.sch|Schéma de la carte]]
 +
*[[Média:ROBOT2021_V6.brd|Board de la carte]]
 +
Lorsque la carte a été imprimé, et après la soudure des composant traversant et CMS sur la carte, nous sommes passer en phase de test pour vérifier que l'ensemble des partie de la carte fonctionnait, l'absence de court circuit ainsi que la continuité des pistes et des vias, puis la bonne transmission de données à l'aide du programmateur et du module Xbee pour bien récupérer les informations en utilisation sans fil sur l'ordinateur.
 +
[[Fichier:Carte sch.PNG|600px|vignette|gauche|Schéma eagle de la carte électronique]]
 +
[[Fichier:Carte brd.PNG|vignette|centré|Board de la carte électronique]]
 +
[[Fichier:Carte top.JPG|vignette|gauche|Face Top de la Carte électronique avec les branchements]]
 +
[[Fichier:Carte bot.JPG|vignette|centré|Face Bot de la carte électonique]]
 +
<br>
  
==Actionneur==
+
==Actionneurs==
  
 
===Déplacement===
 
===Déplacement===
 +
dan
  
 
===Système propulsion===
 
===Système propulsion===
 +
dan
 +
 +
===Crève-Ballon===
 +
[[Fichier:Mat creve ballon.PNG|vignette|gauche|Support de Fixation crève ballon]]
 +
<br><br>
 +
Pour la crevaison du ballon, nous avons utilisé un disque souple en plastique qui est piloté par un moteur à courant continu, ainsi qu’un servo-moteur. Aussi, nous avons réalisé un mât comme support pour l’ensemble décrit ci-dessus. Celui-ci nous sert aussi à positionner le support de la caméra PIXY. Le ballon est maintenu par un câble qui serre le ballon au niveau du nœud et un élastique qui est attaché au câble qui maintient le ballon pour que celui-ci reste en place tout le long du match.
 +
 +
 +
Lien vers la vidéo de la crevaison du ballon :
 +
[https://drive.google.com/file/d/15fuKFu1aPadkrwBS-FIqvhHlt_E1LWdR/view?usp=sharing vidéo crève ballon]
 +
[[Fichier:20210316 102747.jpg|vignette|droite|Ensemble Crève ballon]]
 +
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
 +
{{boîte déroulante/début|titre=Exemple programme crevaison du ballon (fonctionnel)}}
 +
<source lang=Arduino>
 +
#include <Servo.h>
 +
 +
Servo monservo;
 +
//int bp;
  
===Crève Ballon===
+
void setup(){
 +
  //pinMode(3, OUTPUT);
 +
  DDRK|=(1<<PK7);
 +
  //pinMode(2, INPUT);
 +
  DDRH&=~(1<<PH5);
 +
  DDRH&=~(1<<PH4);
 +
  monservo.attach(9);  // utilise la broche 9 pour le contrôle du servomoteur
 +
  monservo.write(0); // positionne le servomoteur à 0°
 +
  delay(5000);
 +
  //Serial.begin(9600);
 +
}
  
==Détection==
+
void loop(){
 +
  //bp=digitalRead(2);
 +
  //Serial.println(bp);
 +
  //if (bp==1){
 +
    monservo.write(120);
 +
    //delay(5000);
 +
    PORTK|=(1<<PK7);
 +
    delay(500);
 +
    PORTK&=~(1<<PK7);
 +
    //delay(1000);
 +
    monservo.write(0);
 +
    delay(10000);
 +
    //bp=0;
 +
  //}
 +
  //else {}
 +
 
 +
}
 +
</source>
 +
{{boîte déroulante/fin}}
 +
 
 +
==Capteurs==
  
 
===Détection des balles===
 
===Détection des balles===
 +
====<span style="color: orange;">De près : Caméra Pixy</span>====
 +
[[Fichier:Pixyrobot.PNG|vignette|Caméra Pixy2 montée sur le robot]]
 +
[[Fichier:Pixymon.PNG|vignette|gauche|Balle de tennis dans le logiciel PixyMon]]
 +
Pour détecter précisément les balles de tennis qui seront proches de notre robot nous avons décidé d'utiliser une caméra Pixy 2.<br>
 +
Grace à la caméra nous pouvons obtenir la position en X et en Y de la balle ce qui nous permet via un programme Arduino de diriger le robot vers la balles détecté.<br>
 +
Cette dernière est alimentée en 5V et est également connectée à notre microcontrôleur sur la broche ISP.<br>
 +
Pour pouvoir utiliser la caméra sur Arduino, nous avons eux besoin de télécharger et d'importer la librairie suivante sur arduino:
 +
[[Media:arduinopixy.zip| Librairie]]
 +
 +
<br><br><br><br><br><br><br><br><br>
 +
 +
{{boîte déroulante/début|titre=Exemple programme détection de balles avec caméra Pixy2 (fonctionnel)}}
 +
<source lang=Arduino>
 +
#include <Pixy2.h>
 +
 +
// This is the main Pixy object
 +
Pixy2 pixy;
 +
 +
void setup()
 +
{
 +
  Serial.begin(115200);
 +
  Serial.print("Starting...\n");
 +
 +
  pixy.init();
 +
}
 +
 +
void loop()
 +
{
 +
  int i;
 +
  int x;
 +
  int y;
 +
  // grab blocks!
 +
  pixy.ccc.getBlocks();
 +
 +
  // si on détecte la balle
 +
  if (pixy.ccc.numBlocks)
 +
  {
 +
 +
  Serial.print("position x de la balle ");
 +
  Serial.print(i);
 +
  Serial.print(": ");
 +
  Serial.println(pixy.ccc.blocks[i].m_x); // on indique la position de la balle sur l'axe x (entre 316 et 0)
 +
 +
 +
 +
  if (pixy.ccc.blocks[i].m_x<158){ // si la balle est plus à gauche par rapport au milieu de l'axe, on tourne à gauche
 +
    Serial.println("tourner à gauche");
 +
  }
 +
 +
  if (pixy.ccc.blocks[i].m_x>158) {
 +
  Serial.println("tourner à droite"); // si la balle est plus à droite par rapport au milieu de l'axe, on tourne à droite
 +
  }
 +
 +
  Serial.print("position y de la balle ");
 +
  Serial.print(i);
 +
  Serial.print(": ");
 +
  Serial.println(pixy.ccc.blocks[i].m_y);
 +
 +
 +
 +
  if (pixy.ccc.blocks[i].m_y<104){ // si la balle est plus en haut par rapport au milieu de l'axe, on tourne à gauche
 +
    Serial.println("avancer doucement");
 +
  }
 +
   
 +
  if (pixy.ccc.blocks[i].m_y>104) {
 +
  Serial.println("avancer rapidement"); // si la balle est plus en bas par rapport au milieu de l'axe, on tourne à droite
 +
  }
 +
 +
  }
 +
 +
//si on ne détecte pas la balle
 +
else {
 +
  Serial.println("chercher la balle");
 +
 +
 +
 +
 +
}
 +
 +
}
 +
 +
</source> {{boîte déroulante/fin}}
 +
 +
====<span style="color: orange;">De loin : Lidar Garmin Lite V3</span>====
 +
[[Fichier:Lidar garmin test.JPG|vignette|Test du capteur : Lidar Garmin Lite V3]]
 +
Avec la caméra Pixy2 nous ne pouvons pas détecter précisément la balle de près et de loin, c'est pourquoi nous avons décider d'utiliser ce Lidar qui à une portée de 5 mètres ( en dessous de 40 cm ces mesures sont fausses). Pour son bon fonctionnement le Lidar Garmin doit être positionner à la hauteur de la balle et parallèle au sol. Avec ce capteur on ne pourra que diriger grossièrement le robot vers la balle afin que la caméra prennent le relais ensuite. Au niveau des branchement, il fonctionnent avec une alimentation de 5V et est connecté sur le bus I2C (SDA-SCL). Il est également nécessaire de placer un condensateur électrolytique de 680 microfarad entre le 5V et le GND.<br>
 +
Pour l'utilisation du programme ci-dessous il est nécessaires d'effectuer les branchementS (comme indiqué dans la [https://cdn.sparkfun.com/assets/9/a/6/a/d/LIDAR_Lite_v3HP_Operation_Manual_and_Technical_Specifications.pdf Datasheet]). Il faut également inclure directement la librairie du capteur sur le logiciel Arduino. Comme on peut le constater la partie de programmation permettant de diriger le robot vers une balle éloigner n'a pas encore pu être réaliser.
 +
[[Fichier:Lidar garmin position.JPG|vignette|centré|Positionnement du Lidar]]
 +
<br><br><br>
 +
{{boîte déroulante/début|titre=Programme d'utilisation du Lidar Garmin Lite V3 dans différent mode de fonctionnement (Affichage de la distance dans la liaison série, fonctionnel)}}
 +
<source lang=Arduino>
 +
#include <stdint.h>
 +
#include <Wire.h>
 +
#include <LIDARLite_v3HP.h>
 +
 +
LIDARLite_v3HP myLidarLite;
 +
 +
#define FAST_I2C
 +
 +
enum rangeType_T
 +
{
 +
RANGE_NONE,
 +
RANGE_SINGLE,
 +
RANGE_CONTINUOUS,
 +
RANGE_TIMER
 +
};
 +
 +
void setup()
 +
{
 +
// Initialize Arduino serial port (for display of ASCII output to PC)
 +
Serial.begin(115200);
 +
 +
// Initialize Arduino I2C (for communication to LidarLite)
 +
Wire.begin();
 +
#ifdef FAST_I2C
 +
    #if ARDUINO >= 157
 +
        Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
 +
    #else
 +
        TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
 +
    #endif
 +
#endif
 +
 +
// Configure the LidarLite internal parameters so as to lend itself to
 +
// various modes of operation by altering 'configure' input integer to
 +
// anything in the range of 0 to 5. See LIDARLite_v3HP.cpp for details.
 +
myLidarLite.configure(0);
 +
}
 +
 +
 +
void loop()
 +
{
 +
uint16_t distance;
 +
uint8_t  newDistance = 0;
 +
uint8_t  c;
 +
rangeType_T rangeMode = RANGE_NONE;
 +
 +
PrintMenu();
 +
 +
// Continuous loop
 +
while (1)
 +
{
 +
    // Each time through the loop, look for a serial input character
 +
    if (Serial.available() > 0)
 +
    {
 +
        //  read input character ...
 +
        c = (uint8_t) Serial.read();
 +
 +
        // ... and parse
 +
        switch (c)
 +
        {
 +
            case 'S':
 +
            case 's':
 +
                rangeMode = RANGE_SINGLE;
 +
                break;
 +
 +
            case 'C':
 +
            case 'c':
 +
                rangeMode = RANGE_CONTINUOUS;
 +
                break;
 +
 +
            case 'T':
 +
            case 't':
 +
                rangeMode = RANGE_TIMER;
 +
                break;
 +
 +
            case '.':
 +
                rangeMode = RANGE_NONE;
 +
                break;
 +
 +
            case 'D':
 +
            case 'd':
 +
                rangeMode = RANGE_NONE;
 +
                dumpCorrelationRecord();
 +
                break;
  
====De près : Caméra Pixy====
+
            case 'P':
 +
            case 'p':
 +
                rangeMode = RANGE_NONE;
 +
                peakStackExample();
 +
                break;
  
====De loin : Lidar Garmin Lite V3====
+
            case 0x0D:
 +
            case 0x0A:
 +
                break;
 +
 
 +
            default:
 +
                rangeMode = RANGE_NONE;
 +
                PrintMenu();
 +
                break;
 +
        }
 +
    }
 +
 
 +
    switch (rangeMode)
 +
    {
 +
        case RANGE_NONE:
 +
            newDistance = 0;
 +
            break;
 +
 
 +
        case RANGE_SINGLE:
 +
            newDistance = distanceSingle(&distance);
 +
            break;
 +
 
 +
        case RANGE_CONTINUOUS:
 +
            newDistance = distanceContinuous(&distance);
 +
            break;
 +
 
 +
        case RANGE_TIMER:
 +
            delay(250); // 4 Hz
 +
            newDistance = distanceFast(&distance);
 +
            break;
 +
 
 +
        default:
 +
            newDistance = 0;
 +
            break;
 +
    }
 +
 
 +
    // When there is new distance data, print it to the serial port
 +
    if (newDistance)
 +
    {
 +
        Serial.println(distance);
 +
    }
 +
 
 +
    // Single measurements print once and then stop
 +
    if (rangeMode == RANGE_SINGLE)
 +
    {
 +
        rangeMode = RANGE_NONE;
 +
    }
 +
}
 +
}
 +
 
 +
void PrintMenu(void)
 +
{
 +
Serial.println("=====================================");
 +
Serial.println("== Type a single character command ==");
 +
Serial.println("=====================================");
 +
Serial.println(" S - Single Measurement");
 +
Serial.println(" C - Continuous Measurement");
 +
Serial.println(" T - Timed Measurement");
 +
Serial.println(" . - Stop Measurement");
 +
Serial.println(" D - Dump Correlation Record");
 +
Serial.println(" P - Peak Stack Example");
 +
}
 +
 
 +
//---------------------------------------------------------------------
 +
// Read Single Distance Measurement
 +
//
 +
// This is the simplest form of taking a measurement. This is a
 +
// blocking function as it will not return until a range has been
 +
// taken and a new distance measurement can be read.
 +
//---------------------------------------------------------------------
 +
uint8_t distanceSingle(uint16_t * distance)
 +
{
 +
// 1. Wait for busyFlag to indicate device is idle. This must be
 +
// done before triggering a range measurement.
 +
myLidarLite.waitForBusy();
 +
 
 +
// 2. Trigger range measurement.
 +
myLidarLite.takeRange();
 +
 
 +
// 3. Wait for busyFlag to indicate device is idle. This should be
 +
// done before reading the distance data that was triggered above.
 +
myLidarLite.waitForBusy();
 +
 
 +
// 4. Read new distance data from device registers
 +
*distance = myLidarLite.readDistance();
 +
 
 +
return 1;
 +
}
 +
 
 +
//---------------------------------------------------------------------
 +
// Read Continuous Distance Measurements
 +
//
 +
// The most recent distance measurement can always be read from
 +
// device registers. Polling for the BUSY flag in the STATUS
 +
// register can alert the user that the distance measurement is new
 +
// and that the next measurement can be initiated. If the device is
 +
// BUSY this function does nothing and returns 0. If the device is
 +
// NOT BUSY this function triggers the next measurement, reads the
 +
// distance data from the previous measurement, and returns 1.
 +
//---------------------------------------------------------------------
 +
uint8_t distanceContinuous(uint16_t * distance)
 +
{
 +
uint8_t newDistance = 0;
 +
 
 +
// Check on busyFlag to indicate if device is idle
 +
// (meaning = it finished the previously triggered measurement)
 +
if (myLidarLite.getBusyFlag() == 0)
 +
{
 +
    // Trigger the next range measurement
 +
    myLidarLite.takeRange();
 +
 
 +
    // Read new distance data from device registers
 +
    *distance = myLidarLite.readDistance();
 +
 
 +
    // Report to calling function that we have new data
 +
    newDistance = 1;
 +
}
 +
 
 +
return newDistance;
 +
}
 +
 
 +
//---------------------------------------------------------------------
 +
// Read Distance Measurement, Quickly
 +
//
 +
// Read distance. The approach is to poll the status register until the device goes
 +
// idle after finishing a measurement, send a new measurement command, then read the
 +
// previous distance data while it is performing the new command.
 +
//---------------------------------------------------------------------
 +
uint8_t distanceFast(uint16_t * distance)
 +
{
 +
// 1. Wait for busyFlag to indicate device is idle. This must be
 +
// done before triggering a range measurement.
 +
myLidarLite.waitForBusy();
 +
 
 +
// 2. Trigger range measurement.
 +
myLidarLite.takeRange();
 +
 
 +
// 3. Read previous distance data from device registers.
 +
// After starting a measurement we can immediately read previous
 +
// distance measurement while the current range acquisition is
 +
// ongoing. This distance data is valid until the next
 +
// measurement finishes. The I2C transaction finishes before new
 +
// distance measurement data is acquired.
 +
*distance = myLidarLite.readDistance();
 +
 
 +
return 1;
 +
}
 +
 
 +
//---------------------------------------------------------------------
 +
// Print the correlation record for analysis
 +
//---------------------------------------------------------------------
 +
void dumpCorrelationRecord()
 +
{
 +
myLidarLite.correlationRecordToSerial(256);
 +
}
 +
 
 +
//---------------------------------------------------------------------
 +
// Print peaks and calculated distances from the peak stack
 +
//---------------------------------------------------------------------
 +
void peakStackExample()
 +
{
 +
int16_t  peakArray[8];
 +
int16_t  distArray[8];
 +
uint8_t  i;
 +
 
 +
// - Read the Peak Stack.
 +
// - Peaks and calculated distances are returned in local arrays.
 +
// - See library function for details on the makeup of the stack
 +
//  and how distance data is created from the stack.
 +
myLidarLite.peakStackRead(peakArray, distArray);
 +
 
 +
// Print peaks and calculated distances to the serial port.
 +
Serial.println();
 +
Serial.println("IDX PEAK DIST");
 +
for (i=0 ; i<8 ; i++)
 +
{
 +
    Serial.print(i);
 +
    Serial.print("  ");
 +
    Serial.print(peakArray[i]);
 +
    Serial.print("  ");
 +
    Serial.print(distArray[i]);
 +
    Serial.println();
 +
}
 +
}
 +
</source>
 +
{{boîte déroulante/fin}}
  
 
===Détection D'angle : Magnétomètre===
 
===Détection D'angle : Magnétomètre===
 +
mathieu
  
 
===Détection d'obstacle : VL53L1X===
 
===Détection d'obstacle : VL53L1X===
 +
[[Fichier:VL53L1X.jpg|vignette|200px|Tof Sensor VL53L1X / Nom broche]]
 +
Le robot ne peut pas sortir de l'aire de jeu, il y a des murs. Pour éviter toutes casse matérielle lors du déplacement de notre robot il faut que nous puissions les détecter.<br>
 +
Pour cela nous avons utiliser un capteur de distance ToF (Time of flight), les VL53L1X.<br>
 +
Ils ont l'avantage d'être petits et arrivent à détecter à de courtes distances des distances et allant jusqu'à 2 m avec une bonne précision.<br>
 +
Ces capteurs se branchent sur un bus I2C (SDA-SCL) et sont alimentés en 5 V sur la broche VIN.<br>
 +
&Agrave; l'initialisation, ces capteurs nécessite un changement d'adresse, on utilise la broche Xshut (tout ou rien) du capteur connecter à une broche logique du microcontrôleur.<br>
 +
Les VL53L1X ont 3 modes de fonctionnement un mode short, medium et long (mode par défaut). Pour notre utilisation on utilisera le mode short (distance max = 1.3 mètres).<br>
 +
Avec notre carte de contrôle nous avons la possibilités d'en utiliser 4, ils sont connecter à la carte via un connecteur Molex.<br>
 +
On a décidé de positionner un capteur à l'avant droite et l'autre à l'avant gauche du robot.<br>
 +
On place ces capteurs sur des petit support amovible pour permettre de les déplacer si besoin, ces support protègent également les capteurs en cas de collision lors des tests par exemple.<br>
 +
Pour utiliser ce capteur sur le logiciel Arduino il est nécessaire d'inclure la bibliothèque du capteur (VL53L1X by Polulu).<br>
 +
Lien vidéo correspondant au programme ci-dessous (vidéo réaliser sur le prototype) : [https://drive.google.com/file/d/1xjHjLWoEe9TJm78cpj2_ozkNqIWRyKXx/view?usp=sharing détection obstacle]<br>
 +
Information supplémentaires sur le capteur : [https://www.robotshop.com/media/files/pdf/tof-range-finder-sensor-breakout-board-voltage-regulator---vl53l1x-datasheet1.pdf datasheet].
 +
<br>
 +
{{boîte déroulante/début|titre=Exemple programme détection des obstacles avec un capteur (fonctionnel)}}
 +
<source lang=Arduino>
 +
#include <Wire.h>
 +
#include <VL53L1X.h>
 +
 +
VL53L1X sensor_1;
  
===Balle attrapé / non attrapé===  
+
int pinMoteurG = 8;
 +
 
 +
int pinMoteurD = 7;
 +
 
 +
int pinMoteurPWMG = 9;
 +
 
 +
int pinMoteurPWMD = 6;
 +
 
 +
int VmG;
 +
int VmD;
 +
 
 +
void setVitesse (int VmG , int VmD) {
 +
 +
if ( VmG < 0 ) {
 +
  digitalWrite(pinMoteurG,HIGH);
 +
  VmG = -VmG;
 +
  } else  {
 +
  digitalWrite(pinMoteurG,LOW);
 +
  };
 +
 
 +
  if ( VmD < 0 ) {
 +
  digitalWrite(pinMoteurD,HIGH);
 +
  VmD = -VmD;
 +
  } else  {
 +
  digitalWrite(pinMoteurD,LOW);
 +
  };
 +
 
 +
analogWrite(pinMoteurPWMG, 2 * VmG + 10);
 +
analogWrite(pinMoteurPWMD, 2 * VmD + 10);
 +
 
 +
 +
  }
 +
 
 +
void arret () {
 +
  VmG = 0;
 +
  VmD = 0;
 +
  analogWrite(pinMoteurPWMG, VmG);
 +
  analogWrite(pinMoteurPWMD, VmD);
 +
 
 +
}
 +
 
 +
 
 +
void setup() {
 +
  // put your setup code here, to run once:
 +
  Serial.begin(115200);
 +
  Wire.begin();
 +
  Wire.setClock(400000); // use 400 kHz I2C
 +
 
 +
  //XSHUT sensor_1
 +
  pinMode(4,OUTPUT);
 +
  digitalWrite(4,LOW);
 +
  delay(100);
 +
  digitalWrite(4,HIGH);
 +
 
 +
  sensor_1.setTimeout(500);
 +
  if (!sensor_1.init())
 +
  {
 +
Serial.println("Failed to detect and initialize sensor_1!");
 +
while (1);
 +
  }
 +
  sensor_1.setDistanceMode(VL53L1X::Short);
 +
  sensor_1.setMeasurementTimingBudget(50000);
 +
 
 +
  sensor_1.startContinuous(50);
 +
  sensor_1.setAddress(41);
 +
 +
  pinMode(pinMoteurG, OUTPUT);
 +
  pinMode(pinMoteurD, OUTPUT);
 +
  pinMode(pinMoteurPWMG, OUTPUT);
 +
  pinMode(pinMoteurPWMD, OUTPUT);
 +
 
 +
 +
}
 +
 
 +
void loop() {
 +
  // put your main code here, to run repeatedly:
 +
 
 +
  sensor_1.read();
 +
 +
  Serial.print("range: ");
 +
  Serial.print(sensor_1.ranging_data.range_mm);
 +
  Serial.print("\tstatus: ");
 +
  Serial.print(VL53L1X::rangeStatusToString(sensor_1.ranging_data.range_status));
 +
  Serial.print("\tpeak signal: ");
 +
  Serial.print(sensor_1.ranging_data.peak_signal_count_rate_MCPS);
 +
  Serial.print("\tambient: ");
 +
  Serial.print(sensor_1.ranging_data.ambient_count_rate_MCPS);
 +
 +
  Serial.println();
 +
 
 +
  Serial.print("n° Adress :");
 +
  Serial.print(sensor_1.getAddress());
 +
  if (sensor_1.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
 +
 
 +
  Serial.println();
 +
 
 +
if (sensor_1.ranging_data.range_mm > 300) {
 +
 
 +
  setVitesse (50 , 50);
 +
 
 +
}else if (sensor_1.ranging_data.range_mm < 300) {
 +
 +
  setVitesse ( 25 , 25);
 +
 
 +
}else if (sensor_1.ranging_data.range_mm < 200) {
 +
  arret ();
 +
  delay(100);
 +
  setVitesse ( 25, -25 );
 +
 +
}
 +
 
 +
}
 +
</source>
 +
{{boîte déroulante/fin}}
 +
 
 +
===Balle attrapé / non attrapé===
 +
Pour savoir si une balle a été attrapé, nous avons utiliser un capteur VL53L1X qui nous permettra de savoir si une balle est présente ou non.<br>
 +
[[Fichier:PresenceBalle.jpg|vignette|centré|Position capteur VL53L1X pour la présence de balle]]
  
 
===Détection de la ligne médiane===
 
===Détection de la ligne médiane===
Ligne 97 : Ligne 700 :
  
 
==Communiquer : Module Xbee==
 
==Communiquer : Module Xbee==
 +
 +
=Assemblage pièces du robot=
 +
[[Fichier:Chassis vue dessus.PNG|vignette|gauche|Châssis vue du dessus (fournie par l'IUT)]]
 +
[[Fichier:Position assemblage.PNG|vignette|positionnement différentes partie]]
 +
[[Fichier:Support batterie2.PNG|vignette|centré|Support de la Batterie (fournie)]]
 +
[[Fichier:Face avant robot.JPG|vignette|gauche|Face avant du robot assembler]]
 +
[[Fichier:bouton de démmarage.JPG|vignette|Bouton de démarrage du programme (fixé à l'arrière droite du robot)]]
 +
[[Fichier:Robot 2021 1A.JPG|vignette|centré|Robot Assembler]]
 +
<br>
 +
<br>
 +
 +
=Pièce imprimante 3D=
 +
*[[Media:Support_telemetre_gauche.zip|Support VL53L1X de gauche]]
 +
*[[Media:Support_telemetre_droite.zip|Support VL53L1X de droite]]
 +
*[[Media:support_pixy.zip|Support caméra Pixy 2]]
 +
*[[Media:Mât_de_fixation.zip|Mât de fixation pour le ballon]]
 +
*[[Media:Butée_droite_lanceur.zip|Butée du système de propulsion droite]]
 +
*[[Media:Butée_gauche_lanceur.zip|Butée du système de propulsion gauche]]
 +
 +
pièce dan
 +
 +
=Travaux restants=
 +
Voici ce que notre robot peut effectuer avec la programme réaliser à la fin de nos séances de travail : [https://drive.google.com/file/d/1ku3K4Z8FueYjLk64h9HIxWAeFiTLePAq/view?usp=sharing Vidéo de lancer de la balle] <br>
 +
Pour avoir un robot fonctionnel à la compétition, il reste du travail à effectuer :
 +
  - Les parties mécaniques sont entièrement réaliser, il reste à fixer le tout.
 +
 +
  - Il faut terminer les tests des différents capteurs avec la carte électronique du microcontrôleur.
 +
 +
  - Il faut réaliser les programmes de chaque parties encore non-existant ou non-fonctionnel et tous les assembler.
 +
 +
  - Après ceci, il faudra faire des tests afin d'avoir les meilleurs réglage possible.

Version actuelle datée du 31 mai 2021 à 18:33


Présentation du projet

Notre équipe

Nous sommes 5 étudiants venant de l’IUT de Troyes en formation d’un DUT Génie électrique et informatique industrielle (GEII), lors de cette formation nous avons eu l’opportunité de réaliser un projet de robotique durant l’année 2020-2021, avec l’objectif de participer à la Coupe Robot GEII.
Notre groupe est composé de Dan Boilleau, Luca Giocondo, Mathieu Beauvois, Louis Foucher et Loris Baroni.

Durant le projet nous nous sommes répartis les tâches à effectuer au fur et à mesures :

 - Dan Boilleau : utilisation des moteurs de déplacements avec les ponts en H / réalisation de la partie permettant de lancer et d'attraper la balle.
 - Luca Giocondo : réalisation de la partie de détection de la ligne médiane.
 - Louis Foucher : réalisation de la partie Crève-ballon / élaboration de support pour différents capteurs.
 - Mathieu Beauvois : réalisation de la partie détection de la balle avec la caméra Pixy2 / réalisation de la partie boussole (magnétomètre).
 - Loris Baroni : Réalisation de la partie des télémètres / Assemblages du robot / réalisation de la carte électronique de contrôle.

Objectifs

Nous avons pour but de réaliser un robot pouvant jouer au tennis de manière autonome en vue de participer à la coupe robotique GEII. Durant la compétition, deux robots s’affrontent. Notre robot doit se déplacer sur le terrain sans toucher les murs ou encore franchir la ligne médiane de séparation des camps. Il doit également attraper et renvoyer un maximum de balles de tennis standard dans le camp adverse en contrôlant une balle à la fois. De plus, Il doit avant la fin du temps imparti (90 secondes : durée du match) crever un ballon accroché à lui-même. Une fois le ballon crevé, le robot doit être immobile sur la ligne médiane (Pour rapporter des points bonus). Nous devons également respecter des contraintes de taille, de composants tels que la batterie ou encore les moteurs.

Cahier des charges / règlement de la compétition

texte alternatif
Aire de jeu

L'aire de jeu

L'aire de jeu a pour dimension 8 x 4 m avec une ligne médiane de 67 cm de large soit un espace de 16 m² pour le déplacement de notre robot.

Les balles

Les balles utilisées sont des balles de tennis standard.
Elles sont placées aléatoirement sur le terrain à l'exception de 3 balles placées systématiquement aux 3 intersections des lignes de notre terrain (points jaunes sur le schéma).

schéma aire de jeu

Le Robot

Le but du robot est d'envoyer le plus de balle possible dans le camps adverse à l'aide d'un système propulseur, sans jamais franchir la ligne médiane qui sépare les deux camps et en ne contrôlant qu'une balle à la fois. Lors du lancement d'un match, le robot doit être démarré à l'aide d'un bouton qu'un utilisateur viendra actionner, ensuite il sera autonome. Le robot gagnant est celui qui aura le moins de balle dans son camp à la fin du match.

Les Balises

Il est possible de poser jusqu'à 3 balises de dimensions maximales de 20 x 20 x 20 cm sur des emplacements spécifiques (détaillé sur le schéma). Nous avons décidé de ne pas utilisée de balise.

Homologation

Le robot doit répondre aux exigences fixées.
Ces exigences sont les suivantes :
- Le robot rentre dans une boite de 40 x 30 x 30 cm.
- Un ballon de baudruche est fixé à 30 cm du sol et doit être percé sur la ligne médiane avant la fin du temps imparti des matchs (90 secondes).
- Le robot ne présente aucun danger, ni au repos, ni en fonctionnement (pas de pièces coupantes...).
- Un dispositif permettant de couper le courant doit être mit en place (bouton d'arrêt d'urgence).
- Un dispositif mécanique de mise en marche doit être présent.

Règlement complet de la compétition

Pour plus d'information sur les règles, je vous invite à aller regarder la réglementation complète: Règlement

Recherche et développement

Schéma fonctionnel

Ci-dessous le schéma fonctionnel qui nous a servi de base dans notre projet.

Schéma fonctionnel












Algorithme

Ici l'algorithme qui nous a servi de point de départ pour avoir chaque étape de se que devra faire le robot durant le match, celui-ci a été décomposé en plusieurs parties que nous avons ensuite réparties entre les membres du groupe.

Schéma fonctionnel

































Prototype

Prototype robot avec actionneur fonctionnel

Dans un premier temps, nous avons utilisés un robot existant afin de pouvoir tester, configurer ou encore programmer différente partie du robot à l'aide d'un Arduino UNO. Dans un premier il a fallut piloter les moteurs permettant un déplacement du robot sur notre terrain à l'aide de pont en H permettant de piloter les moteurs dans les deux sens de rotation, On a programmer la base de notre code. Par la suite nous avons pu coupler au robot la caméra Pixy2 afin que notre robot puisse suivre une balle de tennis en déplacement, après plusieurs test les essais fut concluant, ces étapes de test sont indispensables pour le bon fonctionnement de notre futur robot. On a également pu tester la détection d'un obstacle afin de l'éviter ... (etc)










Solution adoptée

Alimentation / Régulation

Batterie fournie
abaisseur de tension

La batterie

Notre robot comprend un pack de piles rechargeables 4x 18650 LiFePO 4 Emmerich 4A12318650RK 12.8 V 1100 mAh pour permettre d'alimenter les différents éléments.
Une tension minimum de 9V est nécessaires pour le bon fonctionnement de notre robot.




Abaisseur de tension

La batterie fournie délivre 12.8V, hors nous avons besoin d'une alimentation 5V pour le bon fonctionnement de certain capteur ou actionneur.
C'est pourquoi nous avons utilisée un abaisseur de tension réglable.





Gérer

ATmega 2560

Schéma eagle connecteur ISP
Microcontroleur ATmega 2560 16MHz

Ce microcontrôleur qui est présent sur les Arduino Méga possède un grand nombre de port ce qui nous est utile pour l'élaboration d'une carte complète avec un grand nombre de capteur et d'actionneur.
Il est programmable à l'aide du logiciel Arduino ainsi qu'un programmateur brancher sur un connecteur ISP, le connecteur ISP sert également à brancher la caméra Pixy 2 au microcontrôleur.

Schéma ATmega2560
Programmateur connecté à la broche ISP

Carte électronique de contrôle

Pour la réalisation de notre robot, afin de ne pas avoir de fil volant qui pourrait se débrancher nous avons réaliser une carte électronique sur le logiciel Eagle. Cette carte qui comporte le microcontrôleur permet de connecter et contrôler les capteurs et actionneur qui sont tous reliés à la carte. Grâce à cette carte cela nous permet d'alimenter facilement tous les composant à la tension voulue.

Lorsque la carte a été imprimé, et après la soudure des composant traversant et CMS sur la carte, nous sommes passer en phase de test pour vérifier que l'ensemble des partie de la carte fonctionnait, l'absence de court circuit ainsi que la continuité des pistes et des vias, puis la bonne transmission de données à l'aide du programmateur et du module Xbee pour bien récupérer les informations en utilisation sans fil sur l'ordinateur.

Schéma eagle de la carte électronique
Board de la carte électronique
Face Top de la Carte électronique avec les branchements
Face Bot de la carte électonique


Actionneurs

Déplacement

dan

Système propulsion

dan

Crève-Ballon

Support de Fixation crève ballon



Pour la crevaison du ballon, nous avons utilisé un disque souple en plastique qui est piloté par un moteur à courant continu, ainsi qu’un servo-moteur. Aussi, nous avons réalisé un mât comme support pour l’ensemble décrit ci-dessus. Celui-ci nous sert aussi à positionner le support de la caméra PIXY. Le ballon est maintenu par un câble qui serre le ballon au niveau du nœud et un élastique qui est attaché au câble qui maintient le ballon pour que celui-ci reste en place tout le long du match.


Lien vers la vidéo de la crevaison du ballon : vidéo crève ballon

Ensemble Crève ballon
























Exemple programme crevaison du ballon (fonctionnel)

#include <Servo.h>

Servo monservo;
//int bp;

void setup(){
  //pinMode(3, OUTPUT);
  DDRK|=(1<<PK7);
  //pinMode(2, INPUT);
  DDRH&=~(1<<PH5);
  DDRH&=~(1<<PH4);
  monservo.attach(9);  // utilise la broche 9 pour le contrôle du servomoteur
  monservo.write(0); // positionne le servomoteur à 0°
  delay(5000);
  //Serial.begin(9600);
}

void loop(){
  //bp=digitalRead(2);
  //Serial.println(bp);
  //if (bp==1){
    monservo.write(120);
    //delay(5000);
    PORTK|=(1<<PK7);
    delay(500);
    PORTK&=~(1<<PK7);
    //delay(1000);
    monservo.write(0);
    delay(10000);
    //bp=0;
  //}
  //else {}
  
}

Capteurs

Détection des balles

De près : Caméra Pixy

Caméra Pixy2 montée sur le robot
Balle de tennis dans le logiciel PixyMon

Pour détecter précisément les balles de tennis qui seront proches de notre robot nous avons décidé d'utiliser une caméra Pixy 2.
Grace à la caméra nous pouvons obtenir la position en X et en Y de la balle ce qui nous permet via un programme Arduino de diriger le robot vers la balles détecté.
Cette dernière est alimentée en 5V et est également connectée à notre microcontrôleur sur la broche ISP.
Pour pouvoir utiliser la caméra sur Arduino, nous avons eux besoin de télécharger et d'importer la librairie suivante sur arduino: Librairie










Exemple programme détection de balles avec caméra Pixy2 (fonctionnel)

#include <Pixy2.h>

// This is the main Pixy object
Pixy2 pixy;

void setup()
{
  Serial.begin(115200);
  Serial.print("Starting...\n");
 
  pixy.init();
}

void loop()
{
  int i;
  int x;
  int y;
  // grab blocks!
  pixy.ccc.getBlocks();
 
  // si on détecte la balle
  if (pixy.ccc.numBlocks)
  {
 
  	Serial.print("position x de la balle ");
  	Serial.print(i);
  	Serial.print(": ");
  	Serial.println(pixy.ccc.blocks[i].m_x); // on indique la position de la balle sur l'axe x (entre 316 et 0)

 	 
 	 
  	if (pixy.ccc.blocks[i].m_x<158){ // si la balle est plus à gauche par rapport au milieu de l'axe, on tourne à gauche
    	Serial.println("tourner à gauche");
  	}
 	 
  	if (pixy.ccc.blocks[i].m_x>158) {
  	Serial.println("tourner à droite"); // si la balle est plus à droite par rapport au milieu de l'axe, on tourne à droite
  	}

  	Serial.print("position y de la balle ");
  	Serial.print(i);
  	Serial.print(": ");
  	Serial.println(pixy.ccc.blocks[i].m_y);



   	if (pixy.ccc.blocks[i].m_y<104){ // si la balle est plus en haut par rapport au milieu de l'axe, on tourne à gauche
    	Serial.println("avancer doucement");
  	}
    
  	if (pixy.ccc.blocks[i].m_y>104) {
  	Serial.println("avancer rapidement"); // si la balle est plus en bas par rapport au milieu de l'axe, on tourne à droite
  	}

  }

//si on ne détecte pas la balle
else {
  Serial.println("chercher la balle");
 



}

}

De loin : Lidar Garmin Lite V3

Test du capteur : Lidar Garmin Lite V3

Avec la caméra Pixy2 nous ne pouvons pas détecter précisément la balle de près et de loin, c'est pourquoi nous avons décider d'utiliser ce Lidar qui à une portée de 5 mètres ( en dessous de 40 cm ces mesures sont fausses). Pour son bon fonctionnement le Lidar Garmin doit être positionner à la hauteur de la balle et parallèle au sol. Avec ce capteur on ne pourra que diriger grossièrement le robot vers la balle afin que la caméra prennent le relais ensuite. Au niveau des branchement, il fonctionnent avec une alimentation de 5V et est connecté sur le bus I2C (SDA-SCL). Il est également nécessaire de placer un condensateur électrolytique de 680 microfarad entre le 5V et le GND.
Pour l'utilisation du programme ci-dessous il est nécessaires d'effectuer les branchementS (comme indiqué dans la Datasheet). Il faut également inclure directement la librairie du capteur sur le logiciel Arduino. Comme on peut le constater la partie de programmation permettant de diriger le robot vers une balle éloigner n'a pas encore pu être réaliser.

Positionnement du Lidar




Programme d'utilisation du Lidar Garmin Lite V3 dans différent mode de fonctionnement (Affichage de la distance dans la liaison série, fonctionnel)

#include <stdint.h>
#include <Wire.h>
#include <LIDARLite_v3HP.h>

LIDARLite_v3HP myLidarLite;

#define FAST_I2C

enum rangeType_T
{
	RANGE_NONE,
	RANGE_SINGLE,
	RANGE_CONTINUOUS,
	RANGE_TIMER
};

void setup()
{
	// Initialize Arduino serial port (for display of ASCII output to PC)
	Serial.begin(115200);

	// Initialize Arduino I2C (for communication to LidarLite)
	Wire.begin();
	#ifdef FAST_I2C
    	#if ARDUINO >= 157
        	Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
    	#else
        	TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
    	#endif
	#endif

	// Configure the LidarLite internal parameters so as to lend itself to
	// various modes of operation by altering 'configure' input integer to
	// anything in the range of 0 to 5. See LIDARLite_v3HP.cpp for details.
	myLidarLite.configure(0);
}


void loop()
{
	uint16_t distance;
	uint8_t  newDistance = 0;
	uint8_t  c;
	rangeType_T rangeMode = RANGE_NONE;

	PrintMenu();

	// Continuous loop
	while (1)
	{
    	// Each time through the loop, look for a serial input character
    	if (Serial.available() > 0)
    	{
        	//  read input character ...
        	c = (uint8_t) Serial.read();

        	// ... and parse
        	switch (c)
        	{
            	case 'S':
            	case 's':
                	rangeMode = RANGE_SINGLE;
                	break;

            	case 'C':
            	case 'c':
                	rangeMode = RANGE_CONTINUOUS;
                	break;

            	case 'T':
            	case 't':
                	rangeMode = RANGE_TIMER;
                	break;

            	case '.':
                	rangeMode = RANGE_NONE;
                	break;

            	case 'D':
            	case 'd':
                	rangeMode = RANGE_NONE;
                	dumpCorrelationRecord();
                	break;

            	case 'P':
            	case 'p':
                	rangeMode = RANGE_NONE;
                	peakStackExample();
                	break;

            	case 0x0D:
            	case 0x0A:
                	break;

            	default:
                	rangeMode = RANGE_NONE;
                	PrintMenu();
                	break;
        	}
    	}

    	switch (rangeMode)
    	{
        	case RANGE_NONE:
            	newDistance = 0;
            	break;

        	case RANGE_SINGLE:
            	newDistance = distanceSingle(&distance);
            	break;

        	case RANGE_CONTINUOUS:
            	newDistance = distanceContinuous(&distance);
            	break;

        	case RANGE_TIMER:
            	delay(250); // 4 Hz
            	newDistance = distanceFast(&distance);
            	break;

        	default:
            	newDistance = 0;
            	break;
    	}

    	// When there is new distance data, print it to the serial port
    	if (newDistance)
    	{
        	Serial.println(distance);
    	}

    	// Single measurements print once and then stop
    	if (rangeMode == RANGE_SINGLE)
    	{
        	rangeMode = RANGE_NONE;
    	}
	}
}

void PrintMenu(void)
{
	Serial.println("=====================================");
	Serial.println("== Type a single character command ==");
	Serial.println("=====================================");
	Serial.println(" S - Single Measurement");
	Serial.println(" C - Continuous Measurement");
	Serial.println(" T - Timed Measurement");
	Serial.println(" . - Stop Measurement");
	Serial.println(" D - Dump Correlation Record");
	Serial.println(" P - Peak Stack Example");
}

//---------------------------------------------------------------------
// Read Single Distance Measurement
//
// This is the simplest form of taking a measurement. This is a
// blocking function as it will not return until a range has been
// taken and a new distance measurement can be read.
//---------------------------------------------------------------------
uint8_t distanceSingle(uint16_t * distance)
{
	// 1. Wait for busyFlag to indicate device is idle. This must be
	//	done before triggering a range measurement.
	myLidarLite.waitForBusy();

	// 2. Trigger range measurement.
	myLidarLite.takeRange();

	// 3. Wait for busyFlag to indicate device is idle. This should be
	//	done before reading the distance data that was triggered above.
	myLidarLite.waitForBusy();

	// 4. Read new distance data from device registers
	*distance = myLidarLite.readDistance();

	return 1;
}

//---------------------------------------------------------------------
// Read Continuous Distance Measurements
//
// The most recent distance measurement can always be read from
// device registers. Polling for the BUSY flag in the STATUS
// register can alert the user that the distance measurement is new
// and that the next measurement can be initiated. If the device is
// BUSY this function does nothing and returns 0. If the device is
// NOT BUSY this function triggers the next measurement, reads the
// distance data from the previous measurement, and returns 1.
//---------------------------------------------------------------------
uint8_t distanceContinuous(uint16_t * distance)
{
	uint8_t newDistance = 0;

	// Check on busyFlag to indicate if device is idle
	// (meaning = it finished the previously triggered measurement)
	if (myLidarLite.getBusyFlag() == 0)
	{
    	// Trigger the next range measurement
    	myLidarLite.takeRange();

    	// Read new distance data from device registers
    	*distance = myLidarLite.readDistance();

    	// Report to calling function that we have new data
    	newDistance = 1;
	}

	return newDistance;
}

//---------------------------------------------------------------------
// Read Distance Measurement, Quickly
//
// Read distance. The approach is to poll the status register until the device goes
// idle after finishing a measurement, send a new measurement command, then read the
// previous distance data while it is performing the new command.
//---------------------------------------------------------------------
uint8_t distanceFast(uint16_t * distance)
{
	// 1. Wait for busyFlag to indicate device is idle. This must be
	//	done before triggering a range measurement.
	myLidarLite.waitForBusy();

	// 2. Trigger range measurement.
	myLidarLite.takeRange();

	// 3. Read previous distance data from device registers.
	//	After starting a measurement we can immediately read previous
	//	distance measurement while the current range acquisition is
	//	ongoing. This distance data is valid until the next
	//	measurement finishes. The I2C transaction finishes before new
	//	distance measurement data is acquired.
	*distance = myLidarLite.readDistance();

	return 1;
}

//---------------------------------------------------------------------
// Print the correlation record for analysis
//---------------------------------------------------------------------
void dumpCorrelationRecord()
{
	myLidarLite.correlationRecordToSerial(256);
}

//---------------------------------------------------------------------
// Print peaks and calculated distances from the peak stack
//---------------------------------------------------------------------
void peakStackExample()
{
	int16_t   peakArray[8];
	int16_t   distArray[8];
	uint8_t   i;

	// - Read the Peak Stack.
	// - Peaks and calculated distances are returned in local arrays.
	// - See library function for details on the makeup of the stack
	//   and how distance data is created from the stack.
	myLidarLite.peakStackRead(peakArray, distArray);

	// Print peaks and calculated distances to the serial port.
	Serial.println();
	Serial.println("IDX PEAK DIST");
	for (i=0 ; i<8 ; i++)
	{
    	Serial.print(i);
    	Serial.print("   ");
    	Serial.print(peakArray[i]);
    	Serial.print("  ");
    	Serial.print(distArray[i]);
    	Serial.println();
	}
}

Détection D'angle : Magnétomètre

mathieu

Détection d'obstacle : VL53L1X

Tof Sensor VL53L1X / Nom broche

Le robot ne peut pas sortir de l'aire de jeu, il y a des murs. Pour éviter toutes casse matérielle lors du déplacement de notre robot il faut que nous puissions les détecter.
Pour cela nous avons utiliser un capteur de distance ToF (Time of flight), les VL53L1X.
Ils ont l'avantage d'être petits et arrivent à détecter à de courtes distances des distances et allant jusqu'à 2 m avec une bonne précision.
Ces capteurs se branchent sur un bus I2C (SDA-SCL) et sont alimentés en 5 V sur la broche VIN.
À l'initialisation, ces capteurs nécessite un changement d'adresse, on utilise la broche Xshut (tout ou rien) du capteur connecter à une broche logique du microcontrôleur.
Les VL53L1X ont 3 modes de fonctionnement un mode short, medium et long (mode par défaut). Pour notre utilisation on utilisera le mode short (distance max = 1.3 mètres).
Avec notre carte de contrôle nous avons la possibilités d'en utiliser 4, ils sont connecter à la carte via un connecteur Molex.
On a décidé de positionner un capteur à l'avant droite et l'autre à l'avant gauche du robot.
On place ces capteurs sur des petit support amovible pour permettre de les déplacer si besoin, ces support protègent également les capteurs en cas de collision lors des tests par exemple.
Pour utiliser ce capteur sur le logiciel Arduino il est nécessaire d'inclure la bibliothèque du capteur (VL53L1X by Polulu).
Lien vidéo correspondant au programme ci-dessous (vidéo réaliser sur le prototype) : détection obstacle
Information supplémentaires sur le capteur : datasheet.

Exemple programme détection des obstacles avec un capteur (fonctionnel)

 #include <Wire.h>
#include <VL53L1X.h>

VL53L1X sensor_1;

int pinMoteurG = 8;

int pinMoteurD = 7;

int pinMoteurPWMG = 9;

int pinMoteurPWMD = 6;

int VmG;
int VmD;

void setVitesse (int VmG , int VmD) {
 
if ( VmG < 0 ) {
   digitalWrite(pinMoteurG,HIGH);
   VmG = -VmG;
   } else  {
   digitalWrite(pinMoteurG,LOW);
   };
   
   if ( VmD < 0 ) {
   digitalWrite(pinMoteurD,HIGH);
   VmD = -VmD;
   } else  {
   digitalWrite(pinMoteurD,LOW);
   };

analogWrite(pinMoteurPWMG, 2 * VmG + 10);
analogWrite(pinMoteurPWMD, 2 * VmD + 10);
   
 
  }

void arret () {
  VmG = 0;
  VmD = 0;
  analogWrite(pinMoteurPWMG, VmG);
  analogWrite(pinMoteurPWMD, VmD);

}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(400000); // use 400 kHz I2C

  //XSHUT sensor_1
  pinMode(4,OUTPUT);
  digitalWrite(4,LOW);
  delay(100);
  digitalWrite(4,HIGH);

  sensor_1.setTimeout(500);
  if (!sensor_1.init())
  {
	Serial.println("Failed to detect and initialize sensor_1!");
	while (1);
  }
  sensor_1.setDistanceMode(VL53L1X::Short);
  sensor_1.setMeasurementTimingBudget(50000);

  sensor_1.startContinuous(50);
  sensor_1.setAddress(41);
 
  pinMode(pinMoteurG, OUTPUT);
  pinMode(pinMoteurD, OUTPUT);
  pinMode(pinMoteurPWMG, OUTPUT);
  pinMode(pinMoteurPWMD, OUTPUT);

 
}

void loop() {
  // put your main code here, to run repeatedly:

  sensor_1.read();
 
  Serial.print("range: ");
  Serial.print(sensor_1.ranging_data.range_mm);
  Serial.print("\tstatus: ");
  Serial.print(VL53L1X::rangeStatusToString(sensor_1.ranging_data.range_status));
  Serial.print("\tpeak signal: ");
  Serial.print(sensor_1.ranging_data.peak_signal_count_rate_MCPS);
  Serial.print("\tambient: ");
  Serial.print(sensor_1.ranging_data.ambient_count_rate_MCPS);
 
  Serial.println();

  Serial.print("n° Adress :");
  Serial.print(sensor_1.getAddress());
  if (sensor_1.timeoutOccurred()) { Serial.print(" TIMEOUT"); }

  Serial.println();

 if (sensor_1.ranging_data.range_mm > 300) {

  setVitesse (50 , 50);

 }else if (sensor_1.ranging_data.range_mm < 300) {
 
  setVitesse ( 25 , 25);

 }else if (sensor_1.ranging_data.range_mm < 200) {
  arret ();
  delay(100);
  setVitesse ( 25, -25 );
 
 }

}

Balle attrapé / non attrapé

Pour savoir si une balle a été attrapé, nous avons utiliser un capteur VL53L1X qui nous permettra de savoir si une balle est présente ou non.

Position capteur VL53L1X pour la présence de balle

Détection de la ligne médiane

texte alternatif
Capteur CNY70

Pour la détection de la ligne médiane, nous avons choisi d'utiliser des capteurs CNY70. Ces capteurs sont composés d'une LED infrarouge et d'un transistor, le principe est que la LED va émettre une lumière et en fonction de la couleur sur laquelle va réfléchir la lumière, il y aura plus ou moins de courant qui passera dans le transistor. Le noir étant la couleur qui réfléchit le moins et le blanc celle qui réfléchit le plus.



texte alternatif
Emplacement capteurs










Pour ce qui est de l'emplacement des capteurs, nous avons choisi d'en utiliser 8 et de les placer comme le montre l'image à gauche, les capteurs sont espacés de 2.5cm, il sont reliés à des comparateurs afin d'avoir des données numériques et non analogiques. Les sorties des comparateurs sont ensuite reliées à des portes logiques ET à quatre entrées, les sorties des quatre comparateurs reliés aux quatre capteurs de gauche sont reliés au quatre entrées de la Porte ET, même chose pour les quatre capteurs de droites qui sont aussi reliés à une port ET à quatre entrées. On a décidé de procéder de cette manière car lorsque les quatre capteurs de gauche ou de droite sont tous activés alors on est sur de détecter la ligne médiane et non une ligne du terrain.








Voici le schéma électronique :

texte alternatif
Schéma électrique circuit capteur CNY70

La borne 1 sert à relier l'alimentation (+5V), la borne 2 pour le GND, les bornes 3,5,6 et 7 sont reliés au 4 capteurs de gauche et les bornes 8,9,10 et 11 sont reliés au 4 capteurs de droite et la borne 12 est la sortie qui renverra une tension logique au microcontrôleur indiquant l'état des capteurs



Voici le board du circuit précédent créer sur Eagle :

texte alternatif
Board circuit détection de la ligne médiane

Communiquer : Module Xbee

Assemblage pièces du robot

Châssis vue du dessus (fournie par l'IUT)
positionnement différentes partie
Support de la Batterie (fournie)
Face avant du robot assembler
Bouton de démarrage du programme (fixé à l'arrière droite du robot)
Robot Assembler



Pièce imprimante 3D

pièce dan

Travaux restants

Voici ce que notre robot peut effectuer avec la programme réaliser à la fin de nos séances de travail : Vidéo de lancer de la balle
Pour avoir un robot fonctionnel à la compétition, il reste du travail à effectuer :

 - Les parties mécaniques sont entièrement réaliser, il reste à fixer le tout.
 - Il faut terminer les tests des différents capteurs avec la carte électronique du microcontrôleur.
 - Il faut réaliser les programmes de chaque parties encore non-existant ou non-fonctionnel et tous les assembler.
 - Après ceci, il faudra faire des tests afin d'avoir les meilleurs réglage possible.