Ultrasonic Sensor Inconsistent Reading

Hi All,

I'm working with a project that uses 4 pin hypersonic sensors and I'm getting inconsistent distances even when I'm not moving. Here's what code I'm using and what the sensor is outputting:

Code

digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(15);
  duration = pulseIn(echoPin, HIGH, 180000UL);

Output

5071
10000
5000
10000
5134
5038
10000
5060
10000
5167
10000
10000
5139
10000
5127
5131
5157
10000
5253
5117

I've constrained the values between 300 and 10,000 to give it some kind of limit that I can work with. The issue isn't resolved by removing this or the '180000UL' line either so I'm stuck. Any advice for getting clear and more consistent readings would be very much appreciated.

Thanks in advance!

Jack

Are you sure that one sensor is not interfering with the other sensors? Your results seem pretty consistent with sonic rangers interfering with one another (the alternating values?). Do you know how sonic rangers work?

liudr:
Are you sure that one sensor is not interfering with the other sensors? Your results seem pretty consistent with sonic rangers interfering with one another (the alternating values?). Do you know how sonic rangers work?

I am using other ones but they aren't near to each other when I'm testing, facing in the same direction or facing each other. I know they send a 40kHz ping and then wait for the echo and calculate the distance from the time taken vs the speed of sound. I can only put it down to the shape of the object its hitting, as the flatter it is, the better reading I'm getting; so it must be defusing the signal but I'm not sure if this is the case or even how I'd fix it if it is.

If you are using the sonic rangers far enough apart from one another, say they don't interfere, then have you put some capacitors at the sonic ranger side to stabilize power supply? When I was using a simple $5 sonic ranger and a long cable (phone cord about 2m (6ft) long I got garbage all the time until I stuck a 10uF capacitor on the sonic ranger between 5V and gnd. I recommend you to run only one ranger and see if the number still fluctuates. If it still does, add capacitor as recommended. Sending out sonic pulses consumes quite a bit of power.

Hi Liudr,

I did have the other one running at the same time when I was testing so I'll have to see if unplugging one stabilises the other. However I can't see it fixing it to be honest, I think the supply is stable, as its coming directly from the arduino's 5v out pin. However, if it is a fluctuating supply, how should I arrange the capacitor? Do you mean bridge the 5v and Gnd with the capacitor? Also, will a larger capacitor work? I don't have any 10uF ones, only 22's and higher. I want to be sure before I try anything.

Thanks again,

Jack

dantedraven13:
Do you mean bridge the 5v and Gnd with the capacitor? Also, will a larger capacitor work?

Yes, yes. How long is your wire to a typical ranger? Also test out the object you are deflecting sonic pulses off. If you have a large object and one sonic ranger, but you still have fluctuating readings, add a capacitor.

Hi Liudr,

Awesome! I'll give it a go when I'm back at my project and let you know how it goes :smiley:

Thanks again!

Jack

You haven't shown the whole code, so we can't see how often you are taking readings. If you don't have a delay() call in the loop to give a large interval between readings, add one. Try 100ms initially, you can always reduce it later. Without a delay call, the sensor may be picking up secondary echoes from a previous time that you triggered it.

Hi Dc42,

Sorry, I forgot to add the code, basically each sensor has its own delay to wait for the echo, however, the main loop has delay(250) as well to give it a bit more time after each loop.

Thanks,

Jack

How long is the delay between triggering different sensors? Do you still get bad readings if you only trigger one sensor?

Hi Dc42,

Only 15 microseconds between them :~ Might try a longer delay if the capacitor doesn't help. And no, I've been testing with 2 spaced apart and facing away so I'll try just one next.

Thanks,

Jack

Hi All,

Right, I’ve had an experiment with the suggestions you all gave and unfortunately still have inconsistent readings coming in. I’ve added a 22uF capacitor to regulate any fluctuations in the power supply, I’ve changed the delays in both the loop and between sensors, as well as trying these changes out with both a single sensor and a couple running together with no change. I’m stumped if I’m honest, as my project relies on having consistency in the distance measurements coming in and I’ve not had this problem with these sensors since I began using them. Any other suggestions about fixing this issue would be awesome as I’m really pressed for time as my deadlines are looming. I’ll post the code I’m using below, its very basic and includes some serial port communication, however removing there parts and leaving only the PING parts still doesn’t fix the problem.

Thanks in advance!

Jack

#include <SimpleMessageSystem.h>


/* HC-SR04 Sensor
   https://www.dealextreme.com/p/hc-sr04-ultrasonic-sensor-distance-measuring-module-133696
  
   This sketch reads a HC-SR04 ultrasonic rangefinder and returns the
   distance to the closest object in range. To do this, it sends a pulse
   to the sensor to initiate a reading, then listens for a pulse 
   to return.  The length of the returning pulse is proportional to 
   the distance of the object from the sensor.
     
   The circuit:
	* VCC connection of the sensor attached to +5V
	* GND connection of the sensor attached to ground
	* TRIG connection of the sensor attached to digital pin 2
	* ECHO connection of the sensor attached to digital pin 4
 
 
   Original code for Ping))) example was created by David A. Mellis
   Adapted for HC-SR04 by Tautvidas Sipavicius
 
   This example code is in the public domain.
 */
 

const int trigPin = 3;
const int echoPin = 4;

const int trigPin2 = 5;
const int echoPin2 = 6;

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
}
 
