Tuto t-shirt lumineux qui réagit à la musique

Salut bande de salopes !

T’as envie de briller en soirée mais t’es pas une lumière ? Aujourd’hui on va illuminer un t-shirt à ta place avec des motifs qui suivent la musique (contrairement à toi qui sera en train de ramper à 4 pattes en cherchant ton verre de bière au sol).

Du matos :

Pour ce bricolage il te faut :
2 t-shirt simples genre blanc (non, t’es pas bourré, il en faut bien 2)
du fil électroluminescent
Et attention, ça se complique (ah, tu croyais pas que ça serait aussi simple ?). Avec ton putain de fil, tu dois choisir une alimentation appropriée. Si tu as moins de 3 mètres, tu choisis une alimentation 3V, si tu as plus de 3m, et jusqu’à 15m de fil, tu dois utiliser une alimentation 12V, c’est ce que j’ai choisi, et c’est pas autrement !
-donc ton alim 12V
des batteries 12V , moi j’ai choisi 8 batteries AA NiMH de 1.2V chacunes. Oui, ça fait pas 12V au total, fais pas ton malin en faisant genre tu sais calculer. Déjà quand tu les charges à bloc, tes NiMH elles font plus de 1.2V, et en plus de toute façon ça marche quand-même, c’est moi qui te le dis !
un microphone pour chopper le son ambiant. Celui que j’ai choisi il est badass, il a un réglage automatique du gain.
une électronique (EL-Sequencer) avec un microcontrôleur dessus pour traiter le microphone et commander les fils (c’est le cœur du circuit)
un petit interrupteur juste pour compliquer un peu le projet, j’aime bien te faire souffir
des plaques de feutre assorties au T-shirt pour faire les motifs au fil lumineux. Ben ouais, si tu couds le fil directement sur le t-shirt qui est mou, les motifs vont se déformer et donner de la MERDE ! réfléchis un peu, bon sang !
Bon, t’as tout ce qu’il te faut ? trouves aussi un fer à souder, des outils, un kit de couture, du fil électrique, du bois, des petits clous, des vis, tout ce que tu veux, enfin, n’oublies pas ta tête !

On a plusieurs chantiers à attaquer, mais commençons par le début, avant de dessiner tes petits motifs à la con. Déjà, ça fait un moment que je te vois, le regard vide, avec une question que tu te poses :

Mais c’est quoi du fil électroluminescent ?

Ah bah mon salaud, t’as oublié d’être con, t’as même l’air curieux. T’as intérêt à bien comprendre ce qu’est du EL-Wire (oui, en Anglais c’est plus court à écrire) avant de faire quoi que ce soit avec.  Ce fil, il ressemble à ça :

CAM00346~01

Je vole le schéma de Wikipedia parce qu'il est bien

Je vole le schéma de Wikipedia parce qu’il est bien

Bon, alors comment ça marche ? On voit qu’il y a différentes couches, au centre un fil de cuivre avec une couche de phosphore et autour de ce phosphore 2 tout petits fils. Entre ce petit fil et le fil de cuivre on applique une tension de l’ordre de 100V à une fréquence de l’ordre de grandeur du kHz. C’est ce chargement-déchargement rapide du “condensateur”  coaxial formé par les fils de cuivre qui excite le phosphore et le rend lumineux. La dernière couche de plastique lui donne une couleur.

Choses pratiques

Ton fil électroluminescent, il vient sans connexions électriques et tu peux le couper où tu veux. Mais à chaque fois tu dois raccorder un des bouts à ton alimentation pour qu’il s’allume (non, vraiment ?). C’est une des parties les plus marrantes du projet. Il faut dénuder des fils minuscules, les souder sans rien péter, mettre de la gaine thermorétractable dessus pour sécuriser, j’explique pas dans le détail, il y a un gars qui fait ça très bien pour moi. En fait je me suis inspiré de plusieurs tutoriaux du site Instructables et j’ai composé ma méthode perso pour la connexion électrique. RTFM et démerdes-toi !

Une fois le fil connecté, tu vas te brancher sur le EL-Sequencer sur un port de sortie. Le EL-Sequencer est fourni avec des belles prises mâle mais j’ai pas trouvé de prises femelle qui correspondent, j’ai été souder des connecteurs à moi un peu plus loin sur le PCB, on peut aussi souder directement les fils électriques sur le PCB, mais après c’est plus dur de débrancher. Bon donc on a de l’électricité et de la lumière qui sort, mais il faut aussi de l’électricité qui rentre…
Soudes le connecteur des batteries au port DC IN, connectes aussi l’alimentation sur DC OUT et AC IN. J’ai posé une prise sur DC IN pour pouvoir brancher-débrancher les piles (ben oui, sinon ça reste tout le temps allumé, Ducon)

