Announcements

November 24, 2007
Reading for November 27th, are now posted. Enjoy!

October 2, 2007
To upload your thoughtless acts, create a new assignment page like any other lab. You'll see "Thoughtless Acts" listed as one of the assignment options.

May 24, 2008
This site has been archived and is no longer editable. Stay tuned for the next version, coming in the fall!


Lab 4 - Desktop Roadtripping

Project Members: 
Isaac Salier-He...

Description

Using a photocell and an FSR as analog input, it's the desktop roadtrip!

The photocell provides input on the surrounding light, and my Processing program depicts a day/night scene appropriate to the amount of light provided. In a high-light setting, the scene appears with clear blue skies and a bright yellow sun. In medium light, the sun is lower in the horizon and the sky turns to an orange/red color. As the sun goes down, the sky becomes more purple and the moon begins to rise. In a dark room, the moon (with craters!) rises and stars come out in the sky.

The FSR controls the spedometer in the lower right corner. I set it up to work with a "gas pedal" to apply pressure to the FSR. I initially planned to create an animation so that the yellow lane line would move slowly or quickly according to the acceleration established by the FSR, but it proved more difficult than expected.

Compenents

  • breadboard
  • 2 10k Ohm resistors, 1 220 Ohm resistor
  • wires (black/red for ground, green for input/output, orange for 5V)
  • photocell
  • FSR (with wires)
  • Arduino board
  • cardboard, fedex envelope, and old geometry book for gas pedal
  • lots of lights to test the photocell
  • green LED for testing
  • as always, rubber bands for a secure Arduino

Arduino Code


/*
* Resistive Sensor Input
* Takes the input from a resistive sensor, e.g., FSR or photocell
* Dims the LED accordingly, and sends the value (0-255) to the serial port
*/

// Input Pins
int photocellPin = 2;
int fsrPin = 0;

int ledPin = 11; // select the output pin for the LED, if used

int photocellVal;
int fsrVal;

void setup() {
Serial.begin(9600);
}
void loop() {
photocellVal = analogRead(photocellPin);
fsrVal = analogRead(fsrPin);
analogWrite(ledPin, fsrVal/4); // analogWrite (dimming the LED) can be between 0-255
Serial.print(photocellVal);
Serial.print(",");
Serial.print(fsrVal);
delay(100); // rest a little...
}

Processing Code

/*
* Desktop Roadtripping
* ----------------------
* Isaac Salier-Hellendag
* dish@ischool.berkeley.edu
* TUI - Assignment 4
*
* Using a photocell and an FSR, a user can "drive" down the highway.
*
* The photocell responds to nearby light -- a darker room is reflected
* by showing nighttime (featuring stars and moon with craters!) and a lighter
* room is reflected by either clear blue skies or a beautiful red sunset.
*
* Pressing down on the FSR causes the spedometer to jump. Thankfully, there
* don't seem to be any cops on this highway.
*
*/

import processing.serial.*;
// Change this to the portname your Arduino board
String portname = "/dev/tty.usbserial-A4001lSn"; // or "COM5"
Serial port;
String buf="";
int cr = 13; // ASCII return == 13
int lf = 10; // ASCII linefeed == 10
int radius = 25;

int curTime = 0;
int curAcceleration = 0;
int curDirection = 0;

int windowHeight = 600;
int windowWidth = 600;

float leftMost = windowWidth * .15;
float rightMost = windowWidth * .75;
float horizonIndent = 55;
float paintWidth = 10;

float maxColor = 255;

float earthHeight = 100;
float orbApex = 100;
float orbRadius = 100;
float orbYChange = (((windowHeight - earthHeight) + orbRadius) - orbApex);
float bestPhotoInput = 800;
float orbSlope = orbYChange / (bestPhotoInput / 2);
float orbX = 100;
float orbY = 0;
float timeFloat;
float accelFloat;

int lineLength = 4;
int meterRadius = 200;
int centerX = windowWidth - 30;
int centerY = windowHeight - 30;
float fastDegrees = 80;
float slowDegrees = 190;
float degreeVal;

void setup() {
size(windowHeight, windowWidth);
frameRate(100);
smooth();
background(40,40,40);
noStroke();
port = new Serial(this, portname, 9600);
}
void draw() {
}
void keyPressed() {
if(key == ' ') {
background(40,40,40); // erase screen
}
else {
//drawball(radius, radius, 0);
}
}


void drawBall(float x, float y, int sunMoon) {
int r = 255;
int g = 255;
int b = 255;
switch(sunMoon) {
case 0: r=255; g=255; b=0; break;
case 1: r=255; g=255; b=255; break;
}
fill(r,g,b);
ellipse(x, y, orbRadius, orbRadius);
if(sunMoon == 1) {
fill(255,255,255);
ellipse(windowWidth/4,windowHeight/6,3,3);
ellipse(windowWidth/5,windowHeight/3,3,3);
ellipse(windowWidth - 150,windowHeight/7,3,3);
ellipse(windowWidth/7,windowHeight/2,3,3);
ellipse(windowWidth/10,windowHeight/6,3,3);
ellipse(windowWidth/2,windowHeight/4,3,3);
ellipse(windowWidth-75,windowHeight/2,3,3);
fill(200,200,200);
ellipse(x-(orbRadius/5),y-(orbRadius/5),(orbRadius/5),(orbRadius/5));
ellipse(x+(orbRadius/7),y+(orbRadius/7),(orbRadius/3),(orbRadius/3));
}
}

void drawTime(int timeVal) {
if(timeVal != curTime) {
drawSky(timeVal);
drawOrb(timeVal);
drawEarth(timeVal);
//curTime = timeVal;
}
}

void drawSky(int timeVal) {
timeFloat = float(timeVal);
float r = getSkyRed(timeFloat);
float g = getSkyGreen(timeFloat);
float b = getSkyBlue(timeFloat);
background(r,g,b);
}

float getSkyRed(float timeFloat) {
if(timeFloat <= (bestPhotoInput * .25))
return 0;
if(timeFloat > (bestPhotoInput * .25) && timeFloat <= (bestPhotoInput * .5))
return (maxColor * -1) + ((maxColor / (bestPhotoInput * .25)) * timeFloat);
if(timeFloat > (bestPhotoInput * .5) && timeFloat <= (bestPhotoInput * .75))
return maxColor;
if(timeFloat > (bestPhotoInput * .75) && timeFloat < (bestPhotoInput * .875))
return ((maxColor * 4) - ((maxColor / (bestPhotoInput * .25)) * timeFloat));
else
return maxColor * .5;
}

float getSkyBlue(float timeFloat) {
if(timeFloat >= (bestPhotoInput * .75))
return (maxColor * -3) + (((maxColor / (bestPhotoInput * .25)) * timeFloat));
if(timeFloat > (bestPhotoInput * .5) && timeFloat < (bestPhotoInput * .75))
return (maxColor * -3) - ((maxColor / (bestPhotoInput * .25)) * timeFloat);
if(timeFloat > (bestPhotoInput * .25) && timeFloat <= (bestPhotoInput * .5))
return (maxColor * -1) + (((maxColor / (bestPhotoInput * .25)) * timeFloat));
else
return 0;

}

float getSkyGreen(float timeFloat) {
if(timeFloat <= (bestPhotoInput * .5))
return 0;
if(timeFloat > (bestPhotoInput * .5) && timeFloat < (bestPhotoInput * .75))
return (maxColor * -2) + ((maxColor / (bestPhotoInput * .25)) * timeFloat);
if(timeFloat >= (bestPhotoInput * .75) && timeFloat <= (bestPhotoInput * .875))
return (maxColor * 4) - ((maxColor / (bestPhotoInput * .25)) * timeFloat);
else
return maxColor * .5;
}

