Shallow Thoughts : : May
Akkana's Musings on Open Source Computing and Technology, Science, and Nature.
Thu, 30 May 2013
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.
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.
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: arduino, hardware, robots, maker
[
19:40 May 30, 2013
More hardware |
permalink to this entry |
]
Tue, 28 May 2013
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.
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: web, programming, python
[
12:42 May 28, 2013
More tech/web |
permalink to this entry |
]
Sat, 25 May 2013
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: embedded, raspberry pi, hardware, programming, python, maker
[
19:47 May 25, 2013
More hardware |
permalink to this entry |
]
Wed, 22 May 2013
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:
-
The "scratches" on my crystal -- so bad I'd been thinking it was time
to buy a new watch -- were actually melamine (or some such material)
that had rubbed off from the artists' table I use as a desk.
It cleaned off nicely with alcohol.
- I used a needle to open the spring clip over the battery.
-
Rotating the back cover 180° was probably what fixed the beeper.
-
You may or may not need to reset the watch by shorting the two contacts
as suggested on the label inside the watch. If you see an error code
or the watch doesn't work right, try shorting the contacts.
Tags: hardware, maker
[
15:56 May 22, 2013
More hardware |
permalink to this entry |
]
Sat, 18 May 2013
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.
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.
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.
Tags: hardware, raspberry pi, robots, maker
[
17:50 May 18, 2013
More hardware |
permalink to this entry |
]
Wed, 15 May 2013
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: linux, debian, ubuntu, python, programming
[
16:07 May 15, 2013
More linux |
permalink to this entry |
]
Sun, 12 May 2013
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.
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.
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: hardware, raspberry pi, robots, maker
[
14:08 May 12, 2013
More hardware |
permalink to this entry |
]
Wed, 08 May 2013
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: astronomy, science
[
11:46 May 08, 2013
More science/astro |
permalink to this entry |
]
Sat, 04 May 2013
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:
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: raspberry pi, hardware, electronics, robots, maker
[
21:00 May 04, 2013
More hardware |
permalink to this entry |
]