Tuesday, May 5, 2009

It Works*

*Disclaimer
The project works as proposed.
You place a colored gel over the light sensor which takes a transmissive reading and outputs the color.
This whole project is about calibration.

Input:
•The light must be balanced. In testing I used a bright "white" LED. left uncorrected the result was a green output (after the output had been calibrated...more on this in a bit). The LED was actually quite Green and Warm. I used glass Color Correction Filters over the lens. An 82B and a 05 Magenta. This brought the light to around 5450 Kelvin.

Once the light was balanced. I set to mapping each sensor to it's high and low for each Primary R,G, and B response. Using these primaries I could find the maximum saturation level of the sensor. The only caveat here though is that the Lee Filters are calibrated for maximum saturation at 6774K which is "cool" daylight. So it was the maximum minus the mired shift to 5500K.
r255= (int)rv; //Casting float to an INT
g255= (int)gv; //Casting float to an INT
b255= (int)bv; //Casting float to an INT

rmap= map(r255,142,172,0,255)*.8;
gmap= map(g255,85,185,0,255);
bmap= map(b255,74,255,0,255);

Output:
Once these values were identified. I mapped them to the visible range of PWM.
Red was multiplied by a value of .8 This code being a appropriated from Adam Meyer of RISD, I was forced to handle variables that I don't know how to properly manipulate yet. The Casting of the float to INT was such an instance of my inexperience forcing me to simplify. I was unable to figure out how to print the float value. Even though the Arduino reference said that the truncated value would be print inside of a serial.print() it was a no go.

This simplification must be addressed at the input level.

Carrying on. Once the variables were mapped to the stable and color corrected brightness, the device worked with minimum flaw. Green being the only color which was produced somewhat inconsistently. I am unsure as to why this might be.

Color Test


The original code was from Adam Meyer Many thanks to him for getting me started.

CODE:

#include

#define I2C_ADDRESS 0x74 // 7bit

#define REG_CAP_RED 0x06
#define REG_CAP_GREEN 0x07
#define REG_CAP_BLUE 0x08
#define REG_CAP_CLEAR 0x09

#define REG_INT_RED_LO 0x0A
#define REG_INT_RED_HI 0x0B
#define REG_INT_GREEN_LO 0x0C
#define REG_INT_GREEN_HI 0x0D
#define REG_INT_BLUE_LO 0x0E
#define REG_INT_BLUE_HI 0x0F
#define REG_INT_CLEAR_LO 0x10
#define REG_INT_CLEAR_HI 0x11

#define REG_DATA_RED_LO 0x40
#define REG_DATA_RED_HI 0x41
#define REG_DATA_GREEN_LO 0x42
#define REG_DATA_GREEN_HI 0x43
#define REG_DATA_BLUE_LO 0x44
#define REG_DATA_BLUE_HI 0x45
#define REG_DATA_CLEAR_LO 0x46
#define REG_DATA_CLEAR_HI 0x47


//define the output pins for the external RGB LED
#define groundPin 8
#define redPin 9
#define greenPin 10
#define bluePin 11


float redFactor=1;
float blueFactor=1;
float greenFactor=1;

//initial darkLevel;
int calibrationDarkness = 0;
byte calibrationRed = 5;
byte calibrationGreen = 5;
byte calibrationBlue = 5;


