Friday, November 7, 2014

How to Avoid False Positives with a High Sensitivity Piezo Vibration Sensor

Thanks for all the interest and comments in my previous blog on the High Sensitivity Vibration Sensor. In this previous project I described how to use a piezo element, an op amp and comparator to create a high sensitivity vibration sensor. Based on the great level of interest in this project I have created an advanced vibration sensor that uses the same design and builds upon it. One of the challenges with vibration sensors is screening out spurious events such as bumps that can lead to false positives. In this project the sketch running on the Arduino Uno watches for vibration events but only triggers if it sees 5 vibration events within a 5 second period. So if it gets 3 events and then none for a while it will forget those 3 events. Only if it gets 5 or more within 5 seconds will the alarm trigger. This effectively screens out spurious bumps and fires on persistent vibration events. This can be useful for a variety of applications where was is sought is the ability to detect vibration rather than a single bump. The values for the number of events (5 in my sketch) and period of time (5 seconds) are configurable by changing the values at the top of the sketch for your project.

You can find the sketch I used on the Arduino Uno below:

#define VIBRATION_SENSOR_DIGITAL_INPUT_PIN 10
#define VIBRATION_SENSOR_DIGITAL_OUTPUT_PIN 8

#define VIBRATION_SAMPLE_ARRAY_SIZE 100

// if we 5 or more vibration events over a five second period then a vibration alarm is triggered
#define VIBRATION_EVENTS_ALARM_THRESHOLD_COUNT 5
#define VIBRATION_EVENTS_ALARM_THRESHOLD_PERIOD_MILLIS 5000

long vibrationEvents[VIBRATION_SAMPLE_ARRAY_SIZE];
int vibrationEventIndex;

void setup(){
  Serial.begin(19200);
  
  pinMode(VIBRATION_SENSOR_DIGITAL_INPUT_PIN, INPUT);
  pinMode(VIBRATION_SENSOR_DIGITAL_OUTPUT_PIN, OUTPUT);
  
  vibrationEventIndex = 0;
  clearVibrationEvents();
}

void loop(){
  if(digitalRead(VIBRATION_SENSOR_DIGITAL_INPUT_PIN) == HIGH){
    long currentMillis = millis();
    addVibrationSample(currentMillis);
    if(isVibrationAlarmTiggered()){
      triggerAlarm();
      Serial.println(String(millis()) + "\t ALARM");
    }
    delay(100); // wait for current vibration shock to subside
  }
}

void addVibrationSample(long vibrationMillis){
   vibrationEvents[vibrationEventIndex++] = vibrationMillis;
   if(vibrationEventIndex >= VIBRATION_SAMPLE_ARRAY_SIZE){
     vibrationEventIndex = 0; // wrap vibration sample index around when we get to end of sample array
   }
}

boolean triggerAlarm(){
  digitalWrite(VIBRATION_SENSOR_DIGITAL_OUTPUT_PIN, HIGH);
  delay(1000);
  digitalWrite(VIBRATION_SENSOR_DIGITAL_OUTPUT_PIN, LOW);
  clearVibrationEvents();
}

void clearVibrationEvents(){
  for(int i = 0; i < VIBRATION_SAMPLE_ARRAY_SIZE ; ++i){
    vibrationEvents[i] = -1;
  }
}

boolean isVibrationAlarmTiggered(){
  long thresholdMillis = millis() - VIBRATION_EVENTS_ALARM_THRESHOLD_PERIOD_MILLIS;
  if(thresholdMillis < 0) thresholdMillis = 0;
  int numVibrationsSinceThreshold = 0;
  for(int i = 0; i < VIBRATION_SAMPLE_ARRAY_SIZE ; ++i){
    if(vibrationEvents[i] >= thresholdMillis){
      ++numVibrationsSinceThreshold;
    }
  }
  
  Serial.println(String(millis()) + "\t# events: " + String(numVibrationsSinceThreshold));
  boolean alarmTriggered = false;
  if(numVibrationsSinceThreshold >= VIBRATION_EVENTS_ALARM_THRESHOLD_COUNT){
    alarmTriggered = true;
  }
  
  return alarmTriggered;
}



Below is an example of the output on the Arduino IDE console when the Arduino Uno is running off a USB cable:

9018 # events: 1
9703 # events: 2
10330 # events: 3
10935 # events: 4
11697 # events: 5
12698  ALARM
14902 # events: 1
15398 # events: 2
15925 # events: 3
27161 # events: 1

If you found this interesting you may also want to have a look at how to build a High Sensitivity Sound Level Detector. You may also want to look at my subsequent blog on how to use these in an open door or tailgate down sensor which also uses a Reed switch.

