ultrasonic rangefinder for motion sensing code

Hello!

I would be unspeakably grateful for your expert views… I have been enduring a series of failed
attempts at deciphering the code myself, and I’m losing hope.

I am fine arts student who has never coded before. I am currently enrolled in an Arduino class, and I am struggling to keep up with the class. I am very interested in Arduino and the possibilities the technology offer. However, as stated, I am really struggling to grasp the material.

I have an ultrasonic rangefinder that I am trying to use for motion sensing. I have been trying to get coherent and stable readings from the rangefinder before I begin working on the motion sensing aspect of my task. Initially, I had written my own code but after I was unsuccessful I started to look for examples online. I have tried every code that I could find with this sensor(MAXBOTIX Ultrasonic Range Finder XL maxsonar-EZ1) and cannot get a steady reading. I am also unable to grasp why the error is occurring and do not have enough of an understanding of the language to troubleshoot.

I would greatly appreciate it if anyone could recommend an effective code - your guidance would be exceptionally helpful!

sincerely,
Andrea

We need a bit more information.
How unsteady is the reading you are getting?

You don't get a very steady reading from this type of sensor anyway.
Have you tried averaging say 10 readings?

As Mike said, this sort of sensor can get all kinds of jitter from multiple reflections or other sources of ultrasound (they're more common than you might think).
To help you better, can you post your code?
Use the # icon on the editor's toolbar to put the code in code box.

You can also post your current code here, just to let others skim through it for most common mistakes or misunderstandings...

Thank you for responding!
This is the code that I’ve been working with and I’ve been getting the readings below. I am really confused as to why the readings have no correlation to the distance I am holding something from the sensor.

I just added code for averaging ten values like you suggested, but I’m not sure my code worked…?

Can you help me?

Andrea
acrab- I’m sorry to hear about the terrible earthquake. I hope your loved ones are safe.

11
11
11
15
17
946
953
1000
1002
1014
1015
1016
1015
988



145
95
31
146
43
147
148
87
15
147
148
133
35
int THRESHOLD = 30;      
int LED_PIN = 13;      
int sensorPin = 0;   
int avgrange = 10; 
int sum = 0;
int media;

int i;

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

void loop()
{
  int distance = analogRead(sensorPin);
  delay(1000);
  //val= map(distance, 0, 1023, 0, 252) //map value from standard input to inches (21ft)
  Serial.println(distance);          
 
  // if an object is closer than threshold distance, turn on LED
  if (distance < THRESHOLD)
    digitalWrite(LED_PIN, HIGH);
  else
    digitalWrite(LED_PIN, LOW);

 {for(i = 0; i < avgrange ; i++) {
     sum+=analogRead(sensorPin);
     delay(10);
  }
 }

        media = sum/avgrange;
  Serial.println(media); 
   
      sum=0;
      media=0;
}
for(i = 0; i < avgrange ; i++) {
     sum+=analogRead(sensorPin);
     delay(10);
  }

Ultrasonic rangers rarely exceed about 20 readings a second, so your delay should really be of the order of 50 milliseconds.
Or you could calculate a rolling average using an array.

Thanks, we were spared for the time being, but Istanbul will be hit by an earthquake sooner or later...

Anyway, I suggest you to do all the calculations first, and then send serial messages. They take lots of time. They may interfere with your sensor reading period.

I use a push button to print something. When the button is pressed & it was not pressed on previous check, send serial messages. You can do the same.

(compiled but untested)

const int THRESHOLD = 30;
const int LED_PIN = 13;      
const int sensorPin = 0;   
const int avgrange = 10; 
// the following will all be initialsed to zero automatically
long sum;
int readings [avgrange];
int index;
int validNow;

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

void loop()
{
  sum -= readings [index];  // subtract oldest
  sum += readings [index++] = analogRead(sensorPin); // add in newest
  if (index == avgrange) {
    index = 0;
    validNow = 1;  // we've filled the buffer
  }
    
  if (validNow) {
    int avg = sum / avgrange;
    // if an object is closer than threshold distance, turn on LED
    digitalWrite(LED_PIN, avg < THRESHOLD);
    Serial.println(avg); 
  } else {
    Serial.println(sum / index); // just to see how things go.
  }
  delay (50);
}

Thanks, I'm going to test the code now :slight_smile:

This code works great! Thank you AWOL :slight_smile:

Now I am trying to modify the code so that the rangefinder can be used as a motion sensor in a doorway. The desired result would be that when a person walks through the doorway, (value lower than THRESHOLD) the LED turns on. The LED remains on until motion is sensed a second time( person leaving the room). I have been trying to write this into the code. Does anyone have any suggestions about what types of commands/syntax I should be looking at to make this happen? I will post my most directed attempt at this below.

This code does not give back coherent readings and definitely does not control the led properly. However, here is my code so that maybe anyone can help me write it be commenting directly about something or by pointing me in the right direction. I am continuing to work on this code now- trying to perfect it. Once again, I am very grateful for any assistance. :slight_smile:

code w/ comments

const int THRESHOLD = 20;
const int LED_PIN = 13;      
const int sensorPin = 0;   
const int avgrange = 10;
int avg;

// the following will all be initialsed to zero automatically
long sum;
int readings [avgrange];
int index;
int validNow;

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

void loop()
{
  sum -= readings [index];  // subtract oldest
  sum += readings [index++] = analogRead(sensorPin); // add in newest
  if (index == avgrange) {
    index = 0;
    validNow = 1;  // we've filled the buffer
  }
  if (validNow) {
    int avg = sum / avgrange;
   // if an object is closer than threshold distance, turn on LED
    digitalWrite(LED_PIN, avg < THRESHOLD);
    Serial.println(avg); 
  } else {
    Serial.println(sum / index); // just to see how things go.
  }
  delay (50);
//read again  
{ sum -= readings [index];  // subtract oldest
  sum += readings [index++] = analogRead(sensorPin); // add in newest
  if (index == avgrange) {
    index = 0;
    validNow = 1;  // we've filled the buffer
  }
  if (validNow) {
    int avg = sum / avgrange;      // find avgerage
  }
   // if an object is closer than threshold distance, turn on LED
   if (int avg2 = avg > THRESHOLD && avg2 != avg){ //avg2 is the second average read. if the reading is greater than thershold and this is not the same reading as for avg
  digitalWrite(LED_PIN, HIGH);                  // keep the led high
    Serial.println(avg2);
     }
  delay (50);
  
  } //read again
  {
  sum -= readings [index];  // subtract oldest
  sum += readings [index++] = analogRead(sensorPin); // add in newest
  if (index == avgrange) {
    index = 0;
    validNow = 1;  // we've filled the buffer
  }
  if (validNow) {
    int avg = sum / avgrange;
  }
   // if an object is closer than threshold distance, turn on LED
  if (int avg3 = avg < THRESHOLD && avg3 == avg){ //if avg3 is less than threshold(motio  detected)- one in this reagrd the led should be low because someone exited the room.
  digitalWrite(LED_PIN, LOW);
    Serial.println(avg3); 
  } else {
    Serial.println(sum / index); // just to see how things go.
  }
  delay (50);
  }
}

I don't think you understood how the code I wrote works, and the declaration of avg looks suspect.

I am not sure that I completely understand the organization of the code you wrote. I have never seen code written that way before- I am very beginner. I wasn’t sure where to put the comparison commands because I wasn’t a hundred percent sure where exactly the calculation of the avg analog inputted value was taking place.
Is this occurring here?

sum -= readings [index]; // subtract oldest
sum += readings [index++] = digitalRead(sensorPin); // add in newest
if (index == avgrange) {
index = 0;
validNow = 1; // we’ve filled the buffer

I read it to be the case that when you wrote VoidNow you were decalring a high state so that when you write digitalWrite and you put

digitalWrite(LED_PIN, avg < THRESHOLD);

It is the same things as saying digitalWrite(LED_PIN, HIGH)
Is this the case?

Should I be thinking about using an Array?

The code already uses an array to maintain a short history of readings (10 readings).
The code relies on the fact that “loop” repeats.
So the very first time “loop” is called, the history buffer “readings” is empty.
The code also keeps a running total called “sum”.
At the start of the loop, the oldest reading is subtracted from “sum”, a new reading is taken, overwriting the oldest reading and the new reading is added to sum.
As soon has the buffer has been written, the valid flag is set, and the average of the readings computed.

digitalWrite(LED_PIN, avg < THRESHOLD);

is just a shorthand way of writing

if (avg < THRESHOLD) {
  digitalWrite (LED_PIN, HIGH)
} else {
  digitalWrite (LED_PIN, LOW);
}

Oh I think I understand now. Thank you for clarifying.
I’ve been trying to write new codes to get the led to remain on until motion is detected a second time.
I am assuming, based on your description that it is not working because the code needs to loop every 50 milliseconds for readings to come in.
Here is something I’ve tried, but it doesn’t work. I think it is because it is interrupting the loop. The led flashes very low repeatedly.

I am so frustrated because I cannot wrap my head completely around what I need to do to make this motion-sensing led sketch happen. Its really important to me that I can complete this.

I tried to use the idea of buttonpresses to control the LED’s state…

const int THRESHOLD = 20;
const int LED_PIN = 13;      
const int sensorPin = 0;   
const int avgrange = 10; 
// the following will all be initialsed to zero automatically
long sum;
int readings [avgrange];
int index;
int validNow;
int buttonPresses = 2;

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

void loop()
{
  sum -= readings [index];  // subtract oldest
  sum += readings [index++] = analogRead(sensorPin); // add in newest
  if (index == avgrange) {
    index = 0;
    validNow = 1;  // we've filled the buffer
  }
    
  if (validNow) {
    int avg = sum / avgrange;
    if(avg < THRESHOLD){
      if(avg > THRESHOLD){
   buttonPresses++;}
    if(buttonPresses = 1){
      digitalWrite(LED_PIN, HIGH);
    }
    if(buttonPresses = 2){
      digitalWrite(LED_PIN, LOW);
    }
    
    // if an object is closer than threshold distance, turn on LED
    //digitalWrite(LED_PIN, avg < THRESHOLD);
    Serial.println(avg); 
  } else {
    Serial.println(sum / index); // just to see how things go.
  }
  delay (50);
  }
}

Thank you
Andrea

ButtonPresses = 1
Is always going to be true.

ButtonPresses = 2
Is always going to be true

Test equivalence with ==

The sensor and the led are no longer responding to distance
do you know why

No, because I can't see your code.

Thanks I fixed that in the code. It is not responding to distance anymore and the led isn't turning on

Still can't see your code

sorry here it is

const int THRESHOLD = 20;
const int LED_PIN = 13;      
const int sensorPin = 0;   
const int avgrange = 10; 
// the following will all be initialsed to zero automatically
long sum;
int readings [avgrange];
int index;
int validNow;
int buttonPresses = 2;

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

void loop()
{
  sum -= readings [index];  // subtract oldest
  sum += readings [index++] = analogRead(sensorPin); // add in newest
  if (index == avgrange) {
    index = 0;
    validNow = 1;  // we've filled the buffer
  }
    
  if (validNow) {
    int avg = sum / avgrange;
    if(avg < THRESHOLD){
      if(avg > THRESHOLD){
   buttonPresses++;}
    if(buttonPresses == 1){
      digitalWrite(LED_PIN, HIGH);
    }
    if(buttonPresses == 2){
      digitalWrite(LED_PIN, LOW);
    }
    
    // if an object is closer than threshold distance, turn on LED
    //digitalWrite(LED_PIN, avg < THRESHOLD);
    Serial.println(avg); 
  } else {
    Serial.println(sum / index); // just to see how things go.
  }
  delay (50);
  }
}