void setup(void)
{
Serial.begin(9600);
Wire.begin();

pinMode(groundPin, OUTPUT);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
//pinMode(ledPin, OUTPUT);
//pinMode(clearCalPin, INPUT);


// sensor gain setting (Avago app note 5330)
// CAPs are 4bit (higher value will result in lower output)


set_register(REG_CAP_RED, 0x05);
set_register(REG_CAP_GREEN, 0x05);
set_register(REG_CAP_BLUE, 0x01);
set_register(REG_CAP_CLEAR, 0x01);

//calibrate led
digitalWrite(groundPin,LOW);// this was a rig that is not advisable.
digitalWrite(redPin,HIGH);
digitalWrite(bluePin,HIGH);
digitalWrite(greenPin,HIGH);

int ledGain = getColorGain();

set_gain(REG_INT_RED_LO,ledGain);
set_gain(REG_INT_GREEN_LO,ledGain);
set_gain(REG_INT_BLUE_LO,ledGain);

performMeasurement();

int red=get_readout(REG_DATA_RED_LO);
int green=get_readout(REG_DATA_GREEN_LO);
int blue=get_readout(REG_DATA_BLUE_LO);

digitalWrite(redPin,0);// show no color on these pins
digitalWrite(bluePin,0);
digitalWrite(greenPin,0);

int m=2000; //bigger anyway
m=min(m,red);// min means whichever one is less
m=min(m,green);
m=min(m,blue);

Serial.print("m - ");//print out the smallest value of Red Green or Blue
Serial.println(m);
/* This next section mimics white balance */
redFactor=((float)m*255.0)/(1000*(float)red);
greenFactor=((float)m*255.0)/(1000*(float)green);
blueFactor=((float)m*255.0)/(1000*(float)blue);


}

void loop() {

//digitalWrite(redPin,0);
//digitalWrite(bluePin,0);
//digitalWrite(greenPin,0);

int clearGain = getClearGain();
set_gain(REG_INT_CLEAR_LO,clearGain);
int colorGain = getColorGain();
set_gain(REG_INT_RED_LO,colorGain);
set_gain(REG_INT_GREEN_LO,colorGain);
set_gain(REG_INT_BLUE_LO,colorGain);


//reset the RGB (and clear) values
int cc = 0;
int red=0;
int green=0;
int blue=0;


// Take 4 samples, and add them together.
for (int i=0; i<4>
performMeasurement();
cc +=get_readout(REG_DATA_CLEAR_LO);
red +=get_readout(REG_DATA_RED_LO);
green +=get_readout(REG_DATA_GREEN_LO);
blue +=get_readout(REG_DATA_BLUE_LO);
}

//now, divide the totals for each by 4 to get their average.
cc/=4;
red /=4;
green /=4;
blue /=4;


//print out the findings
Serial.print("Readout @");
Serial.print(clearGain);
Serial.print("/");
Serial.print(colorGain);
Serial.print(" c=");
Serial.print(cc);
Serial.print(", r=");
Serial.print(red);
Serial.print(", g=");
Serial.print(green);
Serial.print(", b=");
Serial.println(blue);


//take the values mesured from above, and multiply them with the factors to
//find out what value should be sent to the external RGB LED to reproduce this color
float rv = (float)red*redFactor;
float gv = (float)green*greenFactor;
float bv = (float)blue*blueFactor;

//As we can only output an integer, convert each value.

//These variables Modified by Brian Jones for transmissive readings.


int r = red;
int g = green;
int b = blue;

int r255;
int g255;
int b255;
int rmap;
int gmap;
int bmap;

r255= (int)rv; //Casting float to an INT
g255= (int)gv; //Casting float to an INT
b255= (int)bv; //Casting float to an INT

rmap= map(r255,142,172,0,255)*.8;
gmap= map(g255,85,185,0,255);
bmap= map(b255,74,255,0,255);

rmap= max(rmap,0);
gmap= max(gmap,0);
bmap= max(bmap,0);

//output values to the external RGB LED

analogWrite(redPin, rmap);
analogWrite(greenPin,gmap);
analogWrite(bluePin,bmap);



//output what values where sent

Serial.print(" r255=");
Serial.print(r255);
Serial.print(", g255=");
Serial.print(g255);
Serial.print(", b255=");
Serial.println(b255);
Serial.print("Replay : rmap=");
Serial.print(rmap);
Serial.print(", gmap=");
Serial.print(gmap);
Serial.print(", bmap=");
Serial.println(bmap);

Serial.println("---------------");

//hold it for one second
//delay(1000);
}
/* the next comment is sort function Most likely ---confirm--- so this will set the "exposure" for next loop */
int getClearGain() {
int gainFound = 0;
int upperBox=4096;
int lowerBox = 0;
int half;

while (!gainFound) {
half = ((upperBox-lowerBox)/2)+lowerBox;


if (half == lowerBox) { //no further halfing possbile
break; //no further halfing possbile
} else {
set_gain(REG_INT_CLEAR_LO,half);
performMeasurement();
int halfValue = get_readout(REG_DATA_CLEAR_LO);

if (halfValue > 1000) {
upperBox=half;
} else if (halfValue<1000)>
lowerBox = half;
} else {
break; //no further halfing possbile
}
}
}
return half;
}

