Introduction: Controlling a Raspberry Pi RC Car With a Keyboard

In this intermediate tutorial you will learn how to operate a hacked RC car with a keyboard using a model B Raspberry Pi device using Python. The key points in this tutorial include:

• Configuring the virtual Pulse Width Modulation (PWM) for the GPIO pins so two DC motors can run independently
• Wiring the Raspberry Pi to the RC car

I had originally planned to have the car operated through the use of an IR remote control and receiver but due to compatibility issues between the Raspberry Pi and the required libraries I had to revise my project.

Step 1: Components

Please ensure you have the following components before continuing with the tutorial:

• Raspberry Pi Model B (http://www.adafruit.com/products/998)
• MicroSD Card (http://www.adafruit.com/products/102)
• Pi Cobbler Breakout and Cable (http://www.adafruit.com/products/914)
• Any sized Breadboard (http://www.adafruit.com/products/239)
• M/M Wires (http://www.adafruit.com/products/153)
• F/F Wires (http://www.adafruit.com/products/266)
• Prototyping Pi Plate (http://www.adafruit.com/products/801)
• L293D Chip (http://www.adafruit.com/products/807)
• Medium sized RC Car with DC Motors
• Bluetooth Keyboard
• Soldering Iron and Wire

Step 2: Prerequisites

Please ensure you meet the following prerequisites before continuing with the tutorial:

• An assembled Cobbler with GPIO Cable and Breadboard

• Soldering iron experience

• An upgraded operating system. You can achieve this by entering into the terminal:

      sudo apt-get upgrade

• Up-to-date GPIO library. You can achieve this by entering into the terminal:

      sudo apt-get update
      sudo apt-get install python-dev
      sudo apt-get install python-rpi.gpio

Step 3: The L293D Chip

The most important part of your hardware setup is the L293D chip. With the appropriate code, this chip allows you to control the speed and direction of two independent DC motors. It is crucial for you to understand how this chip works and the function of each of its pins. The ‘+Vmotor’ pin (8) provides the power for the motors while the ‘+V’ pin (16) provides the power for the chip’s logic. The ‘IN’ pins (2, 7, 10, 15) each require a connection to a GPIO pin and the ‘OUT’ pins (3, 6, 11, 14) provide the output for the two DC motors.

Step 4: Hardware

Once you understand the mechanics of the L293D chip it is time to assemble it, along with the rest of the components, onto the breadboard. The schematic has been provided for you. Please note the orientation of the L293D chip.

You may notice the LEDs on the diagram. These represent the headlights or neon underside lights on your RC car. If your car lacks these features please disregard this section of the schematic.

Step 5: Software

Below is the python code you will need in order for this program to work. Save the program as rc_car.py when finished.

import RPi.GPIO as io
io.setmode(io.BCM)
import sys, tty, termios, time

# These two blocks of code configure the PWM settings for
# the two DC motors on the RC car. It defines the two GPIO
# pins used for the input, starts the PWM and sets the
# motors' speed to 0
motor1_in1_pin = 4
motor1_in2_pin = 17
io.setup(motor1_in1_pin, io.OUT)
io.setup(motor1_in2_pin, io.OUT)
motor1 = io.PWM(4,100)
motor1.start(0)
motor1.ChangeDutyCycle(0)

motor2_in1_pin = 24
motor2_in2_pin = 25
io.setup(motor2_in1_pin, io.OUT)
io.setup(motor2_in2_pin, io.OUT)
motor2 = io.PWM(4,100)
motor2.start(0)
motor2.ChangeDutyCycle(0)

# Defining the GPIO pins that will be used for the LEDs on
# the RC car and setting the output to false
io.setup(18, io.OUT)
io.output(18, False)

io.setup(23, io.OUT)
io.output(23, False)

# The getch method can determine which key has been pressed
# by the user on the keyboard by accessing the system files
# It will then return the pressed key as a variable
def getch():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

# This section of code defines the methods used to determine
# whether a motor needs to spin forward or backwards. The
# different directions are acheived by setting one of the
# GPIO pins to true and the other to false. If the status of
# both pins match, the motor will not turn.
def motor1_forward():
    io.output(motor1_in1_pin, True)
    io.output(motor1_in2_pin, False)

def motor1_reverse():
    io.output(motor1_in1_pin, False)
    io.output(motor1_in2_pin, True)

def motor2_forward():
    io.output(motor2_in1_pin, True)
    io.output(motor2_in2_pin, False)

def motor2_reverse():
    io.output(motor2_in1_pin, False)
    io.output(motor2_in2_pin, True)

# This method will toggle the lights on/off when the user
# presses a particular key. It will then change the status
# of the lights so it will know whether to turn them on or
# off when it is next called.
def toggleLights():

    global lightStatus

    if(lightStatus == False):
        io.output(18, True)
        io.output(23, True)
        lightStatus = True
    else:
        io.output(18, False)
        io.output(23, False)
        lightStatus = False

# This method will toggle the direction of the steering
# motor. The method will determine whether the user wants
# to turn left or right depending on the key they press and
# then make the appropriate adjustment. It works as a toggle
# because the program cannot read multiple pressed keys at
# the same time. The possible positions of the wheels are
# "right", "centre" and "left". It will then update the
# status of the wheel to access next time it is called.
def toggleSteering(direction):

    global wheelStatus

    if(direction == "right"):
        if(wheelStatus == "centre"):
            motor1_forward()
            motor1.ChangeDutyCycle(99)
            wheelStatus = "right"
        elif(wheelStatus == "left"):
            motor1.ChangeDutyCycle(0)
            wheelStatus = "centre"

    if(direction == "left"):
        if(wheelStatus == "centre"):
            motor1_reverse()
            motor1.ChangeDutyCycle(99)
            wheelStatus = "left"
        elif(wheelStatus == "right"):
            motor1.ChangeDutyCycle(0)
            wheelStatus = "centre"

# Setting the PWM pins to false so the motors will not move
# until the user presses the first key
io.output(motor1_in1_pin, False)
io.output(motor1_in2_pin, False)
io.output(motor2_in1_pin, False)
io.output(motor2_in2_pin, False)

# Global variables for the status of the lights and steering
lightStatus = False
wheelStatus = "centre"

# Instructions for when the user has an interface
print("w/s: acceleration")
print("a/d: steering")
print("l: lights")
print("x: exit")

# Infinite loop that will not end until the user presses the
# exit key
while True:
    # Keyboard character retrieval method is called and saved
    # into variable
    char = getch()

    # The car will drive forward when the "w" key is pressed
    if(char == "w"):
        motor2_forward()
        motor2.ChangeDutyCycle(99)

    # The car will reverse when the "s" key is pressed
    if(char == "s"):
        motor2_reverse()
        motor2.ChangeDutyCycle(99)

    # The "a" key will toggle the steering left
    if(char == "a"):
        toggleSteering("left")

    # The "d" key will toggle the steering right
    if(char == "d"):
        toggleSteering("right")

    # The "l" key will toggle the LEDs on/off
    if(char == "l"):
        toggleLights()

    # The "x" key will break the loop and exit the program
    if(char == "x"):
        print("Program Ended")
        break

    # At the end of each loop the acceleration motor will stop
    # and wait for its next command
    motor2.ChangeDutyCycle(0)

    # The keyboard character variable will be set to blank, ready
    # to save the next key that is pressed
    char = ""

# Program will cease all GPIO activity before terminating
io.cleanup()

Step 6: Test & Configure

To test the code you must run it as a super user to access the pins. Type the following:

      sudo python rc_car.py

Press the W and S keys to move the car forward and backward
Press the A and D keys to toggle the steering left and right
Press the L key to toggle the lights if you have them.
Press the X key when you are ready to exit the program.

Step 7: Soldering

It is now time to solder the parts onto a protoyping plate to increase its durability, and then solder the plate onto the car connecting the battery pack and motors in the process. Remember to not connect any of the pins together with solder because it will cross the signals. It is also a good idea to colour code your wires for easy reference.

The final product should look similar to this this:

Step 8: Enjoying Your Newly Hacked RC Car

There you have it. With a Raspberry Pi and some simple bits and pieces you have made yourself a fun little toy and learnt about electronics and programming along the way. Enjoy!

Comments

author
Gagana R (author)2017-04-19

How do we download and install getch module

author
hapra (author)2017-02-13

Its not working for me.. It says the code has error... Help pls

author
hapra (author)2017-02-13

can I use a power bank instead of the AA batteries?

Someone help plss...

Thnx in advance

author
MdZaheerHasan made it! (author)2016-11-20

I did it without the breakout board. That picture is in between, but I finished it. It would probably be best if I put it on a proto board now, but I will probably edit the code. I had it rushing and breaking off connections.

Great job man, thanks for sharing!

Great

15146889_10154702461265349_1784199304_o.jpg
author
MdZaheerHasan (author)2016-11-20

Hey, you've got a slight error in your schematic. The +ve power from the batteries aren't connected to anything. You have pin 8 (+VMotor) of the H-bridge connected to ground. It should be connected to the batteries.

author
PriyaG (author)2015-03-12

If i want ride a 12 volt motor will this post code and circuit work, because when i did it with 6v motor it worked the best.

author
g1naveen (author)PriyaG2015-05-08

if you wanna run a 12v motor, then you need a motor controller. If you have used a 6v motor, it might have run with the 5v supply .

12v motor can be connected to a motor controller which can be connected to a 12v power source and RPi input can be directly given to the motor controller input.

Additionally, motor controller does both forward and backward actions just by giving different signals

comment if you need any more help

author
AKhateeb (author)g1naveen2016-11-18

Please I have the same issue.

my RC car has 4 DC Motors with 12v, I have tried to control motors with "L298 H-BRIDGE" but once I connect them and one motor run a little, the controller has broken down and it damage the raspberry too, thus I will not trust H-BRIDGE any more...

please do u have any other solution ... thanks a lot

author
iphoneturn (author)2016-07-20

Hey, I just did all of the wiring and programming stuff I can get the motor to run because I have a Raspberry Pi 3 and it have different gpio pinout than the model B so can you help me please?

author
Enomaly (author)iphoneturn2016-08-30

you would have to change the code at the beginning where its says "pin = (a pin)" at the beginning to match the pi 3. if you search google images you should be able to find a schematic of both GPIO pinouts online, and compare the model b pins mentioned in the code with the corresponding pins on the pi 3.

author
jmillma6 (author)2016-04-14

So I copied the code line for line and wired the breadboard exactly as in the diagram. I'm using a raspberry pi b with the correct cable, motor driver and two 9v DC motors. My power source connected to the breadboard is a 9v battery. I know the pi is getting the button signal from the keyboard because I inserted a few 'print' lines that display when you press a, s, d, or f. Unfortunately, the motors don't run at all. I know it has something to do with the pi sending a signal to the cobbler or with the breadboard, but I don't know which and I don't know how to fix it.

Also, when I run the script through command terminal, it works fine, but when I run it straight from python, it runs with 2 errors (see below). I don't understand why it doesn't work if I copied everything exactly. I can provide more info and/or pictures if necessary.

Traceback (most recent call last):

File "home/pi/Control4.py", line 93, in <module>

Char = getch()

File "home/pi/Control4.oy", line 28, in getch

Fd = sys.stdin.fileno()

Unsupported operation: fileno

author
evilelf121 (author)2016-03-17

Will this work with a raspberry pi 3?

author
VishaalD1 (author)2015-04-09

I have used some part of your code, specifically where you have defined the function getchar(). After that I implemented the infinite while loop but I'm getting an error:

File "/root/BITS_People/test.py", line 20, in <module>

char=getch()

File "/root/BITS_People/test.py", line 9, in getch

fd = sys.stdin.fileno()

AttributeError: fileno

Any ideas on how to fix it? Thanks in advance

author
TusharU (author)VishaalD12016-01-25

I had the same problem so I fixed it by downloading and installing the getch module for python

author
dont_care (author)2016-01-20

How can this be used with a 4WD RC car?

author
KennethL (author)2015-01-22

I connected everything now I am stuck!! I've tried to program it but I keep getting errors and i do not know how to fix them. can anyone help me with the programming, i need it asap!!

author
Scruffybiggems (author)2014-02-23

Your problem is the programs reading the crap at the top how to fix this is open up the file u get the error in in python at the top there like the time and date u want to delete that stuff so that the code starts with import RPi.GPIO as io

io.setmode(io.BCM)
import sys, tty, termios, time

if you have more troubles message me i can help

also heres my code its based off this one so it will work with this set up

http://pastebin.com/b0sKWEpu

author

Hey awesome project just what I was looking for. unfortunately its not working for me... I have raspi B+ and when I run your code I get this error.

errormsg.PNG
author

It will not work with the b+ sorry

author

ah poo thanks anyway...

author
jfelipeara (author)2014-09-22

what means the parameters in the PWM() function?

author
ahachenberg made it! (author)2014-07-06

Thanks for the write-up on this. I'm just getting started with my Raspberry Pi and this was exactly what I was looking for in a first project. I'm having trouble with the setup. When I press W or S for forward or reverse motion the action does not stop when I release the key press. So, if I press the W key the car begins forward motion and will not stop. If I press the S key the car goes in reverse and will not stop until I end the script or hit the W key to change direction. Steering behaves the same way. Thanks for any help. If I find the answer I'll post it here.

2014-07-04.jpg
author

I believe its because the driver your using is it the L293D?? this code will only work with that driver chip, also i have modded the code to work better and fix a few things you can check it out here : http://pastebin.com/m2pBWtKM

author
perrycannon (author)2014-05-19

Will this code work with the below components? I bought a kit on ebay. I would like to control the movement with a keyboard.

1 x Quality Feetech Servo

1 x L298N Motor Drive

1 x IWM Electronics Ultrasonic / Servo Breakout Board

1 X Adjustable Step Down Voltage Controller

One Battery Case Holding 6 x AA With PP3 Style Connector to allow easy removal of battery pack without disturbing wiring use 6 X AA Rechargeable (7.2vdc)

1 x PP3 Connectors

One HC-SR04 dIstance sensor

this is the code that i am using

import RPi.GPIO as GPIO

from time import sleep

from time import time

import os

GPIO.setmode(GPIO.BCM)

GPIO.setup(9,GPIO.OUT)

GPIO.setup(10,GPIO.OUT)

GPIO.setup(11,GPIO.OUT)

Motor1 = GPIO.PWM(11, 50)

Motor1.start(0)

Echo = 17

Steer = 4

def forward(speed):

GPIO.output(9,GPIO.HIGH)

GPIO.output(10,GPIO.LOW)

Motor1.ChangeDutyCycle(speed)

def backward(speed):

GPIO.output(9,GPIO.LOW)

GPIO.output(10,GPIO.HIGH)

Motor1.ChangeDutyCycle(speed)

def left(speed):

string = "echo 0=110 > /dev/servoblaster"

os.system(string)

sleep(1)

GPIO.output(9,GPIO.LOW)

GPIO.output(10,GPIO.HIGH)

Motor1.ChangeDutyCycle(speed)

def right(speed):

string = "echo 0=190 > /dev/servoblaster"

os.system(string)

sleep(1)

GPIO.output(9,GPIO.LOW)

GPIO.output(10,GPIO.HIGH)

Motor1.ChangeDutyCycle(speed)

def stop():

Motor1.ChangeDutyCycle(0)

def get_range():

GPIO.setup(Echo,GPIO.OUT)

GPIO.output(Echo, 0)

sleep(0.1)

GPIO.output(Echo,1)

sleep(0.00001)

GPIO.output(Echo,0)

GPIO.setup(Echo,GPIO.IN)

while GPIO.input(Echo) == 0:

pass

start = time()

while GPIO.input(Echo) == 1:

pass

stop = time()

elapsed = stop - start

distance = elapsed * 17000

return distance

while True:

distance = get_range()

if distance < 30:

print "Distance %.1f " % distance

stop()

string = "echo 0=110 > /dev/servoblaster"

os.system(string)

sleep(1)

disleft = get_range()

print "Left %.1f " % disleft

string = "echo 0=190 > /dev/servoblaster"

os.system(string)

sleep(1)

disright = get_range()

print "Right %.1f " % disright

if disleft < disright:

print "Turn right"

left(100)

sleep(2)

else:

print "Turn left"

right(100)

sleep(2)

os.system("echo 0=150 > /dev/servoblaster")

else:

forward(80)

print "Distance %.1f " % distance

sleep(0.5)

GPIO.cleanup()

author
perrycannon (author)2014-05-19

Will this code work with the below parts. This is a kit that I bought on ebay. I want to control the car with a keyboard. Thank you.

1 x Quality Feetech Servo

1 x L298N Motor Drive

1 x IWM Electronics Ultrasonic / Servo Breakout Board

1 X Adjustable Step Down Voltage Controller

One Battery Case Holding 6 x AA With PP3 Style Connector to allow easy removal of battery pack without disturbing wiring use 6 X AA Rechargeable (7.2vdc)

1 x PP3 Connectors

One HC-SR04 dIstance sensor

author
NahuelMata (author)2014-05-05

And what would i need the prototyping plate for? sorry if it is too obvious im new to the raspberry pi community

author
NahuelMata (author)2014-05-05

HIgh i had a doubt how is that the keyboard connects to the raspberry pi? wouldnt i need a bluetooth receiver conncted to the raspberry pi. Im doing a bridge for a scince fair combining hydraulics and robotics but i dont know how you did to connect the keybord.

author
julianp3000 (author)2014-01-13

If the Raspberry Pi and DC motors are powered by separate supplies, will the L239D wiring change? Do you still connect pin 16 on the L293D chip to the 5V on the Pi?

author

no its says the same u can use 6volts like hes has done and it will work fine

About This Instructable

119,546views

84favorites

License:

More by ChrisMason:Controlling a Raspberry Pi RC Car With a Keyboard
Add instructable to: