Entfernungsmessung mit dem Ultraschallsensor HC-SR04 oder HY-SRF05
Bei einem kleinen Projekt (welches ich in "Meine Projekte" vorgestellt habe, siehe Garagenstopp) habe ich einen Ultraschallsensor im Einsatz. Dafür habe ich mir auch gleich eine Library geschrieben, die meine Erfordernisse für dieses Projekt und vielleicht auch für zukünftige abdecken soll. Die Library kann für Arduino und Attiny eingesetzt werden.
Technische Daten und Anschlüsse des Sensors:
- Spannungsversorgung: DC 5 V
- Stromaufnahme: 15 mA
- Ruhestrom: < 2 mA
- Burstfrequenz: 40 kHz
- Messbereich: ca. 2 cm bis 450 cm
- Auflösung: 0,3 cm HC-SR04, 0,2 cm HY-SRF05
- Messkegel: ca. 15°
- Messungen pro Sekunde: max. 50 HC-SR04, max. 20 HY-SRF05
- Abmessungen: ca. 45*20*15 mm
Bild: Ultraschallsensor HC-SR04 (li) und das Nachfolgemodell(?) HY-SRF05 (re)
Funktionsprinzip:
Nach einer fallenden Flanke am Trigger-Eingang Pin 2 gibt der Sensor ein 40 kHz-Burst-Signal mit einer Länge von 200 us aus. Danach geht der Echo-Ausgang Pin 3 sofort auf H-Pegel und der Sensor wartet auf das Echo des Burst-Signals.
Wird das Echo empfangen, geht der Echo-Ausgang sofort wieder auf L-Pegel. Die Zeit, die der Echo-Ausgang auf H-Pegel verblieben ist, ist also das Maß für die Entfernung zum Gegenstand (= PWM - Pulsweitenmodulation). Diese Zeit muss daher vom Arduino erfasst und in die Entfernung umgerechnet werden.
Um eine neue Messung zu starten, wartet danach der Sensor auf die nächste fallende Flanke am Trigger-Eingang. Beim HC-SR04 muss die Zeit zwischen 2 Messungen mindestens 20 ms betragen (max. 50 Messungen pro Sekunde), beim HY-SRF05 mindestens 50 ms (max. 20 Messungen pro Sekunde)!
Wird kein Echo empfangen (Messung "ins Leere"), geht der Echo-Ausgang nach ca. 200 ms auf L-Pegel und zeigt so eine erfolglose Messung an.
Achtung: Nach jeder Messung "ins Leere" liefert die darauffolgende Messung ein falsches Messergebnis (immer ca. 3 - 5 cm), was meiner Meinung nach an der Auswertesoftware (Firmware) des Sensors selbst liegen muss. Dieses Verhalten habe ich sowohl beim HC-SR04 als auch beim HY-SRF05 festgestellt und in der nachfolgenden Library berücksichtigt (siehe Beschreibung der Library).
Die Funktion des "Out"-Pin beim HY-SRF05 ist mir derzeit unbekannt, da ich leider kein "offizielles" Herstellerdatenblatt gefunden habe und Aussagen darüber auf diversen Internetseiten auch nicht eindeutig sind.
Umrechnung der gemessenen Zeit in die Entfernung:
Der vom Sensor erzeugte Ultraschall breitet sich mit Schallgeschwindigkeit nach folgender Formel aus:
oder in Worten:
Da der Schall aber sowohl den Hin- als auch den Rückweg zurücklegen muss, ist die Entfernung zum Gegenstandes die Hälfte des Weges:
Ist also die Schallgeschwindigkeit bekannt, kann mit der vom Arduino gemessenen Zeit der Weg, bzw. die Entfernung berechnet werden. Allerdings ist die Schallgeschwindigkeit in der Luft keine Konstante, sondern in erster Linie von der Lufttemperatur, aber auch von der Luftfeuchtigkeit abhängig. Die Schallgeschwindigkeit in Abhängigkeit der Lufttemperatur zeigt nachfolgende Tabelle.
Tabelle: Schallgeschwindigkeit in Luft in Abhängigkeit der Lufttemperatur
Mit den nachfolgenden Formeln kann die Schallgeschwindigkeit in m/s näherungsweise berechnet werden:
Die erste Formel habe ich mit MS-Excel aus der obigen Tabelle mit Hilfe einer polynomischen Trendkurve ermittelt:
Die zweite Formel findet man im Internet auf diversen Seiten, wenn man nach "Näherungsformel Schallgeschwindigkeit" sucht:
Den Einfluss der Luftfeuchtigkeit habe ich bei der Berechnung der Schallgeschwindigkeit nicht berücksichtigt, da der Einfluss gegenüber dem Einfluss der Temperatur eher gering ist.
Auszug aus de.wikipedia.org/wiki/Schallgeschwindigkeit:
Beispielsweise ist bei 20 °C die Schallgeschwindigkeit bei 100 % Luftfeuchtigkeit um 0,375 % höher als bei 0 % Luftfeuchtigkeit. Die gleiche Erhöhung der Schallgeschwindigkeit gegenüber trockener Luft würde sich durch eine Temperaturerhöhung auf gut 22 °C ergeben.
Testaufbau am Beispiel HC-SR04:
(Bei Verwendung des HY-SRF05 ist die abweichende Pinbelegung bei Pin 4 und 5 zu beachten)
Verwendete Bauteile:
- 1 Arudino Uno
- 1 Ultraschallsensor HC-SR04
- 1 Temperatursensor LM35
Library MyUltrasonicSensor für Arduino und Attiny:
Die gemessene Entfernung (2 cm bis ca. 4,5 m) zu einem Gegenstand wird von der Library in Zentimeter (cm) zurückgegeben. Erfasst der Sensor in seinem Wirkungsbereich keinen Gegenstand, so gibt die Library als Messergebnis standardmäßig "999" zurück (Variable "maxOverflowVal"), was im Anwenderprogramm verändert werden kann.
Laut Datenblatt kann der HC-SR04-Sensor maximal 50 Messungen pro Sekunde durchführen, das heißt, der zeitliche Abstand zwischen 2 Messungen muss mindestens 20 ms betragen. Der HY-SRF05-Sensor kann maximal 20 Messungen pro Sekunde durchführen, der zeitliche Abstand zwischen 2 Messungen muss daher mindestens 50 ms betragen. Bei kürzeren Zeiten werden die nachfolgenden Messungen durch Echo-Schallwellen der vorangegangenen Messungen beeinflusst. Die Library hat als Standardwert 50 ms vorgegeben (Variable "measureDelay"), dieser Wert kann im Setup eines Programms verändert werden (siehe nachfolgendes Programmbeispiel). Wird jedoch Wert kleiner 20 ms vorgegeben, so wird der Wert trotzdem von der Library auf 20 ms begrenzt.
Wie bereits angemerkt, wenn bei einer Messung kein Echo empfangen wurde (Messung "ins Leere"), liefert die darauffolgende Messung ein falsches Messergebnis (immer ca. 3 - 5 cm), was meiner Meinung nach an der Auswertesoftware (Firmware) des Sensors selbst liegen muss. Die Library startet daher nach jeder Messung "ins Leere" sofort eine neuerliche Messung, ohne dass das Messergebnis dieser zweiten Messung berücksichtigt bzw. ausgegeben wird.
Folgende Funktionen stehen derzeit zur Verfügung:
- Ermittlung der Entfernung bei Raumtemperatur (+20°C) 1)
- Ermittlung der Entfernung bei aktueller Temperatur (-50 ... +50°C) 2)
- Ermittlung der Median-Entfernung von n-Messungen bei aktueller Temperatur 3)
- Detektieren, ob sich ein Gegenstand innerhalb eines definierbaren Entfernungsbereiches befindet 4)
- Berechnung der Schallgeschwindigkeit bei aktueller Temperatur 5)
1) Die Entfernung wird bei einer fix vorgegebenen Schallgeschwindigkeit (jener bei 20 °C Lufttemperatur) ermittelt. Für Messungen, wo mögliche Fehler von einigen cm keine Rolle spielen, z.B. für Torüberwachung oder Durchgangsüberwachung.
2) Hier muss die Temperatur, die - wie im Testaufbau ersichtlich - z.B. mit einem LM35-Temperatursensor ermittelt wird, zur Berechnung der Schallgeschwindigkeit angegeben werden.
3) Die zurückgegebene Entfernung ist der Medianwert (siehe nachfolgende Erklärung) aus mehreren Messungen. Voreingestellt ist, dass 5 Messungen durchgeführt werden. Dieser Wert kann z.B. im Setup verändert werden (Variable "medianNumber", siehe nachfolgendes Beispiel). Der Wert soll einerseits nicht kleiner als 3 sein (sonst macht die Medianberechnung keinen Sinn) und andererseits nicht zu groß, da jede Messung die Bearbeitungszeit um die eingestellte Messverzögerung zwischen 2 Messungen (Voreinstellung 40 ms) verlängert.
4) Das Ergebnis ist TRUE, wenn ein Gegenstand innerhalb des Bereichs erkannt wird, sonst FALSE.
5) Diese Funktion wird innerhalb der Library zur Ermittlung der jeweiligen Schallgeschwindigkeit verwendet und müsste nicht für den Benutzer der Library aufrufbar sein. Wer möchte, kann so die Schallgeschwindigkeit zur Anzeige bringen oder für irgendeine andere Anwendung nutzen.
Wie wird der Medianwert aus einer Messreihe z.B. von 5 Messungen ermittelt:
Dazu ein Beispiel:
Eine Messreihe ergibt folgende Einzelmessungen in cm: 10,5 25,2 10,7 10,6 10,3
Die Abweichungen ergeben sich einerseits aus der Messgenauigkeit des Sensors und der Zeiterfassung des PWM-Signals des Arduinos. Nur der Wert 25,2 weicht, warum sei dahingestellt, von der Messreihe ab.
Zur Ermittlung des Medianwertes müssen die Einzelmessungen zuerst der Größe nach sortiert werden, also: 10,3 10,5 10,6 10,7 25,2
Der Medianwert bei einer ungeraden Anzahl von Messungen entspricht nun dem mittleren Messwert (bei 5 Messungen also dem 3. Messwert), im Beispiel also 10,6 cm.
Wäre die Anzahl der Messungen eine gerade Zahl, so würde der Medianwert dem arithmetischen Mittelwert der beiden mittleren Messwerte entsprechen. Bei z.B. 6 Messwerten also dem arithmetischen Mittelwert des 3. und 4. Messwertes der nach der Größe sortierten Messreihe.
Wie man sieht, spielen bei der Ermittlung des Medianwertes einzelne Falschmessungen für das Ergebnis keine Rolle. Hätte man anstelle des Medianwertes den arithmetischen Mittelwert aus den 5 Messungen berechnet, hätte das Ergebnis 13,46 cm betragen!
Die Library kann hier heruntergeladen werden:
Sollte die Library jemand verwenden oder testen, würde ich mich über eine Rückmeldung sehr freuen!
Version 1.1
Leider kann ich hier keine "cpp"- oder "h"-Files hochladen, daher zum Verwenden der Library das Suffix ".txt" aus diesen Dateinamen entfernen und in einem neuen Verzeichnis mit dem Namen "MyUltrasoundSensor" im Sketchbook-Ordner im Ordner "libraries" speichern.
Zur Auflistung der Funktionen der Library geht es hier: Funktionen
Programmbeispiel MyUltrasoundSensor:
#include <MyUltrasoundSensor.h>
#define trigPin 3
#define echoPin 4
#define tempPin 0
float entfernung;
int tempRohWert; //Rohwert von LM35
float tempWert; //LufttemperaturMyUltrasoundSensor MyUsS(trigPin, echoPin);
void setup() {
Serial.begin(115200);
analogReference(INTERNAL); //Referenzspannung für LM35 auf 1,1 V stellen
//Anzahl der Messungen für Median-Wert (Standardeinstellung = 5)
MyUsS.medianNumber = 3;
//Mindestzeit in ms zwischen 2 Messungen (Standardeinstellung = 50)
//Die kürzeste Zeit darf 20 ms sein (max. 50 Messungen/s) beim HC-SR04//bzw. 50 ms (max. 20 Messungen/s) beim HY-SRF05
//Wird ein kleinerer Wert als 20 angegeben, wird der Wert in der
//Library auf 20 ms begrenzt.
MyUsS.measureDelay = 30;
}
void loop() {
//Lufttemperatur mit LM35 ermitteln
int tempRohWert = analogRead(tempPin);
tempWert = (1.08 / 1024 * tempRohWert) * 100.0;
Serial.print("Lufttemperatur: ");
Serial.println(tempWert);
//Schallgeschwindigkeit anzeigen
Serial.print("Schallgeschwindigkeit: ");
Serial.print(MyUsS.soundVelosity(tempWert) / 100); //Angabe in m/s
Serial.println(" m/s");
//Entfernung ohne Temperaturkompensation
entfernung = MyUsS.distance();
if (entfernung == (-1)) Serial.println("Kein Gegenstand im Messbereich!");
else
{
Serial.print("Entfernung: ");
Serial.println(entfernung);
}
//Entfernung mit Temperaturkompensation
entfernung = MyUsS.distanceTempComp(tempWert);
if (entfernung == (-1)) Serial.println("Kein Gegenstand im Messbereich!");
else
{
Serial.print("Entfernung mit Kompensation: ");
Serial.println(entfernung);
}
//Entfernung als Medianwert
entfernung = MyUsS.distanceTempCompMedian(tempWert);
if (entfernung == (-1)) Serial.println("Kein Gegenstand im Messbereich!");
else
{
Serial.print("Median-Entfernung mit Kompensation: ");
Serial.println(entfernung);
}
//Überprüfung, ob sich ein Gegenstand im Bereich von 5 bis 20 cm befindet
if (MyUsS.detect(tempWert, 5, 20))Serial.println("Gegenstand detektiert");
delay(500);
Serial.println();
}