Si t’as tout bien fait, tu peux déjà brancher et voir si ton fil s’allume, avec le programme par défaut sur le microcontrôleur, il devrait clignoter. On verra après comment le programmer (commences déjà par réviser ton cours de programmation et relis aussi ton cours de math sur l’analyse de Fourier en passant, ça va servir)

On fait de la couture, biatch

20140502_115026

Tu dessines ton motif au crayon sur le feutre et ensuite tu couds le fil dessus pour donner la forme. Il faut faire des trous dans le feutre aux endroits où le fil doit rentrer et sortir. T’as vu comment c’est chiant à souder le fil ? Quand tu fais ton motif, il faut minimiser le nombre de fois que tu coupes le fil, simplifier le motif comme ça t’as moins à souder. Une idée aussi est de faire passer le fil derrière le feutre à certains endroits. Par exemple moi je n’ai utilisé qu’un segment de fil pour faire les deux yeux du smiley. Le cerveau, toujours le garder à portée pour pas se faire chier.

Si tu as un angle droit à faire, tu ne peux pas plier le fil directement. La solution ? Faire un trou dans le feutre, et faire une boucle avec un rayon de courbure plus grand derrière le feutre pour ressortir avec une autre direction par le même trou.

 

20140502_161715Revenons à l’électronique

On peut tout simplement brancher directement le fil électroluminescent sur l’alimentation 3 ou 12V et il s’allume. Mais bon, vous êtes pas des petites bites et ici c’est le Blog de Bob Chidie, on veut du badass, on veut du lourd ! Il faut un t-shirt vivant, qui réagisse à la musique ! Le plus souvent ce que font des gens c’est un circuit analogique qui “écoute” les sons ambiant et déclenchent la lumière en fonction du volume sonore ambiant. Du coup il faut constamment régler le niveau du trigger selon que la musique soit forte ou non. Ca donne un effet assez moisi. Non, ce qu’il faut c’est détecter le rythme de la musique, et le top c’est de détecter la basse. Pour ça on va analyser les fréquences du son ambiant et ne déclencher que si le niveau de base est suffisant.
Dans énormément de domaines de ingénierie pour détecter des fréquences on applique la théorie de la Transformée de Fourier. C’est cool, mais ça se fait avec des nombres complexes, des intégrales, et ça ne fonctionne que pour des signaux avec des caractéristiques idéales. Malheureusement je suis dans le monde réel, et mon microcontrôleur, lui, il sait pas faire des intégrales complexes. Mais ça fait des années qu’on a la solution : la Transformée de Fourier Rapide (FFT) qui est l’application réelle la plus répandue de cette théorie. C’est une méthode bien connue mais elle nécessite pas mal de calculs, mon microcontrôleur, lui est un peu limité. Il y a un type sur son site, il explique tout ça très bien, il l’a même codé lui-même sur microcontrôleur. Mais il est si gentil qu’il donne pas le code qu’il a écrit. Alors j’ai trouvé un autre algo qui marche bien, et qui est déjà tout fait (et dieu sait ce que les programmeurs sont paresseux, on adore copier-coller).

Donc j’ai copié le petit exemple de sa librairie, j’ai ajouté une détection de niveaux selon les fréquences pour faire clignoter les fils et voilà, mon motif s’illumine en suivant la musique. Tests chez moi, ça fonctionne super bien. Attendez, attendez ! Vous connaissez l’adage : “if something has to fail at some point, it will”.

Pour info, le EL-Sequencer, on le programme en utilisant un port série FTDI, ce sont des petits fils à connecter dans un coin sur la carte, et avec un USB à l’autre bout sur le PC. Ca nécessite un article en soit pour régler les détails mais vous êtes pas trop con (je crois) alors je le répète : RTFM

Il faut apporter un minimum de robustesse !

Petit rappel, ce bricolage, il va se promener dans la foule dans un environnement avec un volume sonore élevé, des gens bourrés qui poussent partout, sombre, avec peut-être un peu d’humidité.

