ENIB 2024 : Le Cyclone Breton

De Les Fabriques du Ponant
Aller à : navigation, rechercher

Titre de la fiche expérience :

Description

Nous sommes 5 élèves ingénieurs de 3ème année à l'ENIB : Thomas Mauger, Gregory Jourdain, Benjamin Le Corre, Romaric Hubert, et Martin Candoni

Dans le cadre de l'inter-semestre 3 à l'ENIB, nous avons fait, lors d'un Hackathon, le jeu du cyclone (appelé ici "Le cyclone Breton").

Le but du jeu est d'appuyer sur le bouton quand la led verte (celle qui tourne autour du cercle) est au même endroit que la zone à atteindre (celle en rouge sur le cercle).

Il y a 5 niveaux différents, avec une musique de victoire et une musique de défaite.

Image

Le Cyclone Breton Fini.jpg

Outils et matériel

Outils :

- Fer à souder pour l’étain

- Scie

- Pistolet à colle

- Imprimante 3D (facultatif)

- Découpeuse laser (facultatif)

Matériel :

1 Arduino-Nano

1 Anneau WS2812 avec 60 LED

1 Bouton-poussoir

1 Transistor à usage général NPN

1 Plaque labdec*

25 fils électriques

1 Avertisseur sonore

2 Résistance 220 ohms

1 Résistance à trou traversant, 820 ohm

1 Batterie portable (5 Volts, 3 Ampères)

1 élastique

Bobine d'étain

Colle

Plaques de bois

Scotch

Plastique d'imprimante

Fichiers à joindre

Si vous voulez faire le même montage, voici les documents. C'est un .zip à télécharger et à extraire sur votre ordinateur. Fichier:Le Cyclone Breton.zip

