ENIB 2024 : Le cyclone COMUR

De Les Fabriques du Ponant
Aller à : navigation, rechercher

Titre de la fiche expérience :

Description (résumé)

Notre jeu s'appelle "Le cyclone". Le but est simple, appuyer sur le bouton quand la led tournante atteint la led statique sur le cercle de 60 leds. Il y a 5 niveaux de difficultés différentes. La vitesse d'allumage des leds augmente à chaque niveau. Ci-dessous vous verrez une vidéo exemple de notre jeu :

Introduction

Voici une photo de notre groupe :

Photo groupe cyclone COMUR.jpeg

Notre groupe est composé de :

- Sofiya Debois

- Korao Layo Fatima Nadjad

- Maximin Bourgeais

- Côme Beaudouin

- Arthur Bernel

- Azad Arbab Chirani

Outil et matériel

Ici, on va pouvoir retrouver la liste de matériels ainsi que les outils nécessaire à la confection de notre jeu.

Il nous faut :

- une pochette avec le matériel de base

Photo matériel cyclone COMUR.jpeg

- une carte ESP WROOM 32

Arduino cyclone.jpg

- des résistances pour arriver à 219 Ohms (il nous faut 2 fois ça)

Rési 219Ohm.jpg

- des résistances pour arriver à 830 Ohms

Rési 830 Ohm.jpg

- un buzzer

Buzzerpassif.jpg

- une batterie portative

Batterieportative.jpg

- des câbles

Câbles.jpg

Fichiers à joindre

code, ficher d'impression 3D, de découpe laser ou vinyle, ...

