Error Handling
Learn how to handle errors and invalid readings from ultrasonic sensors.
Understanding Error Conditions
Ultrasonic sensors can return invalid readings due to various conditions:
- No echo received - Object too far or not detected
- Timeout exceeded - No valid echo within timeout period
- Invalid angle - Sound wave doesn't bounce back
- Interference - Crosstalk from other sensors or noise
- Environmental factors - Temperature, humidity, soft surfaces
Return Value of 0
When read() returns 0, it indicates an error condition:
cpp
#include <MinimalUltrasonic.h>
MinimalUltrasonic sensor(12, 13);
void loop() {
float distance = sensor.read();
if (distance == 0) {
Serial.println("❌ Error: No valid reading");
} else {
Serial.print("✓ Distance: ");
Serial.print(distance);
Serial.println(" cm");
}
delay(500);
}Basic Error Handling
Check for Valid Readings
cpp
void loop() {
float distance = sensor.read();
if (distance > 0) {
// Valid reading
Serial.print("Distance: ");
Serial.println(distance);
} else {
// Error condition
Serial.println("No object detected");
}
delay(100);
}Range Validation
cpp
const float MIN_VALID = 2.0; // 2 cm minimum
const float MAX_VALID = 400.0; // 4 m maximum
void loop() {
float distance = sensor.read();
if (distance >= MIN_VALID && distance <= MAX_VALID) {
// Valid range
Serial.print("Valid: ");
Serial.println(distance);
} else if (distance == 0) {
Serial.println("Error: No echo");
} else {
Serial.println("Error: Out of range");
}
delay(100);
}Advanced Error Handling
Multiple Readings with Validation
Take multiple readings and use the median to filter out errors:
cpp
#include <MinimalUltrasonic.h>
MinimalUltrasonic sensor(12, 13);
float getMedianDistance(int samples = 5) {
float readings[samples];
int validCount = 0;
// Collect readings
for (int i = 0; i < samples; i++) {
float dist = sensor.read();
if (dist > 0) {
readings[validCount++] = dist;
}
delay(30);
}
// Not enough valid readings
if (validCount < 3) {
return 0;
}
// Sort readings
for (int i = 0; i < validCount - 1; i++) {
for (int j = i + 1; j < validCount; j++) {
if (readings[i] > readings[j]) {
float temp = readings[i];
readings[i] = readings[j];
readings[j] = temp;
}
}
}
// Return median
return readings[validCount / 2];
}
void loop() {
float distance = getMedianDistance();
if (distance > 0) {
Serial.print("Reliable distance: ");
Serial.println(distance);
} else {
Serial.println("Could not get reliable reading");
}
delay(500);
}Error Counter with Threshold
cpp
#include <MinimalUltrasonic.h>
MinimalUltrasonic sensor(12, 13);
int errorCount = 0;
const int ERROR_THRESHOLD = 5;
void loop() {
float distance = sensor.read();
if (distance > 0) {
// Valid reading
errorCount = 0; // Reset error counter
Serial.print("Distance: ");
Serial.println(distance);
} else {
// Error
errorCount++;
Serial.print("Error count: ");
Serial.println(errorCount);
if (errorCount >= ERROR_THRESHOLD) {
Serial.println("⚠️ ALERT: Too many consecutive errors!");
Serial.println("Check sensor connection and power");
// Take corrective action
}
}
delay(100);
}Moving Average Filter
Smooth out noise and reject outliers:
cpp
#include <MinimalUltrasonic.h>
MinimalUltrasonic sensor(12, 13);
const int BUFFER_SIZE = 10;
float buffer[BUFFER_SIZE];
int bufferIndex = 0;
bool bufferFilled = false;
float getFilteredDistance() {
float distance = sensor.read();
// Only add valid readings
if (distance > 0) {
buffer[bufferIndex] = distance;
bufferIndex = (bufferIndex + 1) % BUFFER_SIZE;
if (bufferIndex == 0) {
bufferFilled = true;
}
// Calculate average
int count = bufferFilled ? BUFFER_SIZE : bufferIndex;
if (count == 0) return 0;
float sum = 0;
for (int i = 0; i < count; i++) {
sum += buffer[i];
}
return sum / count;
}
return 0; // Invalid reading
}
void loop() {
float distance = getFilteredDistance();
if (distance > 0) {
Serial.print("Filtered distance: ");
Serial.println(distance);
} else {
Serial.println("Initializing filter...");
}
delay(50);
}Error Recovery Strategies
Strategy 1: Retry on Error
cpp
float readWithRetry(MinimalUltrasonic& sensor, int maxRetries = 3) {
for (int i = 0; i < maxRetries; i++) {
float distance = sensor.read();
if (distance > 0) {
return distance;
}
delay(50); // Wait before retry
}
return 0; // All retries failed
}
void loop() {
float distance = readWithRetry(sensor);
if (distance > 0) {
Serial.println(distance);
} else {
Serial.println("Failed after retries");
}
delay(500);
}Strategy 2: Use Last Known Good Value
cpp
float lastValidDistance = 0;
const unsigned long STALE_THRESHOLD = 5000; // 5 seconds
unsigned long lastValidTime = 0;
void loop() {
float distance = sensor.read();
if (distance > 0) {
// New valid reading
lastValidDistance = distance;
lastValidTime = millis();
Serial.print("Current: ");
Serial.println(distance);
} else {
// Use last known value if not too old
if (millis() - lastValidTime < STALE_THRESHOLD) {
Serial.print("Using cached: ");
Serial.println(lastValidDistance);
} else {
Serial.println("Data too old, no valid reading");
}
}
delay(100);
}Strategy 3: Fallback Mechanism
cpp
enum SensorState {
NORMAL,
DEGRADED,
FAILED
};
SensorState state = NORMAL;
int consecutiveErrors = 0;
void loop() {
float distance = sensor.read();
if (distance > 0) {
consecutiveErrors = 0;
state = NORMAL;
Serial.print("Distance: ");
Serial.println(distance);
} else {
consecutiveErrors++;
if (consecutiveErrors > 10) {
state = FAILED;
Serial.println("❌ SENSOR FAILED - Switch to backup system");
// Activate backup sensor or safe mode
} else if (consecutiveErrors > 5) {
state = DEGRADED;
Serial.println("⚠️ DEGRADED MODE - Unreliable readings");
} else {
Serial.println("Temporary error");
}
}
delay(100);
}Debugging Invalid Readings
Diagnostic Function
cpp
void diagnosticCheck(MinimalUltrasonic& sensor) {
Serial.println("=== Sensor Diagnostic ===");
// Test multiple readings
int validCount = 0;
int invalidCount = 0;
float minDist = 9999;
float maxDist = 0;
float totalDist = 0;
const int TEST_COUNT = 20;
for (int i = 0; i < TEST_COUNT; i++) {
float dist = sensor.read();
if (dist > 0) {
validCount++;
totalDist += dist;
if (dist < minDist) minDist = dist;
if (dist > maxDist) maxDist = dist;
} else {
invalidCount++;
}
delay(50);
}
Serial.print("Valid readings: ");
Serial.print(validCount);
Serial.print("/");
Serial.println(TEST_COUNT);
Serial.print("Invalid readings: ");
Serial.println(invalidCount);
if (validCount > 0) {
Serial.print("Average: ");
Serial.println(totalDist / validCount);
Serial.print("Min: ");
Serial.println(minDist);
Serial.print("Max: ");
Serial.println(maxDist);
Serial.print("Range: ");
Serial.println(maxDist - minDist);
}
// Diagnosis
if (validCount == 0) {
Serial.println("⚠️ PROBLEM: No valid readings!");
Serial.println(" - Check wiring");
Serial.println(" - Check power supply");
Serial.println(" - Verify pin numbers");
} else if (invalidCount > TEST_COUNT / 2) {
Serial.println("⚠️ WARNING: Many invalid readings");
Serial.println(" - Check for interference");
Serial.println(" - Adjust timeout");
Serial.println(" - Check sensor orientation");
} else if (maxDist - minDist > 50) {
Serial.println("⚠️ WARNING: High variance");
Serial.println(" - Use filtering");
Serial.println(" - Check for vibrations");
} else {
Serial.println("✓ Sensor operating normally");
}
Serial.println("=========================");
}
void setup() {
Serial.begin(9600);
delay(1000);
diagnosticCheck(sensor);
}Common Error Patterns
Error: Always Returns 0
Possible Causes:
- Wrong pin numbers
- Disconnected wiring
- Insufficient power
- Incorrect sensor type (3-pin vs 4-pin)
Debug Code:
cpp
void setup() {
Serial.begin(9600);
// Test trigger pin
pinMode(12, OUTPUT);
digitalWrite(12, HIGH);
delay(100);
digitalWrite(12, LOW);
Serial.println("Trigger test complete");
// Test echo pin
pinMode(13, INPUT);
Serial.print("Echo pin state: ");
Serial.println(digitalRead(13));
}Error: Intermittent Invalid Readings
Possible Causes:
- Crosstalk from nearby sensors
- Electrical noise
- Poor connections
- Environmental interference
Solution:
cpp
// Add delays between readings
float distance = sensor.read();
delay(50); // Increase delay
// Or use filtering
float filtered = getMedianDistance();Error: Out of Range Values
Possible Causes:
- Objects beyond detection range
- Timeout too short
- Angled or soft surfaces
Solution:
cpp
// Increase timeout
sensor.setTimeout(40000UL); // 6.8m range
// Validate range
if (distance > 0 && distance < 400) {
// Valid range for HC-SR04
processDistance(distance);
}Best Practices
- Always Validate - Check for
0return value - Use Filtering - Median or moving average for stability
- Set Appropriate Timeouts - Match your detection range
- Add Retry Logic - Single failures are common
- Log Errors - Track error patterns for diagnosis
- Test Thoroughly - Run diagnostics during setup
- Handle Gracefully - Use fallback values or safe modes
Error Handling Checklist
✅ Check if read() returns 0
✅ Validate reading is within expected range
✅ Implement retry mechanism for transient errors
✅ Use filtering to smooth out noise
✅ Track error rates and patterns
✅ Provide fallback behavior
✅ Log errors for debugging
✅ Test error handling code paths
Next Steps
- Best Practices - Overall best practices
- Troubleshooting - Solve specific problems
- Multiple Sensors - Handle multiple sensor errors