Ultrasonic motion detector with HC-SR04

Hi,
I would like to make a motion-activated light in a room where a hot oven is located. PIR sensors I've tried haven't worked because of the hot air flow. So I would like to use a HC-SR04 ultrasonic sensor. All the code examples I have found are however for a fixed distance, and that doens't work well in case someone closes a door because it would leave the light on if the door is closed and the sensor is pointing to the door opening. So I would like the arduino to compare values and turn on an output if the change is too big (person walking/door opening).

I have tried something like this:

void loop() {

delay(500);
digitalWrite(trigPin, HIGH);
delayMicroseconds(1000);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;
newdistance = (distance/olddistance)*100;
olddistance = distance;
if (newdistance >= 80 || distance <= 0){

Serial.println("no object detected");
digitalWrite(ledPin, LOW);

}
else {
Serial.println("object detected");
digitalWrite(ledPin, HIGH);
}
}

But it doesn't work reliably, the light just turns on randomly. What should I do to compare a new value to an old value?

What should I do

The first thing to do is to post your complete program.

Hi, Here is the whole code:

#define trigPin 3
#define echoPin 2
int ledPin = 9;
float olddistance, newdistance;
float duration, distance;

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(ledPin, OUTPUT);
}

void loop() {

delay(600);
digitalWrite(trigPin, HIGH);
delayMicroseconds(1000);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;
newdistance = (distance/olddistance)*100;
olddistance = distance;
if (newdistance >= 50 || distance <= 0){

Serial.println("no object detected");
digitalWrite(ledPin, LOW);

}
else {
Serial.println("object detected");
digitalWrite(ledPin, HIGH);
}
delay(900);
}
void loop() {

delay(600);
digitalWrite(trigPin, HIGH);
delayMicroseconds(1000);

On every pass through loop(), stick your head in the sand for a while? Why? GET RID OF THE STUPID DELAY()!

That is a very long time to leave the trigger pin high. Why are you using such a long time?

distance = (duration/2) / 29.1;

What is the distance?

newdistance = (distance/olddistance)*100;

newdistance is NOT a distance.

delay(900);

Again with the head in the sand...

distance = (duration/2) / 29.1;

distance should be the measured distance in centimeters calculated from the speed of sound

newdistance = (distance/olddistance)*100;

newdistance should be the change in distance in percent, but I'm not sure it works correctly

if (newdistance >= 50 || distance <= 0){

This would set ledPin on if the change is more than 50%. But I think the problem is that the measurement frequency is so fast that some other method has to be used?

The delays can probably be removed, I just thought I don't need so much speed.

newdistance should be the change in distance in percent

Right. Is it a percentage, NOT a distance. Don't use a name that implies that it contains a distance.

But I think the problem is that the measurement frequency is so fast that some other method has to be used?

Why do you (incorrectly) think that? There will be some time needed to measure the distance. Ping sensors are not instantaneous. Calculating the percentage change will take some time. The times are not relevant, though. The Arduino is plenty capable of dealing with the sensor the way you are trying to use it.

Print the distance read from the sensor EVERY time a distance is read. If the reading does not correlate with observed distance, the rest of the code that uses the distance read will not work. Quit focusing on that part of the code.

Now I got it working a bit better, by adjusting the percentage at which it should trigger. Now I print out the distance and I can see that one problem is that sometimes the distance is reported as 849-850cm, probably because of echoes or from the previous ping signal echoes. Adding delays doesn't seem to help. It's working pretty well now but I would really appreciate some ideas/comments.

Here's the code:

#define trigPin 3
#define echoPin 2
int ledPin = 9;
float olddistance, newdistance;
float duration, distance;

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(ledPin, OUTPUT);
}

void loop() {

digitalWrite(trigPin, HIGH);
//delayMicroseconds(1000);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;
newdistance = (distance/olddistance)*100;  //newdistance is the change in percent between two readings
olddistance = distance;
if (newdistance >= 30 || distance <= 0 || distance > 200){  //turn on led if change is over 30% and distance less than 200cm

Serial.println("no object detected");
Serial.println(distance);
digitalWrite(ledPin, LOW);

}
else {
Serial.println("object detected");
Serial.println(distance);
digitalWrite(ledPin, HIGH);
delay(9000); //keps led on for a few seconds
}

}
digitalWrite(trigPin, HIGH);
//delayMicroseconds(1000);
digitalWrite(trigPin, LOW);

You need to have the trigger pin high for some time - just not 1000 microseconds. Look at the ping example.

As a rule-of-thumb, I would limit ultrasonic readings to no more than ten per second.
I'd also plan on some debug prints.