NewPing Library: HC-SR04, SRF05, SRF06, DYP-ME007, Parallax PING))) - v1.7

how can i use the library with ultrasonic ks103 sensor?

With great difficulty; it's an I2C device.

yonatan36:
how can i use the library with ultrasonic ks103 sensor?
www.dauxi.com/KS10X-V110_EN.pdf
thank you

Do you already have the ks103 or is there a reason you want to use this model instead of the other, more typical ultrasonic sensors like the SR04?

Tim

Hi Tim,
Yes, I have it...

In which case, you're stuck with whatever algorithm is implemented in the device's firmware.

Great work on the library! I thought I might use this thread for a bit of troubleshooting.

My HC-SR04 is doing some very bizarre things and I'm lost. When using newPing and it's included newpingexample sketch, the sensor returns "0 cm" and there is no reaction to changes in proximity to objects. I tried using the simplest code I could find which doesn't require libraries (pasted below), but the same thing happens, this time reporting strange negative distances (-39 through - 45). I've found that changing the voltage supply effects the numbers, but only once did I get it to correctly report distance and very briefly. Is it possible the sensor has been damaged in some way? I'm using an Uno Rev 3 and a macbook pro (10.6.8 ) for config.

/*
  HC-SR04 Ping distance sensor]
  VCC to arduino 5v GND to arduino GND
  Echo to Arduino pin 13 Trig to Arduino pin 12
*/

int echoPin = 13; 
int trigPin = 12; 

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

void loop() { 
  int duration, cm; 
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(20); 
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(20); 
  digitalWrite(trigPin, LOW); 
  duration = pulseIn(echoPin, HIGH); 
  cm = duration / 29 / 2;
 /* Sound velocity=29cm/microsec,
    then divide by 2 because of the return time */
  Serial.print(cm); 
  Serial.println(" cm"); 
  delay(500); 
}

NewWorldScientist:
Great work on the library! I thought I might use this thread for a bit of troubleshooting.

My HC-SR04 is doing some very bizarre things and I'm lost. When using newPing and it's included newpingexample sketch, the sensor returns "0 cm" and there is no reaction to changes in proximity to objects. I tried using the simplest code I could find which doesn't require libraries (pasted below), but the same thing happens, this time reporting strange negative distances (-39 through - 45). I've found that changing the voltage supply effects the numbers, but only once did I get it to correctly report distance and very briefly. Is it possible the sensor has been damaged in some way? I'm using an Uno Rev 3 and a macbook pro (10.6.8 ) for config.

If the unmodified NewPingExample sketch or the sketch you posted don't work, I would guess it's a faulty sensor. It seems you're doing everything correctly.

Tim

teckel:

I've only been keeping up now and then on this thread; I have yet to try the library, but I have to say it seems like an awesome improvement. I was wondering, though, if you were planning on:

  1. Adding the original PING sensor from Parallax to it
  2. Add code for the Polaroid/Senscomp 6500 sensor

???

I think the first should be done before the second (if the second is done at all), simply because there are some people out there using PING sensors with the Arduino, and it could potentially benefit from this library.

The second would only be worthwhile if it could support both the actual Senscomp 6500, as well as hacked Polaroid camera modules; these hacked modules are described in various places around the web, but the most recent version was done in an issue of Servo magazine not too long ago. In this version, it was described how to get the "old school" hack to work properly with the Arduino (as the original hack wasn't compatible with the Arduino in some manner). Then again, not many people likely purchase the Senscomp 6500 for the Arduino (they aren't cheap new), and most people probably don't hack old Polaroid cameras either (as it is cheaper and easier to buy the mass-produced dual-element modules).

Maybe the Maxbotix sensors should be done instead...?

:smiley:

