Showing posts with label arduino. Show all posts
Showing posts with label arduino. Show all posts
Sunday, August 21, 2011
Hullabaloo, the flapping monkey
Update to the flapping monkey project: it flaps, and it has a name, Hullabaloo. There's still work to do to get it looking better. The body can be arranged around the frame to hide the shoulder joints a bit better. Also, the fabric from the head is just sitting loose on top at the moment. I'm considering giving Hullabaloo a different head, from another animal.
Here I'm using an Arduino Mega to send commands to the SSC-32 servo controller, so it's nice to have that working. I'll likely use the SSC-32 to run multiple toys.
Tuesday, August 2, 2011
Frankenshirt
This is a shirt I made last November that changes the colors of the cat's eyes when the right wrist is rotated up or down.
A LilyPad Arduino board controls it, powered by one AAA battery. An accelerometer on the right cuff detects movement. When the right hand is hanging down, the cat's eyes glow red. As the hand is raised, the color of the cat's eyes moves through the color spectrum. When the hand is raised perpendicular to the ground, the eyes glow violet.
The eyes are two RGB LEDs, covered with a piece of plastic to diffuse the light.
Here's a video of the thing in action:
Making Frankenshirt
To start, I made a stencil of the cat outline, then painted the image onto a second shirt using spray fabric paint. Spray stencil temporary glue came in handy for this. The cat outline is based on a drawing in the Neil Gaiman graphic novel series, The Sandman.
I cut a square out of this shirt around the cat image to place over the electronics on the dark brown shirt.
I started sewing the electronics into the dark brown shirt by sewing a strip of conductive braid down the right arm, as well as a strip of conductive fabric on either side of the braid. The braid has three separated tinsel lines in it, so between the braid and the two strips of conductive fabric, I had five lines to connect the accelerometer on the cuff to the LilyPad on the shoulder. These lines are for the x, y, and z axes, and for power and ground connections. As I'm only using two axes for rotation detection, I could have left out one line on the sleeve.
I used conductive thread to sew in the conductive fabric.
accelerometer sewed onto shirt cuff |
To connect the LilyPad to the two RGB LEDs on the front, I sewed a length of conductive braid and a strip of conductive fabric across to the front. The end of the braid I cut up to separate out the three tinsel lines, which I then sewed to the shirt. I insulated the LED lines with black fabric paint.
I cut out a bit of a plastic milk jug a friend saved for me to use, and sewed it over the LEDs. Then I finished the design by attaching the square of fabric with the cat design, using spray fabric glue, and sewed around the edges of the square.
Where's the code?
Oh, here it is!
/* * Change color of an RGB LED based on the angle of rotation * of y/x from an accelerometer, so as to move through the full * color spectrum as the accelerometer turns 180 degrees. * * Used with an ADXL335 analog three-pin three-axis accelerometer. * * Based on the Sleeping Arduino sketch by Ed Halley. * (The Pummer RGB interpolation class is unchanged.) * * Released (cc) Creative Commons Attribution Only * Kathryn Killebrew * */ #include/* Pummer: * A simple RGB color-interpolating helper class. * * When creating one, tell it which three output pins to drive PWM signals. * If your RGB device is common-anode, it can reverse the PWM for you. * Don't forget to limit current to each LED with a resistor (e.g., 220ohm). * * At any time, tell it what color to become by calling the goal() method, * and how fast to transition to that color. * * Call the pummer's loop() method occasionally to let it set the PWM * outputs to the LEDs. */ class Pummer { byte lR, lG, lB; byte nR, nG, nB; byte wR, wG, wB; int pR, pG, pB; unsigned long last, when; boolean reverse; public: Pummer(int pinR, int pinG, int pinB, boolean anode=false) { pinMode(pR = pinR, OUTPUT); pinMode(pG = pinG, OUTPUT); pinMode(pB = pinB, OUTPUT); nR = nG = nB = 0; reverse = anode; show(); goal(255, 255, 255); } void show() { analogWrite(pR, reverse? (255-nR) : nR); analogWrite(pG, reverse? (255-nG) : nG); analogWrite(pB, reverse? (255-nB) : nB); } boolean done() { return last == when; } void goal(byte r, byte g, byte b, unsigned long speed = 500) { lR = nR; lG = nG; lB = nB; wR = r; wG = g; wB = b; last = millis(); when = last + speed; } void loop() { unsigned long now = millis(); if (now > when) { if (last == when) return; nR = wR; nG = wG; nB = wB; last = when; } else { nR = map(now, last, when, lR, wR); nG = map(now, last, when, lG, wG); nB = map(now, last, when, lB, wB); } show(); } }; /* Accelerometer: * Receive input from a 3-axis device, and perform some useful calculations. * * Specify the three axis pins using analog pin numbers. * These are usually adjacent on the common breakout boards. * * Call the accelerometer's update() method occasionally to update the * current values from the hardware. */ #define ANALOG0 14 class Accelerometer { int p[3]; // which analog pins int a[3]; // acceleration, zero-based int b[3]; // acceleration bias/calibration information float r; // angle of rotation public: Accelerometer(int pinX, int pinY, int pinZ) { pinMode((p[0] = pinX) + ANALOG0, INPUT); pinMode((p[1] = pinY) + ANALOG0, INPUT); pinMode((p[2] = pinZ) + ANALOG0, INPUT); for (int i = 0; i < 3; i++) { b[i] = 512; } r = 0; } void update() { for (int i = 0; i < 3; i++) { a[i] = analogRead(p[i]) - b[i]; } r = 0; } void dump() { Serial.print( "x="); Serial.print(a[0]); Serial.print("\ty="); Serial.print(a[1]); Serial.print("\tz="); Serial.print(a[2]); Serial.print("\troll="); Serial.print(roll()); Serial.println(); } int accel(int axis) { if (axis < 0 || axis > 3) return 0; return a[axis]; } float roll() { if (r != 0) return r; r = atan2(a[1], a[0]); // rotation of y / x return r; } }; void loop() { ; } // we do our own loop below void setup() { Serial.begin(9600); byte newColor[3] = {0,0,0}; // RGB values, 0 - 255 float angle; // angle of rotation, in radians int colorPlace; // angle mapped to range of color values int rainbowState; // which state of change color is in byte incColor; // if adding color to mix, how much byte decColor; // if removing color from mix, how much int div = 0; // counter for averaging angle readings int numReads = 8; // number of readings to average float rollReads = 0.0; // running total of rotation angle readings // initialize with pin numbers for LED colors and accelerometer axes Pummer pummer = Pummer(4, 3, 2, true); Accelerometer accel = Accelerometer(A0, A4, A2); while (1) { delay(20); accel.update(); // read accelerometer axes angle = accel.roll(); // get a rotation angle reading angle = abs(angle); // show full spectrum in 180 deg. (have angle in radians, ranges from -pi to pi) rollReads += angle; // accrue readings for average if (--div <= 0) { angle = rollReads / numReads; // get the average angle reading rollReads = 0; // map angle to range of color values with floating-point math colorPlace = (int)( angle * 1535.0 / M_PI + 1 ); // what in-built map function does, with int math //(x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; colorPlace = map(colorPlace, 0, 1535, 1535, 0); // reverse range for red at bottom, violet at top rainbowState = colorPlace / 256; // bin color number into change state incColor = colorPlace % 256; // remainder is amount of partial color to fade in decColor = map(incColor, 0, 255, 255, 0); // reverse partial color range for fading out // make a rainbow if (rainbowState == 0) { // red to orange newColor[0] = 255; newColor[1] = incColor; newColor[2] = 0; } else if (rainbowState == 1) { // orange to green newColor[0] = decColor; newColor[1] = 255; newColor[2] = 0; } else if (rainbowState == 2) { // green to teal newColor[0] = 0; newColor[1] = 255; newColor[2] = incColor; } else if (rainbowState == 3) { // teal to blue newColor[0] = 0; newColor[1] = decColor; newColor[2] = 255; } else if (rainbowState == 4) { // blue to purple newColor[0] = incColor; newColor[1] = 0; newColor[2] = 255; } else if (rainbowState == 5) { // purple to red newColor[0] = 255; newColor[1] = 0; newColor[2] = decColor; } else { // red newColor[0] = 255; newColor[1] = 0; newColor[2] = 0; } // show colors pummer.loop(); if (pummer.done()) { pummer.goal(newColor[0], newColor[1], newColor[2], 100); } // reset counter for readings div = numReads; // print values accel.dump(); } } }
Labels:
accelerometer,
arduino,
cat shirt,
LilyPad,
wearable electronics
Sunday, July 31, 2011
monkeying around
Here's a simple animatronic monkey I've put together, as my first foray into fun with servos.
The baby monkey's head is mounted on a servo, so the head can turn left and right. A Wii nunchuk hooked up to an Arduino controls the servo, using the analog joystick. The red board is an mp3trigger, which plays monkey noises in response to button presses on the nunchuk.
Here's a video of the thing in action:
The center for the servo seems to be off, and there's some jitter, but I was happy enough with this for a demo. To secure the servo and baby monkey, I've sewed both to the belly of the big monkey, which serves as a sort of base.
For reading from the nunchuk, I used code from here:
http://gitorious.org/randomstuff/arduino-nunchuk
Before putting together this version with the nunchuk, I first controlled the servo with a gamepad connected to a PC that was communicating with the Arduino using serial commands. For that, I used the excellent Python scripts from Principialabs:
http://principialabs.com/arduino-python-4-axis-servo-control/
These use pyserial and pygame. I added some bits to use pygame on the PC for audio. I had the idea of maybe using a ladyada Wave shield for the audio, but found its library has a timer conflict with the servo library, which is why I decided to use an mp3trigger board instead.
To use the mp3trigger board by triggering on the track pins (rather than using serial control), I've set the track pins as input pins in the Arduino setup. Then when a button is pressed, I set the appropriate track's pin as an output, write it low, then set it back as an input. Without leaving the pins as inputs, they'll trigger constantly, I suppose because they need to be allowed to float.
The purpose of this project was to get started with animatronics. Next I will set up a larger doll or stuffed toy with a pan-and-tilt bracket, to play with a larger range of motion.
The baby monkey's head is mounted on a servo, so the head can turn left and right. A Wii nunchuk hooked up to an Arduino controls the servo, using the analog joystick. The red board is an mp3trigger, which plays monkey noises in response to button presses on the nunchuk.
Here's a video of the thing in action:
The center for the servo seems to be off, and there's some jitter, but I was happy enough with this for a demo. To secure the servo and baby monkey, I've sewed both to the belly of the big monkey, which serves as a sort of base.
For reading from the nunchuk, I used code from here:
http://gitorious.org/randomstuff/arduino-nunchuk
Before putting together this version with the nunchuk, I first controlled the servo with a gamepad connected to a PC that was communicating with the Arduino using serial commands. For that, I used the excellent Python scripts from Principialabs:
http://principialabs.com/arduino-python-4-axis-servo-control/
These use pyserial and pygame. I added some bits to use pygame on the PC for audio. I had the idea of maybe using a ladyada Wave shield for the audio, but found its library has a timer conflict with the servo library, which is why I decided to use an mp3trigger board instead.
To use the mp3trigger board by triggering on the track pins (rather than using serial control), I've set the track pins as input pins in the Arduino setup. Then when a button is pressed, I set the appropriate track's pin as an output, write it low, then set it back as an input. Without leaving the pins as inputs, they'll trigger constantly, I suppose because they need to be allowed to float.
The purpose of this project was to get started with animatronics. Next I will set up a larger doll or stuffed toy with a pan-and-tilt bracket, to play with a larger range of motion.
Subscribe to:
Posts (Atom)