Wiki

Clone wiki

Arduino New Ping / Home

NewPing Arduino Library for Arduino


Index


Introduction

When I first received an ultrasonic sensor I was not happy with how poorly it performed. I soon realized the problem wasn't the sensor, it was the available ping and ultrasonic libraries causing the problem. The NewPing library totally fixes these problems, adds many new features, and breathes new life into these very affordable distance sensors. Here's a list of some of the features of NewPing:

  • Works with many different ultrasonic sensor models: HC-SR04, SRF05, SRF06, DYP-ME007, JSN-SR04T & Parallax PING)))™.
  • Option to interface with all but the SRF06 sensor using only one Arduino pin.
  • Doesn't lag for a full second if no ping echo is received like all other ultrasonic libraries.
  • Compatible with the entire Arduino line-up (and clones), Teensy family (including $19.80 96Mhz 32 bit Teensy 3.2) and non-AVR microcontrollers.
  • Ping sensors consistently and reliably at up to 30 times per second.
  • Timer interrupt method for event-driven sketches.
  • Built-in digital filter method ping_median() for easy error correction.
  • Uses port registers when accessing pins for faster execution and smaller code size.
  • Allows setting of a maximum distance where pings beyond that distance are read as no ping or clear.
  • Ease of using multiple sensors (sketch that pings 3 sensors - sketch that pings 15 sensors using timers).
  • More accurate distance calculation (cm, inches & microseconds).
  • Doesn't use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models.
  • Actively developed with features being added and bugs/issues addressed.

Download & Install

Download NewPing v1.9.7

Save the .zip file to your desktop, then use the Importing a .zip Library instructions to import the library into the Arduino IDE.

(113,121 downloads on Google Code before being closed)

If you wish to fork this library, please create a private repository as to not confuse others trying to download the latest official version.


Show Your Appreciation

Help future development by making a small donation.

Donate

Supporters (latest: Sept 19th, 2023):

Michael S. $10Muhammad H. $1David T. $5
Nikolaos P. $5James A. $20Baltarete N. $4Brian S. $10
David E. $50Khalsa Pain Relief Clinic $5Bill W. $5Shrimant P. $15
Charlie G. $10Luigino C. $10Ian C. $3William C. $5
S Racing $5Amos S. $15David M. $3Kim F. $10
Tobias E. $2David V. $1Matoe L. $1Ken M. $20
Jw V. $5Dave D. $5Jose R. $5Patrick G. $10
Rüdiger B. $1.50Jason H. $5Lars S. $5Elo Software Co., LTD. $10
Malcolm B. $8K. Worden $2.50SF Simulation Ltd $100Alfredo Z. $10
Charles W. $103 alarm carnival productions $5Charlie S. $3Michael M. $10
Steven P. $10John A. $10Marc D. $5Kfl V. $5
Anatoly S. $10Steve A. $10Darryl F. $2Patrick H. $3
Javier F. $10Kambiz F. $5YourDuino.com $10John S. $2
Pete R. $5Wilson H. $5Zlatko O. $5Muhammad S. $10
JP S. $5Heath M. $25Johann G. $10Aung H. $10
Alan M. $30Alastair M. $20Davide L. $2Mike M. $30
David M. $4Antonio B. $1Carsten W. $3Jose N. $10
Martin M. $5Fred A. $5Alan H. $3Orlando S. $10
Ed N. $10Daniel H. $1Bogdan M. $5Soh K. $10
Pentagono Estudio $1Stephen C. $5Daniel D. $3Adam G. $10
Cha-Rie T. $10Stig M. $5Claudio Z. $5The Forge Initiative $10
Weyman S. $5Bob R. $5Zdenek K. $10Duane G. $10
Ronald B. (Granpa) $20EM Workbench $25Ralph H. $25Ron T. $5
Greg S. $5William M. $10Douglas M. $5Nikita V. $3
Matthew B. $10Olexiy L. $10Matt K. $3Charles D. $10
Frédérik B. $5YourDuino.com $10Silva M. $10David B. $10
Lukas M. $2Jonas H. $2.50Graeme M. $5Alessandro Z. $20
Maximilian S. $10Wally H. $5Debottam B. $2Tim H. $20
Paul M. $5James W. $10Isaac R. $2Erica S. $10



