C'est l'hiver ! Hiver.gif

ENIB 2026 : Enibel

De Les Fabriques du Ponant
Révision datée du 20 janvier 2026 à 15:47 par Mama (discussion | contributions) (Code Arduino)
Aller à : navigation, rechercher

Introduction

Dans le cadre de notre intersemestre, nous participons au hackathon « Hack the POCL », organisé par Les Petits Débrouillards et Les Fabriques du Ponant.

L’objectif de ce hackathon est de rendre des données tangibles en inventant un POCL : un Petit Objet Connecté Ludique.

Notre projet doit également être documenté, c’est pourquoi ce wiki a été créé, afin de retracer la genèse et l’évolution de notre travail.

Nous avons choisi de concevoir un décibelmètre capable d’allumer différentes LED en fonction du niveau sonore capté par un micro.

Ce dispositif peut avoir plusieurs usages, le plus évident étant une utilisation en salle de classe.

Une fois le système installé, une limite de décibels sera définie dans le code que nous fournirons, afin de déclencher l’allumage des LED selon le niveau de bruit. 3 niveaux :

  • Vert : le niveau sonore est faible
  • Jaune : le niveau sonore est assez élevé
  • Rouge : le niveau sonore est très élevé

Équipe

Voici notre équipe :

Equipe Enibel.jpg

Devant : Alexis et Maël

Derriere : Arthur, Léïa et Mael

Nous sommes tous les cinq des étudiant·e·s de 3e année de l'ENIB


Logo-enib.png

Outils et matériel

Pour réaliser ce projet, nous avons besoin :

  • Un ESP32S (ou node MCU_32S)
  • Un ESP32S 38P
  • Un panneau LED 16x16
  • Des câbles Dupont
  • Un micro INMP441
  • Une plaque Labdec

Fichiers à joindre

Code Arduino

  1 //Librairie
  2 #include <Adafruit_NeoPixel.h>
  3 #include <driver/i2s.h>
  4 
  5 //Configuration
  6 ///Leds
  7 #define W2812_PIN 27 //Broche du Din du panneau led 
  8 #define WS2812_PIXELS_NUM 256 // Nombres de leds
  9 ///Micro
 10 #define I2S_WS 25 //GPIO 25
 11 #define I2S_SD 32 //GPIO 32
 12 #define I2S_SCK 33 //GPIO 33
 13 
 14 //Matrice
 15 Adafruit_NeoPixel ledStrip(WS2812_PIXELS_NUM, W2812_PIN, NEO_GRB + NEO_KHZ800); 
 16 // Crée l'instance ledStrip avec 256 LED/pixels sur la sortie GPIO27->PIN27 du microcontrôleur. La communication se fera en GRB (Green, Red, Blue) à 800kHZ
 17 
 18 //Variable systèmes
 19 ///Couleurs codées en (red, green, blue)
 20 uint32_t white = ledStrip.Color(255, 255, 255); // Blanc
 21 uint32_t green = ledStrip.Color(0, 255, 0); // Vert
 22 uint32_t red = ledStrip.Color(255, 0, 0); // Rouge
 23 uint32_t yellow = ledStrip.Color(255, 255, 0); // Jaune
 24 uint32_t marine_blue = ledStrip.Color(46, 62, 115); // Bleu marine
 25 ///Seuils son
 26 const int seuil_orange = 75; //dB -> Jaune
 27 const int seuil_rouge = 90; //dB -> Rouge
 28 const int GAIN_CALIBRATION = 20;
 29 ///Variable micro -> Ne pas toucher
 30 unsigned long lastAudioRead = 0;
 31 float dB_cached = 0;
 32 /// Luminosité dynamique
 33 uint8_t luminositeActuelle = 5;
 34 const uint8_t LUMINOSITE_FORTE = 40;
 35 const uint8_t LUMINOSITE_FAIBLE = 5;
 36 const unsigned long TEMPS_ATTENUATION = 30000; // 30 secondes -> 30 000 ms
 37 const unsigned long TEMPS_EXTINCTION = 60000; // 1 minute -> 60 000 ms
 38 
 39 unsigned long dernierChangementCouleur = 0;
 40 uint32_t couleurActuelle = 0;
 41 ///Dessins
 42 // On utilise uint16_t car il y a 16 bits (pixels) par ligne
 43 const uint16_t faceHappy[16] = {
 44   0b1111111111111111,
 45   0b1111100000011111,
 46   0b1111011111101111,
 47   0b1110111111110111,
 48   0b1101111111111011,
 49   0b1011001111001101, // Yeux
 50   0b1011001111001101, // Yeux
 51   0b1011111111111101,
 52   0b1011111111111101,
 53   0b1011011111101101, // Début sourire
 54   0b1011101111011101,
 55   0b1101110000111011,
 56   0b1110111111110111,
 57   0b1111011111101111,
 58   0b1111100000011111,
 59   0b1111111111111111
 60 };
 61 const uint16_t faceNeutral[16] = {
 62   0b1111111111111111,
 63   0b1111100000011111,
 64   0b1111011111101111,
 65   0b1110111111110111,
 66   0b1101111111111011,
 67   0b1011001111001101, // Yeux
 68   0b1011001111001101, // Yeux
 69   0b1011111111111101,
 70   0b1011111111111101,
 71   0b1011111111111101,
 72   0b1011000000001101, // Bouche droite
 73   0b1101111111111011,
 74   0b1110111111110111,
 75   0b1111011111101111,
 76   0b1111100000011111,
 77   0b1111111111111111
 78 };
 79 const uint16_t faceSad[16] = {
 80   0b1111111111111111,
 81   0b1111100000011111,
 82   0b1111011111101111,
 83   0b1110111111110111,
 84   0b1101111111111011,
 85   0b1011001111001101, // Yeux
 86   0b1011001111001101, // Yeux
 87   0b1011111111111101,
 88   0b1011111111111101,
 89   0b1011110000111101, // Bouche triste
 90   0b1011101111011101,
 91   0b1101011111101011,
 92   0b1110111111110111,
 93   0b1111011111101111,
 94   0b1111100000011111,
 95   0b1111111111111111
 96 };
 97 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 98 
 99 /*~~~~~~~~~~Setup~~~~~~~~~~*/
