PWM for LEDs and motors with a Raspberry Pi (Shallow Thoughts)

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Sat, 04 May 2013

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.

[Raspberry Pi set up for motor control] 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:

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.


Tags: , , , ,
[ 21:00 May 04, 2013    More hardware | permalink to this entry | ]

Comments via Disqus:

blog comments powered by Disqus