ENIB 2024 : Le Cyclone Breton
Titre de la fiche expérience :
Sommaire
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.
Introduction
éventuelle vidéo
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 30 //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(500);
278 }
279 tone(9, 349, 350);
280 delay(400);
281 tone(9, 523, 150);
282 delay(150);
283 tone(9, 440, 500);
284 delay(500);
285 tone(9, 349, 350);
286 delay(400);
287 tone(9, 523, 150);
288 delay(150);
289 tone(9, 440, 1000);
290 delay(1000);
291 tone(9, 659, 659);
292 delay(659);
293 tone(9, 659, 659);
294 delay(659);
295 tone(9, 659, 659);
296 delay(659);
297 tone(9, 698, 698);
298 delay(698);
299 tone(9, 523, 523);
300 delay(523);
301 tone(9, 415, 415);
302 delay(415);
303 tone(9, 349, 349);
304 delay(349);
305 tone(9, 523, 523);
306 delay(523);
307 tone(9, 440, 440);
308 delay(440);
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 :
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
Étape 2 : Code
- Télécharger le logiciel Arduino au lien suivant : https://www.arduino.cc/en/software et l'exécuter
- Télécharger le dossier zip FastLed au lien suivant : https://www.hackster.io/focalintent/fastled-f872e5, le dezipper
- 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)
É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.