100 void setup() {
101   // put your setup code here, to run once:
102   Serial.begin(115200);
103   ledStrip.begin();
104   ledStrip.setBrightness(10);
105   setupI2S();
106   //Serial.println("BOOT OK");
107 }
108 
109 void loop() {
110   uint32_t nouvelleCouleur;
111   const uint16_t* nouveauDessin;
112 
113     // --- Lecture audio toutes les 500 ms ---
114   if (millis() - lastAudioRead > 500) {
115     dB_cached = readDecibels();
116     lastAudioRead = millis();
117     //Serial.println(dB_cached);
118   }
119   // Choix du dessin et de la couleur
120   if (dB_cached >= seuil_rouge) {
121     nouveauDessin = faceSad;
122     nouvelleCouleur = red;
123   }
124   else if (dB_cached >= seuil_orange) {
125     nouveauDessin = faceNeutral;
126     nouvelleCouleur = yellow;
127   }
128   else {
129     nouveauDessin = faceHappy;
130     nouvelleCouleur = green;
131   }
132 
133   // Détection de changement de couleur
134   if (nouvelleCouleur != couleurActuelle) {
135     couleurActuelle = nouvelleCouleur;
136     luminositeActuelle = LUMINOSITE_FORTE;
137     ledStrip.setBrightness(luminositeActuelle);
138     dernierChangementCouleur = millis();
139   }
140 
141   // Atténuation après 30 secondes
142   if (millis() - dernierChangementCouleur > TEMPS_ATTENUATION) {
143     if (luminositeActuelle != LUMINOSITE_FAIBLE) {
144       luminositeActuelle = LUMINOSITE_FAIBLE;
145       ledStrip.setBrightness(luminositeActuelle);
146     }
147   }
148   if (millis() - dernierChangementCouleur > TEMPS_EXTINCTION){
149     //Eteindre Après 1 minutes
150     ledStrip.setBrightness(0);
151   }
152 
153   // Affichage
154   afficherDessin(nouveauDessin, couleurActuelle);
155 }
156 
157 //Fonction d'affichage en 16x16
158 void afficherDessin(const uint16_t dessin[], uint32_t couleur){
159   ledStrip.clear();
160   /*if (couleur == green){
161     ledStrip.setBrightness(5);
162   }
163   else if (couleur == red){
164     ledStrip.setBrightness(200);
165   }
166   else{
167     ledStrip.setBrightness(50);
168   }*/
169   for (int y = 0; y<16; y++){
170     for (int x = 0; x<16; x++){
171       //On verif le bit x dans la ligne y ( en partant de la gauche)
172       if ((dessin[y]>>(15-x)) & 0x01){
173         int index;
174         // Logique serpentin pour largueur 16
175         if (y%2 ==0){
176           index = (y * 16) + x;
177         }else{
178           index = (y*16) + (15 - x);
179         }
180         ledStrip.setPixelColor(index, couleur);
181       }
182     }
183   }
184   ledStrip.show();
185 }
186 
187 //Fonction MICRO (I2S)
188 void setupI2S() {
189   const i2s_config_t i2s_config = {
190     .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
191     .sample_rate = 44100,
192     .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
193     .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
194     .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
195     .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
196     .dma_buf_count = 8,
197     .dma_buf_len = 64
198   };
199   i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
200   const i2s_pin_config_t pins = {.bck_io_num = I2S_SCK, .ws_io_num = I2S_WS, .data_out_num = -1, .data_in_num = I2S_SD};
201   i2s_set_pin(I2S_NUM_0, &pins);
202   i2s_zero_dma_buffer(I2S_NUM_0);
203   delay(10);
204 }
205 
206 float readDecibels() {
207   static int32_t samples[128];
208   size_t bytesRead = 0;
209 
210   esp_err_t result = i2s_read(
211     I2S_NUM_0,
212     samples,
213     sizeof(samples),
214     &bytesRead,
215     20 / portTICK_PERIOD_MS
216   );
217 
218   if (result != ESP_OK || bytesRead < 16) {
219     return dB_cached;  // garde l’ancienne valeur
220   }
221 
222   long long sum = 0;
223   int count = bytesRead / 4;
224 
225   for (int i = 0; i < count; i++) {
226     int32_t val = samples[i] >> 14;
227     sum += (int64_t)val * val;
228   }
229 
230   float rms = sqrt((float)sum / count);
231   if (rms <= 0) return dB_cached;
232 
233   return 20.0 * log10(rms) + GAIN_CALIBRATION;
234 }

