Xylophone Tune Detector

All,

I am working on a project that, upon, playing a certain tune on a xylophone, causes and output to a servo or something similar (Relay, etc..)

I have built the device using small piezos that are epoxied to the back of the xylophone bars and then run to the A0-A4 inputs with a 1M resistor on each.

The problem is that the readings are extremely erratic. I have been messing with the threshold on the piezos which I have set at about 15 and a tone decay delay to take out false hits when a key is struck.

I can get it to work about 2 out of ten times (unacceptable). I need this to be bombproof and have the ability to loosen up the parameters if needed.

I know my sketch is correct, but I cannot for the life of me get it to work reliably. Any help is appreciated.

Maybe a different approach is needed, maybe an FFT?

Thoughts guidance help. Thanks

I can get it to work about 2 out of ten times (unacceptable)

but

I know my sketch is correct

but I cannot for the life of me get it to work reliably

If the sketch only works 2 out of ten times, it isn’t correct.
So post your code (in code tags </>).

Maybe a different approach is needed, maybe an FFT?

That’s orders of magnitude harder than what you’ve done so far.

Pete

Maybe your hardware isn't correct either. Post a picture of how you have attached the piezos.

A piezo has to bend/flex to be able to generate an output voltage. Simply epoxying them could inhibit that movement.

Cheap round piezos could have been randomly glued onto the brass disk in the factory. Some will have a positive spike when hit, others might have a (useless) negative spike. They should be measured/sorted.

Is the piezo wiring shielded, and how long is it (capacitance). Leo..

Here is my code. I believe that it is more of a hardware problem. The piezos are not being read each time they are struck, even when the threshold is down to below 10. The sketch does work. But it is not receiving the info correctly, that was the reason for my comment.

WAWA - The brass disks are epoxied pretty firmly onto the keys with the piezo. I will send a pic tomorrow when I can get to it. They are the cheap ones from Adafruit. I was hoping there was a more elegant solution. I have soldered about 1 foot of 20ga hook up wire to each of the leads and then have about 3 feet of 20ga bell wire that runs to the UNO. I have all the grounds wire nutted together and a single lead running to the breadboard GND. The + are on the BB in line with the 1M resistor and the wire to A0-A4.

//Xylophone Arduino project .When the right order of tones is played on a Xylophone, a 5v output is triggered to actuate a relay or locking device.
   
//By Bruce Hardy with ridiculous assistance from Jason Phillips
//Version 1


//define system states
#define START 0
#define STATE1 1
#define STATE2 2
#define STATE3 3
#define STATE4 4
#define STATE5 5
#define STATE6 6
#define DONE 7

#define LED_PIN 13
#define RINGDOWN_DELAY 100 //set to 1 second right now TWEAK THIS
          
boolean tripped[7]={0,0,0,0,0,0,0};
int i = 0;
int THRESHOLD = 5;

int system_state = START;
int timer_counter=0;

void setup() {
 pinMode(LED_PIN, OUTPUT);  
 Serial.begin(9600);
}


void loop() {
  //Detect hits
  for(i=0; i<7; i++){
    if(analogRead(i) >= THRESHOLD){
      tripped[i] = 1;
      timer_counter=0;
    }else{
      tripped[i] = 0;
    }
  }

if(timer_counter < 10000){
  timer_counter++; //same thing as timer_counter=timer_counter+1;
}else{
  timer_counter = 0;
  system_state=START;
  Serial.println("Timer Ran out, Setting state to START");
}


  //manage system state machine
  //NOTE we want the keys to be played in 4, 1, 2, 3, 2, 1, 0 order 
  switch(system_state){
    case START:
      if(tripped[0]==1){
        system_state = START;
        Serial.println("Moved from START to START");
      }
      if(tripped[1]==1){
        system_state = START;
        Serial.println("Moved from START to START");
      }
      if(tripped[2]==1){
        system_state = START;
        Serial.println("Moved from START to START");
      }
      if(tripped[3]==1){
        system_state = START;
        Serial.println("Moved from START to START");
      }
      if(tripped[4]==1){
        system_state = STATE1;
        Serial.println("Moved from START to STATE1");
      }
   
    break;

    case STATE1:
      if(tripped[0]==1){
        system_state = START;
        Serial.println("Moved from STATE1 to START");
      }
      if(tripped[1]==1){
        system_state = STATE2;
        Serial.println("Moved from STATE1 to STATE2");
      }
      if(tripped[2]==1){
        system_state = START;
        Serial.println("Moved from STATE1 to START");
      }
      if(tripped[3]==1){
        system_state = START;
        Serial.println("Moved from STATE1 to START");
      }
      if(tripped[4]==1){
        system_state = START;
        Serial.println("Moved from STATE1 to START");
      }
    break;

    case STATE2:
      if(tripped[0]==1){
        system_state = START;
        Serial.println("Moved from STATE2 to START");
      }
      if(tripped[1]==1){
        system_state = START;
        Serial.println("Moved from STATE2 to START");
      }
      if(tripped[2]==1){
        system_state = STATE3;
        Serial.println("Moved from STATE2 to STATE3");
      }
      if(tripped[3]==1){
        system_state = START;
        Serial.println("Moved from STATE2 to START");
      }
      if(tripped[4]==1){
        system_state = START;
        Serial.println("Moved from STATE2 to START");
      }
    break;

    case STATE3:
      if(tripped[0]==1){
        system_state = START;
        Serial.println("Moved from STATE3 to START");
      }
      if(tripped[1]==1){
        system_state = START;
        Serial.println("Moved from STATE3 to START");
      }
      if(tripped[2]==1){
        system_state = START;
        Serial.println("Moved from STATE3 to START");
      }
      if(tripped[3]==1){
        system_state = STATE4;
        Serial.println("Moved from STATE3 to STATE4");
      }
      if(tripped[4]==1){
        system_state = START;
        Serial.println("Moved from STATE3 to START");
      }
    break;

    case STATE4:
      if(tripped[0]==1){
        system_state = START;
        Serial.println("Moved from STATE4 to START");
      }
      if(tripped[1]==1){
        system_state = START;
        Serial.println("Moved from STATE4 to START");
      }
      if(tripped[2]==1){
        system_state = STATE5;
        Serial.println("Moved from STATE4 to STATE5");
      }
      if(tripped[3]==1){
        system_state = START;
        Serial.println("Moved from STATE4 to START");
      }
      if(tripped[4]==1){
        system_state = START;
        Serial.println("Moved from STATE4 to START");
      }
    break;

    case STATE5:
      if(tripped[0]==1){
        system_state = START;
        Serial.println("Moved from STATE5 to START");
      }
      if(tripped[1]==1){
        system_state = STATE6;
        Serial.println("Moved from STATE5 to STATE6");
      }
      if(tripped[2]==1){
        system_state = START;
        Serial.println("Moved from STATE5 to START");
      }
      if(tripped[3]==1){
        system_state = START;
        Serial.println("Moved from STATE5 to START");
      }
      if(tripped[4]==1){
        system_state = START;
        Serial.println("Moved from STATE5 to START");
      }
    break;

    case STATE6:
      if(tripped[0]==1){
        system_state = DONE;
        Serial.println("Moved from STATE5 to DONE");
      }
      if(tripped[1]==1){
        system_state = START;
        Serial.println("Moved from STATE6 to START");
      }
      if(tripped[2]==1){
        system_state = START;
        Serial.println("Moved from STATE6 to START");
      }
      if(tripped[3]==1){
        system_state = START;
        Serial.println("Moved from STATE6 to START");
      }
      if(tripped[4]==1){
        system_state = START;
        Serial.println("Moved from STATE6 to START");
      }
    break;

    case DONE:
      //Notes played! Actuate things here
      digitalWrite(LED_PIN, HIGH);
      digitalWrite(LED_PIN, LOW);
      {
        system_state = START;
      }
      
    break;
  }

  delay(RINGDOWN_DELAY); //Adjust to let ringing on keys stop before continuing
}
/code]

A reading of just 15 is way too small, you should get at least 2V from the sensor and many times greater than 5V. So you need to look to your sensor mounting. You need to look at the waveform you get on an oscilloscope to see what you are getting. Are you sure the resistor is across the sensor? The other thing is the polarity of the output, the biggest spike depends on which side you hit it. I am assuming the red wire is to the input and the black to the ground.

The code also looks complex for what you are trying to do and the dead time is way too long, it could be you are missing hits because of this. Don't do any serial printing inside time critical code because it will slow things down quite a bit.

Thanks Mike,

I forgot to change my comments on the Ringdown delay, it is not really one second I have it at 100ms. I do have the black to GND and the red to power, I will double check the resistor set up and make sure it is across. I ordered a few of the enclosed small piezos as I feel the epoxy is retarding the ability of the piezo to vibrate.

Great note on the Serial print instructions, I was not sure how much time it took, but it makes sense that I am missing some cycles.