If you are interested in how this type of sensor can be integrated into a broader solution that includes notification of detected vibration on a users Android phone see Detect Intrusion with Passive Infrared, Sound, or Vibration

4 comments:

  1. Hello my i have your email account. I have a project that i am working on and need some help. i cant explain it fully over here so i wanted to send an email to you about it. Thank you in advance!

    ReplyDelete
  2. Thanks, You wrote awesome, I knew lots of things from your article. Its really helpful for any readers.
    Battery Operated Flow Meter

    ReplyDelete
  3. Dear David,
    I need your help (urgent) to figure out a customised version of your code. I am working on vehicle security alarm project where vibration sensor will trigger both the siren and start a dialer (phone) which will place call to vehicle owner then vehicle owner will press buttons to cutt off engine etc. For automatic dialer I m using this youtube tutorial https://www.youtube.com/watch?v=6fwM_oTjqG0 and for vibration sensor & alarm I am using your one. But facing difficulty in combining both the codes. When I combine them, it gives error like "clearVibrationEvents' was not declared in this scope", etc.

    I am sharing the code here for auto dialer:
    //Constants That Won't Change
    const int call = 11; //Call Button Output
    const int back = 10; //Back Button Output
    const int keypad7 = 9; //No:7 Button Output
    const int alarm_active_led = 8; //Alarm Triggered LED Indicator
    const int power_led = 7; //Power OK LED Indicator
    const int trigger_input = 6; //Alarm Trigger Input
    int repeat =0;

    //Variables That Will Change
    int trigger_state = 0; //trigger_state = Trigger Input (pin7)

    //Setup Routine Runs Once When Reset Is Pressed
    void setup() {

    //Initialize The Digital Pins As Inputs/ Outputs
    pinMode(call, OUTPUT); //Define "Call" pinMode as Output
    pinMode(back, OUTPUT); //Define "Back" pinMode as Output
    pinMode(keypad7, OUTPUT); //Define "keypad7" pinMode as Output
    pinMode(alarm_active_led, OUTPUT); //Define "Alarm LED" pinMode as Output
    pinMode(power_led, OUTPUT); //Define "Power LED" pinMode as Output
    pinMode(trigger_input, INPUT); //Define "Cancel" pinMode as Input
    }

    //Loop Runs Indefinately
    void loop() {
    trigger_state = digitalRead(trigger_input);//Read Trigger Input State

    digitalWrite(power_led, HIGH); //Turn Power LED On
    digitalWrite(alarm_active_led, LOW); //Turn Alarm LED Off

    if (trigger_state == HIGH) { //If Trigger Input HIGH,
    //Run Sequence Below
    digitalWrite(alarm_active_led, HIGH);

    digitalWrite(back, HIGH); //Press Back Button
    delay(100); //Wait 100mS
    digitalWrite(back, LOW); //Depress Back Button

    delay(100); //Wait 100mS
    digitalWrite(back, HIGH); //Press Back Button
    delay(100); //Wait 100mS
    digitalWrite(back, LOW); //Depress Back Button

    delay(100); //Wait 100mS
    digitalWrite(keypad7, HIGH); //Press keypad7 Button
    delay(100); //Wait 100mS
    digitalWrite(keypad7, LOW); //Depress keypad Button

    delay(100); //Wait 100mS
    digitalWrite(call, HIGH); //Press call Button
    delay(100); //Wait 100mS
    digitalWrite(call, LOW); //Depress call Button

    delay(20000); //Wait 20S
    digitalWrite(back, HIGH); //Press back Button
    delay(200); //Wait 100mS
    digitalWrite(back, LOW); //Depress back Button

    digitalWrite(alarm_active_led, HIGH); //Flash Alarm LED
    delay(100); //Flash Alarm LED
    digitalWrite(alarm_active_led, LOW); //Flash Alarm LED
    delay(100); //Flash Alarm LED

    while(trigger_state == HIGH){ //If Trigger Input HIGH
    trigger_state = digitalRead(trigger_input);//Read Trigger Input State
    //Loop Sequence Below
    digitalWrite(alarm_active_led, HIGH); //Flash Alarm LED
    delay(100); //Flash Alarm LED
    digitalWrite(alarm_active_led, LOW); //Flash Alarm LED
    delay(100); //Flash Alarm LED
    if (trigger_state == LOW) { //If Trigger Input Low
    break; //Break
    }
    digitalWrite(alarm_active_led, HIGH); //Turn Alarm LED On
    }
    }
    }

    ReplyDelete