int getColorGain() {
int gainFound = 0;
int upperBox=4096;
int lowerBox = 0;
int half;
while (!gainFound) {
half = ((upperBox-lowerBox)/2)+lowerBox;

if (half==lowerBox) { //no further halfing possbile
break; // gain found
} else {

set_gain(REG_INT_RED_LO,half);
set_gain(REG_INT_GREEN_LO,half);
set_gain(REG_INT_BLUE_LO,half);
performMeasurement();
int halfValue = 0;

halfValue=max(halfValue,get_readout(REG_DATA_RED_LO));
halfValue=max(halfValue,get_readout(REG_DATA_GREEN_LO));
halfValue=max(halfValue,get_readout(REG_DATA_BLUE_LO));

if (halfValue>1000) {
upperBox=half;

} else if (halfValue<1000)>
lowerBox=half;

} else {
break; // gain found
}
}
}
return half;
}


void performMeasurement() {
set_register(0x00,0x01); // start sensing

while(read_register(0x00) != 0) {
// waiting for a result
}
}

int get_readout(int readRegister) {
return read_register(readRegister) + (read_register(readRegister+1)<<8);
}

void set_gain(int gainRegister, int gain) {
if (gain <4096)>
uint8_t hi = gain >> 8;
uint8_t lo = gain;

set_register(gainRegister, lo);
set_register(gainRegister+1, hi);
}
}

void set_register(unsigned char r, unsigned char v){

Wire.beginTransmission(I2C_ADDRESS);
Wire.send(r);
Wire.send(v);
Wire.endTransmission();
}

unsigned char read_register(unsigned char r){

unsigned char v;
Wire.beginTransmission(I2C_ADDRESS);
Wire.send(r); // register to read
Wire.endTransmission();

Wire.requestFrom(I2C_ADDRESS, 1); // read a byte
while(!Wire.available()) {
// waiting
}
v = Wire.receive();
return v;
}



The Future:

Continuing on, I need to figure out how to calibrate the sensor to a wider range of color temperature. I need to establish a standard Kelvin value from which all color calculation outputs are made. As of now the sensor reads all temperatures as "normal" and the sensor values are all calculated the same. Optimally they should be weighted to reflect the cast of the light to give the sensors a proper read and that should be adjusted for output.
This would be going from a non-linear space to a linear space and then back to non-linear for output. The output non-linear. Food for thought no doubt.

Friday, April 3, 2009

Part Research Entry 1

In executing this project my goal is color precsion on input and output. the way forward that was suggested initally was using an array of three photoresistors with an R G and B color seperation gels over each one. the issue with this though is that a value for luminance is needed for a proper color balance reading. I am researching a variety of sensors. The Avago seems like the best fit so far. The input/output is all through serial commands. The sensor is tiny and it averages the sensor readings before sending the resultant data out. The only thing I am a bit dim on at the moment is how exactly the outgoing data is formatted.
-Stay tuned.

Wednesday, March 18, 2009

Kiosk as Social Lubricant.

How do you get two parties that do not know each other to interact in a public space?
My partner Laura Ciporen tried to address this question for our midterm project.
In spaces such as a museum, people will readily interact with kiosks. Their mere presence seems to invite interaction. This predisposition to kiosks was exploited to solve the anonymous interaction issue. Two people could be enticed to interact with the kiosk first, and the kiosk makes the connection between the individuals. The kiosk is the social lubricant that moves the users to the state of interaction (with each other) that is desired.

When we initially came up with the idea, we were very focused on the enticement phase, getting the users attention. We decided to use a looping movie that used the words "come play" which was satisfactory for prototyping. Flashing lights, noises, flags, etc... could also be used to attract attention.





After the user notices the kiosk, and walks nearer, the kiosk is to invite the user to do something. In this case, it is an invitation to move right or left.