Has anyone used this library in an obstacle avoiding robot sketch? I have a simple obstacle avoiding sketch that uses an old ultrasonic library, it works. But I wanted to try it with this library. Can I use "Distance = srf06.ping_cm();" in a sketch without the pingtimer/pingspeed code? Or do I have to use the "pingTimer" and "pingSpeed" like in the example? This makes it much harder to use in a sketch. I tried writing a function that returns the distance but I can't get it to work (I'm not much of a programmer).

I have read up on the prev posts. and i have to say i am impressed. I have downloaded the V.1.3 and i have to say ...... beautiful. very good work Tim.

Now my question is how to implement this with an obstacle avoiding sketch. yes similar to the question posted by Bajidi

SANTI

Here is the minimum amount of sketch you need to use the Newping library.

#include <NewPing.h>

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN     13  // Arduino pin tied to echo pin on ping sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

unsigned int pingSpeed = 50;  // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
unsigned long pingTimer = 75; // Holds the next ping time, start at 75ms to give time for the Arduino pins to stabilize.

void setup() {
  }

void loop() {
  // Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distance pings.
  if (millis() >= pingTimer) { // pingSpeed milliseconds since last ping, do another ping.
    pingTimer += pingSpeed;    // Set the next ping time.
    int cm = sonar.ping_cm();  // Send out the ping, get the results in centimeters.
    }
}

This is the part that saves the results to a variabable named "cm". You could change "cm" to distance, length, or fred if it makes you happy.

 int cm = sonar.ping_cm();  // Send out the ping, get the results in centimeters.

cr0sh:
I've only been keeping up now and then on this thread; I have yet to try the library, but I have to say it seems like an awesome improvement. I was wondering, though, if you were planning on:

  1. Adding the original PING sensor from Parallax to it
  2. Add code for the Polaroid/Senscomp 6500 sensor

I believe the Parallax PING))) sensor would almost work with my library as-is. The only difference would be that the trigger/echo pin would need to switch from input to output as the same pin is used for both. I don't have the sensor to test this, but it appears software-wise the interface is identical except for using a unified pin for both trigger/echo. It would only need a few lines of code modification, and it would be easy to automatically detect that it was a PING))) sensor when the same trigger and echo pin was specified.

If someone has this sensor, I'd be more than willing to make a slight modification to the library for you to test.

The Polaroid/Senscomp 6500 sensor also seems to be similar to the SR04. It does appear that there could be a slight trigger difference (leave the trigger high while sensing?). Again, I don't have this sensor to test. But, this sensor also appears to be not nearly as popular. I can't even find an Arduino library for it.

cr0sh:
Maybe the Maxbotix sensors should be done instead...?

I believe the MaxBotix MaxSonar sensors use an analog, PWM, and serial interface. None of which really match well with the current library interface method. Serial (like I2C) would be out for sure, but it would be possible to implement an analog or PWM interface. Again, I don't have this sensor so I can't really do much with it. Someone have one willing to loan me for a couple weeks?

Also, there's other ultrasonic sensors that use the a I2C interface. These I don't currently plan on supporting. Not because there's anything wrong with them, but because each sensor's I2C commands are totally different. Maybe a PingI2C library just for these sensors that are specialized with the proper commands for each sensor.

Tim

Bajdi:
Has anyone used this library in an obstacle avoiding robot sketch? I have a simple obstacle avoiding sketch that uses an old ultrasonic library, it works. But I wanted to try it with this library. Can I use "Distance = srf06.ping_cm();" in a sketch without the pingtimer/pingspeed code? Or do I have to use the "pingTimer" and "pingSpeed" like in the example? This makes it much harder to use in a sketch. I tried writing a function that returns the distance but I can't get it to work (I'm not much of a programmer).

In the attempt to use IMHO "proper" coding (not using the all too popular dreaded "delay" command), I may have confused some looking for the more typical Arduino code with the typical "delay" commands. I have an alternative agenda with NewPing, to make people think a little outside the box and try to avoid the "delay"s. Anyway, following is maybe an easier to understand sketch that uses old-school "delay" commands with NewPing:

#include <NewPing.h>

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN     11  // Arduino pin tied to echo pin on ping sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing srf06(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
}

void loop() {
    // Send out the ping, get the results in centimeters.  Obviously, nothing is being done with this value, your existing sketch would process this information.
    int distance = srf06.ping_cm();

    delay(100);  // Do nothing for 1/10th of a second.  Poor ATmega, it could do 160,000 instructions in this time.
}

There's still a huge advantage in using the NewPing library even using the above sketch. With other ultrasonic libraries (and I assume the one you're using now) if the sensor doesn't get an echo, the Arduino is just sitting there waiting for a full second for the results (which never arrives). During this time, no new processing is happening. A second is a VERY long time, you could be doing 16 million instructions in that time. With the above sketch, the longest it will sit waiting for an echo is about 30ms (because the maximum distance is set to 200cm). Therefore, if you implement NewPing in your existing sketch it should seem much faster and consistent when the sensor is not getting a ping echo. Making your sketch event-driven would further speed up your sketch and allow you to avoid using "delay" commands. But, NewPing doesn't require this, and your sketch will benefit even if you still use delays.

The "ping_timer" and "check_timer" methods along with the resulting "ping_result" value is a totally different way of interfacing with the sensor. This can further make your sketch event-driven which frees up more processing cycles to do other things in your sketch. It may be a little more advanced, but is really not that hard. Here's an ultra-simple example (you would enter your own robot control code as the sketch does nothing as-is).

#include <NewPing.h>

#define TRIGGER_PIN  12 // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN     11 // Arduino pin tied to echo pin on ping sensor.
#define MAX_DISTANCE 50 // Maximum distance we want to ping for (in centimeters). I set this to 50cm because in a robot situation you probably don't care about an object 200cm away.

NewPing srf06(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
    // Set robot to drive forward.
}

void loop() {
    srf06.ping_timer(echoCheck); // Set the function you want to call to check for a ping
    delay(100);  // Do nothing for 1/10th of a second.  Poor ATmega, it could do 160,000 instructions in this time.
}

void echoCheck() { // Timer2 interrupt calls this function every 24uS where you can check the ping status.
      if (srf06.check_timer()) { // This is how you check to see if the ping was received.
          // Detected object within 50cm of robot, call turn function here.  srf06.convert_cm(srf06.ping_result) would be the distance in cm if you need it for your sketch.
      }
}

I hope these scripts make the different methods of NewPing more clear for some.

Tim

SANTIMO:
I have read up on the prev posts. and i have to say i am impressed. I have downloaded the V.1.3 and i have to say ...... beautiful. very good work Tim.

Now my question is how to implement this with an obstacle avoiding sketch. yes similar to the question posted by Bajidi

SANTI

At a minimum, you can just drop this library in to your existing code and use it instead of the old ultrasonic/ping library you're using now. The syntax of the constructor and methods are designed to match those of other libraries so in most cases it should be very simple to swap. If you have an existing sketch, you could post it and I'd show you how easy it is to switch things over. Or, just post the important parts like the library call, constructor, and calls to your existing library.

Tim

great job... i use the library in my project and test my robot.
i have 15 SRF05 sonar sensors on the bot. I set pingSpeed 200ms, and pingInterval 35ms, but sometimes i get big value or negative value.

#include <NewPing.h>
#define MAX_DISTANCE 200

NewPing sonar0(41, 42, MAX_DISTANCE);
NewPing sonar1(43, 44, MAX_DISTANCE);
NewPing sonar2(45, 20, MAX_DISTANCE);
NewPing sonar3(21, 22, MAX_DISTANCE);
NewPing sonar4(23, 24, MAX_DISTANCE);
NewPing sonar5(25, 26, MAX_DISTANCE);
NewPing sonar6(27, 28, MAX_DISTANCE);
NewPing sonar7(29, 30, MAX_DISTANCE);
NewPing sonar8(31, 32, MAX_DISTANCE);
NewPing sonar9(34, 33, MAX_DISTANCE); //10
NewPing sonar10(35, 36, MAX_DISTANCE); //11
NewPing sonar11(37, 38, MAX_DISTANCE);
NewPing sonar12(39, 40, MAX_DISTANCE);
NewPing sonar13(50, 51, MAX_DISTANCE);
NewPing sonar14(52, 53, MAX_DISTANCE);

