HCSR04

Mit Hilfe des HCSR04 Ultraschall-Abstandssensors lassen sich Abstände von 2 cm bis 300 cm messen. Er wird verwendet zur Kollisionsprävention von Robotern oder zum Messen der aktuellen Höhe bei der Landung von Quadrocoptern. Der Abstandssensor hat einen Eingang um eine Messung zu starten und einen Ausgang um das Echo-Signal zu empfangen. Das empfangene Signal ist ein leicht zu interpretierendes binäres Signal. Genauere Informationen sind unter dem Punkt 'Aufbau' oder dem Datenblatt zu entnehmen. In diesem Tutorial wird im 500 ms-Takt der Abstand gemessen und auf der Konsole ausgegeben.

Inhalt


Material

  • HCSR04
  • Diverse Kabel
  • Steckbrett

Aufbau

Der Abstandssensor ist sehr einfach anzusteuern. Er hat insgesamt folgende vier Anschlüsse:

HCSR04
Dabei sind die Anschlüsse VCC und GND trivial. Mit einer fallenden Flanke an TRIG startet man eine Messung. Hier würde ein Rechteck-Signal mit einer adäquaten Frequenz zu einer kontinuierlichen Messung führen. Das Ergebnis kann am ECHO-Anschluss ausgelesen werden. Nach dem Starten einer Messung liegt ein HIGH-Pegel am ECHO an. Eine fallende Flanke an ECHO in unter 200 ms nach Starten einer Messung bedeutet, dass ein Echo empfangen wurde. Eine fallende Flanke nach 200 ms bedeutet, dass kein Echo empfangen wurde und die Messung fehlgeschlagen ist. Im Programm muss dieser Fall erkannt und entsprechend behandelt werden.

Der gesamte Aufbau ist sehr einfach:

Gesamtaufbau

Bei mehreren Abstandssensoren würde ein einziger Anschluss für alle TRIG-Signale ausreichen. Der Abstand zwischen zwei TRIG-Signale muss mindestens 20 ms sein. Ein Rechteck-Signal mit 50 Hz ist folglich die maximal mögliche Frequenz zum kontinuierlichen Messen.

Programm

Der Ultraschall-Abstandssensor benötigt zwei Anschlüsse, die initialisiert werden müssen:
#define TRIG 28
#define ECHO 29

void init() {
    pinMode(TRIG, OUTPUT);
    pinMode(ECHO, INPUT);
    digitalWrite(TRIG, HIGH);
}
Das Programm wird in zwei Threads laufen. Ein Thread erzeugt das Rechteck-Signal zum Triggern des Sensors, während der andere Thread in einer Endlosschleife das Echo-Signal ausliest. Als erstes kommen die Funktionen für das Rechteck-Signal. Dazu wird eine Funktion benötigt, die einen kurzen LOW-Peak erzeugt, um mit einer fallenden Flanke eine Messung auszulösen. Die Funktion sieht wie folgt aus:
#define TRIGTIME 50

void TRIG_tick() {
    digitalWrite(TRIG, LOW);
    delayMicroseconds(TRIGTIME);
    digitalWrite(TRIG, HIGH);
    delayMicroseconds(TRIGTIME);
}
Insgesamt benötigt die Funktion mindestens 100 Mikrosekunden. Diese Funktion wird in einer Endlosschleife kontinuierlich aufgerufen. Ich habe mich dazu entschieden, jede halbe Sekunde eine Messung zu starten. Die Zeit kann beliebig angepasst werden.
#define WAVELENGTH 500

void infiniteRect() {
    while(1) {
        TRIG_tick();
        delay(WAVELENGTH);
    }
}
Damit ist für das Rechteck-Signal alles vorbereitet.

Die Funktion für das Auslesen ist ein wenig komplexer, beinhaltet aber alles, was unter dem Punkt 'Aufbau' genannt ist. Es wird gewartet, bis das ECHO-Signal auf HIGH ist. Der Zeitpunkt dafür wird mit clock_gettime aus der time.h aufgezeichnet. Anschließend wird gewartet, bis das Signal auf LOW zurück fällt. Der Zeitpunkt dafür wird ebenfalls dokumentiert und eine Differenz zum Startzeitpunkt berechnet. Die Differenz wird mit der Schallgeschwindigkeit multipliziert und damit der gesamte Weg für den Schall berechnet. Da die Schallwelle sich hin und anschließend wieder zurück bewegt, muss die Distanz durch 2 dividiert werden, um die Strecke für eine einzige Richtung zu ermitteln. Dies ist dann die gemessene Distanz zum Objekt. Das ganze in Form einer Funktion sieht folgendermaßen aus:

void infiniteRead() {
    struct timespec start;
    struct timespec end;

    while(1) {
        while(digitalRead(ECHO) == LOW) {
            // Abwarten bis Triggersignal eine Messung auslöst.
            // Sobald ECHO auf HIGH, geht eine Messung los.
        }

        // Akutellen Zeitpunkt zum Beginn der Messung bestimmen.
        clock_gettime(CLOCK_REALTIME, &start);

        while(digitalRead(ECHO) == HIGH) {
            // Abwarten bis Messung zuende ist.
            // Sobald ECHO auf LOW, ist die Messung vorbei.
        }

        // Akutellen Zeitpunkt zum Ende der Messung bestimmen.
        clock_gettime(CLOCK_REALTIME, &end);

        // Zeitdifferenz in Mikrosekunden
        unsigned int timediff = (end.tv_nsec - start.tv_nsec)/1000;

        // 200 ms = 200000 Mikrosekunden
        if(timediff >= 200000) {
            // Laut Datenblatt wird nach 200 ms die Messung abgebrochen,
            // falls kein Echo gemessen wird.
            std::cout << "Fehlerhafte Messung." << std::endl;
        }
        else {
            /*  1. 343 m/s = 0.0343 cm/Mikrosekunden
                2. timediff liegt in Mikrosekunden vor
                3. timediff * 0.0343 cm/Mikrosekunden sind
                   doppelte Distanz zum Objekt in cm
                   weil der Schall hin und zurück geht.
                4. Division durch 2 um Distanz für nur einen Weg zu haben
            */
            double dist = (timediff*0.0343)/2;
            std::cout << "Distanz in cm: " << dist << std::endl;
        }
    }
}
Nun muss das ganze in einer main-Funktion zusammengefasst werden:
int main() {
    if(wiringPiSetup() == -1) {
        return 0;
    }

    init();

    std::thread rect(infiniteRect);
 
    infiniteRead();

    return 0;
}
Die Funktion clock_gettime benötigt eine weitere Bibliothek 'lrt', die beim Kompilieren mit eingebunden werden muss. Außerdem muss man beachten, dass std::thread zum c++11 Standard gehört und dies beim Kompilieren ggf. beachtet werden muss. Beispielsweise wird g++ Version 4.7 benötigt. Die Kommandozeile sah bei mir so aus:
g++-4.7 US.cpp -o US -lwiringPi -lrt -std=c++11
Beim Ausführen dieses Programms wird nun jede halbe Sekunde eine Distanz in cm zu einem Objekt, auf den der Sensor gerichtet ist, auf der Konsole ausgeben.

Ich hoffe dieses Tutorial hat euch bei der Verwendung des HCSR04 weitergeholfen oder euch seinen Nutzen näher gebracht und euch zum Kauf angeregt. Für weitere Informationen zum HCSR04 siehe:

Keine Kommentare:

Kommentar veröffentlichen

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.