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

xvjeko:
is it ok to use this:

HC-SR04 -------> > > > > blank space < < < < < - ------HC-SR04 sensor 2

is it ok if i limit the max reading range of both sensors to like 50 cm (and i need to read 50 cm), and i place sensors like 200 cm away from each other…
Would this work if each sensor had an independent microcontroller ???

delay(STEP_TIME);

unsigned int uS1 = SONAR_L.ping();
  per_l = uS1 / US_ROUNDTRIP_CM;




Is the blank space enough, or should i use a "sponge" to prevent interference between 2 of the sensors ?????
THX :grin:

The thing to remember is that setting the maximum distance doesn’t change how strong the trigger ping is nor how far the sensor will actually sense a ping. All it does is just make anything beyond the set distance register as “clear” and the Arduino to stop monitoring that sensor. The strength of the ping and the ability for a sensor to read a ping up to 500cm away is still there.

There’s still a benefit in setting this distance as short as possible for your project. Especially when using the standard ping() method. But, don’t think of it as changing the way the actual sensor works.

What you always need to consider is that when a sensor does a ping, that ping can echo from around 29 to 35ms. It doesn’t matter what you set the maximum distance to, this is how long a ping could be read by another sensor as a stray echo.

So in your example, it really depends on what the time is between pings. If the ping to ping time is 100ms, there would be no issue. If, however, you want to ping both sensors at the exact same time, you could have a problem.

Hope this helps.

Tim

teckel:

xvjeko:
is it ok to use this:

HC-SR04 -------> > > > > blank space < < < < < - ------HC-SR04 sensor 2

is it ok if i limit the max reading range of both sensors to like 50 cm (and i need to read 50 cm), and i place sensors like 200 cm away from each other…
Would this work if each sensor had an independent microcontroller ???

delay(STEP_TIME);

unsigned int uS1 = SONAR_L.ping();
  per_l = uS1 / US_ROUNDTRIP_CM;




Is the blank space enough, or should i use a "sponge" to prevent interference between 2 of the sensors ?????
THX :grin:

The thing to remember is that setting the maximum distance doesn’t change how strong the trigger ping is nor how far the sensor will actually sense a ping. All it does is just make anything beyond the set distance register as “clear” and the Arduino to stop monitoring that sensor. The strength of the ping and the ability for a sensor to read a ping up to 500cm away is still there.

There’s still a benefit in setting this distance as short as possible for your project. Especially when using the standard ping() method. But, don’t think of it as changing the way the actual sensor works.

What you always need to consider is that when a sensor does a ping, that ping can echo from around 29 to 35ms. It doesn’t matter what you set the maximum distance to, this is how long a ping could be read by another sensor as a stray echo.

So in your example, it really depends on what the time is between pings. If the ping to ping time is 100ms, there would be no issue. If, however, you want to ping both sensors at the exact same time, you could have a problem.

Hope this helps.

Tim

Thanks for the anwser…
I will solve the problem by syncing them (only one sensor will work at a time, then a short delay, then the second will work etc…)

There’s been some confusion about how to use the 15 Sensors Example Sketch. I’ve changed some of the comments in the online code to help. But, I think a post explaining this further would be beneficial.

The 15 Sensors Example Sketch uses the ping_timer() method which is designed for event-driven sketches that don’t use delays. If you’re only used to Arduino sketches that are linear and have delays in the code, this concept will be quite foreign to you. However, it’s a good idea to try and embrace an event-driven paradigm. Simple example “hello world” sketches work fine using delays. But, once you try to do a complex project, using delays will often result in a project that just doesn’t do what you want. Consider controlling a motorized robot with remote control that balances and using ping sensors to avoid collisions. Any delay at all, probably even 1 ms, would cause the balancing to fail and therefore your project would never work. In other words, it’s a good idea to start not using delays at all, or you’re going to have a really hard time getting your project off the ground (literally with the balancing robot example).

So, it’s good to first note that the 15 sensor example doesn’t use any delays and is event driven. You can think of it as multitasking. The for() loop in void() polls each sensor array waiting for when it’s that sensor’s time to ping. If it’s time to ping, it triggers a ping_timer() to run in the background. After the for() loop in void() where the comment is, you could add other code here that doesn’t have anything to do with ping sensors. For example: monitoring other sensors, controlling status lights, or whatever. But, it’s VERY important that these other things are also designed in an event-driven way with no delays. If you add delays, it will miss ping times and skip them, resulting in what appears to be an error.

echoCheck() is where the background ping is polled every 24uS to see if a ping was received. If a ping is received, it sets the ping distance in CM in the cm array. You shouldn’t add anything to echoCheck() to use this sketch in its designed way. This function always needs to be very lean as it’s called every 24uS during a ping.

oneSensorCycle() is called once all of your sensors have been polled. Lets say you have 8 sensors. Every time all 8 sensors are pinged, this function is called and you can do something with the results. For example, determine the surroundings of your robot and maybe make a motor direction change. It doesn’t have to output the results over a serial connection, this is just here for testing. In a real-world sketch, you would remove or comment out everything in the oneSensorCycle() function and replace it with your code that does something with the sensor data in the cm array.

Also note, the 15 Sensors Example Sketch is designed to ping all the sensors and then do something with the results once all the sensors have been polled. Some want to ping each sensor and then do something right away maybe between any two pings. To do that, we no longer need the oneSensorCycle() function nor the if() statement in loop() that calls oneSensorCycle(). The following sketch calls the pingResult() function every time there’s a ping within range. Because this sketch still keeps the cm array, you can look at neighboring ping results in the cm array to do whatever calculations you need to do.

#include <NewPing.h>

#define SONAR_NUM      3 // Number of sensors.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
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] = {   // Sensor object array.
  NewPing(4, 5, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(6, 7, MAX_DISTANCE),
  NewPing(8, 9, 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 = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {
  for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
    if (millis() >= pingTimer[i]) {         // Is it this sensor's time to ping?
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
      sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      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 (processing continues, interrupt will call echoCheck to look for echo).
    }
  }
  // Other code that *DOESN'T* analyze ping results can go here.
}

void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer()) {
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
    pingResult(currentSensor);
  }
}

void pingResult(uint8_t sensor) { // Sensor got a ping, do something with the result.
  // The following code would be replaced with your code that does something with the ping result.
  Serial.print(sensor);
  Serial.print(" ");
  Serial.print(cm[sensor]);
  Serial.println("cm");
}

If, however, you don’t really care about comparing neighboring ping results and just want to ping multiple sensors and anytime there’s something within range you want to trigger something, you can totally get rid of the cm array. The following code is probably the easiest to understand, as it simply pings each sensor and when there’s a ping within range, the pingResult() function is called. You get the sensor number and the cm distance which you can do something with. It will only call pingResult() when one of the sensors “hears” something within range.

#include <NewPing.h>

#define SONAR_NUM      3
#define MAX_DISTANCE 200
#define PING_INTERVAL 33

unsigned long pingTimer[SONAR_NUM];
uint8_t currentSensor = 0;

NewPing sonar[SONAR_NUM] = {
  NewPing(4, 5, MAX_DISTANCE),
  NewPing(6, 7, MAX_DISTANCE),
  NewPing(8, 9, MAX_DISTANCE)
};

void setup() {
  Serial.begin(115200);
  pingTimer[0] = millis() + 75;
  for (uint8_t i = 1; i < SONAR_NUM; i++)
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    if (millis() >= pingTimer[i]) {
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;
      sonar[currentSensor].timer_stop();
      currentSensor = i;
      sonar[currentSensor].ping_timer(echoCheck);
    }
  }
  // Other code that *DOESN'T* analyze ping results can go here.
}

void echoCheck() {
  if (sonar[currentSensor].check_timer())
    pingResult(currentSensor, sonar[currentSensor].ping_result / US_ROUNDTRIP_CM);
}

void pingResult(uint8_t sensor, int cm) {
  // The following code would be replaced with your code that does something with the ping result.
  Serial.print(sensor);
  Serial.print(" ");
  Serial.print(cm);
  Serial.println("cm");
}

Remember, to analyze the ping results, you do that in the pingResults() function in the above sketches or in the oneSensorCycle() function in the 15 Sensors Example Sketch. Also, none of these will properly work if you do any delay statements at any point in your sketch.