Moving right or left would produce a video instructing the user to either "Wave their hands in the air" or "Do the Funky Chicken". Silly? Perhaps, but the goal was to produce an observable output from the user. The funky chicken is unmistakable.

The two kiosks can be set up anywhere. When two people have been enticed by the kiosks and they are being used simulatneously...the outputs swtich. Kiosk A's output is shown on the screen of B and vice versa. A game of "simon sez" occurs A is telling B what to do, as B does A.

The two users have just interacted with one another.
It is at this point that the interaction that requires two individuals can begin.

Sensors.

The kiosks are activated by proximity, so at first we thought about using an array of ranging sensors to drive the interactions. After further research though, laser and pressure sensors were deemed the most cost effective and practical for the prototype. The lasers were attached to external power sources so that we didn't have to worry about the batteries. One strange note. The batteries added up to 4.5V but when I used a voltage regulator and resistors to bring the current down to that value. The lasers were to dim. They were strung together in parallel at 5V.


The "Come hither" movie would play until the user steps onto the mat (pressure sensor) then right and left movements would be activated using the interruption of a laser's beam on a photo diode.

Here is the whole interaction for one Kiosk.


Construction:

Autopoles with super clamps were used to align lasers and sensors. In a final build however we would use sensors that could register inputs without needing beam breaks for activation. We'd keep it all to one side. of the user.
Code:

Because we did not have ANY working experience with Processing, we decided it would be best for all conditional output from the sensors to be evaluated by the Arduino. Only one value would be sent to processing, allowing a simple Case Switch to be used.

The Arduino Code was written first. We set up the sensors and did a serial.read to make sure the sensors were working and used letters to determine which movie instruction would be passed to Processing.
"d" is "Default", the initial state
"m" means the pressure sensor has been tripped, but the laser beams are intact.
"l" and "r" register the right and left beam breaks.
Here is a sample of the serial output:

ArdyCalling
ArdyCalling
d
d
d
d
d
d
d
d
current reading 918
m
current reading 918
m
current reading 918
m
current reading 918
m
current reading 917
m
current reading 917
m
d
d
d
current reading 915
l
current reading 914
l
current reading 914
l
d
d
d
current reading 694
r
current reading 692
r
current reading 691
r





Arduino
//
//THIS CODE IS FOR THE ARDUINO COMMUNICATING WITH THE COMPUTER IN FRONT OF PERSON B
//

//Arduino is responsible for the management of all sensor data being
//sent to processing. Data will be tranlated to a single variable for
//output to processing.


//*************************
//VARIABLES
//*************************

//initialize pin settings
int proxyA=0; //Pressure Sensor on kiosk A on Analog pin 0 Yellow
int proxyB=1; //Pressure Sensor on kiosk B on Analog pin 1 Purple

int irlA=2; // left photocell on kiosk A on Analog pin 2 Orange
int irrA=3; // right photocell on kiosk A on Analog pin 3 Mauve

int irlB=4; // left photocell on kiosk B on Analog pin 4 Blue
int irrB=5; // right photocell on kiosk B on Analog pin 5 Green

//places to store base light readings for all 4 light sensors
int baseIRLA=0;
int baseIRLB=0;
int baseIRRA=0;
int baseIRRB=0;

//places to store the new light readings from the appropriate pair of light sensors
int newIRL=0;
int newIRR=0;

//initialize pressure reading variables
int pressureReadingA=0;
int pressureReadingB=0;
int basePressureReadingA=0;
int basePressureReadingB=0;

//variables to tell Ardy which sensors and base values to use in comparisons
int currentBaseL=baseIRLB;
int currentBaseR=baseIRRB;
int currentSensorL=irlB;
int currentSensorR=irrB;

//int swapped=0; //for our testing purposes
//int i=-1;


//*************************
//FUNCTIONS
//*************************

void setup()
{
Serial.begin(9600);
pickUpTelephone(); //start talking to processing
//get normal reading for light sensors to have a way to tell if the person is blocking the left or right sides or not
baseIRLA=analogRead(irlA);
baseIRLB=analogRead(irlB);
baseIRRA=analogRead(irrA);
baseIRRB=analogRead(irrB);
basePressureReadingA=analogRead(proxyA);
basePressureReadingB=analogRead(proxyB);
}

