I just created this program to test the HC-SRO4 Ultrasonic Range Measurement device. I had a lot of problems getting it to work in a single process waiting for the edge of the measurement pulse, so I modified the program to created a separate (child) process to monitor and report the measurement from the sensor. In addition, just for fun, I also integrated a old Airtronics 94102 servo, moving it to reflect the distance measurement, between 2.5 and 11 inches. I used 1k & 2k resistors to reduce the 5 volt output from the ECHO lead of the sensor to 3.3 volts for input to the GPIO pin.
#!/usr/bin/env python
#
# GPIO Range Measurement with Servo Control
#
# This program is designed to demonstrate the Raspberry Pi
# General Purpose I/O capabilities and also provide an
# example program in Python using multiprocessing capabilities.
#
# Author: Andy Whitt
#
# Last Revised: 8 Jan 2016
#
import os
import multiprocessing
import RPi.GPIO as GPIO
import time
TRIG = 11 # RPi Pin (GPIO 17) initiate range measurement
ECHO = 12 # RPi Pin (GPIO 18) recieve measurement pulse
SERVO_CONTROL = 40 # RPi Pin (GPIO 21) control the servo
PWM_FREQ = 50 # Frequency (Hz) of signal to the servo
#
# Configure the Raspberry Pi GPIO interface and Pin Usage
#
def configGPIO():
try:
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD) # Use RPi header pin numbering
GPIO.setup(TRIG, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(ECHO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(SERVO_CONTROL, GPIO.OUT)
except Exception, reason:
print 'GPIO configuration failed because', reason
print ' '
raise SystemExit
print 'GPIO Version ', GPIO.VERSION
#
# Run in a separate process to measure ECHO lead pulse width, display
# distance value and command the servo to reflect the changes
#
def reportMeasurement():
print 'pid :', os.getpid(),'-> Measurement Reporting Subprocess'
PWM = GPIO.PWM(SERVO_CONTROL, PWM_FREQ) # Setup PWM signal
dutyCycle = 3 # Initial width of pulses sent to the servo
PWM.start(dutyCycle) # Turn on pulse width modulation signal
while True: # Loop handling HC-SRO4 measurement events
GPIO.wait_for_edge(ECHO, GPIO.RISING)
pStart = time.time()
GPIO.wait_for_edge(ECHO, GPIO.FALLING)
pEnd = time.time()
uSpulseWidth = (pEnd - pStart) + .00008 # RPi process delay adjustment
pulseWidth = uSpulseWidth * 1000000 # Use x.x microsecond notation
if ((pulseWidth < 150) | (pulseWidth > 25000)): # Effective sensor range
print '*** Invalid Reading from Ranging Sensor'
else:
print ' '
if (pulseWidth > 999.99): # Pulses above 1k microseconds, display ms
print 'Pulse Duration {0:9.2f}'.format(pulseWidth/1000), 'Milliseconds'
else:
print 'Pulse Duration {0:9.2f}'.format(pulseWidth), 'Microseconds'
distance = (uSpulseWidth / 58) * 1000000
print ' Distance {0:9.2f}'.format(distance), 'Centimeters'
distance = (uSpulseWidth / 148) * 1000000
print ' {0:9.2f}'.format(distance), 'Inches'
dutyCycle = (uSpulseWidth / 148) * 1000000 # Use inches to set servo
if ((dutyCycle > 2.5) & (dutyCycle < 11)): # Effective range of servo
PWM.ChangeDutyCycle(round(dutyCycle,1)) # Change position of servo
else:
print '*** Reached maximum range of servo movement'
#
# Loop until user terminates with control-C
#
def mainLoop():
print ' '
print 'pid :', os.getpid(),'-> Main Loop Process'
time.sleep(1)
print ' '
for second in '54321':
print 'Starting in', second
time.sleep(1)
print ' '
while True: # Continuosly initiate range measurements
GPIO.output(TRIG, GPIO.HIGH)
time.sleep(.000001) # Using 10 microsecond pulse
GPIO.output(TRIG, GPIO.LOW)
time.sleep(.1) # Every 100 milliseconds
#
# Program Entry Point
#
if __name__ == "__main__": # Only run if module (source file) is the main program
print ' '
print 'Measuring Distance with the Cytron HC-SRO4 Ultrasonic Ranging Sensor'
print ' '
print ' Hit Control-C to exit'
print ' '
configGPIO()
try: # Spawn child process for running measurement and reporting
subProcess = multiprocessing.Process(target=reportMeasurement, args=())
subProcess.start()
except Exception, reason:
print ' '
print 'Failed to spawn child process because', reason
print ' '
GPIO.cleanup()
raise SystemExit
try: # Enter main program loop
mainLoop()
except KeyboardInterrupt:
print ' '
print 'Terminated by User'
except Exception, reason:
print ' '
print 'Terminated abnormally because', reason
subProcess.terminate()
GPIO.cleanup()
print ' '