If you ever want to stop the pings in your sketch, for example to do something that requires delays or takes longer than 33ms to process, do the following:

for (uint8_t i = 0; i < SONAR_NUM; i++) pingTimer[i] = -1;

To start the pings again, do the following:

pingTimer[0] = millis();
for (uint8_t i = 1; i < SONAR_NUM; i++) pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;

Hope this helps! Future questions about using the 15 Sensors Example Sketch will be directed to this post first in the hope this will explain things better. I can see some additions/corrections in the future to further clarify.

Tim

I've bought a chinese "reverse gear obstacle detector for cars" ultrasonic sensor and the board , i checked the board and find the trigger and echo pins for sensor like SR04 , but this sensor has a different specifications from SR04 , i want to use this new ping library for measuring the distance with arduino and this sensor, i am not sure witch parts of the code i have to change to work with my sensor , here is the specification of the sensor i got:

center frequency : 40KHZ (i checked the input pulse on the board with osciloscope it is 16 bursts) Ringing : 1.2ms max maximum input voltage : 120 Vp-p

bulut:
I’ve bought a chinese “reverse gear obstacle detector for cars” ultrasonic sensor and the board , i checked the board and find the trigger and echo pins for sensor like SR04 , but this sensor has a different specifications from SR04 , i want to use this new ping library for measuring the distance with arduino and this sensor, i am not sure witch parts of the code i have to change to work with my sensor , here is the specification of the sensor i got:

center frequency : 40KHZ (i checked the input pulse on the board with osciloscope it is 16 bursts)
Ringing : 1.2ms max
maximum input voltage : 120 Vp-p

Have you tried connecting it and using the sample NewPing sketch? By the pin labels, it sounds like it could work as-is. The 120V is a little confusing, but the specs seems a little thin to begin with. Got a picture or more information?

Tim

Have you tried connecting it and using the sample NewPing sketch? By the pin labels, it sounds like it could work as-is. The 120V is a little confusing, but the specs seems a little thin to begin with. Got a picture or more information?

Tim [/quote]

i tried simple new ping sketch but it just reads up to 40cm and not so much accurate , in you sketch the ping pulse is 1 pulse with 10us width i think if we manipulate the code to 2 or 3 pulses with 16us width it will solve my problem,and i think we have to increase the frequency too.how should we change the code?

i think we have to change this part of code

*_triggerOutput &= ~_triggerBit; // Set the trigger pin low, should already be low, but this will make sure it is.
    delayMicroseconds(4);            // Wait for pin to go low, testing shows it needs 4uS to work every time.
    *_triggerOutput |= _triggerBit;  // Set trigger pin high, this tells the sensor to send out a ping.
    delayMicroseconds(10);           // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS.
    *_triggerOutput &= ~_triggerBit; // Set trigger pin back to low.

i need 16 bursts with period of 21us and frequency of 40KHZ for my trigger , how should i change the code?

bulut: i tried simple new ping sketch but it just reads up to 40cm and not so much accurate , in you sketch the ping pulse is 1 pulse with 10us width i think if we manipulate the code to 2 or 3 pulses with 16us width it will solve my problem,and i think we have to increase the frequency too.how should we change the code?

The 1 pulse / 10uS width is just to trigger the sensor. The sensor detects this and then sends out it's own multiple pulses. In other words, the sensor doesn't just send out one 10uS pulse, we just trigger it. I have not seen a sensor that doesn't automatically send out multiple pulses from a trigger. Are you sure it's not ready doing this? The fact that it reads distances appears that it's working. Do you even know the maximum sensor distance? Maybe it's only 40cm. Also, you may need to change the uS to CM conversion if your sensor puts out different values. The URM37 sensor is a good example of this. For the URM37 you set US_ROUNDTRIP_CM to 50, as that's how it converts and outputs the distance values.

Tim

Do your sensors look like these?:

carsensors.jpg

The 1 pulse / 10uS width is just to trigger the sensor. The sensor detects this and then sends out it's own multiple pulses. In other words, the sensor doesn't just send out one 10uS pulse, we just trigger it. I have not seen a sensor that doesn't automatically send out multiple pulses from a trigger.

