Chapter8
Last updated
Last updated
Raspberry PI is a very powerful platform. It can use python to control the GPIO pins and use the GPIO to get sensor data so that the program can be more smart about external environments. In this chapter, we will introduce several common sensors that can be used in Raspberry PI platform.
We open sourced the entire project and the code can be found on
We can use the HC-SR04 ultrasonic ranging sensor. This sensor provides 2cm to 400cm of non-contact measurement functionality with a ranging accuracy that can reach up to 3mm. Each HC-SR04 module includes an ultrasonic transmitter, a receiver and a control circuit.
There are only four pins on the HC-SR04: VCC (5V Power), Trig (Trigger), Echo (Receive), and GND (Ground).
Trig is a pin output for a pulse width of 10 microseconds to regenerate 40 KHz frequency ultrasonic waves into the air from the transmitter. Echo is a pin input pulse signal from the module to the Raspberry PI to detect the width of the pulse and calculate the distance.
The operating principle of ultrasonic sensor is the same as that of object detection system of a bat and is shown in figure below. An ultrasonic transmitter sends a radio frequency of 40 KHz in the air at the speed of 346 meter per second and the receiver receives the reflected signal from the object. Distance between the transmitter and the object can be calculated by simple calculation by considering the time taken by the ultrasonic wave to travel from transmitter and received back (reflected) by the receiver.
Sensing with Python
First, import the Python GPIO library, import our time library (so we make our Pi wait between steps) and set our GPIO pin numbering.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
Next, we need to name our input and output pins, so that we can refer to it later in our Python code. We’ll name our output pin (which triggers the sensor) GPIO 23 [Pin 16] as TRIG, and our input pin (which reads the return signal from the sensor) GPIO 24 [Pin 18] as ECHO.
TRIG = 26
ECHO = 20
Next, set your two GPIO ports as either inputs or outputs as defined previously.
GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO,GPIO.IN)
Then, ensure that the Trigger pin is set low, and give the sensor a second to settle.
GPIO.output(TRIG, False)
print "Waiting For Sensor To Settle"
time.sleep(2)
The HC-SR04 sensor requires a short 10uS pulse to trigger the module, which will cause the sensor to start the ranging program (8 ultrasound bursts at 40 kHz) in order to obtain an echo response. So, to create our trigger pulse, we set out trigger pin high for 10uS then set it low again.
GPIO.output(TRIG, True)
time.sleep(0.00001)
GPIO.output(TRIG, False)
Now that we’ve sent our pulse signal we need to listen to our input pin, which is connected to ECHO. The sensor sets ECHO to high for the amount of time it takes for the pulse to go and come back, so our code therefore needs to measure the amount of time that the ECHO pin stays high. We use the “while” string to ensure that each signal timestamp is recorded in the correct order.
The time.time() function will record the latest timestamp for a given condition. For example, if a pin goes from low to high, and we’re recording the low condition using the time.time() function, the recorded timestamp will be the latest time at which that pin was low.
Our first step must therefore be to record the last low timestamp for ECHO (pulse_start) e.g. just before the return signal is received and the pin goes high.
while GPIO.input(ECHO)== False:
pulse_start = time.time()
Once a signal is received, the value changes from low (False) to high (True), and the signal will remain high for the duration of the echo pulse. We therefore also need the last high timestamp for ECHO (pulse_end).
while GPIO.input(ECHO)==True:
pulse_end = time.time()
We can now calculate the difference between the two recorded timestamps, and hence the duration of pulse (pulse_duration).
pulse_duration = pulse_end - pulse_start
With the time it takes for the signal to travel to an object and back again, we can calculate the distance using the following formula.
Speed =Distance/Time
The speed of sound is variable, depending on what medium it’s travelling through, in addition to the temperature of that medium. However, some clever physicists have calculated the speed of sound at sea level so we’ll take our baseline as the 343m/s. If you’re trying to measure distance through water, this is where you’re falling down – make sure you’re using the right speed of sound!
We also need to divide our time by two because what we’ve calculated above is actually the time it takes for the ultrasonic pulse to travel the distance to the object and back again. We simply want the distance to the object! We can simplify the calculation to be completed in our Python script as follows:
distance = pulse_duration x ( SPEED /2 )
Ideally the SPEED should be equal to 343m/s but as we use pulse edges to approximate the absolute echo start/stop time. We use the following formula in the program:
distance = pulse_duration x 17000 - 9
Also we need to round our distance to 2 decimal places (for neatness!)
distance = round(distance, 2)
The ultrasonic program is in ultrasensor.py.
Micro servo can be controlled by Raspberry PI to drive sensors or move some components in the robot. MG945 is a very simple small micro servo. It has three pins : VCC (power 5V), GND (ground) and SERVO (pulse).
The servos position is controlled by the pulse width of a 50 Hz PWM signal. Hence, we need to turn the PWM sequence on at 50 Hz. Note that for a 50 Hz signal, the Period of the signal is 1/50=.02 seconds, or 20 milliseconds. We start by creating a PWM object on Pin 19 with a 50 Hz signal with the command:
SERVO = 19
GPIO.setup(SERVO,GPIO.OUT)
pwm = GPIO.pwm(SERVO, 50)
pwm.start(7.5)
We can now start the pwm sequence by giving a command to specify the DutyCycle of the signal. Before we do this, we need to talk a little bit about how servos work. A typical servo wants to see a frequency of 50 Hz on the control line. The position it moves to depends on the pulse width of the signal. Most servos behave roughly as such, but you will need to tweak these numbers for your particular servo. Typically, the servo will go to the full left position when it sees a pulse width of 1 millisecond, it will go the middle position when it sees a pulse width of 1.5 millisecond, and it will go to the full right position when it sees a pulse width of 2 millisecond. Note however, that on the Raspberry Pi we do not specify a pulse width, but we specify a DutyCycle. So, we can use the following relationship:
DutyCycle =PulseWidth/Period
Remember that Period = 1/frequency, so:
DutyCycle = PulseWidth/(1/frequency) = PulseWidth * frequency
The PulseWidth that will give us a full left position is 1 milllisecond. We now calculate the applied DutyCycle to give us the desired position:
DutyCycle = PulseWidth*frequency=.001 *50 = .05 = 5%
So, for a 50 Hz signal, if we set the DutyCycle to 5, then we should see the servo move to the full left position. Similarly, if we set DutyCycle to 7.5, we should get the middle position, and if we set it to 10 we should be in the full right position. You can get all the intermediate positions by linearly scaling between 5 and 10. Note that these values will vary between brands, and between individual servos, so play around with your servo to get it calibrated. We are now ready to apply a command to position the servo. If we want the servo in the full left position, we should set the DutyCycle to 5%. We do that with the command:
In python, we can use the following command to update the DutyCycle of a GPIO pin:
pwm.ChangeDutyCycle( dutyCycle ) # 2.5 <= dutyCycle <= 12.5 in our servo , not between 5 and 10
time.sleep(1) #wait for the servo to rotate the angel
Again please note the full left and full right position need to be tuned for the real servo.
The servo program is in servo.py.