2012-10-28

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:

  1. Every hour, get the current word count of a small list of NaNoWriMo participants
  2. Loop through the list of participants and:
    1. illuminate something that represents a NaNoWriMo participant
    2. 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?

#!/usr/bin/env ruby
require 'open-uri'
require 'rexml/document'

class Pin
  def initialize(num)
    @gpio num
    #init this pin
    `gpio -g mode #{@gpioout`
  end
  def on()
     `gpio -g write #{@gpio1`
  end

  def off()
    `gpio -g write #{@gpio0`
  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_percentnum )
    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(configdo |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 |ui|
      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 #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.

Comments
2012-11-28 d-r:
Mr. Jezra -

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
2012-11-28 jezra:
Is it still only two holes? 3 points make a plane, 2 points make a line.

The idea of installing as full Desktop distro just to get decent PWM support is not for me. I'll stick with the BeagleBone
2012-11-28 d-r:
Good point, it is just two holes. It seems like there's a real need for a barebones distro optimized for hardware hacking on the RPi . . . maybe someone will take Adafruit's modifications and turn it in to a real distro.
2012-11-28 jezra:
it's called "Arch"
Name:
not required
Email:
not required (will not be displayed)
Website:
not required (will link your name to your site)
Comment:
required
Please do not post HTML code or bbcode unless you want it to show up as code in your post. (or if you are a blog spammer, in which case, you probably aren't reading this anyway).
Prove you are human by solving a math problem! I'm sorry, but due to an increase of blog spam, I've had to implement a CAPTCHA.
Problem:
1 minus 0
Answer:
required
subscribe
 
2014
2013
2012
2011
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008