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

Hi Tim,

i need some support in my current project. I would like to trigger and read
the data of 64 HCSR04 Ultrasonic distance sensors. I want to build an array
of 8x8 sensors with a distance of 6cm to a vibrating wall.
Through the distance variations (Amplitude is big enough) I hope to
get enough information to analyse the wall.

The echo of the sensors will not effect each other. I have a big distance between
each sensor and a special foam behind the sensors which will hopefully absorb the
signals. I read on your website that your sketch can handle 15 sensors on a 33ms
intervall. When I change the Maximum_Distance even smaller intervalls should be possible, correct?

Do you know a possibility to ping as many sensors as possible at the same time?
I know that it will never be possible to trigger 64 sensors at the same time, because
even with Port Manipulation it is just possible to to activate 7 Pins at the same time.
Do you have any suggestions or do you know if somebody has done something similar before?

Lars

Julio26127:
Hi Tim,

i need some support in my current project. I would like to trigger and read
the data of 64 HCSR04 Ultrasonic distance sensors. I want to build an array
of 8x8 sensors with a distance of 6cm to a vibrating wall.
Through the distance variations (Amplitude is big enough) I hope to
get enough information to analyse the wall.

The echo of the sensors will not effect each other. I have a big distance between
each sensor and a special foam behind the sensors which will hopefully absorb the
signals. I read on your website that your sketch can handle 15 sensors on a 33ms
intervall. When I change the Maximum_Distance even smaller intervalls should be possible, correct?

Do you know a possibility to ping as many sensors as possible at the same time?
I know that it will never be possible to trigger 64 sensors at the same time, because
even with Port Manipulation it is just possible to to activate 7 Pins at the same time.
Do you have any suggestions or do you know if somebody has done something similar before?

Lars

You could ping more frequently if there were no echos. But, cross-talk between sensors prohibits multiple sensors being triggered at the same time. As the sensors must SEND before they can receive, if you would ping two sensors at the same time the cross-talk would result in the echo being garbage yielding bad readings.

The only way to do it is to ping each sensor one at a time, or, look for a different technology. It doesn't sound like ultrasonic is a good method for what you're doing, and how much would this wall be vibrating anyway? It would need to be moving more than a CM for it to be detected, and only the center would move I would assume.

Tim

hi Tim,

I would like to use the timer methods for the NewPing library on an ATTiny841.

In the documentation you mention that the ATTinies do not have "a suitable timer". What do you mean by that ?

As far as I can see you are using a 8-bit timer on the atmega328, and there is an 8 bit timer on the ATTiny84 and ATTiny841 as well.

As I use the ATTiny841, which has two 16 bit timers and one 8 bit timer, I'm a bit confused why it would not be possible to use any of the 16 bit timers ?

kind regards,

Gert

GertSanders:
hi Tim,

I would like to use the timer methods for the NewPing library on an ATTiny841.

In the documentation you mention that the ATTinies do not have "a suitable timer". What do you mean by that ?

As far as I can see you are using a 8-bit timer on the atmega328, and there is an 8 bit timer on the ATTiny84 and ATTiny841 as well.

As I use the ATTiny841, which has two 16 bit timers and one 8 bit timer, I'm a bit confused why it would not be possible to use any of the 16 bit timers ?

kind regards,

Gert

Maybe the ATTiny841 is newer than the last time I looked into this or maybe I didn't know about the ATTiny841 or maybe it doesn't have the proper timer addresses. Not sure, nor could I test this as I don't have this chip.

But, did you try it? Looking at the code (line 207 of NewPing.h) it seems that it's specifically looking for known ATtiny microcontrollers that don't have the needed timer addresses to work. The ATtiny841 isn't listed, so the timer would be enabled for the ATtiny841.

In other words... If at the time of writing all ATtiny processors didn't work, then the documentation would say as such. But, if at a later date something was released that did support timers in the needed way, and that microcontroller was not known to me, then the documentation wouldn't updated, as how could it if it's unknown.

Basically, you should try it out and report back if it works.

Tim

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