Ultrasonic range finder inconsistent

So I am playing around with the ultrasonic and have placed it on top of a servo so that every 1/2 second it rotates 5 degrees and takes 4 readings. What I am finding is that the reading are very inconsistent. I have put in delays thinking I needed time for the servo to get into position, delays between pings, long delays, short delays and just seem to get an almost random reading. Is ths how accurate ultrasonics are in general? Here is a sample of the results and at no time am i up against the wall as the measurements might indicate.

0 - 0 0 0 0
5 - 160 243 163 242
10 - 86 318 0 283
15 - 338 248 158 246
20 - 87 247 158 248
25 - 85 247 158 249
30 - 83 248 158 346
35 - 334 248 158 247
40 - 86 248 160 246
45 - 84 247 164 281
50 - 57 237 171 239
55 - 80 248 163 244
60 - 82 249 165 280
65 - 55 239 173 272
70 - 56 237 208 237
75 - 55 239 204 244
80 - 52 238 205 238
85 - 50 245 200 245
90 - 49 245 201 244
95 - 48 245 0 0
100 - 349 249 0 0
105 - 350 249 0 0
110 - 349 249 0 0
115 - 349 249 0 0
120 - 349 249 0 0
125 - 349 250 0 0
130 - 349 249 0 0
135 - 349 249 0 0
140 - 350 249 0 0
145 - 349 0 0 262
150 - 336 249 0 0
155 - 350 229 230 229
160 - 49 229 230 293
165 - 229 49 208 228
170 - 228 39 229 228
175 - 372 248 0 0
180 - 351 247 252 246

#include <Stepper.h>
#include <NewPing.h>
#include <Servo.h>

// change this to the number of steps on your motor
#define STEPS 200

// create an instance of the stepper class, specifying
// the number of steps of the motor and the pins it's
// attached to
Stepper stepper1(STEPS, 10, 11, 12, 13);
Stepper stepper2(STEPS, 4, 5, 6, 7);

// Ultrasonic settings
#define TRIGGER_PIN 2
#define ECHO_PIN 3
#define MAX_DISTANCE 500 

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); 

//Servo
Servo myServo;
int angle = 0;  //Starting position for servo
int looking = 1;//Starts looking right

//  Body
#define WHEEL 3.81  //wheel diameter in cm

//Radar
int iSpy [37][2];


//Light detection
int val = 50;
int previous = 1000;
int delta = 0;
int steps = 0;

const int leftSensorPin = A1;
const int rightSensorPin = A2;
int leftSensorValue = 0;
int rightSensorValue = 0;

void setup() {
  Serial.begin(9600);   //Open serial communication
  stepper1.setSpeed(200);  // set the speed of the motor to 200 RPMs
  stepper2.setSpeed(200);  // set the speed of the motor to 200 RPMs

  myServo.attach(9);
  
  myServo.write(0);
  for (int x=0; x < 37; x++){
    iSpy [x][0] = x * 5;      
    myServo.write(map(iSpy [x][0],0,180,10,150));
//    delay(500); //1000ms = 1s
    unsigned int uS = sonar.ping();
    iSpy [x][1]  = uS / US_ROUNDTRIP_CM; 
    Serial.print(iSpy [x][0]);    
    Serial.print("  -  ");
    Serial.print(iSpy [x][1]);
    uS = sonar.ping();
    iSpy [x][1]  = uS / US_ROUNDTRIP_CM; 
    Serial.print(" ");
    Serial.print(iSpy [x][1]);
    uS = sonar.ping();
    iSpy [x][1]  = uS / US_ROUNDTRIP_CM; 
    Serial.print(" ");
    Serial.print(iSpy [x][1]);
    uS = sonar.ping();
    iSpy [x][1]  = uS / US_ROUNDTRIP_CM; 
    Serial.print(" ");
    Serial.println(iSpy [x][1]);
    delay(500); //1000ms = 1s
  }
}

void loop() {
}

