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

hi Tim,

it did not compile properly (it did not find an ASSR symbol). I tried changing things to allow it to use Timer0, which is the 8 bit timer on this MCU (Timer2 is 16 bit).
That also failed, but that is probably due to my poor understanding of the datasheet.

I do have another question: when ping_cm() is called, will it execute for the duration of time needed for the echo to register (or up to the time needed for MAX_DISTANCE) ?
Does it basically only continue when either the echo is detected or the maximum wait time for MAX_DISTANCE expires ?

I use the SR-HC04 with a max distance of 150cm, and will be using it mostly for shorter distances, so that would mean that I can ping sensors every 89micro seconds (if I use 8 of them spread out to avoid false echo's).

Would be nice to get confirmation on this last question. Gert

GertSanders:
hi Tim,

it did not compile properly (it did not find an ASSR symbol). I tried changing things to allow it to use Timer0, which is the 8 bit timer on this MCU (Timer2 is 16 bit).
That also failed, but that is probably due to my poor understanding of the datasheet.

I do have another question: when ping_cm() is called, will it execute for the duration of time needed for the echo to register (or up to the time needed for MAX_DISTANCE) ?
Does it basically only continue when either the echo is detected or the maximum wait time for MAX_DISTANCE expires ?

I use the SR-HC04 with a max distance of 150cm, and will be using it mostly for shorter distances, so that would mean that I can ping sensors every 89micro seconds (if I use 8 of them spread out to avoid false echo's).

Would be nice to get confirmation on this last question. Gert

ping_cm() uses blocking mode, so yes, it will wait till it gets a ping back or it exceeds the defined max distance. Remember it's not just what you set for the software as the max distance, there's the physical world to consider, and those pings may echo in the real world no matter how you set the max distance. In other words, you could still have echo and cross-talk issues even if you only care about shorter distances. Multiple sensors cause even more cross-talk and echo problems. Nothing a library can do about this, as you're dealing with the speed of sound, echos (the physical world) and the sensitivity of the sensors (hardware limitations).

Tim

Hi :slight_smile: I'm a student who is completing an HND in systems engineering, my graded unit project inlvolves and arduino, ultrasonic sensor, relay switch, buzzer and a pump. When the ultrasonic see's my given high and low parameters is switches the relay which activates both my pump and buzzer for the duration of filling the tank.

I have the programme working fine :):slight_smile: however i'm experiencing rapid switching when the sensor reaches around my high and low level. Through some research I have now added hysteresis to help issues, however, i can't seem to get it to work properly.

I have posted the current adapted programme below, can anyone help? Please.....

// defines pins numbers
const int trigPin = 9;
const int echoPin = 10;
const int buzzer = 11;
const int relayPin = 13;

// defines variables
long duration;
int distance;
int lastDistance;
int hysteresis = 2;

void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(buzzer, OUTPUT);
pinMode(relayPin, OUTPUT);
Serial.begin(9600); // Starts the serial communication
}

void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(1000);

// Sets the trigPin on HIGH state for 30 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(1000);
digitalWrite(trigPin, LOW);

// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);

// Calculating the distance
distance= duration*0.034/2;

lastDistance = distance;
if ((lastDistance + hysteresis) <= 12 && (lastDistance - hysteresis) >= 4){
digitalWrite(buzzer, HIGH);
digitalWrite(relayPin, HIGH);
}

else{
digitalWrite(buzzer, LOW);
digitalWrite(relayPin, LOW);
}

// Prints the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.println(distance);
}

Student83:
Hi :slight_smile: I'm a student who is completing an HND in systems engineering, my graded unit project inlvolves and arduino, ultrasonic sensor, relay switch, buzzer and a pump. When the ultrasonic see's my given high and low parameters is switches the relay which activates both my pump and buzzer for the duration of filling the tank.

I have the programme working fine :):slight_smile: however i'm experiencing rapid switching when the sensor reaches around my high and low level. Through some research I have now added hysteresis to help issues, however, i can't seem to get it to work properly.