void drawOrb(int timeVal) {
timeFloat = float(timeVal);
if(timeVal < (bestPhotoInput/2)) {
orbY = (orbSlope * timeFloat) + orbApex;
drawBall(orbX, orbY, 1);
} else {
orbY = (orbSlope * timeVal * -1) + ((orbYChange * 2) + orbApex);
drawBall(orbX, orbY, 0);
}
}

void drawEarth(int timeVal) {
fill(40,40,40);
rect(0, (windowHeight - earthHeight), windowWidth, earthHeight);
drawHighway();
}

void drawHighway() {
fill(255,255,255);
quad(leftMost + horizonIndent, windowHeight - earthHeight,
leftMost + horizonIndent + paintWidth, windowHeight - earthHeight,
leftMost + paintWidth + 5, windowHeight,
leftMost, windowHeight);
quad(rightMost - paintWidth, windowHeight - earthHeight,
rightMost, windowHeight - earthHeight,
rightMost + horizonIndent + paintWidth + 5, windowHeight,
rightMost + horizonIndent, windowHeight);
drawDashedLine();
}

void drawDashedLine() {
fill(255,220,0);
quad((windowWidth/2) - (paintWidth/2) + 1, windowHeight - earthHeight,
(windowWidth/2) + (paintWidth/2) - 1, windowHeight - earthHeight,
(windowWidth/2) + (paintWidth/2), windowHeight - earthHeight + 20,
(windowWidth/2) - (paintWidth/2), windowHeight - earthHeight + 20);
quad((windowWidth/2) - (paintWidth/2) - 1, windowHeight - earthHeight + 40,
(windowWidth/2) + (paintWidth/2) + 1, windowHeight - earthHeight + 40,
(windowWidth/2) + (paintWidth/2) + 3, windowHeight - earthHeight + 60,
(windowWidth/2) - (paintWidth/2) - 3, windowHeight - earthHeight + 60);
quad((windowWidth/2) - (paintWidth/2) - 4, windowHeight - earthHeight + 82,
(windowWidth/2) + (paintWidth/2) + 4, windowHeight - earthHeight + 82,
(windowWidth/2) + (paintWidth/2) + 6, windowHeight,
(windowWidth/2) - (paintWidth/2) - 6, windowHeight);
}

void drawSpedometer(int accelerationVal) {
accelFloat = float(accelerationVal);
drawMeter();
drawSpeedLine(accelFloat);
}

void drawMeter() {
fill(255,255,255);
ellipse(centerX, centerY, meterRadius, meterRadius);
fill(0,0,0);
ellipse(centerX, centerY, meterRadius - 2, meterRadius - 2);
}

void drawSpeedLine(float accelFloat) {
degreeVal = (((fastDegrees - slowDegrees)/1024) * accelFloat) + slowDegrees;
float rad = radians(degreeVal);
float lineX = (cos(rad) * meterRadius * .45) + centerX;
float lineY = centerY - (sin(rad) * meterRadius * .45);
stroke(255,0,0);
strokeWeight(3);
line(lineX, lineY, centerX, centerY);
noStroke();
}

// called whenever serial data arrives
void serialEvent(Serial p) {
int c = port.read();
if (c != lf && c != cr) {
buf += char(c);
}
if (c == lf) {
String[] inputs = buf.split(",");
int timeVal = int(inputs[0]);
int accelerationVal = int(inputs[1]);
drawTime(timeVal);
drawSpedometer(accelerationVal);
buf = "";
}
}

Photos & Video

Photos available at:

http://www.flickr.com/photos/46877131@N00/sets/72157602189563095/

See it in action (YouTube, featuring Chuck Berry):

http://www.youtube.com/v/WQ_S_O-NX0Y


Comments

isaac, really fun demo.

isaac, really fun demo. Great job! I like how you said "more difficult than expected" though it's not the intention of the course, it's unfortunately true a lot of the times, isn't it?


Powered by Drupal - Design by Artinet