You are on page 1of 68

www.keyestudio.

com

Note: need to turn off the programme of boot-up, then follow the below instructions
Open the terminal and input sudo nano /etc/rc.local then press Enter

Add # before enabling the scripts, as shown below;

Press Ctrl + o to save, then press Enter and Ctrl + X to exit editing

Raspberry Pi Control
Contents
Expansion Board.........................................................................................................................................................................3
1. Passive Buzzer........................................................................................................................................................................4
1.1 Code 1...................................................................................................................................................................................4
1.2 Run code 1 and test result.....................................................................................................................................................6
1.3 Code 2...................................................................................................................................................................................6
1.4 Run code 2.............................................................................................................................................................................9
2. Line Tracking Sensor............................................................................................................................................................10
2.1 Code....................................................................................................................................................................................10
2.2 Run code and test result......................................................................................................................................................11

1
www.keyestudio.com

3. Ultrasonic Sensor..................................................................................................................................................................12
3.1 Code....................................................................................................................................................................................13
3.2 Run code and test result......................................................................................................................................................15
4. Servo Control........................................................................................................................................................................15
4.1 Code 1.................................................................................................................................................................................16
4.2 Run code and test result......................................................................................................................................................17
4.3 Code2..................................................................................................................................................................................17
4.4 Run code and test result......................................................................................................................................................19
5. LED Panel.............................................................................................................................................................................19
5.1 8*16 Dot Matrix Display....................................................................................................................................................19
5.2 Interface Description and Communication Protocol:..........................................................................................................20
5.3 Introduction for modulus tool.............................................................................................................................................23
5.4 Code....................................................................................................................................................................................25
5.5 Run code and test result......................................................................................................................................................28
6. OLED Display.......................................................................................................................................................................28
6.1 Code....................................................................................................................................................................................28
6.2 Run code and test result......................................................................................................................................................30
6.3 Code2..................................................................................................................................................................................31
6.4 Run code 2 and test result...................................................................................................................................................33
7. Driver Motor.........................................................................................................................................................................34
7.1 Schematic Diagram........................................................................................................................................................34
7.2 Code....................................................................................................................................................................................35
7.3 Run code and test result......................................................................................................................................................37
8. Infrared Receiver...................................................................................................................................................................37
8.1 Code....................................................................................................................................................................................39
8.2 Run code and test result......................................................................................................................................................42
9. IR Remote Control Car.........................................................................................................................................................42
9.1 Code....................................................................................................................................................................................42
9.2 Run code and test result......................................................................................................................................................49
10. Line Tracking Car...............................................................................................................................................................49
10.1 Code..................................................................................................................................................................................50
10.2 Run code and test result....................................................................................................................................................54
11. Ultrasonic Following Car....................................................................................................................................................54
11.1 Code..................................................................................................................................................................................55
11.2 Run code and test result....................................................................................................................................................59
12. Ultrasonic Obstacle Avoidance Robot................................................................................................................................59
12.1 Code..................................................................................................................................................................................61
12.2 Run code and test result....................................................................................................................................................66

Expansion Board

2
www.keyestudio.com

When programming GPIO pins, there are three different ways to refer to

them: BCM GPIO number, physical number and WiringPi GPIO number.

Generally the WiringPi GPIO number is for the C language.The BCM GPIO

number and physical numbers can be applied to Python.

Our tutorial is written in Python, so the BCM GPIO number will be used,

and the silkscreen on the expansion board is identified by the BCM GPIO

number.

1. Passive Buzzer

Passive buzzer relies on piezoelectric effect to produce sound which is very clear

3
www.keyestudio.com

and pleasant, suitable for electronic music box.

BCM pin:GPIO 16

1.1 Code 1

# -*- coding: utf-8 -*-

import time

import RPi.GPIO as GPIO

buzPin = 16

i1 = 0

i2 = 0

GPIO.setmode(GPIO.BCM) # use BCM numbers

GPIO.setup(buzPin, GPIO.OUT) # set pin OUTPUT mode

try:

4
www.keyestudio.com

while 1: #loop

while(i1<50):

GPIO.output(buzPin,GPIO.HIGH)

time.sleep(0.001) #wait for 1 ms

GPIO.output(buzPin,GPIO.LOW)

time.sleep(0.001)

i1 = i1 + 1

time.sleep(0.3)

while(i2<50):

GPIO.output(buzPin,GPIO.HIGH)

time.sleep(0.001) #wait for 1 ms

GPIO.output(buzPin,GPIO.LOW)

time.sleep(0.001)

i2 = i2 + 1

time.sleep(1)

i1 = 0

i2 = 0

except KeyboardInterrupt:

pass

GPIO.cleanup() #release all GPIO

5
www.keyestudio.com

1.2 Run code 1 and test result

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp1_1buzzer.py

After running test code, the buzzer will emit “tick,tick” sound。

Press "Ctrl + C" to exit code running

1.3 Code 2

This example code uses GPIO.PWM to make the buzzer emit sounds with

different frequency.

# -*- coding: utf-8 -*-

import RPi.GPIO as GPIO

import time

Buzzer = 16 # set the Pin

# Happy birthday

Do = 262

6
www.keyestudio.com

Re = 294

Mi = 330

Fa = 349

Sol = 392

La = 440

Si = 494

Do_h = 523

Re_h = 587

Mi_h = 659

Fa_h = 698

Sol_h = 784

La_h = 880

Si_h = 988

# The tune

