Go Down

Topic: primo esperimento con arduino e i piezo, consigli (Read 1 time) previous topic - next topic

mantissa00

Jul 26, 2010, 05:09 pm Last Edit: Jul 26, 2010, 05:11 pm by mantissa00 Reason: 1
ciao
questo è il mio primo post, spero di non dire cavolate
sto provando a fare una drum machine con arduino e i piezo

devo leggede dati da un sensore piezo e mandarli in seriale a puredata. su puredata vorrei leggere un valore che sarà l'insensità di un suono

ho trovato vari progetti simili
http://www.spikenzielabs.com/SpikenzieLabs/DrumKitKit.html
http://todbot.com/blog/2006/10/29/spooky-arduino-projects-4-and-musical-arduino/
http://drummaster.digitalcave.ca

ma un po' non sono riuscito a capire benissimo il codice, un po' vorrei cercare di fare un progetto da zero, un po' non mi sembrano tanto più precisi del metodo che ho trovato

è abbastanza empirico,
e funziona abbastanza bene, volevo sapere cosa ne pensate e se avete qualche consiglio da darmi.

come schematiche per il pizeo ho adottato lo schema di todbot:
piezo con resistenza da 1MOhm e un diodo
http://todbot.com/blog/wp-content/uploads/2006/10/arduino_midi_schematic.png

il problema dei piezo è che quando vengono colpiti danno vari valori,
che oscillano su e giù fino a stabilizzarsi sullo zero

non sono una cima in programmazione, e ho adottato questo metodo:
leggo i valori dal sensore e li metto dentro un array.
ogni loop prendo il valore più alto e controllo se l'array è pieno di zeri.
se l'array è pieno di zeri significa che il segnale del piezo si è stabilizzato, e la vibrazione è finita.
posso prendere il valore più alto e mandarlo in seriale.

questo è il codice:
Code: [Select]

#define MIN 20
#define NUMS 250
int vals[NUMS];
int maxVal = 0;
int index = 0;
boolean array_is_zero = true;

void setup() {
 Serial.begin(9600);
 Serial.println("Hello..");
 
 // array init to zero
 for(int i=0; i<NUMS; i++) {
   vals[i]=0;
 }
}

void loop() {
 // read piezo
 int val = analogRead(0);
 
 // update maxval
 if(val>maxVal){
   maxVal = val;
 }
 
 //fill vals
 vals[index]=val;
 if(index>=NUMS-1)index=0;
 else index++;

 // if oscillating is finished, print maxval
 if( checkZero(vals) && maxVal>MIN) {
   Serial.println( maxVal );
   maxVal=0;
   delay(10);
 }
}

boolean checkZero(int array[]) {
 for(int i=0; i<=NUMS-1; i++) {
   if(array[i]>=MIN)
     return false;
 }
 return true;
}


ora, il problema è che ogni tanto mi manda due numeri quando faccio un solo battito.
secondome il motivo è che la vibrazione del piezo ancora non è finita,
per cercare di ovviare ho:
- aumetato la grandezza dell'array (ma anche con valori molto alti tipo 400 a volte da ancora lo stesso problema. abbassando a 50 il problema si moltiplica e vengono stampati un sacco di numeri)
- messo un limite minimo (#define MIN 20) per fare il controllo sullo zero
- inserito delay(10)

delay(10) e aumentare la grandezza dell'array mi sembrano cose un po' quick and dirty, perchè se al posto di avere 1 piezo ne ho 4.. sono fregato. insomma non è scalabile.

so che al posto dei valori dell'array potrei usare un timer con i millis.. è meglio? che mi consigliate?

nel progetto http://drummaster.digitalcave.ca/design.jsp usa un filtro hardware con diodi e capacitori, ma non ho capito come funziona..

mantissa00

effettivamente la soluzione dell'array è poco scalabile,
ora ho implementato un counter con un index e un limite,
ogni MAXR secondi si legge il valore più alto, se è maggiore del threshold viene stampato via seriale.

il problema è che usando tuti e 6 gli ingressi analogici certe volte accumula del delay,
penso sia dovuto alla scarsa capacità computazionale?

ecco il codice aggiornato.
spero serva a qualcuno, e se c'è qualche palese errore qualcuno me lo faccia notare!
Code: [Select]


#define MIN 20
#define MAXR 500

int maxVal[6];
   /////////////////////////////////////////////int repetition[6];

int _repetition;

void setup() {
 Serial.begin(9600);
 Serial.println("Hello..");

 //inits arrays
 for(int i=0; i<6; i++) {
   maxVal[i]=0;
   /////////////////////////////////////////////repetition[i]=0;
 }
}

void loop() {
 _repetition++;
 for(int i=0; i<6;i++) {
   // read piezo
   int val = analogRead(i);

   // update maxval
   if(val>maxVal[i]){
     maxVal[i] = val;
   }

   /////////////////////////////////////////////repetition[i]++;

   // if oscillation is finished, print maxval
   /////////////////////////////////////////////if( repetition[i]>MAXR) {
   if( _repetition>MAXR) {
     if(maxVal[i]>MIN) {
       Serial.print(i);
       Serial.print(" ");
       Serial.println(maxVal[i]);

       //delay(10);
     }
   /////////////////////////////////////////////repetition[i]=0;
     _repetition=0;
     maxVal[i]=0;
   }
 }
}


il motivo dei commenti è che effettivamente non serve mantenere un counter di ogni sensore..

se qualcuno ha qualche consiglio su possibili ottimizzazioni...

Go Up