Volume sonore élevé, il se passe quoi si le micro foire pour une quelconque raison et ça ne s’allume plus ? Au cas où malgré mes tests et réglages ça marche pas, il faut un plan B ! Le plan B, c’est un petit interrupteur qui n’est lu qu’au démarrage et qui permet de dire si on va en mode microphone, ou en mode automatique, avec les lumières qui clignotent aléatoirement en suivant un séquenceur. Ça évite de passer pour un con si en fait ça marche pas comme prévu.

L’électronique est rangée dans une boite en bois qui va lui éviter de prendre des chocs, les fils que j’ai soudé directement sur la carte je les ai noyé dans la colle thermique pour ne pas user ou défaire les soudures si je tire sur les fils. Le tout est placé dans un sac banane devant moi sous le t-shirt.

Donc ouais, il y a 2 t-shirt, celui du dessous sur lequel sont fixés les motifs de feutre, et celui du dessus qui cache le feutre mais laisse passer la lumière.

Test des batteries, avant de savoir si je peux fêter toute la nuit ou pas

Test des batteries, avant de savoir si je peux fêter toute la nuit ou pas

L'électronique de la brouette

L’électronique de la brouette

 Quelques remarques auxquelles j’ai eu droit

Après une démo live de la détection sonore :

Mouais, ta détection tu devrais mieux la régler…

Et tes hauts-parleurs de merde, tu comptes les régler ? Moi j’ai mis des niveaux qui correspondent à du vrai son de scène, pas de la merde comme ça….

——————————————————————————————————-

T’as testé tes batteries que pendant 3h et tu penses que ça va tenir la soirée ?

Ben ouais, mon t-shirt a tourné de 20h30 à 4h du matin non stop

——————————————————————————————————-

Un peu tout le long de la soirée :

Whaou, trop cool/classe/bien ton T-shirt ! Yeeeeeaaah !

Wazaaaaaaaaaa !

——————————————————————————————————-

Comment t’as fait ça ? Moi j’ai un CFC d’électricien, on fait pas des trucs comme ça !

Moi je suis mécanicien alors bon… sors ton fer à souder, un microcontrôleur et lance toi, mec !

——————————————————————————————————-

Oh trop cool, tu l’as acheté où ton T-shirt ?

C’est moi qui l’ai fait

Ah, t’es un étudiant de l’EPFL alors ?

Ouais

Bon, c’est pas grave, mais ton T-thirt est vraiment cool !

——————————————————————————————————-

Tu fais partie du Staff ?

 

Le code source du T-shirt

 

#define LOG_OUT 1 // use the log output function
#define FHT_N 256 // set to 256 point fht

//A,B et C sont 3 ports du EL-Sequencer
//A est le logo Balélec dans le dos
//B est le cercle autour du smiley
//C est le visage
#define allumeA digitalWrite(2,HIGH);
#define allumeB digitalWrite(3,HIGH);
#define allumeC digitalWrite(4,HIGH);
#define eteintA digitalWrite(2,LOW);
#define eteintB digitalWrite(3,LOW);
#define eteintC digitalWrite(4,LOW);

#include FHT.h 
int pin = A3;
int activeSequence = 0;

void setup() {
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  eteintA; eteintB; eteintC;
  //résistance pullup improvisée sur port analogique
  digitalWrite(pin, HIGH); 
  
  //mode automatique
  if(digitalRead(pin)){
      activeSequence = 1;
      randomSeed(analogRead(A4));
  }
  else{ //mode microphone
  //bout de code volé à l'auteur de la librairie FHT
    Serial.begin(115200); // use the serial port
    TIMSK0 = 0; // turn off timer0 for lower jitter
    ADCSRA = 0xe5; // set the adc to free running mode
    ADMUX = 0x42; // use adc0 //0x42 est le pin A2, 0x40 le pin A0
    DIDR0 = 0x01; // turn off the digital input for adc0
  }
}

void clignote(int temps, int n) {
  for(unsigned int i = 0; i < n; i++){
    allumeA; allumeB; allumeC;
    delay(temps);
    eteintA; eteintB; eteintC;
    delay(temps);
  }
}
void clignoteInverse(int temps,int n) {
  for(unsigned int i = 0; i < n; i++){
    allumeA; allumeB; eteintC;
    delay(temps);
    eteintA; eteintB; allumeC;
    delay(temps);
  }
}