song_1 = [

Sol,Sol,La,Sol,Do_h,Si,

Sol,Sol,La,Sol,Re_h,Do_h,

Sol,Sol,Sol_h,Mi_h,Do_h,Si,La,

Fa_h,Fa_h,Mi_h,Do_h,Re_h,Do_h

7
www.keyestudio.com

# delay

beat_1 = [

0.5,0.5,1,1,1,1+1,

0.5,0.5,1,1,1,1+1,

0.5,0.5,1,1,1,1,1,

0.5,0.5,1,1,1,1+1,

def setup():

GPIO.setmode(GPIO.BCM) # Numbers GPIOs by physical

location

GPIO.setup(Buzzer, GPIO.OUT) # Set pins' mode is output

global Buzz # Assign a global variable to replace

GPIO.PWM

Buzz = GPIO.PWM(Buzzer, 440) # 440 is initial frequency.

Buzz.start(50) # Start Buzzer pin with 50% duty

ration

def loop():

while True:

print('\n Playing song 3...')

8
www.keyestudio.com

for i in range(0, len(song_1)): # Play song 1

Buzz.ChangeFrequency(song_1[i]) # Change the

frequency along the song note

time.sleep(beat_1[i] * 0.5) # delay a note for beat *

0.5s

def destory():

Buzz.stop() # Stop the buzzer

GPIO.output(Buzzer, 1) # Set Buzzer pin to High

GPIO.cleanup() # Release resource

if __name__ == '__main__': # Program start from here

setup()

try:

loop()

except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the

child program destroy() will be executed.

destory()

9
www.keyestudio.com

1.4 Run code 2

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp1_2buzzer_pwm.py

After running test code, the buzzer will play a birthday song.

Press "Ctrl + C" to exit code running

2. Line Tracking Sensor

The detection element of the tracking sensor is composed of an infrared

light-emitting tube and an infrared receiving tube.

It mainly depends on whether the infrared receiving tube can receive the

infrared rays emitted by the transmitting tube.

Pins of three-channel line tracking sensor : L : GPIO 19 M :

GPIO 18 R : GPIO 17

10
www.keyestudio.com

2.1 Code

import RPi.GPIO as GPIO


from time import sleep

#tracking pin
trackingPin1 = 17
trackingPin2 = 18
trackingPin3 = 19

GPIO.setmode(GPIO.BCM) # use BCM numbers

GPIO.setup(trackingPin1,GPIO.IN) # set trackingPin INPUT mode


GPIO.setup(trackingPin2,GPIO.IN)
GPIO.setup(trackingPin3,GPIO.IN)

while True:
val1 = GPIO.input(trackingPin1) # read the value
val2 = GPIO.input(trackingPin2)
val3 = GPIO.input(trackingPin3)
print("tracking1 = ", val1, "tracking2 = ", val2, "tracking3 = ", val3)
sleep(0.1)

GPIO.cleanup() # Release all GPIO

2.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp2_tracking.py

If the car is placed on the table, the IR receiving tube will receive the IR

rays and the value will be 0; as shown below;

11
www.keyestudio.com

3. Ultrasonic Sensor

Ultrasonic sensor is a very affordable distance sensor, mainly used in

various robot projects to avoid objects.

The principle of ultrasonic sensor

As the above picture shown, it is like two eyes. One is transmitting end,

the other is receiving end.

The ultrasonic module will emit the ultrasonic waves after triggering a

signal. When the ultrasonic waves encounter the object and are reflected

back, the module outputs an echo signal, so it can determine the distance

of the object from the time difference between the trigger signal and

echo signal.

The t is the time that emitting signal meets obstacle and returns. And the

propagation speed of sound in the air is about 343m/s, and distance =

12
www.keyestudio.com

speed * time. However, the ultrasonic wave emits and comes back, which

is 2 times of distance. Therefore, it needs to be divided by 2, the distance

measured by ultrasonic wave = (speed * time)/2

1. Use method and timing chart of ultrasonic module:

2. Setting the delay time of Trig pin of SR04 to 10μs at least, which can

trigger it to detect distance.

3. After triggering, the module will automatically send eight 40KHz

ultrasonic pulses and detect whether there is a signal return. This step will

be completed automatically by the module.

4. If the signal returns, the Echo pin will output a high level, and the

duration of the high level is the time from the transmission of the

ultrasonic wave to the return.

Trigger signals 10us high level

Send ultrasonic waves Send 8t 40KHz ultrasonic pulses

Module gets the time gap of transmission Test result


and reception

Pins of ultrasonic sensor: Trig : GPIO 14    Echo : GPIO 4

13
www.keyestudio.com

3.1 Code

import RPi.GPIO as GPIO


import time

GPIO.setmode(GPIO.BCM)

#define GPIO pin


GPIO_TRIGGER = 14
GPIO_ECHO = 4

#set GPIO mode (IN / OUT)


GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)

def distance():
# 10us is the trigger signal
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001) #10us
GPIO.output(GPIO_TRIGGER, False)

start_time = time.time() # Log the time the program runs to this point
stop_time = time.time() # Log the time the program runs to this point

while GPIO.input(GPIO_ECHO) == 0: #Indicates that the ultrasonic wave has been


emitted
start_time = time.time() #Record launch time

while GPIO.input(GPIO_ECHO) == 1: #Indicates that the returned ultrasound has


been received
stop_time = time.time() #Record receiving time

time_elapsed = stop_time - start_time #Time difference from transmit to receive


distance = (time_elapsed * 34000) / 2 #Calculate the distance
return distance #Return to calculated distance

if __name__ == '__main__': #Program entry


try:

14
www.keyestudio.com

while True:
dist = distance() #
print("Measured Distance = {:.2f} cm".format(dist)) #{:.2f},Keep two decimal
places
time.sleep(0.1)

# Reset by pressing CTRL + C


except KeyboardInterrupt:
print("Measurement stopped by User")
GPIO.cleanup()

3.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp3_ultrasonic.py

After running test code, then the detected distance value will be displayed

on the terminal.

4. Servo Control

Servo motor is a position control rotary actuator. It mainly consists of a housing,

15
www.keyestudio.com

a circuit board, a core-less motor, a gear and a position sensor. In general,

servo has three lines in brown, red and orange. The brown wire is grounded,

the red one is a positive pole line and the orange one is a signal line.

When the motor speed is constant, the potentiometer is driven to rotate

through the cascade reduction gear, which leads that the voltage difference is

0, and the motor stops rotating. Generally, the angle range of servo rotation is

0° --180 °

The rotation angle of servo motor is controlled by regulating the duty cycle of

PWM (Pulse-Width Modulation) signal. The standard cycle of PWM signal is

20ms (50Hz). Theoretically, the width is distributed between 1ms-2ms, but in

fact, it's between 0.5ms-2.5ms. The width corresponds the rotation angle from

0° to 180°. But note that for different brand motors, the same signal may have

different rotation angles.

Pins of servo:
Servo for ultrasonic sensor: GPIO 5 Base servo: GPIO 7 Servo for camera:GPIO 6

16
www.keyestudio.com

4.1 Code 1

We first control the servo on the pan tilt to rotate


import RPi.GPIO as GPIO
import time
servoPin1 = 5
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

def init():
GPIO.setup(servoPin1, GPIO.OUT)

def servoPulse(servoPin, myangle):


pulsewidth = (myangle*11) + 500 # The pulse width
GPIO.output(servoPin,GPIO.HIGH)
time.sleep(pulsewidth/1000000.0)
GPIO.output(servoPin,GPIO.LOW)
time.sleep(20.0/1000 - pulsewidth/1000000.0) # The cycle of 20 ms

try:
init()
while True:
for i in range(0,180):
servoPulse(servoPin1, i)

for i in range(0,180):
i = 180 - i
servoPulse(servoPin1, i)

except KeyboardInterrupt:
pass

4.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project

17
www.keyestudio.com

sudo python3 bp4_servo_test.py

After running code, the servo for ultrasonic sensor rotates

4.3 Code2

The servo controlling the pan tilt of the camera rotates


import RPi.GPIO as GPIO
import time

servoPin2 = 7
servoPin3 = 6
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

def init():
GPIO.setup(servoPin2, GPIO.OUT)
GPIO.setup(servoPin3, GPIO.OUT)

def servoPulse(servoPin, myangle):


pulsewidth = (myangle*11) + 500 # The pulse width
GPIO.output(servoPin,GPIO.HIGH)
time.sleep(pulsewidth/1000000.0)
GPIO.output(servoPin,GPIO.LOW)
time.sleep(20.0/1000 - pulsewidth/1000000.0) # The cycle of 20 ms

try:
init()
while True:
for i in range(0,180):
servoPulse(servoPin2, i)
for i in range(0,180):
servoPulse(servoPin3, i)

for i in range(0,180):
i = 180 - i
servoPulse(servoPin2, i)
for i in range(0,180):

18
www.keyestudio.com

i = 180 - i
servoPulse(servoPin3, i)

for j in range(0, 50):


servoPulse(servoPin2, 90)
for j in range(0, 50):
servoPulse(servoPin3, 90)
time.sleep(2)
except KeyboardInterrupt:
pass
GPIO.cleanup()

4.4 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp4_2servo.py

After running the code, the pan tilt of the camera rotates.

5. LED Panel

The data of the microprocessor (arduino) communicates with the AiP1640

through the two-wire bus interface.

5.1 8*16 Dot Matrix Display

19
www.keyestudio.com

5.2 Interface Description and Communication Protocol:

The communication protocol diagram is shown below:

(SCLK) is SCL, (DIN) is SDA:

①The starting condition for data input: SCL is high level and SDA changes

from high to low.

②For data command setting, there are methods as shown in the figure

below