You haven't mentioned which ultrasonic sensor you're using. A HC-SR04 needs a delay between individual readings. The datasheet says 60mS, and Tim Eckel, (NewPing), says either 30mS or 50mS, (can't remember which).
Other ultrasonic modules would be similar, I imagine.

Currently, the only real delay between your readings at each position is the time taken for the serial prints.

Edit: Here's a link to the HC-SR04 datasheet:- HC-SR04 datasheet

OldSteve:
A HC-SR04 needs a delay between individual readings. The datasheet says 60mS, and Tim Eckel, (NewPing), says either 30mS or 50mS, (can't remember which).

Isn't it a little strange that the library doesn't manage that requirement?

aarg:
Isn't it a little strange that the library doesn't manage that requirement?

There's a 'ping_timer()' method, that does it for you, using a timer, but the basic 'ping()' ( edit: and ping_cm() ) methods don't.
Here's the 'loop()' from the basic "NewPing.ino" example:-

void loop() {
  delay(50);                     // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
  Serial.print("Ping: ");
  Serial.print(sonar.ping_cm()); // Send ping, get distance in cm and print result (0 = outside set distance range)
  Serial.println("cm");
}

The constraint depends on the environment, so the user should be responsible.

20Hz (50ms) is about the best you should expect with the common off-the-shelf sensors.

AWOL:
The constraint depends on the environment, so the user should be responsible.

20Hz (50ms) is about the best you should expect with the common off-the-shelf sensors.

I agree. Tim says 29mS, but I think that's pushing it a bit. Some sensors might be OK with that short a period, but 50mS is safer.

Thanks OldSteve, that did help. The unit that I am using is the HC-SR04. I added in a 60us delay which helped with the consistency of the numbers. Still have some odd numbers in there which might be related to my servo as it appear to have a nervous tick that causes to jump around. I am as some points in the reading also finding that I am pinging up against fabric that does not give reliable readings but at least it is consistently unreliable now.:smiley:

0 - 230 276 279 112 278 277 277 278 277
5 - 279 279 279 278 278 278 279 277 277
10 - 130 343 348 0 0 0 278 278 278
15 - 279 278 280 0 0 0 279 279 278
20 - 178 0 0 0 0 279 279 280 279
25 - 248 343 334 279 0 0 0 0 0
30 - 71 0 0 0 0 0 0 0 0
35 - 0 0 0 0 0 0 0 0 0
40 - 242 339 0 0 0 0 0 0 0
45 - 0 0 0 0 0 0 0 0 0
50 - 54 339 0 178 0 0 0 0 0
55 - 200 0 179 0 178 0 0 0 0
60 - 0 0 0 0 0 0 54 319 0
65 - 173 340 0 0 0 0 0 0 0
70 - 0 0 0 0 0 0 0 0 0
75 - 243 0 0 0 0 0 0 0 69
80 - 118 0 0 0 0 65 0 0 0
85 - 63 0 0 0 0 64 0 0 0
90 - 63 0 0 0 0 0 0 65 0
95 - 0 196 0 0 0 65 195 195 0
100 - 0 196 195 195 194 196 194 195 196
105 - 195 195 194 194 195 194 194 193 194
110 - 193 193 194 194 193 195 193 193 193
115 - 138 193 193 193 193 193 193 193 193
120 - 96 192 193 194 68 193 140 193 193
125 - 193 194 193 193 193 193 193 193 193
130 - 180 192 192 192 192 192 192 193 192
135 - 102 192 192 192 192 192 193 192 192
140 - 101 192 192 192 78 193 193 192 192
145 - 192 32 192 194 164 165 192 192 193
150 - 192 150 164 149 150 149 150 148 148
155 - 149 67 147 148 148 148 147 147 148
160 - 149 110 150 147 148 147 148 147 149
165 - 147 105 149 147 147 147 147 146 147
170 - 146 113 145 145 146 145 145 144 144
175 - 145 129 146 144 144 144 145 145 147
180 - 145 145 144 76 77 76 76 76 76

#include <Stepper.h>
#include <NewPing.h>
#include <Servo.h>

// change this to the number of steps on your motor
#define STEPS 200

// create an instance of the stepper class, specifying
// the number of steps of the motor and the pins it's
// attached to
Stepper stepper1(STEPS, 10, 11, 12, 13);
Stepper stepper2(STEPS, 4, 5, 6, 7);

// Ultrasonic settings
#define TRIGGER_PIN 2
#define ECHO_PIN 3
#define MAX_DISTANCE 500 

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); 

//Servo
Servo myServo;
int angle = 0;  //Starting position for servo
int looking = 1;//Starts looking right

//  Body
#define WHEEL 3.81  //wheel diameter in cm

//Radar
int iSpy [37][2];


//Light detection
int val = 50;
int previous = 1000;
int delta = 0;
int steps = 0;

const int leftSensorPin = A1;
const int rightSensorPin = A2;
int leftSensorValue = 0;
int rightSensorValue = 0;

void setup() {
  Serial.begin(9600);   //Open serial communication
  stepper1.setSpeed(200);  // set the speed of the motor to 200 RPMs
  stepper2.setSpeed(200);  // set the speed of the motor to 200 RPMs

  myServo.attach(9);
  myServo.write(0);
  delay(500); //1000ms = 1s
  for (int x=0; x < 37; x++){
    iSpy [x][0] = x * 5;      
    myServo.write(map(iSpy [x][0],0,180,10,150));
    //delay(500); //1000ms = 1s
    Serial.print(iSpy [x][0]);    
    Serial.print("  -  ");
    for (int y=1; y < 10; y++){
      unsigned int uS = sonar.ping();
      iSpy [x][1]  = uS / US_ROUNDTRIP_CM; 
      delay(60); //1000ms = 1s
      Serial.print(iSpy [x][1]);
      Serial.print(" ");
    }
    Serial.println();
    delay(60); //1000ms = 1s
  }
}

void loop() {
}

How are you powering your servo? Not from the Arduino, I hope.

You could be getting weird readings because the objects you are sensing are not flat. I suggest you keep the ultrasonic sensor at one angle and don't move it just to see if your setup is working. Then, you may want to consider making the times between rotating the sensor longer.

You said you added a 60us delay. That's not much compared with the 50ms that was mentioned above.

The code says 60ms

dgkindy:
Still have some odd numbers in there which might be related to my servo as it appear to have a nervous tick that causes to jump around.

As Paul asked, how are you powering the servo? It needs a separate power supply and can't be powered directly from the Arduino.

I am as some points in the reading also finding that I am pinging up against fabric that does not give reliable readings but at least it is consistently unreliable now.:smiley:

Yep, fabric can cause inconsistent and out-of-range readings. Also note what goodinventor said. A ping sensor works best when the target is directly across the line of sensing, at 90 degrees.

When set up properly, this system should work well. I do exactly the same thing with my robot car - the ping sensor is attached to the body of an inverted servo and takes measurements at 5 positions during a sweep from one side to the other. I only stop the servo for a few milliseconds at each of the 5 positions, (to the naked eye it can't really be seen to stop), and it works well.

I am powering the servo from the Arduino. This is the way is shows to do it in the Arduino Starter Kit. Based on the other comments sounds like this is bad.

goodinventor, i did as you suggested and got a good consistent set of reading. I inserted a 5 second delay between movement and first ping. Much betters numbers until it is pointed at a couch/wall and then it gives me the primarily the zero readings until it is pointed at me down at the 135 range.

I noted on the data sheet that it has a measuring angle of 15 degrees. I imagine this is a cone coming out from the unit so at 2.5 meters away, the cone would be getting quite large and could be bouncing off anything but does not explain why I am getting all the zeroes.

  • 268 269 270 270 268 269 270 269 268
    5 - 270 269 272 270 0 271 270 270 269
    10 - 269 268 268 268 270 268 268 270 268
    15 - 267 269 269 270 268 268 195 268 268
    20 - 267 267 270 268 268 267 267 268 268
    25 - 268 268 267 271 267 267 268 270 268
    30 - 268 267 267 268 267 268 267 268 270
    35 - 267 268 267 268 268 267 268 267 267
    40 - 269 267 267 268 268 268 267 267 268
    45 - 268 268 267 269 267 270 268 267 268
    50 - 267 268 267 267 269 268 268 269 268
    55 - 268 268 268 268 268 269 268 268 268
    60 - 268 268 269 268 269 268 271 270 270
    65 - 269 271 269 270 269 271 271 269 270
    70 - 0 0 0 0 0 0 0 0 0
    75 - 0 0 0 0 0 0 0 0 0
    80 - 0 0 0 0 0 0 0 0 0
    85 - 0 0 0 0 0 0 0 0 0
    90 - 0 0 0 0 0 0 0 0 0
    95 - 0 0 0 0 0 0 0 0 0
    100 - 0 0 0 0 0 0 0 0 0
    105 - 0 0 0 0 0 0 0 0 0
    110 - 0 0 0 0 0 0 0 0 0
    115 - 0 0 0 0 0 0 0 0 0
    120 - 0 0 0 0 0 0 0 0 0
    125 - 0 0 0 0 59 0 0 0 0
    130 - 60 0 0 0 0 0 0 0 0
    135 - 0 0 0 0 44 0 0 0 0
    140 - 39 0 0 0 0 40 0 0 0
    145 - 39 0 0 0 0 39 0 0 0
    150 - 38 0 0 0 0 39 203 0 0
    155 - 206 204 206 206 205 205 203 205 202
    160 - 202 202 201 204 201 201 201 203 203
    165 - 201 201 201 201 201 201 201 201 201
    170 - 200 201 201 201 201 200 203 201 201
    175 - 201 201 200 200 201 201 200 201 201
    180 - 201 200 201 200 200 200 200 199 201
#include <Stepper.h>
#include <NewPing.h>
#include <Servo.h>

// change this to the number of steps on your motor
#define STEPS 200

// create an instance of the stepper class, specifying
// the number of steps of the motor and the pins it's
// attached to
Stepper stepper1(STEPS, 10, 11, 12, 13);
Stepper stepper2(STEPS, 4, 5, 6, 7);

// Ultrasonic settings
#define TRIGGER_PIN 2
#define ECHO_PIN 3
#define MAX_DISTANCE 400 

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); 

//Servo
Servo myServo;
int angle = 0;  //Starting position for servo
int looking = 1;//Starts looking right

//  Body
#define WHEEL 3.81  //wheel diameter in cm

//Radar
int iSpy [37][2];


//Light detection
int val = 50;
int previous = 1000;
int delta = 0;
int steps = 0;

const int leftSensorPin = A1;
const int rightSensorPin = A2;
int leftSensorValue = 0;
int rightSensorValue = 0;

void setup() {
  Serial.begin(9600);   //Open serial communication
  stepper1.setSpeed(200);  // set the speed of the motor to 200 RPMs
  stepper2.setSpeed(200);  // set the speed of the motor to 200 RPMs

  myServo.attach(9);
  myServo.write(80);
  delay(500); //1000ms = 1s
  for (int x=0; x < 37; x++){
    iSpy [x][0] = x * 5;      
    myServo.write(map(iSpy [x][0],0,180,10,150));
    delay(5000); //1000ms = 1s
    Serial.print(iSpy [x][0]);    
    Serial.print("  -  ");
    for (int y=1; y < 10; y++){
      unsigned int uS = sonar.ping();
      iSpy [x][1]  = uS / US_ROUNDTRIP_CM; 
      delay(60); //1000ms = 1s
      Serial.print(iSpy [x][1]);
      Serial.print(" ");
    }
    Serial.println();
//    delay(60); //1000ms = 1s
  }
}

void loop() {
}

Based on the other comments sounds like this is bad.

You need a separate power source for the servo. Connect its ground to the Arduino.

Until you do this, messing with the code is a waste of time.

Moderator edit: Implied language.