Schéma de branchement

ENIBEL Schema.jpg

Étapes de fabrication

Ce projet est relativement simple et nécessite peu d’étapes :

Étape 1

Tout d’abord, vérifiez l’état du matériel : assurez-vous que les pins sont en bon état, qu’aucun câble n’est sectionné et qu’aucune LED n’est endommagée.

Concernant l’Arduino, il est nécessaire de connecter l’ESP32S à votre ordinateur et de disposer de l’application Arduino ainsi que des pilotes requis, notamment la bibliothèque Adafruit DMA Neopixel développée par Adafruit.

Pour plus de détails sur l’installation et la configuration, vous pouvez vous référer au lien suivant : https://www.wikidebrouillard.org/wiki/Utiliser_l%27ESP32_avec_le_logiciel_Arduino

Étape 2

Ouvrez l’application Arduino et copiez-y le code fourni.

Réalisez ensuite le branchement en suivant le schéma fourni.

Étape 3

Vous pouvez modifier dans le code les différents paramètres définis par défaut afin d’ajuster les niveaux de décibels auxquels les LED s’activent.

Il est également possible d’adapter le programme à un panneau LED plus petit ou plus grand.

De la même manière, l’affichage ainsi que les couleurs déclenchées peuvent être personnalisés selon vos besoins.

Il est également possible de modifier la durée de la mise en veille des LED.

Notre histoire

