Led's dance

par Faironniers J.L_Et_D

Afin de fêter dignement ses 10 ans d’existence, la bibliothèque universitaire du Havre organise une silent party. La faironnerie ABC a décidé de participer à l’événement en animant l’atelier led’s dance.

Put on your red shoes and dance the blues
To the song they’re playing on the radio
While colour lights up your face
Sway through the crowd to an empty space

David Bowie

Nous proposons deux montages :

  1. Le premier consiste à créer un pendentif avec une led clignotante que vous pourrez porter durant cette soirée silencieuse ou la mettre dans votre sapin de Noël recyclé ;
  2. Le second, un sonomètre avec un arduino, un micro et un anneau de leds.

Leds Aalto

René Dottelonde a permis que l’esprit du designer et architecte finlandais Alvar Aalto et son vase Savoy hante la bibliothèque universitaire du Havre. Pour les 10 ans de cette dernière, il nous a semblé amusant de réaliser un clin d’oeil intermittent. Nous allons essayer de décrire les différentes étapes.

Matériel

Il nous faut une pile bouton 3v, un support, une led clignotante, le logo de la bibliothèque découpé dans du médium et le plus important un bout de ficelle.

Matériel

Montage

On commence par installer la pile dans le support le + côté visible. Pile

On pose ensuite un morceau de scotch double face sous le support de pile.

Double face

On glisse la led des deux côtés de la pile bouton. Attention les leds sont polarisées il faut mettre la plus grande patte sur le dessus, elle correspond au plus. Elle devrait s’allumer et clignoter.

Mise en place de la led

Le moment délicat arrive, il faut plier la led. On va tout d’abord introduire la led dans le logo de la BU.

Led dans logo

Led dans logo

On plie avec délicatesse …..

pliage

On enlève le tout, pour croiser les pattes de la led de façon à ce que cela fasse ressort.

ressort

ressort

On repositionne la led. Attention au plus qui est maintenant la patte la moins longue horizontalement…

remontage

On enlève le double face.

remontage

Et voila le travail.

Le montage

J’espère que vous avez conservé la protection du double face, car cela va servir d’interrupteur.

Interrupteur

On passe une cordelette.

Interrupteur

Sonomètre ou le baroufledomètre

L’idée consiste à réaliser un sonomètre à l’aide d’un micro amplifié et d’un anneau de led qui s’allumera plus ou moins en fonction de l’intensité sonore dans la pièce.

Matériel

Pour réaliser le montage, il est nécessaire d’avoir

Premier montage

Pour commencer nous allons mesurer l’intensité sonore à l’aide du micro amplifié. Les pins analogiques de l’Arduino renvoient un nombre entier compris entre 0 et 1023. Ces données ne sont pas directement utilisables, nous allons échantillonner durant environ 50 ms ce qui correspond à la fréquence basse perçue par l’oreille humaine (20 Hz et 20 000 Hz) et nous allons déterminer crête à crête l’amplitude.

Le montage

Nano + micro

Le code

/*
 * Mesure d'un niveau sonore ambiant
 */

#define TRACEUR

#define BROCHE_MICRO   A0                // Le micro est connecté à une broche analogique

const int fenetreEchantillonnage = 50;   // Fenêtre d'échantillonnage (50 ms = 20Hz) fréquence audible
unsigned int echantillon;

void setup()
{
   Serial.begin(9600);
}


void loop()
{
   unsigned long debutCrono= millis();  // Debut d'échantillonnage
   unsigned int creteACrete = 0;        // Niveau crête à crête

   unsigned int signalMax = 0;
   unsigned int signalMin = 1024;

   // Acquisition des valeurs durant la fenêtre d'échantillonnage
   while (millis() - debutCrono < fenetreEchantillonnage)
   {
      echantillon = analogRead(BROCHE_MICRO);
      if (echantillon < 1024)           // Valeur cohèrente ?
      {
         if (echantillon > signalMax)
         {
            signalMax = echantillon;
         }
         else if (echantillon < signalMin)
         {
            signalMin = echantillon;
         }
      }
   }
   creteACrete = signalMax - signalMin;  // Amplitude crête à crête

#ifdef TRACEUR
  Serial.print(creteACrete);
  Serial.println();
#else
   Serial.print("Min   = ");
   Serial.println(signalMin);
   Serial.print("Max   = ");
   Serial.println(signalMax);
   Serial.print("Delta = ");
   Serial.println(creteACrete);
   double volts = (creteACrete * 3.3) / 1023;   // Convertion en volts
   Serial.print("Volts = ");
   Serial.println(volts);
#endif

}

Le code complet.

Amplitude du son

Deuxième montage

L’anneau de led sert ici de vumètre. On va l’allumer en fonction de l’amplitude du son. Nous allons essayer de réaliser cela progressivement.

La première chose à faire est de récupérer la bibliothèque adafruit correspondante et l’installer dans l’environnement de développement arduino. Il suffit pour cela d’utiliser le gestionnaire de bibliothèque. À partir du menu croquis, Inclure une bibliothèque > Gérer les bibliothèques. Au niveau de la boite de dialogue entrer Neopixel. Vous devez voir apparaître dans la liste Adafruit NeoPixel by Adafruit choisissez la dernière version et installez la.