Code Arduino

  1  
  2 //----------------------Variables----------------------
  3 
  4 #include "FastLED.h"
  5 #define NUM_LEDS 60 //on utilise 60 leds
  6 #define DATA_PIN A0
  7 #define SCORE_PIN 6
  8 #define SCORE_LEDS 6
  9 #define BRIGHTNESS 15 //luminosite de la led
 10 CRGB leds[NUM_LEDS]; //variable constante leds
 11 CRGB sleds[NUM_LEDS]; //variable constante score leds
 12 
 13 bool reachedEnd = false;
 14 
 15 byte gameState = 0; //niveau du jeu
 16 //byte ledSpeed = 0;
 17 int period = 1000;
 18 unsigned long time_now = 0;
 19 byte Position = 0; //position de la led
 20 byte level = 0;
 21 
 22 const byte ledSpeed[6] = {50, 40, 30, 20, 14, 7}; //differentes vitesses de la led rouge
 23 
 24 //Debounce
 25 bool findRandom = false; //Indique si une nouvelle position aléatoire doit être trouvée
 26 byte spot = 0; //On y stocke la position aleatoire
 27 
 28 //-----------------------------------------------------
 29 
 30 void setup() {
 31   // put your setup code here, to run once:
 32   FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS); //configure la bibliothèque FastLED pour utiliser des LEDs de type WS2812B (ou compatibles) avec la broche DATA_PIN. 
 33                                                            //Les LEDs sont déclarées dans le tableau leds et le nombre total de LEDs est spécifié par NUM_LEDS
 34 
 35   FastLED.addLeds<WS2812B, SCORE_PIN, GRB>(sleds, SCORE_LEDS);
 36   pinMode(A3, INPUT_PULLUP); //Configure la broche A3 en mode d'entrée avec résistance de tirage vers le haut (INPUT_PULLUP)
 37   Serial.begin(9600);// Initialise la communication série avec une vitesse de transmission de 9600 bauds. 
 38                      //Cela permet de communiquer avec le moniteur série de l'IDE Arduino pour déboguer et afficher des informations pendant l'exécution du programme.
 39   Serial.println("Reset"); //Envoie le message "Reset" via la communication série. 
 40                            //Cela peut être utile pour signaler le redémarrage du microcontrôleur ou pour des fins de débogage.
 41 }
 42 
 43 void loop() {
 44   // put your main code here, to run repeatedly:
 45   FastLED.setBrightness(BRIGHTNESS );
 46   if (gameState == 0) {
 47 
 48     fill_rainbow(leds, NUM_LEDS, 0, 20); //2 = longer gradient strip
 49     fill_rainbow(sleds, SCORE_LEDS, 0, 40); //2 = longer gradient strip
 50 
 51     if (digitalRead(A3) == LOW) { //on vient lire la broche A3, si c'est en LOW (bas), on exécute le code ci-dessous
 52       Position = 0;
 53       findRandom = true;
 54       delay(500); //fait une pause de 500 millisecondes
 55       for (byte i = 0; i < NUM_LEDS; i++) {
 56         leds[i].setRGB(0, 0, 0); //on eteint toutes les leds
 57         delay(40);
 58         FastLED.show(); //Met à jour l'affichage pour refléter les changements sur les leds.
 59        int thisPitch = map (i, 60, 0, 100, 1500); //Utilise la fonction map pour convertir la valeur de i d'une plage de 60 à 0 en une plage de 100 à 1500. Cette valeur est utilisée comme fréquence pour générer un ton.
 60        //tone(9, thisPitch,120); //Genere une note sur la broche 9, à la frequence thisPitch (en Hz) pendant 120 millisecondes
 61       }
 62       for (byte i = 0; i < SCORE_LEDS; i++) {
 63         sleds[i].setRGB(0, 0, 0); //eteindre toutes les leds de score 
 64         delay(100);
 65         FastLED.show(); 
 66       }
 67       gameState = 1; //passer au niveau 1
 68     }
 69     FastLED.show();
 70   }
 71   if (gameState == 1) {
 72     period = ledSpeed[0];
 73     if (millis() > time_now + period) {
 74       time_now = millis();
 75       if (findRandom) {
 76         spot = random(56) + 3;
 77         findRandom = false;
 78       }
 79       leds[spot - 1].setRGB(255, 140, 0);
 80       leds[spot].setRGB(0, 255, 0);
 81       leds[spot + 1].setRGB(255, 110, 0);
 82       sleds[0].setRGB(0, 255, 0);
 83       PlayGame(spot - 1, spot + 1);
 84     }
 85     if (digitalRead(A3) == LOW) {
 86       delay(300);
 87       findRandom = false;
 88       if (Position > spot - 1 && Position < spot + 3) {
 89         level = gameState;
 90         gameState = 98;
 91       } else {
 92         gameState = 99;
 93       }
 94     }
 95   }
 96   if (gameState == 2) {
 97 //    period = 320;
 98     period = ledSpeed[1];
 99     if (millis() > time_now + period) {
100       time_now = millis();
101       if (findRandom) {
102         spot = random(56) + 3;
103         findRandom = false;
104       }
105       leds[spot - 1].setRGB(255, 190, 0);
106       leds[spot].setRGB(0, 255, 0);
107       leds[spot + 1].setRGB(255, 190, 0);
108       sleds[1].setRGB(255, 255, 0);
109       PlayGame(spot - 1, spot + 1);
110     }
111     if (digitalRead(A3) == LOW) {
112       delay(300);
113       if (spot - 1 && Position < spot + 3) {
114         level = gameState;
115         gameState = 98;
116       } else {
117         gameState = 99;
118       }
119     }
120   }
121   if (gameState == 3) {
122     period = ledSpeed[2];
123     if (millis() > time_now + period) {
124       time_now = millis();
125       if (findRandom) {
126         spot = random(56) + 3;
127         findRandom = false;
128       }
129       leds[spot].setRGB(0, 255, 0);
130       sleds[2].setRGB(255, 50, 0);
131       PlayGame(spot, spot);
132     }
133     if (digitalRead(A3) == LOW) {
134       delay(300);
135       if (Position == spot+1) {
136         
137         level = gameState;
138         gameState = 98;
139       } else {
140         gameState = 99;
141       }
142     }
143   }
144   if (gameState == 4) {
145     period = ledSpeed[3];
146     if (millis() > time_now + period) {
147       time_now = millis();
148       if (findRandom) {
149         spot = random(56) + 3;
150         findRandom = false;
151       }
152       leds[spot].setRGB(0, 255, 0);
153       sleds[3].setRGB(255, 0, 0);
154       PlayGame(spot, spot);
155     }
156     if (digitalRead(A3) == LOW) {
157       delay(300);
158       if (Position == spot+1) {
159         level = gameState;
160         gameState = 98;
161       } else {
162         gameState = 99;
163       }
164     }
165   }
166 
167   if (gameState == 5) {
168     period = ledSpeed[4];
169     if (millis() > time_now + period) {
170       time_now = millis();
171       if (findRandom) {
172         spot = random(56) + 3;
173         findRandom = false;
174       }
175       leds[spot].setRGB(0, 255, 0);
176       sleds[4].setRGB(0, 150, 255);
177       PlayGame(spot , spot);
178     }
179     if (digitalRead(A3) == LOW) {
180       delay(300);
181       if (Position == spot+1) {
182         level = gameState;
183         gameState = 98;
184       } else {
185         gameState = 99;
186       }
187     }
188   }
189   
190   if (gameState == 98) {
191     winner();
192   }
193   if (gameState == 99) {
194     loser();
195   }
196 }
197 void PlayGame(byte bound1, byte bound2) {
198   leds[Position].setRGB(255, 0, 0); //Allume la LED à la position actuelle (Position) avec une couleur rouge
199   if (Position < bound1 + 1 || Position > bound2 + 1) { //Cette condition vérifie si la position actuelle est en dehors des limites spécifiées par bound1 et bound2. 
200                                                         //Si la position est inférieure à bound1 + 1 ou supérieure à bound2 + 1, cela signifie que la position actuelle est en dehors des limites permises
201     leds[Position - 1].setRGB(0, 0, 0);//Si la condition est vraie, alors cela signifie que la position a dépassé les limites, 
202                                        //et la LED à la position précédente (leds[Position - 1]) est éteinte en la mettant à la couleur noire (0, 0, 0)
203   }
204   FastLED.show();
205   Position++; //Passe à la position suivante
206   if (Position >= NUM_LEDS) { //Cette condition vérifie si la position a dépassé le nombre total de LEDs (NUM_LEDS). 
207                               //Si c'est le cas, cela signifie que la position a atteint la fin de la séquence de LEDs.
208     leds[Position - 1].setRGB(0, 0, 0); //Si la condition est vraie, alors la LED à la dernière position est éteinte (leds[Position - 1].setRGB(0, 0, 0)) en la mettant à la couleur noire,
209                                         //et la position est réinitialisée à 0 pour recommencer le jeu
210     Position = 0;
211   }
212 }
213 
214 void winner() { //fonction de victoire
215   win_sound(); //Final Fantasy 7  victoire
216   for (byte i = 0; i < 3; i++) {
217     for (byte j = 0; j < NUM_LEDS; j++) {
218       leds[j].setRGB(0, 255, 0); //on met toutes les leds en vert
219       
220       
221     }
222     FastLED.show();
223     delay(500);
224     clearLEDS();
225     FastLED.show();
226     delay(500);
227   
228   }
229   
230   findRandom = true;
231   Position = 0;
232 
233   gameState = level + 1;
234   if (gameState > 5) {
235     gameState = 0;
236   }
237 }
238 void loser() { //fonction de defaite
239   lose_sound(); //imperial march lose
240   for (byte i = 0; i < 3; i++) {
241     for (byte j = 0; j < NUM_LEDS; j++) {
242       leds[j].setRGB(255, 0, 0); //on met toutes les leds en rouge
243       //tone(9, 200, 250);
244       
245       
246     }
247     FastLED.show();
248     delay(500);
249     clearLEDS();
250     FastLED.show();
251     delay(500);
252   }
253   
254   gameState = 0;
255 }
256 void win_sound(){ //Final Fantasy 7 victoire
257   for (byte k = 0; k < 3; k++){
258     tone(9, 659, 250);
259     delay(400);}
260   tone(9, 659, 750);
261   delay(400);
262   tone(9, 523, 750);
263   delay(400);
264   tone(9, 587, 750);
265   delay(400);
266   tone(9, 659, 250);
267   delay(400);
268   tone(9, 587, 250);
269   delay(400);
270   tone(9, 659, 250);
271   delay(400);
272 }
273 
274 void lose_sound(){ //Marche imperial defaite
275   for (byte k = 0; k < 3; k++){
276     tone(9, 440, 500);
277     delay(200);
278     }
279   tone(9, 349, 350);
280   delay(200);
281   tone(9, 523, 150);
282   delay(200);
283   tone(9, 440, 500);
284   delay(200);
285   tone(9, 349, 350);
286   delay(200);
287   tone(9, 523, 150);
288   delay(200);
289   tone(9, 440, 1000);
290   delay(200);
291   tone(9, 659, 659);
292   delay(200);
293   tone(9, 659, 659);
294   delay(200);
295   tone(9, 659, 659);
296   delay(200);
297   tone(9, 698, 698);
298   delay(200);
299   tone(9, 523, 523);
300   delay(200);
301   tone(9, 415, 415);
302   delay(200);
303   tone(9, 349, 349);
304   delay(200);
305   tone(9, 523, 523);
306   delay(200);
307   tone(9, 440, 440);
308   delay(200);
309 }
310 void clearLEDS() {
311   for (byte i = 0; i < NUM_LEDS; i++) {
312     leds[i].setRGB(0, 0, 0); //on eteint les leds
313   }
314 }

