Sonar

Sonar works by measuring the time it takes for an sound to bounce off an object and return to the point of origin.  With readily available, inexpensive components, sonar seemed like a great choice when determining how to go about object avoidance.


Image result for hc sr04
We chose to use an HC-SR04 ultrasonic rangefinder for our sonar module, which has a 4-pin interface: VCC-Trigger-Echo-Ground.  
5V VCC comes from the RPi, and it takes 3.3V for the trigger signal.  It returns a 5V signal, which the RPi doesn't like, but a simple voltage divider was used to protect the the computer.





Since the HC-SR04 is static, we needed a way to have the droid "look" around.  To accomplish this, we mounted the rangefinder on a servo motor.  This is a simple micro servo, with approximately 60 degrees of rotation.

To control everything, we used Python.  The RPi is set up to be programmed in Python, and subsequently ships with most of the libraries needed to interact with its peripherals.  We'll take a look at some of that code.  I've included the comments, so you can see the reminders we put in for ourselves:

# -----------------------
# Pinout for sonar:
# VCC    - Pin 2
# Trig   - Pin 16
# Echo   - Pin 18
# Gnd    - Pin 6
#
# Pinout for servo:
# VCC    - Pin 2
# Gnd    - Pin 6
# Signal - Pin 7
#
# Use a voltage divider to ensure no more than 3.3V returns to the Pi
#
# Echo--1kOhm---1kOhm-- Pin 18
#             |
#           2kOhm
#             |
# Gnd------------------ Pin 6

# -----------------------

# ------------------------------

# Import required python libraries
# ------------------------------

from __future__ import print_function

import RPi.GPIO as GPIO
import time

The comments were a reminder on how to connect the devices to the RPi.  RPi.GPIO is the library needed to interact with the 40 GPIO pins.


# ------------------------------

# Set up GPIO pins
# ------------------------------

GPIO.setmode(GPIO.BOARD)

GPIO.setup(7, GPIO.OUT)
GPIO.setup(16, GPIO.OUT)
GPIO.setup(18, GPIO.IN)
GPIO_TRIGGER = 16
GPIO_ECHO = 18
p = GPIO.PWM(7,50) #Sets pin 7 to be PWM, with a freq of 50Hz
p.start(7.5)

We chose to interact with the RPi using physical pin numbers, allowing for quick visual assessment of a setup.


# ------------------------------

# Functions
# ------------------------------

def measure():

    """ A function to measure a distance"""

    GPIO.output(GPIO_TRIGGER, True)

    # Wait 10ns
    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 * speedSound)/2

    return distance


def measure_average():

    """ Takes 3 Measurements and returns the average"""
    
    distance1=measure()
    time.sleep(0.001)
    distance2=measure()
    time.sleep(0.001)
    distance3=measure()
    distance = distance1 + distance2 + distance3
    distance = distance / 3
    return distance

These two functions do most of the heavy lifting of the sonar.  The first emits a pulse, waits 10 microseconds, then waits for a echo.  Once it gets that echo, it calculates the distance, based on the speed of sound (in cm/sec).  The second function simply takes the average of three measurements, and returns that value.


# ------------------------------

# Main Loop
# ------------------------------

# Speed of sound in cm/s at temperature

temperature = 20
speedSound = 33100 + (0.6*temperature)

print("Ultrasonic Measurement")

print("Speed of sound is",speedSound/100,"m/s at ",temperature,"deg")

# Set trigger to False (Low)

GPIO.output(GPIO_TRIGGER, False)

# Allow module to settle

time.sleep(0.0001)

# 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:
        p.ChangeDutyCycle(angle)
        distance = measure_average()
        print("Distance : {0:5.1f}".format(distance))
        # plt.scatter(angle, distance)
        # plt.xlabel("angle")
        # plt.ylabel("distance")
        # plt.show()
        time.sleep(.01)
        if(goUp == 1 and angle < 9):
            angle += 0.1
        elif(goUp == 1 and angle >= 9):
            goUp = 0
            angle -= 0.1
        elif(goUp == 0 and angle > 6):
            angle -= 0.1
        elif(goUp == 0 and angle <= 6):
            goUp = 1
            angle += 0.1       


except KeyboardInterrupt:

    # User pressed CTRL-C
    # Reset GPIO settings
    print('Stopped')

    GPIO.cleanup()


Comments

Popular posts from this blog