Ultrasonic Distance Measurement Using Python – Part 2

Following on from my Ultrasonic Distance Measurement Using Python – Part 1 article I decided to make my Python script a little bit more sophisticated.

In this example the script takes three measurements and calculates the average. This is displayed and one second later it takes another average. This allows the script to be used to constantly measure distances and print them to the command line.

The Ultrasonic module is connected as before to the Raspberry Pi using a small piece of breadboard and some jumper cables.

The Trigger accepts a 3.3V output from the Pi but the Echo pin must be converted to 3.3V from 5V before it reaches the GPIO input.

Ultrasonic Module Circuit

Ultrasonic Module Circuit

Python Script

Here is the modified script :

#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# ultrasonic_2.py
# Measure distance using an ultrasonic module
# in a loop.
#
# Author : Matt Hawkins
# Date   : 28/01/2013

# -----------------------
# Import required Python libraries
# -----------------------
import time
import RPi.GPIO as GPIO

# -----------------------
# Define some functions
# -----------------------

def measure():
  # This function measures a distance
  GPIO.output(GPIO_TRIGGER, True)
  time.sleep(0.00001)
  GPIO.output(GPIO_TRIGGER, False)
  start = time.time()

  while GPIO.input(GPIO_ECHO)==0:
    start = time.time()

  while GPIO.input(GPIO_ECHO)==1:
    stop = time.time()

  elapsed = stop-start
  distance = (elapsed * 34300)/2

  return distance

def measure_average():
  # This function takes 3 measurements and
  # returns the average.
  distance1=measure()
  time.sleep(0.1)
  distance2=measure()
  time.sleep(0.1)
  distance3=measure()
  distance = distance1 + distance2 + distance3
  distance = distance / 3
  return distance

# -----------------------
# Main Script
# -----------------------

# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO to use on Pi
GPIO_TRIGGER = 23
GPIO_ECHO    = 24

print "Ultrasonic Measurement"

# Set pins as output and input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo

# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)

# Wrap main content in a try block so we can
# catch the user pressing CTRL-C and run the
# GPIO cleanup function. This will also prevent
# the user seeing lots of unnecessary error
# messages.
try:

  while True:

    distance = measure_average()
    print "Distance : %.1f" % distance
    time.sleep(1)

except KeyboardInterrupt:
  # User pressed CTRL-C
  # Reset GPIO settings
  GPIO.cleanup()

This script can also be downloaded onto your Pi directly using this command line :

wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/ultrasonic_2.py

This can then be run using :

sudo python ultrasonic_2.py

This will give you a command line that looks something like this :

ultrasonic_2.py Screenshot

ultrasonic_2.py Screenshot

Obviously your measurements will depend on what you point your sensor at!

Related Articles

Here are some of my other articles you might find interesting if you enjoyed this one :

This entry was posted in Hardware, Python and tagged , , , . Bookmark the permalink.



12 Responses to Ultrasonic Distance Measurement Using Python – Part 2

  1. Great post as always, Matt.

  2. Niobe says:

    Awesome!!!
    This could be very useful in a quadrocopter to stabilise the hovering height.
    How much does the non-realtime nature of the OS affect the readings?

  3. Nick says:

    What is the maximum distance this could measure?

    Thanks

  4. Chris says:

    Hi
    My Dad is blind and I’m looking into a project to make some kind of wearable device (hat, glasses, armband, kneepad etc) which detects upcoming obstructions and feeds back via audio or vibration to alert him. He keeps banging his head on things because his stick is usually sweeping low. This looks like a good start for the distance detector part. Would this be the right approach? Do you know of any projects which have done the whole thing? I haven’t bought a Pi yet, just done 15 minutes surfing.
    I have seen one using a different type of sensor (http://jeremyblythe.blogspot.co.uk/2012/09/raspberry-pi-distance-measuring-sensor.html) – which would you consider more appropriate for my application?
    Thanks for any help – as a noob I want to start off in the right direction.
    Chris (Ex-developer, now pre-sales)

  5. Dick Haight says:

    My experience with this sensor is that the code gives differing results depending on the current CPU load on the Pi. See post 50 at the above website. I ended up doing 3 samples each time and keeping the lowest result. The minimum time between good readings is about 2 seconds — not useful. Too bad there doesn’t seem to be a way to “sleep” until the ECHO pin causes an interrupt. This kind of device would probably work better with an Arduino where ump-teen Linux background processes would not be a problem.

  6. Lance says:

    all i get everytime i execute the python is
    ultrasonic_2.py:70: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
    GPIO.setup(GPIO_TRIGGER,GPIO.OUT) # Trigger

    any help would mean a lot. thanks

    • Matt says:

      That is just a warning issued by the RPi.GPIO library. It just means you are configuring a GPIO output that has previously been configured. Probably in a previous run of the script. It can be ignored. Or you can stick GPIO.setwarnings(FALSE) at the start of the script to disable it.

  7. Pingback: Ultrasonic Distance Measurement Using Python – Part 1 | Raspberry Pi Spy

  8. Jeff says:

    Thanks for the very helpful article.

    I had need of something like this to report the water level in my porch plant watering system. However; all I had available were the Parallax PING))) 28015 units which are 3-pin; combining the Trigger and Echo into a single channel. I found that a pair of simple functions to switch the GPIO pin between .IN and .OUT was about all that was necessary to adapt your code.

    I also found that the 28015 seems perfectly happy in my implementation running directly off the Pi’s 3.3v rail — eliminating the need for a voltage divider. I doubt that this set-up would be very reliable for a dynamic environment, but for a once/day check of my reservoir level in gallons, it seems to suffice. I do use a sort of “circular buffer” to smooth the readings because my set-up allows for the luxury of time.

    Cheers!

  9. Ian Carbarns says:

    Even if you have the 4-pin Ultrasonic unit with separate ‘trigger’ and ‘measure’ pins, it is possible to combine these so that only a single GPIO pin is used on the Pi. Just adds a couple of resistors to ‘pull down’ the trigger pin and between the 2 pins, as well as make the voltage divider, and then switch the GPIO pin between output and input as needed

  10. wdog says:

    to reduce the error you can use:


    def measure_average():
    distances=[]
    elements = 20
    distances= range(0,elements)

    for i in range(0,elements):
    distances[i]= measure()
    time.sleep(0.1)

    d = sum(distances) /len(distances)
    return d

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>