//call up Processing to make sure that it is ready to get info
void pickUpTelephone() {
while (Serial.available() <= 0) { Serial.println(666); // send a starting message delay(300); } } void loop() { if (Serial.available() > 0) {
int inByte = Serial.read(); // read the incoming byte from processing

//IF person my person is standing in front of the kiosk
//figure out if the other person is and if so, react to their movements, otherwise react to my person's
pressureReadingB=analogRead(proxyB);
if((pressureReadingB-basePressureReadingB)>60){
// if (Serial.available() > 0) {
// int inByte = Serial.read(); // read the incoming byte from processing
pressureReadingA=analogRead(proxyA); //read pressure sensor for other person
if((pressureReadingA-basePressureReadingA)>60) { //if other person is standing in front of their kiosk...
//read from other person's sensors
currentBaseL=baseIRLA;
currentBaseR=baseIRRA;
currentSensorL=irlA;
currentSensorR=irrA;
}//end if other person is close
else {
//reset left and right sensors and base readings to my person
currentBaseL=baseIRLB;
currentBaseR=baseIRRB;
currentSensorL=irlB;
currentSensorR=irrB;
}//end else if other person isn't close

//see if whichever person we are paying attention to is moving to the left or right or neither
//we are treating the possibility of someone breaking both beams as if they only broke the left one for simplicity's sake
newIRL=analogRead(currentSensorL); //read the left sensor
newIRR=analogRead(currentSensorR); //read the right sensor

if((currentBaseL-newIRL)>20) { //if left is blocked
Serial.println('l', DEC);
// Serial.print("Did we swap? ");
// Serial.println(swapped);
}//end if person broke left beam
else if((currentBaseR-newIRR)>20) { //if right is blocked
Serial.println('r', DEC);
}//end if person broke right beam
else {
Serial.println('m', DEC); //m for middle IE person is close but not breaking either side beam
// Serial.print("Is A broken? ");
// Serial.println(swapped);
}//end default for reacting to person


// }//end if serial available
}//end if my person is close

else {
Serial.println('d', DEC); //tell processing to go back to the default video
// Serial.print("Is A broken? ");
// Serial.println(swapped);
}

}//end if serial available

delay(10);
} //end loop



Processing
import processing.serial.*; // import the Processing serial library
Serial myPort; // The serial port
import processing.video.*;

//initialize movie variables
Movie myComeHitherMovie;
Movie myMiddleMovie;
Movie myLeftMovie;
Movie myRightMovie;

boolean firstContact = false; // Whether we've heard from the microcontroller
int thisIsNotAstring=999999;

//set the window size and which movie variable holds which movie
void setup()
{
size(720, 480);
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);

// read bytes into a buffer until you get a linefeed (ASCII 10):
myPort.bufferUntil('\n');

myComeHitherMovie = new Movie(this, "comeHither.mov");
myComeHitherMovie.loop();

myMiddleMovie = new Movie(this, "arrow.mov");
myMiddleMovie.loop();

myLeftMovie = new Movie(this, "funkychicken.mov");
myLeftMovie.loop();

myRightMovie = new Movie(this, "waveHand.mov");
myRightMovie.loop();

}

//I'm not sure, but I think this tells the movie to keep looking for the next frame...
void movieEvent(Movie m) {
m.read();
}

//the main loop, which plays a movie depending on which key you press (since I don't have my Ardy here)
//these correspond to the letters Ardy is sending to Processing
void draw()
{

} //end draw

void serialEvent(Serial myPort) {
// read the serial buffer:
String myString = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {

myString = trim(myString);

// if you haven't heard from the microncontroller yet, listen:
if (firstContact == false) {
if (myString.equals("666")) {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
}
}
// if you have heard from the microcontroller, proceed:
else {
// println(myString);
/* if (myString=="d"){
thisIsNotAstring=1;
}//end if d
else if (myString=="m"){
thisIsNotAstring=2;
}//end if m
else if (myString=="l"){
thisIsNotAstring=3;
}//end if l
if (myString=="r"){
thisIsNotAstring=4;
}//end if r
println(thisIsNotAstring); */

thisIsNotAstring=int(myString);
// println(thisIsNotAstring);
switch (thisIsNotAstring){
case 100:
image(myComeHitherMovie, 0, 0);
break;
case 109:
image(myMiddleMovie, 0, 0);
break;
case 108:
image(myLeftMovie, 0, 0);
break;
case 114:
image(myRightMovie, 0, 0);
break;
default:
fill(66,66,0);
ellipse(200, 80, 200, 40);
break;
}//end switch case

myPort.write("A");
}
// when you've parsed the data you have, ask for more:

}
}