In our sample program, select the way to add 1 to the address

20
www.keyestudio.com

automatically, the binary value is 0100 0000 and the corresponding

hexadecimal value is 0x40

add 1 to the address Description


automatically
Fixed address

Universal mode
Test mode

Irrelevant Irrelevant
choice, choice,
fill in 0 fill in 0

③For address command setting, the address can be selected as shown

below.

The first 00H is selected in our sample program, and the binary number

1100 0000 corresponds to the hexadecimal 0xc0

21
www.keyestudio.com

Display address

Irrelevant
choice,
fill in 0

④The requirement for data input is that SCL is high level when inputting

data, the signal on SDA must remain unchanged. Only when the clock

signal on SCL is low level, the signal on SDA can be altered. The data

input is low-order first, high-order is behind

⑤ The condition to end data transmission is that when SCL is low, SDA is

low, and when SCL is high, the SDA level also becomes high.

⑥ Display control, set different pulse width, the pulse width can be

selected as shown below

In the example, we choose pulse width 4/16, and the hexadecimal

corresponds to 1000 1010 is 0x8A

22
www.keyestudio.com

Function Description

Clear quantity Set pulse width to 1/16


setting Set pulse width to 2/16
Set pulse width to 4/16
Irrelevant Set pulse width to
choice, (Brightness 10/16
fill in 0 setting) Set pulse width to
11/16
Set pulse width to
12/16
Set pulse width to
13/16
Set pulse width to
Display switch On
setting off

5.3 Introduction for modulus tool

The online version of dot matrix modulus tool:

http://dotmatrixtool.com/#

①Open the link to enter the following page.

23
www.keyestudio.com

②The dot matrix is 8*16 in this project. So set the height to 8, width to 16,

and select Big Endian; as shown below.

③ Generate hexadecimal data from the pattern

24
www.keyestudio.com

As shown below, the left button of the mouse is for selection while the

right is for canceling. Thus you could use them to draw the pattern you

want, then click Generate, to yield the hexadecimal data needed.

BCM pin: SCL : GPIO 8 SDA : GPIO 9

5.4 Code

import RPi.GPIO as GPIO


import time

SCLK = 8
DIO = 9
# Display pattern data
smile = (0x00, 0x00, 0x38, 0x40, 0x40, 0x40, 0x3a, 0x02, 0x02, 0x3a, 0x40, 0x40, 0x40,
0x38, 0x00, 0x00)
matrix_forward = (0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x48, 0x90, 0x90, 0x48, 0x24, 0x12,
0x00, 0x00, 0x00, 0x00)
matrix_back = (0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12, 0x09, 0x09, 0x12, 0x24, 0x48,
0x00, 0x00, 0x00, 0x00)

25
www.keyestudio.com

matrix_left = (0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x99, 0x24, 0x42, 0x81, 0x00,
0x00, 0x00, 0x00, 0x00)
matrix_right = (0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x42, 0x24, 0x99, 0x42, 0x24, 0x18,
0x00, 0x00, 0x00, 0x00)

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(SCLK,GPIO.OUT)
GPIO.setup(DIO,GPIO.OUT)

def nop():
time.sleep(0.00003)

def start():
GPIO.output(SCLK,0)
nop()
GPIO.output(SCLK,1)
nop()
GPIO.output(DIO,1)
nop()
GPIO.output(DIO,0)
nop()

def matrix_clear():
GPIO.output(SCLK,0)
nop()
GPIO.output(DIO,0)
nop()
GPIO.output(DIO,0)
nop()

def send_date(date):
for i in range(0,8):
GPIO.output(SCLK,0)
nop()
if date & 0x01:
GPIO.output(DIO,1)
else:
GPIO.output(DIO,0)
nop()
GPIO.output(SCLK,1)
nop()
date >>= 1

26
www.keyestudio.com

GPIO.output(SCLK,0)

def end():
GPIO.output(SCLK,0)
nop()
GPIO.output(DIO,0)
nop()
GPIO.output(SCLK,1)
nop()
GPIO.output(DIO,1)
nop()

def matrix_display(matrix_value):
start()
send_date(0xc0)

for i in range(0,16):
send_date(matrix_value[i])

end()
start()
send_date(0x8A)
end()

try:
while True:
matrix_display(smile)
time.sleep(1)
matrix_display(matrix_back)
time.sleep(1)
matrix_display(matrix_forward)
time.sleep(1)
matrix_display(matrix_left)
time.sleep(1)
matrix_display(matrix_right)
time.sleep(1)
except KeyboardInterrupt:
GPIO.cleanup()

27
www.keyestudio.com

5.5 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp5_LED8X16_TM1604.py

After running the code, the dot matrix shows a smile image and a

direction pattern.

6. OLED Display

OLED display is the most commonly used for mobile phone. It features

the fine image quality, small size and high brightness. The size of our

OLED display is 0.96 inches, and the driving chip is SSD1306. It adopts IIC

communication, with a resolution of 128*64.

For more information, please refer to:


https://github.com/adafruit/Adafruit_CircuitPython_SSD1306

6.1 Code

import time

import Adafruit_GPIO.SPI as SPI


import Adafruit_SSD1306

from PIL import Image


from PIL import ImageDraw

28
www.keyestudio.com

from PIL import ImageFont

import subprocess

# Raspberry Pi pin configuration:


RST = None # on the PiOLED this pin isnt used
# Note the following are only used with SPI:
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0

# Beaglebone Black pin configuration:

# 128x64 display with hardware I2C:


disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

# Initialize library.
disp.begin()

# Clear display.
disp.clear()
disp.display()

# Create blank image for drawing.


# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))

# Get drawing object to draw on image.


draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.


draw.rectangle((0,0,width,height), outline=0, fill=0)

# Draw some shapes.


# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height-padding
# Move left to right keeping track of the current x position for drawing shapes.
x=0

29
www.keyestudio.com

# Load default font.


font = ImageFont.load_default()

# Alternatively load a TTF font. Make sure the .ttf font file is in the same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8)

while True:

# Draw a black filled box to clear the image.


draw.rectangle((0,0,width,height), outline=0, fill=0)

# Shell scripts for system monitoring from here :


https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-
load
cmd = "hostname -I | cut -d\' \' -f1"
IP = subprocess.check_output(cmd, shell = True )
cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'"
CPU = subprocess.check_output(cmd, shell = True )
cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%sMB %.2f%%\", $3,$2,$3*100/$2 }'"
MemUsage = subprocess.check_output(cmd, shell = True )
cmd = "df -h | awk '$NF==\"/\"{printf \"Disk: %d/%dGB %s\", $3,$2,$5}'"
Disk = subprocess.check_output(cmd, shell = True )

# Write two lines of text.

draw.text((x, top), "IP: " + str(IP), font=font, fill=255)


draw.text((x, top+8), str(CPU), font=font, fill=255)
draw.text((x, top+16), str(MemUsage), font=font, fill=255)
draw.text((x, top+25), str(Disk), font=font, fill=255)

# Display image.
disp.image(image)
disp.display()
time.sleep(.1)

6.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project/OledModule

30
www.keyestudio.com

sudo python3 bp6_oled_stats.py

After running the code, the OLED display shows the IP address, CPU,

running memory and RAM information of the Raspberry Pi.

6.3 Code2

import time

import RPi.GPIO as GPIO

import time

GPIO.setmode(GPIO.BCM)

import Adafruit_GPIO.SPI as SPI

import Adafruit_SSD1306

from PIL import Image

from PIL import ImageDraw

from PIL import ImageFont

#define GPIO pin

GPIO_TRIGGER = 14

