Tag

, , , , , , , ,

Una delle applicazioni più divertenti che si possono realizzare con Arduino è un rilevatore di suoni. Il principio su cui si basa questo studio è piuttosto semplice: molti componenti possono funzionare “al contrario”.

Infatti, se è vero che un piezo elettrico sollecitato dalla corrente vibra, generando un suono – è anche vero che, sollecitato da una vibrazione, questo componente genererà una piccola tensione: in questo senso, il piezo è in buona sostanza anche un “rilevatore di suoni”. Naturalmente molto dipende dalla sensibilità del componente, dal momento che la corrente generata sarà molto piccola. Tuttavia, è possibile ottenere buoni risultati anche con un componente di base, di quelli per intenderci che si trovano in ogni kit Arduino.

Proviamo allora ad accendere un LED battendo semplicemente le mani!

Prima di tutto, guadiamo come montare il piezo. Un piezo di solito ha 2 pin, che vengono collegati con il + ad un pin analogico ed il – alla terra. A questo punto, per farlo suonare, è sufficiente impostare il pin + ad HIGH e poi a LOW molto velocemente – anche migliaia di volte al secondo: in questo modo facciamo vibrare il piezo, e in base al numero di vibrazioni che impostiamo (la frequenza), si genererà un suono più alto o più basso.

Per il nostro studio dobbiamo montarlo in maniera leggermente differente: per farlo, tutto quello che ci occorre è una resistenza da 1M Ohm.

Schema rilevatore di suoni

Schema rilevatore di suoni

Una volta sistemato il piezo elettrico sulla breadboard, colleghiamo il – alla terra e il + prima al pin analogico A0 e poi, tramite la resistenza da 1M Ohm, alla terra anch’esso. Andiamo quindi a scrivere il nostro sketch.

void setup() 
{
  Serial.begin(9600); // Imposto la connessione seriale
  pinMode(ledPin, OUTPUT); // Dichiaro ledPin come OUTPUT
}

void loop() 
{
  // Leggo il valore analogico (da 0 a 1023) del sensore
  float valoreSensore = analogRead(tocPin); 

  // Se il valore supera la soglia
  if (valoreSensore >= soglia) 
  {
    Serial.println("Toc! Toc!"); // Stampo la scritta
    digitalWrite(ledPin, HIGH); // Accendo il LED
    delay(100); // Aspetto per non sovraccaricare il buffer della porta seriale
  }
  else {
    // Nessun suono, spengo il LED
    digitalWrite(ledPin, LOW);
  }
}

Niente di complicato, come possiamo vedere. Il codice legge il valore analogico del piezo collegato sul pin A0, e se il suo valore (0-1023) supera la soglia prestabilita, viene considerato un suono abbastanza forte da accendere il LED. Per conferma, stampiamo la scritta “Toc! Toc!” sul monitor seriale. Toccate il piezo con la punta di una penna, oppure battete forte le mani e il LED si accenderà! Perfetto, avete realizzato il vostro primo rilevatore di suoni.

Un esperimento divertente

Proviamo adesso a creare qualcosa di più divertente Non sarebbe molto bello se il LED si accendesse solo quando “picchiettiamo” una determinata sequenza? Pensiamo alla più classica delle bussate: ta-tata, ta-ta, ta-tà. D’accordo, non so come si scrive, ma credo si capisca. Se volessimo la partitura, sarebbe simile a questa:

Partitura toc-toc

Partitura toc-toc

Per fare in modo che il LED si accenda solo quando viene picchiettata la giusta sequenza non dobbiamo fare altro che registrare ogni battito, e calcolare la distanza tra un battito e il precedente: se il “ritmo” sarà corretto, accenderemo il LED. Cominciamo con il creare l’elemento che ci permetterà di salvare e controllare la sequenza dei battiti: un array.

double elenco[7]; // Sette battiti sono la sequenza che attiva il LED (0-6)

Dichiarare un array può sembrare difficile; in realtà bisogna solo fare molta attenzione: elenco contiene 7 battiti, ma per leggere o salvare un valore nell’array, bisogna partire da 0 e contare fino a 6. Stranezze dell’informatica. Una volta preparato il nostro array, vediamo come utilizzarlo per salvare i battiti.