This method uses the handshake protocol as described in the second serial lab.

Debugging.

Our two biggest issues were:

A- Getting Processing to recognize the variable we were passing it.
We had to declare the variable as a DEC. So that it could be read in processing. Initially the ASCII value was being read as a string and it wouldn't allow the Case Swtich to work. we tried a ParseInt but it didn't work. Still recognized it as a String. DEC solved the issue.

B- The handshake was not working because we forgot to instruct the Arduino code to pass the "/n" to Processing. It only interating through the loop once. This caused a big headache but with help, we sorted it out.

C- The last bug that remains unresolved is once the inputs swtich. Whichever kiosk is approached first is the one that will drive BOTH outputs, they do not swtich as planned. They do swtich however at the Arduino output level. It is not a circuit issue but a coding one.

This project was interesting because I feel that it does have the ability to promote interaction in a public space. In a final build of the design, the next step of the interaction would need two people to take place. But I could also see an more playful exercise of havving the kiosks in totally seperate locations and making the interactions more varied and complex. A person could be engaging with a person in another location for several minutes before realizing they are playing with someone else as opposed to the computer. Having that person be far away (the further the better) could start a thought provoking dialogue about connections , anonymity and isolation.

Wednesday, February 18, 2009

Servo Lab

Giving my Mom a special shout out this week for helping me talk it out.

I am really interested in biophilic design. While this aesthetic has several different characteristics, I find natural light to be one of the most important
of the lot.
In urban environments natural light must be optimised for both plants and people.
The idea for this week was to build a device that measures the strongest light source, and then orients itself towards that brightest value.

The device itself was pretty straightforward:
  • A box for the Servo to sit in
  • A tube for the photo sensor
    (a small bit of sponge to mount the photo sensor)

  • a little wire to mount the tube onto the box



The majority of my tinkering was relegated to the code.

The first iteration was just creating a for loop that controlled the sweep of the servo.

#include // include the servo library

Servo servoMotor; // creates an instance of the servo object to control a servo

int servoPin = 9; // Control pin for servo motor, must be a PWM pin
// the value representing the angle of the servo


void setup()
{

servoMotor.attach(servoPin); // attaches the servo on pin 2 to the servo object

} //end setup

void loop()
{
for (int servoAng = 0; servoAng <= 180; servoAng++)
{
servoMotor.write(servoAng);
delay(15);
} //end for
// waits for the servo to get there
}// end loop

I continued adding pauses because I didn't want to be overwhelmed by sensor values. So I had the servo move in 10 degree increments. Then I was going to make a variable for each one (Ham fisted).



#include // include the servo library

Servo servoMotor; // creates an instance of the servo object to control a servo

int analogPin = 0; // the analog pin that the sensor is on

int analogValue = 0; // the value returned from the analog sensor

int servoPin = 9; // Control pin for servo motor, must be a PWM pin
// the value representing the angle of the servo


void setup()
{

servoMotor.attach(servoPin); // attaches the servo on pin 2 to the servo object

} //end setup

