RobotiqueCoupeGEII : Différence entre versions
(→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 | + | =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.<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 | + | 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> | ||
− | |||
− | = | + | === 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 | + | [[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> |
− | = | + | |
+ | =Solution adoptée= | ||
==Alimentation / Régulation== | ==Alimentation / Régulation== | ||
− | [[Fichier:BatterieRobot.jpg|300px| | + | [[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 | + | ===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> | ||
− | == | + | ==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; | ||
− | === | + | 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 {} | ||
+ | |||
+ | } | ||
+ | </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; | ||
− | + | 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(); | ||
+ | } | ||
+ | } | ||
+ | </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> | ||
+ | À 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
Sommaire
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
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).
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.
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.
Prototype
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
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
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.
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.
Actionneurs
Déplacement
dan
Système propulsion
dan
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
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
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
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.
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
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.
Détection de la ligne médiane
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.
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 :
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 :
Communiquer : Module Xbee
Assemblage pièces du robot
Pièce imprimante 3D
- Support VL53L1X de gauche
- Support VL53L1X de droite
- Support caméra Pixy 2
- Mât de fixation pour le ballon
- Butée du système de propulsion droite
- 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 : 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.