GPIO_ECHO = 4

#set GPIO mode (IN / OUT)

GPIO.setup(GPIO_TRIGGER, GPIO.OUT)

GPIO.setup(GPIO_ECHO, GPIO.IN)

def distance():

# 10us is the trigger signal

GPIO.output(GPIO_TRIGGER, GPIO.HIGH)

time.sleep(0.00001) #10us

GPIO.output(GPIO_TRIGGER, GPIO.LOW)

while not GPIO.input(GPIO_ECHO):

pass

31
www.keyestudio.com

t1 = time.time()

while GPIO.input(GPIO_ECHO):

pass

t2 = time.time()

print("distance is %d " % (((t2 - t1)* 340 / 2) * 100))

time.sleep(0.01)

return ((t2 - t1)* 340 / 2) * 100

import subprocess

# Raspberry Pi pin configuration:

RST = None # on the PiOLED this pin isnt used

# Note the following are only used with SPI:

DC = 23

SPI_PORT = 0

SPI_DEVICE = 0

# Beaglebone Black pin configuration:

# 128x64 display with hardware I2C:

disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

# Initialize library.

disp.begin()

# Clear display.

disp.clear()

disp.display()

# Create blank image for drawing.

# Make sure to create image with mode '1' for 1-bit color.

width = disp.width

height = disp.height

image = Image.new('1', (width, height))

# Get drawing object to draw on image.

draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.

32
www.keyestudio.com

draw.rectangle((0,0,width,height), outline=0, fill=0)

# Draw some shapes.

# First define some constants to allow easy resizing of shapes.

padding = -2

top = padding

bottom = height-padding

# Move left to right keeping track of the current x position for drawing shapes.

x=0

# Load default font.

font = ImageFont.load_default()

# Alternatively load a TTF font. Make sure the .ttf font file is in the same directory as the python script!

# Some other nice fonts to try: http://www.dafont.com/bitmap.php

# font = ImageFont.truetype('Minecraftia.ttf', 8)

while True:

dist = int(distance()) # round numbers

print("Measured Distance = {:.2f} cm".format(dist)) #{:.2f},Keep two decimal places

# Draw a black filled box to clear the image.

draw.rectangle((0,0,width,height), outline=0, fill=0)

# Write two lines of text.

draw.text((x, top), "Distance: " , font=font, fill=255)

draw.text((x, top+8), str(dist), font=font, fill=255)

# Display image.

disp.image(image)

disp.display()

time.sleep(.1)

33
www.keyestudio.com

6.4 Run code 2 and test result

cd /home/pi/RaspberryPi-Car/basic_project/OledModule
sudo python3 bp6_2oled_ultrasonic.py

After running the code, the terminal will print out the distance measured

by the ultrasonic sensor, and the value measured by ultrasound will also

be displayed on the OLED display.

7. Driver Motor

We use two TB6612 motor driver chips to drive four motors, that is to say,

each motor of the car can be controlled respectively.

34
www.keyestudio.com

7.1 Schematic Diagram

Motor Drive BCM Pin:


Left(M2): direction control:GPIO20 GPIO21 speed PWM:GPIO 0
left(M1): direction control:GPIO22 GPIO23 speed PWM:GPIO 1
Right(M3): direction control:GPIO24 GPIO25 speed PWM:GPIO 12
Right(M4): direction control:GPIO26 GPIO27 speed PWM:GPIO 13

7.2 Code

import RPi.GPIO as GPIO


import time
GPIO.setwarnings(False)

# Control M2 motor
L_IN1 = 20
L_IN2 = 21
L_PWM1 = 0
# Control M1 motor
L_IN3 = 22
L_IN4 = 23
L_PWM2 = 1
# Control M3 motor
R_IN1 = 24
R_IN2 = 25
R_PWM1 = 12
# Control M4 motor
R_IN3 = 26
R_IN4 = 27

35
www.keyestudio.com

R_PWM2 = 13

GPIO.setmode(GPIO.BCM) # use BCM numbers


#set the MOTOR Driver Pin OUTPUT mode
GPIO.setup(L_IN1,GPIO.OUT)
GPIO.setup(L_IN2,GPIO.OUT)
GPIO.setup(L_PWM1,GPIO.OUT)

GPIO.setup(L_IN3,GPIO.OUT)
GPIO.setup(L_IN4,GPIO.OUT)
GPIO.setup(L_PWM2,GPIO.OUT)

GPIO.setup(R_IN1,GPIO.OUT)
GPIO.setup(R_IN2,GPIO.OUT)
GPIO.setup(R_PWM1,GPIO.OUT)

GPIO.setup(R_IN3,GPIO.OUT)
GPIO.setup(R_IN4,GPIO.OUT)
GPIO.setup(R_PWM2,GPIO.OUT)

GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.LOW)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.LOW)

GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.LOW)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.LOW)

#set pwm frequence to 1000hz


pwm_R1 = GPIO.PWM(R_PWM1,100)
pwm_R2 = GPIO.PWM(R_PWM2,100)
pwm_L1 = GPIO.PWM(L_PWM1,100)
pwm_L2 = GPIO.PWM(L_PWM2,100)

#set inital duty cycle to 0


pwm_R1.start(0)
pwm_L1.start(0)
pwm_R2.start(0)
pwm_L2.start(0)

36
www.keyestudio.com

while True:
GPIO.output(L_IN1,GPIO.LOW) #Upper Left forward
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(50)
GPIO.output(L_IN3,GPIO.HIGH) #Lower left forward
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(50)
GPIO.output(R_IN1,GPIO.HIGH) #Upper Right forward
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(50)
GPIO.output(R_IN3,GPIO.LOW) #Lower Right forward
GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(50)

#stop pwm
pwm_R1.stop()
pwm_L1.stop()
pwm_R2.stop()
pwm_L2.stop()
sleep(1)

GPIO.cleanup() #release all GPIO

7.3 Run code and test result

Note: Run the code and the car will go forward. If you connect the power

and network cables, remember to lift the car first before running it so as

to avoid damaging the device.

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp7_motor_test.py

Run the code, then the car will go forward.

37
www.keyestudio.com

8. Infrared Receiver

NEC Protocol:

 8 bit address and 8 bit command length.

 Extended mode available, doubling the address size.

 Address and command are transmitted twice for reliability.

 Pulse distance modulation.

 Carrier frequency of 38kHz.

 Bit time of 1.125ms or 2.25ms.

NEC IR transmission protocol:

Notice from Figure 1 that it takes:

Send 9ms+4.5ms leading code firstly, then address, inverse, command

and inverse.

38
www.keyestudio.com

The inverse code is used to verify and improve the accuracy of keys value.

The four bytes of data bits are each sent least significant bit first. Figure 1

illustrates the format of an NEC IR transmission frame, for an address of

00h (00000000b) and a command of ADh (10101101b).

The NEC protocol uses pulse distance encoding of the bits. Each pulse is a

562.5µs long 38kHz carrier burst (about 21 cycles). A logical "1" takes

2.25ms to transmit, while a logical "0" is only half of that, being 1.125ms.

The recommended carrier duty-cycle is 1/4 or 1/3.

Logical‘0’– a 562.5µs pulse burst followed by a 562.5µs space, with a

total transmit time of 1.125ms

Logical‘1’– a 562.5µs pulse burst followed by a 1.6875ms space, with a

total transmit time of 2.25ms

39
www.keyestudio.com

Note: a 562.5µs pulse and a 1.6875ms space combine 2.23ms, 562.5µs

pulse is high level, therefore, the rest is low level.

Infrared receiving pin: GPIO 15