void loop()
{
int servoAng = 0;
int sensArray [18];
servoAng = 0;
servoMotor.write(servoAng);
sensArray[0] = analogValue;

delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[0] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[1] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[2] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[3] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[4] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[5] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[6] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[7] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[8] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[9] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[10] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[11] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[12] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[13] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[14] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[15] = analogValue;
delay(1000);

servoAng = servoAng + 10;
servoMotor.write(servoAng);
sensArray[16] = analogValue;
delay(1000);

/* for (int servoAng = 0; servoAng <= 180; servoAng = servoAng+10) { servoMotor.write(servoAng); delay(1000); // this value is important because there is a minimum time the servo needs to return to it's point of origin }end for delay(10000); // set this delay to control reevaluation interval }// end loop

Having already informed my lab partner Laura C. that I am to be beat about the head and shoulders for such madness, I realized I needed to rethink my plan.

I decided to use an Array, to store the analog value. Using the Servo Degree (degCount) as the driver of the element indexing. This saved me from having to negotiate a multi-dimensional array. I Got some much needed clarity from
Craig Kapp and came up with this:





#include // include the servo library

Servo servoMotor; // creates an instance of the servo object to control a servo

int analogPin = 0; // the analog pin that the sensor is on
int analogValue = 0; // the value returned from the analog sensor

int servoPin = 9; // Control pin for servo motor, must be a PWM pin
// the value representing the angle of the servo


void setup()
{

servoMotor.attach(servoPin); // attaches the servo on pin 2 to the servo object

} //end setup

void loop()
{
/* Survey */
int capAng[180]= {0};
int degCount;

for (int degCount = 0; degCount <= 180; degCount++) { servoMotor.write(degCount); capAng[degCount] = analogRead(analogPin); delay(15); } //end suurvey int brightVal=0; int brightestDeg=0; for (int degCount = 0; degCount <= 180; degCount++) { if(capAng[degCount] > brightVal)
{
brightVal= capAng[degCount];
brightestDeg= degCount;
}//end if that evaluates brightest value and corresponding Angle
}// end analysis for loop

servoMotor.write(brightestDeg);
delay(10000);
}// end Loop
















Wednesday, February 11, 2009

Electronics Lab

My Lab Partner this week was Laura Ciporen.

With 4 AA batteries before the voltage regulator: 5.48, with regulator: 4.46
With 12V power supply, before regulator: 17.13, with regulator: 5.01
12V, regulator, 220ohms resistor, 1 LED: voltage across the resistor: 3.15, voltage across the LED: 1.79 (when switch is off, all V=0)
  • 3LEDs in series: V across resistor: .12, across 1st LED:1.63, across 2nd LED: 1.63, across 3rd:1.62
  • 3LEDs in series, no resistor: 1.68, 1.68, 1.67
  • Amperage measurements, 2LEDs in series, 220ohm resistor 12v power, power regulator: second LED=4.83mA, 1st LED=4.81mA, resistor=4.84mA




  • 3LEDs in parallel: resistor=3.2, all 3 LEDs=1.71


Goofy problem: we were using a push button switch and thought we were using a momentary switch. When we plugged the LED in, it lit up and we were confused but then pushed the switch and it went off so all is right with the world.

Notes to us: We discovered that to measure the resistance of a resistor (or other component) you have to remove it from the circuit (no power connected).
NOTE:When measuring the voltage across components, place the leads of the volt meter on the actual components, not into the board ( yields a more consistent reading).

  • We tried adding a 4th LED in series but none lit up.
We think this is because the minimum voltage required to light the red LEDs (the ones we were using) is 1.6 according to Mims.
  • Then we tried 3 green ones (min 2.2v) to test our hypothesis about the red ones and they did not light up.
  • Two green ones did. Confirming our theory.
The starting point for the LEDs to light up varies for LED color: 1.54 for red, 1.74 for yellow & green

Questions:
  • If we measure the voltage by putting the leads of the volt meter into the breadboard, what are we measuring?
  • When we do this and turn off the switch, the voltage across the resistor jumps to 3.64. That makes no sense to us.
  • When we were using the pot we were getting readings of 1.54 with the red LED. Then we switched to a yellow LED without touching the pot and got readings of 1.64. Why is that?
    -Different LEDs draw different amounts of current. So the Pot will draw have less Voltage to drop in it's resistor.

Wednesday, February 4, 2009

Observations

My partner for this was Andy Jordan

We left NYU around midday and went through Soho.

For the most part we saw people using phones, which at this point do not seem to require much concentration, it is something people do mindlessly. Clearly the goal is to contact people, which seems to happen effortlessly.
We went into the Apple Store where we saw people interacting with a variety of devices