Installation de la bibliothèque Neopixel

Le montage

Nous allons réaliser un montage de base extrémement simple qui consiste à connecter l’anneau de led à l’arduino nano. On prend l’alimentation sur l’arduino, attention cependant si vous utilisez un anneau plus important ou une guirlane de led, à la consommation électrique. Il faut alors adapter le montage.

Montage NeoPixel

Le code

On commence par inclure le fichier d’entête contenant les prototypes des différentes fonctions permettant d’utiliser les Neopixels.

#include <Adafruit_NeoPixel.h>

Il faut déclarer ensuite une variable globale représentant votre Neopixel que vous pourrez utiliser dans vos différentes fonctions :

Adafruit_NeoPixel uneVariable = Adafruit_NeoPixel(<paramètre1>, <paramètre2>, <paramètre3>);
  1. <paramètre1> vous précisez combien il y a de leds RGB dans votre anneau ou votre guirlande.
  2. <paramètre2> la broche sur laquelle votre dispositif est connecté.
  3. <paramètre3> une valeur indiquant le type de NeoPixels connectés, le plus souvent vous pouvez omettre cette valeur.
#include <Adafruit_NeoPixel.h>

#define N_LEDS  16              // Nombre de leds RGB dans l'anneau
#define BROCHE_ANNEAU 6         // Broche sur laquelle est connecté l'anneau (Data input)

// Paramètre 3 =
//   NEO_KHZ800  800 KHz fréquence du flux (le plus souvent)
//   NEO_KHZ400  400 KHz
//   NEO_GRB     cablage GRB (le plus souvent)
//   NEO_RGB     cablage RGB
Adafruit_NeoPixel anneau = Adafruit_NeoPixel(N_LEDS, BROCHE_ANNEAU, NEO_GRB + NEO_KHZ800);


void setup() {
  anneau.begin();
  anneau.show();              // Toutes les leds sont éteintes.
}

void loop() {
for(int j = 0; j < 3; j++ ) {
    // Éclat croissant
    for(int k = 0; k < 256; k++) {
      switch(j) {
        case 0: setAll(k,0,0); break;
        case 1: setAll(0,k,0); break;
        case 2: setAll(0,0,k); break;
      }
      anneau.show();
      delay(3);
    }
    // Éclat décroissant
    for(int k = 255; k >= 0; k--) {
      switch(j) {
        case 0: setAll(k,0,0); break;
        case 1: setAll(0,k,0); break;
        case 2: setAll(0,0,k); break;
      }
      anneau.show();
      delay(3);
    }
}
}

void setAll(int rouge, int vert, int bleu) {
  for(int i = 0; i < N_LEDS; i++ ) {
    anneau.setPixelColor(i, anneau.Color(rouge, vert, bleu));
  }
  anneau.show();
}

Le code complet.

On va compléter notre programme. Nous avons joué sur le “fade” (éclat), on va maintenant utiliser la roue chromatique. Ainsi lorsque l’amplitude n’est pas trop forte les leds s’allumeront en vert, puis en jaune orange, puis en rouge. On code en RGB : anneau.Color(rouge, vert, bleu) et nous allons utiliser le modèle HSL, ( Hue, Saturation, Lightness ; teinte, saturation, lumière).

  • La teinte est mesurée par un angle autour de la roue chromatique ;
  • La saturation correspond à la pureté de la couleur. C’est une quantité en % de gris contenue dans une teinte. La saturation est mesurée du centre de la roue vers les bords en partant des couleurs neutres vers les couleurs les plus vives.
  • La luminosité indique la variation d’intensité lumineuse de la couleur.

Roue Chromatique

Il va nous falloir faire varier l’angle entre 120° (vert) jusqu’à 0 (rouge). Les primitives Neopixels étant en RGB, on écrit une fonction de conversion.


teinte_2_RGB( v1, v2, vH )
{
   if ( vH < 0 ) vH += 1;
   if ( vH > 1 ) vH -= 1;
   if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH );
   if ( ( 2 * vH ) < 1 ) return ( v2 );
   if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 );
   return ( v1 );
}

uint32_t roueChromatique(byte teinte, float saturation, float lumiere)
 if ( saturation == 0 )
 {
    rouge = lumiere * 255;
    vert  = lumiere * 255;
    bleu  = lumiere * 255;
 }
 else
 {
    if ( lumiere < 0.5 )
      var_2 = lumiere * ( 1 + saturation );
      else var_2 = ( lumiere  + saturation ) - ( saturation * lumiere );

    var_1 = 2 * lumiere - var_2;

    rouge = 255 * teinte_2_RGB( var_1, var_2, teinte + ( 1. / 3 ) );
    vert  = 255 * teinte_2_RGB( var_1, var_2, teinte );
    bleu  = 255 * teinte_2_RGB( var_1, var_2, teinte - ( 1. / 3 ) );
    return anneau.Color(rouge, vert, bleu);
 }

On écrit une fonction qui eteint n leds consécutives en donnant le numéro de la première et le numéro de la dernière.

