PWM for LEDs and motors with a Raspberry Pi
I've written about how to drive small DC motors with an Arduino, in order to drive a little toy truck around. But an Arduino, while great at talking to hardware, isn't very powerful. It's easy to add simple sensors to the truck so it can stop before hitting the wall; but if I wanted to do anything complicated -- like, say, image processing with a camera -- the Arduino really isn't enough.
Enter Raspberry Pi. It isn't a super-fast processor either, but it's fast enough to run Linux, Python, and image processing packages like SimpleCV. A Raspberry-Pi driven truck would be a lot more powerful: in theory, I could make a little Mars Rover to drive around my backyard. If, that is, I could get the RPi driving the car's motors.
Raspberry Pi, sadly, has a lot of limitations as a robotics platform. It's picky about input voltages and power; it has no analog inputs, and only one serial port (which you probably want to use for a console if you're going to debug your robot reliably). But my biggest concern was that it has only one pulse-width modulation (PWM) output, while I needed two of them to control the car's two motors. It's theoretically possible to do software PWM on any pin -- but until recently, there were no libraries supporting that.
Until recently. I've been busy for the last month or two and haven't been doing much RPi experimenting. As I got back into it this week, I discovered something delightful: in the widely available python library RPi.GPIO, Software PWM is available starting with 0.5.2a.
Getting the right RPi.GPIO
Just what I'd been wanting! So I got an LED and resistor and plugged them into a breadboard. I ran a black wire from the RPi's pin 6, ground, to the short LED pin, and connected the long pin via the resistor to the RPi's pin 18 (GPIO 24) (see the RPi Low-level peripherals for the official GPIO pin diagrams).
With the LED wired up, I
plugged
in my serial cable, powered up the RPi with its Raspbian SD card,
and connected to it with screen /dev/ttyUSB0 115200
.
I configured the network to work on my local net and typed
sudo apt-get install python-rpi.gpio
to get the latest version. It got 0.5.2a-1. Hooray!
I hurried to do a test:
pi@raspberrypi:~$ sudo python Python 2.7.3 (default, Jan 13 2013, 11:20:46) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> >>> import RPi.GPIO as GPIO >>> GPIO.setmode(GPIO.BCM) >>> GPIO.setup(24, GPIO.OUT) >>> led = GPIO.PWM(24, 100) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'PWM'
Whoops! But Raspbian said it was the right version ...
I checked again with aptitude show python-rpi.gpio
--
yep, 0.5.2a-1. Hmph!
After some poking around, I discovered that help(GPIO), after printing out an interminable list of exception classes, eventually gets to this:
VERSION = '0.5.1a'
In other words, Rapsbian is fibbing: that package that Raspbian says is version 0.5.2a-1 is actually version 0.5.1a. (This is the sort of thing that makes Raspberry Pi such a joy to work with. Yes, that's sarcasm.)
Okay. Let's try removing that bogus Raspbian package and getting it from pypi instead:
apt-get remove python-rpi.gpio pip install --upgrade RPi.GPIO
Then I tried the same test as before. Success! And now I was able to set the LED to half brightness:
led.start(50)
I was able to brighten and dim the LED at will:
led.ChangeDutyCycle(90) led.ChangeDutyCycle(25)
I played with it a little while longer, then cleaned up:
led.stop() GPIO.cleanup()
If you're experimenting with RPi.GPIO's PWM, you'll want to check out this useful 2-part tutorial:
- RPi.GPIO 0.5.2a now has software PWM – How to use it
- How to use soft PWM in RPi.GPIO 0.5.2a pt 2 – led dimming and motor speed control
What about motors?
So PWM works great for LEDs. But would it drive my little robotic car?
I unplugged my LED and wired up one of the SN754410 motor drivers circuits I'd wired up for the Arduino. And it worked just as well! I was able to control the motor speed using ChangeDutyCycle().
I'll write that up separately, but I do have one caveat:
GPIO.cleanup()
, for some reason, sets the pin output to HIGH.
So if you have your car plugged in and sitting on the ground when you
run cleanup(), it will take off at full speed.
I recommend testing with the car on a stand and the wheels off the ground.
Update: the motor post is up now, at Driving two DC motors with a Raspberry Pi.
[ 21:00 May 04, 2013 More hardware | permalink to this entry | ]