Multi-pin analogRead() - piezo for eDrum

My son and me are trying to build a eDrum using Arduino UNO. We have 3 piezo sensor discs, each of which can be read as expected using analogRead() individually, but having difficulty in reading them simultaneously (rather sequentially).

Have read and I think understood the part that the UNO has a single 10-bit SAR-type ADC that takes 13 clock-cycles to produce 10-bit resolution output, for each pin. Also understood that the S/H capacitor needs a finite bit of time to charge. I have introduced delayMicroseconds(20). The analog value read is then compared against a Threshold (values tried from 20-200), and only if higher than Threshold is the number 1, 2 or 3 printed on Serial output. The Serial port baudRates tried are 9600, 19200, 115200 and the observation is unimpacted, i.e. whenever I hit the piezo disc connected to pin A0, I notice that both 1 and 2 are printed (almost 90% of the times). When I hit piezo disc connected to ping A2, I notice that 90% of the time, I get 3 printed. Of course, because there is no debounce logic, I actually get output like:

when disc connected to A0:

1 2 1 2 1 2 1 2

where-as, I'd expect to see only 1.

when disc connected to A2:

3 3 3 3 1 3 1 3

where-as, I'd expect to see only 3.

Finally, I modified the code to try to introduce some crude de-bounce logic using averaging (3 rounds). Also I tried using Faster ADC mechanism found here. AFAIU, it modifies the ADC prescaler and sacrifice the resolution, for faster ADC read.

Code:

#include <Albert.h>

const int BaudRate = 19200;
const int Threshold = 150;
const int AvgLoopCt = 3;

int sensVal1 = 0;
int sensVal2 = 0;
int sensVal3 = 0;
int loopCount = 0;

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

void loop() {
  if (loopCount < AvgLoopCt) {
    sensVal1 += analogReadFast(A0, 2);
    delayMicroseconds(10);
    sensVal2 += analogReadFast(A1, 2);
    delayMicroseconds(10);
    sensVal3 += analogReadFast(A2, 2);
    delayMicroseconds(10);
    loopCount++;
  }
  else {
    if ((sensVal1 / AvgLoopCt) >= Threshold) {
      Serial.print("1 ");
      sensVal1 = 0;
    }
    if ((sensVal2 / AvgLoopCt) >= Threshold) {
      Serial.print("2 ");
      sensVal2 = 0;
    }
    if ((sensVal3 / AvgLoopCt) >= Threshold) {
      Serial.print("3 ");
      sensVal3 = 0;
    }
    loopCount = 0;
  }
}

Would appreciate any help in trying to understand what the problem is. Kindly note that, instead of using the "Albert.h" (Fast ADC) library, using the standard inbuilt readAnalog(), the results aren't much different.

The circuit is connected on a breadboard and I've ripped apart the circuit assembly several times and reconnected, but that hasn't helped.

instead of delay - try reading the pin twice

Piezo sensors can by high impedance, add 100nF to ground for each of them (although this may
reduce the bandwidth too much). Such a capacitor is plenty big enough to charge the ADC sample/hold
capacitor fast enough.

But a piezo generates AC.

And the first hit can be a negative voltage, depending how/where the piezo is mounted.
Not every piezo generates a positive voltage when hit on the brass side.
Positive or negative depends on how the piezo was dropped on the brass disc before gluing it down.

The typical 1Meg load resistor can be lowerd to e.g. 100k for drum use.
Are the piezos mechanically isolated from each other.
Don't worry that much about delay.
You can read each piezo many times (and you should) before you notice a delay in playing.
If you use a peak-hold in your sketch, then you also have intensity information.
Leo..

Knock sketch I wrote some time ago.
It might give you some ideas.
Leo..

// knock sensor/alarm
// Piezo, with 1Megohm load resistor across, connected to A0 and ground
// optional 5volt buzzer on pin 13

int threshold = 100; // alarm threshold from 1 (very sensitive) to 1022 <<<<<<<<
int alarmDuration = 100; // alarm duration in milliseconds <<<<<<<<

const byte piezoPin = A0;
int rawValue; // raw A/D readings
int piezoValue; // peak value
const byte onboardLED = 13; // onboard LED and/or buzzer

void setup() {
  //analogReference(INTERNAL); // remove this line if too sensitive
  Serial.begin(115200); // serial monitor for raw piezo output
  pinMode (onboardLED, OUTPUT);
}

void loop() {
  // reset
  piezoValue = 0;
  // read
  for (int x = 0; x < 250; x++) { // multiple A/D readings
    rawValue = analogRead(piezoPin);
    if (rawValue > piezoValue) {
      piezoValue = rawValue; // store peaks
    }
  }
  // print
  if (piezoValue > 0) {
    Serial.print(F("Piezo value is "));
    Serial.println(piezoValue);
  }
  // action
  if (piezoValue > threshold) {
    Serial.print(F("Knock was over the threshold of "));
    Serial.println(threshold);
    digitalWrite (onboardLED, HIGH);
    delay(alarmDuration);
    digitalWrite (onboardLED, LOW);
  }
}

Thanks @Wawa.

Wawa:
The typical 1Meg load resistor can be lowerd to e.g. 100k for drum use.
Are the piezos mechanically isolated from each other.

Yes, the piezos are (even at this prototype stage) all mounted on medium density foam pads, that are normally placed at a gap of 3-4 inches. The piezo discs are not yet mounted on metal plate but directly "stitched down" to the foam pads.

In fact, I forgot to mention that even if I disconnect 2 of the other piezes (on pin A1, A2), and hit only the one connected to A0, I still see patterns like:

1 2 1 2 1 2 1 2

which is what beats me.

Individually the piezo reading is perfect, and in fact, I am able to determine reasonable velocity information as well (as low, medium, high... a resolution that is good enough for the eDrums). The issue really is with the "false triggering" of pad (rather piezo) that has not been hit. That is absolutely unacceptable for eDrums. Such false triggers should be less than 0.1%.

MarkT:
Piezo sensors can by high impedance, add 100nF to ground for each of them (although this may
reduce the bandwidth too much). Such a capacitor is plenty big enough to charge the ADC sample/hold
capacitor fast enough.

Thanks @MarkT. Will try adding some 100nF ceramic disc capacitors and see if that helps. However, doesn't the ATmega already have similar capacitance for each pin, built into the die ?

knut_ny:
instead of delay - try reading the pin twice

Doesn't help my cause. I still get the false triggers.

falcon74:
Thanks @MarkT. Will try adding some 100nF ceramic disc capacitors and see if that helps. However, doesn't the ATmega already have similar capacitance for each pin, built into the die ?

Certainly not. 100nF is enormous load for a logic pin. Pins have perhaps 5pF or so.