Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HC-SR04 Ultrasonic Sensor #114

Closed
bennuttall opened this issue Nov 16, 2015 · 21 comments
Closed

HC-SR04 Ultrasonic Sensor #114

bennuttall opened this issue Nov 16, 2015 · 21 comments
Assignees
Milestone

Comments

@bennuttall
Copy link
Member

Another one from camjam kit 3, see the worksheet

Example code:

pinTrigger = 17
pinEcho = 18

GPIO.setup(pinTrigger, GPIO.OUT)
GPIO.setup(pinEcho, GPIO.IN)

while True:
    GPIO.output(pinTrigger, False)
    time.sleep(0.5)

    # Send 10us pulse to trigger
    GPIO.output(pinTrigger, True)
    time.sleep(0.00001)
    GPIO.output(pinTrigger, False)

    StartTime = time()
    # The start time is reset until the Echo pin is taken high (==1)
    while GPIO.input(pinEcho) == 0:
        StartTime = time()
    # Stop when the Echo pin is no longer high - the end time
    while GPIO.input(pinEcho) == 1:
        StopTime = time()
        # If the sensor is too close to an object, the Pi cannot
        # see the echo quickly enough, so it has to detect that
        # problem and say what has happened
        if StopTime-StartTime >= 0.04:
            print("Hold on there! You're too close for me to see.")
            StopTime = StartTime
            break
    # Calculate pulse length
    ElapsedTime = StopTime - StartTime
    # Distance pulse travelled in that time is
    # time multiplied by the speed of sound (cm/s)
    Distance = ElapsedTime * 34326
    # That was the distance there and back so halve the value
    Distance = Distance / 2
    print("Distance : %.1f" % Distance)
    time.sleep(0.5)
@martinohanlon
Copy link
Contributor

My example:

import RPi.GPIO as GPIO
from time import time, sleep

#the factor used to times the echo time by to get the distance
DISTANCEFACTOR = 17000