I have posted the current adapted programme below, can anyone help? Please.....

// defines pins numbers
const int trigPin = 9;
const int echoPin = 10;
const int buzzer = 11;
const int relayPin = 13;

// defines variables
long duration;
int distance;
int lastDistance;
int hysteresis = 2;

void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(buzzer, OUTPUT);
pinMode(relayPin, OUTPUT);
Serial.begin(9600); // Starts the serial communication
}

void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(1000);

// Sets the trigPin on HIGH state for 30 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(1000);
digitalWrite(trigPin, LOW);

// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);

// Calculating the distance
distance= duration*0.034/2;

lastDistance = distance;
if ((lastDistance + hysteresis) <= 12 && (lastDistance - hysteresis) >= 4){
digitalWrite(buzzer, HIGH);
digitalWrite(relayPin, HIGH);
}

else{
digitalWrite(buzzer, LOW);
digitalWrite(relayPin, LOW);
}

// Prints the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.println(distance);
}

You're not even using the NewPing library, which is the purpose of this thread and would greatly clean up your code. Also, putting code inside a code container would make your code much easier to read. You could also use the ping_median() method in NewPing to even out a lot of the bouncing around that happens if you're only doing a single ping, this would greatly reduce the results you're getting.

Anyway, I'd start with using the NewPing library, using the example sketch, adding the buzzer instead of outputing the results to serial, and change the ping_cm() to ping_median() to smooth out the results better. That's a good start.

Tim

Thank you for responding, I'm a new user and unsure how I start a new topic hence the backing onto this thread :open_mouth:
I'll look over the info you have suggested and re-try. Thank you :slight_smile:

Student83:
Thank you for responding, I'm a new user and unsure how I start a new topic hence the backing onto this thread :open_mouth:
I'll look over the info you have suggested and re-try. Thank you :slight_smile:

I've converted your code to use NewPing and use NewPing's built-in ping_median() method which in this example will do 5 pings and return the median value. This typically provides more stable results as it throws out the "noise". Depending on how fast you need the loop to run, you could increase the MEDIAN_PINGS define to 7 or higher (typically odd numbers). This would provide even more stable results.

#include <NewPing.h>

#define TRIGGER_PIN    9 // Arduino pin tied to trigger pin on the ultrasonic sensor
#define ECHO_PIN      10 // Arduino pin tied to echo pin on the ultrasonic sensor
#define BUZZER_PIN    11 // Arduino pin tied to buzzer pin
#define RELAY_PIN     13 // Arduino pin tied to relay pin
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters)
#define MEDIAN_PINGS   5 // The nubmer of pings to fire

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

unsigned long duration;
unsigned int distance, lastDistance, hysteresis = 2;

void setup() {
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
  Serial.begin(9600); // Starts the serial communication
}

void loop() {
  // Do 5 pings, use the median distance, returns the sound wave travel time in microseconds
  duration = sonar.ping_median(MEDIAN_PINGS);

  // Calculating the distance
  distance = duration / US_ROUNDTRIP_CM;

  lastDistance = distance;
  if ((lastDistance + hysteresis) <= 12 && (lastDistance - hysteresis) >= 4) {
    digitalWrite(BUZZER_PIN, HIGH);
    digitalWrite(RELAY_PIN, HIGH);
  } else {
    digitalWrite(BUZZER_PIN, LOW);
    digitalWrite(RELAY_PIN, LOW);
  }

  // Prints the distance on the Serial Monitor
  Serial.print("Distance: ");
  Serial.println(distance);
}

If, however, what you are measuring is moving, you may not wan to use the ping_median() method. Instead, something like this would be better:

#include <NewPing.h>

#define TRIGGER_PIN    9 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN      10 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define BUZZER_PIN    11 // Arduino pin tied to buzzer pin
#define RELAY_PIN     13 // Arduino pin tied to relay pin
#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 distance, lastDistance, hysteresis = 2;

