ping

xod-dev/hc-sr04/ping

Measures sound roundtrip time with HC-SR04 ultrasonic range meter. Outputs infinity on no echo. Possible errors: — Invalid port — Wrong connection
ping
@/ping
Measures sound roundtrip time with HC-SR04 ultrasonic range meter. Outputs infinity on no echo. Possible errors: — Invalid port — Wrong connection
DEV@/hc-sr04-device
PINGpulse
Triggers new ultrasonic ping which would result in the output update once sound echo will be captured. Pulses coming within 60 ms window after last one are ignored to fight sensor’s PCB resonance.
ping
Ts
DONE
DEV
PING
DONEpulse
Fires when ping is done
Tsnumber
Last measured sound roundtrip time in seconds.
To use the node in your project you should have the xod-dev/hc-sr04 library installed. Use the “File → Add Library” menu item in XOD IDE if you don’t have it yet. See Using libraries for more info.

C++ implementation

#pragma XOD evaluate_on_pin disable
#pragma XOD evaluate_on_pin enable input_PING
#pragma XOD error_raise enable

node {
    static const uint32_t HCSR04_MAX_START_US = 5000;
    static const uint32_t HCSR04_MAX_ROUNDTRIP_US =
        1000ul * 1000ul         // seconds to μs
        * 4ul                   // max meters
        * 2ul                   // to the moon and back
        / 340ul;                // sound speed

    enum Status {
        HCSR04_OK,
        HCSR04_NO_ECHO,
        HCSR04_WRONG_CONNECTION
    };

    Status pingSync(uint8_t echoPort, uint8_t trigPort, uint32_t* outRoundtripUs) {
        uint32_t maxUs;

        // Request measurement: make a pulse for 10 μs.
        pinMode(trigPort, OUTPUT);
        digitalWrite(trigPort, HIGH);
        delayMicroseconds(10);
        digitalWrite(trigPort, LOW);

        // Wait for echo pin rise which means ultrasonic burst success
        maxUs = micros() + HCSR04_MAX_START_US;
        pinMode(echoPort, INPUT);
        while (digitalRead(echoPort) == LOW) {
            if (micros() > maxUs)
                return HCSR04_WRONG_CONNECTION;
        }

        // Now wait for echo line to be pulled back low which means echo capture
        uint32_t tStart = micros();
        maxUs = tStart + HCSR04_MAX_ROUNDTRIP_US;
        while (digitalRead(echoPort) == HIGH) {
            if (micros() > maxUs)
                return HCSR04_NO_ECHO;
        }

        *outRoundtripUs = micros() - tStart;
        return HCSR04_OK;
    }

    void evaluate(Context ctx) {
        if (!isInputDirty<input_PING>(ctx))
            return;

        auto dev = getValue<input_DEV>(ctx);

        // TODO: static port validation
        if (!isValidDigitalPort(dev->echoPort) || !isValidDigitalPort(dev->trigPort)) {
            raiseError(ctx); // Invalid port
            return;
        }

        uint32_t t;
        auto status = pingSync(
            dev->echoPort,
            dev->trigPort,
            &t
        );

        if (status == HCSR04_OK) {
            emitValue<output_Ts>(ctx, Number(t) / 1000000.0);
            emitValue<output_DONE>(ctx, 1);
        } else if (status == HCSR04_NO_ECHO) {
            emitValue<output_Ts>(ctx, INFINITY);
            emitValue<output_DONE>(ctx, 1);
        } else {
            raiseError(ctx); // HCSR04_WRONG_CONNECTION
        }
    }
}