Clock Radios: One person
Many of the people when interacting with them would often press the largest button on the device no matter what it did. "Eject, On/Off Volume". We both observed that they kind of "pecked" at them.
Wireless Checkout: Two people
Some Apple merchants were checking people out with there purchases. The transactions took about 120 seconds. I think it works well because the buyer does not have to make that trip to the Cashier. I can say for myself I have walked out of line (especially that line) several times putting my purchase back. This device helps to eliminate that impulse.

Genius Bar Line Queue: Multiple people
The line queue at the genius bar is managed by a sales associate armed with a laptop. users go to him and check in which takes about 10 seconds. This information is passed on the "Geniuses" which call up the people in the line. This allows people to queue in a more casual manner. Instead of having to physically stand in a line. They can mill about, saving energy.

Back on the street:
People listening to ipods and using their phones. Maybe it would be more interesting if people were lolly gagging in the warm weather but most people were moving about their business, not doing much

Week Two


Again my Partner this week was Laura Ciporen.

When we first reached out for this week's task we realized that our projects while different, could share identical code. We wanted to separate the analog values into ranges that would assign different outputs to each range.

In my case, I wanted to build a device that would measure the amount of finger pressure required to open a jar.

-A jar that is loose would register as Yellow.
-A jar that is the proper tightness would register as Green
-A jar that is too tight would glow Red.

Here is the code.

# define YelLED 2
# define GreLED 3
# define RedLED 4
# define HandSens 5
int HandVAL = 0;

void setup()
{
pinMode (YelLED,OUTPUT);
pinMode (GreLED,OUTPUT);
pinMode (RedLED,OUTPUT);
beginSerial(9600);
} //end setup

void loop()
{
HandVAL=analogRead(HandSens);
HandVAL=HandVAL/4; // converting value from 10bit to 8bit
Serial.println(HandVAL);
if (HandVAL <= 85)
{
analogWrite(YelLED,HandVAL+85);
digitalWrite(GreLED,LOW);
digitalWrite(RedLED,LOW);
}// end if
else if (HandVAL >= 85 && HandVAL <= 170)
{
digitalWrite(YelLED,LOW);
analogWrite(GreLED,HandVAL);
digitalWrite(RedLED,LOW);
}
else if (HandVAL >= 170)
{
digitalWrite(YelLED,LOW);
digitalWrite(GreLED,LOW);
analogWrite(RedLED,HandVAL);
}
else
{
digitalWrite(YelLED,HIGH);
digitalWrite(GreLED,HIGH);
digitalWrite(RedLED,HIGH);
}


delay(10);
}//end loop

You will see that we were hoping for each LED to ramp up in brightness as the analog value increased.
On our first observation the 1st LED in the analog range did not light up at all. The middle one seemed to show a visible varience in brightness and the third was bright with no ramping.
We realized that the by tying the output value to the sensor value HandVAL=analogRead(HandSens)
the lowest range would not be visible. So we added to the value
HandVAL+85
In an effort to "boost" it's brightness.

After further observation, it was determined that the lowest value LED did not even reach the threshold for lighting until the sensor was already through half of it's range. We tried remapping the values so that the threshold was the baseline.
This solution bore no fruit.
If the issue was one purely of computational origin the "boost" in the value should have resolved the issue. Since it did not, we began to look for other potential factors.

Since the LED was on a Digital Switch any brightness variance would need to be achieved using PWM. At the same time the LED has a minimum current (sustained current) to cross the junction within it.

We tried decoupling the 1:1 ratio of the sensor value to the LED output using various mathematical functions to try and give a better spread for the PWM but none of it seemed to produce any visible change in the brightness.

1- PWM is not good enough to display a difference?
2-perhaps there is a mathematical function that will solve this?

issue:
Middle LED seems to be the only with dynamic range (through very small)
1st and 3rd LEDs in series seem Binary.
How to Decouple brightness range from if/else switch range.
Hypotheses
1- PWM is not good enough to display a difference?
2-perhaps there is a mathematical function that will solve this?


Dap-O-Meter from Brian Jones on Vimeo.

FINAL

Untitled from Brian Jones on Vimeo.