void loop() {
  
  if(activeSequence){
	//le t-shirt est allumé et par moment il clignote au bol
    switch(random(1, 4)){
      case 1:
        clignoteInverse(300,random(10,40));
        break;
      case 2:
        clignoteInverse(30,random(20,40));
        break;
      case 3:
        for(int i = 20; i > 1; i--){
          clignote(5*i,4);
        }
        break;
      default:
        for(int i = 20; i > 1; i--){
          clignote(5*random(3,20),4);
        }
    }
    allumeA; allumeB; allumeC;
    delay(random(10,30)*1000); 
    return;
  }
  
  //bout de code volé à l'auteur de la librairie FHT
  while(1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    sei();
    Serial.write(255); // send a start byte
    Serial.write(fht_log_out, FHT_N/2); // send out the data
    
    //ma détection de basse
    if(fht_log_out[2] > 175){
      allumeA; allumeB; allumeC; 
    }
    //ma détection de mid
    else if(fht_log_out[63] > 110){
      allumeC;
    }
    else{
      eteintA; eteintB; eteintC;
    }
  }
}

LEDs RGB + Arduino

Force Rouge !

Force Rouge !

J’ai récemment acheté un ruban de LEDs RGB de 5 mètres. Le kit comprend un petit transfo, un petit boîtier et une télécommande infrarouge pour choisir la couleur ou le pattern d’animation. Passionné par le concept d’internet des objets, il me fallait trouver un moyen d’interfacer cet éclairage avec Arduino.
J’ouvre le boîtier et ne découvre que peu de composants (ouf, car mes connaissances en électronique ne sont pas bien solides). Il y a 3 pistes pour les 3 couleurs, alimentées par 3 transistors MOSFET. Un capteur infrarouge pour la télécommande et au centre de la conception… un microcontrôleur.

CAM00086 Je me dis que si je branche un microcontrôleur à la place de l’original je fais ce que je veux du circuit. Je dessoude la puce originale et ponte timidement Arduino avec un code de test sur une des pattes allant vers le MOSFET. Victoire, ça fonctionne, je peux allumer les LEDs vertes !

CAM00087 Finalement j’ai asservi les 3 couleurs, pris la puissance à l’entrée du boitier original pour donner à l’Arduino et attaqué le software.

CAM00091
Comment contrôler la couleur exacte du ruban ?
Pour chaque couleur je fais varier l’intensité de la tension avec une valeur entre 0 et 255 par PWM (Pulse Width Modulation). C’est la technique qu’utilisait le microcontrôleur original et il s’avère que les transistors de puissance sont optimisés pour la PWM. Donc R,G,B, 3 fois 0-255 en combinatoire ça me donne théoriquement plus de 16 millions de couleurs. En pratique il y a sûrement des non linéarités dans le fonctionnement des LEDs et tout et tout mais on peut quand même faire de beaux dégradés et un paquet de couleurs différentes.
J’ai réutilisé des bouts de code Arduino que j’avais déjà fait, piqué un code javascript pour aider à sélectionner les couleurs et ça me donne une petite interface pour commander n’importe quelle couleur de la lampe via un navigateur web.
Je passe un moment aussi à implémenter des systèmes de dégradé automatique pour animer un peu le truc.

Choix de la couleur, choix des preset, un paramètre et le preset actuel

Choix de la couleur, choix des preset, un paramètre et le preset actuel

Choix de la couleur graphiquement

Choix de la couleur graphiquement

Je rebranche ensuite le capteur infrarouge et dépoussière une librairie que j’avais testé sur Arduino il y a longtemps pour décoder des télécommandes. J’arrive à associer à chaque bouton un nombre et ça me suffit pour me faire mes propres contrôles de la lampe.
Me voilà avec une lampe qui fonctionne sur Ethernet et via infrarouge, ou comment ajouter des fonctionnalités (ô combien essentielles) à l’appareil original.

 

Force Bleue !

Force Bleue !

Bonus inutile : le code de mon arduino

#include 
#include 
#include 

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x09, 0x36 };

const int ledRouge = 6;
const int ledVerte =  5;
const int ledBleue = 3;
int r = 0;
int g = 0;
int b = 0;
int preset = 0;
int phase = 0;
int delai = 20;
int count = 0;
int r2 = 0;
int g2 = 0;
int b2 = 0;

String readString = String(30);
IRrecv irrecv(2);
decode_results results;

EthernetServer server(80);