void setup() {
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
  Serial.begin(9600); // Starts the serial communication
}

void loop() {
  delay(50); // Wait 50ms between pings (about 20 pings/sec)

  distance = sonar.ping_cm(); // Do a ping, returns the distnace in CM

  lastDistance = distance;
  if ((lastDistance + hysteresis) <= 12 && (lastDistance - hysteresis) >= 4) {
    digitalWrite(BUZZER_PIN, HIGH);
    digitalWrite(RELAY_PIN, HIGH);
  } else {
    digitalWrite(BUZZER_PIN, LOW);
    digitalWrite(RELAY_PIN, LOW);
  }

  // Prints the distance on the Serial Monitor
  Serial.print("Distance: ");
  Serial.println(distance);
}

Neither of these examples modify your hysteresis logic. But, it may work better because you're using the NewPing library instead of rolling your own.

Tim

What is the status of false positives the library may give?

In my situation I'm pointing an SR04 (4-prong model) into nowhere and setting the max distance to 400 cm (max per the spec).

I still get false positives quite often even outside of the house in the backyard.

I used single ping_cm() call , then did convert_cm(ping_median()) (default 5 signals) still the library returns false positives quite often.

Can it be the case of misbehaving sensor? Because I have 2 and with both the library behaves identically.

nskmda:
What is the status of false positives the library may give?

In my situation I'm pointing an SR04 (4-prong model) into nowhere and setting the max distance to 400 cm (max per the spec).

I still get false positives quite often even outside of the house in the backyard.

I used single ping_cm() call , then did convert_cm(ping_median()) (default 5 signals) still the library returns false positives quite often.

Can it be the case of misbehaving sensor? Because I have 2 and with both the library behaves identically.

Returning false-positives is probably the sensor as I never get them. Also, I don't hear of this kind of problem from others very frequently.

But, it's possible that if you're trying to do pings too frequently you could be doing a ping and stepping over the last ping, causing the echo pin to be high when it's being monitored.

It's also possible that your sensor needs more time to wait before listening for a ping. There's a define in NewPing.h named MAX_SENSOR_DELAY that by default is set to 5800. It's possible that your sensor needs more time. Try setting MAX_SENSOR_DELAY to 40000 and see if that gives you better results. This value is set via a define to allow you to change it if you're particular sensor needs more time.

Tim

teckel:
Returning false-positives is probably the sensor as I never get them.
...

But, it's possible that if you're trying to do pings too frequently...

It's also possible that your sensor needs more time to wait before listening for a ping. There's a define...

Tim, thanks a lot for the response.

I'll try to change the delay (is it in micro-seconds or in something else? i mean, why 40K as the new value).
Am I guessing it right I'm going to the lib's source code for that? Or can I override the #def in my sketch'es code? (I'm a Java guy, only have brief experience with C/C++).

If it doesn't help then it may totally be a sensor (it was shipped even w/o antistatic bag).

Also, my sketch has the main loop delay(250) between pings. Also, on a detection (distance > 0) I send a radio ping (which also takes some time).
Do you think I need to extend the delay?

nskmda:
Tim, thanks a lot for the response.

I'll try to change the delay (is it in micro-seconds or in something else? i mean, why 40K as the new value).
Am I guessing it right I'm going to the lib's source code for that? Or can I override the #def in my sketch'es code? (I'm a Java guy, only have brief experience with C/C++).

If it doesn't help then it may totally be a sensor (it was shipped even w/o antistatic bag).

Also, my sketch has the main loop delay(250) between pings. Also, on a detection (distance > 0) I send a radio ping (which also takes some time).
Do you think I need to extend the delay?

It's in the NewPing source code, but it's very easy to change (just a txt file like your sketch).

Setting the MAX_SENSOR_DELAY to 40000 is in microseconds. I'm suggesting to set it high to see if that resolves anything. Setting it to just a slightly larger delay probably won't do anything, so it's not worth trying.