i know it how the sensor works but this sensor dosnt operate with 1 pulse / 10 us it works with 16 pulses with period of 21us and frequency of 40KHZ if i can apply this to my sensor it will work, now i just want to know how should i produce this 16 pulses(40KHZ)

Do you even know the maximum sensor distance? Maybe it's only 40cm

the maximum is 5 meter , it reads 40cm but not accurate it has 13cm error.

CyklKent: Do your sensors look like these?:

exactly the same

bulut:

CyklKent: Do your sensors look like these?:

exactly the same

So, you're trying to use just the sensor without the control board? Many people have tried doing this and I have yet to hear of anyone who was successful. The same is true with the typical HC-SR04 type sensors. You can't just use the sensors without the control board.

Basically, if you want to use these sensors, you're going to need to interface with the control board, not the sensors directly. It's not something that can be fixed with software. You need hardware to amplify the signals, issue the pings, etc. You can't just connect them to an Arduino, they won't work that way.

Tim

So, you’re trying to use just the sensor without the control board?

no i am not trying to use the sensor without the board , in my first post i noted that i am using the sensor board . i know if i connect the sensor directly to the arduino it wont work.

It’s not something that can be fixed with software

believe me if we apply the 16 pulses with 21us period with 40KHZ frequency i will be work i am sure, so please tell me how to change the code to produce this pulses .

You need hardware to amplify the signals

the sensor board has the amplifyer inside.

check the pictures

untitled.JPG

bulut: believe me if we apply the 16 pulses with 21us period with 40KHZ frequency i will be work i am sure, so please tell me how to change the code to produce this pulses .

The NewPing library doesn't do the ultrasonic pulses. It only triggers the control board which does the pulses. It's very odd that this control board doesn't do these pulses (that's one of the duties of the control board). I've never heard of a control board that doesn't do the required pulses that the control board's decoder requires. It only makes sense that the control board would issue the correct pulses that it needs on the decode side. It could be how you're doing the ping trigger. Maybe you're not doing the trigger, but actually just a single fire? In other words, maybe you're connecting to the wrong place on the control board.

In any case, doing these pulses is outside the scope of the NewPing library as it would drastically change things and be specific to one individual control board.

What you'll need to do is create your own control function or library. In order to do the pulses with accuracy, you'll need to look into PWM. I don't think the standard Arduino PWM will work as you need to set a frequency of around 47 kHz (21uS) while the maximum Arduino PWM is 1 kHz. Using timers you can get as high as 64 kHz, but I believe the next step would be 32 kHz so you could still have a problem.

I'd really try to get the control board to do the correct pulses (that's its job anyway). If you can't, try looking for PWM library that can do high frequency pulses.

Tim

I am using the new Ping library with my code and have hit a dead end. My code is running a SparkFun stepper motor in a loop where it slowly increments the RPM. I eventually want to control the speed based on the distance measurement from my Ping((( sensor, but I’ve dumbed it down to find the error. It’s not the best code for my motor, but for example sake it works. The problem is that even though I use the ping_timer like in the example calling:

sonar.ping_timer(echoCheck);

stops the motor from moving. once I comment that line out the motor starts working again. below is the code. any ideas?

#include <NewPing.h>
#include <AFMotor.h>


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

AF_Stepper motor(200, 1);
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
unsigned int pingSpeed = 1000; // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
unsigned long pingTimer;     // Holds the next ping time.
int rpm =10;

void setup(){
  Serial.begin(115200);
  pingTimer = millis(); // Start now.
  
  Serial.println("Stepper test!");
  motor.setSpeed(100);  // 100 rpm   
  motor.step(100, FORWARD, SINGLE); 
  Serial.println("step done");
  motor.release();
  delay(1000);
  
}

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.
    sonar.ping_timer(echoCheck); // Send out the ping, calls "echoCheck" function every 24uS where you can check the ping status.
  }
  
  
  Serial.print("setting RMP = ");
  Serial.println(rpm);
  motor.setSpeed(rpm);
  Serial.println();
  Serial.println();
  motor.step(100, FORWARD, SINGLE);
  rpm = rpm +10;
  delay(1000);
}
  void echoCheck() { // Timer2 interrupt calls this function every 24uS where you can check the ping status.
  // Don't do anything here!
  if (sonar.check_timer()) { // This is how you check to see if the ping was received.
    // Here's where you can add code.
    Serial.print("Ping: ");
    Serial.print(sonar.ping_result / US_ROUNDTRIP_CM); // Ping returned, uS result in ping_result, convert to cm with US_ROUNDTRIP_CM.
    Serial.println("cm");
  }
  
  
}

I think this part of the code is incorrect. It will always check as true. That is all that I have found at the moment.

if (millis() >= pingTimer) {   // pingSpeed milliseconds since last ping, do another ping.
    pingTimer += pingSpeed;      // Set the next ping time.
    sonar.ping_timer(echoCheck); // Send out the ping, calls "echoCheck" function every 24uS where you can check the ping status.
  }

Take a look at the blink without delay example.

 unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;  
    
    
    // run function here
    
  }