8.1 Code

import RPi.GPIO as GPIO


import time

PIN = 15;

GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN,GPIO.IN,GPIO.PUD_UP)
print("irm test start...")

def exec_cmd(key_val):
if(key_val==0x46):
print("Button up")
elif(key_val==0x44):
print("Button left")
elif(key_val==0x40):
print("Button ok")
elif(key_val==0x43):
print("Button right")
elif(key_val==0x15):
print("Button down")
elif(key_val==0x16):
print("Button 1")
elif(key_val==0x19):
print("Button 2")
elif(key_val==0x0d):
print("Button 3")
elif(key_val==0x0c):
print("Button 4")
elif(key_val==0x18):

40
www.keyestudio.com

print("Button 5")
elif(key_val==0x5e):
print("Button 6")
elif(key_val==0x08):
print("Button 7")
elif(key_val==0x1c):
print("Button 8")
elif(key_val==0x5a):
print("Button 9")
elif(key_val==0x42):
print("Button *")
elif(key_val==0x52):
print("Button 0")
elif(key_val==0x4a):
print("Button #")

try:
while True:
if GPIO.input(PIN) == 0:
count = 0
while GPIO.input(PIN) == 0 and count < 200: # Wait for 9ms LOW level boot
code and exit the loop if it exceeds 1.2ms
count += 1
time.sleep(0.00006)

count = 0
while GPIO.input(PIN) == 1 and count < 80: # Wait for a 4.5ms HIGH level
boot code and exit the loop if it exceeds 0.48ms
count += 1
time.sleep(0.00006)

idx = 0 # byte count variable


cnt = 0 #Variable per byte bit
#There are 4 bytes in total. The first byte is the address code, the second is the
address inverse code,
#the third is the control command data of the corresponding button, and the
fourth is the control command inverse code
data = [0,0,0,0]
for i in range(0,32): # Start receiving 32BITE data
count = 0
while GPIO.input(PIN) == 0 and count < 15: # Wait for the LOW LOW level
of 562.5US to pass and exit the loop if it exceeds 900US
count += 1

41
www.keyestudio.com

time.sleep(0.00006)

count = 0
while GPIO.input(PIN) == 1 and count < 40: # waits for logical HIGH level
to pass and exits the loop if it exceeds 2.4ms
count += 1
time.sleep(0.00006)

# if count>8, that is, the logical time is greater than 0.54+0.562=1.12ms,


that is,
#the period is greater than the logical 0 period, that is equivalent to receiving
logical 1
if count > 8:
data[idx] |= 1<<cnt #When idx=0 is the first data data[idx] =
data[idx] | 1<<cnt 00000001 <<1 == 0000 0010
if cnt == 7: #With 8 byte
cnt = 0 #Displacement qing 0
idx += 1 #Store the next data
else:
cnt += 1 #The shift adds 1
#Determine whether address code + address inverse code =0xff, control code +
control inverse code = 0xFF
if data[0]+data[1] == 0xFF and data[2]+data[3] == 0xFF:
print("Get the key: 0x%02x" %data[2]) #Data [2] is the control code we
need
exec_cmd(data[2])
except KeyboardInterrupt:
GPIO.cleanup()

8.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project

sudo python3 bp8_ir_remote.py

42
www.keyestudio.com

After running the code, point at infrared receiver module with the infrared

remote control and press keys. The terminal will print out the received

signal values, as shown in the figure below:

9. IR Remote Control Car

We have learned motor drivers, 8*16 dot matrix and infrared remote

control. Let's make the infrared remote control car.

9.1 Code

import RPi.GPIO as GPIO


import time

PIN = 15;
SCLK = 8
DIO = 9
# Display pattern data
matrix_smile = (0x00, 0x00, 0x38, 0x40, 0x40, 0x40, 0x3a, 0x02, 0x02, 0x3a, 0x40, 0x40, 0x40, 0x38,
0x00, 0x00)
matrix_forward = (0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x48, 0x90, 0x90, 0x48, 0x24, 0x12, 0x00,
0x00, 0x00, 0x00)
matrix_back = (0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12, 0x09, 0x09, 0x12, 0x24, 0x48, 0x00, 0x00,
0x00, 0x00)

43
www.keyestudio.com

matrix_left = (0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x99, 0x24, 0x42, 0x81, 0x00, 0x00, 0x00,
0x00, 0x00)
matrix_right = (0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x42, 0x24, 0x99, 0x42, 0x24, 0x18, 0x00, 0x00,
0x00, 0x00)

GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN,GPIO.IN,GPIO.PUD_UP)
GPIO.setup(SCLK,GPIO.OUT)
GPIO.setup(DIO,GPIO.OUT)

print("irm test start...")


# Control M2 motor
L_IN1 = 20
L_IN2 = 21
L_PWM1 = 0
# Control M1 motor
L_IN3 = 22
L_IN4 = 23
L_PWM2 = 1
# Control M3 motor
R_IN1 = 24
R_IN2 = 25
R_PWM1 = 12
# Control M4 motor
R_IN3 = 26
R_IN4 = 27
R_PWM2 = 13

GPIO.setmode(GPIO.BCM) # use BCM numbers


#set the MOTOR Driver Pin OUTPUT mode
GPIO.setup(L_IN1,GPIO.OUT)
GPIO.setup(L_IN2,GPIO.OUT)
GPIO.setup(L_PWM1,GPIO.OUT)
GPIO.setup(L_IN3,GPIO.OUT)
GPIO.setup(L_IN4,GPIO.OUT)
GPIO.setup(L_PWM2,GPIO.OUT)
GPIO.setup(R_IN1,GPIO.OUT)
GPIO.setup(R_IN2,GPIO.OUT)
GPIO.setup(R_PWM1,GPIO.OUT)
GPIO.setup(R_IN3,GPIO.OUT)
GPIO.setup(R_IN4,GPIO.OUT)
GPIO.setup(R_PWM2,GPIO.OUT)

44
www.keyestudio.com

GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.LOW)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.LOW)
GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.LOW)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.LOW)

#set pwm frequence to 1000hz


pwm_R1 = GPIO.PWM(R_PWM1,100)
pwm_R2 = GPIO.PWM(R_PWM2,100)
pwm_L1 = GPIO.PWM(L_PWM1,100)
pwm_L2 = GPIO.PWM(L_PWM2,100)

#set inital duty cycle to 0


pwm_R1.start(0)
pwm_L1.start(0)
pwm_R2.start(0)
pwm_L2.start(0)

def nop():
time.sleep(0.000001)

def nop2():
time.sleep(0.01)

def start():
GPIO.output(SCLK,1)
nop()
GPIO.output(DIO,1)
nop()
GPIO.output(DIO,0)
nop()
GPIO.output(SCLK,0)

def send_date(date):
for i in range(0,8):
GPIO.output(SCLK,0)
nop()
if date & 0x01:
GPIO.output(DIO,1)
else:

45
www.keyestudio.com

GPIO.output(DIO,0)
nop()
GPIO.output(SCLK,1)
nop()
date >>= 1
GPIO.output(SCLK,0)

def end():
GPIO.output(SCLK,0)
nop()
GPIO.output(DIO,0)
nop()
GPIO.output(SCLK,1)
nop()
GPIO.output(DIO,1)
nop()

def matrix_display(matrix_value):
start()
send_date(0xc0)

for i in range(0,16):
send_date(matrix_value[i])

end()
start()
send_date(0x8A)
end()

