Those old coin-op photobooths are awesome. Sit down, close the drape, put some money in the coin slot, and in a few minutes you will have some memories in your pocket. Why can't I have one of those? Oh yea, because they take up a lot of room, use stinky chemicals, and I have no idea how to build one. Fortunately, I have some computer skills.
The Mission
if
Yea, that's a big if. If I had it my way, I'd make an art installation piece that was a digital photobooth with a built in webserver, so that after pictures were taken, one would connect to the photobooth over the internet and download pictures. Unfortunately, I don't have the room or the tools to make a photobooth, but I can get cracking on a much smaller, yet curiously similar project that focuses on the computer and software aspect of a digital photobooth.
The Computer
The computer for this project is a Rev 2 Raspberry Pi. See that little wood block that the computer is screwed to? Good. The Rev 1 Raspberry Pi didn't have any mounting holes and it made putting the device into a custom enclosure a real pain in the ass. The Rev 2 only has two mounting holes and a small block of wood was used for both holes.
I'm still waiting for a apology for the lack of mounting holes fiasco. Oh yea, this computer's name is 'shitbird' because I couldn't come up with another name
The Case
A few years back, my buddy gave me two almost fancy Wild Turkey boxes. One box was used for my media machine, the other was used for this project.
A bit of hot glue affixed the wood blocks to the inside of the case.
Notches were cut in the sides of the box to handle cabling.
This case is far too big for this project, but I really wanted to make it and this is what I had kicking around .... so tough!
Big Red Switch
This switch is identical to the emergency 'play Black Sabbath' button, and it is mounted on my wall near the heater and some sweet rotary phones. For input, the switch is connected to the Raspberry Pi on GPIO pins 5 and 6.
The Camera
In a few days time, a 5 megapixel camera will be arriving at my home, but for now I'm using this less than ideal 640x480 logitec webcam that has been placed on a shelf next to some sweet rotary phones.
To be honest, everything in my home is "near" a sweet rotary phone (or two).
Nesting in the corner
Oh hey, is that a Raspberry Pi on your wall? Yes, yes it is.
If my home were a Federation Star Ship, that corner would be the Engineering Department. beep boop.
Aside from a bunch of sweet rotary phones, there is lantern that can be controlled over the network, and there is a toaster with a postcard on it. RAD!
Code
So it is built and all in place. What does it do?
The computer is running Arch Linux and the software for this project is written in the Ruby programming language without any third party libraries. However, in order to take a picture, the code makes a system call to fswebcam which is easily installable from the Arch Linux software repositories.
Pressing the big red button takes a pictures and saves the picture in a local directory. The code also contains a basic webserver that makes accessing the saved images a snap. Included in the webserver is a simple way to make the computer take a picture. This can be accomplished by directing a web browser to http://NAME_OF_COMPUTER:8080/capture
Enter the Ruby
require 'webrick'
require 'thread'
require 'observer'
#we might be testing
@@TESTING = ARGV[0].nil? ? false : true
##define some variables
this_dir = File.dirname(__FILE__)
@@public_dir = File::join(this_dir,"public")
@@captures_dir = File::join(@@public_dir, "captures")
class Switch
include Observable #instances will be watched!
def initialize()
#init the switch GPIO
@io = 3 #this is pin 7 on a Rev 2 Raspberry Pi
@value_file = "/sys/class/gpio/gpio#{@io}/value"
@value
#clean up first
unless @@TESTING
clean_up()
File.open("/sys/class/gpio/export","w") do |f|
f.puts(@io)
end
#set direction to in
File.open("/sys/class/gpio/gpio#{@io}/direction", "w") do |f|
f.puts("in")
end
#record the initial value
@value = get_value()
end
end
def get_value()
unless @@TESTING
value = File.read("/sys/class/gpio/gpio#{@io}/value").chomp()
end
end
def run()
puts "running switch"
running = true
thread = Thread.new() do
while running
#poll the value
value = get_value()
if value != @value
@value = value
#emit the value
changed
notify_observers(self, @value)
end
sleep 0.1
end
end
end
def clean_up()
unless @@TESTING
File.open("/sys/class/gpio/unexport","w") do |f|
f.puts(@io)
end
end
end
end
class PictureTaker
def initialize()
p 'creating picture taker'
end
def switch_changed(switch, value)
if value == "1"
puts "value: #{value}"
take_picture
end
end
def server_wants_capture(server, value)
if value
take_picture
end
end
def take_picture
now = Time.now.strftime("%Y%m%d%H%M%S")
puts now
new_file = File::join(@@captures_dir, now+".png")
cmd = "fswebcam -r 640x480 -S 3 -F 2 --no-banner --png 7 --save "+new_file
#run the command
start = Time.now
IO.popen(cmd) do |f|
output = f.gets
end
return (Time.now - start).to_s
end
end
if __FILE__ == $0
pt = PictureTaker.new
sw = Switch.new
sw.run
#watch for a switch press
sw.add_observer(pt, :switch_changed)
#make a webrick server
server = WEBrick::HTTPServer.new({:Port=>8080,:DocumentRoot=>@@public_dir})
#what server actions do we have?
server.mount_proc('/capture') do |req, resp|
resp['Content-Type'] = 'text/plain'
resp.body = pt.take_picture
end
running = true
trap "SIGINT" do
server.shutdown
end
server.start
sw.clean_up()
end
For easier copy and paste, the code is available at http://hoof.jezra.net/snip/ob
What's next?
Aside from waiting for the 5MP camera...
There are still plenty of unused GPIO pins on the computer and there is a lot of unused space in the computer case. It should be possible to find something else to do with the computer.
- upload captured images to somewhere on the internet
- have the motion detecting toaster tell the picture taker to take (and upload) pictures when motion is detected.
- Always skip step 3
- enjoy a bit of home security
Now quit reading, and go take a picture.
Solitude is my muse, and taking things apart keeps me from getting depressed. However, it is still nice to hear other people say nice things so I decided to convert a toaster into an interactive art project that says nice things when something (usually me) walks in front of it.
The Build
TAKE IT APART!
The first step to any great project seems to begin with a bit of destruction. Good. Nothing really clears my mind like taking something apart. Yea, I laughed when I bought the toaster and I'm still laughing now.
The toaster was soon gutted and a bunch of innards where chucked in the waste bin.
Make some mounting thingies
For this build, I planned on using the Raspberry Pi from the NaNoBox and since someone is a hobby hardware hacker hater, there are no mounting holes on my Raspberry Pi. sigh. Who's a liar? ME (sort of). I said I wouldn't use the Raspberry Pi for a similar project. Fortunately, this project isn't too similar.
A small wooden block was epoxied to the toast box (at least that is my name for it). Similarly, a piece of thick plastic from VHS case was also epoxied to the toast box.
Circuit from the shell
Surrounding the toast box is the toaster shell, and this is the circuit board that was mounted inside of the toaster shell. On the circuit are 3 buttons and two LEDs.
After a bit of scratching at the circuit board and some soldering, the buttons and LEDs where ready to be wired up.
The circuit back in the shell
Oh man, look at that rat's nest of wires.
This is the inside of the shell with most of the wiring finished. This includes the PIR thingy. What's a PIR thingy you might ask? good question.
PIR Thingy
Hey look, kids, it's a PIR thingy! This Passive InfraRed sensor thingy was purchased at https://www.adafruit.com/products/189 for 10 bucks.
A notch was cut in the toaster's lever channel and the PIR was hot glued into place. Damn, I love adhesives.
Sound!
My buddy gave me a small USB amplifier and speaker combo used for plugging into a mobile phone.
In my haste, I obliterated the amplifier before taking a pictures. What a shame. The wires on the amp were to frail for my needs so I soldered on some heavier wires for audio in, audio out, and the power connector. Since the amp was originally powered over USB I figured I could wire it to the 5v pin on the Raspberry Pi. The speaker is from another portable amplifier.
Buckle up
Like I've said may times, the designer of the Raspberry Pi hates me and didn't include mounting holes on the board. Because of this, I needed to find a creative way to keep the board in place and my solution was a nice little 'belt'.
To keep the number of cable going to the toaster to a minimum, an old USB 802.11g was connected to the board.
Add some more LEDs
Aside from the two bright blue LEDs on the toaster shell, I added a green LED to each slot of the toaster box.
All Together
With much finagling, the toaster box and the copious amount of wires was stuffed into the toaster shell and the end result was put on a desk and pointed at the busiest foot traffic area of my home.
The toaster lever, although no longer in use, was hot glued back where it belongs and helps hide the PIR sensor.
What does it do?
When the sensor detects movement, an audio file is selected at random from a directory of audio files, and played through the speaker. While the audio is playing, the LEDs are flashing.
some of the setup
The code for running the toaster is written in python and utilizes gstreamer-0.10 for audio playing. In order to get gstreamer to default to playing through the 'audio out' on the Raspberry Pi, I had to edit the /etc/asound.conf file to look like the following:
pcm.mmap0 { type mmap_emul; slave { pcm "hw:0,0"; } } pcm.!default { type plug; slave { pcm mmap0; } }
Switches
Due to the lack of GPIO documentation for the Raspberry Pi, most tutorials for the device involved wiring in "pull-up" resistor which means that extra work is involved just to get a simple button press to register. However, pins 3,5,7,24, and 26 have built in pull up resistors which makes these pins ideal for connection switches.
Most (if not all) of the information I needed for programming the pins on the Raspberry Pi came from http://www.panu.it/raspberry/ and not from the Raspberry Pi website. Seriously, this is wrong. The RPi website should have some useful information, but alas, it does not.
What's next?
The power for the amplifier was specifically not taken from the one remaining USB port. It would be fairly trivial to plug a USB camera into the USB and, when the PIR detects motion, have the camera take a picture and then upload the picture to a back up server. Hella cheap home security system. booyah!
Also, I need to figure out what to do the the buttons.
if your browser doesn't play ogg files, you should switch browsers
Why? Because if your browser doesn't play ogg:
- your browser hates freedom
- you won't be able to hear
duh!
The System
Like almost all of my computers, the toaster is running Arch Linux
Now quit reading and go make something...
"Talky's the name, toasting's the game."
For those that don't know, November is when NaNoWriMo (National Novel Writing Month) takes place and there is a poster on the wall of my work that tracks the progress of my coworker's word count. However, since I work from home quite a bit, the poster in the office doesn't do me much good.... time to create a device that allows me to track people's progress.
Hello NaNoBox!
The basic idea of of the NaNoBox is to use a mini computer to access the NaNoWriMo wordcount API and do the following:
- Every hour, get the current word count of a small list of NaNoWriMo participants
- Loop through the list of participants and:
- illuminate something that represents a NaNoWriMo participant
- show the progress of the represented participant as a percentage on an analog meter
The Hardware
Earlier this month I acquired a Raspberry Pi from http://www.adafruit.com, and I felt that the device would be ideal for this project.... I was wrong.
While I still used the Raspberry Pi for my project, I will never purchase another one, nor will I ever use the Raspberry Pi for another similar project.
Why I don't like the Pi
- There are no mounting holes. When I make a custom enclosure for a computer, I like to mount the motherboard on standoffs, and I can't do this with the Raspberry Pi. lame
- Handling PWM is not as simple as just writing to a file, and I needed to compile a 3rd party application to help me with PWM. I was spoiled by the Beaglebone
- The is little to no documentation for the Raspberry Pi at http://www.raspberrypi.org/. Very lame
- Proprietary video drivers. Not a big deal for this project, but still less than ideal
Alright, that's enough complaining about the computer, let's get on with the build.
The Interface
At the suggestion of my friend who is a wood worker, I made a template of how I wanted the interface of the NaNoBox to look.
The Case
There is something about the scent of a nice cedar cigar box that tickles my brain.
This cigar box has been hanging out at my house for long enough. Time to chop it up.
Chop Chop
After laying out the design on the box, I used my poor selection of power tools to hack a bunch of holes in the cigar box.
The logo on the box was impossible to remove, but I sanded it down as best as I could.
Power
On the back of the box I drilled a hole for the power cable to go through.
Ewww, there is a sideburn hair in the picture
Stain
After much sanding, I stained the top of the box with the only stain I have (other than coffee), some red leather stain.
Diffused
On the inside of the box, I hot glued a piece of paper to diffuse light that shines upon it. What? you'll find out.
DVD Box
This is part of a DVD case. I like the way this plastic clip holds paper in the DVD case and I figure it would be a not too crappy way to hold the Raspberry Pi in place within the box.
Computer Mount
The DVD case clip was cut up and hot glued into the cigar box. See the black dots? LEDs will go there.
Like I said earlier, the lack of mounting holes is a serious downside of the Raspberry Pi (at least for the type of projects I like to do).
Put It On The Wall
Two screws and a bit of baling wire make for a great wall hanging bracket.
LEDs Wired Up
Here are the LEDs, soldered together and hot glued in place so that they shine through the square holes in the cigar box.
Voltmeter In Place
A 3.3V voltmeter was bolted into place, and an amber LED was hot glued over a small hole in the center of the box.
All Wired Up
The electronics are all done and ready to roll! I added a small 802.11n wireless USB adapter so that I wouldn't need another cable running to the computer.
Picture Holdy Thingies
Some thick paper was cut and folder in order to make holders for pictures that will be placed over the openings in the case.
Glued In Place
There it is! Two of the image holdy thingies were glued to the box for each of the images.
All Done
The pictures are in place and ready to light up.
The photographs are of my coworkers. The two other images represent podcasters that I listen too who happen to be participating in this years NaNoWriMo, and they are Thistleweb from Crivins and Moosical from The Bugcast.
Tim Kim
Hi Tim! Wow, I took a very unflattering picture of Tim for use in this project. Haha!
In Action
I dropped some test data into the code that runs the NaNoBox so that I could see the device in action before the event starts. When the participants get to 50,000 words, the amber LED in the middle of the box illuminates.
The Code
For this project, I decided to use Ruby because .... um... why not?
require 'open-uri'
require 'rexml/document'
class Pin
def initialize(num)
@gpio = num
#init this pin
`gpio -g mode #{@gpio} out`
end
def on()
`gpio -g write #{@gpio} 1`
end
def off()
`gpio -g write #{@gpio} 0`
end
end
class Nanobox
def initialize()
#keep it clean
clean_up()
#define the pins
@pins = [
Pin.new(4),
Pin.new(17),
Pin.new(23),
Pin.new(24),
Pin.new(25),
Pin.new(22),
Pin.new(21),
Pin.new(10),
]
#create the PWM on 18 (AKA pin 12)
`gpio -g mode 18 pwm`
end
def clean_up()
#unexport all of the assigned pins
`gpio unexportall`
end
def set_pwm_percent( num )
max = 1023
offset_percent = num*0.92
val = max*offset_percent/100
`gpio -g pwm 18 #{val}`
end
def read_config_file
this_dir = File.dirname(__FILE__)
config = File.join(this_dir, "users.conf")
@users = []
File.open(config) do |file|
file.each_line do |line|
if line.chomp != ""
user = {"name" => line.chomp}
@users << user
end
end
end
end
def update_wordcount_of_user(user)
begin
url = "http://nanowrimo.org/wordcount_api/wc/"+user['name']
xml_text = open(url).read
doc = REXML::Document.new xml_text
if doc.root.elements['error'].nil?
wc = doc.root.elements['user_wordcount'].text.to_i/500.to_i
else
wc = 0
end
rescue
#do nothing
end
if wc > 100
wc = 100
end
@users.each_with_index do |u, i|
if u['name'] == user['name']
user['wc'] = wc
@users[i] = user
break
end
end
end
def update_all_wordcounts()
@users.each do |user|
update_wordcount_of_user(user)
end
end
def run
#read the config
read_config_file()
#do the initial wordcount update
update_all_wordcounts()
@running = true
update_wc_count = 0
count = 0
sleep_time = 5 #seconds
update_wc_count_max = 3600/sleep_time
current_pin = nil
while @running
unless current_pin.nil?
current_pin.off()
end
current_pin = @pins[count]
current_pin.on()
count+=1
update_wc_count+=1
if count >= @pins.length or count >= @users.length
count = 0
end
if update_wc_count > update_wc_count_max
update_wc_count = 0
update_all_wordcounts()
end
value = @users[count]["wc"]
if value >= 100
@pins[7].on()
else
@pins[7].off()
end
set_pwm_percent(value)
sleep 5
end
quit
end
def stop
@running = false
end
def quit
set_pwm_percent(0)
#turn off all of the LEDS
@pins.each do |p|
p.off()
end
#do some cleanup
clean_up()
end
end
if __FILE__ == $0
nano = Nanobox.new
trap("INT"){ nano.stop }
nano.run()
end
Yup, that's some ugly, uncommented code. While parsing the XML that gets returned by the Word Count API, I realized that I don't like processing XML in Ruby, and then I had an epiphany: XML is very consistant, I dislike parsing it in any language. ZING!
Wait a second. Don't I have more coworkers? Why aren't they represented in this project? Yes, I do have more coworkers, but the cigar box has a very limited amount of space. Fortunately, I have enough components to make another NaNoWriMo status tracker. Time to get to the drawing board.
Now quit reading, and get ready to start procrastinating.
You probably are already aware of this, but the latest rev of the Raspberry Pi has mounting holes (just got mine today!).
Also, have you checked out Adafruit's modification of Raspbian, called Occidentalis? They've done some stuff to make the GPIO stuff more useful, including PWM. I don't really understand that stuff, but perhaps a real hacker such as yourself will find it useful: http://learn.adafruit.com/adafruit-raspberry-pi-educational-linux-distro/occidentalis-v0-dot-2
It doesn't sound like they intend to maintain it like a real distro, but it looks useful for single purpose projects.
Maybe some day they'll get around to proper documentation . . . seems like a genuinely useful open graphics driver isn't going to happen though.
Regards,
d-r
The idea of installing as full Desktop distro just to get decent PWM support is not for me. I'll stick with the BeagleBone
great work!
Karl
A: Yes
B: Yes
let me know what you create.
I use a fairly generic big red button switch, and just about any button/switch would work for this. There are 2 or 3 pins on the RPi that can have a switch directly connected, and in this case, it is pin 7.
I need a programm?
Sorry, i'm noob in this stuff....