void loop()
{
  // establish variables for duration of the ping, 
  // and the distance result in inches and centimeters:
  long duration, duration2, inches, cm;
 
  pinMode(trigPin, OUTPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin, INPUT); 
  pinMode(echoPin2, INPUT); 
  
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
 
  //Sensor 1
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(15);
  duration = pulseIn(echoPin, HIGH, 180000UL);

 delayMicroseconds(15);
 
  //Sensor 2
  digitalWrite(trigPin2, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin2, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);
  delayMicroseconds(15);
  duration2 = pulseIn(echoPin2, HIGH, 180000UL);
  

// read the value from the sensor
   
//  messageSendInt(millis());    // along with a timestamp
  messageSendInt(duration);
  messageSendInt(duration2);
  messageEnd();
  
     duration = constrain(duration, 300, 10000);
     duration2 = constrain(duration2, 300, 10000);
     
  Serial.println(duration);  
//  Serial.println(duration2);  
  delay(50);
  
  
}

Only 15 microseconds between them

5mm worth of delay is nowhere near long enough.
Start with 100ms and work down.
You probably won’t get below about 50ms unless you have pretty insensitive sensors.

Hi All,

I’ve thought of a solution but am having trouble implementing it. Basically, if I could compare the previous distance measurement to the current one and make sure they aren’t very far apart, then I could set the current distance to the previous one until a closer signal to the first is achieved.

So for example, if the previous pass gave 5000 and the current one was 6000 then it would continue, as this is an acceptable change in distance; however, if it were 9000, it would default back to the first reading of 5000 until it got a better reading, as it probably jumped to 9000.

Could anyone pose a piece of code that would do this? I’ve written one, but its not working correctly and outputs 0’s until someone gets within the range set in the test written as ‘if (outPut > 2000)’

Here’s my attempt:

const int trigPin = 3;
const int echoPin = 4;

const int trigPin2 = 5;
const int echoPin2 = 6;

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
  
  delay(1500);
}
 
void loop()
{
  // establish variables for duration of the ping, 
  // and the distance result in inches and centimeters:
  long duration, duration2, inches, cm, compVal, compVal2, outPut, outPut2;
  

  pinMode(trigPin, OUTPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin, INPUT); 
  pinMode(echoPin2, INPUT); 
  
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
 
  //Sensor 1
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(15);
  duration = pulseIn(echoPin, HIGH, 180000UL);

 delayMicroseconds(15);
 
  //Sensor 2
  digitalWrite(trigPin2, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin2, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);
  delayMicroseconds(15);
  duration2 = pulseIn(echoPin2, HIGH, 180000UL);
  
  duration = constrain(duration, 300, 10000);
  duration2 = constrain(duration2, 300, 10000);

 
 //Compare the current distance value with the previous pass to see if the sensor
//has jumped value rather than reading correctly.

    if 
    (duration > compVal) //is the current distance higher than the last?
{outPut = duration - compVal; //calculate the difference between the two numbers

          if (outPut > 2000) //is this difference within the specified limits?
             {duration = compVal; //if not, set it to the previous value
              }
              else 
              {duration = duration; //if so, continue
              }
            }

    else if
    
    (duration < compVal) // do the same test but for the inverse effect
{outPut = compVal - duration; 

         if (outPut > 2000) 
            {duration = compVal;
            } 
            else 
            {duration = duration;
            }
            
}
//Now do the same test for the second sensor
            
             if 
    (duration2 > compVal2)
{outPut2 = duration2 - compVal2; 

          if (outPut2 > 2000) 
             {duration2 = compVal2;
              }
              else 
              {duration2 = duration2;
              }
            }

    else if
    
    (duration2 < compVal2)
{outPut2 = compVal2 - duration2; 

         if (outPut > 2000) 
            {duration2 = compVal2;
            } 
            else 
            {duration2 = duration2;
            }
            
            
}

// read the value from the sensor  
//  messageSendInt(millis());    // along with a timestamp
//  messageSendInt(duration);
//  messageSendInt(duration2);
//  messageEnd();
  
  //Set compVal to the previous distance value, ready for the next pass
  compVal = duration;
  compVal2 = duration2;
 
  
  Serial.println(compVal);  
//  Serial.println(duration2);  
  delay(50);
  
  
}

I think I need to initialise compVal so that it doesn’t begin as 0 which is causing the problem, however, I’m not sure how to do this without resetting on each pass. Any help would be greatly appreciated, as I think this is going to sort out my problems with the sensor as well as create a failsafe from sudden changes.

Thanks in advance!

Jack

I think "abs" is the operation you may be looking for.

??? Abs Operation? I haven’t heard of that, have you got a link I may be able to have a look at?

Thanks again,

Jack

Here

I'm not sure how I'd use this to be honest. Have you got some code that uses it? It looks like it only compares 'x' to '0,' which won't help as I need to compare the current incoming value with its previous one.

Is there a way to initialise a variable in the loop only once?

That would fix my problem as initialising compVal in void setup has no effect on the loop; I think its because 'compVal' in the setup isn't the same as 'compVal' in the loop, its just another instance.

Thanks again,

Jack

It looks like it only compares 'x' to '0,' which won't help as I need to compare the current incoming value with its previous one

The "abs" operation makes thresholding differences easier.
Difference like the difference between the current reading and the provious reading, which may be positive or negative.

I had a problem with one of my programs. It used to print out insults with lots of profanity. I figure out a solution, though. I just had it print out a warning for the user to look away for a few seconds, every time the profanity was about to show up.

Seriously.. did you try increasing the time between pings as you were advised?