def exec_cmd(key_val):
if(key_val==0x46):
print("Button up")
matrix_display(matrix_forward)
GPIO.output(L_IN1,GPIO.LOW) #Upper Left forward
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(50)
GPIO.output(L_IN3,GPIO.HIGH) #Lower left forward
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(50)
GPIO.output(R_IN1,GPIO.HIGH) #Upper Right forward
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(50)
GPIO.output(R_IN3,GPIO.LOW) #Lower Right forward

46
www.keyestudio.com

GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(50)
elif(key_val==0x44):
print("Button left")
matrix_display(matrix_left)
GPIO.output(L_IN1,GPIO.HIGH)
GPIO.output(L_IN2,GPIO.LOW)
pwm_L1.ChangeDutyCycle(100)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.HIGH)
pwm_L2.ChangeDutyCycle(100)
GPIO.output(R_IN1,GPIO.HIGH) #Upper Right forward
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(100)
GPIO.output(R_IN3,GPIO.LOW) #Lower Right forward
GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(100)
elif(key_val==0x40):
print("Button ok")
matrix_display(matrix_smile)
pwm_L1.ChangeDutyCycle(0)
pwm_L2.ChangeDutyCycle(0)
pwm_R1.ChangeDutyCycle(0)
pwm_R2.ChangeDutyCycle(0)
elif(key_val==0x43):
print("Button right")
matrix_display(matrix_right)
GPIO.output(L_IN1,GPIO.LOW) #Upper Left forward
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(100)
GPIO.output(L_IN3,GPIO.HIGH) #Lower left forward
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(100)
GPIO.output(R_IN1,GPIO.LOW) #Upper Right forward
GPIO.output(R_IN2,GPIO.HIGH)
pwm_R1.ChangeDutyCycle(100)
GPIO.output(R_IN3,GPIO.HIGH) #Lower Right forward
GPIO.output(R_IN4,GPIO.LOW)
pwm_R2.ChangeDutyCycle(100)
elif(key_val==0x15):
print("Button down")
matrix_display(matrix_back)
GPIO.output(L_IN1,GPIO.HIGH)

47
www.keyestudio.com

GPIO.output(L_IN2,GPIO.LOW)
pwm_L1.ChangeDutyCycle(50)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.HIGH)
pwm_L2.ChangeDutyCycle(50)
GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.HIGH)
pwm_R1.ChangeDutyCycle(50)
GPIO.output(R_IN3,GPIO.HIGH)
GPIO.output(R_IN4,GPIO.LOW)
pwm_R2.ChangeDutyCycle(50)
elif(key_val==0x16):
print("Button 1")
elif(key_val==0x19):
print("Button 2")
elif(key_val==0x0d):
print("Button 3")
elif(key_val==0x0c):
print("Button 4")
elif(key_val==0x18):
print("Button 5")
elif(key_val==0x5e):
print("Button 6")
elif(key_val==0x08):
print("Button 7")
elif(key_val==0x1c):
print("Button 8")
elif(key_val==0x5a):
print("Button 9")
elif(key_val==0x42):
print("Button *")
elif(key_val==0x52):
print("Button 0")
elif(key_val==0x4a):
print("Button #")

try:
while True:
if GPIO.input(PIN) == 0:
count = 0
while GPIO.input(PIN) == 0 and count < 200: # Wait for 9ms LOW level boot code and exit
the loop if it exceeds 1.2ms
count += 1

48
www.keyestudio.com

time.sleep(0.00006)

count = 0
while GPIO.input(PIN) == 1 and count < 80: # Wait for a 4.5ms HIGH level boot code and
exit the loop if it exceeds 0.48ms
count += 1
time.sleep(0.00006)

idx = 0 # byte count variable


cnt = 0 #Variable per byte bit
#There are 4 bytes in total. The first byte is the address code, the second is the address
inverse code,
#the third is the control command data of the corresponding button, and the fourth is the
control command inverse code
data = [0,0,0,0]
for i in range(0,32): # Start receiving 32BITE data
count = 0
while GPIO.input(PIN) == 0 and count < 15: # Wait for the LOW LOW level of 562.5US to
pass and exit the loop if it exceeds 900US
count += 1
time.sleep(0.00006)

count = 0
while GPIO.input(PIN) == 1 and count < 40: # waits for logical HIGH level to pass and
exits the loop if it exceeds 2.4ms
count += 1
time.sleep(0.00006)

# if count>8, that is, the logical time is greater than 0.54+0.562=1.12ms, that is,
#the period is greater than the logical 0 period, that is equivalent to receiving logical 1
if count > 8:
data[idx] |= 1<<cnt #When idx=0 is the first data data[idx] = data[idx] | 1<<cnt
00000001 <<1 == 0000 0010
if cnt == 7: #With 8 byte
cnt = 0 #Displacement qing 0
idx += 1 #Store the next data
else:
cnt += 1 #The shift adds 1
#Determine whether address code + address inverse code =0xff, control code + control
inverse code = 0xFF
if data[0]+data[1] == 0xFF and data[2]+data[3] == 0xFF:
print("Get the key: 0x%02x" %data[2]) #Data [2] is the control code we need
exec_cmd(data[2])

49
www.keyestudio.com

except KeyboardInterrupt:
GPIO.cleanup()

9.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project
sudo python3 bp9_ir_car.py

After running test code, press the keys of the remote control,then the car

will move and the dot matrix will show the corresponding patterns.

10. Line Tracking Car

The three-channel line tracking sensor has three sensor. When it detects

black lines, the value will be 1.

The middle sensor detects black lines: the car will go forward.

When the middle one doesn’t detect the black line:

Left sensor detects black lines and right one doesn’t detect black lines;

the car will turn left.

The left one doesn’t detect black lines, the right one detects ones ;the

car will turn right.

Neither left one nor right one detects black lines;the car will stop

50
www.keyestudio.com

Both of two sensors detect black lines;the car will stop.

Middle left line Right line Status


tracking tracking tracking
sensor sensor sensor
1 - - Go forward
1 0 Turn left
0 1 Turn right
0
0 0 stop
1 1 stop

10.1 Code

import RPi.GPIO as GPIO


import time
GPIO.setwarnings(False)

# Control M2 motor
L_IN1 = 20
L_IN2 = 21
L_PWM1 = 0
# Control M1 motor
L_IN3 = 22

51
www.keyestudio.com

L_IN4 = 23
L_PWM2 = 1
# Control M3 motor
R_IN1 = 24
R_IN2 = 25
R_PWM1 = 12
# Control M4 motor
R_IN3 = 26
R_IN4 = 27
R_PWM2 = 13

#tracking pin
trackingPin1 = 17
trackingPin2 = 18
trackingPin3 = 19

GPIO.setmode(GPIO.BCM) # use BCM numbers

GPIO.setup(trackingPin1,GPIO.IN) # set trackingPin INPUT mode


GPIO.setup(trackingPin2,GPIO.IN)
GPIO.setup(trackingPin3,GPIO.IN)

#set the MOTOR Driver Pin OUTPUT mode


GPIO.setup(L_IN1,GPIO.OUT)
GPIO.setup(L_IN2,GPIO.OUT)
GPIO.setup(L_PWM1,GPIO.OUT)

GPIO.setup(L_IN3,GPIO.OUT)
GPIO.setup(L_IN4,GPIO.OUT)
GPIO.setup(L_PWM2,GPIO.OUT)

GPIO.setup(R_IN1,GPIO.OUT)
GPIO.setup(R_IN2,GPIO.OUT)
GPIO.setup(R_PWM1,GPIO.OUT)

GPIO.setup(R_IN3,GPIO.OUT)
GPIO.setup(R_IN4,GPIO.OUT)
GPIO.setup(R_PWM2,GPIO.OUT)

