Shallow Thoughts : : May

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

Thu, 30 May 2013

GetSET Robotics workshop -- now, with cheap motor shields

Last summer I led a one day robotics workshop for high school girls as part of the Society of Women Engineers' GetSET summer camp. I'm giving it again this year, on June 26. We're still lining up volunteers to help teach the workshop, and I'd love help from bay area women -- you don't have to be a robotics or programming expert, just willing to learn and play.

The workshop is based around the Arduino open-source microcontroller: we hook up Arduinos, then wire up LEDs, buzzers and other parts on breadboards and make them do things.

It's a programming workshop as well as a hardware one: most of the girls had a workshop the previous summer on Ruby programming, but that's their only exposure to programming. So it's a challenge to see how much we can cover in one day -- and a testament to the girls that they do so well.

Last year we spent the morning covering wiring Arduinos to the basics like breadboards, LEDs, pushbuttons and potentiometers. Then in the afternoon, teams worked on projects -- some of them wired together lots of colored LEDs, some worked with making sounds with buzzers, and one team built a robotic truck. I was hoping to be able to show them more motorized projects, and I'd brought several toy cars and trucks scavenged from thrift shops (radio controlled toys that had lost their radio controller).

But the wiring needed for the H-bridge to control the motor is complex, and the team that chose the truck project had their hands full getting the truck running by the end of the day -- forget about adding any bells and whistles. I wanted to make that easier. [Homemade, super cheap Arduino motor shield]

So for this year, with a little more time to prepare, I'm wiring up some Arduino motor shields.

Shields are devices that stack on top of an Arduino. You can do all the difficult wiring beforehand, and just plug in the shield when you're ready to use it. The down side is that shields can be expensive -- motor shields typically cost around $25. That's okay if you're buying one, but if you're trying to outfit a classroom, that can add up pretty quickly.

But I found a way of building motor shields cheaply. The H-bridge chip I'm using, the SN754410, is $1.75 at Jameco if you buy 5 or more. Jameco also carries a proto-shield PC board ($4.25 in quantity) and stacking headers ($1.59). So that's only $7.59 per shield, plus shipping, not counting a few sundries like battery connectors that I'd already bought for last year's class.

Then I had to wire up the shields. I was all fired up about having a good excuse to use wire-wrap instead of soldering. But then I realized that tiny 30-gauge wire-wrap wire probably wasn't adequate for the current going to the motors. So I soldered wires for the motors, the power lines from the battery connector to the H-bridge chip, and from the battery connector to the Arduino's Vin. Then I wire-wrapped everything else. [Car sporting super cheap Arduino motor shield]

The end result looks nice and clean from the top (please avert your eyes from my messy soldering underneath). There's no scary rats-nest of wires, like with the breadboards I used last year, and there's plenty of empty space on the board to velcro a battery or attach sensors like an ultrasonic rangefinder. I think this will work well and will encourage the girls to get some little cars zipping around the computer room.

I'm looking forward to setting up some simple projects I can combine with the cars -- light sensors, sonar or IR rangefinders, other ideas? I'd love suggestions from anybody, and I'd especially love to line up some volunteers (women only for the day of the workshop, please). Workshop day -- June 26 -- mostly means walking around checking on how the girls are doing, cheering them on, helping them debug problems by checking their wiring and looking over their programs (very simple code -- remember, they've never seen C code before).

And if anybody (male or female) wants to get together before the workshop and play with Arduinos, help me solder the rest of the shields, and brainstorm fun projects for the girls, please drop me a line!

The rough outline, handouts and wiring diagrams so far are at my Robots and Sensors Workshop page.

Tags: , , ,
[ 19:40 May 30, 2013    More hardware | permalink to this entry | comments ]

Tue, 28 May 2013

A quick URL shortener

For years I've used bookmarklets to shorten URLs. For instance, with is.gd, I set up a bookmark to javascript:document.location='http://is.gd/create.php?longurl='+encodeURIComponent(location.href);, give it a keyword like isgd, and then when I'm on a page I want to paste into Twitter (the only reason I need a URL shortener), I type Ctrl-L (to focus the URL bar) then isgd and hit return. Easy.