class HCSR04Sensor:
    def __init__(self, triggerPin, echoPin):
        #persist values
        self.triggerPin = triggerPin
        self.echoPin = echoPin

        #setup pins
        GPIO.setup(triggerPin, GPIO.OUT)
        GPIO.setup(echoPin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

        #set trigger to off
        GPIO.output(triggerPin, False)

    def getEcho(self):
        #if the echo pin is high wait for it to go low
        if GPIO.input(self.echoPin) == 1:
            while GPIO.input(self.echoPin) == 1:
                pass

        #turn trigger on
        GPIO.output(self.triggerPin, True)

        #wait 10 micro settings
        sleep(0.00001)

        #turn trigger off
        GPIO.output(self.triggerPin, False)

        #wait for the echo to go high
        while GPIO.input(self.echoPin) == 0:
            pass
        #start the timer
        start = time()

        #wait for it to go low
        while GPIO.input (self.echoPin) == 1:
            pass
        #stop the timer
        end = time()

        #work out the time difference
        diff = end - time

        return diff

    def getDistance(self):
        return self.getEcho() * DISTANCEFACTOR

#test
if __name__ == "__main__":

    #set the mode
    GPIO.setmode(GPIO.BCM)

    #pins
    TRIGGERPIN = 23
    ECHOPIN = 24    

    try:
        #create the sensor
        sensor = HCSR04Sensor(TRIGGERPIN, ECHOPIN)
        while True:
            #read the distance
            print sensor.getDistance()
            sleep(0.01)
    finally:
        #cleanup the GPIO
        GPIO.cleanup()

@alaudet
Copy link

alaudet commented Nov 24, 2015

I have an HCSR04 sensor module I put together and use for a sump pit monitoring system. The module allows extra functionality

  • adjusting speed of sound based on temperature.
  • returns imperial or metric measurements.
  • uses the median reading of a sample of readings to eliminate wacky readings that get returned once in a while.
  • return rounded values

https://github.com/alaudet/hcsr04sensor/blob/master/hcsr04sensor/sensor.py

Sample usage scripts
https://github.com/alaudet/hcsr04sensor/tree/master/examples

@waveform80
Copy link
Member

@alaudet - Very interesting stuff - I'll certainly dig into that when I get around to the ultra-sonic sensor, thanks!

@waveform80
Copy link
Member

Got an ultra-sonic in the CamJam 3 kit now so I can work on this for 1.2.

@waveform80 waveform80 added this to the v1.2 milestone Feb 8, 2016
@waveform80 waveform80 self-assigned this Feb 8, 2016
@bennuttall
Copy link
Member Author

Yup was going to say let's make sure we get this in. @MarcScott was asking me about it today - told him to use the base classes for now.

waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 9, 2016
Implements support for the HR-SC04 ultrasonic sensor as an input device
class named DistanceSensor
@waveform80
Copy link
Member

Okay, there's a rough initial commit for anyone that wants to play. I'll make this into a proper PR when I get some time but it's not ready for merge yet.

waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 9, 2016
Implements support for the HR-SC04 ultrasonic sensor as an input device
class named DistanceSensor
@bennuttall
Copy link
Member Author

Cool thanks I'll check it out. @MarcScott get in here!

@waveform80
Copy link
Member

If people really want to play with right now, just clone my repo (https://github.com/waveform80/gpio-zero) and checkout the ultrasonics branch.

But as mentioned, this isn't ready for a PR yet (still need to add some configuration for speed of sound conversion and experiment a bit with the smoothing; at the moment I think it's set to take the median of the last 30 samples that the background thread has read - in experiments it reads about 160samples/s on an idle Pi2 so that's effective latency of 3/16ths of a second for any given reading). Still pretty jittery in certain circumstances though, but I suspect that's just the hardware for you...

waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 10, 2016
Implements support for the HR-SC04 ultrasonic sensor as an input device
class named DistanceSensor
waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 10, 2016
Implements support for the HR-SC04 ultrasonic sensor as an input device
class named DistanceSensor
waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 10, 2016
Implements support for the HR-SC04 ultrasonic sensor as an input device
class named DistanceSensor
waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 10, 2016
Implements support for the HC-SR04 ultrasonic sensor as an input device
class named DistanceSensor
waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 10, 2016
Implements support for the HC-SR04 ultrasonic sensor as an input device
class named DistanceSensor
@waveform80
Copy link
Member

Okay, that's the PR done - give it a whirl and let me know if anything needs changing. I'm not sure about some of the naming (far/near? Hmmm... couldn't think of anything better off the top of my head, suggestions welcome).

The class has a few oddities; while it's got the usual 0-1 scaled value attribute (to allow easy interfacing to other stuff) and a similar threshold property which is used to trigger the near/far events the constructor (and class) provide a threshold_distance property which is just threshold scaled into meters (which seemed a lot more obvious for people constructing the object). The scaling of value to 0-1 is handled by virtue of a max_distance parameter which specifies what "1" means to value. This defaults to 1 meter because firstly the sensor seems to be quite iffy beyond that (or maybe that's just my sensor?) and secondly because it means value and distance will be equal by default (principle of least surprise and all that).

For now I've left out any overt mention of the ability to re-configure the class for different speeds of sound (compensating for different mediums / temperatures / whatever) because I figure that's probably "too much information". However, if you want to play with it, just modify the speed_of_sound attribute on the class; it's just a float which currently gives the speed of sound in m/s so the class measures everything in meters (yes, that means if you're particularly bonkers and want your code to use feet you could always substitute feet per second in there; no, I will not be adding this as an option in the class).

I've also modified the smoothing thread to use median averaging by default. The ultrasonic sensor seems to be considerably more jittery than most and median was necessary to eliminate some of its wilder swings. As a result, LDR might be a bit "smoother" too but I figure that's no bad thing. In case we desperately need mean in future, I've made the averaging algorithm used by GPIOQueue configurable and back-ported the median and mean implementations from Python 3.4 for 3.2 (wheezy) or 2.7 users.

Anyway, let me know what you think!

@waveform80
Copy link
Member

Oh, and there's a fun new recipe thrown in too for a nervous robot (haven't tested it yet though :)