Connection Example

1424201420-2wire_bb.png


Constructor

NewPing sonar(trigger_pin, echo_pin [, max_cm_distance])

Initialize an ultrasonic device, trigger pin, echo pin, and optional maximum distance you wish to sensor to measure (default = 500cm).

Example:

NewPing sonar(12, 11, 200);

This initializes NewPing to use pin 12 for trigger output, pin 11 for echo input, with a maximum ping distance of 200cm. max_cm_distance is optional (default = 500cm). If connecting using a single pin, specify the same pin for both trigger_pin and echo_pin as the same pin is doing both functions.


Methods

  • sonar.ping([max_cm_distance]) - Send a ping and get the echo time (in microseconds) as a result. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.ping_in([max_cm_distance]) - Send a ping and get the distance in whole inches. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.ping_cm([max_cm_distance]) - Send a ping and get the distance in whole centimeters. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.ping_median(iterations [, max_cm_distance]) - Do multiple pings (default=5), discard out of range pings and return median in microseconds. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.convert_in(echoTime) - Convert echoTime from microseconds to inches.
  • sonar.convert_cm(echoTime) - Convert echoTime from microseconds to centimeters.
  • sonar.ping_timer(function [, max_cm_distance]) - Send a ping and call function to test if ping is complete. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.check_timer() - Check if ping has returned within the set distance limit.
  • NewPing::timer_us(frequency, function) - Call function every frequency microseconds.
  • NewPing::timer_ms(frequency, function) - Call function every frequency milliseconds.
  • NewPing::timer_stop() - Stop the timer.

History

v1.9.7 - Released 02/16/2023 - ONE_PIN_ENABLED mode is now automatic, based on if you use the same trigger and echo pins. TRIGGER_WIDTH can now be modified if your sensors are out of spec (defaults to 12uS, previously 10uS).

v1.9.6 - Released 12/15/2022 - Reverted timer overflow commit as it contained bugs.

v1.9.5 - Released 12/13/2022 - Resolved micros() timer overflow bug. Changed example sketch extensions so they load in latest release of the Arduino IDE. Changed private members to protected for easier 3rd party customization.

v1.9.4 - Released 01/26/2022 - Added esp32 to the compatible architectures (note: non-timer methods only).

v1.9.3 - Released 01/20/2022 - Default to disable timer methods for non-AVR microcontrollers and on the ATmega4809 used in the Nano Every.

v1.9.1 - Released 07/15/2018 - Added support for ATtiny441 and ATtiny841 microcontrollers.

v1.9.0 - Released 12/09/2017 - Added support for the ARM-based Particle devices. If other ARM-based microcontrollers adopt a similar timer method that the Particle and Teensy 3.x share, support for other ARM-based microcontrollers could be possible. Attempt to add to Arduino library manager. License changed.

v1.8 - Released 07/30/2016 - Added support for non-AVR microcontrollers. For non-AVR microcontrollers, advanced ping_timer() timer methods are disabled due to inconsistencies or no support at all between platforms. However, standard ping methods are all supported. Added new optional variable to ping(), ping_in(), ping_cm(), ping_median(), and ping_timer() methods which allows you to set a new maximum distance for each ping. Added support for the ATmega16, ATmega32 and ATmega8535 microcontrollers. Changed convert_cm() and convert_in() methods to static members. You can now call them without an object. For example: cm = NewPing::convert_cm(distance);

v1.7 - Released 09/29/2015 - Removed support for the Arduino Due and Zero because they're both 3.3 volt boards and are not 5 volt tolerant while the HC-SR04 is a 5 volt sensor. Also, the Due and Zero don't support pin manipulation compatibility via port registers which can be done (see the Teensy 3.2).

v1.6 - Released 06/17/2014 - Corrected delay between pings when using ping_median() method. Added support for the URM37 sensor (must change URM37_ENABLED from false to true). Added support for Arduino microcontrollers like the $20 32 bit ARM Cortex-M4 based Teensy 3.2. Added automatic support for the Atmel ATtiny family of microcontrollers. Added timer support for the ATmega8 microcontroller. Rounding disabled by default, reduces compiled code size (can be turned on with ROUNDING_ENABLED switch). Added TIMER_ENABLED switch to get around compile-time "_vector_7" errors when using the Tone library, or you can use the toneAC, NewTone or TimerFreeTone libraries. Other speed and compiled size optimizations.

v1.5 - Released 8/15/2012 - Added ping_median() method which does a user specified number of pings (default=5) and returns the median ping in microseconds (out of range pings ignored). This is a very effective digital filter. Optimized for smaller compiled size (even smaller than sketches that don't use a library).

v1.4 - Released 7/14/2012 - You can now interface with all but the SRF06 sensor using only one Arduino pin. Added support for the Parallax PING)))™ sensor. You can also interface with the SRF06 using one pin if you install a 0.1uf capacitor on the trigger and echo pins of the sensor then tie the trigger pin to the Arduino pin (doesn't work with Teensy). To use the same Arduino pin for trigger and echo, specify the same pin for both values. Various bug fixes.

v1.3 - Released 6/8/2012 - Big feature addition, event-driven ping! Uses Timer2 interrupt, so be mindful of PWM or timing conflicts messing with Timer2 may cause (namely PWM on pins 3 & 11 on Arduino, PWM on pins 9 and 10 on Mega, and Tone library). Simple to use timer interrupt functions you can use in your sketches totaly unrelated to ultrasonic sensors (don't use if you're also using NewPing?'s ping_timer because both use Timer2 interrupts). Loop counting ping method deleted in favor of timing ping method after inconsistant results kept surfacing with the loop timing ping method. Conversion to cm and inches now rounds to the nearest cm or inch. Code optimized to save program space and fixed a couple minor bugs here and there. Many new comments added as well as line spacing to group code sections for better source readability.

NOTE: For Teensy/Leonardo (ATmega32U4) the library uses Timer4 instead of Timer2. Also, only 16Mhz microcontrollers are supported with the timer methods, which means the ATmega8 and ATmega128 will not work with the timer methods. However, the standard ping method should work just fine on 8Mhz microcontrollers.

v1.2 - Released 5/24/2012 - Lots of code clean-up thanks to Adruino Forum members. Rebuilt the ping timing code from scratch, ditched the pulseIn code as it doesn't give correct results (at least with ping sensors). The NewPing? library is now VERY accurate and the code was simplified as a bonus. Smaller and faster code as well. Fixed some issues with very close ping results when converting to inches. All functions now return 0 only when there's no ping echo (out of range) and a positive value for a successful ping. This can effectively be used to detect if something is out of range or in-range and at what distance. Now compatible with Arduino 0023.

v1.1 - Released 5/16/2012 - Changed all I/O functions to use low-level port registers for ultra-fast and lean code (saves from 174 to 394 bytes). Tested on both the Arduino Uno and Teensy 2.0 but should work on all Arduino-based platforms because it calls standard functions to retrieve port registers and bit masks. Also made a couple minor fixes to defines.

v1.0 - Released 5/15/2012 - Initial release.


Compatibility

Ultrasonic Sensors

  • HC-SR04, SRF05, SRF06, DYP-ME007, JSN-SR04T, Parallax PING)))™

Platforms - All Methods

  • Arduino Uno, Mega, Mega 2560, Leonardo, Micro, Mini, Nano, Nano Every, Pro, Pro Mini, Fio, Mega ADK, Ethernet, Robot, Bluetooth, Yún, Lilypad, Duemilanove, Diecimila, Teensy 1.x, Teensy 2.x, Teensy 3.x, Particle Photon, Particle Electron, ATmega328, ATmega168, ATmega8, ATmega16, ATmega32, ATmega8535, ATmega4809

Platforms - No Timer Methods

The following won't work with these methods: ping_timer(), check_timer(), timer_us(), timer_ms() & timer_stop(). The reason is either because the microcontroller doesn't have a suitable timer (like the ATtiny line) or doesn't have built-in standardized timer functionality (like the Zero, Due, and other non-AVR microcontrollers). The Tiny 3.x line is the exception due to its built-in standardized timer functionality, so it works with all methods.

  • Arduino Zero, Due, MKR1000, Gemma, ATmega128, ATtiny24, ATtiny44, ATtiny84, ATtiny25, ATtiny45, ATtiny85, ATtiny261, ATtiny461, ATtiny861, ATtiny43U, and most ARM microcontrollers not noted above

