COUPE ROBOTIQUE DES IUT : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
({{Rouge|CODE}})
 
(211 révisions intermédiaires par 2 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
[[RobotGEII 16-17]]
 
                                              {{Rouge| <u>'''''Sommaire:'''''</u>}}         
 
  
# Présentation
+
Le wiki est actuellement en rédaction, certaines parties sont donc partiellement rédigées ou incomplètes.  
#*Présentation du projet
+
== ''COUPE ROBOTIQUE 2018'' ==
#*Cahier des charges fonctionnel
+
<br>
#*Solution techniques
 
# Étude et Réalisation des Différentes Parties
 
#*Alimentation et Régulation
 
#**Batterie
 
#**Moteurs de roues
 
#**Régulation de la tension d'alimentation
 
#*Contrôle des moteurs CC par un dual H-Bridge (L298P)
 
#**Principe de fonctionnement d'un H-Bridge (PONT-H)
 
#**Le composant L298N
 
#**Tests effectués avec un SHIELD Arduino (L298P)
 
#**Mode PWM
 
#*Positionnement du robot :Explication du principe
 
#**Approximation par des segments de droites
 
#*Estimation de la position du robot
 
#**Étude et Réalisation Carte Encodeurs
 
#**Roue codeuse
 
#**Valeur reçu par les capteurs  
 
#** Interruption et timer
 
#**suivons une ligne droite
 
#**suivons une consigne
 
#*Détection de balles de tennis
 
#*Caméra
 
#**Choix Caméra 
 
#**Caméra CMU cam 5
 
#** Programme de gestion du cap
 
#*Mise à l’arrêt du robot et le perçage du ballon
 
#**Capteur de "Mise à l’arrêt" du robot
 
#**Système "perçage du ballon"
 
#*Réalisation Carte des "Entrées et Sorties" et du pont H
 
#**Objectifs et Composants utilisés
 
#**Schéma électrique de la carte (Eagle)
 
#**Routage et Correspondance des pins (Eagle)
 
#**La commande des Moteurs de Roues(L298N H-Bridge)
 
#**Les signaux d'entrée et de sortie
 
#**La carte final et les connecteurs
 
#**Problèmes rencontrés :
 
#Code complet
 
#Vidéo de Démonstration
 
#Bibliographie/références
 
={{Rouge|Présentation}}=
 
=={{Vert|Présentation du projet}}==
 
Ce projet consiste à réaliser un robot pour participer à la coupe de robotique des GEII.Pour fabriquer ce robot nous devons respecter un cahier des charges défini par le :  http:(...) Le principe de ce concours est  d’envoyer un maximum de balles de tennis dans le camp adverse, sans entrer dans le camp adverse et sans jamais contrôler plus d’une balle à la fois
 
=={{Vert|Cahier des charges fonctionnel}}==
 
  
 +
[[Fichier:Maus.png|cadre|droite]]
 +
<br>
 +
=== {{Bleu|Introduction}} ===
 +
<big>P</big>our la deuxième fois consécutive l'IUT de Troyes auxquelles nous appartenons va participé à la Coupe de France Robotique des Iut qui se déroule chaque années du Jeudi 9 au samedi 11 Juin lors du Festival de Robotique dans la ville de Cachan. L'année dernière le But de la Coupe étais de se déplacé d'un point A à un point B en évitant des obstacles. Cette année l'objectif est radicalement différent puisqu'il s'agit de joué au Tennis ! 
 +
Nous avons donc développé un robot répondant à une problématique et à un cahier des charges bien précis fixé par les organisateurs de la coupe. Je vous invite à consulté le règlement afin de bien comprendre le principe de la coupe de cette année.<br>
 +
Vous pouvez retrouvé ce règlement [http://www.gesi.asso.fr/coupe_robotique_des_iut/images/2018/reglement_Robotique_2018_V001.pdf ici]<br>
 +
Cette année nous devons donc joué au tennis, voici donc un bref résumé du déroulement de la coupe :<br>
  
 +
-Deux robots se font face sur un terrain de Tennis de dimension 8*4 m.<br>
 +
-Chaque robot à sur sont terrains un certain nombre de balles de Tennis par terre.<br>
 +
-Le centre de la piste est délimité par une ligne.<br>
 +
-Il y a deux ballons de chaque côtés des deux camps leurs explosions déclenche un surplus de balle dans le camp adverse.<br>
 +
-Un match dure 90 secondes.<br>
 +
-A la fin des 90 secondes l'envoi d'un projectile autre qu'une balle dans le camps adverses ajoute une balle supplémentaires dans le terrain adverses.
 +
Il Faut donc avoir le moins de balles possibles dans sont camps à la fin de la partie.<br>
 +
Voici un aperçu du terrain:<br>
 +
[[Fichier:Terrain concour.PNG |800px|cadre|centré]]
 +
<br>
 +
<br>
 +
==={{Bleu|Etudes}}===
 +
Il y a donc de nombreux But à atteindre, nous avons donc à l'aide d'un diagramme fonctionnelle décomposé tous ces Buts en Tâches à effectuées:
 +
[[Fichier:Analyse fonctionnelle.PNG|cadre|centré]]
  
 +
Cela nous à permis de définir les tâches que le robot doit effectué et les solutions techniques associées :<br>
 +
-Se déplacé => Deux moteurs commandés par un micro controleur Atmega 2560 via un pont en H l298n. <br>
 +
-Détecté les balles de Tennis => Première Caméra Pixy. <br>
 +
-Détecté la balise pour orienté le robot => Seconde Caméra Pixy. <br>
 +
-orientation de la deuxième caméra pixy => Moteur pas à pas.<br>
 +
-Détecté la proximité avec la balle et l'attrapée => Capteur de distance SHARP et Bras préhenseur. <br>
 +
-Propulsé la balle dans le camps adverse => Verrin. <br>
 +
-Atteindre les ballons situés en bordure du terrain => Bras rotatif. <br>
 +
-Faire éclaté les ballons en bordure du terrain => Arc électrique supporté par le bras rotatif nommé précédemment. <br>
 +
-Détecté les délimitations centrale du terrain => Capteur Cny70. <br>
 +
-Détecté la proximité avec les parois du terrain => Capteurs temps de vols. <br>
  
Schéma fonctionnel de degré II
 
  
 +
=== {{Bleu|Principe de fonctionnement }} ===
 +
Comme nous l'avons vus précédemment il y a de nombreuses taches à effectuées, elles doivent toutes êtres réalisées en synchronisme cela implique un fonctionnement assez complexe que je vais vous expliquer.<br>
 +
Tous d'abord la direction, comment le robot se dirige t'il ?  Le robot doit repérer les balles et les attrapées, pour ce faire la caméra pixy située à l'avant du robot va repérer les balles, selon la position de la balle dans le champ de vision de la caméra, c'elle si va renvoyé des informations à notre microcontrôleur. Le programme que contient le microcontrôleur va commandé les moteurs dans le but de maintenir la balle au centre du champs de vision de la caméra. Il va également tâché de faire grossir la balle dans l'objectif de la caméra, c'est à dire ce rapprocher de la balle.
 +
Une fois la balle arrivée à une certaine distance de la caméra (la balle remplis quasiment l'objectif de la caméra)  un capteur de distance infrarouge Sharp va détecter la présence de la balle à l'endroit voulus, le bras va ensuite ce refermer pour "capturé" la balle. Pendant toutes cette période la deuxième caméra Pixy n'est pas restée inactive, en effet pendant ce temps elle fixe en permanence une balise émettant une lumière rouge que nous avons préalablement posé en fin de piste c'est à dire à l'arrière de notre camps. Nous pouvons donc déterminé en fonction des mouvements que notre deuxième caméra pixy à effectué ou se situe l'arrière de notre terrain.
 +
Nous pouvons donc déterminé la direction dans laquelle notre robot doit envoyé la balle !
  
  
 +
==={{Bleu|Realisation}}===
 +
<br>
 +
==== {{Rouge|<big>PREMIER PROTOTYPE</big>}} ====
 +
<br>
 +
[[Fichier:Proto1.jpg|cadre|centré]]<br>
 +
====={{Bleu|Les différents éléments}}=====
 +
<br>
 +
Nous avons choisi de concevoir un chassi qui pourrais accueillir tous nos composants, nous ne savions pas à ce moment la leurs dimensionnement.
 +
Nous avons donc découpé en fonction du besoins des plaques de plastiques que nous avons assemblé. <br>
 +
Vous pouvez voir dans la photo précédente le robot complètement assemblé. <br>
 +
Ce robot ce déplace grâce à deux moteur fournis par les organisateurs de la coupe. <br>
 +
Ce sont deux moteurs Dunkermotoren G 42*25 qui permettent au robot de se mouvoir, vous pourrez retrouvé toutes leurs caractéristiques techniques [http://www.nrc.com.tw/CAT/Dunkermotoren/GR%20G/GR42x25.pdf ici]<br>
 +
Ces moteurs et l'intégralités des dispositifs du robot sont alimentés par une batterie également définie par les organisateur de la coupe :
 +
C'est une batterie 12 V avec une capacité de 7 Ah.<br>
  
 +
{{Bleu|Déplacement:}}<br>
 +
Ces deux moteurs sont donc contrôlés par un pont en H l298n, vous pourrez trouvez toutes les informations utiles concernant ce composant [https://www.sparkfun.com/datasheets/Robotics/L298_H_Bridge.pdf ici]
 +
Ce composant serras placé sur la carte principale du robot, en effet au lieu de faire une carte pour la gestion des moteurs, une autre pour la gestion des caméras etc nous avons choisi de tous centralisé sur un seul shield d'une arduino mega.
 +
Vous pouvez également distingué sur le Robot les deux caméras Pixys, une à l'avant, une autre à l'arrière pour la détection de la Balle, une description plus précise des Pixys serras faites plus en Avale en effet elles seront abordés dans la partie traitant du second prototype.
 +
Vous pouvez voir également à l'avant du Robot le bras servant à attrapé la balle.<br>
 +
Ce bras à été imprimé à l'aide de l'imprimante 3D de l'Iut, il épouse parfaitement les dimensions de la balle, une version améliorée de ce bras à été fabriqué pour le deuxième prototype. Ce bras à été réalisé à l'aide d'une logiciel Freecad, ce logiciel libre est facile à prendre en mains c'est pour cela que nous l'avons préférés à Solydworks (même si les futures pièces seront surement faites à l'aide de ce dernier logiciel). Pour crée cette pièce nous avons crée une esquisse 2D puis à l'aide de protusion et de perçage nous obtenons une pièce en 3 dimensions. Il suffit ensuite de l'exporter sous un fichier "MESH" que l'imprimante 3D peux lire. Il existe ensuite plusieurs logiciels pouvant lire ce fichier, pour notre part nous disposions de deux imprimantes, les pièces les plus petites ont été réalisées à l'aide du logiciel Repetier Host et de l'imprimante 3D microDelta original et les pièces les plus grandes ont été réalisées grâce au logiciel Cura et à l'imprimante 3D Witbox <br>
 +
{{Bleu|Bras préhenseur:}}<br>
  
 +
[[Fichier:Bras préhension balle.PNG|cadre|centré]]
  
 +
{{Bleu|Les capteurs Cny70:}}<br>
 +
Ces capteurs à pour but de détecter le milieu du terrain en effet notre robot n'as pas à empiéter sur le terrain de l'adversaire, nous avons donc conçu des petites cartes avec le capteurs et ce qui est nécessaire à sont fonctionnement dessus, seul bé mole nous allons devoirs inclinés les  Cny en effet notre robot ne doit pas dépasser la ligne, nous devons donc la détecté à l'avance. Encore une fois si vous avez besoins de précision concernant ce photo transistor suivez ce lien : [https://www.vishay.com/docs/83751/cny70.pdf ici]
 +
<br>
 +
{{Bleu|Le moteur Pas à Pas}}<br>
  
Schéma fonctionnelle 1er degres
+
Dans ce projet, on a voulu mettre un moteur pas à pas pour la rotation de la caméra pixy derrière afin de pouvoir tourner à 360° en effet les servos moteurs présent sur la caméra pixy ne nous permettent de tournés seulement à 180°.
 +
On a donc utilisé un contrôleur de moteur pas à pas TCA 3727.
  
  
 +
[[Fichier:Pins_TCA_3727.png|cadre|centré]]
  
=={{Vert|Solutions techniques}}==
 
Pour fabriquer ce robot nous avions plusieurs choix pour procéder à la détection des balles de tennis ainsi que le contrôle et direction du robot vers la ligne noir ...  , ainsi qu'au guidage vers la position (zone) du ballon . Nous avons choisi pour guider le robot un système hybride composé de roues codeuses et d'une caméra CMUCam Pixy, spécialisée dans la reconnaissance d'objets. La roue codeuse permettra d'effectuer le début du parcours, et sera remplacée par la caméra, plus précise, une fois la distance de détection atteinte. L'évitement des obstacles sera assuré par trois capteurs infrarouges SHARP GP2Y0A21YK0F, permettant la détection d'objets jusqu'à 80 centimètres de distance, qui, placés à l'avant du robot, permettront l'esquive si un obstacle est rencontré.
 
={{Rouge|Etude et Réalisation des Differentes Parties}}=
 
=={{Vert|Alimentation et Régulation}}==
 
==={{Bleu| Batterie}}===
 
La batterie est imposée :<br>
 
  
{| class="wikitable"
+
Le câblage du contrôleur TCA 3727 se trouve ci-dessous.
|-
 
|Tension || 12 V
 
|-
 
| Capacité || 7 Ah
 
|}
 
  
 +
[[Fichier:Cablâge_moteur_pas_à_pas.png|cadre|centré]]
  
 +
On peut commander le moteur en mode Full Step ou Half Step en envoyant des signaux à des entreés I10 I11 I20 I21.
 +
Exemple du full step :
  
 +
[[Fichier:Mode_full_step.png|cadre|centré]]
  
==={{Bleu|Moteurs de roues}}===
 
Les moteurs sont imposés.
 
* '''Caracteristique du moteur:'''
 
  
{| class="wikitable"
 
|-
 
|Marque ||  Dunkermotoren G 42*25
 
|-
 
| Tension ||  15V
 
|-
 
| In || 1.45 A
 
|-
 
| Ifm || 10.9A
 
|-
 
| Rpm || 3300 tr/mn
 
|}
 
* '''Tests en conditions réeles sur les moteurs montés sur le robot ( U=12V ) :'''<br>
 
  
{| class="wikitable"
 
|-
 
|Résistance électrique ||  4 ohm
 
|-
 
| Courant à vide ||  0.28 A
 
|-
 
| Courant en charge nominale robot|| 0.7A
 
|-
 
| Courant en charge au démarage robot|| 1.6A
 
|}
 
* '''Consommation maximum en courant pour les 2 moteurs du robot :''' <br>
 
  
Imax = 2*1.6A = 3.2A <br>
 
  
  
==={{Bleu|Régulation de la tension d'alimentation}}===
+
{{Bleu|Le générateur d'arc électriques}}<br>
 +
Il est invisible ici car il est situé à l'intérieur du robot, ce petit générateur produit des petits arcs électriques en ionisant l'air, il  est commandé par un transistor Mosfet type N. Nous avons mesuré qu'il consomme au maximum de sont fonctionnement jusqu’à 3 Ampère, en effet plus l'arc électrique est grand plus la consommation de courant est grande. Après avoir effectué plusieurs tests nous en avons conclus que cette arc électrique étais suffisant pour faire éclater un ballon.
  
 +
{{Bleu|Les capteurs temps de vols}}<br>
  
* '''Les besoins :'''  
+
Nous allons être amené à nous déplacé sur le terrain , il nous faut donc pouvoir en détecter les limites, comme nous l'avons déjà vus nous avons les Cny pour repérer la ligne délimitant le milieu du terrain mais nous avons aussi besoins de capteurs capables de détecter les rebords du terrain. Pour ce faire nous utiliserons des capteurs temps de vols VL53L0X. Vous pourrez trouvez toutes les informations concernant ce capteur. [http://www.st.com/resource/en/datasheet/vl53l0x.pdf ici] 
 +
 +
[[Fichier:Capteurs VL53L0X.jpg|vignette|centré]]
 +
<br>
 +
{{Bleu|Le système pneumatique}}<br>
 +
Pour propulsé la balle nous utiliserons donc un vérin, nous utiliserons un vérin mis à disposition par notre enseignant.
 +
Ce vérin à besoins pour fonctionner d'une réserve d'air comprimée, ne pouvant évidement pas monté un compresseur sur notre petit robot nous utiliserons des cartouches de co2 de 12 G avec tige filetée, elles ont l'avantages non négligeable d'être facilement transportable.
 +
Nous commanderons le fonctionnement de notre vérin à l'aide d'une électrovanne également fournie par notre enseignant, nous sommes actuellement à la recherche d’électrovannes plus petites.
 +
Voici quelques photos du système pneumatique :
 +
On peut voir le régulateur de pression à l'arrière du robot et le vérin démonté :
 +
[[Fichier:Regulateur_pression_vérin.jpg|vignette|centré]]
 +
Sur cette photo l'on peut voir l'ensemble du système pneumatique câblé, nous avons donc notre électrovanne commandé par la carte via un survolteur 12 -> 24V. Notre électrovanne est notre interrupteur dans notre circuit pneumatique.
 +
[[Fichier:Electrovanne.jpg|cadre|centré]]
  
  
'''Pour Arduino MEGA:''' <br>
 
Caractéristiques techniques :
 
{| class="wikitable"
 
|-
 
|Operating Voltage||  5V
 
|-
 
| Input Voltage (recommended) ||  7-12V
 
|-
 
| Input Voltage (limit)|| 6-20V
 
|-
 
| Total output current MAX||800mA
 
|}
 
  
On constate qu'il est possible d'alimenter la carte Arduino MEGA directement avec la tension de la batterie ( 12.8V chargée). <br>
+
<br>
Ce n'est toutefois pas recommandé, car le régulateur intégré dans l'Arduino chaufferait, ce qui pourrait endommager le microcontrôleur. <br>
+
====={{Bleu|<big>Le shield arduino mega</big>}}=====
  
Solutions Alimentation Arduino MEGA:<br>
+
Pour commandé tous ces actionneurs que ce soit les moteurs ou les bras servants à percés les ballons ou à attrapé les balles, ainsi que pour centralisé et réagir aux informations fournis par nos nombreux capteurs nous avons besoins d'un micro contrôleur avec un nombre de pattes et un nombre de timers important. Nous avons donc choisi le micro contrôleur Atmega 2560. En effet il réponds parfaitement à nos attentes, cependant nous devons également mettre en oeuvre un pont en H et plusieurs transistors mosfet qui ne sont pas présent sur la carte arduino Mega. Nous allons donc créée un shield à cette carte. Le shield le voici :
#  Tension d'alimentation inférieure à 12 V  <br>
 
#  Tension régulé de 5V qu'on fait venir directement sur les pattes VCC d'Arduino: <br>
 
Le courant maximum requis: 800mA
 
  
 +
[[Fichier:CarteV1.jpg|vignette|centré]]
 +
[[Fichier:Carte_V1.png|cadre|centré]]
 +
 
  
'''Pour les Moteurs de Roues :'''<br>
 
 
# Tension maximum requise: 15V<br>
 
# Courant maximum requis: 3.2A  <br>
 
* '''Utilisation d'un Convertisseur DC/DC '''
 
  
Nous avons utilisé une carte faite par des étudiants des années précédents. <br>
 
  
  
 +
<br>
 +
C'est le premier shield que nous avons réalisés cependant nous avons rencontrés de nombreuses difficultés lors de sa fabrication, ces difficultés sont principalement du à un routage qui n’étais pas optimum, de très nombreux via ainsi que des piste dont la disposition ne facilitais pas le routage. Par exemple certains composants rendaient difficile le soudage des autres notamment à cause du manque de place. Cela rajouté à des erreurs de soudures ont rendus les essais de fonctionnements de cette cartes très laborieux. Finalement après une semaine à essayer de faire fonctionné correctement cette carte en vain nous avons décidé de fabriqué une version améliorée de celle si.<br>
 +
Voici donc la version corrigée de ce premier shield, le routage à été simplifié autant que possible, des nombreuses erreurs ont été corrigés et la disposition des pistes à été optimisé autant que possible. Nous avons également abordé la fabrication d'une manière différente en tirant les enseignement des erreurs de fabrication du premier shield. Par exemple nous avons soudé les composants traversants dans un ordre bien précis pour ne pas être gêner lors du soudage de ceux de l'un ou de l'autre.
 +
Voici donc le routage finale :<br>
  
Cette carte contient deux régulateurs à découpage:<br>
+
[[Fichier:CarteV3.png|cadre|centré]]<br>  
# LM2596S fournit 5V ( 3A max )<br>
+
Et voici la carte fabriqué :
# XL6009E1 qui fournit 12V ( 4A max )<br>
+
[[Fichier:CarteV2.jpg|cadre|centré]]<br>  
  
Les régulateurs fournissent largement le nécessaire en tension et courant.<br>
+
====={{Bleu|<big>La carte principale finale</big>}}=====
Pour le semestre suivant nous prévoyons à réaliser une autre carte d'alimentation, qui sera plus compacte.<br>
+
Après avoir testé et utilisé le shield arduino fabriqué pour le premier prototype, il existait toujours des problèmes qui provoquaient un mauvais fonctionnement du robot. De plus, on voulait ajouter certains composants afin d’améliorer notre robot. Pour ce faire, on a décidé de créer une carte principale en utilisant  le micro-contrôleur ATMEGAG 2560 qui se trouve sur la carte Arduino MEGA pour fabriquer une carte qui est à la fois plus compatible et a beaucoup plus de places dans le but d’installer les autres dispositifs nécessaires (module XBEE, les transistors, etc).
=={{Vert|Contrôle des moteurs CC par un dual H-Bridge (L298P)}}==
+
Cette carte a été fabriquée en tirant  les enseignements des erreurs de fabrication des cartes précédente et le routage est optimisé le plus possible pour avoir une carte de qualité et facile à dépanner et tester.  
 +
Les entrées/sorties non utilisées sont aussi reliées à des connecteurs MOLEX pour un ajout complémentaire des modules en tant que les capteurs, les modules supplémentaires dans le futur sans le besoin de refabriquer une nouvelle carte.
 +
Par contre, lors de la fabrication de cette carte principale, on a eu aussi pas mal de problème avec la mise en place du micro -contrôleur sur la carte.
  
==={{Bleu|Principe de fonctionnement d'un H-Bridge (PONT-H)}}===
+
Voici le routage de la carte :
 +
[[Fichier:Board_BOT+TOP.PNG|cadre|centré]]<br>
  
Le pont-H est une structure utilisée en électronique de puissance pour:
 
#controle moteurs
 
#convertisseurs et hacheurs
 
#onduleurs
 
  
  
* Principe:  On active les commutateurs avec differents cominaisons pour obtenir le branchement voulu. Le courant va circuler dans un sens ou dans l'autre dans le moteur, ce qui va permettre d'inverser les sens de rotation du moteur. Avec le pont-H on peut également varier la vitesse en modulant la tension aux bornes du moteur.    <br>
 
Combinaisons de commutateurs possibles pour commander un moteur DC:
 
{| class="wikitable"
 
|-
 
|Sens + || Fermer A et D
 
|-
 
| Sens - || Fermer B et C
 
|-
 
| Freinage magnétique || A et C / B et D
 
|-
 
| Arret libre || A,B,C,D ouverts
 
|-
 
| Autres combinaison || INTERDITES
 
|}
 
  
==={{Bleu|Le composant L298N }}===
+
Et voici la carte finie:
<br>
+
[[Fichier:Carte_principale.jpg|vignette|centré]]<br>  
  
Nous allons utiliser pour notre robot le composant L298N (traversant) qui a le meme principe de fonctionement que celui en CMS (L298P).
 
Dans la figure suivante on peux voir le cablage du composant, les signaux de commande et les sorties d'alimentation MOTEUR. Dans le tableau nous avons les 4 modes possibles en actionant les entrées logique C et D ainsi que Venable (PWM) pour varier la tension d'alimentation des moteurs (0-12V).
 
==={{Bleu|Tests éffectués avec un SHIELD Arduino (L298P) (}}===
 
Pour commander les moteurs nous allons utiliser le pont H L298P [ datasheet].
 
[[Fichier:L298-pinout.jpg|vignette|centré|L298P]]
 
  
Le composant est ci-dessous:
 
[[Fichier:POWERSO-20-SEMI-STM-FNT-MED.jpeg|vignette|centré|L298P]]
 
Pour faire des tests nous avons utlisé le '''Motor Shield For Arduino'''. En connectant ce shield  à l'arduino nous pouvons commander les deux moteurs (commande du sens et de la vitesse).
 
  
[[Fichier:ShildL298P.jpeg|vignette|centré|L298P]]
 
  
*'''PWM'''
 
  
Nous allons utiliser le shield en mode PWM, on placera donc les jumpers en conséquence.
 
  
[[Fichier:Arduino Shield4.png|vignette|centré|L298P]]
 
  
*'''Borne du moteur'''
+
====={{Thor_tank lors de la coupe robotique}}=====
 +
[[Fichier:Thor_tank_troyes.jpg|vignette|centré]]
  
Nous avons deux bornes (bleues) pour connecter les moteurs CC. Les connecteurs mâles derrière sont identiques à celui des bornes bleues.
 
  
[[Fichier:Arduino Shield5.png|vignette|centré|L298P]]
 
  
*'''PWRIN'''
+
==== {{Rouge|<big>SECOND PROTOTYPE</big>}} ====
 +
====={{Rouge|Le Chassi en PLA}}=====
  
Les moteurs peuvent être alimentés par une alimentation externe lorsque le courant du moteur dépasse les limites fournies par l'Arduino (Il est conseillé de séparer les alimentations d’Arduino et des moteurs). Le changement entre la puissance externe et l'Arduino est mis en œuvre par deux jumpers .<br>
+
Nous avons décidé à la suite de la réalisation du premier prototype de tenir compte au maximum des nécessité techniques que devais remplir le chassi, nous avons donc crée un châssi robuste en PLA sur lequel chacun des actionneurs serait fixé rapidement. Nous l'avons dessiné  sur Freecad et fabriqué à l'aide de l'imprimante 3D de l'iut. Il y a eu 3 versions différentes du châssi tous au long du projet voici donc quelques photos du chassi le plus récent une fois terminé :
 +
Sur freecad :
 +
[[Fichier:Chassi_vue_Supérieure.PNG|vignette|centré]]
 +
Et enfin imprimé :
 +
[[Fichier:Chassi.jpg|vignette|centré]]
 +
[[Fichier:Tourelle_assemblée.jpg|vignette|centré]]
  
'''PWRIN''': Alimentation externe.<br>
 
'''VIN''': Alimentation du Arduino.<br>
 
  
On placera donc les jumpers d’alimentation sur PWRIN.
+
====={{Rouge|Les deux caméras pixy}}=====
 +
[[Fichier:Pixy à l'avant.jpg|vignette|Pixy à l'avant]]
 +
La caméra Pixy est une caméra intelligente laquelle, principalement, fait un traitement d'images des objets qu'on garde dans leur mémoire. Cette caméra nous donne différentes informations telles que: les coordonnées X, Y du centre de l'objet, la largeur ainsi que la hauteur du carreau autour l'objet, la quantité d'objets détectés et leurs couleurs parmi des autres données. ''Vous pouvez avoir plus d'information ici http://www.cmucam.org/projects/cmucam5/wiki/Arduino_API''
  
[[Fichier:Arduino Shield6.png|vignette|centré]]
+
Pour ce projet on utilise deux caméras : La caméra positionnée devant du robot sera qui détecte les balles, également les deux  ballons à coté du terrain et celle qui est derrière sera capable de nous donner l’angle entre la direction du robot et l’arrière du terrain. Cette dernière donnée nous aidera à envoyer les balles vers la direction correcte!
  
 +
[[Fichier:20180331 134152-min.jpg|vignette| Pixy à l'arrière]]
  
On doit avoir quelque chose comme cela:
+
Pour la première caméra, elle est monté à l’inverse(important pour la programmation puisque cela change l’orientation de l’axe X!) avec qu’un seul servomoteur qui contrôle le mouvement en l’axe Y. Ce mouvement est fait simplement, tout d’abord pour la détection des balles du sol et après pour la détection des ballons.
[[Fichier:Arduino Shield3.png|vignette|centré|L298P]]
+
Pourtant, la deuxième est montée sur deux servomoteurs qui contrôle le mouvement dans les deux axes. Il se trouve que si le robot est près de la balise on risque de la perdre, c’est pour cela qu’on utilise le mouvement en Y.
  
*'''Signal de contrôle Tableau de vérité'''
+
====={{Rouge|La carte principale}}=====
 +
==== {{Rouge|<big>CODE</big>}} ====
 +
{{boîte déroulante/début|titre=codeRobot}}
 +
<source lang=c>
  
{| class="wikitable"
+
/*
|-
+
  Program challenge "Coupe Robotique des IUT 2018"
! E1 !! M1 !!  !! E2 !! M2 !! Texte de l’en-tête
+
  IUT de Troyes
|-
+
  June - 2018
| L || X || Moteur 1 désactivé || L || X || Moteur 2 désactivé
+
*/
|-
+
#include <avr/io.h>
| H || H || Moteur 1 en arrière|| H || H || Moteur 2 en arrière
+
#include <avr/interrupt.h>
|-
+
#include <Wire.h>
| H || L || Moteur 1 en avant|| H || L || Moteur 2 en avant
+
#include <SPI.h>
|-
+
#include <PixySPI_SS.h>
| PWM || X || Contrôle vitesse PWM || PWM || X || Contrôle vitesse PWM
+
#include "Adafruit_VL53L0X.h"
|}
+
#include <ServoTimer2.h>
  
'''{{Rouge|NOTE:}}'''
 
  
H: Niveau haut <br>
+
#define topPWM            255      //Valeur Max du PWM Motors (8bits)
L: Niveau bas <br>
+
#define X_center          160    //PixyBalls consigne
X: N'importe quel niveau.
+
#define sensor_ball        0  //sensor ball
  
==={{Vert|Mode PWM}}===
+
#define S1                1  //CNY70 left1
 +
#define S2                2  //CNY70 right1
 +
#define S3                3  //CNY70 left2
 +
#define S4                4  //CNY70 right2
  
 +
#define PixyBalls        22  // camera for detect balls
 +
#define PixyDirection    23  // camera for the direction of the robot
  
{| class="wikitable"
+
#define Eject_ball        36  // Eject ball
|-
+
#define Eject_cloth      38  // Eject cloth (pas utilisé)
! Commande !! Moteur !! Pin Arduino !!Pin Atmega328p  !! Signification
+
#define Explode_balloons 34  // set servo to explode balloons
|-
+
//servos Pixy direction
| M1 || Gauche || 4 || PD4 || Contrôle du sens de rotation
+
#define X_CENTER        ((PIXY_MAX_X-PIXY_MIN_X)/2)
|-
+
#define Y_CENTER        ((PIXY_MAX_Y-PIXY_MIN_Y)/2)
| E1 (PWM) || Gauche  || 5 || PD5  || Contrôle de la vitesse de rotation
 
|-
 
| M2 || Droit || 7 || PD7 || Contrôle du sens de rotation
 
|-
 
| E2 (PWM) || Droit  || 6 || PD6  || Contrôle de la vitesse de rotation
 
|-
 
  
|}
 
  
  
*'''Exemple de code'''
+
const int limit = 90;
 +
bool start = false;
 +
bool balise = false;
  
 +
int s1 = 0;
 +
int s2 = 0;
 +
int s3 = 0;
 +
int s4 = 0;
 +
float new_s1 = 0;
 +
float new_s2 = 0;
 +
float new_s3 = 0;
 +
float new_s4 = 0;
  
Nous allons gérer les moteurs par des signaux PWM (-255 a 255), le signe moins (-) indique que le moteur fonctionne en marche arrière, et le signe plus (+) qu'il fonctionne en marche avant. Ce code nous permet de gérer les deux moteurs par la fonction setVitesse(vG,vD). Dans la suite nous allons l'utiliser pour gérer le déplacement du robot.
+
int signature = 0;
 +
int timer = 0;
 +
int16_t size_max_balle = 0;
 +
int16_t size_max_ballon = 0;
 +
int16_t size = 0;
 +
bool caught_ball = false;
 +
//Cameras
 +
PixySPI_SS pixy1(PixyBalls);
 +
PixySPI_SS pixy2(PixyDirection);
  
{{boîte déroulante/début|titre=Code exemple}}
 
<source lang=c>
 
#include <avr/io.h>//Librairie AVR
 
#define topPWM 255 //Valeur Max du PWM (8bits)
 
  
void initMoteur()//PWM sur PD5 et PD6
+
//Capteurs temps de vol
 +
Adafruit_VL53L0X sensor1 = Adafruit_VL53L0X();
 +
Adafruit_VL53L0X sensor2 = Adafruit_VL53L0X();
 +
Adafruit_VL53L0X sensor3 = Adafruit_VL53L0X();
 +
Adafruit_VL53L0X sensor4 = Adafruit_VL53L0X();
 +
//Servomoteurs
 +
ServoTimer2 ball;    // servo to catch balls
 +
ServoTimer2 arm;    // servo to move the arm to explode balloons
 +
ServoTimer2 ball_pixy;
 +
////////////////////////////////////////////////////////////////
 +
////////////////////////////////////////////////////////////////
 +
// Pantilt camera direction
 +
///////////////////////////////////////////////////////////////
 +
////////////////////////////////////////////////////////////////
 +
class ServoLoop
 
{
 
{
   //fpwm = fq / (topPWM * p)
+
   public:
  //fpwmi:fréquence du PWM
+
    ServoLoop(int32_t pgain, int32_t dgain);
  //fq:fréquence du quark
 
  //topPWM: valeur maximum du PWM
 
  //p:prédiviseur
 
 
 
  //Déclaration de sorties
 
  DDRD |= (1 << PD4);//Sens du moteur Gauche
 
  DDRD |= (1 << PD5);//PWM du moteur Gauche
 
  DDRD |= (1 << PD7);//Sens du moteur Droit
 
  DDRD |= (1 << PD6);//PWM du moteur Droit
 
 
 
  TCCR0B |= (1 << CS00) | (1 << CS01);//Prédiviseur P=64
 
  
  TCCR0A |= (1 << WGM00) | (1 << WGM01);//Mode FAST PWM
+
    void update(int32_t error);
  
  TCCR0A |= 1 << COM0A1;//PWM sur OC0A
+
    int32_t m_pos;
 +
    int32_t m_prevError;
 +
    int32_t m_pgain;
 +
    int32_t m_dgain;
 +
};
  
  TCCR0A |= 1 << COM0B1;//PWM sur OC0B
 
  
  OCR0A = 0;//Valeur de comparaison pour A --> PD6
+
ServoLoop panLoop(300, 500);
 +
ServoLoop tiltLoop(500, 700);
  
  OCR0B = 0;//Valeur de comparaison pour B --> PD5
+
ServoLoop::ServoLoop(int32_t pgain, int32_t dgain)
}
 
void setMoteurG(int16_t vit)//fonction pour gérer le moteur gauche
 
 
{
 
{
   if (vit < 0)
+
   m_pos = PIXY_RCS_CENTER_POS;
  {
+
   m_pgain = pgain;
    vit = -vit;
+
   m_dgain = dgain;
    PORTD |= (1 << PD4);//Moteur Gauche en arrière
+
   m_prevError = 0x80000000L;
   }
 
  else PORTD &= ~ (1 << PD4);//Moteur Gauche en avant
 
 
 
   if (vit > topPWM) vit = topPWM;//Si jamais on met une valeur supérieure à 255, la vitesse maximum sera 255
 
 
 
   OCR0B = vit;//Action sur le PWM --> PD5
 
 
}
 
}
  
void setMoteurD(int16_t vit)//fonction pour gérer le moteur droit
+
void ServoLoop::update(int32_t error)
 
{
 
{
   if (vit < 0)
+
  long int vel;
 +
  char buf[32];
 +
   if (m_prevError != 0x80000000)
 
   {
 
   {
     vit = -vit;
+
     vel = (error * m_pgain + (error - m_prevError) * m_dgain) >> 10;
     PORTD |= (1 << PD7);//Moteur Droit en arrière
+
     //sprintf(buf, "%ld\n", vel);
 +
    //Serial.print(buf);
 +
    m_pos += vel;
 +
    if (m_pos > PIXY_RCS_MAX_POS)
 +
      m_pos = PIXY_RCS_MAX_POS;
 +
    else if (m_pos < PIXY_RCS_MIN_POS)
 +
      m_pos = PIXY_RCS_MIN_POS;
 
   }
 
   }
   else PORTD &= ~ (1 << PD7);//Moteur Droit en avant
+
   m_prevError = error;
 
 
  if (vit > topPWM) vit = topPWM;//Si jamais on met une valeur supérieure a 255, la vitesse maximum sera 255
 
 
 
  OCR0A = vit;//Action sur le PWM --> PD6
 
 
}
 
}
 
+
///////////////////////////////////////////////////////////////////////////
void setVitesse(int16_t vG, int16_t vD)//cette fonction nous permet gérer les deux moteurs avec "une seule" ligne
+
///////////////////////////////////////////////////////////////////////////
 +
// PixyDirection
 +
///////////////////////////////////////////////////////////////////////////
 +
///////////////////////////////////////////////////////////////////////////
 +
void direction()
 
{
 
{
  setMoteurD(vD);
 
  setMoteurG(vG);
 
}
 
  
int main()
+
  uint16_t blocks;
{
+
   int32_t panError, tiltError;
   initMoteur();
 
  
while(1)
+
   blocks = pixy2.getBlocks();
{
 
   setVitesse(100,100);//Exemple d’utilisation
 
}
 
}
 
  
</source>
+
  if (blocks)
{{boîte déroulante/fin}}
+
  {
 +
    panError = X_CENTER - pixy2.blocks[0].x;
 +
    tiltError = pixy2.blocks[0].y - Y_CENTER;
  
=={{Vert|Positionnement du robot: Explication du principe}}==
+
    panLoop.update(panError);
==={{Bleu|Approximation par des segments de droites}}===
+
    tiltLoop.update(tiltError);
  
Le positionnement du robot est obtenu par odométrie, c'est à dire que la position est obtenue par intégration de petits déplacements. L'intérêt de l'odométrie est qu'elle est assez simple à mettre en oeuvre et qu'elle est fiable. Par contre, quand on intègre les déplacements, on intègre aussi l'erreur ce qui fait que l'erreur de position croît avec le temps.
+
    pixy2.setServos(panLoop.m_pos, tiltLoop.m_pos);
 
+
a    balise = true; //balise detectee
Entre deux lectures, on peut savoir de combien s'est déplacée chaque roue codeuse et il faut à partir de cela en déduire la position du robot.
+
  }
 
+
  else balise = false;
 
+
}
[[Fichier:GrapheASD.png|vignette|centré]]
+
//////////////////////////////////////////////////////////////////
 
+
//////////////////////////////////////////////////////////////////
Appelons ∆d et ∆g les distances (en mm) parcourues respectivement par les roues droites et gauches entre deux lectures des LM soit un intervalle de temps Te. Connaissant la position du robot à l'instant n-1, on cherche la pose à l'instant n.
+
//SetMotors
 
+
//////////////////////////////////////////////////////////////////
 
+
//////////////////////////////////////////////////////////////////
[[Fichier:4545.png|vignette|centré]]
+
void initMotor()//PWM on PE3 (Left) and PH3(Right)
 
+
{
On a donc :
+
  //fpwm = fq / (topPWM * p)
∆moy_n = (∆d_n + ∆g_n)/2
+
  //fpwmi: frequency PWM
 
+
  //fq: frequency quartz
∆dif_n = ∆d_n - ∆g_n
+
  //topPWM: value max PWM
 
+
  //p: predivisor
∆x_n = ∆moy_n cos(theta_n-1)
 
 
 
∆y_n = ∆moy_n sin(theta_n-1)
 
 
 
∆theta_n = ∆dif_n/L
 
 
 
 
 
x_n = x_n-1 + ∆x_n
 
 
 
y_n = y_n-1 + ∆y_n
 
 
 
theta_n = theta_n-1 + ∆theta_n
 
=={{Vert|Estimation de la position du robot }}==
 
 
 
==={{Bleu|Etude et Réalisation Carte Encodeurs}}===
 
 
 
L'odométrie nous permettra d'estimer la position du robot en mouvement, des le début et jusqu'à la détection de la balise par la caméra. C'est à partir de la mesure des déplacements des roues, qu'on pourra reconstituer le mouvement du robot. En partant d'une position initiale connue et en intégrant les déplacements mesurés, on peut ainsi calculer à chaque instant la position courante du véhicule.
 
 
 
 
 
Pour mesurer le déplacement des roues, nous allons utiliser un encodeur, monté sur l'axe de chaque roue.
 
[[Fichier:Encodeur roue.PNG|cadre|centre]]
 
 
 
 
 
*'''ENCODEUR DE BASE''':
 
Ce montage basique permet de mesurer la vitesse de rotation à partir de la fréquence, mais il ne permet pas de connaître le sens de rotation.
 
 
 
[[Fichier:Principe de base.PNG|350px|vignette|centre|principe ]]
 
 
 
 
 
 
 
*'''ENCODEUR EN QUADRATURE''':  
 
Celui-ci nous permettra de connaître à la fois le sens et la vitesse des roues. Il est composé d’un disque rotatif, 1 led infrarouge et 2 capteurs optique décalé un par rapport à l’autre de 90°. C’est justement ce décalage la qui va nous permettre de connaître le sens de rotation de la roue. Suivant le sens de rotation, nous auront deux signaux déphasés en avance/retard de 90°. La vitesse sera déterminé en fonction de la fréquence.
 
 
 
[[Fichier:Encodeur en quadrature.PNG|500px|vignette|gauche]]
 
 
 
 
 
[[Fichier:Signaux de sortie.PNG|400px|vignette|centré]]
 
            Les signaux de sortie à l’oscilloscope
 
 
 
 
 
 
 
 
 
*'''CAPTEUR TCUT 1300'''.  Nous allons utiliser ce capteur il nous permettra d'avoir le sens et la vitesse de chaque roue.
 
The TCUT1300X01 is a compact transmissive sensor that
 
includes an infrared emitter and two phototransistor
 
detectors, located face-to-face in a surface mount package.
 
 
 
[[Fichier:Tcut1300.PNG|400px|gauche]]
 
 
 
[[Fichier: TCUT1300 1.PNG|200px|centre]]
 
 
 
 
 
[[Fichier: Caracteristiques Tcut 1300.PNG|700px|gauche]]
 
  
 +
  //Declaration de sorties
 +
  DDRB |= (1 << PB6);//Sense motor left    12  in1
 +
  DDRB |= (1 << PB5);//Sense motor left    11  in2
 +
  DDRH |= (1 << PH3);//PWM motor left OC4A  6  enA
 +
  DDRH |= (1 << PH4);//Sense motor right    7  in3
 +
  DDRB |= (1 << PB4);//Sense motor right    10  in4
 +
  DDRH |= (1 << PH5);//PWM motor right OC4C 8  enB
  
  
 +
  //Timer4 PH3
  
 +
  TCCR4A |= (1 << WGM40);//Mode FAST PWM
 +
  TCCR4B |= (1 << WGM42);
  
 +
  TCCR4B |= (1 << CS40) | (1 << CS41);//divisor P=64
  
  
 +
  TCCR4A |= 1 << COM4A1;//PWM on OC4A
  
 +
  TCCR4A |= 1 << COM4C1;//PWM on OC4C
  
 +
  OCR4A = 0;//Value first comparison  --> PH3
  
 +
  OCR4C = 0;//Value first comparison --> PH5
 +
}
  
  
 
+
void setMotorL(int16_t speed)//function motor left
 
 
 
 
*'''Schéma et dimensionnement des composants'''
 
 
 
Emiter:  If = 10mA (Vf = 1.2V), Re = (5V-Vf)/If = 380 ohm. 
 
 
 
Collector: Ic sat = 0.4mA (If = 10mA), Rmin = Vce /Ic = 12.5 kohm. Vce sat = 0.4V max (pour Ic sat = 0.4mA, If = 10mA ). On prendra Rc = 15 kohm.
 
 
 
Nous devons obtenir les signaux correspondents:
 
 
 
{| class="wikitable"
 
|-
 
|Présence dent || Signal de sortie = 0 V
 
|-
 
| Absence dent || Signal de sortie = 5 V
 
|}
 
 
 
[[Fichier: Schéma TCUT 1300.PNG|500px|centré]]
 
*'''Schéma et routage en Eagle'''
 
 
 
 
 
// [[Fichier: Schéma Encodeur12.PNG|600px|gauche]]
 
 
// [[Fichier: Routage Encodeur.PNG |600px|centré]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
*'''Réalisation carte (2 exemplaires) et installation '''
 
 
 
- Carte simple face CMS.
 
 
 
'''TEST RÉALISÉ SUR LA CARTE FINIE:'''
 
 
 
{| class="wikitable"
 
|-
 
|Présence dent || G1,G2,D1,D2 = 0 V
 
|-
 
| Absence dent || G1,G2,D1,D2 = 4.8 V
 
|}
 
 
 
'''Conclusion:''' Les valeurs sont cohérentes et exploitables.
 
 
 
// [[Fichier: Carte_finale.PNG|500px|vignette|gauche]] 
 
[[Fichier: CarteEncodeur+RouesCodeuse.jpg |630px|vignette|droite]] <br>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<br>
 
 
 
 
 
 
 
==={{Bleu|Roue codeuse}}===
 
 
 
Pour determiner la position du robot nous allons utiliser deux Roues Codeuses et deux capteurs (TCUT 1300). Nous avons créé le roue sur le logiciel GEFAO et fabrication avec la machine '''charlyrobot'''. Vous trouverez ici le fichier de la roue ([[Fichier:RoueCodeuse.zip]]).
 
 
 
 
 
 
 
[[Fichier:Roue codeuse.jpg|thumb|800px|centré|Roue Codeuse composée de 30 dents]]
 
 
 
==={{Bleu|Valeurs recu par les capteurs}}===
 
 
 
Cette roue sera placer sur l'arbre des motors et sur les deux capteurs, lorsque le moteur est en train de tourner les capteurs va nous envoyer une signal qui se resamblera à:
 
 
 
 
 
 
 
*'''Si la roue en avant'''
 
 
 
Il faut remarquer que la signal 1 est en avance. Donc sur chaque front montant de la signal 1, la signal 2 est à 0. Et sur chanque front descendate de la signal 1, la signal 2 est à 1. Ce raisonnement sera utiliser dans le code du proogramme.
 
 
 
 
 
[[Fichier:Signal capteurRC.jpg|thumb|500px|centré]]
 
 
 
 
 
*'''Si la roue en arriere'''
 
 
 
Il faut remarquer que la signal 1 est en retard. Donc sur chaque front montant de la signal 1, la signal 2 est à 1. Et sur chanque front descendate de la signal 1, la signal 2 est à 0. Ce raisonnement sera aussi utiliser dans le code du proogramme.
 
 
 
 
 
 
 
[[Fichier:Signal capteurRCarriere.jpg|thumb|450px|centré]]
 
 
 
 
 
Il faut remarquer que si le robot avance, la roue codeuse est en arriere et si le robot recule la roue codeuse est en avant. Ce effet est du aux engranages qui sont sur les moteurs et la roue.
 
 
 
==={{Bleu|Interruptions et timer}}===
 
<br>
 
 
 
*'''Interruptions INT0 et INT1: Code example'''
 
 
 
Dans cette partie nous allons utiliser les interruptions et les timers. On utilisera les inturruptions ('''INT0 et INT1''') pour dechancher un code a chaque fois que les dents de la roue codeuse travers le flux lumineuse du capteurs (sur le front montant et front descendant). Nous allons aussi utliser un timer qui sera dechanché sur un temps assez petit ( <10ms) pour calculer un deltaX, un deltaY et un detaTeta qui nous permetront de determiner la position du robot a chaque instante.
 
 
 
{{boîte déroulante/début|titre=Code example}}
 
<source lang=c>
 
#include <avr/io.h>//Libreries AVR
 
 
 
volatile int8_t NbDentsD = 0; //Nombre de dents captés par le capteur (TCUT 1300) de la roue codeuse Droit
 
volatile int8_t NbDentsG = 0; //Nombre de dents captés par le capteur (TCUT 1300) de la Roue Codeuse Gauge
 
 
 
 
 
ISR(INT0_vect)
 
 
{
 
{
   //Sur chaque roue nous avons un emeteur et deux recepteurs, ces deux seront lus sur le pates PD2 et PB0
+
   if (speed < 0)
  uint8_t Pin2 = PIND & (1 << PD2); //INTERRUPTION INT0 sur PD2
 
  uint8_t Pin8 = PINB & (1 << PB0);
 
 
 
  if (Pin2 != 0)
 
 
   {
 
   {
     if (Pin8 == 0) NbDentsD++;//Si la roue droit avance dont on aditionne le dents
+
     speed = -speed;
     else NbDentsD--;//sinon on soustrait les dents, car cela signifie que le roue est en arrière
+
    PORTB |= (1 << PB6);//Motor left : sense "-"
 +
     PORTB &= ~ (1 << PB5);
 
   }
 
   }
   else if (Pin2 == 0)
+
   else {
  {
+
     PORTB &= ~ (1 << PB6);//Motor left : sense "+"
     if (Pin8 != 0) NbDentsD++;
+
     PORTB |= (1 << PB5);
     else NbDentsD--;
 
 
   }
 
   }
 +
  if (speed > topPWM) speed = topPWM;//speed max
 +
 +
  OCR4A = speed;//Action sur le PWM --> PE3
 
}
 
}
  
ISR(INT1_vect)
+
void setMotorR(int16_t speed)//function motor right
 
{
 
{
   uint8_t Pin3 = PIND & (1 << PD3); //INTERRUPTION INT1 sur PD3
+
   if (speed < 0)
  uint8_t Pin9 = PINB & (1 << PB1);
 
 
 
  if (Pin3 != 0)
 
 
   {
 
   {
     if (Pin9 == 0) NbDentsG++;//Si la roue gauge avance dont on aditionne le dents
+
     speed = -speed;
     else {
+
    PORTH &= ~ (1 << PH4); //Motor right : sense "-"
      NbDentsG--;//sinon on soustrait les dents, car cela signifie que le roue est en arrière
+
     PORTB |=  (1 << PB4);
    }
 
 
   }
 
   }
   else if (Pin3 == 0)
+
   else
 
   {
 
   {
     if (Pin9 != 0) NbDentsG++;
+
     PORTH |= (1 << PH4); //Motor left : sense "+"
     else {
+
     PORTB &= ~ (1 << PB4);
      NbDentsG--;
 
    }
 
 
   }
 
   }
}
 
 
void int0()
 
{
 
  //CONFIGURATION INTERRUPTION INT0
 
  //Pin2 --> PD2--> INT0 entrée
 
 
  EIMSK |= 1 << INT0; //Autorisation interruption INT0
 
  
   EICRA |= 1 << ISC00; //Activation sur changement d'etat sur PD2
+
   if (speed > topPWM) speed = topPWM;//speed max
}
 
  
void int1()
+
   OCR4C = speed;//Action sur le PWM --> PH3
{
 
   //CONFIGURATION INTERRUPTION INT1
 
  //PIN3 -->PD3--> INT1 entrée
 
 
 
  EIMSK |= 1 << INT1; //Autorisation interruption INT1
 
 
 
  EICRA |= 1 << ISC10; //Activation sur changement d'etat sur PD3
 
 
}
 
}
  
void sei_interruption()
+
void setSpeed(int16_t vL, int16_t vR)//only one function for 2 motors
 
{
 
{
   sei(); //Autorisation global d'interruptions
+
   setMotorL(vL);
 +
  setMotorR(vR);
 
}
 
}
 
+
//////////////////////////////////////////////////////////////////
int main()
+
//////////////////////////////////////////////////////////////////
{
+
// play time = 90s
  int0();//Interruption 0
+
//////////////////////////////////////////////////////////////////
  int1();//Interruption 1
+
//////////////////////////////////////////////////////////////////
  sei_interruption();//Autorisation d'interruptions
+
void timer_90s()
 
 
  while(1)
 
  {
 
 
 
  }
 
}
 
 
 
</source>
 
{{boîte déroulante/fin}}
 
 
 
*'''TIMER 1'''
 
En faite nous allons calculer la position du robot en ajoutant de petits deltas de postition lequels seront calculer sur un temps suffisamment petit ( <20ms)  pour eviter que l'erreur soit grand. On utilisera un drapeau pour eviter de faire de calculs dans le ISR(TIMER1_COMPA_vect), nous allons les faire plutot sur while(1), cela nous permettra de reduire l'erreur.
 
 
 
{{boîte déroulante/début|titre=Code example}}
 
<source lang=c>
 
#include <avr/io.h>//Libreries AVR
 
 
 
void timer1()//CONFIGURATION DU TIMER1
 
 
{
 
{
 
   //Tt1=(n*p)/fq
 
   //Tt1=(n*p)/fq
 +
  //n=Tt1*fq/p
 
   //Tt1: periode du timer
 
   //Tt1: periode du timer
 
   //n=valuer de comparaison (OCR1A)
 
   //n=valuer de comparaison (OCR1A)
 
   //p:prediviseur
 
   //p:prediviseur
   //fq:frequence du quark (arduino uno 16Mhz)
+
   //fq:frequence du quark (arduino Mega 16Mhz)
  
   TCCR1B |= (1 << CS10) | (1 << CS11); //p=64
+
   TCCR1B |= (1 << CS10) | (1 << CS12); //p=1024
  
 
   TCCR1B |= 1 << WGM12; //RAZ mode CTC
 
   TCCR1B |= 1 << WGM12; //RAZ mode CTC
Ligne 686 : Ligne 435 :
 
   TIMSK1 |= 1 << OCIE1A; //Autorisation d'interruption de comparaison A
 
   TIMSK1 |= 1 << OCIE1A; //Autorisation d'interruption de comparaison A
  
   OCR1A = 7500; //Comparaison n=7500
+
   OCR1A = 15625; //Comparaison , Tt1=1s,
 
}
 
}
  
 
ISR(TIMER1_COMPA_vect)
 
ISR(TIMER1_COMPA_vect)
 
{
 
{
   newCalc = true;//drapeau
+
   timer++;
 +
  //PORTB^=1<<PB7; activar verin para la tela blanca
 
}
 
}
 +
//////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////
 +
// setCameras
 +
//////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////
 +
void setCameras() {
  
int main()
+
  //pixy2.init();
{
+
  pinMode(PixyBalls, OUTPUT); // Slave output PixyBalls
   timer1();
+
   pinMode(PixyDirection, OUTPUT); // Slave output PixyDirection
   while (1)
+
 
   {
+
   digitalWrite(PixyBalls, HIGH); // desactivation PixyBalls
    if (newCalc == true)
+
   digitalWrite(PixyBalls, HIGH); // desactivation PixyDirection
    {
 
  
    //Calculs de la position
+
  pixy1.init();
 +
  pixy2.init();
  
      newCalc = false;
+
}
    }
+
//////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////
 +
// PixyBalls
 +
//////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////
 +
void Pixy_tracking() {
 +
  int signature = 0;
  
 +
  //unsigned int16_t size_max_balle = 0;
 +
  //unsigned int16_t size_max_ballon = 0;
 +
  uint32_t size_balle = 0;
 +
  uint16_t posX  = 0;
 +
  //static int i = 0;
 +
  int blocks;
 +
  blocks    = pixy1.getBlocks();
 +
  // grab blocks!
 +
  if (blocks)
 +
  {
 +
    signature        = pixy1.blocks[0].signature;
 +
    posX            = pixy1.blocks[0].x;
 +
    size_balle      = pixy1.blocks[0].width; * pixy1.blocks[0].height;
 
   }
 
   }
 +
  /*else
 +
  {
 +
    posX = 0;
 +
    size_balle = 0;
 +
  }*/
 +
  //Serial.println(sizeta /256)
 
}
 
}
</source>
+
//////////////////////////////////////////////////////////////////
{{boîte déroulante/fin}}
+
//////////////////////////////////////////////////////////////////
 
+
// Activation capteurs temps de vol protocol I2C
==={{Bleu|Suivons une ligne droite}}===
+
//////////////////////////////////////////////////////////////////
 
+
//////////////////////////////////////////////////////////////////
On sait que le moteurs n'ont pas la vitesse, donc il faut essayer de faire cela par code. On va donc faire '''setVitesse(Vmax * cos(Teta + PI / 4.0), Vmax * sin(Teta + PI / 4.0))''', les cos et sin nous permettra jouer sur la vitesse et de cette facon faire que le robot suis une ligne droite. Il faut remarquer qu'il ne va pas s'arreter.
+
void configAddress() {
 
+
  pinMode(44, OUTPUT);
{{boîte déroulante/début|titre=Code de Suivons une ligne droite}}
+
  pinMode(45, OUTPUT);
<source lang=c>
+
   pinMode(46, OUTPUT);
#include <avr/io.h>//Libreries AVR
+
   pinMode(47, OUTPUT);
#include <math.h>//Libreries Math pour les calculs de sinus, cosinus, etc;
 
 
 
#define topPWM 255 //Valeur Max du PWM (8bits)
 
 
 
float d = 51.2; //Rayon des roues
 
float Delta_Dent = PI * d / 60.0; //Espacement entre chaque dent de la roue.
 
float L = 230.0; //Distence entre les centre des roues.
 
 
 
volatile int8_t NbDentsD = 0; //Nombre de dents captés par le capteur TCUT 1300 de la roue codeuse Droit
 
volatile int8_t NbDentsG = 0; //Nombre de dents captés par le capteur TCUT 1300 de la Roue Codeuse Gauge
 
 
 
float Delta_D = 0;
 
float Delta_G = 0;
 
 
 
float Delta_moy = 0;
 
float Delta_dif = 0;
 
float Delta_teta = 0;
 
 
 
float Delta_X = 0;
 
float Delta_Y = 0;
 
 
 
float Position_X = 0;
 
float Position_X_precendent = 0;
 
 
 
float Position_Y = 0;
 
float Position_Y_precendent = 0;
 
 
 
float Teta = 0;
 
float Teta_precedent = 0;
 
 
 
float Teta_consigne = 0; //Angle qu'on veux attaindre
 
float X_consigne = 0; //Position en X qu'on veux attaindre
 
float Y_consigne = 0; //Position en Y qu'on veux attaindre
 
 
 
volatile boolean newCalc = true;//Drapeau qui nous permetra de
 
 
 
float Vmax = 0;
 
 
 
void int0()
 
{
 
   //CONFIGURATION INTERRUPTION INT0
 
   //Pin2 --> PD2--> INT0 entrée
 
  
   EIMSK |= 1 << INT0; //Autorisation interruption INT0
+
   digitalWrite(47, HIGH);
 +
  digitalWrite(46, LOW);
 +
  digitalWrite(45, LOW);
 +
  digitalWrite(44, LOW);
 +
  sensor1.setAddress(30);
 +
  sensor1.begin(30);
 +
  delay(10);
 +
// Serial.println("1 device");
  
   EICRA |= 1 << ISC00; //Activation sur changement d'etat sur PD2
+
   digitalWrite(47, HIGH);
}
+
  digitalWrite(46, HIGH);
 
+
  digitalWrite(45, LOW);
void int1()
+
  digitalWrite(44, LOW);
{
+
  sensor2.setAddress(31);
   //CONFIGURATION INTERRUPTION INT1
+
   sensor2.begin(31);
   //PIN3 -->PD3--> INT1 entrée
+
   delay(10);
 +
// Serial.println("2 device");
  
   EIMSK |= 1 << INT1; //Autorisation interruption INT1
+
   digitalWrite(47, HIGH);
 +
  digitalWrite(46, HIGH);
 +
  digitalWrite(45, HIGH);
 +
  digitalWrite(44, LOW);
 +
  sensor3.setAddress(32);
 +
  sensor3.begin(32);
 +
  delay(10);
 +
//Serial.println("3 device");
  
   EICRA |= 1 << ISC10; //Activation sur changement d'etat sur PD3
+
   digitalWrite(47, HIGH);
 +
  digitalWrite(46, HIGH);
 +
  digitalWrite(45, HIGH);
 +
  digitalWrite(44, HIGH);
 +
  sensor3.setAddress(32);
 +
  sensor4.setAddress(33);
 +
  sensor4.begin(33);
 +
  delay(10);
 +
  //Serial.println("4 device");
 
}
 
}
  
void timer1()//CONFIGURATION DU TIMER1
+
void sensorRead() {
{
 
  //Tt1=(n*p)/fq
 
  //Tt1: periode du timer
 
  //n=valuer de comparaison (OCR1A)
 
  //p:prediviseur
 
  //fq:frequence du quark (arduino uno 16Mhz)
 
 
 
  TCCR1B |= (1 << CS10) | (1 << CS11); //p=64
 
  
   TCCR1B |= 1 << WGM12; //RAZ mode CTC
+
   VL53L0X_RangingMeasurementData_t measure1; // mesure prope de la librairie
 +
  VL53L0X_RangingMeasurementData_t measure2;
 +
  VL53L0X_RangingMeasurementData_t measure3;
 +
  VL53L0X_RangingMeasurementData_t measure4;
  
   TIMSK1 |= 1 << OCIE1A; //Autorisation d'interruption de comparaison A
+
   sensor1.rangingTest(&measure1, false);
 +
  sensor2.rangingTest(&measure2, false);
 +
  sensor3.rangingTest(&measure3, false);
 +
  sensor4.rangingTest(&measure4, false);
  
   OCR1A = 7500; //Comparaison n=7500
+
   s1 = measure1.RangeMilliMeter;
 +
  //delay(30);
 +
  s2 = measure2.RangeMilliMeter;
 +
  //delay(30);
 +
  s3 = measure3.RangeMilliMeter;
 +
  //delay(30);
 +
  s4 = measure4.RangeMilliMeter;
 +
  delay(30);  // mesure rapide, on a des autres posibilitées
 
}
 
}
 +
//////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////
 +
// Détection des obstacles(limites du terrain)
 +
//////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////
 +
void robot_movement() {
  
void initMoteur()//PWM sur PD5 et PD6
+
   if ( s1 <= limit) new_s1 = 0.55 * limit; // détection de la limite du terrain
{
+
   else new_s1 = 0;
  //fpwm = fq / (topPWM * p)
 
  //fpwmi:frequence du PWM
 
  //fq:frequance du quark
 
  //topPWM: valeur maximun du PWM
 
  //p:prediviseur
 
 
 
   //Declaration de sorties
 
  DDRD |= (1 << PD4);//Sens du motor Gauge
 
  DDRD |= (1 << PD5);//PWM du motor Gauge
 
  DDRD |= (1 << PD7);//Sens du motor Droit
 
  DDRD |= (1 << PD6);//PWM du motor Droit
 
 
 
   TCCR0B |= (1 << CS00) | (1 << CS01);//Prediviseur P=64
 
 
 
  TCCR0A |= (1 << WGM00) | (1 << WGM01);//Mode FAST PWM
 
 
 
  TCCR0A |= 1 << COM0A1;//PWM sur OC0A
 
  
   TCCR0A |= 1 << COM0B1;//PWM sur OC0B
+
   if ( s2 <= limit) new_s2 = 3.2* limit;
 +
  else new_s2 = 0;
  
   OCR0A = 0;//Valeur de comparaison pour A --> PD6
+
   if ( s3 <= limit) new_s3 = 3.2* limit;
 +
  else new_s3 = 0;
  
   OCR0B = 0;//Valeur de comparaison pour B --> PD5
+
   if ( s4 <= limit) new_s4 = 0.55 * limit;
 +
  else new_s4 = 0;
 +
  //Serial.print(new_s1); Serial.print(" "); Serial.print(new_s2); Serial.print(" "); Serial.print(new_s3); Serial.print(" "); Serial.print(new_s4); Serial.println();
 
}
 
}
 
+
//////////////////////////////////////////////////////////////////
void sei_interruption()
+
//////////////////////////////////////////////////////////////////
 +
//Movement Intégrateur
 +
//////////////////////////////////////////////////////////////////
 +
//////////////////////////////////////////////////////////////////
 +
void go()
 
{
 
{
   sei(); //Autorisation global d'interruptions
+
   sensorRead();
 +
  robot_movement();
 +
  int leftSpeed  = ;
 +
  int rightSpeed = ;
 +
/*
 +
    int leftSpeed  = constrain(180 + posX / 2.0 - 80 - size_balle /256  , 110, 200);
 +
    int rightSpeed = constrain(180 - posX / 2.0 + 80 - size_balle /256  , 110, 200);
 +
    setSpeed(leftSpeed, rightSpeed);*/
 +
    //Serial.print(leftSpeed); Serial.print("  ");Serial.print(rightSpeed);Serial.println();
 +
    int speedL = constrain(180 + new_s1 - new_s2 - new_s3 - new_s4 + posX / 2.0 - 80 - size_balle /256, -180, 200);
 +
    int speedR = constrain(180 - new_s1 - new_s2 - new_s3 + new_s4 - posX / 2.0 + 80 - size_balle /256, -180, 200);
 +
    //Serial.print(speedL);Serial.print(" ");Serial.print(speedR);Serial.println();
 +
    setSpeed(speedL, speedR);
 
}
 
}
  
ISR(INT0_vect)
+
//////////////////////////////////////////////////////////////////
{
+
//////////////////////////////////////////////////////////////////
  //Sur chaque roue nous avons un emeteur et deux recepteurs, ces deux seront lu sur le pate PD2 et PB0
+
// Set servos
  uint8_t Pin2 = PIND & (1 << PD2); //INTERRUPTION INT0 sur PD2
+
//////////////////////////////////////////////////////////////////
  uint8_t Pin8 = PINB & (1 << PB0);
+
//////////////////////////////////////////////////////////////////
 
 
  if (Pin2 != 0)
 
  {
 
    if (Pin8 == 0) NbDentsD++;//Si la roue droit avance dont on aditionne le dents
 
    else NbDentsD--;//sinon on soustrait les dents, car cela signifie que le roue est en arrière
 
  }
 
  else if (Pin2 == 0)
 
  {
 
    if (Pin8 != 0) NbDentsD++;
 
    else NbDentsD--;
 
  }
 
}
 
  
ISR(INT1_vect)
+
void setServo()
 
{
 
{
   uint8_t Pin3 = PIND & (1 << PD3); //INTERRUPTION INT1 sur PD3
+
   ball_pixy.attach(27);
   uint8_t Pin9 = PINB & (1 << PB1);
+
   ball.attach(32);
 
+
   arm.attach(25);
  if (Pin3 != 0)
 
  {
 
    if (Pin9 == 0) NbDentsG++;//Si la roue gauge avance dont on aditionne le dents
 
    else {
 
      NbDentsG--;//sinon on soustrait les dents, car cela signifie que le roue est en arrière
 
    }
 
  }
 
  else if (Pin3 == 0)
 
   {
 
    if (Pin9 != 0) NbDentsG++;
 
    else {
 
      NbDentsG--;
 
    }
 
  }
 
 
}
 
}
 
+
int inte = 0;
ISR(TIMER1_COMPA_vect)
+
void setup()
 
{
 
{
   newCalc = true;
+
   pinMode(33, INPUT_PULLUP);
}
+
  timer_90s();                //timer 90sec
 +
  initMotor();              //set Motors
 +
  Wire.begin();              //connection I2C
 +
  //Serial1.begin(9600);
 +
  configAddress();
 +
  setServo();
 +
  sei();                      //timer1
 +
  //Serial1.print("Start...");
  
void setMoteurG(int16_t vit)//fontion pour gener le moteur gauge
+
   setCameras();               //déclaration des cameras Balles et Direction
{
 
   if (vit < 0)
 
  {
 
    vit = -vit;
 
    PORTD |= (1 << PD4);//Moteur Gauge en arrière
 
  }
 
  else PORTD &= ~ (1 << PD4);//Moteur Gauge en avant
 
 
 
  if (vit > topPWM) vit = topPWM;//Si jamais on met une vauleur superior a 255, la vitesse maximun sera 255
 
 
 
  OCR0B = vit;//Action sur le PWM --> PD5
 
}
 
  
void setMoteurD(int16_t vit)//fontion pour gener le moteur droit
+
  pinMode(sensor_ball, INPUT);
{
+
  //Commande de transitors MOSFET
   if (vit < 0)
+
   pinMode(Eject_ball, OUTPUT);
   {
+
   pinMode(Eject_cloth, OUTPUT);
    vit = -vit;
+
   pinMode(Explode_balloons, OUTPUT);
    PORTD |= (1 << PD7);//Moteur Droite en arrière
 
   }
 
  else PORTD &= ~ (1 << PD7);//Moteur Droite en avant
 
  
   if (vit > topPWM) vit = topPWM;//Si jamais on met une vauleur superior a 255, la vitesse maximun sera 255
+
   ball.write(4); // etat Initialize
 
+
  arm.write(100);
   OCR0A = vit;//Action sur le PWM --> PD6
+
  ball_pixy.write(130);
 +
  while(inte == 0)inte = digitalRead(33);
 +
   start = true;
 
}
 
}
  
void setVitesse(int16_t vG, int16_t vD)//cette fontion nous permet gerer les deux moteurs avec "une seule" ligne
+
void loop()
 
{
 
{
  setMoteurD(vD);
 
  setMoteurG(vG);
 
}
 
  
int main()
 
{
 
  int0();//Interruption 0
 
  int1();//Interruption 1
 
  timer1();//Timer 1
 
  initMoteur();//PWM
 
  sei_interruption();//Autorisation d'interruptions
 
  
   while (1)//Boucle infinie
+
   if (start)
 
   {
 
   {
     if (newCalc == true)
+
    Pixy_tracking();
 +
     if (timer <= 70 && signature == 1)
 
     {
 
     {
       Delta_D = (NbDentsD * Delta_Dent);//pas de la roue droit à chaque declanchement du TIMER 1.
+
       go();
      Delta_G = (NbDentsG * Delta_Dent); //pas de la roue gauge à chaque declanchement du TIMER 1.
+
      int mes_sensor_ball = analogRead(sensor_ball);
 +
      if (mes_sensor_ball >= 430)
 +
      {
 +
        ball.write(53); // on attrape la balle
 +
        caught_ball = true; //on a une balle dans
 +
      }
 +
      while (caught_ball) //mesure du capteur des balles
 +
      {
 +
        setSpeed(0, 0);
 +
        if(balise)
 +
        {
 +
        if (panLoop.m_pos > 750L)
 +
        {
 +
          setSpeed(180, 0);
 +
          delay(1000);
 +
          setSpeed(0, 0);
 +
          ball.write(4); // On enleve le bras qui attrapait la balle
 +
          delay(250);  //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
 +
          digitalWrite(Eject_ball, HIGH); //on tire la balle
 +
          delay(10);
 +
          digitalWrite(Eject_ball, LOW);
 +
          caught_ball = false;
 +
        }
 +
        else if (panLoop.m_pos < 250L)
 +
        {
  
      NbDentsG = 0;//Remise à zéro à chaque declanchement du TIMER 1.
+
        setSpeed(180, 0);
      NbDentsD = 0;//Remise à zéro sà chaque declanchement du TIMER 1.
+
        delay(1000);
 
+
        setSpeed(0, 0);
      Delta_moy = (1 / 2.0) * (Delta_D + Delta_G);//pas du robot à chaque declanchement du TIMER 1.
+
        ball.write(4); // On enleve le bras qui attrapait la balle
      Delta_dif = Delta_D - Delta_G;
+
        delay(250); //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
       Delta_teta = Delta_dif / L;//Calcul de Delta_teta en rad à chaque declanchement du TIMER 1.
+
        digitalWrite(Eject_ball, HIGH); //on tire la balle
 
+
        delay(10);
      Delta_X = Delta_moy * cos(Teta_precedent);//pas sur X du deplacement du robot à chaque declanchement du TIMER 1.
+
        digitalWrite(Eject_ball, LOW);
      Delta_Y = Delta_moy * sin(Teta_precedent);//pas sur Y du deplacement du robot à chaque declanchement du TIMER 1.
+
        caught_ball = false;
 
+
       }
       Teta = Teta_precedent + Delta_teta;//Angle de desviation par rapport à l'axe X du robot.
+
        else
      Teta_precedent = Teta;//Angle de desviation precedent par rapport à l'axe X du robot.
+
        {
 
+
          ball.write(4); // On enleve le bras qui attrapait la balle
      Position_X = Position_X_precendent + Delta_X;//Potition actuelle du robot en X
+
          delay(250); //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
      Position_X_precendent = Position_X;//Position precedente du robot en X
+
          digitalWrite(Eject_ball, HIGH); //on tire la balle
 
+
          delay(10);
      Position_Y = Position_Y_precendent + Delta_Y;//Potition actuelle du robot en Y
+
          digitalWrite(Eject_ball, LOW);
       Position_Y_precendent = Position_Y;//Position precedente du robot en Y
+
          caught_ball = false;
 
+
        }
       Vmax = 250;//valeur maximun qu'on impose aux moteurs
+
      }
 
+
      else
      setVitesse(Vmax * cos(Teta + PI / 4.0), Vmax * sin(Teta + PI / 4.0));
+
       {
 
+
        setSpeed(200, 0);
       newCalc = false;
+
        delay(2000); //delay necessaire pour faire une demi tour
 +
        setSpeed(0, 0);
 +
        ball.write(4); // On enleve le bras qui attrapait la balle
 +
        delay(250); //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
 +
        digitalWrite(Eject_ball, HIGH); //on tire la balle
 +
        delay(10);
 +
        digitalWrite(Eject_ball, LOW);
 +
        caught_ball = false;
 +
       }
 +
      }
 +
    }
 +
    else if (timer > 70 && signature == 2)
 +
    {
 +
      ball_pixy.write(53);   //valor pour laisser de voir des balles et commencer à voir les balloons
 +
      go();
 +
       if(size_max_balle >= 456) //determiné cette Valeur
 +
      {
 +
        setSpeed(0,0); //arret du robot_movement
 +
        arm.write(170); //mettre en position le servos
 +
        digitalWrite(Explode_balloons, HIGH);
 +
        delay(10);
 +
        digitalWrite(Explode_balloons, LOW);
 +
        arm.write(100); //mettre en position le servos
 +
       }
 
     }
 
     }
 +
    else if (timer >= 90){setSpeed(0, 0); while(true);// Au bout de 90sec on arrete le jeu :)}
 
   }
 
   }
 +
  else setSpeed(0, 0);// Arrêté avant de commencer
 
}
 
}
 
 
 
</source>
 
</source>
 
{{boîte déroulante/fin}}
 
{{boîte déroulante/fin}}
  
==={{Bleu|Suivons une consigne}}===
+
<big>Liens vers la compétition de l'année passée : </big>[[RobotGEII 16-17]]
 
 
Cette fois nous pourrons donner une valeur en X ey Y et le robot sera capable d'arriver au point et s'arreté. La valeurs doit etre donnée en cm.
 
 
 
{{boîte déroulante/début|titre=ws2812_config.h}}
 
<source lang=c>
 
 
 
//Code precedente (suivons un ligne)
 
 
 
int main()
 
{
 
  //Configurations
 
 
 
  while (1)//Boucle infinie
 
  {
 
    if (newCalc == true)
 
    {
 
     
 
    //Calculs
 
 
 
      X_consigne = 100;//valeur donné en cm
 
      Y_consigne = 50;//valeur donné en cm
 
      Teta_consigne = atan((Y_consigne - Position_Y / 50.0) / (X_consigne - Position_X / 50.0)) - Teta;//Nous divisons par 50 pour avoir les valeur en cm
 
 
 
      Vmax = 250;//valeur maximun qu'on impose aux moteurs
 
 
 
      setVitesse(Vmax * cos(Teta_consigne + PI / 4.0), Vmax * sin(Teta_consigne + PI / 4.0));
 
 
 
      newCalc = false;
 
    }
 
  }
 
}
 

Version actuelle datée du 20 juin 2018 à 19:31

Le wiki est actuellement en rédaction, certaines parties sont donc partiellement rédigées ou incomplètes.

COUPE ROBOTIQUE 2018


Maus.png


Introduction

Pour la deuxième fois consécutive l'IUT de Troyes auxquelles nous appartenons va participé à la Coupe de France Robotique des Iut qui se déroule chaque années du Jeudi 9 au samedi 11 Juin lors du Festival de Robotique dans la ville de Cachan. L'année dernière le But de la Coupe étais de se déplacé d'un point A à un point B en évitant des obstacles. Cette année l'objectif est radicalement différent puisqu'il s'agit de joué au Tennis ! Nous avons donc développé un robot répondant à une problématique et à un cahier des charges bien précis fixé par les organisateurs de la coupe. Je vous invite à consulté le règlement afin de bien comprendre le principe de la coupe de cette année.
Vous pouvez retrouvé ce règlement ici
Cette année nous devons donc joué au tennis, voici donc un bref résumé du déroulement de la coupe :

-Deux robots se font face sur un terrain de Tennis de dimension 8*4 m.
-Chaque robot à sur sont terrains un certain nombre de balles de Tennis par terre.
-Le centre de la piste est délimité par une ligne.
-Il y a deux ballons de chaque côtés des deux camps leurs explosions déclenche un surplus de balle dans le camp adverse.
-Un match dure 90 secondes.
-A la fin des 90 secondes l'envoi d'un projectile autre qu'une balle dans le camps adverses ajoute une balle supplémentaires dans le terrain adverses. Il Faut donc avoir le moins de balles possibles dans sont camps à la fin de la partie.
Voici un aperçu du terrain:

Terrain concour.PNG



Etudes

Il y a donc de nombreux But à atteindre, nous avons donc à l'aide d'un diagramme fonctionnelle décomposé tous ces Buts en Tâches à effectuées:

Analyse fonctionnelle.PNG

Cela nous à permis de définir les tâches que le robot doit effectué et les solutions techniques associées :
-Se déplacé => Deux moteurs commandés par un micro controleur Atmega 2560 via un pont en H l298n.
-Détecté les balles de Tennis => Première Caméra Pixy.
-Détecté la balise pour orienté le robot => Seconde Caméra Pixy.
-orientation de la deuxième caméra pixy => Moteur pas à pas.
-Détecté la proximité avec la balle et l'attrapée => Capteur de distance SHARP et Bras préhenseur.
-Propulsé la balle dans le camps adverse => Verrin.
-Atteindre les ballons situés en bordure du terrain => Bras rotatif.
-Faire éclaté les ballons en bordure du terrain => Arc électrique supporté par le bras rotatif nommé précédemment.
-Détecté les délimitations centrale du terrain => Capteur Cny70.
-Détecté la proximité avec les parois du terrain => Capteurs temps de vols.


Principe de fonctionnement

Comme nous l'avons vus précédemment il y a de nombreuses taches à effectuées, elles doivent toutes êtres réalisées en synchronisme cela implique un fonctionnement assez complexe que je vais vous expliquer.
Tous d'abord la direction, comment le robot se dirige t'il ? Le robot doit repérer les balles et les attrapées, pour ce faire la caméra pixy située à l'avant du robot va repérer les balles, selon la position de la balle dans le champ de vision de la caméra, c'elle si va renvoyé des informations à notre microcontrôleur. Le programme que contient le microcontrôleur va commandé les moteurs dans le but de maintenir la balle au centre du champs de vision de la caméra. Il va également tâché de faire grossir la balle dans l'objectif de la caméra, c'est à dire ce rapprocher de la balle. Une fois la balle arrivée à une certaine distance de la caméra (la balle remplis quasiment l'objectif de la caméra) un capteur de distance infrarouge Sharp va détecter la présence de la balle à l'endroit voulus, le bras va ensuite ce refermer pour "capturé" la balle. Pendant toutes cette période la deuxième caméra Pixy n'est pas restée inactive, en effet pendant ce temps elle fixe en permanence une balise émettant une lumière rouge que nous avons préalablement posé en fin de piste c'est à dire à l'arrière de notre camps. Nous pouvons donc déterminé en fonction des mouvements que notre deuxième caméra pixy à effectué ou se situe l'arrière de notre terrain. Nous pouvons donc déterminé la direction dans laquelle notre robot doit envoyé la balle !


Realisation


PREMIER PROTOTYPE


Proto1.jpg

Les différents éléments


Nous avons choisi de concevoir un chassi qui pourrais accueillir tous nos composants, nous ne savions pas à ce moment la leurs dimensionnement. Nous avons donc découpé en fonction du besoins des plaques de plastiques que nous avons assemblé.
Vous pouvez voir dans la photo précédente le robot complètement assemblé.
Ce robot ce déplace grâce à deux moteur fournis par les organisateurs de la coupe.
Ce sont deux moteurs Dunkermotoren G 42*25 qui permettent au robot de se mouvoir, vous pourrez retrouvé toutes leurs caractéristiques techniques ici
Ces moteurs et l'intégralités des dispositifs du robot sont alimentés par une batterie également définie par les organisateur de la coupe : C'est une batterie 12 V avec une capacité de 7 Ah.

Déplacement:
Ces deux moteurs sont donc contrôlés par un pont en H l298n, vous pourrez trouvez toutes les informations utiles concernant ce composant ici Ce composant serras placé sur la carte principale du robot, en effet au lieu de faire une carte pour la gestion des moteurs, une autre pour la gestion des caméras etc nous avons choisi de tous centralisé sur un seul shield d'une arduino mega. Vous pouvez également distingué sur le Robot les deux caméras Pixys, une à l'avant, une autre à l'arrière pour la détection de la Balle, une description plus précise des Pixys serras faites plus en Avale en effet elles seront abordés dans la partie traitant du second prototype. Vous pouvez voir également à l'avant du Robot le bras servant à attrapé la balle.
Ce bras à été imprimé à l'aide de l'imprimante 3D de l'Iut, il épouse parfaitement les dimensions de la balle, une version améliorée de ce bras à été fabriqué pour le deuxième prototype. Ce bras à été réalisé à l'aide d'une logiciel Freecad, ce logiciel libre est facile à prendre en mains c'est pour cela que nous l'avons préférés à Solydworks (même si les futures pièces seront surement faites à l'aide de ce dernier logiciel). Pour crée cette pièce nous avons crée une esquisse 2D puis à l'aide de protusion et de perçage nous obtenons une pièce en 3 dimensions. Il suffit ensuite de l'exporter sous un fichier "MESH" que l'imprimante 3D peux lire. Il existe ensuite plusieurs logiciels pouvant lire ce fichier, pour notre part nous disposions de deux imprimantes, les pièces les plus petites ont été réalisées à l'aide du logiciel Repetier Host et de l'imprimante 3D microDelta original et les pièces les plus grandes ont été réalisées grâce au logiciel Cura et à l'imprimante 3D Witbox
Bras préhenseur:

Bras préhension balle.PNG

Les capteurs Cny70:
Ces capteurs à pour but de détecter le milieu du terrain en effet notre robot n'as pas à empiéter sur le terrain de l'adversaire, nous avons donc conçu des petites cartes avec le capteurs et ce qui est nécessaire à sont fonctionnement dessus, seul bé mole nous allons devoirs inclinés les Cny en effet notre robot ne doit pas dépasser la ligne, nous devons donc la détecté à l'avance. Encore une fois si vous avez besoins de précision concernant ce photo transistor suivez ce lien : ici
Le moteur Pas à Pas

Dans ce projet, on a voulu mettre un moteur pas à pas pour la rotation de la caméra pixy derrière afin de pouvoir tourner à 360° en effet les servos moteurs présent sur la caméra pixy ne nous permettent de tournés seulement à 180°. On a donc utilisé un contrôleur de moteur pas à pas TCA 3727.


Pins TCA 3727.png


Le câblage du contrôleur TCA 3727 se trouve ci-dessous.

Cablâge moteur pas à pas.png

On peut commander le moteur en mode Full Step ou Half Step en envoyant des signaux à des entreés I10 I11 I20 I21. Exemple du full step :

Mode full step.png




Le générateur d'arc électriques
Il est invisible ici car il est situé à l'intérieur du robot, ce petit générateur produit des petits arcs électriques en ionisant l'air, il est commandé par un transistor Mosfet type N. Nous avons mesuré qu'il consomme au maximum de sont fonctionnement jusqu’à 3 Ampère, en effet plus l'arc électrique est grand plus la consommation de courant est grande. Après avoir effectué plusieurs tests nous en avons conclus que cette arc électrique étais suffisant pour faire éclater un ballon.

Les capteurs temps de vols

Nous allons être amené à nous déplacé sur le terrain , il nous faut donc pouvoir en détecter les limites, comme nous l'avons déjà vus nous avons les Cny pour repérer la ligne délimitant le milieu du terrain mais nous avons aussi besoins de capteurs capables de détecter les rebords du terrain. Pour ce faire nous utiliserons des capteurs temps de vols VL53L0X. Vous pourrez trouvez toutes les informations concernant ce capteur. ici

Capteurs VL53L0X.jpg


Le système pneumatique
Pour propulsé la balle nous utiliserons donc un vérin, nous utiliserons un vérin mis à disposition par notre enseignant. Ce vérin à besoins pour fonctionner d'une réserve d'air comprimée, ne pouvant évidement pas monté un compresseur sur notre petit robot nous utiliserons des cartouches de co2 de 12 G avec tige filetée, elles ont l'avantages non négligeable d'être facilement transportable. Nous commanderons le fonctionnement de notre vérin à l'aide d'une électrovanne également fournie par notre enseignant, nous sommes actuellement à la recherche d’électrovannes plus petites. Voici quelques photos du système pneumatique :

On peut voir le régulateur de pression à l'arrière du robot et le vérin démonté :
Regulateur pression vérin.jpg

Sur cette photo l'on peut voir l'ensemble du système pneumatique câblé, nous avons donc notre électrovanne commandé par la carte via un survolteur 12 -> 24V. Notre électrovanne est notre interrupteur dans notre circuit pneumatique.

Electrovanne.jpg



Le shield arduino mega

Pour commandé tous ces actionneurs que ce soit les moteurs ou les bras servants à percés les ballons ou à attrapé les balles, ainsi que pour centralisé et réagir aux informations fournis par nos nombreux capteurs nous avons besoins d'un micro contrôleur avec un nombre de pattes et un nombre de timers important. Nous avons donc choisi le micro contrôleur Atmega 2560. En effet il réponds parfaitement à nos attentes, cependant nous devons également mettre en oeuvre un pont en H et plusieurs transistors mosfet qui ne sont pas présent sur la carte arduino Mega. Nous allons donc créée un shield à cette carte. Le shield le voici :

CarteV1.jpg
Carte V1.png




C'est le premier shield que nous avons réalisés cependant nous avons rencontrés de nombreuses difficultés lors de sa fabrication, ces difficultés sont principalement du à un routage qui n’étais pas optimum, de très nombreux via ainsi que des piste dont la disposition ne facilitais pas le routage. Par exemple certains composants rendaient difficile le soudage des autres notamment à cause du manque de place. Cela rajouté à des erreurs de soudures ont rendus les essais de fonctionnements de cette cartes très laborieux. Finalement après une semaine à essayer de faire fonctionné correctement cette carte en vain nous avons décidé de fabriqué une version améliorée de celle si.
Voici donc la version corrigée de ce premier shield, le routage à été simplifié autant que possible, des nombreuses erreurs ont été corrigés et la disposition des pistes à été optimisé autant que possible. Nous avons également abordé la fabrication d'une manière différente en tirant les enseignement des erreurs de fabrication du premier shield. Par exemple nous avons soudé les composants traversants dans un ordre bien précis pour ne pas être gêner lors du soudage de ceux de l'un ou de l'autre. Voici donc le routage finale :

CarteV3.png

Et voici la carte fabriqué :

CarteV2.jpg

La carte principale finale

Après avoir testé et utilisé le shield arduino fabriqué pour le premier prototype, il existait toujours des problèmes qui provoquaient un mauvais fonctionnement du robot. De plus, on voulait ajouter certains composants afin d’améliorer notre robot. Pour ce faire, on a décidé de créer une carte principale en utilisant le micro-contrôleur ATMEGAG 2560 qui se trouve sur la carte Arduino MEGA pour fabriquer une carte qui est à la fois plus compatible et a beaucoup plus de places dans le but d’installer les autres dispositifs nécessaires (module XBEE, les transistors, etc). Cette carte a été fabriquée en tirant les enseignements des erreurs de fabrication des cartes précédente et le routage est optimisé le plus possible pour avoir une carte de qualité et facile à dépanner et tester. Les entrées/sorties non utilisées sont aussi reliées à des connecteurs MOLEX pour un ajout complémentaire des modules en tant que les capteurs, les modules supplémentaires dans le futur sans le besoin de refabriquer une nouvelle carte. Par contre, lors de la fabrication de cette carte principale, on a eu aussi pas mal de problème avec la mise en place du micro -contrôleur sur la carte.

Voici le routage de la carte :

Board BOT+TOP.PNG



Et voici la carte finie:

Carte principale.jpg




Modèle:Thor tank lors de la coupe robotique
Thor tank troyes.jpg


SECOND PROTOTYPE

Le Chassi en PLA

Nous avons décidé à la suite de la réalisation du premier prototype de tenir compte au maximum des nécessité techniques que devais remplir le chassi, nous avons donc crée un châssi robuste en PLA sur lequel chacun des actionneurs serait fixé rapidement. Nous l'avons dessiné sur Freecad et fabriqué à l'aide de l'imprimante 3D de l'iut. Il y a eu 3 versions différentes du châssi tous au long du projet voici donc quelques photos du chassi le plus récent une fois terminé : Sur freecad :

Chassi vue Supérieure.PNG

Et enfin imprimé :

Chassi.jpg
Tourelle assemblée.jpg


Les deux caméras pixy
Pixy à l'avant

La caméra Pixy est une caméra intelligente laquelle, principalement, fait un traitement d'images des objets qu'on garde dans leur mémoire. Cette caméra nous donne différentes informations telles que: les coordonnées X, Y du centre de l'objet, la largeur ainsi que la hauteur du carreau autour l'objet, la quantité d'objets détectés et leurs couleurs parmi des autres données. Vous pouvez avoir plus d'information ici http://www.cmucam.org/projects/cmucam5/wiki/Arduino_API

Pour ce projet on utilise deux caméras : La caméra positionnée devant du robot sera qui détecte les balles, également les deux ballons à coté du terrain et celle qui est derrière sera capable de nous donner l’angle entre la direction du robot et l’arrière du terrain. Cette dernière donnée nous aidera à envoyer les balles vers la direction correcte!

Pixy à l'arrière

Pour la première caméra, elle est monté à l’inverse(important pour la programmation puisque cela change l’orientation de l’axe X!) avec qu’un seul servomoteur qui contrôle le mouvement en l’axe Y. Ce mouvement est fait simplement, tout d’abord pour la détection des balles du sol et après pour la détection des ballons. Pourtant, la deuxième est montée sur deux servomoteurs qui contrôle le mouvement dans les deux axes. Il se trouve que si le robot est près de la balise on risque de la perdre, c’est pour cela qu’on utilise le mouvement en Y.

La carte principale

CODE

codeRobot

/*
  Program challenge "Coupe Robotique des IUT 2018"
  IUT de Troyes
  June - 2018
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <Wire.h>
#include <SPI.h>
#include <PixySPI_SS.h>
#include "Adafruit_VL53L0X.h"
#include <ServoTimer2.h>


#define topPWM            255       //Valeur Max du PWM Motors (8bits)
#define X_center          160     //PixyBalls consigne
#define sensor_ball        0   //sensor ball

#define S1                 1   //CNY70 left1
#define S2                 2   //CNY70 right1
#define S3                 3   //CNY70 left2
#define S4                 4   //CNY70 right2

#define PixyBalls         22   // camera for detect balls
#define PixyDirection     23   // camera for the direction of the robot

#define Eject_ball        36   // Eject ball
#define Eject_cloth       38   // Eject cloth (pas utilisé)
#define Explode_balloons  34   // set servo to explode balloons
//servos Pixy direction
#define X_CENTER        ((PIXY_MAX_X-PIXY_MIN_X)/2)
#define Y_CENTER        ((PIXY_MAX_Y-PIXY_MIN_Y)/2)



const int limit = 90;
bool start = false;
bool balise = false;

int s1 = 0;
int s2 = 0;
int s3 = 0;
int s4 = 0;
float new_s1 = 0;
float new_s2 = 0;
float new_s3 = 0;
float new_s4 = 0;

int signature = 0;
int timer = 0;
int16_t size_max_balle = 0;
int16_t size_max_ballon = 0;
int16_t size = 0;
bool caught_ball = false;
//Cameras
PixySPI_SS pixy1(PixyBalls);
PixySPI_SS pixy2(PixyDirection);


//Capteurs temps de vol
Adafruit_VL53L0X sensor1 = Adafruit_VL53L0X();
Adafruit_VL53L0X sensor2 = Adafruit_VL53L0X();
Adafruit_VL53L0X sensor3 = Adafruit_VL53L0X();
Adafruit_VL53L0X sensor4 = Adafruit_VL53L0X();
//Servomoteurs
ServoTimer2 ball;    // servo to catch balls
ServoTimer2 arm;     // servo to move the arm to explode balloons
ServoTimer2 ball_pixy;
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// Pantilt camera direction
///////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
class ServoLoop
{
  public:
    ServoLoop(int32_t pgain, int32_t dgain);

    void update(int32_t error);

    int32_t m_pos;
    int32_t m_prevError;
    int32_t m_pgain;
    int32_t m_dgain;
};


ServoLoop panLoop(300, 500);
ServoLoop tiltLoop(500, 700);

ServoLoop::ServoLoop(int32_t pgain, int32_t dgain)
{
  m_pos = PIXY_RCS_CENTER_POS;
  m_pgain = pgain;
  m_dgain = dgain;
  m_prevError = 0x80000000L;
}

void ServoLoop::update(int32_t error)
{
  long int vel;
  char buf[32];
  if (m_prevError != 0x80000000)
  {
    vel = (error * m_pgain + (error - m_prevError) * m_dgain) >> 10;
    //sprintf(buf, "%ld\n", vel);
    //Serial.print(buf);
    m_pos += vel;
    if (m_pos > PIXY_RCS_MAX_POS)
      m_pos = PIXY_RCS_MAX_POS;
    else if (m_pos < PIXY_RCS_MIN_POS)
      m_pos = PIXY_RCS_MIN_POS;
  }
  m_prevError = error;
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// PixyDirection
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
void direction()
{

  uint16_t blocks;
  int32_t panError, tiltError;

  blocks = pixy2.getBlocks();

  if (blocks)
  {
    panError = X_CENTER - pixy2.blocks[0].x;
    tiltError = pixy2.blocks[0].y - Y_CENTER;

    panLoop.update(panError);
    tiltLoop.update(tiltError);

    pixy2.setServos(panLoop.m_pos, tiltLoop.m_pos);
a    balise = true; //balise detectee
  }
  else balise = false;
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//SetMotors
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void initMotor()//PWM on PE3 (Left) and PH3(Right)
{
  //fpwm = fq / (topPWM * p)
  //fpwmi: frequency PWM
  //fq: frequency quartz
  //topPWM: value max PWM
  //p: predivisor

  //Declaration de sorties
  DDRB |= (1 << PB6);//Sense motor left     12   in1
  DDRB |= (1 << PB5);//Sense motor left     11  in2
  DDRH |= (1 << PH3);//PWM motor left OC4A  6   enA
  DDRH |= (1 << PH4);//Sense motor right    7   in3
  DDRB |= (1 << PB4);//Sense motor right    10   in4
  DDRH |= (1 << PH5);//PWM motor right OC4C 8   enB


  //Timer4 PH3

  TCCR4A |= (1 << WGM40);//Mode FAST PWM
  TCCR4B |= (1 << WGM42);

  TCCR4B |= (1 << CS40) | (1 << CS41);//divisor P=64


  TCCR4A |= 1 << COM4A1;//PWM on OC4A

  TCCR4A |= 1 << COM4C1;//PWM on OC4C

  OCR4A = 0;//Value first comparison  --> PH3

  OCR4C = 0;//Value first comparison --> PH5
}


void setMotorL(int16_t speed)//function motor left
{
  if (speed < 0)
  {
    speed = -speed;
    PORTB |= (1 << PB6);//Motor left : sense "-"
    PORTB &= ~ (1 << PB5);
  }
  else {
    PORTB &= ~ (1 << PB6);//Motor left : sense "+"
    PORTB |= (1 << PB5);
  }
  if (speed > topPWM) speed = topPWM;//speed max

  OCR4A = speed;//Action sur le PWM --> PE3
}

void setMotorR(int16_t speed)//function motor right
{
  if (speed < 0)
  {
    speed = -speed;
    PORTH &= ~ (1 << PH4); //Motor right : sense "-"
    PORTB |=  (1 << PB4);
  }
  else
  {
    PORTH |= (1 << PH4); //Motor left : sense "+"
    PORTB &= ~ (1 << PB4);
  }

  if (speed > topPWM) speed = topPWM;//speed max

  OCR4C = speed;//Action sur le PWM --> PH3
}

void setSpeed(int16_t vL, int16_t vR)//only one function for 2 motors
{
  setMotorL(vL);
  setMotorR(vR);
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// play time = 90s
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void timer_90s()
{
  //Tt1=(n*p)/fq
  //n=Tt1*fq/p
  //Tt1: periode du timer
  //n=valuer de comparaison (OCR1A)
  //p:prediviseur
  //fq:frequence du quark (arduino Mega 16Mhz)

  TCCR1B |= (1 << CS10) | (1 << CS12); //p=1024

  TCCR1B |= 1 << WGM12; //RAZ mode CTC

  TIMSK1 |= 1 << OCIE1A; //Autorisation d'interruption de comparaison A

  OCR1A = 15625; //Comparaison , Tt1=1s,
}

ISR(TIMER1_COMPA_vect)
{
  timer++;
  //PORTB^=1<<PB7; activar verin para la tela blanca
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// setCameras
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void setCameras() {

  //pixy2.init();
  pinMode(PixyBalls, OUTPUT); // Slave output PixyBalls
  pinMode(PixyDirection, OUTPUT); // Slave output PixyDirection

  digitalWrite(PixyBalls, HIGH); // desactivation PixyBalls
  digitalWrite(PixyBalls, HIGH); // desactivation PixyDirection

  pixy1.init();
  pixy2.init();

}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// PixyBalls
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void Pixy_tracking() {
  int signature = 0;

  //unsigned int16_t size_max_balle = 0;
  //unsigned int16_t size_max_ballon = 0;
  uint32_t size_balle = 0;
  uint16_t posX   = 0;
  //static int i = 0;
  int blocks;
  blocks     = pixy1.getBlocks();
  // grab blocks!
  if (blocks)
  {
    signature        = pixy1.blocks[0].signature;
    posX             = pixy1.blocks[0].x;
    size_balle       = pixy1.blocks[0].width; * pixy1.blocks[0].height;
  }
  /*else
  {
    posX = 0;
    size_balle = 0;
  }*/
  //Serial.println(sizeta /256)
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// Activation capteurs temps de vol protocol I2C
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void configAddress() {
  pinMode(44, OUTPUT);
  pinMode(45, OUTPUT);
  pinMode(46, OUTPUT);
  pinMode(47, OUTPUT);

  digitalWrite(47, HIGH);
  digitalWrite(46, LOW);
  digitalWrite(45, LOW);
  digitalWrite(44, LOW);
  sensor1.setAddress(30);
  sensor1.begin(30);
  delay(10);
//  Serial.println("1 device");

  digitalWrite(47, HIGH);
  digitalWrite(46, HIGH);
  digitalWrite(45, LOW);
  digitalWrite(44, LOW);
  sensor2.setAddress(31);
  sensor2.begin(31);
  delay(10);
//  Serial.println("2 device");

  digitalWrite(47, HIGH);
  digitalWrite(46, HIGH);
  digitalWrite(45, HIGH);
  digitalWrite(44, LOW);
  sensor3.setAddress(32);
  sensor3.begin(32);
  delay(10);
//Serial.println("3 device");

  digitalWrite(47, HIGH);
  digitalWrite(46, HIGH);
  digitalWrite(45, HIGH);
  digitalWrite(44, HIGH);
  sensor3.setAddress(32);
  sensor4.setAddress(33);
  sensor4.begin(33);
  delay(10);
  //Serial.println("4 device");
}

void sensorRead() {

  VL53L0X_RangingMeasurementData_t measure1; // mesure prope de la librairie
  VL53L0X_RangingMeasurementData_t measure2;
  VL53L0X_RangingMeasurementData_t measure3;
  VL53L0X_RangingMeasurementData_t measure4;

  sensor1.rangingTest(&measure1, false);
  sensor2.rangingTest(&measure2, false);
  sensor3.rangingTest(&measure3, false);
  sensor4.rangingTest(&measure4, false);

  s1 = measure1.RangeMilliMeter;
  //delay(30);
  s2 = measure2.RangeMilliMeter;
  //delay(30);
  s3 = measure3.RangeMilliMeter;
  //delay(30);
  s4 = measure4.RangeMilliMeter;
  delay(30);  // mesure rapide, on a des autres posibilitées
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// Détection des obstacles(limites du terrain)
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void robot_movement() {

  if ( s1 <= limit) new_s1 = 0.55 * limit; // détection de la limite du terrain
  else new_s1 = 0;

  if ( s2 <= limit) new_s2 = 3.2* limit;
  else new_s2 = 0;

  if ( s3 <= limit) new_s3 = 3.2* limit;
  else new_s3 = 0;

  if ( s4 <= limit) new_s4 = 0.55 * limit;
  else new_s4 = 0;
  //Serial.print(new_s1); Serial.print(" "); Serial.print(new_s2); Serial.print(" "); Serial.print(new_s3); Serial.print(" "); Serial.print(new_s4); Serial.println();
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//Movement Intégrateur
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void go()
{
  sensorRead();
  robot_movement();
  int leftSpeed  = ;
  int rightSpeed = ;
/*
    int leftSpeed  = constrain(180 + posX / 2.0 - 80 - size_balle /256  , 110, 200);
    int rightSpeed = constrain(180 - posX / 2.0 + 80 - size_balle /256  , 110, 200);
    setSpeed(leftSpeed, rightSpeed);*/
    //Serial.print(leftSpeed); Serial.print("   ");Serial.print(rightSpeed);Serial.println();
    int speedL = constrain(180 + new_s1 - new_s2 - new_s3 - new_s4 + posX / 2.0 - 80 - size_balle /256, -180, 200);
    int speedR = constrain(180 - new_s1 - new_s2 - new_s3 + new_s4 - posX / 2.0 + 80 - size_balle /256, -180, 200);
    //Serial.print(speedL);Serial.print(" ");Serial.print(speedR);Serial.println();
    setSpeed(speedL, speedR);
}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// Set servos
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

void setServo()
{
  ball_pixy.attach(27);
  ball.attach(32);
  arm.attach(25);
}
int inte = 0;
void setup()
{
  pinMode(33, INPUT_PULLUP);
  timer_90s();                //timer 90sec
  initMotor();               //set Motors
  Wire.begin();              //connection I2C
  //Serial1.begin(9600);
  configAddress();
  setServo();
  sei();                       //timer1
  //Serial1.print("Start...");

  setCameras();                //déclaration des cameras Balles et Direction

  pinMode(sensor_ball, INPUT);
  //Commande de transitors MOSFET
  pinMode(Eject_ball, OUTPUT);
  pinMode(Eject_cloth, OUTPUT);
  pinMode(Explode_balloons, OUTPUT);

  ball.write(4); // etat Initialize
  arm.write(100);
  ball_pixy.write(130);
  while(inte == 0)inte = digitalRead(33);
  start = true;
}

void loop()
{


  if (start)
  {
    Pixy_tracking();
    if (timer <= 70 && signature == 1)
    {
      go();
      int mes_sensor_ball = analogRead(sensor_ball);
      if (mes_sensor_ball >= 430)
      {
        ball.write(53); // on attrape la balle
        caught_ball = true; //on a une balle dans
      }
      while (caught_ball) //mesure du capteur des balles
      {
        setSpeed(0, 0);
        if(balise)
        {
        if (panLoop.m_pos > 750L)
        {
          setSpeed(180, 0);
          delay(1000);
          setSpeed(0, 0);
          ball.write(4); // On enleve le bras qui attrapait la balle
          delay(250);  //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
          digitalWrite(Eject_ball, HIGH); //on tire la balle
          delay(10);
          digitalWrite(Eject_ball, LOW);
          caught_ball = false;
        }
        else if (panLoop.m_pos < 250L)
        {

        setSpeed(180, 0);
        delay(1000);
        setSpeed(0, 0);
        ball.write(4); // On enleve le bras qui attrapait la balle
        delay(250);  //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
        digitalWrite(Eject_ball, HIGH); //on tire la balle
        delay(10);
        digitalWrite(Eject_ball, LOW);
        caught_ball = false;
      }
        else
        {
          ball.write(4); // On enleve le bras qui attrapait la balle
          delay(250);  //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
          digitalWrite(Eject_ball, HIGH); //on tire la balle
          delay(10);
          digitalWrite(Eject_ball, LOW);
          caught_ball = false;
        }
      }
      else
      {
        setSpeed(200, 0);
        delay(2000);  //delay necessaire pour faire une demi tour
        setSpeed(0, 0);
        ball.write(4); // On enleve le bras qui attrapait la balle
        delay(250);  //!!!!!!!!AAAATTTTEEEENNNTTTTIOOOOONNN!!!!! changer ce temps il faut le mesure
        digitalWrite(Eject_ball, HIGH); //on tire la balle
        delay(10);
        digitalWrite(Eject_ball, LOW);
        caught_ball = false;
      }
      }
    }
    else if (timer > 70 && signature == 2)
    {
      ball_pixy.write(53);   //valor pour laisser de voir des balles et commencer à voir les balloons
      go();
      if(size_max_balle >= 456) //determiné cette Valeur
      {
        setSpeed(0,0); //arret du robot_movement
        arm.write(170); //mettre en position le servos
        digitalWrite(Explode_balloons, HIGH);
        delay(10);
        digitalWrite(Explode_balloons, LOW);
        arm.write(100); //mettre en position le servos
      }
    }
    else if (timer >= 90){setSpeed(0, 0); while(true);// Au bout de 90sec on arrete le jeu :)}
  }
  else setSpeed(0, 0);// Arrêté avant de commencer
}

Liens vers la compétition de l'année passée : RobotGEII 16-17