Etapes de fabrication

Étape 1 : Electronique

Utilisez le fer à souder pour souder des fils :

  • Aux 5 Leds
  • Au bouton
  • Au bouton

Exemple pour les Leds :

Le Cyclone Breton Leds.jpg


Ensuite, il faut cabler le circuit en suivant le schéma suivant :

ATENTION ! Il ne faut pas cabler la batterie comme sur le schéma, il faut faire comme si elle n'était pas la. Il faut la brancher directement à la carte avec un cable USB-B

Le cyclone breton circuit.PNG

Étape 2 : Code

  • Démarrer le logiciel Arduino
  • Brancher l'ordinateur à la carte Arduino
  • Aller dans "outil" --> "carte" --> Arduino AVR Boards, et choisir "Arduino Nano"
  • Aller dans "outil" --> "Port" et sélectionner le bon port USB (celui où est branché la carte sur votre ordinateur)
  • Copier dans le logiciel le programme ci-dessus, l'enregistrer dans le dossier FastLED-master/src puis aller dans « édition » et cliquer sur « téléversement »

Étape 3 : Impression 3D (facultatif)

Le but est de faire un petit socle pour le cercle de 60 leds. Il est facultatif mais ca permet de faire une petite protection en plus. Il a pris 9g (0,5 centimes pour une bobine à 18 euros le kilo) et 1h10 d'impression.