I looked at several different ways of coding, but felt that the state machine made sense to me logically. Any other ideas are very welcomed.

I will try to upload a view of the mounting and the BB. Thanks again.

I would use the millis timer and not use your own in a state machine. What I would do when you detect a signal over the threshold is to mark it with a flag ( boolean variable ) and not look at that sensor again until a certain time has elapsed. BUT you still keep looking at the others.

What happens when you tap the sensor directly you should get a good size pulse. I am not sure how much impact you are getting from your setup. The other thing is that while the xylophone block vibrates that is also transmitting vibrations to the sensor. I am assuming that you do have a xylophone ( wooden blocks ) and not a glockenspiel ( metal blocks ). As I said the reading you are getting is very small. Here is the oscilloscope trace from a transducer that is just tapped with the finger. You can see the voltage generated is in excess of 30V, so it should be much better than you are getting.

DS1Z_QucikPrint4.png

Thanks again Mike,

I am going to get back to it today. I think I need to take a look at the resistors, I can't see them now, but I don't think I have them across the piezo, but inline with the +. I don't think I would make that mistake, but... I don't have anything to read the output of the piezos, I was just adjusting the threshold up and down to see if I could get a consistent strike of the element. It is a Xylophone and not a Gspiel. I have never used the uncased piezos and have used the enclosed ones with much success on a similar project. I will post what I find after making some changes and see if i am closer to an answer.

Attached are two pics of my bb. The white wire on the far right is the combined (wire nutted) grounds of all five piezos. I think it is right, if so then it must be the cheap piezos and the mounting (epoxy) that is causing the erratic reading.

Hi, I think what was needed was a picture of the assembly that has the piezo units attached?

Thanks.. Tom... :)

Gotcha,

Wanted to get as much info out there as possible. Hadn’t made it out to the project yet. Picture of the mounting attached.

Did you ever try reversing the polarity of the piezo connections as suggested in reply #4?

I would glue the sensor on the flat part of the block to get more mechanical coupling. I have used impact adhesive and hot melt glue for this with good results, however I have not used epoxy.

The polarity of the wires looks right from my experience.

Until you get out of the trouble zone, your sketch should be a simpler one, only read one block.

Yes, I tried reversing all of them. Same issue. erratic behavior, non consistent reports.

I pared the sketch down to this:

//define system states
#define START 0

#define LED_PIN 13
#define RINGDOWN_DELAY  100 // TWEAK THIS
            
boolean tripped[7]={0,0,0,0,0,0,0};
int i = 0;
int THRESHOLD = 50;

int system_state = START;
int timer_counter=0;

void setup() {
 pinMode(LED_PIN, OUTPUT);  
 Serial.begin(9600);
}


void loop() {
  //Detect hits
  for(i=0; i<7; i++){
    if(analogRead(i) >= THRESHOLD){
      tripped[i] = 1;
      timer_counter=0;
    }else{
      tripped[i] = 0;
    }
  }





  //manage system state machine
  //NOTE we want the keys to be played in 4, 1, 2, 3, 2, 1, 0 order 
  switch(system_state){
    case START:
      if(tripped[0]==1){
        system_state = START;
        Serial.println("Key 1 working");
      }
      if(tripped[1]==1){
        system_state = START;
        Serial.println("Key 2 working");
      }
      if(tripped[2]==1){
        system_state = START;
        Serial.println("Key 3 working");
      }
      if(tripped[3]==1){
        system_state = START;
        Serial.println("Key 4 working");
      }
      if(tripped[4]==1){
        system_state = START;
        Serial.println("Key 5 working");
      }
   
    break;
  }

  delay(RINGDOWN_DELAY); //Adjust to let ringing on keys stop before continuing
}
/code]

Why not just look at one key, as I suggested? What you have there is not a debug sketch. You should also be reading values and looking at them, instead of testing them against a threshold. Until things work.

Got it. This should do it right?

const int knockSensor = A0; 
const int threshold = 100; 


// these variables will change:
int sensorReading = 0;      


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

void loop() {
  // read the sensor and store it in the variable sensorReading:
  sensorReading = analogRead(knockSensor);
  Serial.println(sensorReading);

  
  }/code]

Yes, but when I expect a ton of values to be printed, I separate them with spaces rather than newlines, so I don't have to scroll as much. But that is a minor quibble. What results are you seeing?

I am away from the project until tomorrow morning. I will post what I read tomorrow. Thanks for the help so far.