#define pingSpeed      100
#define pingInterval   35
#define SONAR_NUM      15
unsigned long pingTimer[SONAR_NUM];

void setup()
{

  Serial.begin(115200);
  pingTimer[0] = millis() + pingSpeed;
  for(int i = 0; i < SONAR_NUM - 1; i++) {
    pingTimer[i+1] = pingTimer[i] + pingInterval;
  }
}

void loop() 
{
  int cm[15];
  unsigned long time = millis();
  if (millis() >= pingTimer[0]) {
    pingTimer[0] += pingSpeed;   
    cm[0] = sonar0.ping_cm();
  }
  if (millis() >= pingTimer[1]) {
    pingTimer[1] = pingTimer[0] + pingInterval;   
    cm[1] = sonar1.ping_cm();
  }
  
  if (millis() >= pingTimer[2]) {
    pingTimer[2] = pingTimer[1] + pingInterval;    
    cm[2] = sonar2.ping_cm();
  }  
  
  if (millis() >= pingTimer[3]) {
    pingTimer[3] = pingTimer[2] + pingInterval;
    
    cm[3] = sonar3.ping_cm();

  }

  if (millis() >= pingTimer[4]) {
    pingTimer[4] = pingTimer[3] + pingInterval;

    cm[4] = sonar4.ping_cm();

  }
  
  if (millis() >= pingTimer[5]) {
    pingTimer[5] = pingTimer[4] + pingInterval;
    
    cm[5] = sonar5.ping_cm();
  }
  
  if (millis() >= pingTimer[6]) {
    pingTimer[6] = pingTimer[5] + pingInterval;

    cm[6] = sonar6.ping_cm();
  }
  
  if (millis() >= pingTimer[7]) {
    pingTimer[7] = pingTimer[6] + pingInterval;
    cm[7] = sonar7.ping_cm();
  }
  
  if (millis() >= pingTimer[8]) {
    pingTimer[8] = pingTimer[7] + pingInterval;
    cm[8] = sonar8.ping_cm();
  }
  
  if (millis() >= pingTimer[9]) {
    pingTimer[9] = pingTimer[8] + pingInterval;
    cm[9] = sonar9.ping_cm();
  }
  
  if (millis() >= pingTimer[10]) {
    pingTimer[10] = pingTimer[9] + pingInterval;
    cm[10] = sonar10.ping_cm();
  }
  
  if (millis() >= pingTimer[11]) {
    pingTimer[11] = pingTimer[10]+ pingInterval;
    cm[11] = sonar11.ping_cm();
  }
  
  if (millis() >= pingTimer[12]) {
    pingTimer[12] = pingTimer[11]+ pingInterval;
    cm[12] = sonar12.ping_cm();
  }

  if (millis() >= pingTimer[13]) {
    pingTimer[13] = pingTimer[12]+ pingInterval;
    cm[13] = sonar13.ping_cm();
  }

  if (millis() >= pingTimer[14]) {
    pingTimer[14] = pingTimer[13]+ pingInterval;
    cm[14] = sonar14.ping_cm();
    for(int i = 0; i < 15; i++) {
      Serial.print("Ping");
      Serial.print(i);
      Serial.print(": ");
      Serial.print(cm[i]);
      Serial.print("cm");
    }
    Serial.println();
  }  
}

The ping12 result like this :

Ping12: 3328cm
Ping12: 12288cm
Ping12: -24544cm