52
www.keyestudio.com

GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.LOW)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.LOW)

GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.LOW)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.LOW)

#set pwm frequence to 1000hz


pwm_R1 = GPIO.PWM(R_PWM1,100)
pwm_R2 = GPIO.PWM(R_PWM2,100)
pwm_L1 = GPIO.PWM(L_PWM1,100)
pwm_L2 = GPIO.PWM(L_PWM2,100)

#set inital duty cycle to 0


pwm_R1.start(0)
pwm_L1.start(0)
pwm_R2.start(0)
pwm_L2.start(0)
# car forward
def car_forward():
GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(30)
GPIO.output(L_IN3,GPIO.HIGH)
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(30)
GPIO.output(R_IN1,GPIO.HIGH)
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(30)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(30)
# car left
def car_left():

53
www.keyestudio.com

GPIO.output(L_IN1,GPIO.HIGH)
GPIO.output(L_IN2,GPIO.LOW)
pwm_L1.ChangeDutyCycle(50)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.HIGH)
pwm_L2.ChangeDutyCycle(50)
GPIO.output(R_IN1,GPIO.HIGH)
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(50)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(50)
# car right
def car_right():
GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(50)
GPIO.output(L_IN3,GPIO.HIGH)
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(50)
GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.HIGH)
pwm_R1.ChangeDutyCycle(50)
GPIO.output(R_IN3,GPIO.HIGH)
GPIO.output(R_IN4,GPIO.LOW)
pwm_R2.ChangeDutyCycle(50)
# car stop
def car_stop():
pwm_L1.ChangeDutyCycle(0)
pwm_L2.ChangeDutyCycle(0)
pwm_R1.ChangeDutyCycle(0)
pwm_R2.ChangeDutyCycle(0)

while True:
val1 = GPIO.input(trackingPin1) # read the value
val2 = GPIO.input(trackingPin2)
val3 = GPIO.input(trackingPin3)

54
www.keyestudio.com

if(val2 == 1):
car_forward()
print("forward")
else:
if((val1 == 1) and (val3 == 0)):
car_right()
print("right")
elif((val1 == 0) and (val3 == 1)):
car_left()
print("left")
else:
car_stop()
print("stop")

#stop pwm
pwm_R1.stop()
pwm_L1.stop()
pwm_R2.stop()
pwm_L2.stop()
sleep(1)

GPIO.cleanup() #release all GPIO

10.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project
sudo python3 bp10_tracking_car.py

Run the code and plug in power and place it on a tracking map,then the

car will move along the black line.

55
www.keyestudio.com

11. Ultrasonic Following Car

Gauge distance by the ultrasonic detection, make car follow the object to

go forward or backward.

Logical form of the ultrasonic following car

Distance value detected by Ultrasonic Following Car

the ultrasonic sensor

<10 Go back

10≤distance value≤14 stop

14<distance value≤50 Go forward

>50 stop

11.1 Code

import RPi.GPIO as GPIO


import time
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # use BCM numbers

#define GPIO pin


GPIO_TRIGGER = 14
GPIO_ECHO = 4

56
www.keyestudio.com

#set GPIO mode (IN / OUT)


GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)
def distance():
# 10us is the trigger signal
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001) #10us
GPIO.output(GPIO_TRIGGER, False)
start_time = time.time() # Log the time the program runs to this point
stop_time = time.time() # Log the time the program runs to this point
while GPIO.input(GPIO_ECHO) == 0: #Indicates that the ultrasonic wave has been emitted
start_time = time.time() #Record launch time
while GPIO.input(GPIO_ECHO) == 1: #Indicates that the returned ultrasound has been
received
stop_time = time.time() #Record receiving time
time_elapsed = stop_time - start_time #Time difference from transmit to receive
distance = (time_elapsed * 34000) / 2 #Calculate the distance
return distance #Return to calculated distance

# Control M2 motor
L_IN1 = 20
L_IN2 = 21
L_PWM1 = 0
# Control M1 motor
L_IN3 = 22
L_IN4 = 23
L_PWM2 = 1
# Control M3 motor
R_IN1 = 24
R_IN2 = 25
R_PWM1 = 12
# Control M4 motor
R_IN3 = 26
R_IN4 = 27
R_PWM2 = 13

#set the MOTOR Driver Pin OUTPUT mode


GPIO.setup(L_IN1,GPIO.OUT)

57
www.keyestudio.com

GPIO.setup(L_IN2,GPIO.OUT)
GPIO.setup(L_PWM1,GPIO.OUT)
GPIO.setup(L_IN3,GPIO.OUT)
GPIO.setup(L_IN4,GPIO.OUT)
GPIO.setup(L_PWM2,GPIO.OUT)
GPIO.setup(R_IN1,GPIO.OUT)
GPIO.setup(R_IN2,GPIO.OUT)
GPIO.setup(R_PWM1,GPIO.OUT)
GPIO.setup(R_IN3,GPIO.OUT)
GPIO.setup(R_IN4,GPIO.OUT)
GPIO.setup(R_PWM2,GPIO.OUT)

GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.LOW)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.LOW)
GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.LOW)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.LOW)

#set pwm frequence to 1000hz


pwm_R1 = GPIO.PWM(R_PWM1,100)
pwm_R2 = GPIO.PWM(R_PWM2,100)
pwm_L1 = GPIO.PWM(L_PWM1,100)
pwm_L2 = GPIO.PWM(L_PWM2,100)

#set inital duty cycle to 0


pwm_R1.start(0)
pwm_L1.start(0)
pwm_R2.start(0)
pwm_L2.start(0)
# car forward
def car_forward():
GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(30)

58
www.keyestudio.com

GPIO.output(L_IN3,GPIO.HIGH)
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(30)
GPIO.output(R_IN1,GPIO.HIGH)
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(30)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(30)
# car back
def car_back():
GPIO.output(L_IN1,GPIO.HIGH)
GPIO.output(L_IN2,GPIO.LOW)
pwm_L1.ChangeDutyCycle(30)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.HIGH)
pwm_L2.ChangeDutyCycle(30)
GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.HIGH)
pwm_R1.ChangeDutyCycle(30)
GPIO.output(R_IN3,GPIO.HIGH)
GPIO.output(R_IN4,GPIO.LOW)
pwm_R2.ChangeDutyCycle(30)
# car stop
def car_stop():
pwm_L1.ChangeDutyCycle(0)
pwm_L2.ChangeDutyCycle(0)
pwm_R1.ChangeDutyCycle(0)
pwm_R2.ChangeDutyCycle(0)

while True:
dist = distance()
print("Measured Distance = {:.2f} cm".format(dist))
#time.sleep(0.02)
if dist < 10:
time.sleep(0.15)
car_back()
elif (dist>=10 and dist<=14):

59
www.keyestudio.com

car_stop()
time.sleep(0.1)
elif (dist>14 and dist<= 50):
time.sleep(0.15)
car_forward()
else:
car_stop()

print("stop")
#stop pwm
pwm_R1.stop()
pwm_L1.stop()
pwm_R2.stop()
pwm_L2.stop()
sleep(1)

GPIO.cleanup() #release all GPIO

11.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project
sudo python3 bp11_follow_car.py

Run test code and plug in power. Put your hand before the car, then it will

follow your hand to go forward, stop and go back.

12. Ultrasonic Obstacle Avoidance Robot

60
www.keyestudio.com

Gauge distance by the ultrasonic detection to make car avoid the

obstacle.

Principle:

If the obstacle is away from more than 15cm, the car will go forward

If the obstacle is less than or equal to 15cm, the servo will rotate to left