But with the latest rev of Firefox (I'm not sure if this started with version 20 or 21), sometimes javascript: links don't work. They just display the javascript source in the URLbar rather than executing it. Lacking a solution to the Firefox problem, I still needed a way of shortening URLs. So I looked into Python solutions.

It turns out there are a few URL shorteners with public web APIs. is.gd is one of them; shorturl.com is another. There are also APIs for bit.ly and goo.gl if you don't mind registering and getting an API key. Given that, it's pretty easy to write a Python script.

Which of course I did: shorturl.

[Python url shortening script] In the browser, I select the URL I want (e.g. by doubleclicking in the URLbar, or by right-clicking and choosing "Copy link location". That puts the URL in the X selection. Then I run the shorturl script, with no arguments. (I have it in my window manager's root menu.)

shorturl reads the X selection and shortens the URL (it tries is.gd first, then shorturl.com if is.gd doesn't work for some reason). Then it pops up a little window showing me both the short URL and the original long one, so I can be sure I shortened the right thing. (One thing I don't like about a lot of the URL services is that they don't tell you the original URL; I only find out later that I tweeted a link to something that wasn't at all the link I intended to share.)

It also copies the short URL into the X selection, so after verifying that the long URL was the one I wanted, I can go straight to my Twitter window (in my case, a Bitlbee tab in my IRC client) and middleclick to paste it.

After I've pasted the short link, I can dismiss the window by typing q. Don't type q too early -- since the python script owns the X selection, you won't be able to paste it anywhere once you've closed the window. (Unless you're running a selection-managing app like klipper.)

I just wish there were some way to use it for Twitter's own shortener, t.co. It's so frustrating that Twitter makes us all shorten URLs to fit in 140 characters just so they can shorten them again with their own service -- in the process removing any way for readers to see where the link will go. Sorry, folks -- nothing I can do about that. Complain to Twitter about why they won't let anyone use t.co directly.

Tags: , ,
[ 12:42 May 28, 2013    More tech/web | permalink to this entry | comments ]

Sat, 25 May 2013

Telling your Raspberry Pi that your terminal is bigger than 24 lines

When I'm working with an embedded Linux box -- a plug computer, or most recently with a Raspberry Pi -- I usually use GNU screen as my terminal program. screen /dev/ttyUSB0 115200 connects to the appropriate USB serial port at the appropriate speed, and then you can log in just as if you were using telnet or ssh.

With one exception: the window size. Typically everything is fine until you use an editor, like vim. Once you fire up an editor, it assumes your terminal window is only 24 lines high, regardless of its actual size. And even after you exit the editor, somehow your window will have been changed so that it scrolls at the 24th line, leaving the bottom of the window empty.

Tracking down why it happens took some hunting. Tthere are lots of different places the screen size can be set. Libraries like curses can ask the terminal its size (but apparently most programs don't). There's a size built into most terminfo entries (specified by the TERM environment variable) -- but it's not clear that gets used very much any more. There are environment variables LINES and COLUMNS, and a lot of programs read those; but they're often unset, and even if they are set, you can't trust them. And setting any of these didn't help -- I could change TERM and LINES and COLUMNS all I wanted, but as soon as I ran vim the terminal would revert to that scrolling-at-24-lines behavior.

In the end it turned out the important setting was the tty setting. You can get a summary of what the tty driver thinks its size is:

% stty size
32 80

But to set it, you use rows and columns rather than size. I discovered I could type stty rows 32 (or whatever my current terminal size was), and then I could run vim and it would stay at 32 rather than reverting to 24. So that was the important setting vim was following.

The basic problem was that screen, over a serial line, doesn't have a protocol for passing the terminal's size information, the way a remote login program like ssh, rsh or telnet does. So how could I get my terminal size set appropriately on login?

Auto-detecting terminal size

There's one program that will do it for you, which I remembered from the olden days of Unix, back before programs like telnet had this nice size-setting built in. It's called resize, and on Debian, it turned out to be part of the xterm package.

That's actually okay on my current Raspberry Pi, since I have X libraries installed in case I ever want to hook up a monitor. But in general, a little embedded Linux box shouldn't need X, so I wasn't very satisfied with this solution. I wanted something with no X dependencies. Could I do the same thing in Python?

How it works

Well, as I mentioned, there are ways of getting the size of the actual terminal window, by printing an escape sequence and parsing the result.

But finding the escape sequence was trickier than I expected. It isn't written about very much. I ended up running script and capturing the output that resize sent, which seemed a little crazy: '\e[7\e[r\e[999;999H\e[6n' (where \e means the escape character). Holy cow! What are all those 999s?

Apparently what's going on is that there isn't any sequence to ask xterm (or other terminal programs) "What's your size?" But there is a sequence to ask, "Where is the cursor on the screen right now?"

So what you do is send a sequence telling it to go to row 999 and column 999; and then another sequence asking "Where are you really?" Then read the answer: it's the window size.

(Note: if we ever get monitors big enough for 1000x1000 terminals, this will fail. I'm not too worried.)

Reading the answer

Okay, great, we've asked the terminal where it is, and it responds. How do we read the answer? That was actually the trickiest part.

First, you have to write to /dev/tty, not just stdout.

Second, you need the output to be available for your program to read, not just echo in the terminal for the user to see. Setting the tty to noncanonical mode does that.

Third, you can't just do a normal blocking read of stdin -- it'll never return. Instead, put stdin into non-blocking mode and use select() to see when there's something available to read.

And of course, you have to make sure you reset the terminal back to normal canonical line-buffered mode when you're done, whether or not your read succeeds.

Once you do all that, you can read the output, which will look something like "\e[32;80R". The two numbers, of course, are the lines and columns values you want; ignore the rest.

stty in python

Oh, yes, and one other thing: once you've read the terminal size, how do you set the stty size appropriately? You can't just run system('stty rows %d' % (rows) seems like it should work, but it doesn't, probably because it's using stdout instead of /dev/tty. But I did find one way to do it, the enigmatic:

fcntl.ioctl(fd, termios.TIOCSWINSZ,
            struct.pack("HHHH", rows, cols, 0, 0))

Here it all is in one script, which you can install on your Raspberry Pi (or other embedded Linux box) and run from .bash_profile:
termsize: set stty size to the size of the current terminal window.

Update, 2017: Turns out this doesn't quite work in Python 3, but I've updated the script, so use the code in the script rather than copying and pasting from this article. The explanation of the basic method hasn't changed.

Tags: , , , , ,
[ 19:47 May 25, 2013    More hardware | permalink to this entry | comments ]

Wed, 22 May 2013

Fixing the Indiglo and beeper on a Timex Expedition watch

[Timex Expedition Chrono Alarm Timer] For half a year now my Timex watch (yes, I'm one of those old fogeys who actually wears a watch) hasn't had a light. And it doesn't beep when I use the stopwatch. I don't care so much about the beep, but the light was handy.

I replaced the battery at some point, and apparently got something wrong when I put it back together. I've been meaning to go back in and figure out what I got wrong, but life intervened, so I've been putting up with it for way too long, until now.

I felt a bit better about having messed up when some web searching showed that many, many people have this exact same problem. Some of the web pages I found had succestions that got the beeper working again; but the light still didn't work.

Curiously, it worked fine with the watch disassembled: the watch's brains and battery are all in one self-contained module, and if you push the tiny button in the front, the light comes on. It's just that the big button in the front didn't push the tiny button on the watch module.

Maybe there was some tiny piece that went sproinging off to freedom the first time I opened the watch. No matter; if so, it's long gone now. But you know what? Several pieces of masking tape stacked up over the inner button worked fine -- and now my Indiglo light works again.

A few other tips for Timex fixers, some of which aren't obvious from the how-to sites:


Tags: ,
[ 15:56 May 22, 2013    More hardware | permalink to this entry | comments ]

Sat, 18 May 2013

Running Raspberry Pi off a battery

In my post about Controlling a toy car with a Raspberry Pi, I skipped over one important detail: the battery. How do you power the RPi while it's driving around the room?

Most RPi sites warn that you shouldn't use the Pi with a power supply drawing less than an amp. I suspect that's overstated, and it probably doesn't draw more than half of that most of the time; but add the draw of two motors and we're talking a fairly beefy battery, not a couple of AAs or a 9V.

Luckily, as an R/C plane pilot, I have a fridge full of small 2- and 3-cell lithium-polymer batteries (and a li-po charger to go with them). The problem is: the Pi is rather picky about its input voltage. It wants 5V and nothing else. A 2-cell li-po is 7.4V. So I needed some sort of voltage regulator.

[5V voltage regulator] It's easy enough to get a simple 5V voltage regulator (pictured at right) -- 30c at Jameco, not much more locally. But they're apparently fairly inefficient, and need a heat sink for high current loads. [5V step-down power converter] So I decided to blow the big bucks ($15) for a 5V step-down power converter (left) that claims to be 94% efficient with no need for a heat sink.

Unlike most of Adafruit's products, this one comes with no tutorials and no hints as to pinouts, but after a little searching, I determined that the pins worked the same way as the cheap voltage regulators. With the red logo facing you, the left pin (your left) is input power from the battery; middle is ground (connect this to the battery's ground which is shared with the Pi's ground); the right pin is the regulated 5V output, which goes to pin 2 on the Pi's GPIO connector.

I was able to run both the RPi and the motor drive circuit off the same 7.4 volt 2-cell li-po battery (which almost certainly wouldn't work with 4 AAs, though it might work with 8). A 500 mAh battery seems to be plenty to drive the RPi and the car, though I don't know how long the battery life will be. I'll probably be using 610 mAh batteries for most of my testing, since I have a collection of them for the aerial combat planes.

Here's a wiring diagram made with Fritzing showing how to hook up the battery to power a RPi. If you're driving motors, you can run a line from the battery's + terminal (the left pin of the voltage regulator) as your motor voltage source, and use the right pin as your 5V logic source for whatever motor controller chip you're using.
[Battery-powered Raspberry Pi]

Tags: , , ,
[ 17:50 May 18, 2013    More hardware | permalink to this entry | comments ]

Wed, 15 May 2013

Finding versions of installed packages in Debian/Ubuntu

Checking versions in Debian-based systems is a bit of a pain.

This happens to me a couple of times a month: for some reason I need to know what version of something I'm currently running -- often a library, like libgtk. aptitude show will tell you all about a package -- but only if you know its exact name. You can't do aptitude show libgtk or even aptitude show '*libgtk*' -- you have to know that the package name is libgtk2.0-0. Why is it libgtk2.0-0? I have no idea, and it makes no sense to me.

So I always have to do something like aptitude search libgtk | egrep '^i' to find out what packages I have installed that matches the name libgtk, find the package I want, then copy and paste that name after typing aptitude show.

But it turns out it's super easy in Python to query Debian packages using the Python apt package. In fact, this is all the code you need:

import sys
import apt

cache = apt.cache.Cache()

pat = sys.argv[1]

for pkgname in cache.keys():
    if pat in pkgname:
        pkg = cache[pkgname]
        instver = pkg.installed
        if instver:
            print pkg.name, instver.version
Then run aptver libgtk and you're all set.

In practice, I wanted nicer formatting, with columns that lined up, so the actual script is a little longer. I also added a -u flag to show uninstalled packages as well as installed ones. Amusingly, the code to format the columns took about twice as many lines as the code that does the actual work. There doesn't seem to be a standard way of formatting columns in Python, though there are lots of different implementations on the web. Now there's one more -- in my aptver on github.

Tags: , , , ,
[ 16:07 May 15, 2013    More linux | permalink to this entry | comments ]

Sun, 12 May 2013

Driving two DC motors with a Raspberry Pi

[Raspberry Pi robotic car]

In my previous article about pulse-width modulation on Raspberry Pi, I mentioned that the reason I wanted PWM on several pins at once was to drive several motors, for a robotic car.

But there's more to driving motors than just PWM. The GPIO output pins of a Pi don't have either enough current or enough voltage to drive a motor. So you need to use a separate power supply to drive the motors, and do some sort of switching -- at minimum, a transistor or relay for each motor.

There are lots of motor driver chips. For Arduinos, "motor shields", and such things are starting to become available for the Pi as well. But motor shields are expensive, usually more than the Pi costs itself. If you're trying to outfit a robotics class, or to help low-income students build robots, it's not a great solution.

When I struggled with this problem for the Arduino, the solution I eventually hit on was a SN754410 H-bridge chip. For under $2, you get bidirectional control of two DC motors. For each motor, you send input to the chip via a PWM line and two directional control lines.

[Snarl of wires driving a car with a Raspberry Pi] The only problem is the snarl of wiring. One PWM and two direction lines per motor is six wires, plus power for the chip's logic side, power for the motors, and ground, and the three pins for a serial cable, and you're talking a lot of wires to plug in. Although this is all easy in comcept, it's also easy to get a wire plugged in one spot over on the breadboard from where it ought to be, and then nothing works.

I spent too much time making tables of what should get plugged into where. I ended up with a table like this:
Pi connector pin GPIO (BCM) SN754410 pin
Pi 2 5V power Breadboard bottom V+ row
Pi 18 24 1 (motor 1 PWM)
Pi 15 22 1 (motor 0 PWM)
Pi 24 8 (SPI CE0) 4 (motor 1 direc 0)
Pi 26 7 (SPI CE1) 14 (motor 1 direc 1)
Pi 25 Gnd Breadboard both grounds
Pi 19 10 (MOS1) 3 (motor 0 direc 0)
Pi 21 9 (MOS0) 13 (motor 0 direc 1)
motor 0 5, 11
motor 1 6, 12
... though, as you'll see, some of those pin assignments ended up getting changed later.

One more thing: I found that I had to connect the chip's logic V+ (pin 2 on the SN754410) to the 5v pin on the RPi, not the 3.3V pin. The SN754410 is okay with 3.3V logic signals, but it seems to need a full 5V of power.

Programming it

The software control is a little trickier than it ought to be, too, because of the 2-wire control lines on each motor. With both lines high or both lines low, nothing moves. (Some motor driver chips distinguish between those two states: e.g. both low might be a brake, while both high lets the motor freewheel; but I haven't seen anything indicating the SN754410 makes any distinction.) Then set one line high, the other low, and the motor spins one way; reverse the lines, and the motor spins the other way. Assuming, of course, the PWM line is sending a signal.

Of course, you need RPI.GPIO version 0.5.2a or later to do any of this PWM control. Get it via pip install --upgrade RPi.GPIO -- the RPI.GPIO in Raspbian mis-reports its version and is really 0.5.1a.

Simple enough in concept. Okay, now try explaining that to beginning programmers. No, thanks! So I wrote a PiMotor class in Python that takes care of all those details. Initialize it with the pins you want to use, then use calls like set_speed(s) and stop(). It's on GitHub at pimotors.py.

I put the H-bridge chip on a breadboard, wired up all the lines to the Pi and a lithium-polymer airplane battery, and (after several hours of head-banging while I found all the errors in my wiring), sure enough, I could get the motors to spin.

But one thing I found while wiring was that I couldn't always use the GPIO lines I'd intended to use. The RPi has seemingly a lot of GPIO lines -- but nearly all of the GPIO lines have other purposes, except I haven't found any good explanation of what those uses are and how to know when they're in use. I found that quite frequently, I'd try a GPIO.setup(pin, GPIO.OUT) and get "This channel is already in use". Sometimes GPIO.cleanup() helped, and sometimes it didn't. None of this stuff has much documentation, and I haven't found any IRC channel or mailing list for discussing RPi GPIO. And of course, there's no relation between the pin number on the header and the GPIO pin number. So I spent a lot of time counting breadboard rows and correlating to a printout I'd made of the RPi's GPIO socket.

Putting the circuit on a proto-board

Once I got it working, I realized how much I didn't relish the thought of ever doing it again -- like whenever I needed to unplug the motors from the Pi and use it for something else.

Fortunately, at some point I'd bought an Adafruit Pi Plate, sort of the RPi equivalent of Adafruit's Arduino ProtoShield. I love protoshields. I have a bunch of them, and I use them for all sorts of Arduino projects, so I'd bought the Pi Plate thinking it might come in handy some day. It's not quite like a protoshield, because it's expensive and heavy, loaded up with lots of pointless screw terminals. But you don't have to solder the screw terminals on; just solder the headers and you have a protoshield for your RPi on which you can put a mini breadboard and build your motor circuit.

I do wish, though, that Adafruit or someone made a simple, basic proto board PCB with headers for the Pi. No screw terminals, no extra parts, just the PCB and headers, to make it easy and cheap to swap between different RPi projects. The HobbyTronics Slice of Pi looks intriguing, but the GPIO pins it exposes don't seem to be the same ones exposed on the RPI's GPIO header. I'd be interested in hearing from anyone who's tried one of these.

[Raspberry Pi motor circuitn] Anyway, with the Pi Plate shield, my motor circuit looks much neater, and I can unplug it from my RPi without fear that it'll mean another half hour if I ever want to get the motors hooked up again. I did have to change some of the pin assignments yet again, because the Pi Plate doesn't expose all the GPIO pins available on the RPi header. I ended up using 25, 23, 24 for the first motor, and 17, 21, 22 for the second.

I wanted to make a circuit diagram with Fritzing, but it turns out the Fritzing I have can't import part definitions like the one for Raspberry Pi, and the current Fritzing doesn't work on Debian Wheezy. So that'll have to wait. But here's a photo of my breadboarded circuit on the Pi Plate, and a link to my motor breadboarded circuit using a cable to the GPIO.

Kevin Mark tipped me off that Fritzing is quite easy to build under Debian, if you first apt-get install qt4-qmake libqt4-dev libboost1.49-dev
I had to add one more package to Kevin's list, libqt4-sql-sqlite, or I got a lot of QSQLITE driver not loaded and other errors on the terminal, and a dialog saying "Unable to find the following 114 parts" followed by another dialog too big to fit on the screen with a list of all the missing parts.
Once those packages are installed, download the Fritzing source tarball, qmake, make, and sudo make install.

And my little car can go forward, spin around in both directions, and then reverse! Now the trick will be to find some sensors I can use with the pins remaining ...

Tags: , , ,
[ 14:08 May 12, 2013    More hardware | permalink to this entry | comments ]

Wed, 08 May 2013

Gamymede whac-a-moon tonight

A couple of months ago I wrote about watching an eclipse of Europa by Jupiter's shadow. It's a game I call "Whac-a-Moon", where a moon comes out from behind Jupiter, but stays there for only a short time then disappears into eclipse. If you aren't ready for it, it's gone.

This can only happen when Jupiter's shadow is offset from Jupiter that there's a gap between the planet and the shadow as seen from Earth. Jupiter is getting low in the west, and soon we'll lose it behind the sun, but tonight, Wednesday May 8, there's a decent Ganymede Whac-a-Moon opportunity for those of us on the US west coast.

Ganymede disappears behind Jupiter at 6:45 pm PDT, still during daylight. Some time around 9:43 Ganymede reappears from behind Jupiter, but it only stays visible for a couple of minutes before entering Jupiter's eclipse. Don't trust these times I'm giving you: set up at least five minutes early, preferably more than that. And set up somewhere with a good western horizon, because Jupiter will be very low, less than 8 degrees above the horizon.

You can simulate the event on my Javascript Jupiter. When the G goes blue, that means Ganymede is in eclipse. But the simulation won't show you the interesting part: how gradual the eclipse is, as the moon slides through the edge of Jupiter's shadow. During the Europa eclipse a few months ago, I wanted to record the time of disappearance so I could adjust my code accordingly, but I found I couldn't pin it down at all -- Europa started dimming almost as soon as it emerged from behind Jupiter, and kept dimming until I couldn't convince myself I saw it any more.

So far, I've only watched Europa as it slid into eclipse by Jupiter's shadow; I haven't whacked Ganymede. But Ganymede is so much larger that I suspect the slow dimming effect will be even more obvious. Unfortunately, I'm not optimistic about being able to see it myself; we've had cloudy skies here for the last few nights, and that combined with the low western horizon may do me in. I may have to wait until autumn, when Jupiter will next be visible in our evening skies. But I hope someone reading this gets a chance to see this month's eclipse.

Tags: ,
[ 11:46 May 08, 2013    More science/astro | permalink to this entry | comments ]

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 ]