void eteintEntre(uint8_t ledDepart, uint8_t ledArrivee) {
  uint8_t tmp;
  if (ledDepart > ledArrivee)
  {
    tmp = ledDepart;
    ledDepart = ledArrivee;
    ledArrivee = tmp;
  }
  for (int quelleLed = ledDepart; quelleLed <= ledArrivee; quelleLed++)
    anneau.setPixelColor(quelleLed, anneau.Color(0, 0, 0));
}

En s’inspirant de cette dernière on pourrait écrire une fonction qui allume n leds consécutives en donnant le numéro de la première, le numéro de la dernière et la couleur. Nous allons écrire une version plus sophistiquée qui allume un gradient de couleur entre les leds considérées. On utilise pour cela une fonction map (valeur, source_limite_basse, source_limite_haute, destination_limite_basse, destination_limite_haute) :

  • valeur : le nombre à mettre à l’echelle ;
  • source_limite_basse : la borne inférieure de l’échelle de la valeur ;
  • source_limite_haute : la borne supérieure de l’échelle de la valeur ;
  • destination_limite_basse: la borne inférieure de la nouvelle échelle ;
  • destination_limite_haute: la borne supérieure de la nouvelle échelle.

La valeur renvoyée est la valeur mise à l’échelle. On utilise la fonction map(), la couleur est choisie par le numéro de led à allumer.

void allumeEntre(uint8_t ledDepart, uint8_t ledArrivee, unsigned int angleDepart, unsigned int angleArrivee) {
  uint8_t tmp;
  if (ledDepart > ledArrivee)
  {
    tmp = ledDepart;
    ledDepart = ledArrivee;
    ledArrivee = tmp;
  }
  for (int quelleLed = ledDepart; quelleLed <= ledArrivee; quelleLed++)
    anneau.setPixelColor(quelleLed,roueChromatique(map(ledArrivee - ledDepart + 1, 0, N_LEDS - 1, angleDepart, angleArrivee), 1, 0.5));
}

On repart de notre programme qui lisait la sortie du micro, pour une meilleure lisibilité on écrit une fonction acquisition() qui réalise le traitement.

unsigned int acquisition()
{
  unsigned int echantillon;
  unsigned int signalMax = 0;
  unsigned int signalMin = 1024;

  unsigned long debutCrono = millis(); // Debut d'échantillonnage
  unsigned int creteACrete = 0;        // Niveau crête à crête

  while (millis() - debutCrono < fenetreEchantillonnage)
  {
    echantillon = analogRead(BROCHE_MICRO);
    if (echantillon < 1024)           // Valeur cohèrente ?
    {
      if (echantillon > signalMax)
      {
        signalMax = echantillon;
      }
      else if (echantillon < signalMin)
      {
        signalMin = echantillon;
      }
    }
  }
  creteACrete = signalMax - signalMin;  // Amplitude crête à crête
  return creteACrete;
}

Il nous reste à définir la fonction loop() principale :

void loop() {
  unsigned int amplitude = acquisition(); // Amplitude crête à crête
  unsigned int nbAAllumer = map(amplitude, 0, 1024, 0, 17 );

#ifdef DEBUG
  Serial.print("amplitude = "); Serial.println(amplitude);
  Serial.print("nbAAllumer = "); Serial.println(nbAAllumer);
#endif

  eteintEntre(nbAAllumer, N_LEDS - 1);   // On éteint les leds en trop ...
  if (nbAAllumer > 0) allumeEntre(0, nbAAllumer - 1, 120, 0);
  anneau.show();
}

Le montage complet est le suivant :

Schéma complet

On remarquera que l’on a été cherché une masse sur l’ISCP. Le code complet.

Pour aller plus loin

Notre baroufledomètre est terminé. Des améliorations sont possibles, nous traitons les mesures linéairement ce qui n’est pas correct. Nos oreilles sont sensibles à des variations de pression entre 0,00002 Pa (20 μPa) et 200 Pa (la pression atmosphérique est de 101 300 Pa), l’étendue de l’échelle est de 10⁶ et elle est donc très grande. D’autre part c’est la variation relative entre deux sons que nous percevons et non pas une variation absolue. Un son exerçant une pression acoustique de 0,02 Pa relativement à 0,01 Pa est aussi fort qu’un son de 2 Pa relativement à 1 Pa. Le son a augmenté de 100% ! On utilise donc le décibel pour mesurer le son, c’est une échelle logarithmique. Dans l’usage courant, un niveau de bruit exprimé en décibels est un niveau de pression acoustique Lp = 0 dB avec comme référence 20 μPa. Cette échelle est trompeuse car non linéaire. Un bruit de 55 dB (bruit d’une conversation) ajouté à un bruit de 55 dB n’est pas un bruit de 110 db. Pour la première source : et pour la deuxième . Le niveau d’intensité acoustique résultant du fonctionnement des deux sources est donc Les deux sources produisent ici la même intensité, , , donc environ 55 + 3 dB = 58 dB.

Nous contacter

Vous pouvez nous contacter à cette adresse ou utiliser le formulaire ci-dessous.