and record the distance value away form an obstacle, then rotate to right

and record the distance value away from an obstacle. Next, compare

these two values, if left one is greater than the right one,the car will turn

left;otherwise, it will turn left.

Logic Chart:

Detected
Left distance Right distance
distance Compare values Status
value value
value

>15cm - - - Go

61
www.keyestudio.com

forward

Servo rotates Servo rotates Servo rotates to 90°(front);


Turn left
to 180°, the to 0°, the value left_distance>right_distance
<15cm
value is us Turn
left_distance<right_distance
left_distance right_distance right

12.1 Code

import RPi.GPIO as GPIO


import time
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # use BCM numbers

servoPin1 = 5
GPIO.setup(servoPin1, GPIO.OUT)
def servoPulse(servoPin, myangle):
pulsewidth = (myangle*11) + 500 # The pulse width
GPIO.output(servoPin,GPIO.HIGH)
time.sleep(pulsewidth/1000000.0)
GPIO.output(servoPin,GPIO.LOW)
time.sleep(20.0/1000 - pulsewidth/1000000.0) # The cycle of 20 ms

#define GPIO pin


GPIO_TRIGGER = 14
GPIO_ECHO = 4
#set GPIO mode (IN / OUT)
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)

62
www.keyestudio.com

GPIO.setup(GPIO_ECHO, GPIO.IN)
def distance():
# 10us is the trigger signal
GPIO.output(GPIO_TRIGGER, True)
time.sleep(0.00001) #10us
GPIO.output(GPIO_TRIGGER, False)
start_time = time.time() # Log the time the program runs to this point
stop_time = time.time() # Log the time the program runs to this point
while GPIO.input(GPIO_ECHO) == 0: #Indicates that the ultrasonic wave has been emitted
start_time = time.time() #Record launch time
while GPIO.input(GPIO_ECHO) == 1: #Indicates that the returned ultrasound has been received
stop_time = time.time() #Record receiving time
time_elapsed = stop_time - start_time #Time difference from transmit to receive
distance = (time_elapsed * 34000) / 2 #Calculate the distance
return distance #Return to calculated distance

# Control M2 motor
L_IN1 = 20
L_IN2 = 21
L_PWM1 = 0
# Control M1 motor
L_IN3 = 22
L_IN4 = 23
L_PWM2 = 1
# Control M3 motor
R_IN1 = 24
R_IN2 = 25
R_PWM1 = 12
# Control M4 motor
R_IN3 = 26
R_IN4 = 27
R_PWM2 = 13

#set the MOTOR Driver Pin OUTPUT mode


GPIO.setup(L_IN1,GPIO.OUT)
GPIO.setup(L_IN2,GPIO.OUT)
GPIO.setup(L_PWM1,GPIO.OUT)
GPIO.setup(L_IN3,GPIO.OUT)

63
www.keyestudio.com

GPIO.setup(L_IN4,GPIO.OUT)
GPIO.setup(L_PWM2,GPIO.OUT)
GPIO.setup(R_IN1,GPIO.OUT)
GPIO.setup(R_IN2,GPIO.OUT)
GPIO.setup(R_PWM1,GPIO.OUT)
GPIO.setup(R_IN3,GPIO.OUT)
GPIO.setup(R_IN4,GPIO.OUT)
GPIO.setup(R_PWM2,GPIO.OUT)

GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.LOW)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.LOW)
GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.LOW)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.LOW)

#set pwm frequence to 1000hz


pwm_R1 = GPIO.PWM(R_PWM1,100)
pwm_R2 = GPIO.PWM(R_PWM2,100)
pwm_L1 = GPIO.PWM(L_PWM1,100)
pwm_L2 = GPIO.PWM(L_PWM2,100)

#set inital duty cycle to 0


pwm_R1.start(0)
pwm_L1.start(0)
pwm_R2.start(0)
pwm_L2.start(0)
# car forward
def car_forward():
GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(40)
GPIO.output(L_IN3,GPIO.HIGH)
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(40)

64
www.keyestudio.com

GPIO.output(R_IN1,GPIO.HIGH)
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(40)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(40)
# car left
def car_left():
GPIO.output(L_IN1,GPIO.HIGH)
GPIO.output(L_IN2,GPIO.LOW)
pwm_L1.ChangeDutyCycle(80)
GPIO.output(L_IN3,GPIO.LOW)
GPIO.output(L_IN4,GPIO.HIGH)
pwm_L2.ChangeDutyCycle(80)
GPIO.output(R_IN1,GPIO.HIGH)
GPIO.output(R_IN2,GPIO.LOW)
pwm_R1.ChangeDutyCycle(80)
GPIO.output(R_IN3,GPIO.LOW)
GPIO.output(R_IN4,GPIO.HIGH)
pwm_R2.ChangeDutyCycle(80)
# car right
def car_right():
GPIO.output(L_IN1,GPIO.LOW)
GPIO.output(L_IN2,GPIO.HIGH)
pwm_L1.ChangeDutyCycle(80)
GPIO.output(L_IN3,GPIO.HIGH)
GPIO.output(L_IN4,GPIO.LOW)
pwm_L2.ChangeDutyCycle(80)
GPIO.output(R_IN1,GPIO.LOW)
GPIO.output(R_IN2,GPIO.HIGH)
pwm_R1.ChangeDutyCycle(80)
GPIO.output(R_IN3,GPIO.HIGH)
GPIO.output(R_IN4,GPIO.LOW)
pwm_R2.ChangeDutyCycle(80)

# car stop
def car_stop():
pwm_L1.ChangeDutyCycle(0)

65
www.keyestudio.com

pwm_L2.ChangeDutyCycle(0)
pwm_R1.ChangeDutyCycle(0)
pwm_R2.ChangeDutyCycle(0)

# Loop several times to make sure the steering gear is turned to the specified Angle
# The initialization Angle is 90 degrees
for g in range(0, 50):
servoPulse(servoPin1, 90)

while True:
dist = distance()
print("Measured Distance = {:.2f} cm".format(dist))
time.sleep(0.01)
if dist > 15: # If the obstacle in front is larger than 15cm
car_forward()
else: # If the obstacle in front is less than 15cm
dist = distance()
if dist <= 15: # Make sure the obstacle in front is less than 15cm
car_stop()
# Loop several times to make sure the steering gear is turned to the specified Angle
for i in range(0, 50):
servoPulse(servoPin1, 180)
time.sleep(0.1)
left_distance = distance() # Measure the distance to the left
time.sleep(0.2)
for j in range(0, 50):
servoPulse(servoPin1, 0)
time.sleep(0.1)
right_distance = distance() # Measure the distance to the right
time.sleep(0.2)
for k in range(0, 50):
servoPulse(servoPin1, 90)
time.sleep(0.3)
# Compare the distance between the left and right sides
if left_distance > right_distance:
car_left()
time.sleep(0.6)
#The car stops to prevent the sudden positive and

66
www.keyestudio.com

#negative rotation of the motor from causing the raspberry PI voltage and
#current too low malfunction
car_stop()
time.sleep(0.1)
else:
car_right()
time.sleep(0.6)
car_stop()
time.sleep(0.1)

#stop pwm
pwm_R1.stop()
pwm_L1.stop()
pwm_R2.stop()
pwm_L2.stop()
sleep(1)

GPIO.cleanup() #release all GPIO

12.2 Run code and test result

cd /home/pi/RaspberryPi-Car/basic_project
sudo python3 bp12_avoid_car.py

Run test code and plug in power. The car will avoid the obstacle

67
www.keyestudio.com

68

You might also like