@waveform80 waveform80 mentioned this issue Feb 10, 2016
@lgcproductions
Copy link

Thank you. :D :D

Will give this a whirl tomorrow on my robot project. It uses two of these sensors as an avoider. I'm new to coding but have already created a working code in the old GPIO format as it where.

@alaudet
Copy link

alaudet commented Feb 11, 2016

I am anxious to have a look. Just for the record though, it's a HC-SR04 and not HR-SC04

@waveform80 waveform80 changed the title HR-SC04 Ultrasonic Sensor HC-SR04 Ultrasonic Sensor Feb 11, 2016
@waveform80
Copy link
Member

Fixed :) I actually realized I'd got that wrong in nearly every place the other day before committing, but thankfully it's a unique enough string so a quick bufdo %s in vim cleared it all up!

@alaudet
Copy link

alaudet commented Feb 11, 2016

oh ya, I wanted to comment on the speed of sound stuff. Given that this sensor doesn't work very well beyond a few metres its probably not even necessary to add anything in regards temperature. I added it in hcsr04sensor module but its kind of useless and you can never get highly accurate readings anyway. In an educational setting I have to think most people are sitting at about room temperature. Unless people plan to use it at -25 or something, it just won't make much difference in readings.

@waveform80
Copy link
Member

Yeah, I'll leave the speed of sound as a "hidden" bit of configuration for anyone that wants to play with it, but I don't think there's much point complicating the docs with it.

waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 11, 2016
Implements support for the HC-SR04 ultrasonic sensor as an input device
class named DistanceSensor
waveform80 added a commit to waveform-computing/gpio-zero that referenced this issue Feb 11, 2016
Implements support for the HC-SR04 ultrasonic sensor as an input device
class named DistanceSensor
@waveform80
Copy link
Member

Anybody got any better ideas for event names than near/far? If not, I'm tempted to just merge this so it's easier for people to have a play with it - we're not doing a release yet so no big deal if we change the names later (and now we've got a stable default docs version we won't confuse any newbies looking at them).

@lurch
Copy link
Contributor

lurch commented Feb 11, 2016

Yeah, I can see that with 'near' and 'far' there might be an expectation that there's a third state between the two (rather than it being a 'boolean' state like a button-press), but I can't think of any better suggestions...

@waveform80
Copy link
Member

A thought occurs (as so rarely happens!): how about doing something similar to MotionSensor: when_near, when_not_near, wait_for_near, wait_for_not_near (hmm, that last one feels a bit weird).

Still, I think you've hit the nail on the head: it does feel strange that something is "near", then a millimetre further back and suddenly it's "far" (initially I was thinking "when_close" but especially for non-native English speakers the conflation of "close" for distance with "close" to closing an object would just be too confusing). Even googling "synonym near" and "synonym far" I don't get that many inspirations for alternatives (everything seems to be a variation on near, close, nearby, far, afar, etc.)

@alaudet
Copy link

alaudet commented Feb 12, 2016

I haven't played with it yet, but looked at the recipe. Near/Far seems ok. The only other thing I can think of would be in_range/out_of_range

@waveform80
Copy link
Member

Hmm, I'm liking in_range and out_of_range: when_in_range, when_out_of_range, wait_for_in_range, wait_for_out_of_range - that last one's a little wordy but it still reads well. And it makes sense; there's a threshold and if something's over it, it's in range, and otherwise it's out of range. Yeah ... definitely liking that.

Okay, if there's no objections (or better ideas!) by this evening I'll do a little renaming, then merge this.

@bennuttall
Copy link
Member Author

Sounds good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants