Two piezo elements: detect if "knock" is closer to A or B

Hi,

Using two piezo elements, I am trying to detect if a "knock" is closer to the first, or the second piezo element. Both are 2 meters apart from each other and attached to a table. Any time I knock with my finger on the table and use the analogRead function, I can tell both register the knock just fine.

However, it looks like the analogRead function takes a lot of time to return a value. This means I am not able to tell which of the two piezo elements registered the knock first and thus cannot tell if the knock was closer to one or the other.

I read about the AnalogReadFast library which can speed up the analogRead method a lot, but it does not seem to support my Arduino Nano Every (because it runs on mega avr architecture and not avr or samd). I also read an article about lowering the prescale factor but that throws errors on my board too.

Does anyone know what I need to get around these limitations are any other way for me to tell if the "knock" was closer to the first or the second piezo element? Maybe there is a way to process the output as a digital value somehow and use (the much faster) digitalRead instead?

const byte sensor1 = A1;
const byte sensor2 = A2;
int sensor1threshold = 0;
int sensor2threshold = 0;

unsigned long sensor1Time = 0;
unsigned long sensor2Time = 0;
unsigned long lastDetection = 0;

void setup() {

  Serial.begin(9600);
  
  Serial.println("Determining threshold");

  delay(1000);

  // Determine threshold for Sensor 1
  for (int i=0; i < 100; i++)
  {
    int tempReading = analogRead(sensor1);
    if (tempReading > sensor1threshold)
    {
      sensor1threshold = tempReading + 1;
    }
    delay(10);
  }
  Serial.print("Sensor 1 threshold: ");
  Serial.println(sensor1threshold);
  
  // Determine threshold for Sensor 2
  for (int i=0; i < 100; i++)
  {
    int tempReading = analogRead(sensor2);
    if (tempReading > sensor2threshold)
    {
      sensor2threshold = tempReading + 1;
    }
    delay(10);
  }
  Serial.print("Sensor 2 threshold: ");
  Serial.println(sensor2threshold);

  Serial.println("Start");
  
}

void loop() {

  // Get reading from sensors
  int sensor1Reading = analogRead(sensor1); // <--- Note, this line takes ~100ms to process, which is 
  int sensor2Reading = analogRead(sensor2);

  // Save current time
  unsigned long currentTime = micros();

  // Detect if either sensor passed its threshold value
  if (sensor1Reading > sensor1threshold)
  {
    sensor1Time = currentTime;
  }
  if (sensor2Reading > sensor2threshold)
  {
    sensor2Time = currentTime;
  }

  // Ensure to filter out echos
  if (lastDetection < currentTime)
  {
    
    if (sensor1Time + 1000 > currentTime && sensor2Time + 1000 > currentTime)
    {
      // Pretend as if this detection happened 0.5 seconds in the future, so "echos" won't trigger another knock
      lastDetection = currentTime + 500000;

      // Check where the ball landed
      if (sensor1Time < sensor2Time)
      {
        Serial.print("CLOSER TO SENSOR 1");
      }
      if (sensor1Time > sensor2Time)
      {
        Serial.print("CLOSER TO SENSOR 2");
      }
      if (sensor1Time == sensor2Time)
      {
        Serial.print("EQUAL DISTANCE    ");
      }
      Serial.print(" - ");
      Serial.print(sensor1Time);
      Serial.print(" - ");
      Serial.print(sensor2Time);
      Serial.println();
      
    }
    
  }

  delay(1);
}

Note: I do realize that the speed of sounds through wood is much higher than through air. Even if the analogRead function can get a value in 10ms, it might still be too slow for my intended purposes. However, I might experiment some with using rubber between the piezo elements and the table to slow down the waves, but am not yet sure how well it would be able to register the knock.

Enabling ADC Free Running mode is something else I have tried, but which did not seem to be supported by my Arduino Nano Every.

For AVR based Arduinos, the default time to read the ADC is about 110 microseconds.

At 4000 m/s (wood and some other solid materials), sound travels about 0.45 m in that time, and your project requires taking measurements on two channels and comparing them. Although the ADC can run many times faster, using it for this purpose is not very practical.

It is possible to use digital inputs and interrupts, but that introduces different complications. Most people would use a dedicated circuit (amplifier and level detector).

Many things related to timers work a lot different in the 0-series AVR chips, like the ATMega4809 used in the Nano Every.

The 4809 has three type B timers, each of which offer input capture functionality. As long as the piezo signal is strong enough to trigger an interrupt (i.e. reaches at least 0.6*Vcc) you can do that.

Connect the peizo to two input pins; connect the pin rising interrupt to the event capture of the timer (use the event subsystem), and measure away.

For maximum resolution, set the timer to system clock input without prescaler.

Getting the two timers to start at the same clock cycle will be impossible but if you start them one after the other you will always have the exact same startup delay for the second one (2-4 clock cycles I expect), and thus can compensate for that.

For details, refer to the datasheet.

External SPI ADCs are available that can be read much faster - however you still have to process the data
as well as read it, and I suspect this is too compute intensive for a lowly microcontroller and something
closer to a DSP chip in capabilities is needed.

Thank you all so far, this has given me enough options to research.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.