Robotique2 1 : Différence entre versions
(→Repérage dans l'espace) |
(→Assemblage du Robot) |
||
(89 révisions intermédiaires par le même utilisateur non affichées) | |||
Ligne 5 : | Ligne 5 : | ||
=Présentation du projet= | =Présentation du projet= | ||
− | Le projet | + | Le projet a pour objectif de réaliser un match entre 2 robots. Ceux-ci devront envoyer depuis leur terrain le plus de balles de tennis possible sans aller sur le terrain adverse. <br /> |
− | Le terrain mesure 8 mètres par 4 et est séparé en 2 parties par une ligne médiane donc chaque robot aura un terrain d'approximativement 16m² pour se | + | Le terrain mesure 8 mètres par 4 et est séparé en 2 parties par une ligne médiane donc chaque robot aura un terrain d'approximativement 16m² pour se déplacer. |
− | Une partie dure 90s,avant la fin du temps | + | Une partie dure 90s, avant la fin du temps imparti le robot devra être immobile au niveau de la ligne médiane et avoir éclaté un ballon qu'il aura emporté avec lui au début du match. <br /> |
Le vainqueur sera le robot avec le moins de balle sur son terrain. <br /> | Le vainqueur sera le robot avec le moins de balle sur son terrain. <br /> | ||
Ligne 14 : | Ligne 14 : | ||
=={{Rouge|Objectif du Projet}}== | =={{Rouge|Objectif du Projet}}== | ||
− | * | + | *Réaliser un Robot capable de se déplacer dans son terrain. |
− | * | + | *Renvoyer des balles depuis son terrain jusqu'au terrain adverse. |
*Crever le ballon que l'on a emporté à l'arrêt devant la ligne médiane avant la fin du temps imparti. | *Crever le ballon que l'on a emporté à l'arrêt devant la ligne médiane avant la fin du temps imparti. | ||
=={{Rouge|Règlement}}== | =={{Rouge|Règlement}}== | ||
− | Voici ci-joint le règlement ainsi que les contraintes | + | Voici ci-joint le règlement ainsi que les contraintes associées à la création du Projet.<br/> |
*[[Media:Coupe_GEII_-_Règlement_-_2020.pdf| règlement de la coupe de robotique]]<br/> | *[[Media:Coupe_GEII_-_Règlement_-_2020.pdf| règlement de la coupe de robotique]]<br/> | ||
Ligne 30 : | Ligne 30 : | ||
*Le robot doit être dimensionné selon 30x30x40cm.<br /> | *Le robot doit être dimensionné selon 30x30x40cm.<br /> | ||
− | * | + | *Moteurs |
**Vitesse de rotation entre 600 à 800 tr/min max. | **Vitesse de rotation entre 600 à 800 tr/min max. | ||
**Moteur MFA 970d (imposé par l'IUT) | **Moteur MFA 970d (imposé par l'IUT) | ||
Ligne 36 : | Ligne 36 : | ||
*Châssis imposé par l'IUT | *Châssis imposé par l'IUT | ||
− | *Le mécanisme lanceur de balle | + | *Le mécanisme lanceur de balle dépassera seulement pour envoyer la balle, il devra se replier après. |
*La batterie doit être en lithium Li-ion.<br /> | *La batterie doit être en lithium Li-ion.<br /> | ||
Ligne 49 : | Ligne 49 : | ||
=={{Bleu|Découpage fonctionnel}}== | =={{Bleu|Découpage fonctionnel}}== | ||
[[Fichier:Schéma fonctionnel robot geii.png|vignette]]<br/> | [[Fichier:Schéma fonctionnel robot geii.png|vignette]]<br/> | ||
− | Afin de commencer le projet, nous avons | + | Afin de commencer le projet, nous avons dû séparer les parties essentielles du projet pour ensuite répartir les tâches. |
*On a séparé le travail en différent groupe fonctionnel | *On a séparé le travail en différent groupe fonctionnel | ||
− | **L' | + | **L' Alimentation |
**Le Déplacement | **Le Déplacement | ||
− | **Le | + | **Le Système de renvoi des balles |
− | **Les | + | **Les Capteurs pour trouver les balles |
− | **Les | + | **Les Capteurs pour se repérer dans l'espace |
− | **Un | + | **Un Support ballon |
− | **Un | + | **Un Système de crevaison de ballon |
− | Vous | + | Vous trouverez ci-joint en vignette le schéma fonctionnel de notre robot. |
==Répartition des tâches== | ==Répartition des tâches== | ||
− | Nous nous sommes répartis les tâches de la façon suivante: | + | *Nous nous sommes répartis les tâches de la façon suivante: |
− | + | **Jason Savouret a pour tâches de s'occuper du repérage dans l'espace grâce à des capteurs. | |
+ | **Aurelien Noirault gère le système de renvoie des balles ainsi que le moyen de les repérer et de les attraper, le montage du robot (pièces et composants), l'alimentation ainsi que la maintenance. | ||
+ | **Aurelien Laurens a pour mission de crée le système pour supporter le ballon et du système de crevaison associé pour la fin de la partie, le montage du robot (pièces et composants), l'alimentation ainsi que la maintenance et le Site Web. | ||
+ | **Cécile Forgeot s'oriente sur toute la partie mobilité du robot en gérant la partie déplacement ainsi que la maintenance du robot | ||
− | + | ==Repérage dans l'espace== | |
+ | ===Partie 1: Objectif=== | ||
+ | [[Fichier:Boussolerobot.png|vignette|Boussole(MPU9250°]] | ||
+ | *Le robot ne doit dépasser sous aucun prétexte la ligne médiane. | ||
+ | *Le robot doit pouvoir se placer face au terrain adverse et connaître sa position vis à vis de celui-ci. | ||
+ | |||
+ | ===Partie 2: Recherche=== | ||
+ | |||
+ | [[Fichier:SEN10.png|vignette|Capteur SEN1010]] | ||
+ | [[Fichier:CNY.png|vignette|Capteur CNY70]] | ||
+ | *Afin de se repérer dans l'espace plusieurs choix ont été possible: | ||
+ | **une boussole MPU9250 pour s’orienter vis à vis du camp adverse. Au démarrage le robot prendra en valeur initiale les coordonnées de la direction pour le camps adverses et ainsi il pourra connaître son orientation vis à vis du camp adverse. | ||
+ | **un capteur de couleur SEN0101 afin de capter les couleurs du terrain. Son but serait de connaître la couleur sous le capteur afin de savoir s'il se situe au dessus d'une ligne blanche ou au dessus du sol (bleu foncé) du terrain. Avec ces information cela pourrait permettre au robot de se déplacer de manière autonome sur tout le terrain en analysant le terrain. | ||
+ | *Dans le fonctionnement le capteur renvoie des valeurs pour connaître la composante de la couleur au dessus de laquelle il est. Grâce a une succession de tests on renvoie un état logique 1 ou 0. | ||
+ | **0 permet de dire que l'on est sur le terrain (bleu). | ||
+ | **1 permet de dire que l'on est sur une ligne blanche et donc possiblement la ligne médiane. | ||
+ | Néanmoins la multitude de ligne blanche ne permet pas d'être très efficace et va davantage nuire au bon fonctionnement plutôt qu'être bénéfique. En effet, le robot pourrait confondre une ligne médiane et une autre ligne du terrain donc cette solution n'est pas optimale. | ||
+ | |||
+ | *Des capteurs infrarouge CNY70 pour savoir si il est sur le terrain ou sur la ligne médiane. | ||
+ | |||
+ | ===Partie 3: Solution adoptée=== | ||
+ | *La boussole MPU9250 renvoie des valeurs qui permettent de calculer un angle en fonction de la position du robot. Au démarrage elle enregistre une valeur initiale d'angle qui sera donc la direction dans laquelle le camp adverse se situe car le robot sera placé face à celui-ci pour le début du match. | ||
+ | **La boussole aura 2 buts: | ||
+ | ***S'il n'y a pas de balle devant le robot, la boussole enregistrera l'angle actuel puis le robot fera un tour sur lui-même sur la gauche jusqu'à retrouver sa position initiale en comparant son angle actuel à l'angle de début de tour et s'arrêtera de tourner s'il trouve une balle pour aller l'attraper. | ||
+ | ***Si le robot attrape une balle, la boussole comparera son angle avec celui du camps adverse, si le robot n'est pas dans la bonne direction il tournera sur la gauche jusqu'à se situé face au terrain adverse. | ||
+ | *Nous adopterons aussi la solution d'utiliser 2 capteurs CNY70 placé à l'avant du robot dans les "mandibules" et 1 capteur juste derrière le système de lancer de balle. Les capteurs renverront chacun une valeur entre 0(clair) et 1023(foncée). En analysant en permanence les 3 capteurs et leurs valeurs, on établira une condition qui dira que si 2 capteurs renvoient un état logique 1 sachant que le robot pendant ce temps se déplace, cela reviendrait à dire que nous sommes sur la ligne médiane car les autres lignes sont assez fines donc on arrêtera le robot directement. | ||
+ | |||
+ | ==Gestion des balles== | ||
+ | ===Partie 1: Objectif=== | ||
+ | *Le robot doit être capable de repérer la balle | ||
+ | *L'attraper | ||
+ | *La renvoyer | ||
+ | |||
+ | ===Partie 2: Recherche=== | ||
+ | *Dans le but de repérer la balle, 2 choix ont été trouvé: | ||
+ | **L'utilisation d'un capteur de distance VL53L1X qui permet de balayer le terrain pour trouver des reliefs(balles) tout comme le système de sonar d'un sous marin. Seulement le capteur n'est pas du tout assez précis et un angle légèrement différent rend l'utilisation bien moins fiable. De plus le capteur pouvait confondre un mur et les balles vu que il ne cherchait qu'un relief. | ||
+ | **Une caméra pixy2 qui permettrait d'enregistrer des formes pour pouvoir les retrouver. | ||
+ | |||
+ | *En vue de l'attraper: | ||
+ | **La réalisation d'une partie supplémentaire à l'avant du robot pour l'attraper et la bloquer. | ||
+ | **Un servomoteur possédant une barre permettant de bloquer la balle. | ||
+ | |||
+ | *Dans l'intention de renvoyer la balle: | ||
+ | **L'emploi de 2 moteurs avec 1 mini roue chacun dans le principe d'un lanceur de tennis mais le soucis rencontré est la place disponible. Donc des modifications, comme le fait d'utiliser 1 seul moteur avec une rampe ont été essayées. Cependant le soucis de place toujours présent et de puissance est remarqué, l'idée de remplacer la mini roue par une pale avec ou sans rampe fut testée mais toujours sans réelle réussite dû au manque de place et de puissance. | ||
+ | **L'emploi d'un moteur brushless avec une partie pour frapper la balle | ||
+ | |||
+ | ===Partie 3: Solution adoptée=== | ||
+ | *Pour repérer la balle, la caméra pixy2 est un bon système. En lui faisant enregistrer la forme et la couleur d'une balle elle est capable sur un maximum d'un mètre en face d'elle de repérer la dites balle et ses coordonnées. Ainsi le robot se dirigera vers elle peu à peu. Si le robot ne voit pas de balle face à lui il tournera sur lui même dans un premier temps pour observer autour de lui s'il y a une balle ou non. | ||
+ | *La partie pour attraper la balle sera composée d'une extension réalisée en modélisation 3D en forme d'entonnoir et d'un servomoteur avec une barre. Quand le robot repérera la balle il avancera dans sa direction. Grâce aux extensions des mandibules la balle se logera à l'avant du robot et le servomoteur enfermera la balle, ce qui empêchera la balle de partir et d'autres balles de rentrer. | ||
+ | *Pour renvoyer la balle un moteur brushless possédant une extension dans le style d'une barre permettra de frapper la balle quand le moteur tournera. On alimentera et contrôlera le moteur avec un Roxxy Bl-control 712 BEC qui a été relié au moteur Brushless. | ||
+ | |||
+ | ==Crève ballon== | ||
+ | [[Fichier:Support ballon.png|100px|vignette|Modélisation support-ballon]] | ||
+ | ===Partie 1: Objectif=== | ||
+ | *Crée un support pour placer le ballon | ||
+ | *Trouver un moyen pour crever le ballon | ||
+ | |||
+ | ===Partie 2: Recherche=== | ||
+ | [[Fichier:Arduino branchement.jpg|100px|vignette|Câblage arduino]] | ||
+ | *Pour le support ballon il est nécessaire de trouver un moyen de fixer à minimum 30 cm du sol un ballon et une partie pour maintenir la pièce. La conception d'un modèle 3D fut donc nécessaire. Mais pour le maintenir une petite extension en haut de la colonne à tenté d'être faites mais quand le ballon bouge il y a des chances qu'il se détache et parte | ||
+ | |||
+ | *Pour crever le ballon plusieurs idées ont été testé: | ||
+ | **Un servomoteur HS-311 avec une extension en plastique afin d'y placé un moteur à courant continue avec une partie pointu seulement le moteur manque de couple pour crever le ballon donc cette solution n'est pas utilisable. | ||
+ | **Un servomoteur HS-311 et une extension en plastique avec un servomoteur GS-9018 mais par volonté d'optimisation de ressources, de fil et de consommation on a pas choisis cette solution. | ||
+ | **Un servomoteur GS-9018 qui par mouvement à 180° pourrait crever le ballon. | ||
+ | |||
+ | ===Partie 3: Solution adoptée=== | ||
+ | |||
+ | [[Fichier:Partie creve ballon.jpg|100px|vignette|Système support et crève ballon]] | ||
+ | *Une modélisation 3D d'une colonne a été réalisé à l'aide du logiciel Openscad, celle-ci possède 2 ouverture sur sa face afin de placer le servomoteur et l'autre permettant le câblage du servomoteur(schéma ci-contre de la modélisation). Un soucis a été rencontré en plus de maintenir le ballon durablement. Le ballon étant en plastique, il pouvait être poussé par le crève ballon et non être percé. Pour remédier au soucis lié au ballon, une pince a été placé au sommet de la colonne pour l'attraper et le garder maintenue et une barre à été ajouté sur le coté de la colonne pour bloquer le ballon. | ||
+ | |||
+ | *Afin de percer le ballon, le servomoteur sera relié à un arduino (câblage ci-contre)et est équipé d'une extension réalisé en modélisation 3D afin de taper de coté le ballon en opposition à la barre qui sert à bloquer le ballon. Une pointe est placé au bout de cette extension, elle sera recouverte par un cache lors du transport pour ne représenté aucun danger et il sera enlevé une fois le robot sur le terrain. | ||
+ | |||
+ | ==Déplacement== | ||
+ | |||
+ | ===Partie 1: Objectif=== | ||
+ | |||
+ | La partie moteur se doit d'être irréprochable. En fonction des données obtenues (capteurs, pixy, timer), les moteurs se mettent en marchent à une vitesse plus ou moins rapide. | ||
+ | [[Fichier:Motor.png|vignette]] | ||
+ | |||
+ | |||
+ | *Commander les moteurs grâce au MD13S | ||
+ | [[Fichier:Cytron motor driver.jpg|vignette]] | ||
+ | |||
+ | ===Partie 2: Recherche=== | ||
+ | |||
+ | *Pour déplacer le robot, 2 moteurs MA 970D sont imposés. Pour chaque moteur on utilise un pilote de Moteur MD13S. | ||
+ | *Le MD13S a besoin d'une PWM et d'un pin normal (DIR). Pour brancher les moteurs, il y a une borne GND. | ||
+ | *Pour tester le fonctionnement des moteurs nous avons utilisé un potentiomètre pour simuler les capteurs de ligne et la boussole. | ||
+ | *La vitesse des moteurs est au minimum de 0 et au maximum de 255. | ||
+ | *Pour initialiser les moteurs sur Arduino, il faut enregistrer la librairie "Cytron Motor Driver" puis on utilisera la commande "setSpeed()" par la suite. | ||
+ | *Problème rencontré: les 2 moteurs ne tournent pas à la même vitesse pour la même consigne. | ||
+ | |||
+ | ===Partie 3: Solution adoptée=== | ||
+ | |||
+ | *Pour permettre au robot de se déplacer, les bras des moteurs s'insèrent dans des roues. | ||
+ | *Afin de remédier aux soucis de vitesse, nous avons remarqué que le problème était le manque de puissance. Avec une alimentation plus importante, le problème était réglé. | ||
+ | *Pour le moteur de gauche, il est connecté au pins 3(PWM) et 4(DIR). Le moteur de droit quant à lui est connecté aux pins 6(PWM) et 7(DIR). | ||
+ | *Voici un exemple de l'utilisation du MD13S : | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(0); | ||
+ | *En ce qui concerne la vitesse (0 à 255), nous avons privilégié des vitesses inférieures à 100. En effet, au dessus de cette valeur, le robot en devient incontrôlable. | ||
+ | |||
+ | ==Programmation== | ||
+ | Le robot fonctionne à l'aide d'un Arduino uno sur lequel on a connecté tous les composants. Chaque membre du groupe avait le code de sa partie puis nous les avons rassemblés de manière à que toutes les fonctions fonctionnent ensemble. | ||
+ | Un chronomètre est initialisé grâce à la fonction millis ainsi qu'une boussole pour connaitre la position du terrain ennemie au début du match dans l'Arduino. Si le temps est inférieur à 85 s alors le robot sera en mode recherche de balle. Le robot tournera sur lui même en regardant avec la caméra pixy s'il voit une balle. Si le robot en trouve une, il ira la chercher puis la renvoyer dans le terrain adverse en se dirigeant grâce à la Boussole, face au terrain adverse. | ||
+ | S'il n'en trouve pas alors il se déplacera puis effectuera la même démarche jusqu'à en trouver une. | ||
+ | Si le temps est supérieur à 85s alors le robot montera à la ligne blanche et percera son ballon puis s'arrêtera de fonctionner. | ||
+ | |||
+ | {{boîte déroulante/début|titre=Programme}} | ||
+ | <source lang=arduino> | ||
+ | #include<Pixy2.h> | ||
+ | #include<Servo.h> | ||
+ | #include <Wire.h> | ||
+ | #include <CytronMotorDriver.h> | ||
+ | #include <math.h> | ||
+ | #include <TimerOne.h> | ||
+ | |||
+ | #define ouvert 0 | ||
+ | #define fermer 50 | ||
+ | |||
+ | //boussole | ||
+ | #define MPU9250_ADDRESS 0x68 | ||
+ | #define MAG_ADDRESS 0x0C | ||
+ | |||
+ | #define GYRO_FULL_SCALE_250_DPS 0x00 | ||
+ | #define GYRO_FULL_SCALE_500_DPS 0x08 | ||
+ | #define GYRO_FULL_SCALE_1000_DPS 0x10 | ||
+ | #define GYRO_FULL_SCALE_2000_DPS 0x18 | ||
+ | |||
+ | #define ACC_FULL_SCALE_2_G 0x00 | ||
+ | #define ACC_FULL_SCALE_4_G 0x08 | ||
+ | #define ACC_FULL_SCALE_8_G 0x10 | ||
+ | #define ACC_FULL_SCALE_16_G 0x18 | ||
+ | |||
+ | float AngleZ = 0; | ||
+ | int BonAngle = 1; | ||
+ | float AngleInit; | ||
+ | float AngleQuelconque = 0; | ||
+ | |||
+ | // Counter BOUSSOLE | ||
+ | long int cpt = 0; | ||
+ | |||
+ | //////////////////////////////////BOUSSOLE | ||
+ | // This function reads Nbytes bytes from I2C device at address Address. | ||
+ | // Put read bytes starting at register Register in the Data array. | ||
+ | void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data) | ||
+ | { | ||
+ | // Set register address | ||
+ | Wire.beginTransmission(Address); | ||
+ | Wire.write(Register); | ||
+ | Wire.endTransmission(); | ||
+ | |||
+ | // Read Nbytes | ||
+ | Wire.requestFrom(Address, Nbytes); | ||
+ | uint8_t index = 0; | ||
+ | while (Wire.available()) | ||
+ | Data[index++] = Wire.read(); | ||
+ | } | ||
+ | |||
+ | // Write a byte (Data) in device (Address) at register (Register) | ||
+ | void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data) | ||
+ | { | ||
+ | // Set register address | ||
+ | Wire.beginTransmission(Address); | ||
+ | Wire.write(Register); | ||
+ | Wire.write(Data); | ||
+ | Wire.endTransmission(); | ||
+ | } | ||
+ | // Initial time | ||
+ | long int ti; | ||
+ | volatile bool intFlag = false; | ||
+ | ////////////////////////////BOUSSOLE | ||
+ | |||
+ | //pixy | ||
+ | Pixy2 pixy; | ||
+ | double x; | ||
+ | double y; | ||
+ | |||
+ | //Moteur | ||
+ | CytronMD moteurG(PWM_DIR, 3, 4); // PWM = broche 3, DIR = broche 4 / moteur GAUCHE | ||
+ | CytronMD moteurD(PWM_DIR, 6, 7); //PWM = broche 6, DIR = broche 7 / moteur DROIT | ||
+ | |||
+ | double var_inter; | ||
+ | double consigneG; | ||
+ | double consigneD; | ||
+ | |||
+ | // Manipulation Balle | ||
+ | Servo esc; | ||
+ | Servo blockBalle; | ||
+ | |||
+ | // Perce Ballon | ||
+ | Servo perceBallon; | ||
+ | |||
+ | int pos; | ||
+ | int i; | ||
+ | |||
+ | // Mesure temps | ||
+ | int temps; | ||
+ | const int t_max; | ||
+ | |||
+ | |||
+ | // Prototype fonction | ||
+ | void propulseBalle(); | ||
+ | void finPartie(); | ||
+ | void callback(); | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | void setup() { | ||
+ | pos = 0; | ||
+ | i = 0; | ||
+ | |||
+ | pixy.init(); | ||
+ | |||
+ | // init servo | ||
+ | // perce ballon | ||
+ | perceBallon.attach(9); | ||
+ | perceBallon.write(pos); | ||
+ | |||
+ | // block balle | ||
+ | blockBalle.attach(10); | ||
+ | blockBalle.write(ouvert); | ||
+ | |||
+ | esc.attach(11); | ||
+ | |||
+ | ////////////////////////// BOUSSOLE | ||
+ | // Arduino initializations | ||
+ | Wire.begin(); | ||
+ | Serial.begin(9600); | ||
+ | |||
+ | // Set accelerometers low pass filter at 5Hz | ||
+ | I2CwriteByte(MPU9250_ADDRESS, 29, 0x06); | ||
+ | // Set gyroscope low pass filter at 5Hz | ||
+ | I2CwriteByte(MPU9250_ADDRESS, 26, 0x06); | ||
+ | |||
+ | |||
+ | // Configure gyroscope range | ||
+ | I2CwriteByte(MPU9250_ADDRESS, 27, GYRO_FULL_SCALE_1000_DPS); | ||
+ | // Configure accelerometers range | ||
+ | I2CwriteByte(MPU9250_ADDRESS, 28, ACC_FULL_SCALE_4_G); | ||
+ | // Set by pass mode for the magnetometers | ||
+ | I2CwriteByte(MPU9250_ADDRESS, 0x37, 0x02); | ||
+ | |||
+ | // Request continuous magnetometer measurements in 16 bits | ||
+ | I2CwriteByte(MAG_ADDRESS, 0x0A, 0x16); | ||
+ | |||
+ | // pinMode(13, OUTPUT); | ||
+ | //pinMode(1, INPUT); | ||
+ | Timer1.initialize(10000); // initialize timer1, and set a 1/2 second period | ||
+ | Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt | ||
+ | |||
+ | |||
+ | // Store initial time | ||
+ | ti = millis(); | ||
+ | } | ||
+ | //////////////////////////////BOUSSOLE | ||
+ | // Counter | ||
+ | void callback() | ||
+ | { | ||
+ | intFlag = true; | ||
+ | digitalWrite(13, digitalRead(13) ^ 1); | ||
+ | } | ||
− | + | void loop() { | |
− | + | //////////////////////BOUSSOLE | |
+ | while (!intFlag); | ||
+ | intFlag = false; | ||
− | == | + | // Display time |
− | === | + | Serial.print (millis() - ti, DEC); |
− | *Le robot | + | Serial.print ("\t"); |
− | *Le robot | + | |
+ | delay(10); | ||
+ | |||
+ | // _______________ | ||
+ | // ::: Counter ::: | ||
+ | |||
+ | // Display data counter | ||
+ | // Serial.print (cpt++,DEC); | ||
+ | // Serial.print ("\t"); | ||
+ | |||
+ | |||
+ | // ____________________________________ | ||
+ | // ::: accelerometer and gyroscope ::: | ||
+ | |||
+ | // Read accelerometer and gyroscope | ||
+ | uint8_t Buf[14]; | ||
+ | I2Cread(MPU9250_ADDRESS, 0x3B, 14, Buf); | ||
+ | |||
+ | // Create 16 bits values from 8 bits data | ||
+ | |||
+ | // Accelerometer | ||
+ | int16_t ax = -(Buf[0] << 8 | Buf[1]); | ||
+ | int16_t ay = -(Buf[2] << 8 | Buf[3]); | ||
+ | int16_t az = Buf[4] << 8 | Buf[5]; | ||
+ | |||
+ | // Gyroscope | ||
+ | int16_t gx = -(Buf[8] << 8 | Buf[9]); | ||
+ | int16_t gy = -(Buf[10] << 8 | Buf[11]); | ||
+ | int16_t gz = Buf[12] << 8 | Buf[13]; | ||
+ | |||
+ | |||
+ | |||
+ | // Display values | ||
+ | |||
+ | // Accelerometer | ||
+ | /*Serial.print ("ax"); | ||
+ | Serial.print (ax,DEC); | ||
+ | Serial.print ("\t"); | ||
+ | Serial.print ("ay"); | ||
+ | Serial.print (ay,DEC); | ||
+ | Serial.print ("\t"); | ||
+ | Serial.print ("az"); | ||
+ | Serial.print (az,DEC); | ||
+ | Serial.print ("\t"); | ||
+ | |||
+ | // Gyroscope | ||
+ | Serial.print ("gx"); | ||
+ | Serial.print (gx,DEC); | ||
+ | Serial.print ("\t"); | ||
+ | Serial.print ("gy"); | ||
+ | Serial.print (gy,DEC); | ||
+ | Serial.print ("\t"); | ||
+ | Serial.print ("gz"); | ||
+ | Serial.print (gz,DEC); | ||
+ | Serial.print ("\t");*/ | ||
+ | |||
+ | |||
+ | // _____________________ | ||
+ | // ::: Magnetometer ::: | ||
+ | |||
+ | |||
+ | // Read register Status 1 and wait for the DRDY: Data Ready | ||
+ | |||
+ | uint8_t ST1; | ||
+ | do | ||
+ | { | ||
+ | I2Cread(MAG_ADDRESS, 0x02, 1, &ST1); | ||
+ | } | ||
+ | while (!(ST1 & 0x01)); | ||
+ | |||
+ | // Read magnetometer data | ||
+ | uint8_t Mag[7]; | ||
+ | I2Cread(MAG_ADDRESS, 0x03, 7, Mag); | ||
+ | |||
+ | |||
+ | // Create 16 bits values from 8 bits data | ||
+ | |||
+ | // Magnetometer | ||
+ | int16_t mx = -(Mag[3] << 8 | Mag[2]); | ||
+ | int16_t my = -(Mag[1] << 8 | Mag[0]); | ||
+ | int16_t mz = -(Mag[5] << 8 | Mag[4]); | ||
+ | |||
+ | |||
+ | // Magnetometer | ||
+ | /*Serial.print ("mx+200"); | ||
+ | Serial.print (mx+200,DEC); | ||
+ | Serial.print ("\t"); | ||
+ | Serial.print ("my-70"); | ||
+ | Serial.print (my-70,DEC); | ||
+ | Serial.print ("\t"); | ||
+ | Serial.print ("mz-700"); | ||
+ | Serial.print (mz-700,DEC); | ||
+ | Serial.print ("\t");*/ | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | AngleZ = atan2(my, mx) * (180 / PI); | ||
+ | //3.14159265); | ||
+ | if (AngleZ < 0) { | ||
+ | AngleZ = AngleZ + 360; | ||
+ | } | ||
+ | |||
+ | delay(10); | ||
+ | |||
+ | Serial.print ("Angle Z : "); | ||
+ | Serial.print (AngleZ); | ||
+ | Serial.print ("\t"); | ||
+ | |||
+ | delay(10); | ||
+ | |||
+ | //ValeurBouton = digitalRead(1); | ||
+ | //Serial.print ("valeur bouton :"); | ||
+ | // Serial.print (ValeurBouton); | ||
+ | // Serial.print ("\t"); | ||
+ | |||
+ | delay(10); | ||
+ | |||
+ | //if (ValeurBouton == 1) { | ||
+ | // BonAngle = 1; | ||
+ | // } else { | ||
+ | // BonAngle = 0; | ||
+ | //} | ||
+ | |||
+ | Serial.print("Bon angle : "); | ||
+ | Serial.print(BonAngle); | ||
+ | Serial.print(" "); | ||
+ | delay(10); | ||
+ | |||
+ | if (BonAngle == 1) { | ||
+ | AngleInit = AngleZ; | ||
+ | BonAngle = 0; | ||
+ | } | ||
+ | |||
+ | delay(10); | ||
+ | |||
+ | if (AngleZ >= AngleInit - 15 && AngleZ <= AngleInit + 15) { | ||
+ | //Code de lancé de balle | ||
+ | Serial.print("on peut lancer la balle"); | ||
+ | } | ||
+ | |||
+ | // End of line | ||
+ | Serial.println(" "); | ||
+ | delay(10); | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | // récupère données pixy | ||
+ | pixy.ccc.getBlocks(); | ||
+ | |||
+ | if (temps < t_max) | ||
+ | { | ||
+ | if (pixy.ccc.numBlocks) | ||
+ | { | ||
+ | x = pixy.ccc.blocks[0].m_x; | ||
+ | y = pixy.ccc.blocks[0].m_y; | ||
+ | if (y < 190) | ||
+ | { | ||
+ | consigneD = x / 316 * (-100) + 100; | ||
+ | var_inter = x / 316, 0; | ||
+ | consigneG = var_inter * 100; | ||
+ | moteurD.setSpeed(consigneD); | ||
+ | moteurG.setSpeed(consigneG); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | moteurG.setSpeed(90); | ||
+ | moteurD.setSpeed(90); | ||
+ | delay(100); | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(0); | ||
+ | |||
+ | propulseBalle(); | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | //pas un tour complet | ||
+ | AngleQuelconque = AngleZ; | ||
+ | if (AngleQuelconque < 350) { | ||
+ | if (AngleZ < AngleQuelconque && AngleZ > AngleQuelconque + 10) { | ||
+ | moteurG.setSpeed (0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } else { | ||
+ | moteurG.setSpeed(100); | ||
+ | moteurD.setSpeed(100); | ||
+ | delay(500); | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(0); | ||
+ | } | ||
+ | } else { //au dessus de 350 | ||
+ | if (AngleZ < AngleQuelconque && AngleZ > int(AngleQuelconque + 10) % 360) { | ||
+ | moteurG.setSpeed (0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } else { | ||
+ | moteurG.setSpeed(100); | ||
+ | moteurD.setSpeed(100); | ||
+ | delay(500); | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(0); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | finPartie(); | ||
+ | } | ||
+ | //pas en face | ||
+ | if (AngleInit >= 355) { | ||
+ | while (AngleZ < AngleInit - 5 && AngleZ > int(AngleInit + 5) % 360) { | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | if (AngleInit <= 5) { | ||
+ | while (AngleZ < int(AngleInit - 5) % 360 && AngleZ > AngleInit + 5) { | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } | ||
+ | } else { | ||
+ | if (AngleInit < 355 && AngleInit > 5) { | ||
+ | while (AngleZ < AngleInit - 5 && AngleZ > AngleInit + 5) { | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if (AngleZ >= int(AngleInit - 5) % 360 && AngleZ <= int(AngleInit + 5) % 360) { | ||
+ | moteurG.setSpeed(100); | ||
+ | moteurD.setSpeed(100); | ||
+ | delay(500); | ||
+ | moteurG.setSpeed(0); | ||
+ | moteurD.setSpeed(0); | ||
+ | } else { | ||
+ | |||
+ | //pas en retour position précedente | ||
+ | |||
+ | if (AngleQuelconque < 350) { | ||
+ | if (AngleZ < AngleQuelconque && AngleZ > AngleQuelconque + 10) { | ||
+ | moteurG.setSpeed (0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } | ||
+ | } else { //au dessus de 350 | ||
+ | if (AngleZ < AngleQuelconque && AngleZ > int(AngleQuelconque + 10) % 360) { | ||
+ | moteurG.setSpeed (0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | // Fonctions | ||
+ | |||
+ | void propulseBalle() | ||
+ | { | ||
+ | // ferme servo | ||
+ | blockBalle.write(fermer); | ||
+ | |||
+ | //pas tour complet | ||
+ | AngleQuelconque = AngleZ; | ||
+ | if (AngleQuelconque < 350) { | ||
+ | if (AngleZ < AngleQuelconque && AngleZ > AngleQuelconque + 10) { | ||
+ | moteurG.setSpeed (0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } | ||
+ | } else { //au dessus de 350 | ||
+ | if (AngleZ < AngleQuelconque && AngleZ > int(AngleQuelconque + 10) % 360) { | ||
+ | moteurG.setSpeed (0); | ||
+ | moteurD.setSpeed(100); | ||
+ | } | ||
+ | } | ||
+ | // OUVRE SERVO | ||
+ | blockBalle.write(ouvert); | ||
+ | esc.write(0); | ||
+ | delay(1000); | ||
+ | esc.write(180); | ||
+ | delay(1000); | ||
+ | esc.write(0); | ||
+ | // Tourne le moteur | ||
+ | esc.write(20); | ||
+ | } | ||
+ | |||
+ | void finPartie() | ||
+ | { | ||
+ | //partie servomoteur qui crève le ballon | ||
+ | while (i < 3) { | ||
+ | for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees | ||
+ | // in steps of 1 degree | ||
+ | perceBallon.write(pos); // tell servo to go to position in variable 'pos' | ||
+ | delay(5); // waits 15ms for the servo to reach the position | ||
+ | } | ||
+ | for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees | ||
+ | perceBallon.write(pos); // tell servo to go to position in variable 'pos' | ||
+ | delay(5); // waits 15ms for the servo to reach the position | ||
+ | } | ||
+ | i++; | ||
+ | |||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | {{boîte déroulante/fin}} | ||
+ | |||
+ | ==Assemblage du Robot== | ||
+ | [[Fichier:Robot geii2.jpg|vignette]] | ||
+ | *Le montage des différents systèmes et pièces du robot fut débuté tout d'abord par les grosses parties qui représentent la base du robot comme le bloc d'alimentation. | ||
+ | **Le bloc d'alimentation ainsi que les différents réseaux d'alimentation | ||
+ | **Bouton d'arrêt d'urgence | ||
+ | **Moteur MA 970D | ||
+ | |||
+ | *Puis après avoir fixé ces pièces et câblé, nous avons assemblé et fixé les parties supplémentaires du robot qui sont: | ||
+ | **Les supports des pilotes Moteurs MD13S auxquels nous les avons fixés. | ||
+ | **Les différents capteurs comme les 3 CNY70 et la boussole MPU9250. | ||
+ | **le système de renvoi de balle. | ||
+ | **Le support du ballon et avec le système de perçage de ballon. | ||
+ | Quand tous les derniers systèmes fut installé nous les avons reliés, câblés et alimentés. | ||
+ | |||
+ | ==Travaux à finir== | ||
+ | *Afin d'avoir un robot fonctionnel pour la compétition il reste encore quelque travaux à faire: | ||
+ | **Test et mise au point du programme sur la partie recherche de balle. | ||
+ | **Test et mise au point sur la partie "renvoie de balle". | ||
+ | **Réglages divers. | ||
+ | **Essaie du robot en situation de match pour observer le fonctionnement de chaque partie et si celle-ci ne présente pas de défaut ou dysfonctionnement sur le terrain. | ||
− | + | '''FORGEOT Cécile''' | |
− | |||
− | |||
− | + | '''LAURENS Aurélien''' | |
− | + | '''NOIRAULT Aurélien''' | |
− | + | '''SAVOURET Jason''' | |
− | |||
− | |||
− | |||
− |
Version actuelle datée du 16 avril 2021 à 15:20
Sommaire
Présentation du projet
Le projet a pour objectif de réaliser un match entre 2 robots. Ceux-ci devront envoyer depuis leur terrain le plus de balles de tennis possible sans aller sur le terrain adverse.
Le terrain mesure 8 mètres par 4 et est séparé en 2 parties par une ligne médiane donc chaque robot aura un terrain d'approximativement 16m² pour se déplacer.
Une partie dure 90s, avant la fin du temps imparti le robot devra être immobile au niveau de la ligne médiane et avoir éclaté un ballon qu'il aura emporté avec lui au début du match.
Le vainqueur sera le robot avec le moins de balle sur son terrain.
Objectif du Projet
- Réaliser un Robot capable de se déplacer dans son terrain.
- Renvoyer des balles depuis son terrain jusqu'au terrain adverse.
- Crever le ballon que l'on a emporté à l'arrêt devant la ligne médiane avant la fin du temps imparti.
Règlement
Voici ci-joint le règlement ainsi que les contraintes associées à la création du Projet.
* règlement de la coupe de robotique
Contraintes et Caractéristiques imposées
Les principales contraintes sont dues aux règles de la compétition.
- Le robot doit être dimensionné selon 30x30x40cm.
- Moteurs
- Vitesse de rotation entre 600 à 800 tr/min max.
- Moteur MFA 970d (imposé par l'IUT)
- Châssis imposé par l'IUT
- Le mécanisme lanceur de balle dépassera seulement pour envoyer la balle, il devra se replier après.
- La batterie doit être en lithium Li-ion.
- Aucune tension sur le robot ne doit dépasser 24V.
- Les dimensions du terrain sont données sur ce schéma :
Réalisation
Découpage fonctionnel
Afin de commencer le projet, nous avons dû séparer les parties essentielles du projet pour ensuite répartir les tâches.
- On a séparé le travail en différent groupe fonctionnel
- L' Alimentation
- Le Déplacement
- Le Système de renvoi des balles
- Les Capteurs pour trouver les balles
- Les Capteurs pour se repérer dans l'espace
- Un Support ballon
- Un Système de crevaison de ballon
Vous trouverez ci-joint en vignette le schéma fonctionnel de notre robot.
Répartition des tâches
- Nous nous sommes répartis les tâches de la façon suivante:
- Jason Savouret a pour tâches de s'occuper du repérage dans l'espace grâce à des capteurs.
- Aurelien Noirault gère le système de renvoie des balles ainsi que le moyen de les repérer et de les attraper, le montage du robot (pièces et composants), l'alimentation ainsi que la maintenance.
- Aurelien Laurens a pour mission de crée le système pour supporter le ballon et du système de crevaison associé pour la fin de la partie, le montage du robot (pièces et composants), l'alimentation ainsi que la maintenance et le Site Web.
- Cécile Forgeot s'oriente sur toute la partie mobilité du robot en gérant la partie déplacement ainsi que la maintenance du robot
Repérage dans l'espace
Partie 1: Objectif
- Le robot ne doit dépasser sous aucun prétexte la ligne médiane.
- Le robot doit pouvoir se placer face au terrain adverse et connaître sa position vis à vis de celui-ci.
Partie 2: Recherche
- Afin de se repérer dans l'espace plusieurs choix ont été possible:
- une boussole MPU9250 pour s’orienter vis à vis du camp adverse. Au démarrage le robot prendra en valeur initiale les coordonnées de la direction pour le camps adverses et ainsi il pourra connaître son orientation vis à vis du camp adverse.
- un capteur de couleur SEN0101 afin de capter les couleurs du terrain. Son but serait de connaître la couleur sous le capteur afin de savoir s'il se situe au dessus d'une ligne blanche ou au dessus du sol (bleu foncé) du terrain. Avec ces information cela pourrait permettre au robot de se déplacer de manière autonome sur tout le terrain en analysant le terrain.
- Dans le fonctionnement le capteur renvoie des valeurs pour connaître la composante de la couleur au dessus de laquelle il est. Grâce a une succession de tests on renvoie un état logique 1 ou 0.
- 0 permet de dire que l'on est sur le terrain (bleu).
- 1 permet de dire que l'on est sur une ligne blanche et donc possiblement la ligne médiane.
Néanmoins la multitude de ligne blanche ne permet pas d'être très efficace et va davantage nuire au bon fonctionnement plutôt qu'être bénéfique. En effet, le robot pourrait confondre une ligne médiane et une autre ligne du terrain donc cette solution n'est pas optimale.
- Des capteurs infrarouge CNY70 pour savoir si il est sur le terrain ou sur la ligne médiane.
Partie 3: Solution adoptée
- La boussole MPU9250 renvoie des valeurs qui permettent de calculer un angle en fonction de la position du robot. Au démarrage elle enregistre une valeur initiale d'angle qui sera donc la direction dans laquelle le camp adverse se situe car le robot sera placé face à celui-ci pour le début du match.
- La boussole aura 2 buts:
- S'il n'y a pas de balle devant le robot, la boussole enregistrera l'angle actuel puis le robot fera un tour sur lui-même sur la gauche jusqu'à retrouver sa position initiale en comparant son angle actuel à l'angle de début de tour et s'arrêtera de tourner s'il trouve une balle pour aller l'attraper.
- Si le robot attrape une balle, la boussole comparera son angle avec celui du camps adverse, si le robot n'est pas dans la bonne direction il tournera sur la gauche jusqu'à se situé face au terrain adverse.
- La boussole aura 2 buts:
- Nous adopterons aussi la solution d'utiliser 2 capteurs CNY70 placé à l'avant du robot dans les "mandibules" et 1 capteur juste derrière le système de lancer de balle. Les capteurs renverront chacun une valeur entre 0(clair) et 1023(foncée). En analysant en permanence les 3 capteurs et leurs valeurs, on établira une condition qui dira que si 2 capteurs renvoient un état logique 1 sachant que le robot pendant ce temps se déplace, cela reviendrait à dire que nous sommes sur la ligne médiane car les autres lignes sont assez fines donc on arrêtera le robot directement.
Gestion des balles
Partie 1: Objectif
- Le robot doit être capable de repérer la balle
- L'attraper
- La renvoyer
Partie 2: Recherche
- Dans le but de repérer la balle, 2 choix ont été trouvé:
- L'utilisation d'un capteur de distance VL53L1X qui permet de balayer le terrain pour trouver des reliefs(balles) tout comme le système de sonar d'un sous marin. Seulement le capteur n'est pas du tout assez précis et un angle légèrement différent rend l'utilisation bien moins fiable. De plus le capteur pouvait confondre un mur et les balles vu que il ne cherchait qu'un relief.
- Une caméra pixy2 qui permettrait d'enregistrer des formes pour pouvoir les retrouver.
- En vue de l'attraper:
- La réalisation d'une partie supplémentaire à l'avant du robot pour l'attraper et la bloquer.
- Un servomoteur possédant une barre permettant de bloquer la balle.
- Dans l'intention de renvoyer la balle:
- L'emploi de 2 moteurs avec 1 mini roue chacun dans le principe d'un lanceur de tennis mais le soucis rencontré est la place disponible. Donc des modifications, comme le fait d'utiliser 1 seul moteur avec une rampe ont été essayées. Cependant le soucis de place toujours présent et de puissance est remarqué, l'idée de remplacer la mini roue par une pale avec ou sans rampe fut testée mais toujours sans réelle réussite dû au manque de place et de puissance.
- L'emploi d'un moteur brushless avec une partie pour frapper la balle
Partie 3: Solution adoptée
- Pour repérer la balle, la caméra pixy2 est un bon système. En lui faisant enregistrer la forme et la couleur d'une balle elle est capable sur un maximum d'un mètre en face d'elle de repérer la dites balle et ses coordonnées. Ainsi le robot se dirigera vers elle peu à peu. Si le robot ne voit pas de balle face à lui il tournera sur lui même dans un premier temps pour observer autour de lui s'il y a une balle ou non.
- La partie pour attraper la balle sera composée d'une extension réalisée en modélisation 3D en forme d'entonnoir et d'un servomoteur avec une barre. Quand le robot repérera la balle il avancera dans sa direction. Grâce aux extensions des mandibules la balle se logera à l'avant du robot et le servomoteur enfermera la balle, ce qui empêchera la balle de partir et d'autres balles de rentrer.
- Pour renvoyer la balle un moteur brushless possédant une extension dans le style d'une barre permettra de frapper la balle quand le moteur tournera. On alimentera et contrôlera le moteur avec un Roxxy Bl-control 712 BEC qui a été relié au moteur Brushless.
Crève ballon
Partie 1: Objectif
- Crée un support pour placer le ballon
- Trouver un moyen pour crever le ballon
Partie 2: Recherche
- Pour le support ballon il est nécessaire de trouver un moyen de fixer à minimum 30 cm du sol un ballon et une partie pour maintenir la pièce. La conception d'un modèle 3D fut donc nécessaire. Mais pour le maintenir une petite extension en haut de la colonne à tenté d'être faites mais quand le ballon bouge il y a des chances qu'il se détache et parte
- Pour crever le ballon plusieurs idées ont été testé:
- Un servomoteur HS-311 avec une extension en plastique afin d'y placé un moteur à courant continue avec une partie pointu seulement le moteur manque de couple pour crever le ballon donc cette solution n'est pas utilisable.
- Un servomoteur HS-311 et une extension en plastique avec un servomoteur GS-9018 mais par volonté d'optimisation de ressources, de fil et de consommation on a pas choisis cette solution.
- Un servomoteur GS-9018 qui par mouvement à 180° pourrait crever le ballon.
Partie 3: Solution adoptée
- Une modélisation 3D d'une colonne a été réalisé à l'aide du logiciel Openscad, celle-ci possède 2 ouverture sur sa face afin de placer le servomoteur et l'autre permettant le câblage du servomoteur(schéma ci-contre de la modélisation). Un soucis a été rencontré en plus de maintenir le ballon durablement. Le ballon étant en plastique, il pouvait être poussé par le crève ballon et non être percé. Pour remédier au soucis lié au ballon, une pince a été placé au sommet de la colonne pour l'attraper et le garder maintenue et une barre à été ajouté sur le coté de la colonne pour bloquer le ballon.
- Afin de percer le ballon, le servomoteur sera relié à un arduino (câblage ci-contre)et est équipé d'une extension réalisé en modélisation 3D afin de taper de coté le ballon en opposition à la barre qui sert à bloquer le ballon. Une pointe est placé au bout de cette extension, elle sera recouverte par un cache lors du transport pour ne représenté aucun danger et il sera enlevé une fois le robot sur le terrain.
Déplacement
Partie 1: Objectif
La partie moteur se doit d'être irréprochable. En fonction des données obtenues (capteurs, pixy, timer), les moteurs se mettent en marchent à une vitesse plus ou moins rapide.
- Commander les moteurs grâce au MD13S
Partie 2: Recherche
- Pour déplacer le robot, 2 moteurs MA 970D sont imposés. Pour chaque moteur on utilise un pilote de Moteur MD13S.
- Le MD13S a besoin d'une PWM et d'un pin normal (DIR). Pour brancher les moteurs, il y a une borne GND.
- Pour tester le fonctionnement des moteurs nous avons utilisé un potentiomètre pour simuler les capteurs de ligne et la boussole.
- La vitesse des moteurs est au minimum de 0 et au maximum de 255.
- Pour initialiser les moteurs sur Arduino, il faut enregistrer la librairie "Cytron Motor Driver" puis on utilisera la commande "setSpeed()" par la suite.
- Problème rencontré: les 2 moteurs ne tournent pas à la même vitesse pour la même consigne.
Partie 3: Solution adoptée
- Pour permettre au robot de se déplacer, les bras des moteurs s'insèrent dans des roues.
- Afin de remédier aux soucis de vitesse, nous avons remarqué que le problème était le manque de puissance. Avec une alimentation plus importante, le problème était réglé.
- Pour le moteur de gauche, il est connecté au pins 3(PWM) et 4(DIR). Le moteur de droit quant à lui est connecté aux pins 6(PWM) et 7(DIR).
- Voici un exemple de l'utilisation du MD13S :
moteurG.setSpeed(0); moteurD.setSpeed(0);
- En ce qui concerne la vitesse (0 à 255), nous avons privilégié des vitesses inférieures à 100. En effet, au dessus de cette valeur, le robot en devient incontrôlable.
Programmation
Le robot fonctionne à l'aide d'un Arduino uno sur lequel on a connecté tous les composants. Chaque membre du groupe avait le code de sa partie puis nous les avons rassemblés de manière à que toutes les fonctions fonctionnent ensemble. Un chronomètre est initialisé grâce à la fonction millis ainsi qu'une boussole pour connaitre la position du terrain ennemie au début du match dans l'Arduino. Si le temps est inférieur à 85 s alors le robot sera en mode recherche de balle. Le robot tournera sur lui même en regardant avec la caméra pixy s'il voit une balle. Si le robot en trouve une, il ira la chercher puis la renvoyer dans le terrain adverse en se dirigeant grâce à la Boussole, face au terrain adverse. S'il n'en trouve pas alors il se déplacera puis effectuera la même démarche jusqu'à en trouver une. Si le temps est supérieur à 85s alors le robot montera à la ligne blanche et percera son ballon puis s'arrêtera de fonctionner.
Programme
#include<Pixy2.h>
#include<Servo.h>
#include <Wire.h>
#include <CytronMotorDriver.h>
#include <math.h>
#include <TimerOne.h>
#define ouvert 0
#define fermer 50
//boussole
#define MPU9250_ADDRESS 0x68
#define MAG_ADDRESS 0x0C
#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18
#define ACC_FULL_SCALE_2_G 0x00
#define ACC_FULL_SCALE_4_G 0x08
#define ACC_FULL_SCALE_8_G 0x10
#define ACC_FULL_SCALE_16_G 0x18
float AngleZ = 0;
int BonAngle = 1;
float AngleInit;
float AngleQuelconque = 0;
// Counter BOUSSOLE
long int cpt = 0;
//////////////////////////////////BOUSSOLE
// This function reads Nbytes bytes from I2C device at address Address.
// Put read bytes starting at register Register in the Data array.
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.endTransmission();
// Read Nbytes
Wire.requestFrom(Address, Nbytes);
uint8_t index = 0;
while (Wire.available())
Data[index++] = Wire.read();
}
// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.write(Data);
Wire.endTransmission();
}
// Initial time
long int ti;
volatile bool intFlag = false;
////////////////////////////BOUSSOLE
//pixy
Pixy2 pixy;
double x;
double y;
//Moteur
CytronMD moteurG(PWM_DIR, 3, 4); // PWM = broche 3, DIR = broche 4 / moteur GAUCHE
CytronMD moteurD(PWM_DIR, 6, 7); //PWM = broche 6, DIR = broche 7 / moteur DROIT
double var_inter;
double consigneG;
double consigneD;
// Manipulation Balle
Servo esc;
Servo blockBalle;
// Perce Ballon
Servo perceBallon;
int pos;
int i;
// Mesure temps
int temps;
const int t_max;
// Prototype fonction
void propulseBalle();
void finPartie();
void callback();
void setup() {
pos = 0;
i = 0;
pixy.init();
// init servo
// perce ballon
perceBallon.attach(9);
perceBallon.write(pos);
// block balle
blockBalle.attach(10);
blockBalle.write(ouvert);
esc.attach(11);
////////////////////////// BOUSSOLE
// Arduino initializations
Wire.begin();
Serial.begin(9600);
// Set accelerometers low pass filter at 5Hz
I2CwriteByte(MPU9250_ADDRESS, 29, 0x06);
// Set gyroscope low pass filter at 5Hz
I2CwriteByte(MPU9250_ADDRESS, 26, 0x06);
// Configure gyroscope range
I2CwriteByte(MPU9250_ADDRESS, 27, GYRO_FULL_SCALE_1000_DPS);
// Configure accelerometers range
I2CwriteByte(MPU9250_ADDRESS, 28, ACC_FULL_SCALE_4_G);
// Set by pass mode for the magnetometers
I2CwriteByte(MPU9250_ADDRESS, 0x37, 0x02);
// Request continuous magnetometer measurements in 16 bits
I2CwriteByte(MAG_ADDRESS, 0x0A, 0x16);
// pinMode(13, OUTPUT);
//pinMode(1, INPUT);
Timer1.initialize(10000); // initialize timer1, and set a 1/2 second period
Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt
// Store initial time
ti = millis();
}
//////////////////////////////BOUSSOLE
// Counter
void callback()
{
intFlag = true;
digitalWrite(13, digitalRead(13) ^ 1);
}
void loop() {
//////////////////////BOUSSOLE
while (!intFlag);
intFlag = false;
// Display time
Serial.print (millis() - ti, DEC);
Serial.print ("\t");
delay(10);
// _______________
// ::: Counter :::
// Display data counter
// Serial.print (cpt++,DEC);
// Serial.print ("\t");
// ____________________________________
// ::: accelerometer and gyroscope :::
// Read accelerometer and gyroscope
uint8_t Buf[14];
I2Cread(MPU9250_ADDRESS, 0x3B, 14, Buf);
// Create 16 bits values from 8 bits data
// Accelerometer
int16_t ax = -(Buf[0] << 8 | Buf[1]);
int16_t ay = -(Buf[2] << 8 | Buf[3]);
int16_t az = Buf[4] << 8 | Buf[5];
// Gyroscope
int16_t gx = -(Buf[8] << 8 | Buf[9]);
int16_t gy = -(Buf[10] << 8 | Buf[11]);
int16_t gz = Buf[12] << 8 | Buf[13];
// Display values
// Accelerometer
/*Serial.print ("ax");
Serial.print (ax,DEC);
Serial.print ("\t");
Serial.print ("ay");
Serial.print (ay,DEC);
Serial.print ("\t");
Serial.print ("az");
Serial.print (az,DEC);
Serial.print ("\t");
// Gyroscope
Serial.print ("gx");
Serial.print (gx,DEC);
Serial.print ("\t");
Serial.print ("gy");
Serial.print (gy,DEC);
Serial.print ("\t");
Serial.print ("gz");
Serial.print (gz,DEC);
Serial.print ("\t");*/
// _____________________
// ::: Magnetometer :::
// Read register Status 1 and wait for the DRDY: Data Ready
uint8_t ST1;
do
{
I2Cread(MAG_ADDRESS, 0x02, 1, &ST1);
}
while (!(ST1 & 0x01));
// Read magnetometer data
uint8_t Mag[7];
I2Cread(MAG_ADDRESS, 0x03, 7, Mag);
// Create 16 bits values from 8 bits data
// Magnetometer
int16_t mx = -(Mag[3] << 8 | Mag[2]);
int16_t my = -(Mag[1] << 8 | Mag[0]);
int16_t mz = -(Mag[5] << 8 | Mag[4]);
// Magnetometer
/*Serial.print ("mx+200");
Serial.print (mx+200,DEC);
Serial.print ("\t");
Serial.print ("my-70");
Serial.print (my-70,DEC);
Serial.print ("\t");
Serial.print ("mz-700");
Serial.print (mz-700,DEC);
Serial.print ("\t");*/
AngleZ = atan2(my, mx) * (180 / PI);
//3.14159265);
if (AngleZ < 0) {
AngleZ = AngleZ + 360;
}
delay(10);
Serial.print ("Angle Z : ");
Serial.print (AngleZ);
Serial.print ("\t");
delay(10);
//ValeurBouton = digitalRead(1);
//Serial.print ("valeur bouton :");
// Serial.print (ValeurBouton);
// Serial.print ("\t");
delay(10);
//if (ValeurBouton == 1) {
// BonAngle = 1;
// } else {
// BonAngle = 0;
//}
Serial.print("Bon angle : ");
Serial.print(BonAngle);
Serial.print(" ");
delay(10);
if (BonAngle == 1) {
AngleInit = AngleZ;
BonAngle = 0;
}
delay(10);
if (AngleZ >= AngleInit - 15 && AngleZ <= AngleInit + 15) {
//Code de lancé de balle
Serial.print("on peut lancer la balle");
}
// End of line
Serial.println(" ");
delay(10);
// récupère données pixy
pixy.ccc.getBlocks();
if (temps < t_max)
{
if (pixy.ccc.numBlocks)
{
x = pixy.ccc.blocks[0].m_x;
y = pixy.ccc.blocks[0].m_y;
if (y < 190)
{
consigneD = x / 316 * (-100) + 100;
var_inter = x / 316, 0;
consigneG = var_inter * 100;
moteurD.setSpeed(consigneD);
moteurG.setSpeed(consigneG);
}
else
{
moteurG.setSpeed(90);
moteurD.setSpeed(90);
delay(100);
moteurG.setSpeed(0);
moteurD.setSpeed(0);
propulseBalle();
}
}
else
{
//pas un tour complet
AngleQuelconque = AngleZ;
if (AngleQuelconque < 350) {
if (AngleZ < AngleQuelconque && AngleZ > AngleQuelconque + 10) {
moteurG.setSpeed (0);
moteurD.setSpeed(100);
} else {
moteurG.setSpeed(100);
moteurD.setSpeed(100);
delay(500);
moteurG.setSpeed(0);
moteurD.setSpeed(0);
}
} else { //au dessus de 350
if (AngleZ < AngleQuelconque && AngleZ > int(AngleQuelconque + 10) % 360) {
moteurG.setSpeed (0);
moteurD.setSpeed(100);
} else {
moteurG.setSpeed(100);
moteurD.setSpeed(100);
delay(500);
moteurG.setSpeed(0);
moteurD.setSpeed(0);
}
}
}
}
else
{
finPartie();
}
//pas en face
if (AngleInit >= 355) {
while (AngleZ < AngleInit - 5 && AngleZ > int(AngleInit + 5) % 360) {
moteurG.setSpeed(0);
moteurD.setSpeed(100);
}
}
else {
if (AngleInit <= 5) {
while (AngleZ < int(AngleInit - 5) % 360 && AngleZ > AngleInit + 5) {
moteurG.setSpeed(0);
moteurD.setSpeed(100);
}
} else {
if (AngleInit < 355 && AngleInit > 5) {
while (AngleZ < AngleInit - 5 && AngleZ > AngleInit + 5) {
moteurG.setSpeed(0);
moteurD.setSpeed(100);
}
}
}
}
if (AngleZ >= int(AngleInit - 5) % 360 && AngleZ <= int(AngleInit + 5) % 360) {
moteurG.setSpeed(100);
moteurD.setSpeed(100);
delay(500);
moteurG.setSpeed(0);
moteurD.setSpeed(0);
} else {
//pas en retour position précedente
if (AngleQuelconque < 350) {
if (AngleZ < AngleQuelconque && AngleZ > AngleQuelconque + 10) {
moteurG.setSpeed (0);
moteurD.setSpeed(100);
}
} else { //au dessus de 350
if (AngleZ < AngleQuelconque && AngleZ > int(AngleQuelconque + 10) % 360) {
moteurG.setSpeed (0);
moteurD.setSpeed(100);
}
}
}
}
// Fonctions
void propulseBalle()
{
// ferme servo
blockBalle.write(fermer);
//pas tour complet
AngleQuelconque = AngleZ;
if (AngleQuelconque < 350) {
if (AngleZ < AngleQuelconque && AngleZ > AngleQuelconque + 10) {
moteurG.setSpeed (0);
moteurD.setSpeed(100);
}
} else { //au dessus de 350
if (AngleZ < AngleQuelconque && AngleZ > int(AngleQuelconque + 10) % 360) {
moteurG.setSpeed (0);
moteurD.setSpeed(100);
}
}
// OUVRE SERVO
blockBalle.write(ouvert);
esc.write(0);
delay(1000);
esc.write(180);
delay(1000);
esc.write(0);
// Tourne le moteur
esc.write(20);
}
void finPartie()
{
//partie servomoteur qui crève le ballon
while (i < 3) {
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
perceBallon.write(pos); // tell servo to go to position in variable 'pos'
delay(5); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
perceBallon.write(pos); // tell servo to go to position in variable 'pos'
delay(5); // waits 15ms for the servo to reach the position
}
i++;
}
}
Assemblage du Robot
- Le montage des différents systèmes et pièces du robot fut débuté tout d'abord par les grosses parties qui représentent la base du robot comme le bloc d'alimentation.
- Le bloc d'alimentation ainsi que les différents réseaux d'alimentation
- Bouton d'arrêt d'urgence
- Moteur MA 970D
- Puis après avoir fixé ces pièces et câblé, nous avons assemblé et fixé les parties supplémentaires du robot qui sont:
- Les supports des pilotes Moteurs MD13S auxquels nous les avons fixés.
- Les différents capteurs comme les 3 CNY70 et la boussole MPU9250.
- le système de renvoi de balle.
- Le support du ballon et avec le système de perçage de ballon.
Quand tous les derniers systèmes fut installé nous les avons reliés, câblés et alimentés.
Travaux à finir
- Afin d'avoir un robot fonctionnel pour la compétition il reste encore quelque travaux à faire:
- Test et mise au point du programme sur la partie recherche de balle.
- Test et mise au point sur la partie "renvoie de balle".
- Réglages divers.
- Essaie du robot en situation de match pour observer le fonctionnement de chaque partie et si celle-ci ne présente pas de défaut ou dysfonctionnement sur le terrain.
FORGEOT Cécile
LAURENS Aurélien
NOIRAULT Aurélien
SAVOURET Jason