Ruffles the fidgety penguin and Tom the melty snowman

by heidiqc

Once upon a time, Ruffles the fidgety penguin decided that he was tired of being static, unmoving little plushie. “I want to be REAL!” He cried, wiggling his little soft head, and wishing upon a star. Of course, the said star was feeling quite benevolent that day, and promptly granted (the first part) of his wish, giving him the magical ability to rotate his head to see the world around him.

However, Ruffles was quite an antsy fella (hence his name), and unfortunately had a nervous twitch, which could not be cured.  The star was rather unsatisfied with this particular outcome, and decided to pick a less jumpy toy as his next subject. Tom the melty snowman was the toy of choice, as his outlook on life had recently been negatively affected by the recent Boston sun. His bored, resigned nature made him the perfect candidate. His unhurried gaze pleased the star, who proclaimed Iteration 2 a success!

The end.

Behind-The-Scenes- The making of Ruffles and Tom:

Ruffles the Fidgety Penguin:

Analog rotation sensor with two channels, Left and Right. Each channel is essentially a potentiometer, created by needle felting aluminum and steel fibers into wool so that the resistance increases when the angle of rotation is increased.  The analog pins A0 and A1 are connected to the potentiometers at the point where the penguin head points forward. The center clasp serves as a switch, as the top clasp is connected to a magnet, which remains in contact with the resistive surface. The bottom clasp is connected to the (-) terminal on the Arduino via a length of conductive fabric. The unstable nature of the signal received from the felted potentiometer can be attributed to the uneven density of the conductive fibers. The mass of conductive and non-conductive fibers also changes resistance with pressure, which causes even more fluctuation. This results in a jumpy image on the screen even after smoothing out the serial output in Arduino over 30 readings.

Resistance of potentiometer when penguin is facing forward- 13.2 ohms, turning away by 90 degrees – 4.83 Mohms, almost facing behind – 15.6Mohms

Tom the Melty Snowman:

Digital rotation sensor with 5 outputs- 2 left, 1 center, and 2 right. Works similarly to the analog sensor, except that the bottom half of rotation sensor has 5 magnets for the 5 outputs embedded below the felt layer and top half has 1 magnet. The jewelry clasp from the analog sensor was changed to the larger snap clasp for easier handling. The processing code was changed to scroll the image by 1 until the desired point of view was reached.

Inside Ruffles (Analog Rotation Sensor):

Arduino:

// set number of readings to smooth over
const int numReadings = 10;
// set variables for A0
int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average
int inputPin = A0;
// set variables for A1
int readings2[numReadings];      // the readings from the analog input
int index2 = 0;                  // the index of the current reading
int total2 = 0;                  // the running total
int average2 = 0;                // the average
int inputPin2 = A1;
void setup() {
// initialize the serial communication:
Serial.begin(9600);
// set pins to high
digitalWrite(A0, HIGH);
digitalWrite(A1, HIGH);
// initialize all the readings to 0
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}
// a0 is left, a1 is right
//1023 is not sensing, 15 is sensing
void loop() {
// when a0 is on left, send signal to monitor
if (analogRead(A0)<900) {
// subtract the last reading:
total= total – readings[index];
// read from the sensor:
readings[index] = analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we’re at the end of the array…
if (index >= numReadings)
// …wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer
Serial.println(3000+average);
}
// when a1 is on right, send signal to monitor
if (analogRead(A1)<900) {
// subtract the last reading:
total2= total2 – readings2[index2];
// read from the sensor:
readings2[index2] = analogRead(inputPin2);
// add the reading to the total:
total2= total2 + readings2[index2];
// advance to the next position in the array:
index2 = index2 + 1;
// if we’re at the end of the array…
if (index2 >= numReadings)
// …wrap around to the beginning:
index2 = 0;
// calculate the average:
average2 = total2 / numReadings;
// send it to the computer
Serial.println(average2);
}
// wait a bit for the analog-to-digital converter
// to stabilize after the last reading:
delay(20);
}



Processing:

import processing.serial.*;
Serial myPort;        // The serial port
// Declaring a variable of type PImage
PImage img;
void setup () {
// set the window size:
size(600, 400);
// List all the available serial ports
println(Serial.list());
// Open whatever port is the one you’re using.
myPort = new Serial(this, Serial.list()[1], 9600);
// don’t generate a serialEvent() unless you get a newline character:
myPort.bufferUntil(‘\n’);
// set inital background:
background(0,0,0);
// Make a new instance of a PImage by loading an image file
img = loadImage(“penguin_pan.jpg”);
}
void draw () {
// everything happens in the serialEvent()
}
void serialEvent (Serial myPort) {
// get the ASCII string:
String inString = myPort.readStringUntil(‘\n’);
if (inString != null) {
// trim off any whitespace:
inString = trim(inString);
// convert to an int
float inByte = float(inString);
// for left, convert back to correct signal
if (inByte > 3000) {
inByte = inByte-3000;
}
// for right, convert to negative signal
else {
inByte= -inByte;
}
// map to panorama
inByte = map(inByte, 0, 1023, 0, 735);
// draw the panorama at correct position
image(img,-735+inByte,0);
}
}



Inside Tom (Digital Rotation Sensor):
Arduino:

void setup() {
// initialize the serial communication:
Serial.begin(9600);
// set inputs to high
digitalWrite(3, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
}
void loop() {
// output number in serial monitor when connected
if (digitalRead(3)== LOW) {
Serial.println(1);
}
else if (digitalRead(5)== LOW) {
Serial.println(2);
}
else if (digitalRead(6)== LOW) {
Serial.println(3);
}
else if (digitalRead(9)== LOW) {
Serial.println(4);
}
else if (digitalRead(10)== LOW) {
Serial.println(5);
}
// wait a bit for the analog-to-digital converter
// to stabilize after the last reading:
delay(10);
}



Processing:

import processing.serial.*;
Serial myPort;        // The serial port
// Declaring a variable of type PImage
PImage img;
// initialize coordinate and scrolling speed
int c =-400;
int tick = 1;
void setup () {
// set the window size:
size(800, 659);
// List all the available serial ports
println(Serial.list());
// Open whatever port is the one you’re using.
myPort = new Serial(this, Serial.list()[1], 9600);
// don’t generate a serialEvent() unless you get a newline character:
myPort.bufferUntil(‘\n’);
// set inital background:
background(0,0,0);
// Make a new instance of a PImage by loading an image file
img = loadImage(“snow_pan.jpg”);
}
void draw () {
// everything happens in the serialEvent()
}
void serialEvent (Serial myPort) {
// get the ASCII string:
String inString = myPort.readStringUntil(‘\n’);
if (inString != null) {
// trim off any whitespace:
inString = trim(inString);
// convert to an int
float inByte = float(inString);
if (inByte==1 && c>=-786) {
c = c-tick;
}
else if (inByte==2) {
if (c>=-524) {
c= c-tick;
}
else {
c= c+tick;
}
}
else if (inByte==3) {
if (c>=-262) {
c= c-tick;
}
else {
c= c+tick;
}
}
else if (inByte==4 && c<0) {
c= c+tick;
}
// draw the panorama at correct position
image(img,c,0);
}
}