Support

Support/Issue Tracking

  • NewPing issue tracking - Create an issue if you're having a problem using NewPing. It's best to have an issue for each unique problem, instead of creating a single issue with multiple problems.

Timer 2 Conflict

  • Having a conflict with the tone library or another library using timer 2? Instead of the tone library, use my NewTone or toneAC libraries which instead uses timer 1 (and also has many other advantages). Or use my Timer Free Tone library which doesn't use any timers to generate tones.

Multiple Definition of "_vector_7" Error

Help with 15 Sensors Sketch

  • Trying to use the 15 sensor sketch and need some help? There's a Wiki help page with loads of information.

Examples

Simple NewPing Sketch

// ---------------------------------------------------------------------------
// Example NewPing library sketch that does a ping about 20 times per second.
// ---------------------------------------------------------------------------

#include <NewPing.h>

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     11  // 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.

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

void setup() {
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

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

Single Pin Sketch

// ---------------------------------------------------------------------------
// NewPing library sketch that interfaces with all but the SRF06 sensor using
// only one Arduino pin. You can also interface with the SRF06 using one pin
// if you install a 0.1uf capacitor on the trigger and echo pins of the sensor
// then tie the trigger pin to the Arduino pin (doesn't work with Teensy).
// ---------------------------------------------------------------------------

#include <NewPing.h>

#define PING_PIN  12  // Arduino pin tied to both trigger and echo pins 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.

NewPing sonar(PING_PIN, PING_PIN, MAX_DISTANCE); // NewPing setup of pin and maximum distance.

void setup() {
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

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

3132521682-SinglePin.png


Ping 3 Sensors Sketch

// ---------------------------------------------------------------------------
// Example NewPing library sketch that pings 3 sensors 20 times a second.
// ---------------------------------------------------------------------------

#include <NewPing.h>

#define SONAR_NUM 3      // Number of sensors.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.

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); // Open serial monitor at 115200 baud to see ping results.
}

void loop() { 
  for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through each sensor and display results.
    delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
    Serial.print(i);
    Serial.print("=");
    Serial.print(sonar[i].ping_cm());
    Serial.print("cm ");
  }
  Serial.println();
}

Custom Speed of Sound Sketch

// ------------------------------------------------------------------------------
// Example NewPing library sketch that uses a custom speed of sound based on temp
// ------------------------------------------------------------------------------

#include <NewPing.h>

#define TRIGGER_PIN  12  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     11  // 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.

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

float temp = 30.5; // Temperature in Celsius (this value would probably come from a temperature sensor).
float factor = sqrt(1 + temp / 273.15) / 60.368; // Speed of sound calculation based on temperature.

void setup() {
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

void loop() {
  delay(1000); // Wait 1 second between distance readings.
  Serial.print("Ping: ");
  Serial.print((float)sonar.ping_median(5) * factor); // Send 5 pings, get median distance, convert to cm and print result
  Serial.println("cm");
}

Event Timer Sketch

// ---------------------------------------------------------------------------
// This example shows how to use NewPing's ping_timer method which uses the Timer2 interrupt to get the
// ping time. The advantage of using this method over the standard ping method is that it permits a more
// event-driven sketch which allows you to appear to do two things at once. An example would be to ping
// an ultrasonic sensor for a possible collision while at the same time navigating. This allows a
// properly developed sketch to multitask. Be aware that because the ping_timer method uses Timer2,
// other features or libraries that also use Timer2 would be effected. For example, the PWM function on
// pins 3 & 11 on Arduino Uno (pins 9 and 11 on Arduino Mega) and the Tone library. Note, only the PWM
// functionality of the pins is lost (as they use Timer2 to do PWM), the pins are still available to use.
// NOTE: For Teensy/Leonardo (ATmega32U4) the library uses Timer4 instead of Timer2.
// ---------------------------------------------------------------------------
#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 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;     // Holds the next ping time.

void setup() {
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
  pingTimer = millis(); // Start now.
}

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.
  }
  // Do other stuff here, really. Think of it as multi-tasking.
}

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");
  }
  // Don't do anything here!
}

Timer Median Sketch