void color(int red, int green, int blue)
{
  analogWrite(ledRouge, red);
  analogWrite(ledVerte, green);
  analogWrite(ledBleue, blue);
}

void setup()
{
  pinMode(ledRouge, OUTPUT);
  pinMode(ledVerte, OUTPUT);
  pinMode(ledBleue, OUTPUT);
  color(0,0,0);
  randomSeed(analogRead(0));
  irrecv.enableIRIn();
  
  Ethernet.begin(mac);
  server.begin();
}

void loop()
{
  EthernetClient client = server.available();
  if (client) {  
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read()
        
        if(readString.length() < 100)
          readString.concat(c);
        
        if (c == '\n' && currentLineIsBlank) {    
          int Re = readString.indexOf("preset=");
          if(Re > 1)
          {
            if(readString.indexOf("smooth",0) > 1)
              preset = 1;
            if(readString.indexOf("fixed",0) > 1)
              preset = 0;
            if(readString.indexOf("wtf",0) > 1){
              preset = 2;
              count = 0;
            }
          }        
          Re = readString.indexOf("color=",0);
          if(Re > 1 && !preset)
          {
            char c[3];
            readString.substring((Re+6),(Re+8)).toCharArray(c,3);
            r = strtoul(c, 0, 16);
            readString.substring((Re+8),(Re+10)).toCharArray(c,3);
            g = strtoul(c, 0, 16);
            readString.substring((Re+10),(Re+12)).toCharArray(c,3);
            b = strtoul(c, 0, 16);
            
          }
          Re = readString.indexOf("delay=");
          if(Re > 1)
            delai = readString.substring((Re+6),(Re+9)).toInt();
          
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("");
          client.print("
Couleur : "); client.println("Smooth "); client.println("WTF Mode "); client.println("Fixe "); client.println("Delai Smooth : "); client.println("
"); client.print("Preset : "); switch(preset) { case 0: client.println("Fixe"); break; case 1: client.println("Smooth"); break; case 2: client.println("WTF Mode"); break; } break; } if (c == '\n') { currentLineIsBlank = true; } else if (c != '\r') { currentLineIsBlank = false; } } } delay(1); readString = ""; client.stop(); } switch(preset) { case 1: //smooth animSmooth(); break; case 2: wtfMode(); break; } color(r,g,b); if (irrecv.decode(&results)) { switch (results.value){ case 16748655 : //off r = 0; g = 0; b = 0; preset = 0; break; case 16752735 : //on r = random(0,2)*127; g = random(0,2)*127; b = random(0,2)*127; delai = 20; preset = 0; break; case 16724175 : //red r = 255; g = 0; b = 0; preset = 0; break; case 16713975 : //green r = 0; g = 255; b = 0; preset = 0; break; case 16716015 : //blue r = 0; g = 0; b = 255; preset = 0; break; case 16736415 : //smooth preset = 1; if(r > g && r > b) phase = 2; else if(g > r && g > b) phase = 1; else phase = 0; break; case 16769055 : //fade preset = 2; r2 = r; g2 = g; b2 = b; break; case 16720605 : //strobe delai = 1; preset = 2; break; case 16756815 : //eclairer if(delai > 30) delai += 5; if(delai > 50) delai += 45; delai += 5; if(delai > 200) delai = 200; break; case 16746615 : //assombrir if(delai > 30) delai -= 5; if(delai > 100) delai -= 45; delai -= 5; if(delai < 5) delai = 5; break; case 16720095 : //W preset = 0; break; } irrecv.resume(); } } void animSmooth() { if(phase == 0) { if(r > 0) r--; if(g > 0) g--; if(b < 255) b++; if(b == 255 && r == 0 && g == 0) phase = 1; } if(phase == 2) { if(g > 0) g--; if(b > 0) b--; if(r < 255) r++; if(r == 255 && g == 0 && b == 0) phase = 0; } if(phase == 1) { if(r > 0) r--; if(b > 0) b--; if(g < 255) g++; if(g == 255 && r == 0 && b == 0) phase = 2; } delay(delai); } void wtfMode() { if(r2 == r && g2 == g && b2 == b) { r2 = random(0,2)*127; g2 = random(0,2)*127; b2 = random(0,2)*127; } if(r-r2 < 0) r++; else if(r-r2 > 0) r--; if(g-g2 < 0) g++; else if(g-g2 > 0) g--; if(b-b2 < 0) b++; else if(b-b2 > 0) b--; delay(delai); }