my code is not simple and clean, and i'd like to know how to use NewPing to slove 15 sonar sensors problem

 if (millis() >= pingTimer[13]) {
    pingTimer[13] = pingTimer[12]+ pingInterval;
    cm[13] = sonar13.ping_cm();
  }

Your code would be an awful lot shorter if you formed another array of the sonar objects.

AWOL:

 if (millis() >= pingTimer[13]) {

pingTimer[13] = pingTimer[12]+ pingInterval;
    cm[13] = sonar13.ping_cm();
  }



Your code would be an awful lot shorter if you formed another array of the sonar objects.

thanks for your advise, and i want to shorter my code. But i don't know how to form NewPing object array. Counld you tell me how to do?

I've been using a parallax ping))) using the way described in the tutorial, but I would like to start optimizing my code. I am already using timing events instead of delays between ping measurements to allow processing between ping measurements. I also understand the arduino may hang up to a second while waiting for an echo to not arrive. I believe this is due to the default timeout in the pulseIn command. Is there any difference between just changing this timeout to a maximum distance and using your library (other than the interrupt method)?

For example
duration = pulseIn(pingPin, HIGH, 5800) // 29 us per centimeter * 200 cm max distance

JesterSig:
I've been using a parallax ping))) using the way described in the tutorial, but I would like to start optimizing my code. I am already using timing events instead of delays between ping measurements to allow processing between ping measurements. I also understand the arduino may hang up to a second while waiting for an echo to not arrive. I believe this is due to the default timeout in the pulseIn command. Is there any difference between just changing this timeout to a maximum distance and using your library (other than the interrupt method)?

For example
duration = pulseIn(pingPin, HIGH, 5800) // 29 us per centimeter * 200 cm max distance

First, setting a limit would greatly help your current sketch. But, you have a bit of a math issue as 200cm is 400cm round-trip and the speed of sound in a typical indoor environment is closer to 28.5uS/cm. If you wanted to set a maximum distance of 200cm, you should set it to around 11400uS, not 5800uS. 5800uS would be closer to 102cm max distance.

There's a few differences in NewPing over standard Ping/Ultrasonic libraries. Off the top of my head:

  • Doesn't lag for 1 second if no ping/echo is received.
  • Uses port registers for a faster interface to the pins and smaller code size.
  • Allows you to set a maximum distance where pings beyond that distance are read as no ping "clear".
  • Ease of using multiple sensors.
  • More accurate distance calculation.
  • Same library works with different ultrasonic sensor models.
  • Doesn't use pulseIn, which gives incorrect results with some ultrasonic sensor models.
  • Timer interrupt method for event-driven sketches.
  • Being actively developed with features being added and bugs/issues addressed.

So, changing your current sketch so pulseIn is set to a timeout of 11400 should noticeably improve your sketch. But, using NewPing (especially if you used the interrupt events) would improve your sketch even more.

With that said, NewPing won't currently work with the Ping))) sensor as it uses the same pin for trigger and echo. It shouldn't be a big deal to make NewPing compatible with the Ping))) sensor and I'd love to make it compatible. So, if you're willing to give it a try, I could modify NewPing for you and have you try it out.

You should consider using the interrupt method of NewPing at some point also. As you're already using timing events instead of delays, using the interrupt method of NewPing would free up the ATmega instead of waiting up to 11400uS for a ping to echo back.

Tim

Thanks so much for the fast reply! I've been trying to learn more about libraries and yours is one of the ones I've been playing with. Thanks for correcting my math, I'm sure I would have realized I forgot the return trip when I got home to actually test it. I also wasn't aware that port registers worked faster.

I'll probably come back to your library some time in the future when I want to add more sensors or to change over to interrupts. In the mean time I may try changing the library to work with the parallax ping. I don't mind stumbling around for a while to learn something.

duxiaoshi:
great job... i use the library in my project and test my robot.
i have 15 SRF05 sonar sensors on the bot. I set pingSpeed 200ms, and pingInterval 35ms, but sometimes i get big value or negative value.