Le fichier s'appelle Cercle_pour_60_Leds.stl


Nous avons aussi fait une protection pour les 5 petites leds (voir fichier), il a pris 2,2g de plastique et 13 minutes d'impression.

Le fichier d'appelle protection_5_lets.STL


Il y a également les supports de batterie à imprimer dans le dossier. Il prend 18 minutes à imprimer et 6,2g de plastique. Le dossier d'appelle support_batterie.stl


Une fois que vous avez imprimé les pièces (si vous voulez faire le même design que sur la photo), vous pouvez passer à l'étape suivante.

Étape 4 : Découpe laser (facultatif)

Cela nous permet de faire toute l'armature en bois. Il est décomposer en 4 pièces, vous pouvez découper du bois avec la découpeuse laser. Il faut utiliser les dossiers que vous avez téléchargé au début : contour.svg, dessus.svg, dessous.svg et Fermeture_en_U.svg

Il faut imprimer au moins 3 Fermetures en U pour bien fermer la boite et qu'elle soit droite quand on la pose sur une table.

Une fois que vous avez découpé les 4 pièces (si vous avez besoin d'une armature), vous pouvez passer à l'étape suivante.

Étape 6 : Montage

  • Utiliser de la colle (pistolet ou pas) pour coller les 2 parties du contour. Coller ensuite le dessus avec le contour collé.
  • Mettre le bouton poussoir dans le trou prévu, le sérer avec le boulon en plastique pour ne pas qu'il s'échappe.
  • Coller le cercle en plastique pour les 60 leds au centre du dessus en bois, et les leds au cercle en plastique.
  • Coller également la ligne de 5 leds au centre du cercle, bien faire passer les fils électriques par le trou et les branchements. Coller la protection par dessus.
  • Accrocher ensuite la plaque labdec à l'intérieur de la boite
  • Faire passer le cable de la batterie à l'extérieur par le trou prévu.
  • Accrocher les supports batterie sur le coté de la boite (à l'extérieur)
  • Mettre la batterie dans le support et la brancher
  • Bloquer la batterie avec un élastique de chaque coté
  • Fermer la boite et la bloquer en métant plusieurs fermetures en U (minimum 3)


Image de l'intérieur : Le Cyclone Breton interieur.jpg


Image de la fabrication : Le Cyclone Breton fabrication1.jpg

Étape 5 : Résultat

Si tout se passe bien, sur le cercle de LEDs, il y aura une LED verte fixe qui est l’objectif, une zone jaune qui est la zone acceptable de réussite (qui se réduira selon les niveaux) et une LED rouge qui parcourt tout le cercle.
Le joueur aura à sa disposition un bouton sur lequel il devra appuyer quand il estime que la LED rouge est au même niveau que la LED verte ou dans la zone acceptable.
S’il réussit, le joueur passera au niveau supérieur et une nouvelle LED sur un bandeau représentant les niveaux s’allumera.
Enfin, s'il passe tous les niveaux, une musique de victoire se lancera et de même en cas de défaite.

Les problèmes possibles

  • Si ça ne fonctionne pas

Vérifier le câblage, ça peut être un mauvais câblage, un faux contact, un composant défectueux etc...


  • Des fois, le jeu annonce une victoire à la place d'une défaite (ou le contraire), cela arrive une fois de temps en temps, c'est parce que la carte Arduino a beaucoup de lignes de code à gérer en même temps. Nous ne pouvons rien faire pour contrer ca sauf si on prend une carte Arduino plus puissante.


  • Ne pas hésiter à éteindre puis rallumer en débranchant la batterie.


  • Si on n'arrive pas à téléverser le code

Sur le logiciel Arduino, aller dans l'onglet "outil" --> "port" pour vérifier que la carte est branchée sur le bon port USB de l'ordinateur.

Sinon, aller sur "outil" --> "carte" et vérifier qu'on ait bien la carte "Arduino Nano"

Sinon, aller dans "outil" --> "processor" et sélectionner "ATmega328P (Old Bootloader)"


  • Comment fermer la boîte ?

On a décidé de créer des pièces en U à mettre de part et d'autre de la boîte avec la partie supérieure et la partie inférieure dans les U.


  • La carte Arduino ne tient pas sur la plaque Labdec

On a mis un élastique pour la tenir en place.

Sources et documentation complémentaire

ne pas modifier sous cette ligne