Theory
The HC-SR04 is an inexpensive distance sensor that is easy to work with. It uses two ultrasonic transducers, one acting as a speaker and one serving as a microphone. The left transducer (acting as a speaker) emits a series of high-frequency sound pulses that travels through the air. When they hit a solid surface, these pulses are reflected back towards the module. The right transducer (acting as a microphone) registers this echo. The time required for the sound to make the trip away and back is used to determine how far the sound has traveled, and thus the distance to the obstacle.
Sensor Module
The ultrasonic sensor module makes it easy to get distance data by abstracting out a lot of the work associated with actuating the speaker and recognizing the echoes.
It has a 4 pin interface:
- Vcc is power. It is connected to 5V.
- GND is ground. It is connected to a ground pin of the microcontroller.
- TRIG is the trigger pin. It is connected to a digital pin of the microcontroller.
- ECHO is the echo pin. It is also connected to a digital pin of the microcontroller.
In our case, we will connect TRIG and ECHO to the same pin, as this will enable us to use a convenient function in the Arduino-Python library called pulseIn_set .
Getting a distance measurement from the module works like this:
- When you want to make a distance measurement, send a quick pulse to the sensor on the trigger line.
- The ultrasonic module will use the speaker to send out a sound-pulse and wait for an echo to come back.
- When the module detects an echo, it sends a pulse to the microcontroller over the ECHO wire.
- The time difference between when the trigger pulse was transmitted and when the echo pulse returned can be used to determine how far the sound has traveled (distance = speed * time).
Code
Get Distance Measurements
In your code, you will need to keep track of how long it has taken from the trigger pulse was sent to the echo returns. We could write this functionality manually, but it is easier and more accurate to use a library function called pulseIn_set .
pulseIn_set Function Specification
inputs:
- pin : pin number for pulse measurement.
- val : “HIGH” or “LOW”. Pulse is measured when this state is detected.
- numTrials : number of trials used for average. Default value is 5.
returns:
- duration : an average of pulse length measurements.
pulseIn_set Operation
This function works as follows:
- Set pin to the OUTPUT
- Set pin to the opposite logic level of val and wait a little.
- Set pin to the logic level of val . For the ultrasonic sensor, this will trigger a distance
- Start a
- Set pin to the INPUT
- When the logic level of pin is pulled to LOW by the ultrasonic sensor, stop the
- Repeat steps 1 to 6 numTrials times (if no number specified, use repeat five times).
- Average the time from all the numTrials distance measurements, and return this
That is quite a lot going on!
Code
You now know all you need to start writing code to interface with the ultrasonic sensor. It can look something like this:
from Arduino import Arduino import time PIN_SENSE = 12 # pin where ultrasonic sensor is connected # connect to Arduino - you may need to specify the data rate and PORT_NAME as per module 5, i.e. PORT_NAME = 'COM3' # example of Windows port name #PORT_NAME = '/dev/tty.usbserial-1420' # example of Mac port name board = Arduino('9600', port=PORT_NAME) print('Connected')
try:
while True: # make distance measurement pulseTime = board.pulseIn_set(PIN_SENSE, 'HIGH') print(pulseTime) time.sleep(1) # delay to keep UART bus for getting overloaded
except KeyboardInterrupt: board.close() # close serial connection
By running this program, you should see numbers print to your console in rapid succession.
- Observe how the numbers change when you point the ultrasonic sensor in different directions.
Calibrating for Distance Measurement
By using a ruler, you can manually determine how far the sound has traveled.
Find a scaling factor that makes the value printed by the Arduino correspond to the distance to an obstacle (and not the time it took the sound to travel out and back as it currently is doing).
Hint: how different is the constant of proportionality you get from this?
Writing to a file
You can use the csv library to write data to a file. This can be very useful for data analysis and will be used in the next module where you use the ultrasonic range finder for conducting an experiment.
from Arduino import Arduino
import time import csv # new, for writing to file FILE_NAME = 'pendulum_data.csv' # name of file that data will be written to PIN_SENSE = 12 # pin where ultrasonic sensor is connected
# connect to Arduino from Arduino import Arduino PORT_NAME = 'COM3' # example of Windows port name #PORT_NAME = '/dev/tty.usbserial-1420' # example of Mac port name board = Arduino('9600',port=PORT_NAME) # find and connect microcontroller print('Connected') f = open(FILE_NAME,'a') # open a file for 'a'ppending writer = csv.writer(f,delimiter=',') # prepare for writing to file # Write data-field titles to file writer.writerow(['Time (s)', 'Distance (cm)']) startTime = time.time() # capture current time as datum
try:
while True: # make distance measurement pulseTime = board.pulseIn_set(PIN_SENSE, 'HIGH') distance = pulseTime * 0.034 / 2; # in cm # write list of data to file currentTime = time.time()-startTime data = [currentTime, distance] writer.writerow(data) # write data to file print('time = %5.2f distance = %5.1f' % tuple(data)) time.sleep(1) # delay to keep UART bus for getting overloaded # press ctrl+c while the console is active to terminate the program except KeyboardInterrupt: board.close() # close serial connection f.close() # close file gracefully when program is terminated
Exercises
- How fast can you get the sensor to measure data? By reducing the delay too much, you may find that the sensor stops working. You can observe the TX and RX LEDs on the Nano to see the UART activity.
- Make the program print the values to the screen only occasionally.
- Add the LED, and set up a circuit that lights up whenever the sensor finds something that is getting too close.
Modules
- Buying Parts
- Preparing the Arduino
- Setting up Python on your PC
- Learning Python
- Arduino for Data Collection
- Ultrasonic Range Sensing
- Pendulum Experiment
Updated 2020-05-19 CEW
Sensor Module
The ultrasonic sensor module makes it easy to get distance data by abstracting out a lot of the work associated with actuating the speaker and recognizing the echoes.
It has a 4 pin interface:
PWR is power. It is connected to 5V.
GND is ground. It is connected to a ground pin of the microcontroller.
TRIG is the trigger pin. It is connected to a digital pin of the microcontroller. ECHO is the echo pin. It is connected to a digital pin of the microcontroller.
In our case, we will connect TRIG and ECHO to the same pin, as this will enable us to use a convenient function in the Arduino-Python library called pulseIn_set .
Getting a distance measurement from the module works like this:
When you want to make a distance measurement, send a quick pulse to the sensor on the trigger line. The ultrasonic module will use the speaker to send out a sound-pulse and wait for an echo to come back. When the module detects an echo, it sends a pulse to the microcontroller over the ECHO wire.
The time difference between when the trigger pulse was transmitted and when the echo pulse returned can be used to determine how far the sound has traveled (distance = speed * time).
Code
Get Distance Measurements
In your code, you will need to keep track of how long it has taken from the trigger pulse was sent to the echo returns. We could write this functionality manually, but it is easier and more accurate to use a library function called pulseIn_set .
pulseIn_set Function Specification
inputs:
pin : pin number for pulse measurement.
val : “HIGH” or “LOW”. Pulse is measured when this state is detected.
numTrials : number of trials used for average. Default value is 5. returns:
duration : an average of pulse length measurements.
pulseIn_set Operation
This function works as follows:
- Set pin to the OUTPUT
- Set pin to the opposite logic level of val and wait a little.
- Set pin to the logic level of val . For the ultrasonic sensor, this will trigger a distance
- Start a
- Set pin to the INPUT
- When the logic level of pin is pulled to LOW by the ultrasonic sensor, stop the
- Repeat steps 1 to 6 numTrials times (if no number specified, use repeat five times).
- Average the time from all the numTrials distance measurements, and return this
That is quite a lot going on!
Code
You now know all you need to start writing code to interface with the ultrasonic sensor. It can look something like this:
from Arduino import Arduino import time
PIN_SENSE = 12 # pin where ultrasonic sensor is connected
# connect to Arduino board = Arduino() print(‘Connected’)
try:
while True:
# make distance measurement
pulseTime = board.pulseIn_set(PIN_SENSE, ‘HIGH’) print(pulseTime)
time.sleep(1) # delay to keep UART bus for getting overloaded
except KeyboardInterrupt:
board.close() # close serial connection
By running this program, you should see numbers print to your console in rapid succession.
Observe how the numbers change when you point the ultrasonic sensor in different directions.
Calibrating for Distance Measurement
By using a ruler, you can manually determine how far the sound has traveled.
Find a scaling factor that makes the value printed by the Arduino correspond to the distance to an obstacle (and not the time it took the sound to travel out and back as it currently is doing).
Hint: how different is the constant of proportionality you get from this?
Writing to file
You can use the csv library to write data to a file. This can be very useful for data analysis and will be used in the next module where you use the ultrasonic range finder for conducting an experiment.
from Arduino import Arduino import time
import csv # new, for writing to file
FILE_NAME = ‘pendulum_data.csv’ # name of file that data will be written to PIN_SENSE = 12 # pin where ultrasic sensor is connected
# connect to Arduino board = Arduino() print(‘Connected’)
f = open(FILE_NAME,’a’) # open a file for ‘a’ppending writer = csv.writer(f,delimiter=’,’) # prepare for writing to file
# Write data-field titles to file writer.writerow([‘Time (s)’, ‘Distance (cm)’])
startTime = time.time() # capture current time as datum
try:
while True:
# make distance measurement
pulseTime = board.pulseIn_set(PIN_SENSE, ‘HIGH’) distance = pulseTime * 0.034 / 2; # in cm
# write list of data to file currentTime = time.time()-startTime data = [currentTime, distance]
writer.writerow(data) # write data to file print(‘time = %5.2f distance = %5.1f’ % tuple(data))
time.sleep(1) # delay to keep UART bus for getting overloaded
# press ctrl+c while the console is active to terminate the program except KeyboardInterrupt:
board.close() # close serial connection
f.close() # close file gracefully when program is terminated
Exercises
How fast can you get the sensor to measure data? By reducing the delay too much, you may find that the sensor stops working. You can observe the TX and RX LEDs on the Nano to see the UART activity.
Make the program print the values to the screen only occasionally.
Add the LED, and set up a circuit that lights up whenever the sensor finds something that is getting too close.
Next: Module 4: Pendulum Experiment
7. Pendulum Experiment
This module is an experiment where we use the ultrasonic distance sensor to collect data from a pendulum undergoing damped simple harmonic motion.
Experimental setup and procedure
The setup for this experiment requires a few parts. The most important thing is that the pendulum is aimed squarely at the large, flat surface on the pendulum at all times during the oscillations. This means it is important that you do not make the amplitude of the oscillations too large.
Equipment
Cardboard String
Hole-punch Mass
Stand for suspending the pendulum Box or similar for the sensor to sit on
Setup
- Cut out a rectangle in cardboard that is about 5 cm by 10
- Use a hole-punch to make three holes in it. Two holes are in the upper left and right corner for attaching the string, and one is at the bottom center for suspending the
- Tie a string through the top
- Hang the string on the stand so that it will not
- Position the ultrasonic sensor so that it points directly at the cardboard cutout as the pendulum
Code
Use the code you developed during the last module to measure the distance and print it to a file. The code below can also be used as a starting point, including a fairly accurate time to distance calibration.
from Arduino import Arduino import time
import csv
FILE_NAME = ‘pendulum_data.csv’ # name of file that data will be written to PIN_SENSE = 12 # pin where ultrasic sensor is connected
# connect to Arduino board = Arduino() print(‘Connected’)
f = open(FILE_NAME,’a’) # open a file for ‘a’ppending writer = csv.writer(f, delimiter=’,’, newline=”) # prepare for writing to file
# Write data-field titles to file writer.writerow([‘Counter’, ‘Time (s)’, ‘Distance (cm)’])
counter = 0 # to count how many data-points we have collected startTime = time.time() # capture current time as datum
try:
while True:
counter = counter + 1 # increment counter
# make distance measurement
pulseTime = board.pulseIn_set(PIN_SENSE, ‘HIGH’, 1) distance = pulseTime * 0.034 / 2; # in cm
# write list of data to file
writer.writerow([counter, time.time()-startTime, distance])
# print to console every 10 iterations. % is modulo operator if counter % 10 == 0:
print(distance)
time.sleep(0.01) # delay to keep UART bus for getting overloaded
# press ctrl+c while the console is active to terminate the program except:
board.close() # close board connection
f.close() # close file gracefully when program is terminated
Procedure
- Excite the pendulum so that it starts oscillating. Make sure it moves about 10 cm away from the equilibrium position in either direction.
- Start the Python program to collect data.
- Wait for the oscillations to die down before stopping data-collection. 20 seconds of data will be more than enough, but you can collect for longer if you want to.
- Change the name of the file that data is being printed to if you are going to redo the experiment. This makes it easy to see which data-points corresponds to which runs of the
Data Analysis
For analyzing the data, we can continue using Spyder to write and run code. Another tool designed explicitly for this type of work is known as Jupyter Notebook .
You can install and launch Jupyter from the Anaconda Navigator in the same way you have been using Spyder.
The following instructions have been written using a Jupyter notebook that you can open and copy code from, or that you can download and use as a starting point for your work.
Data Analysis in Jupyter Notebooks
Google is your friend. As a starting point, you can take a look at these links: