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).
}