Shallow Thoughts : : hardware
Akkana's Musings on Open Source Computing, 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
[
18:40 May 30, 2013
More hardware |
permalink to this entry |
comments
]
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.
Tags: embedded, raspberry pi, hardware, programming, python
[
18:47 May 25, 2013
More hardware |
permalink to this entry |
comments
]
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
[
14:56 May 22, 2013
More hardware |
permalink to this entry |
comments
]
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
[
16:50 May 18, 2013
More hardware |
permalink to this entry |
comments
]
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
[
13:08 May 12, 2013
More hardware |
permalink to this entry |
comments
]
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
[
20:00 May 04, 2013
More hardware |
permalink to this entry |
comments
]
Sun, 17 Feb 2013
I've done a few experiments with
playing
music on an Arduino over the years -- the Arduino library has a
tone() call that gives you a nice tinny monophonic
"chiptunes" style noise. But for playing anything more complex,
you need more processing power.
I had a silly little project in mind. I like some pink noise when I'm
sleeping (in summer, I usually have a fan running). You can buy
electronic devices called "sleep soothers" that have tracks of the
ocean, rain, trains etc. but they often have annoying misfeatures
(like foghorns or train whistles in the middle of a track). Wouldn't
it be more fun to make my own, with sound samples of my choice?
Pink noise samples
Of course, I needed some sound samples, and
I found a great resource: Laptop.org's list of
Free sound samples.
I downloaded a few sample collections that looked like they might have
some nice ambient pink-noise sounds -- rain, ocean and so forth.
Some of the samples were usable right away.
But others are only available at 44.1k, and the
Adafruit Wave Shield, the hardware I was targeting first, will only play
WAV audio at 16k. So they needed to be converted.
A simple shell loop did that:
for fil in *.wav ; do
avconv -i $fil -ar 16000 ../samples16/$fil
echo $fil
done
Arduino hardware
There are several Arduino shields for playing sound files.
The simplest (and probably cheapest) is the
Adafruit Wave Shield,
and that's what I started with. It comes as a kit that you solder
together (an easy soldering project) and it has its own volume control
and SD card reader. On the down side, it can only play .WAV files, not
other formats like .MP3 or .OGG. But for my sleep soother project that
was okay.
Getting basic sounds playing was easy, following Adafruit's tutorial
and sample code. But for my project, I also needed some external
buttons, to allow for jumping from one track to the next. I was a
little confused about which pins are used by the shield, and I ended
up wiring my button to one of the pins that the shield uses for
talking to the SD card reader. Things didn't work at all. And then
while I was fumbling with plugging/unplugging things, at some point
I installed the shield onto the Arduino wrong, with the pins off by one.
I'm not sure whether it was the miswired button or the off-by-one shield,
but something got fried in the wave shield and it was never able to
read an SD card again after that (yes, even after plugging it in properly).
I thought about ordering another Wave Shield. But I was leery -- if
it's so delicate that a stray 5v signal in the wrong place can fry it
permanently, how long did I expect a second one to last? Besides, I was
tired of soldering things, and I happened to be putting in an Amazon
order for some other things. So I ran a search and found that there was
an MP3 player shield available through them, made by Seeed Studio.
It even had buttons built in, so I wouldn't need any extra hardware.
It was a little more expensive than the Wave shield, but it claimed to
play MP3 and OGG as well as WAV, and it comes pre-assembled, no
soldering needed.
The hardware arrived and looked nice. Two simple buttons plus a
"multifunction" button you can press or rock left or right. I grabbed
a micro SD card, put some MP3s on it, and went to
Seeed's page
on the Music Shield.
Hacking the Seeed library
I was a little worried when I discovered that they have three
different demos there -- each of which comes with a different library,
and you have to remove one set of libraries before you can try a
different demo. Not a good sign.
And indeed, it wasn't. None of the demos worked at all. When I added
some debug Serial.printlns, I found that it wasn't opening
the SD card.
Much web searching found a couple of people saying they'd discovered that
the Seeed shield only works with 2G or smaller microSD cards. Good luck
finding one of those! The next day, I drove all over town looking for
one, without success, and was on the verge of giving up when Dave remembered a
little cheapie camera he'd bought a few years ago for taking airplane
movies. It came with a microSD card. Success! It was a 2G card.
Back to trying the various demos and their incompatible libraries again.
And this time, one of the demos, the first one (the one that comes with
the Music v1 14.zip library), worked. I could play tracks,
sequentially as they were loaded on the SD card.
Unfortunately, that wasn't what I wanted to do -- I wanted to play the
same track over and over, jumping to the next track when the user
presses a button. I tried the other demos. None of them worked at all.
Long story short, after struggling for the better part of a week and
reverse-engineering a fair amount of the Music v1 14 library, I finally
got my sketch working.
Sharing the changes
I come from the open-source world. I keep my
Arduino sketches on GitHub
(at least once they work well enough to be useful to anybody).
So of course I wanted to share the work I'd put into fixing this
library.
I had it all laid out and ready to commit, and was working on
some documentation on how to use it, when I noticed the readme.txt
in the library directory. It begins:
Copyright (c) 2010 Seedstudio. All right reserved.
Pffft! So after finally getting things working, I can't share my working
version of the library! What are they thinking? What on earth is the
point of distributing a library for your hardware, one that you know
doesn't work very well (or you wouldn't be distributing four different
incompatible versions of it), and then not letting anyone fix it for you?
I posted a query in one of the many
threads
discussing problems with the Music Shield, asking if Seeed would
consider releasing the library under a license that allowed redistribution.
It's been a few weeks now, and no answer yet.
Incidentally, even posting the query wasn't easy. Seeed doesn't let
you post in their forums unless you register -- and the registration
process requires full name, address, and phone number! Fortunately,
they have no way of knowing whether the info you give them is fake,
so that's what I did.
Since I don't have permission to share the code directly, I've checked
in a patch that updates their library so it can play arbitrary tracks,
not just sequential ones, and can re-play the same track. It's here:
Music Shield
library on GitHub, along with my sample app, called play-repeat.
Conclusions
So my app is working now. Well, mostly; sometimes the volume randomly
jumps in the middle of the night, which I think is a hardware glitch,
but since it only happens after several hours of play, it's hard to debug.
But if you're looking for an Arduino sound project, I can't recommend
either the Wave Shield or the Seeed Music Shield. The Wave Shield
seems too fragile and its formats are limited, though the
tutorials and support are great.
And I'll certainly never buy anything from Seeed again.
If I had it to do over again, I'd spend the big bucks and buy
the Sparkfun
MP3 Player Shield. It's more expensive ($40) and doesn't have nice
buttons like the Seeed shield, but it plays all the formats the Seeed
shield does, and they offer tons of documentation and examples,
including an open-source library and code contributed by users.
Tags: arduino, hardware, music
[
11:37 Feb 17, 2013
More hardware |
permalink to this entry |
comments
]
Sun, 06 Jan 2013
For a recent Raspberry Pi project, I decided to use the
Adafruit Pi Cobbler
to give me easy access to the RPi's GPIO pins.
My Cobbler arrived shortly before I had to leave for a short trip.
I was planning to take my RPi with me -- but not my soldering iron.
So the night before I left,
I hastily soldered together the Cobbler along with a few other parts I
wanted to play with. No problem -- it's an easy solder project, lots of
pins but no delicate parts or complicated circuitry.
Later, far from home, I opened up my hardware hack box, set up a breadboard and
started plugging in wires, following one of the tutorials mentioned below.
Except -- wait, the pins didn't seem to be in the place I expected them.
I quickly realized I'd soldered the ribbon cable connector on backward.
Argh!
There's no way I could unsolder 26 pins all at once, even at home;
but away from home, without even a soldering iron, how could I possibly
recover?
(image courtesy of
PANAMATIK
of Wikipedia)
The ribbon cable connector is basically symmetrical, two rows of 13 pins.
The connector on the cable is keyed -- it has a dingus sticking out of
it that's supposed to fit into the slot in the connector's plastic box.
If I could, say, cut another slot on the opposite side of the plastic
box, something big enough for the ribbon cable's sticky-out dingus
(sorry for the highly technical language!),
I could salvage this project and play with my RPi.
I was just about to dig in with the diagonal cutter when someone on IRC
suggested that I try to slide the plastic box (it turns out this is
called a "box header") up off the pins, turn it around and slide it back
on. They suggested that using a heat gun to soften the plastic might help.
I didn't have a heat gun where I was staying, but I did have a hairdryer.
I slipped a jeweler's screwdriver under the bottom of one side of the box,
levered against the circuit board to apply pressure upward, and hit it
with the hairdryer. It slid a few millimeters immediately.
I switched to the other side of the box and
repeated; that side obligingly slid too. About ten minutes of
alternating sides and occasional blasts from the hairdryer, and
the box was off! Sliding it back on was even easier. Project rescued!
(Incidentally, you may be thinking that the Cobbler is really just a
way to connect the Pi's header pins to a breadboard. I could have used
the backwards-soldered Cobbler and just kept track of which pins should
map to which other pins. True!
But all the pin numbers would have been mislabeled, and I know myself
well enough to know that eventually, I would have gotten the pin mapping
wrong and plugged something in to the wrong place. Having
destroyed an Adafruit Wave Shield earlier that day by doing just that,
connecting 5V to an I/O pin that it turned out wasn't expecting it
(who knew the SD reader chip was so sensitive?),
I didn't want to take the same risk with my only Raspberry Pi.)
Tags: hardware, raspberry pi, ribbon cable, box header
[
15:29 Jan 06, 2013
More hardware |
permalink to this entry |
comments
]