if (valoreSensore >= soglia) 
{
  Serial.println("Toc! Toc!"); // Stampo la scritta
  registraBattito(); // Registro in elenco il momento in cui viene avvertito il battito
  valutaSequenza(); // Controllo se la sequenza e' completa
  delay(100); // Aspetto per non sovraccaricare il buffer della porta seriale
 }

Utilizziamo la funzione registraBattito() per salvare il momento in cui viene avvertito il battito: ci servirà per fare poi un confronto tra tutti i battiti e capire se sono stati fatti con il ritmo giusto.

void registraBattito()
{
  double time = millis();
  lastSound = millis(); // Ci servirà per azzerare l'elenco se la sequenza viene interrotta
  if ( elenco[0]==0 ) { elenco[0] = time; return; }
  if ( elenco[1]==0 ) { elenco[1] = time; return; }
  if ( elenco[2]==0 ) { elenco[2] = time; return; }
  if ( elenco[3]==0 ) { elenco[3] = time; return; }
  if ( elenco[4]==0 ) { elenco[4] = time; return; }
  if ( elenco[5]==0 ) { elenco[5] = time; return; }
  if ( elenco[6]==0 ) { elenco[6] = time; return; }
}

Il codice è abbastanza triviale ma serve allo scopo. Ogni volta che viene avvertito un battito, il codice salva nel primo spazio disponibile dell’array il momento in cui è stato registrato. Dopo aver registrato ogni nuovo battito, il codice controlla se la sequenza è completa. Se lo è, calcola le distanze tra un battito e il precedente. Dato che è difficile avere la precisione di un metronomo, per comodità è stata aggiunta al “ritmo” anche una certa tolleranza, qui è 100 ms.

void valutaSequenza()
{
  // Se c'e' il numero corretto di battiti registrati
  if ( elenco[6] > 0 )
  {
   // Verifica il "ritmo" della sequenza di battiti
   if ( elenco[1]-elenco[0] >= 400 && elenco[1]-elenco[0] <= 600 ) // 500 ms
   if ( elenco[2]-elenco[1] >= 150 && elenco[2]-elenco[1] <= 350 ) // 250 ms
   if ( elenco[3]-elenco[2] >= 150 && elenco[3]-elenco[2] <= 350 ) // 250 ms
   if ( elenco[4]-elenco[3] >= 400 && elenco[4]-elenco[3] <= 600 ) // 500 ms
   if ( elenco[5]-elenco[4] >= 900 && elenco[5]-elenco[4] <= 1100 ) // 1000 ms
   if ( elenco[6]-elenco[5] >= 400 && elenco[6]-elenco[5] <= 600 ) // 500 ms
     success();

  // Resetto l'elenco ogni volta che ho registrato 7 colpi
   resetta();
  }
}

Il valore, indicato in ms, si ricava dalla durata delle note nella partitura: la prima nota dura 500ms, la seconda 250ms, ecc. Se la distanza tra tutti i battiti è corretta, allora la sequenza è stato eseguito con il giusto ritmo, perciò possiamo far lampeggiare il LED:

void success()
{
  // Sequenza corretta
  Serial.println("SEQUENZA CORRETTA!!");

  // Lampeggia 3 volte il LED
  for ( int n=0; n<3; n++ )
  {
    digitalWrite(ledPin,HIGH);
    delay(150);
    digitalWrite(ledPin,LOW);
    delay(150);
  } 
}

Nel caso la sequenza sia sbagliata, o non ci siano battiti per un certo numero di secondi, resettiamo il nostro array per permettere ad Arduino di registrare una nuova sequenza. Per farlo utilizziamo la funzione che imposta di nuovo a 0 tutti i valori dell’array.

void resetta()
{
  Serial.println("Resetto.");
  for ( int n=0; n<=6; n++ ) { elenco[n] = 0; }
}

Per fare in modo che una sequenza interrotta venga resettata dopo alcuni secondi di silenzio, è sufficiente richiamare la funzione resetta() alla fine del loop().

if ( elenco[0] && millis()-lastSound > 3000 ) { resetta(); }

Non è il codice più elegante che sia mai stato scritto, ma per una sequenza di pochi battiti può essere sufficiente. Possiamo battere le mani o picchiettare il nostro piezo con una penna per ricreare la sequenza corretta: se il ritmo sarà quello giusto, vedrete il LED lampeggiare!

Download: sound_detect_suite.zip

Annunci