Little Robot Presentation! Tonight!
27 Jan 2010
I'm going to be talking these little robots tonight, at DemoCamp Guelph! Proceedings get underway at about 6:30 at the eBar.
Little Robots -- Hardware
19 Jan 2010
This is part one of a three part series: Part two covers the firmware, and part three will cover the software.
I find interaction design to be pretty fascinating. And lets face it, most of the technology we deal with on a daily basis has not been designed with interaction in mind. Or at least not subtle interaction.
Take telephones: they're a priority interrupt. When a phone rings, you go through a full context switch. You have to stop what you're doing to answer. Email doesn't interrupt, but it's not priority either. Email doesn't say "I'm thinking of you" it says "I thought of you twenty minutes ago". These are great examples of technologies that meet their minimum need; they do work, but do they work well? Is email the best way to get text from one human being to another? My spam filter says no. Is the telephone the best way to tell someone you were just thinking about them?
When you're in a room with someone, there are many different subtle ways to indicate that you enjoy their presence. Everything from where you sit to how you breath has at least some degree of significance -- some degree of communication. This project was my way of performing that communicative act, when I'm not in a room with that someone.
Enough waxing philosophical: I made two little robots. One for my fiancé's desk, and one for mine. When you poke one in the belly, the other one waves.
Without further ado, here's part one:
Hardware
The hardware on this project is absolutely informed by the firmware. From the outset I expected to use Objective Development's V-USB package. It provides a software USB stack capable of running on 8-bit Atmel AVR microcontrollers. With that in mind, I sought a challenge and picked the smallest AVR I could get on short notice -- the ATtiny85, in an 8-pin DIP package. This is a pretty powerful chip, at least for these purposes. Less than $3 Canadian gets 8kB of flash program storage, a half a kilobyte of RAM, two hardware timers, and an internal oscillator. Not really being one to reinvent the wheel, I found an existing project using the same firmware and microcontroller -- the one key keyboard by Flip van den Berg. After some ethical deliberations, I shamelessly took his schematic, and breadboarded out myself: To my surprise, it actually ran! You can make a USB keyboard on a breadboard! And it works on any computer that supports HID compliant devices! The next step was to take the same circuit, and put it on something a little bit more permanent. In this case, some protoboard. The circuit on the left is a programming target board, with a standard programming header. I use it with an Adafruit USBtinyISP programmer. The circuit on the right is the USB controller with a button and header for a servo motor. Servos are fairly useful beasts. They don't really need drivers. Supply them with a suitable PWM signal, and they'll drive themselves. In this case, the servo is powered off the +5v USB supply, even though the microcontroller is running at +3.3v. My servo didn't seem to care, and quick google searching suggests that this is pretty standard; servos will amplify their PWM signal internally. So at this point I found that the electronics basically worked. I was able to control a servo, and read button presses. So now for some larger scale hardware. I don't have access to a full shop, so I relied on a low impact sculpting material: Sculpey, a polymer clay, similar to Fimo. A little armature wire, some low-fidelity sculpting and the parts went into the oven at 250° F for about 15 minutes. As easy as sculpey is to work, it is even easy to rework. Hot glue and acrylic paint stick to it quite happily. Next, I installed the guts with lots of hot glue. Then I painted the exterior with acrylic spray paint. I touched up the eyes with acrylic paint, and added craft foam tank treads and covers for the belly-switches. And here's what they look like from the back. Next up: The firmware! Update: This article was featured on Make: Online.Arduino / Physical Computing Demo!
15 Jan 2010
At the next Guelph Coffee and Code. I will give a short demonstration of the Arduino platform. This will be a variation of a talk I gave while TA-ing the Human Computer Interaction course at the University of Guelph. It's not going to be technically heavy -- there will be lots of pictures, lots of live demonstrations and a little bit of fire, all in the name of science!
If you are in Guelph, and curious about the Arduino platform, or hardware hacking in general, please come on out to the Synnema, next Thursday (the 21st)!
Little Robot Preview.
11 Jan 2010
For our wedding save-the-date cards, I drew two little robots.
For Christmas, I made little robots for Sheena.
They're USB powered -- one for her desk and one for mine. When you poke one, the other will wave, wherever they happen to be.
These are powered by an ATtiny85, Objective Development's V-USB and python.
More details to come soon.
An AVR Powered Arc Reactor
11 Jan 2010
For Hallowe'en last year I wanted to go as Tony Stark on a night out. There are quite a few Arc Reactor projects floating around the internet, but I wanted something that would shine through a dress shirt, and have a bit of motion to it.
Hardware
I was inspired by Sprite's post on electronic minimalism. He points out that many components that are necessary in traditional electronics can be omitted when using a microcontroller. You can fake some hardware in software. With that in mind, HC Gilje has a great write-up on how to make a truly minimal arduino clone, using the LilyPad arduino firmware. I wrote the software, and did about half the assembly. Matt Englert did the other half, soldering up the controller board in less than half an hour with no schematic and a semi-coherent description from me. It's pretty basic. The ring is made of 3mm white LEDs hotglued into a piece of dollar store cutting board. I think this one is polystyrene rather than HDPE. The LEDs have a common cathode. Their other ends are connected directly to the microcontroller on pins 6 and 11 to 19 -- that corresponds to digital 4 to digital 13 in the arduino environment. There are no current limiting resistors. Each LED is controlled via pulse width modulation or PWM. Rather than a constant current, they are each turned on and off at about 250 Hz. By varying the duty cycle, the microcontroller can set the brightness of each LED. LEDs are like any other component: their specifications are approximate, and recommended values. You can overpower just about any component for small amounts of time. By making sure these LEDs are never given a 100% duty cycle, I felt okay overpowering them. This is an exercise in minimal circuitry. And truth be told, it only needed to last one night. Mouse over these pictures for more details: Given that a typical AAA has about 750mAh of capacity, and this gizmo was still going at noon the next day, it averaged about 40 milliamps.Software
The ATmega168 chip only has six hardware PWM outputs, and for this project I needed ten. Dimming an LED is a pretty trivial application. Doing PWM in software will certainly be sufficient. The dimming is handled by a function called update_dimmer(). It is called by a timer interrupt at 4kHz. With 16 dimming levels, a complete PWM cycle occurs about 250 times a second. The animation is handled by animate_rotating_sine(). It runs constantly, but only updates the animation every 25 milliseconds. The animation is timed to rotate about 70 times a minute, or roughly equivalent to the average human heart rate. Here's the source code:
#define ARC_START 4 // Circle of LEDs starts at digital pin 4 (Arduino, not AVR)
#define ARC_SIZE 10 // There are 10 leds.
// Dimming parameters.
#define PIN_DUTY_CYCLE 16 // Number of dimming levels to support
int pin_duty_cycle = 0; // Where are we in the current dimming cycle.
int pin_duty[ ARC_SIZE ]; // Gray level for each pin. Should < PIN_DUTY_CYCLE
// Animation parameters.
#define ANIMATION_INTERVAL 25 // milliseconds
long animation_time = 0; // When did we last update the animation?
#define ANIMATION_CYCLE (((60.0*1000)/(70*ANIMATION_INTERVAL))) // should be about 70bpm -- avg human heart rate.
int animation_cycle = 0; // Where are we in the animation cycle?
#define CPU_FREQ 8000000.0 // Timer2 runs at this speed. Needed for interrupt calculations.
#define TIMER2_DIVISOR 32
#define TIMER2_FREQ ( CPU_FREQ / TIMER2_DIVISOR )
// The setup() method runs once, when the sketch starts
void setup() {
// Set LED pins to output.
for( int pin = 0; pin < ARC_SIZE; pin++ ) {
pin_duty[ pin ] = 0;
pinMode( ARC_START + pin, OUTPUT );
digitalWrite( ARC_START + pin, OUTPUT );
}
// Update our dimming level periodically.
SetupTimer2(4000);
rotate_blink();
}
// Initialize Timer 2
// Shamelessly taken from http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/
unsigned char SetupTimer2( float timeoutFrequency ){
unsigned char result; //The timer load value.
//Calculate the timer load value
result=(int)((257.0-(TIMER2_FREQ/timeoutFrequency))+0.5);
//The 257 really should be 256 but I get better results with 257.
//Timer2 Settings: Timer Prescaler /32, mode 0
TCCR2A = 0;
TCCR2B = 0<= PIN_DUTY_CYCLE ) ? 0 : pin_duty_cycle + 1;
}
void rotate_blink() {
// Animation start up. Pulse each LED.
for( int pin = 0; pin < ARC_SIZE; pin++ ) {
pin_duty[ pin ] = 0.75 * PIN_DUTY_CYCLE;
delay( 100 );
pin_duty[ pin ] = 0;
delay( 50 );
}
}
void animate_rotating_sine() {
// We might have just overflowed. Overflown?
if( millis() < animation_time )
animation_time = 0;
if( millis() - animation_time > ANIMATION_INTERVAL ) {
// Where is the sine rotated overall?
float animation_angle = PI * 2 * animation_cycle / ANIMATION_CYCLE;
for( int pin = 0; pin < ARC_SIZE; pin++ ) {
// How far around the arc is this LED?
float led_angle = PI * 2 * pin / ARC_SIZE;
// Values tweaked for appearance; there's no science here :)
pin_duty[ pin ] = ( sin( animation_angle + led_angle ) + 2 ) * PIN_DUTY_CYCLE / 3 *.9;
}
animation_time = millis();
animation_cycle = ( animation_cycle >= ANIMATION_CYCLE ) ? 0 : animation_cycle + 1;
}
}
// the loop() method runs over and over again,
// as long as the Arduino has power
void loop()
{
animate_rotating_sine();
}
Conways' Life Writ Large
08 Jan 2010
This is (half of) a system I developed for SHARCNET last year. They have a nifty little 'Supercomputer in a Box' project designed for community outreach. Like most modern supercomputers, it's a cluster of machines. For the sake of size, it's made of eight Apple Mac Minis.
Supercomputers have their own constraints; it is not worth parallelizing a process if the gains in computation are outweighed by communications overhead. This is intuitive to a computer scientist, but we're not normal people. Non-computer scientists could use a visual aide.
The above screenshot shows a distributed version of Conway's Life, a trivial cellular automata. It's not a particularly important application; it's just intended to burn up CPU cycles. Each stripe represents a process running on a distinct CPU. In this case I'm wasting time in 16-way glory.
Using the control panel on the left, a user can change the dimensions of the cellular automata, or inflate its computational complexity. For example, a very wide, short simulation will use more network than CPU. A very large simulation will use up available memory and thrash when running on a single processor, but will be perfectly happy when split across a cluster.
In practical use, this program is only half a solution; it works well in concert with a cluster monitoring package such as ganglia.
The distributed conway's life implementation is written in C using MPI. The front end program is written in Python, using wxPython for the graphical interface, and Twisted Python to receive images from each compute process.
Sketching In Hardware (2)
05 Jan 2010
I've had an urge lately to post some of the nifty projects I've done over the last few months. Hopefully it will help me put some of my experiences in context. Not to mention actually taking notes lets me find them later.
As long as computers have existed, we've tried to represent the physical world in the virtual one. This trend goes as far back as the punched cards and tabulating machines used in the 1890 United States Census, but it doesn't end there. When computers became common enough that regular people -- without specialized training -- may use them, interface designers went straight for spacial metaphors. We pulled more of the physical world into the machine.
What I find fascinating about hardware hacking and platforms like the Arduino is that we can reverse that trend. We can interact with computers through the physical world, rather than interpreting the physical world through a virtual one. And we can do it trivially.
Here's my own humble first effort:
This is a bot that monitors an IRC channel. When I announce a mood, it moves the needle accordingly. It's not very complicated at all -- some cardboard, marker, sticky tape, a ~$10 hobby servo, and two pieces of code.
The first, runs on a host computer, monitors the IRC channel, and tells the arduino where to point the needle. Ruby is very terse -- but it's also very expressive. It is easy to make very functional object oriented programs in very little space.
#!/usr/bin/env ruby
require 'rubygems'
require 'net/irc'
require 'serialport'
# This is an IRC Bot that also
# talks to an arduino microcontroller.
class ToneOMeter < Net::IRC::Client
# What emotions should this bot respond to?
# These are passed directly to the arduino.
@@emotions = {
'sarcastic' => '20s',
'sardonic' => '60s',
'acerbic' => '135s',
'cynical' => '180s'
}
def self.emotions
@@emotions
end
def initialize(*args)
super
# Connect to the arduino. This will work on linux, other
# platforms may require some adjustment.
@sp = SerialPort.new "/dev/ttyUSB0", 19200
end
def on_rpl_welcome(m)
# We've connected to the server, join a channel.
post JOIN, "#tone-o-test"
end
def on_privmsg(m)
# Someone has entered text into the channel. Who was it?
name = /^(.+)!/.match( m.prefix )[1]
# If it was my owner (tony), and it's an action...
if name =~ /tony/ && m[1] =~ /ACTION/
# Extract the action, and send the canned result to the arduino.
action = /\01ACTION is (.+)\01/.match( m[1] )[1].strip.downcase
@sp.write( ToneOMeter.emotions[ action ] )
end
end
end
# Instantiate a new bot, and start it.
ToneOMeter.new("test.server", "6667", {
:nick => "Tone-O-Meter",
:user => "Tone-O-Meter",
:real => "Tone-O-Meter",
}).start
The second set of software is taken from the Arduino Playground and runs on the microcontroller itself. It uses Arduino's servo library to set the servo to a given angle. This isn't my code, but it's trivial enough (and useful enough) to repeat here.
#include
Servo servo1;
void setup() {
pinMode(1,OUTPUT);
servo1.attach(14); //analog pin 0
//servo1.setMaximumPulse(2000);
//servo1.setMinimumPulse(700);
Serial.begin(19200);
Serial.println("Ready");
}
void loop() {
static int v = 0;
if ( Serial.available() ) {
char ch = Serial.read();
switch(ch) {
case '0'...'9':
v = v * 10 + ch - '0';
break;
case 's':
servo1.write(v);
v = 0;
break;
}
}
Servo::refresh();
}
So there you have it: Physical computing done with little electronics skill, for less than $40, and in less than a hundred lines of code. This is a pretty trivial example, but even just given the context of IRC it suggests some nifty projects. For example, a physical representation of how many users are in a channel? Or how active the conversation is?
With physical interfaces now trivial to prototype, interface designers have yet another tool: Physical, tangible interfaces.
Update: This article was featured on Make: Online.