Mettre du code Arduino

  1 //jeu
  2 /*
  3 code trouvé sur https://www.hackster.io/mircemk/diy-arduino-cyclone-game-with-ws2812b-led-ring-738c58
  4 */
  5 
  6 #include "FastLED.h" //Bibliothèque permettant de gérer les LEDs
  7 #define NUM_LEDS 60 //Le nombre de LEDs sur le ring
  8 #define DATA_PIN 0 //Pin correspondant au ring
  9 #define BUTTON_PIN 2 //Pin du bouton
 10 #define SCORE_PIN 4 //Pin de la bande LED du score
 11 #define SCORE_LEDS 5 //Le nombre de LEDs sur la bande du score
 12 #define BRIGHTNESS 60 //Luminosité des LEDs du jeu
 13 CRGB leds[NUM_LEDS]; //ring LED
 14 CRGB sleds[NUM_LEDS]; //bande LED
 15 
 16 byte gameState = 0; //Variable pour suivre l'étape du jeu
 17 int period = 1000; //On instantie une variable qui déterminera la vitesse de déroulement du jeu
 18 unsigned long time_now = 0; //Variable qui garde en mémoire le temps à un instant précis
 19 byte Position = 0; //La position de la LED du joueur
 20 byte level = 0; //Variable qui garde en mémoire le niveau actuel
 21 
 22 const byte ledSpeed[5] = {50, 40, 30, 20, 10}; //Liste contenant toutes les vitesses des différents niveaux
 23 
 24 bool findRandom = false; //Variable booléenne pour lancer la recherche d'un nouvel objectif à chaque passage de niveau
 25 byte spot = 0; //Variable correspondant à la position de la LED objectif
 26 
 27 void setup() {
 28   FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
 29   FastLED.addLeds<WS2812B, SCORE_PIN, GRB>(sleds, SCORE_LEDS);
 30   pinMode(BUTTON_PIN, INPUT_PULLUP);
 31   pinMode(DATA_PIN, OUTPUT);
 32   Serial.begin(9600);
 33   Serial.println("Reset");
 34 }
 35 
 36 void loop() {
 37   FastLED.setBrightness(BRIGHTNESS); //Mise à jour du niveau de luminosité des LEDs
 38   if (gameState == 0) {
 39     fill_rainbow(leds, NUM_LEDS, 0, 20); //2 = longer gradient strip 
 40     fill_rainbow(sleds, SCORE_LEDS, 0, 40); //2 = longer gradient strip 
 41 
 42     if (digitalRead(2) == LOW) { //Bouton appuyé
 43       Position = 0; //On initialise la position du joueur à 0
 44       findRandom = true;
 45       delay(500);
 46       for (byte i = 0; i < NUM_LEDS; i++) { //On éteint les LEDs du ring progressivement
 47         leds[i].setRGB(0, 0, 0);
 48         delay(40);
 49         FastLED.show();
 50         tone(5, 400);
 51       }
 52       for (byte i = 0; i < SCORE_LEDS; i++) { //On éteint les LEDs de la bande progressivement
 53         sleds[i].setRGB(0, 0, 0);
 54         delay(100);
 55         FastLED.show();
 56         tone(5, 400);
 57       }
 58       noTone(5);
 59       gameState = 1; //Passage à la prochaine étape du jeu
 60     }
 61     FastLED.show();
 62   }
 63 
 64   if (gameState == 1) {
 65     period = ledSpeed[0];
 66     if (millis() > time_now + period) {
 67       time_now = millis();
 68       if (findRandom) {
 69         spot = random(56) + 3; //Choix de l'objectif aléatoirement
 70         findRandom = false;
 71       }
 72       leds[spot - 1].setRGB(255, 140, 0); //Allumage des LEDs objectif
 73       leds[spot].setRGB(0, 255, 0);
 74       leds[spot + 1].setRGB(255, 110, 0);
 75       sleds[0].setRGB(0, 255, 0);
 76       PlayGame(spot - 1, spot + 1); //Avancement de la LED joueur
 77     }
 78     if (digitalRead(2) == LOW) {
 79       delay(300);
 80       findRandom = false;
 81       if (Position > spot - 1 && Position < spot + 3) { //Vérification de la position du joueur au moment de l'appui
 82         level = gameState;
 83         gameState = 98;
 84       } else {
 85         gameState = 99;
 86       }
 87     }
 88   }
 89   if (gameState == 2) {
 90     period = 320;
 91     period = ledSpeed[1];
 92     if (millis() > time_now + period) {
 93       time_now = millis();
 94       if (findRandom) {
 95         spot = random(56) + 3;
 96         findRandom = false;
 97       }
 98       leds[spot - 1].setRGB(255, 190, 0);
 99       leds[spot].setRGB(0, 255, 0);
100       leds[spot + 1].setRGB(255, 190, 0);
101       sleds[1].setRGB(255, 255, 0);
102       PlayGame(spot - 1, spot + 1);
103     }
104     if (digitalRead(2) == LOW) {
105       delay(300);
106       if (spot - 1 && Position < spot + 3) {
107         level = gameState;
108         gameState = 98;
109       } else {
110         gameState = 99;
111       }
112     }
113   }
114   if (gameState == 3) {
115     period = ledSpeed[2];
116     if (millis() > time_now + period) {
117       time_now = millis();
118       if (findRandom) {
119         spot = random(56) + 3;
120         findRandom = false;
121       }
122       leds[spot].setRGB(0, 255, 0);
123       sleds[2].setRGB(255, 50, 0);
124       PlayGame(spot, spot);
125     }
126     if (digitalRead(2) == LOW) {
127       delay(300);
128       if (Position == spot+1) {
129         level = gameState;
130         gameState = 98;
131       } else {
132         gameState = 99;
133       }
134     }
135   }
136   if (gameState == 4) {
137     period = ledSpeed[3];
138     if (millis() > time_now + period) {
139       time_now = millis();
140       if (findRandom) {
141         spot = random(56) + 3;
142         findRandom = false;
143       }
144       leds[spot].setRGB(0, 255, 0);
145       sleds[3].setRGB(255, 0, 0);
146       PlayGame(spot, spot);
147     }
148     if (digitalRead(2) == LOW) {
149       delay(300);
150       if (Position == spot+1) {
151         level = gameState;
152         gameState = 98;
153       } else {
154         gameState = 99;
155       }
156     }
157   }
158 
159   if (gameState == 5) {
160     period = ledSpeed[4];
161     if (millis() > time_now + period) {
162       time_now = millis();
163       if (findRandom) {
164         spot = random(56) + 3;
165         findRandom = false;
166       }
167       leds[spot].setRGB(0, 255, 0);
168       sleds[4].setRGB(0, 50, 255);
169       PlayGame(spot , spot);
170     }
171     if (digitalRead(2) == LOW) {
172       delay(300);
173       if (Position == spot+1) {
174         level = gameState;
175         gameState = 98;
176       } else {
177         gameState = 99;
178       }
179     }
180   }
181 
182   if (gameState == 98) {
183     winner();
184   }
185   if (gameState == 99) {
186     loser();
187   }
188 }
189 void PlayGame(byte bound1, byte bound2) {
190   leds[Position].setRGB(255, 0, 0); //on allume la led à la position du joueur
191   if (Position < bound1 + 1 || Position > bound2 + 1) {
192     leds[Position - 1].setRGB(0, 0, 0);
193   }
194   FastLED.show();
195   Position++;
196   if (Position >= NUM_LEDS) {
197     leds[Position - 1].setRGB(0, 0, 0);
198     Position = 0;
199   }
200 }
201 
202 void winner() {
203   tone(5, 720);
204   delay(240);
205   noTone(5);
206   for (byte i = 0; i < 3; i++) {
207     for (byte j = 0; j < NUM_LEDS; j++) {
208       leds[j].setRGB(0, 255, 0);
209     }
210     FastLED.show();
211     delay(500);
212     clearLEDS();
213     FastLED.show();
214     delay(500);
215   
216   }
217   findRandom = true;
218   Position = 0;
219 
220   gameState = level + 1;
221   if (gameState > 5) {
222     winAll();
223   }
224 }
225 void loser() {
226   for (byte i = 0; i < 3; i++) {
227     for (byte j = 0; j < NUM_LEDS; j++) {
228       leds[j].setRGB(255, 0, 0);
229     }
230     FastLED.show();
231     tone(5, 280);
232     delay(500);
233     clearLEDS();
234     noTone(5);
235     FastLED.show();
236     delay(500);
237   }
238   gameState = 0;
239 }
240 void clearLEDS() {
241   for (byte k = 0; k < NUM_LEDS; k++) {
242     leds[k].setRGB(0, 0, 0);
243   }
244 }
245 void winAll(){
246   gameState = 0;
247 }
248 
249 void freq(){
250 }