// ---------------------------------------------------------------------------
// Calculate a ping median using the ping_timer() method.
// ---------------------------------------------------------------------------

#include <NewPing.h>

#define ITERATIONS     5 // Number of iterations.
#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 (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[ITERATIONS]; // Holds the times when the next ping should happen for each iteration.
unsigned int cm[ITERATIONS];         // Where the ping distances are stored.
uint8_t currentIteration = 0;        // Keeps track of iteration step.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum 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 < ITERATIONS; i++) // Set the starting time for each iteration.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {
  for (uint8_t i = 0; i < ITERATIONS; i++) { // Loop through all the iterations.
    if (millis() >= pingTimer[i]) {          // Is it this iteration's time to ping?
      pingTimer[i] += PING_INTERVAL * ITERATIONS; // Set next time this sensor will be pinged.
      if (i == 0 && currentIteration == ITERATIONS - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      sonar.timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      currentIteration = i;        // Sensor being accessed.
      cm[currentIteration] = 0;    // Make distance zero in case there's no ping echo for this iteration.
      sonar.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.check_timer())
    cm[currentIteration] = sonar.ping_result / US_ROUNDTRIP_CM;
}

void oneSensorCycle() { // All iterations complete, calculate the median.
  unsigned int uS[ITERATIONS];
  uint8_t j, it = ITERATIONS;
  uS[0] = NO_ECHO;
  for (uint8_t i = 0; i < it; i++) { // Loop through iteration results.
    if (cm[i] != NO_ECHO) { // Ping in range, include as part of median.
      if (i > 0) {          // Don't start sort till second ping.
        for (j = i; j > 0 && uS[j - 1] < cm[i]; j--) // Insertion sort loop.
          uS[j] = uS[j - 1];                         // Shift ping array to correct position for sort insertion.
      } else j = 0;         // First ping is sort starting point.
      uS[j] = cm[i];        // Add last ping to array in sorted position.
    } else it--;            // Ping out of range, skip and don't include as part of median.
  }
  Serial.print(uS[it >> 1]);
  Serial.println("cm");
}

15 Sensors Sketch

NOTICE! - For assistance this this sketch, see: Help with 15 Sensors Example Sketch. But seriously, you probably should REALLY consider using the sketch that pings 3 sensors instead, you've been warned!

This sketch is designed for seasoned programming experts, don't use unless you really know what you're doing!

// ---------------------------------------------------------------------------
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
// would normally process the sensor results in this function (for example, decide if a robot needs to
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
// ---------------------------------------------------------------------------
#include <NewPing.h>

#define SONAR_NUM     15 // 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(41, 42, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  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),
  NewPing(35, 36, MAX_DISTANCE),
  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 = 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.
      if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      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;
}

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
  // The following code would be replaced with your code that does something with the ping results.
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(cm[i]);
    Serial.print("cm ");
  }
  Serial.println();
}

Cool User Projects Using NewPing

newping1.jpgnewping2.jpg
YouTube of Arduino simple object avoidance robot ultrasonicVimeo of sonic interactive table using NewPing



My Other Arduino Libraries

NewPing Works with many ultrasonic sensors, can communicate using only one pin, very low lag, fast (up to 30 pings per second), timer interrupt method for event-driven sketches, light code, and much more.

LCDBitmap Arduino library that allows you to create a tiny 20x16 pixel bitmap (raster) display on a normally character-only Hitachi HD44780 based LCD display. Typical drawing functions like line, rectangle, invert, etc. Control is right down to the pixel level.

toneAC Replacement to the standard tone library with the advantage of nearly twice the volume, higher quality, can produce higher frequencies, 1.5k smaller compiled code, and less stress on the speaker.

toneAC2 Replacement to the standard tone library with the advantage of nearly twice the volume, 800 bytes smaller compiled code size, and less stress on the speaker.

NewTone About 1,200 bytes smaller code size than the standard tone library, faster execution time, exclusive use of port registers for fastest and smallest code, higher quality sound output than tone library.

TimerFreeTone Replacement to the standard tone library but without using timers. Also over 1.5k smaller compiled code, exclusive use of port registers, and compatible with ATmega, ATtiny, and ARM-based microcontrollers.

Updated