One thing you said was a little confusing. When you get a ping back you say you send a "radio ping". Is that another sonar ping or something else?

Maybe your sketch would help, as you could be song something incorrectly which I would never know without seeing your code. It's kinda a standard rule here that you should always post your sketch, as that's typically the only way anyone can help (or else they're just guessing).

Tim,
I will try to post my sketch.

No, the 'radio ping' is just that - radio: I'm using the RadioHead lib + transmitter module (which should not interfere with the sonar, I hope!) to send signal from the backyard into the house.

I'll update and re-test the behavior.

One thing which I might have missed is what could interfere with sonar outside in the 'wild'?

Because I already tried a PIR module, but it turned out to get a lot of interference (like wind and sun) and I had to switch to sonar (as - hopefully - less prone to interference of those kinds).

Because, again, inside the sensor seemed to work more or less stable (in open space I didn't see too many positives in the serial output in monitor).

One thing which just came to my mind: I'm connecting the sensor directly, w/o any extra curcuitry (i.e., capasitors, diodes, resistors etc.) to the board and am using direct powering, not from the board's pins.
Have you heard about anything extra which may make those sensors be more stable?
But anyway, I did test it inside the house and the serial output looked pretty stable...

nskmda:
Tim,
I will try to post my sketch.

No, the 'radio ping' is just that - radio: I'm using the RadioHead lib + transmitter module (which should not interfere with the sonar, I hope!) to send signal from the backyard into the house.

I'll update and re-test the behavior.

One thing which I might have missed is what could interfere with sonar outside in the 'wild'?

Because I already tried a PIR module, but it turned out to get a lot of interference (like wind and sun) and I had to switch to sonar (as - hopefully - less prone to interference of those kinds).

Because, again, inside the sensor seemed to work more or less stable (in open space I didn't see too many positives in the serial output in monitor).

One thing which just came to my mind: I'm connecting the sensor directly, w/o any extra curcuitry (i.e., capasitors, diodes, resistors etc.) to the board and am using direct powering, not from the board's pins.
Have you heard about anything extra which may make those sensors be more stable?
But anyway, I did test it inside the house and the serial output looked pretty stable...

Make sure all your grounds are tied together if you have multiple power sources or voltages, that can cause problems.

Maybe understanding better what you're doing would be helpful. If it's outside, an insect, bird or whatever could easily be giving you these false-positives. If you're trying to detect something that's mostly stationary or moving slowly, another technique is to do multiple pings per loop and only report a positive result if all (or most) have a ping result. For example, something like this code snip-it:

#include <NewPing.h>

NewPing sonar(12, 11, 500);

unsigned int pings[3];

void loop() {
  for (uint8_t i = 0; i < 3; i++) {
    delay(50);
    pings[i] = sonar.ping_cm();
    if (pings[0] > 0 and pings[1] > 0 and pings[2] > 0) {
      // ping the radio
    }
  }
}

This would only ping your radio if you received 3 positive pings in a row within 150ms. You could easily change this from 2 to 3 pings if you wanted to require only 2 pings for a positive radio ping.

Again, seeing your sketch and what you're trying to accomplish can GREATLY help diagnosing and resolving your problem.

Tim

Tim,

Here's the sketch:

#include <NewPing.h>
#include <RH_ASK.h>
#include <SPI.h>

RH_ASK driver(500);

boolean driverInitialized = false;
boolean somethingStirring = false;
boolean messageSent = false;
const char *msg = "object around!";

#define SONAR_SENSORS 1
#define MAX_DISTANCE_CM 350

NewPing sonar[SONAR_SENSORS] = 
{
  NewPing(8, 9, MAX_DISTANCE_CM)
};

void setup()
{

  Serial.begin(9600);

  driverInitialized = driver.init();
  if (!driverInitialized)
  {
    Serial.println("radio driver init failed");  
  }
  else
  {
    Serial.println("radio driver initialized");
  }
  delay(5000);
}

void loop()
{
  if (driverInitialized)
  {
    if (shouldSendMessage())
    {
      sendObjectDetected();
    }
  }
  delay(250);
}

boolean shouldSendMessage()
{
  boolean sonarDetected = false;
  for (int i=0; i<SONAR_SENSORS; i++)
  {
    String distance = "Sonar ";
    distance.concat(i);
    distance.concat(" distance returned: ");
    int median_cm = NewPing::convert_cm(sonar[i].ping_median(3));
    distance.concat(median_cm);
    Serial.println(distance);
    sonarDetected = sonarDetected || (median_cm>0);
    if (sonarDetected) { break; }
  }
  return sonarDetected;
}

void sendObjectDetected()
{
  Serial.println("sending object signal");
  driver.send((uint8_t *)msg, strlen(msg));
  driver.waitPacketSent();
  Serial.println("object signal sent");
}

I originally planned to use 2 sensors, but now I'm only doing one.

nskmda:
Tim,

I originally planned to use 2 sensors, but now I'm only doing one.

Something like this...

#include <NewPing.h>
#include <RH_ASK.h>
#include <SPI.h>

RH_ASK driver(500);
NewPing sonar(8, 9, 350);

boolean driverInitialized = false;
boolean somethingStirring = false;
boolean messageSent = false;
const char *msg = "object around!";
unsigned int pings[3];

void setup() {
  Serial.begin(9600);

  driverInitialized = driver.init();
  if (!driverInitialized) {
    Serial.println("radio driver init failed");  
  } else {
    Serial.println("radio driver initialized");
  }
  delay(5000);
}

void loop() {
  if (driverInitialized) {
    for (uint8_t i = 0; i < 3; i++) {
      delay(50);
      pings[i] = sonar.ping_cm();
    }
    unsigned int average_cm = 0;
    if (pings[0] > 0 and pings[1] > 0 and pings[2] > 0) {
      average_cm = (pings[0] + pings[1] + pings[2]) / 3;
    }
    String distance = "Sonar distance returned: ";
    distance.concat(average_cm);
    Serial.println(distance);
    if (average_cm > 0) {
      sendObjectDetected();
    }
  }
}

void sendObjectDetected() {
  Serial.println("sending object signal");
  driver.send((uint8_t *)msg, strlen(msg));
  driver.waitPacketSent();
  Serial.println("object signal sent");
}

teckel:
Something like this...

Yes, I got the idea.
I can totally do similar.

But I tried to experiment today and looks like there really might have been something which caused the sensor to receive a reflected signal back.

I put it on the front porch pointing to the sky. And it was okay for some time. Then there was a bit of drizzle and it started 'overreacting" again (it looked like water got on the protective mesh in front of the transmitter/receiver).

I will test more.
But I tried to change the '#define' and for some reason the IDE didn't pick up the change (i tried to put something non-compilable in the .h file and it still was okay with the sketch).

Do I need to find where the .zip file went? Or may be uninstall/reinstall the library somehow?

Hi Tim,

Apologies if this has already been asked. I am trying to use NewPing with the dfrobot waterproof sensor (link below), but I can't get the demo examples to report anything other than zero. My board is an Arduino Mega 2560. The example listed on the wiki page below does work. I've tried both the IDE (1.8.5) and the web editor.

Should this be possible? Many of the sites selling this product link to NewPing so I assumed so.

https://www.dfrobot.com/wiki/index.php/Weather_-_proof_Ultrasonic_Sensor_with_Separate_Probe_SKU_:_SEN0208

Edit: It seems I may have the JSN-SR04T-2.0, which is not compatible with the previous version, or likely with NewPing.

Thanks,
Craig

Hello everybody.

First of all, I would like to say a few words about my project: For a long time, I have been using a level indicator for my water reservoir with an Arduino Mega and a DYP-ME007Y waterproof ultrasonic module.
For various reasons, I would like to switch to an ESP8266 (IoT, OTA, etc.) and then the problems begin. The old DYP-ME007Y module has a serial interface. But I need the one serial interface with the ESP8266 for the upload of the sketch. That's why I switched to an AJ-SR04M or JSN-SR04T module (trigger and echo as interface).
To increase the accuracy I would like to use the NewPing Library (median value and iterations etc).
Now I have 2 problems:
1.: If I do not use the NewPing-Lib for distance measurement (trigger pulse and evaluation by "pulseIn (echo, HIGH)"), then I get from a distance of about 3m completely wrong results. I also read somewhere that the ESP8266 has problems with "pulseIn" ...
2nd: That's why I try to use the NewPing-Lib, because here on "pulseIn" is omitted. But when I use the NewPing lib, I get much worse or no results at all. Only about every twentieth value is displayed correctly, since only very rarely a trigger pulse is sent out.

I've spent many weeks for troubleshooting, but can not find any mistake. Does anyone have any idea why it does not work or where to find the mistake? Did someone already have similar problems? I am grateful for any help or tip!

Best regards
Martin

scytayl:
Hi Tim,

Apologies if this has already been asked. I am trying to use NewPing with the dfrobot waterproof sensor (link below), but I can't get the demo examples to report anything other than zero. My board is an Arduino Mega 2560. The example listed on the wiki page below does work. I've tried both the IDE (1.8.5) and the web editor.

Should this be possible? Many of the sites selling this product link to NewPing so I assumed so.

Weather_-_proof_Ultrasonic_Sensor_with_Separate_Probe_SKU___SEN0208-DFRobot

Edit: It seems I may have the JSN-SR04T-2.0, which is not compatible with the previous version, or likely with NewPing.

Thanks,
Craig

If the JSN-SR04T-2.0 operates with a trigger and echo, it should work. If the sketch on the link works, so should NewPing, as they're doing the same basic thing to initiate a ping and listen for a result.

Tim

Weissglut:
Hello everybody.

First of all, I would like to say a few words about my project: For a long time, I have been using a level indicator for my water reservoir with an Arduino Mega and a DYP-ME007Y waterproof ultrasonic module.
For various reasons, I would like to switch to an ESP8266 (IoT, OTA, etc.) and then the problems begin. The old DYP-ME007Y module has a serial interface. But I need the one serial interface with the ESP8266 for the upload of the sketch. That's why I switched to an AJ-SR04M or JSN-SR04T module (trigger and echo as interface).
To increase the accuracy I would like to use the NewPing Library (median value and iterations etc).
Now I have 2 problems:
1.: If I do not use the NewPing-Lib for distance measurement (trigger pulse and evaluation by "pulseIn (echo, HIGH)"), then I get from a distance of about 3m completely wrong results. I also read somewhere that the ESP8266 has problems with "pulseIn" ...
2nd: That's why I try to use the NewPing-Lib, because here on "pulseIn" is omitted. But when I use the NewPing lib, I get much worse or no results at all. Only about every twentieth value is displayed correctly, since only very rarely a trigger pulse is sent out.

I've spent many weeks for troubleshooting, but can not find any mistake. Does anyone have any idea why it does not work or where to find the mistake? Did someone already have similar problems? I am grateful for any help or tip!

Best regards
Martin

Are you using version 1.9.0? Also to keep it simple, are you using the example simple NewPing sketch? You could also try setting ONE_PIN_ENABLED to false

Tim

Yes of course. I am useing the 1.9.0-Version. And yes I keep the sketch as simple as possible (like the NewPing Example). So nothing else could disturb the measurement.
What do you mean by "try setting ONE_PIN_ENABLED to false" ?

BR Martin

Edit: Okay. I know what you are meaning with "try setting ONE_PIN_ENABLED to false". I set this parameter at the NewPing.h to false, but it did not solve the problem. Every time I reset the ESP8266 I am getting 2 "good" results. After the first 2 results, most of the time I get "0" at the output-monitor. And only a very few times, a trigger was sending...