that code was taken straight from the NewPingEventTimer example code, and as far as I can tell should not always be true.

hbaxton:
I am using the new Ping library with my code and have hit a dead end. My code is running a SparkFun stepper motor in a loop where it slowly increments the RPM. I eventually want to control the speed based on the distance measurement from my Ping((( sensor, but I’ve dumbed it down to find the error. It’s not the best code for my motor, but for example sake it works. The problem is that even though I use the ping_timer like in the example calling:

sonar.ping_timer(echoCheck);

stops the motor from moving. once I comment that line out the motor starts working again. below is the code. any ideas?

I’d start debugging this by removing the Serial.print/Serial.println stuff inside the echoCheck subroutine. This is only there for a test, you should eventually replace it with code that processes the ping result. But for now you can simply delete it. If it still doesn’t work correctly, it could be that the AFMotor library is also using the same timer that NewPing is using to do the stepper motor control.

Also, cyclegadget is correct, you’re not really using the pingTimer correctly. Both ping_timer() and the pingTimer variable are designed to be used WITHOUT delays. If you’re using delays, it’s going to not work correctly.

Basically, if you’re going to use delays, you should not use any of the polling (pingTimer) stuff and shouldn’t use the ping_timer() method. You should just use the standard ping() method. If you want to create a more event driven sketch, you need to be comfortable with not using delay commands.

I simplified your sketch and used the standard ping() method (well, ping_cm() which is ping that converts the result to centimeters). This may make more sense and be a closer fit to what you’re trying to do.

#include <NewPing.h>
#include <AFMotor.h>

AF_Stepper motor(200, 1);
NewPing sonar(7, 7, 200); // NewPing setup of pins and maximum distance.
int rpm = 10;

void setup(){
  Serial.begin(115200);
  Serial.println("Stepper test!");
  motor.setSpeed(100);  // 100 rpm   
  motor.step(100, FORWARD, SINGLE); 
  Serial.println("step done");
  motor.release();
  delay(1000);
}

void loop(){
  int cm = sonar.ping_cm();
  Serial.print(cm);
  Serial.println(" cm");
  
  Serial.print("setting RMP = ");
  Serial.println(rpm);
  motor.setSpeed(rpm);
  Serial.println();
  Serial.println();
  motor.step(100, FORWARD, SINGLE);
  rpm += 10;
  delay(1000);
}

hbaxton: that code was taken straight from the NewPingEventTimer example code, and as far as I can tell should not always be true.

It is always true, because you're adding delays and telling it to start right away, yet then adding a full second delay. Basically, you need to either create an event driven/polling type sketch, or one with delays. Combining the two could give you problems.

It doesn't seem you're comfortable with an event driven/polling type sketch. So, you shouldn't really try to use any example NewPing sketch that uses the ping_timer() method. Stick with ping(), ping_cm(), ping_in(), and ping_median() till you're comfortable with not using the delay() command in your sketch.

Tim

hi teckel & cyclegadget,

thank you for your response. i am new to events. so i tried taking out all the delays and also tried calling the ping function directly but i had the same results. i’m going to look into the adafruit motor library to see if it is using the timer as the new ping library.

thanks again! i’ll report back.