The ping12 result like this :

Ping12: 3328cm
Ping12: 12288cm
Ping12: -24544cm

my code is not simple and clean, and i'd like to know how to use NewPing to slove 15 sonar sensors problem

15 sensors! Now THAT'S what I'm talking about as a perfect use for the NewPing library!

First, is this only happening for sensor 12? If so, that could isolate the problem to something wrong with that sensor.

In any case, I believe the problem is that you're setting up the pings to happen 35ms apart, but then starting the loop process again in only 100ms. This works for 2 sensors, as it only takes 352=70ms per cycle through all the sensors. But, with 15, it would take at least 525ms to cycle through all 15 sensors (3515=525). Also, as AWOL stated, making an array of sonar objects makes the code a LOT shorter. I also noticed you're not using the "time" variable and the "cm" array should be set outside loop(). Below is a streamlined version of your sketch. I also converted it to use the timer event so it's more event driven:

#include <NewPing.h>

#define SONAR_NUM     15
#define MAX_DISTANCE 200
#define PING_INTERVAL 35 // Milliseconds between each sensor ping (35ms is about the minimum to avoid cross-sensor echos.  You could try making this as low as 29ms and see what happens).

const int pingCycle = PING_INTERVAL * (SONAR_NUM + 1); // This used to be PING_SPEED, pings as fast as possible.
unsigned long pingTimer[SONAR_NUM + 1]; // +1 for timer that displays results.
unsigned int cm[SONAR_NUM]; // Where the ping distances are stored.
uint8_t currentSensor = 0;  // Keeps track of which sensor is active.

NewPing sonar[SONAR_NUM] = {
  NewPing(41, 42, MAX_DISTANCE),
  NewPing(43, 44, MAX_DISTANCE),
  NewPing(45, 20, MAX_DISTANCE),
  NewPing(21, 22, MAX_DISTANCE),
  NewPing(23, 24, MAX_DISTANCE),
  NewPing(25, 26, MAX_DISTANCE),
  NewPing(27, 28, MAX_DISTANCE),
  NewPing(29, 30, MAX_DISTANCE),
  NewPing(31, 32, MAX_DISTANCE),
  NewPing(34, 33, MAX_DISTANCE), //10
  NewPing(35, 36, MAX_DISTANCE), //11
  NewPing(37, 38, MAX_DISTANCE),
  NewPing(39, 40, MAX_DISTANCE),
  NewPing(50, 51, MAX_DISTANCE),
  NewPing(52, 53, MAX_DISTANCE)
};

void setup() {
  Serial.begin(115200);
  pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting.
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    pingTimer[i+1] = pingTimer[i] + PING_INTERVAL;
  }
}

void loop() {
  for (uint8_t i = 0; i <= SONAR_NUM; i++) {
    if (millis() >= pingTimer[i]) {
      pingTimer[i] += pingCycle; // Set next time this sensor will be pinged.
      if (i == SONAR_NUM) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      else {
        sonar[currentSensor].timer_stop(); // Make sure previous timer is canceled before starting a new ping.
        currentSensor = i; // Sensor being accessed.
        cm[currentSensor] = 0; // Make distance zero in case there's no ping echo for this sensor.
        sonar[currentSensor].ping_timer(echoCheck); // Do the ping and wait for the echo interrupt.
      }
    }
  }
  // The rest of your code would go here.
}

void echoCheck() {
  if (sonar[currentSensor].check_timer()) { // Check to see if the ping was received.
    cm[currentSensor] = sonar[currentSensor].convert_cm(sonar[currentSensor].ping_result); // Set the sensor distance to the array.
  }
}

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(cm[i]);
    Serial.print("cm ");
  }
  Serial.println();
}

I don't have 15 sensors nor an Arduino Mega to totally test this sketch. But, I did test it with 3 sensors and it worked. Let me know how it works with your project. Also, I'd love to see a picture of whatever you have going with 15 sensors.

Tim