Après avoir réfléchi à plusieurs idées, nous avons finalement choisi de concevoir un décibelmètre capable d’allumer différentes LED en fonction du niveau sonore capté par un micro.

Au départ, nous envisagions d’utiliser des LED polarisées. Cependant, après une demande au magasin des Petits Débrouillards, nous avons obtenu un panneau LED, ce qui s’est avéré plus adapté au rendu final. Notre objectif est notamment de créer un smiley, particulièrement pertinent pour une utilisation en salle de classe.

Lors du premier jour, nous avons rencontré un problème : deux membres du groupe ne parvenaient pas à suivre le tutoriel de téléchargement pour l’ESP32S. La cause était la lenteur et l’instabilité de la connexion internet du local, alors qu’une connexion rapide et stable est nécessaire pour cette étape.

Par ailleurs, lors de la connexion de la carte à l’ordinateur, le modèle indiqué dans le tutoriel ne correspondait pas à notre matériel. Dans notre cas, il s’agissait de la ESP32-WROOM-DA Module.

Pour créer nos schémas, nous souhaitions initialement utiliser Fritzing, mais celui-ci n’était plus utilisable gratuitement. Nous avons donc choisi d’utiliser LibreOffice Draw comme alternative.

Les branchements représentés sur le schéma fourni ont dû être refaits à plusieurs reprises, car lors des premiers essais, un membre du groupe avait effectué un mauvais branchement sur les pins correspondantes, ce qui nous a grandement retardé.

Enfin, nous avons rencontré des difficultés avec le branchement du panneau LED, qui ne fonctionnait sur aucun des appareils de l’équipe, ainsi qu’avec le téléversement du code sur l’ESP32S, qui générait une erreur.

Chez lui, Alexis a corrigé plusieurs problèmes liés à la connexion et a développé le code :

Il a réussi à téléverser le code en mettant la carte en mode téléchargement : pour ce faire, il a fallu débrancher puis rebrancher le câble reliant la carte à l’ordinateur. La fonction utilisée pour lire les informations du micro était bloquante, ce qui arrêtait le processeur. Par conséquent, le programme Watchdog Timer — qui définit le temps maximal pendant lequel le processeur peut rester inactif — forçait automatiquement le redémarrage de la carte. Il faut également faire attention aux broches utilisées, car de nombreuses petites erreurs provenaient de mauvais branchements.

Pour que ce dispositif fonctionne correctement, il doit être alimenté soit via l’ordinateur, soit sur secteur, mais pas sur batterie.

Durant le temps restant, nous souhaitions améliorer le dispositif en ajoutant un support ainsi qu’un système de bouton permettant d’éteindre les LED. Nous avons modélisé le support, mais par manque de temps, nous n’avons pas pu l’imprimer ni tester le système de bouton. C’est pour cette raison que ces éléments n’ont pas été partagés sur ce wiki, uniquement nos test dans la section ci-dessous. Nous avons néanmoins mis en place un système de mise en veille : lorsque le niveau sonore reste identique pendant une minute, le dispositif se met en veille et se réactive automatiquement dès que le son ambiant change.

Sources et documentation complémentaire

Bus I2S pour le micro : https://docs.espressif.com/projects/arduino-esp32/en/latest/api/i2s.html

Bibliothèque pour gérer les LED : https://github.com/adafruit/Adafruit_NeoPixel

Documentation technique du micro : https://docs.cirkitdesigner.com/component/ad344a2a-950b-4700-8fb3-8d6f269dcf55/inmp441

Fichier STL du support test : https://wiki.lesfabriquesduponant.net/images/b/b1/Enibel_Piece_STL.stl

Voici le prompt que nous avons utilisé pour nous guider dans l’implémentation du code et des branchements :

"Pour ce projet, nous utilisons un microphone INMP441 associé à un NodeMCU-32S afin de mesurer la puissance sonore en décibels. Nous souhaitons également connaître les branchements à réaliser ainsi que le code à implémenter dans l’Arduino IDE pour effectuer cette tâche."

Élément de présentation

ENIBEL Presentation.jpg

Ne pas modifier sous cette ligne