Étapes de fabrication

On va indiquer ici toutes les étapes de la création du prototype à la version finale de notre projet (avec des photos, dessins...).

étape 1 : comprendre le fonctionnement du jeu

En allant sur le wiki de la fabrique du ponant, vous pouvez retrouver des vidéos montrant le fonctionnement du jeu (voir la vidéo dessus). On retrouve aussi un prototype de code qu'on va modifier pour qu'il fonctionne avec notre matériel.

étape 2 : réunir le matériel nécessaire

Au niveau du matériel, dès le début, vous avez une pochette avec à l'intérieur, une ring avec 60 leds, une bande de 5 leds, un transistor, une plaquette pour les liaisons entre les résistances et les câbles et un bouton. Il a fallu qu'on aille chercher en plus :

- une carte ESP WROOM 32

- des câbles

- une résistance 830 Ohms (on l'a décomposé en une résistance de 680 Ohms et une résistance de 150 Ohms)

- deux résistances de 219 Ohms (on les a décomposé en trois résistance de 68 ohms et une résistance de 15 Ohms)

- un buzzer

- une batterie portative

étape 3 : dessiner le design sur papier

Avant de faire la découpe du carton, on a dessiné un design sur papier.

Dessin1.jpg Dessin2.jpg

étape 4 : découper le socle

On a décidé de faire notre jeu en carton. Voici les découpes qu'on a réalisé :

Découpe carton.jpg Découpe.jpg

On a rajouté cette découpe en noir pour la customisation de notre jeu.

étape 5 : faire le câblage sur Tinkercad

Avant de réaliser notre câblage avec des vrais composants, nous avons réalisé un câblage sur Tinkercad.

Cablagetc.png Image rési tc.png

L'image à droite représente les 2 résistances sur l'image à gauche (219 Ohms en 4 résistances).

étape 6 : réaliser le câblage et tester le code

On réalise le câblage final pour voir si tout fonctionne bien (le code, le téléversement sur la carte...).

Câblagefin.jpg

étape 7 : finir la maquette

Voici des photos du résultat final de notre jeu "Le cyclone" :

Pf1.jpg Pf2.jpg

Troubleshouting

Le premier problème qu'on a rencontré est au niveau du code. Au lieu d'avoir le jeu du cyclone, on a toute les leds qui s'allument ce qui n'est pas normal (voir photo).

Erreurcâblage.jpg

Le problème venait des entrées sur le code car nous n'avons pas la même carte que le code qu'on nous a donné.

1 #include "FastLED.h" //Bibliothèque permettant de gérer les LEDs
2 #define NUM_LEDS 60 //Le nombre de LEDs sur le ring
3 #define DATA_PIN 0 //Pin correspondant au ring
4 #define BUTTON_PIN 2 //Pin du bouton
5 #define SCORE_PIN 4 //Pin de la bande LED du score
6 #define SCORE_LEDS 5 //Le nombre de LEDs sur la bande du score
7 #define BRIGHTNESS 10 //Luminosité des LEDs du jeu
8 CRGB leds[NUM_LEDS]; //ring LED
9 CRGB sleds[NUM_LEDS]; //bande LED

Le second problème était un problème de temps. A chaque fois qu'on passait au niveau suivant, on devait attendre une trentaine de secondes, ce qui est vachement long.

Le problème venait entre autre du buzzer. Notre jeu a normalement besoin d'un buzzer passif et notre programme doit générer une fréquence pour ce buzzer. Elle était créé par la fonction arduino "tone", qui ralentissait énormément notre programme. On a donc pris un haut parleur passif qui génère des fréquences à différents moments clés du jeu (niveau passé, lorsqu'on a perdu...).

Sources et documentation complémentaire

Téléchargez le fichier de découpe

ne pas modifier sous cette ligne