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

Hey,

I just recently started using this library and noticed that when I disconnect my sensor and use ping(), instead of getting NO_ECHO (0) sometimes it reports a random number (usually 20-30cm below MAX_SENSOR_DISTANCE). Wondering if anyone else is experiencing this issue?

This is especially impacting the reliability of ping.median() as NO ECHOs are factored out, so even just 1 faulty reading is sufficient for the sensor to still report a measurement.

NewPing.h (renamed to sr4t)

#include "WProgram.h"

#define sr4t_h
#define MAX_SENSOR_DISTANCE 300
#define US_ROUNDTRIP_CM 58
#define NO_ECHO 0
#define MAX_SENSOR_DELAY 5800   // Maximum uS it takes for sensor to start the ping
#define ECHO_TIMER_FREQ 24      // Frequency to check for a ping echo
#define PING_MEDIAN_DELAY 29000
#define PING_OVERHEAD 5
#define PING_TIMER_OVERHEAD 13
#define NewPingConvert(echoTime, conversionFactor) (max(((unsigned int)echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0)))

class sr4t {
public:
sr4t(uint8_t trigger_pin, uint8_t echo_pin, unsigned int max_cm_distance = MAX_SENSOR_DISTANCE);
unsigned int ping(unsigned int max_cm_distance = 0);
unsigned long ping_cm(unsigned int max_cm_distance = 0);
unsigned long ping_in(unsigned int max_cm_distance = 0);
unsigned long ping_median(uint8_t it = 5, unsigned int max_cm_distance = 0);
static unsigned int convert_cm(unsigned int echoTime);
static unsigned int convert_in(unsigned int echoTime);
private:
boolean ping_trigger();
void set_max_distance(unsigned int max_cm_distance);
uint8_t _triggerPin;
uint8_t _echoPin;
unsigned int _maxEchoTime;
unsigned long _max_time;
   };

NewPing.cpp

#include "sr4t.h"

sr4t::sr4t(uint8_t trigger_pin, uint8_t echo_pin, unsigned int max_cm_distance) {
    _triggerPin = trigger_pin;
    _echoPin = echo_pin;
	set_max_distance(max_cm_distance);
    }

unsigned int sr4t::ping(unsigned int max_cm_distance) {
	if (max_cm_distance > 0) set_max_distance(max_cm_distance); // Call function to set a new max sensor distance.
	if (!ping_trigger()) return NO_ECHO; // Trigger a ping, if it returns false, return NO_ECHO to the calling function.
	while (digitalRead(_echoPin))                 // Wait for the ping echo.
	    if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
	    return (micros() - (_max_time - _maxEchoTime) - PING_OVERHEAD); // Calculate ping time, include overhead.
    }

unsigned long sr4t::ping_cm(unsigned int max_cm_distance) {
	unsigned long echoTime = sr4t::ping(max_cm_distance); // Calls the ping method and returns with the ping echo distance in uS.
	return (echoTime / US_ROUNDTRIP_CM);              // Call the ping method and returns the distance in centimeters (no rounding).
    }

unsigned long sr4t::ping_median(uint8_t it, unsigned int max_cm_distance) {
	unsigned int uS[it], last;
	uint8_t j, i = 0;
	unsigned long t;
	uS[0] = NO_ECHO;
	while (i < it) {
		t = micros();                  // Start ping timestamp.
		last = ping(max_cm_distance);  // Send ping.
		if (last != 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] < last; 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] = last;              // Add last ping to array in sorted position.
			i++;                       // Move to next ping.
		    } 
		else it--;                   // Ping out of range, skip and don't include as part of median.
		if (i < it && micros() - t < PING_MEDIAN_DELAY)
			delay((PING_MEDIAN_DELAY + t - micros()) / 1000); // Millisecond delay between pings.
	    }
	return (uS[it >> 3]); // Return the ping 12.5th percentile distance.
    }

boolean sr4t::ping_trigger() {
	pinMode(_triggerPin, OUTPUT); // Set trigger pin to output.
	digitalWrite(_triggerPin, LOW);
	delayMicroseconds(4);
	digitalWrite(_triggerPin, HIGH);
	delayMicroseconds(10);
	digitalWrite(_triggerPin, LOW);
    pinMode(_triggerPin, INPUT);  // Set trigger pin to input (when using one Arduino pin, this is technically setting the echo pin to input as both are tied to the same Arduino pin).
	if (digitalRead(_echoPin)) return false;                // Previous ping hasn't finished, abort.
	_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
	while (!digitalRead(_echoPin))                          // Wait for ping to start.
	    if (micros() > _max_time) return false;             // Took too long to start, abort.
	    _max_time = micros() + _maxEchoTime; // Ping started, set the time-out.
	    return true;                         // Ping started successfully.
    }

void sr4t::set_max_distance(unsigned int max_cm_distance) {
	_maxEchoTime = min(max_cm_distance + 1, (unsigned int) MAX_SENSOR_DISTANCE + 1) * US_ROUNDTRIP_CM; // Calculate the maximum distance in uS (no rounding).
    }

unsigned int sr4t::convert_cm(unsigned int echoTime) {
	return (echoTime / US_ROUNDTRIP_CM);              // Convert uS to centimeters (no rounding).
    }