Category: FinalProject

The Rambler

The Rambler is my second automaton, and what I consider my first real kinetic sculpture. The pieced consists of a Brother Electric Typewriter, a piece of tissue paper from a roll which it types onto, and the board that holds the control components.

_MG_8443

The text that the piece prints is selected from the last statements of former Death Row Inmates. I’ve had access to this data for a while, and have been working with it as a narrative subject for work for a while. It currently only uses a small number of phrases due to size restrictions.

IMG_8402

 

This project began with the simple goal of bypassing the keyboard of an electric typewriter. The technology has a wide variety of applications, and I intend to use this type of machine further, although I want to find some way to make the controller smaller. The current version using relays is visually impacting, but it overrides the piece performatively.

I began this project with no useful documentation on how to go about my task. I eventually  figured out that the typewriter runs off an 8×8 matrix that was held in a 16-pin header  normally connected to the keyboard. connecting any pin from the top 8 to one from the bottom 8 constituted a key press. It simply remained to automate this function.

IMG_1186

 

These notes (particularly the matrix) were what allowed me to make the piece function by reverse-engineering the matrix.

_MG_8426

I did make a frizzing diagram. It has been simplified for the sake of convenience. the two loose wires are a jumper that I had manually connect upon turning the typewriter on. The switch it connected to was a reset switch on the bottom of the keyboard.

RamblerFritz_bb

 

code:

String I[18] ={"I hope you let go of all of the hate because of all my actions.",
                "I came in as a lion and I come as peaceful as a lamb.",
                "I am at peace.",
                "I hope society sees who else they are hurting with this.",
                "I hope both victims find in their hearts to forgive me. ",
                "I have forgave everyone and I love everyone.",
                "I forgive myself.",
                "I love you all and I will be waiting for you all.",
                "I will be listening.",
                "I am ready Warden.",
                "I am sorry.", 
                "I love you all.", 
                "I am always going to be with you.",
                "I love you all,",
                "I love you all.",
                "I love you Father.",
                "I love you Father.",
                "I love you Savior."};
                
int latchPinA = 1;
int clockPinA = 8;
int dataPinA = 3;

int latchPinB = 2;
int clockPinB = 10;
int dataPinB = 5;

int latchPinC = 4;
int clockPinC = 11;
int dataPinC = 6;

int latchPinD = 7;
int clockPinD = 12;
int dataPinD = 9;
 
int writeA = 0;
int writeB = 0;
int writeC = 0;
int writeD = 0;

int del = 175;

int ll = 0;
char s;


void hitA(int val) {
   writeA += val; digitalWrite(latchPinA, LOW);
   shiftOut(dataPinA, clockPinA, MSBFIRST, writeA);  
   digitalWrite(latchPinA, HIGH); delay(del/2);
   writeA -= val; digitalWrite(latchPinA, LOW);
   shiftOut(dataPinA, clockPinA, MSBFIRST, writeA);  
   digitalWrite(latchPinA, HIGH); delay(del/2);
   ll += 1;
}

void hitB(int val) {
   writeB += val; digitalWrite(latchPinB, LOW);
   shiftOut(dataPinB, clockPinB, MSBFIRST, writeB);  
   digitalWrite(latchPinB, HIGH); delay(del/2);
   writeB -= val; digitalWrite(latchPinB, LOW);
   shiftOut(dataPinB, clockPinB, MSBFIRST, writeB);  
   digitalWrite(latchPinB, HIGH); delay(del/2);
   ll += 1;
}

void hitC(int val) {
   writeC += val; digitalWrite(latchPinC, LOW);
   shiftOut(dataPinC, clockPinC, MSBFIRST, writeC);  
   digitalWrite(latchPinC, HIGH); delay(del/2);
   writeC -= val; digitalWrite(latchPinC, LOW);
   shiftOut(dataPinC, clockPinC, MSBFIRST, writeC);  
   digitalWrite(latchPinC, HIGH); delay(del/2);
   ll += 1;
}

void hitD(int val) {
   writeD += val; digitalWrite(latchPinD, LOW);
   shiftOut(dataPinD, clockPinD, MSBFIRST, writeD);  
   digitalWrite(latchPinD, HIGH); delay(del);
   writeD -= val; digitalWrite(latchPinD, LOW);
   shiftOut(dataPinD, clockPinD, MSBFIRST, writeD);  
   digitalWrite(latchPinD, HIGH);
   ll += 1;
}

void holdShift() {
   writeD += 128; digitalWrite(latchPinD, LOW);
   shiftOut(dataPinD, clockPinD, MSBFIRST, writeD);  
   digitalWrite(latchPinD, HIGH); delay(del);
}

void liftShift() {
   writeD -= 128; digitalWrite(latchPinD, LOW);
   shiftOut(dataPinD, clockPinD, MSBFIRST, writeD);  
   digitalWrite(latchPinD, HIGH); delay(del);
}

void hitEnt() {
   hitD(64);
   delay(ll * 32);
   ll = 0;
}

void zeroRelays() {
  writeA = 0;
  writeB = 0;
  writeC = 0;
  writeD = 0;
  
  digitalWrite(latchPinA, LOW);
  shiftOut(dataPinA, clockPinA, MSBFIRST, 0);  
  digitalWrite(latchPinA, HIGH);
    
  digitalWrite(latchPinB, LOW);
  shiftOut(dataPinB, clockPinB, MSBFIRST, 0);  
  digitalWrite(latchPinB, HIGH);
    
  digitalWrite(latchPinC, LOW);
  shiftOut(dataPinC, clockPinC, MSBFIRST, 0);  
  digitalWrite(latchPinC, HIGH);
    
  digitalWrite(latchPinD, LOW);
  shiftOut(dataPinD, clockPinD, MSBFIRST, 0);  
  digitalWrite(latchPinD, HIGH);
  
  delay(del);
  
}

void setup() {
  //set pins to output so you can control the shift register
  pinMode(latchPinA, OUTPUT);
  pinMode(clockPinA, OUTPUT);
  pinMode(dataPinA, OUTPUT);
  
  pinMode(latchPinB, OUTPUT);
  pinMode(clockPinB, OUTPUT);
  pinMode(dataPinB, OUTPUT); 
  
  pinMode(latchPinC, OUTPUT);
  pinMode(clockPinC, OUTPUT);
  pinMode(dataPinC, OUTPUT);  
  
  pinMode(latchPinD, OUTPUT);
  pinMode(clockPinD, OUTPUT);
  pinMode(dataPinD, OUTPUT);
  
  zeroRelays();

}

// relay : 0  1  2  3  4  5  6  7 
// values: 1  2  4  8  16 32 64 128

void processString(String str){
  int len = str.length();
  for (int i = 0; i < len; i++){
    s = str.charAt(i);
    if(s == 'a'){
      hitA(1);
    } else if(s == 'b'){
      hitA(2);
    } else if(s == 'c'){
      hitA(4);
    } else if(s == 'd'){
      hitA(8);
    } else if(s == 'e'){
      hitA(16);
    } else if(s == 'f'){
      hitA(32);
    } else if(s == 'g'){
      hitA(64);
    } else if(s == 'h'){
      hitA(128);
    } 
      else if(s == 'i'){
      hitB(1);
    } else if(s == 'j'){
      hitB(2);
    } else if(s == 'k'){
      hitB(8);
    } else if(s == 'l'){
      hitB(4);
    } else if(s == 'm'){
      hitB(16);
    } else if(s == 'n'){
      hitB(32);
    } else if(s == 'o'){
      hitB(64);
    } else if(s == 'p'){
      hitB(128);
    } 
      else if(s == 'q'){
      hitC(1);
    } else if(s == 'r'){
      hitC(2);
    } else if(s == 's'){
      hitC(4);
    } else if(s == 't'){
      hitC(8);
    } else if(s == 'u'){
      hitC(16);
    } else if(s == 'v'){
      hitC(32);
    } else if(s == 'w'){
      hitC(64);
    } else if(s == 'x'){
      hitC(128);
    }
      else if(s == 'y'){
      hitD(1);
    } else if(s == 'z'){
      hitD(2);
    } else if(s == ','){
      hitD(4);
    } else if(s == '.'){
      hitD(8);
    } else if(s == '/'){
      hitD(16);
    } else if(s == ' '){
      if (ll > 55){
        hitEnt();
      } else {
        hitD(32);
      }
    }
    //------------------------CAPS------------------------------
      else if(s == 'A'){
      holdShift();
      hitA(1);
      liftShift();
    } else if(s == 'B'){
      holdShift();
      hitA(2);
      liftShift();
    } else if(s == 'C'){
      holdShift();
      hitA(4);
      liftShift();
    } else if(s == 'D'){
      holdShift();
      hitA(8);
      liftShift();
    } else if(s == 'E'){
      holdShift();
      hitA(16);
      liftShift();
    } else if(s == 'F'){
      holdShift();
      hitA(32);
      liftShift();
    } else if(s == 'G'){
      holdShift();
      hitA(64);
      liftShift();
    } else if(s == 'H'){
      holdShift();
      hitA(128);
      liftShift();
    } 
      else if(s == 'I'){
      holdShift();
      hitB(1);
      liftShift();
    } else if(s == 'J'){
      holdShift();
      hitB(2);
      liftShift();
    } else if(s == 'K'){
      holdShift();
      hitB(4);
      liftShift();
    } else if(s == 'L'){
      holdShift();
      hitB(8);
      liftShift();
    } else if(s == 'M'){
      holdShift();
      hitB(16);
      liftShift();
    } else if(s == 'N'){
      holdShift();
      hitB(32);
      liftShift();
    } else if(s == 'O'){
      holdShift();
      hitB(64);
      liftShift();
    } else if(s == 'P'){
      holdShift();
      hitB(128);
      liftShift();
    } 
      else if(s == 'Q'){
      holdShift();
      hitC(1);
      liftShift();
    } else if(s == 'R'){
      holdShift();
      hitC(2);
      liftShift();
    } else if(s == 'S'){
      holdShift();
      hitC(4);
      liftShift();
    } else if(s == 'T'){
      holdShift();
      hitC(8);
      liftShift();
    } else if(s == 'U'){
      holdShift();
      hitC(16);
      liftShift();
    } else if(s == 'V'){
      holdShift();
      hitC(32);
      liftShift();
    } else if(s == 'W'){
      holdShift();
      hitC(64);
      liftShift();
    } else if(s == 'X'){
      holdShift();
      hitC(128);
      liftShift();
    }
      else if(s == 'Y'){
      holdShift();
      hitD(1);
      liftShift();
    } else if(s == 'Z'){
      holdShift();
      hitD(2);
      liftShift();
    } else if(s == '?'){
      holdShift();
      hitD(16);
      liftShift();
    } else {
      hitD(32);
    }
  }
  hitEnt();
}

void loop() {  
  
  zeroRelays();
  
  for (int i = 0; i < 18; i++){
    String sub = I[i];
    processString(sub);
    delay(200); 
  }
  
}

 

 

 

 

 

Charlotte Stiles: Tiny Fits of Rage

Tiny Fits of Rage is a networked button. This is very ridged and hard to press as well as spiky, so it requires a lot of effort to push this button. When the user pushes this button hard enough it activates the webcam to capture three seconds of the user while they are still ferociously pushing this button. The three seconds of the users painful-concentration-button-pushing-face is then converted into a gif and automatically uploaded to a tumblr blog to be added to a gallery of painful faces, purposefully mislabeled as rage faces, since the two can be interchangeable.

My inspiration was this project called 3frames by Aaron Meyers, this is where the user was allowed to only take three photos of themselves, then the photos were made into gifs and added to their gallery of three-framed-gifs.

2015-02-09 02.01.14

The button is simply a pressure sensor incased in a hard plastic that is a bit flexible2015-02-09 02.05.45

The pins at the top are to increase the users grimace by making the user feel alittle pain on top of exertion.2015-02-09 02.05.12

2015-02-09 02.05.25
Tiny-fits-of-rage.tumblr.com

 

//importing temboo so i can post this to tumblr
import com.temboo.core.*;
import com.temboo.Library.Tumblr.Post.*;
// Create a session using your Temboo account application details
TembooSession session = new TembooSession("yourTembooUsername", "appName", "appKey");
//Library for converting the gif to B64, thanks to Kevin Buck from temboo for helping me out
import javax.xml.bind.DatatypeConverter;
//library for creating and exporting gif http://extrapixel.github.io/gif-animation/
import gifAnimation.*;
import processing.opengl.*;
GifMaker gifExport;
 
import processing.serial.*;
 
Serial myPort;        // The serial port

//capturing webcam
import processing.video.*;
Capture cam;
int gifNum=0;
boolean makeGif=false;
int startTime;
int elapsTime;
int once=1;
int makeGifHappenOnce;
float squeeze;
boolean dontFuckUpMyPort = true;

public void setup() {
  if (dontFuckUpMyPort ==true){
  size(320,240, OPENGL);
  frameRate(12);
  cam = new Capture(this, width,height,12);
  cam.start();
  println("gifAnimation " + Gif.version());
  myPort = new Serial(this, Serial.list()[2], 9600);
 // don't generate a serialEvent() unless you get a newline character:

  myPort.bufferUntil('\n');
  startTime=0;
  dontFuckUpMyPort=false;
  makeGifHappenOnce=1;
   }

  gifExport = new GifMaker(this, "export.gif");
  gifExport.setRepeat(0); // make it an endless animation
  

}
void captureEvent(Capture cam){
    cam.read();
}

void draw() {
  image(cam,0,0);
  dontFuckUpMyPort=false; 
  
  if (makeGif==true){
  gifExport.setQuality(5); // usually its at 10 but i need the file to be small for tumblr
  gifExport.setDelay(10);//again making the gif smaller
  gifExport.addFrame();
  }
  
  elapsTime = (millis() - startTime)/1000;//so elasped time starts over everytime someone hit the max pressure
  if (elapsTime==3){ //this is how long the gif will be time-wise
    if (once==0){
    stopGif();
    once=once+1;
    }
    }

}
////this is for getting the button information from arduino
void serialEvent (Serial myPort) {
 // get the ASCII string:
String inString = myPort.readStringUntil('\n');
 
 if (inString != null) {
 // trim off any whitespace:
 inString = trim(inString); 
 squeeze = float(inString);
 
 //setting it over inbetween people:
 if (squeeze==0){
 makeGifHappenOnce=0;
 }
 //make gif when someone squeezes the maximum amout
 if (squeeze > 230 && makeGifHappenOnce==0 && elapsTime > 5){ //if someone is squeezing hard and they havent totally let go and there wasnt a bug that would make the gif record over another gif
    makeGif=true;
    startTime = millis();// this resets elapsed time to 0
    once=0;
    makeGifHappenOnce++;

         }
     }

//  println(squeeze);
//  println(makeGifHappenOnce);
 }

void stopGif() {
  gifExport.finish();
  makeGif=false;
  println("gif saved");
  //converting the gif that was just saved in my data folder to base64
  byte b[] = loadBytes("export.gif"); 
  String b64 = DatatypeConverter.printBase64Binary(b);
  //posting it to tumblr via temboo
  runCreatePhotoPostWithImageFileChoreo(b64);
  //Hacky way to be able to re-create more than one gif per program run!
  setup();
}

//Below is temboo business
void runCreatePhotoPostWithImageFileChoreo(String b64) {
  // Create the Choreo object using your Temboo session
  CreatePhotoPostWithImageFile createPhotoPostWithImageFileChoreo = new CreatePhotoPostWithImageFile(session);

  // Set inputs
  createPhotoPostWithImageFileChoreo.setData(b64);
  createPhotoPostWithImageFileChoreo.setAPIKey("getYourOwn");
  createPhotoPostWithImageFileChoreo.setAccessToken("getYourOwn");
  createPhotoPostWithImageFileChoreo.setAccessTokenSecret("getYourOwn");
  createPhotoPostWithImageFileChoreo.setSecretKey("getYourOwn");
  createPhotoPostWithImageFileChoreo.setBaseHostname("tiny-fits-of-rage.tumblr.com");

  // Run the Choreo and store the results
  CreatePhotoPostWithImageFileResultSet createPhotoPostWithImageFileResults = createPhotoPostWithImageFileChoreo.run();
  
  // Print results
  println(createPhotoPostWithImageFileResults.getResponse());

}

circut13_bb

final project: Artificial Linings

IMG_5310

Working in combination with Maya Kaisth I created “Artificial Linings” a modern installation representative of sky landscapes. The second rendition of artificial linings that will feature the technology shown here will be up for viewing in the Ellis gallery from December 10-11th. PLEASE COME! :)

here is an example of the kinect in action!

here is a photo of the first rendition of artificial linings
IMG_8305

here’s a video of the first rendition

here’s my code!

import tsps.*;
TSPS tspsReceiver;
TSPSPerson[] previousPeople={};
float blueX=400;
float cyanY=550;
float pinkX=1000;
float tinyPinkY=300;
float tinyCyanY=1000;
float purpleX=1200;
float purpleY=300;
float whiteXTWO=1200;
float whiteYTWO=500;
boolean tinyPinkGoesUp=true;
boolean tinyCyanGoesUp=false;
boolean pinkGoingRight=true;
boolean whiteTWOGoingNE=true;
boolean goingRight=true;
boolean goingUp=true;
boolean goingNE=true;
boolean blueGoesRight=true;
boolean purpleGoesSW=true;
int whiteX=300;
int whiteY=displayHeight;


void setup()
{
  size(displayWidth,displayHeight);
  smooth();
  background(255,255,255);
  
  tspsReceiver= new TSPS(this, 12000);
};

//coment in the boolean thing when you're ready for full screen.
boolean sketchFullScreen() {
return true;}

float previousAverage=0;



void draw(){
   background(157,3,255);
   float diameter= displayWidth/1.5;
   noStroke();
   
   
   boolean fastPerson=false;
   float peopleSum=0;
   TSPSPerson[] currentPeople =tspsReceiver.getPeopleArray();
   if ((currentPeople.length!=0) && (previousPeople.length!=0))
   { for (int i=0; i<currentPeople.length; i++){
    // get person
    TSPSPerson currentPerson = currentPeople[i];
      for (int j=0; j<previousPeople.length; j++){
        TSPSPerson previousPerson = previousPeople[j];
        if (currentPerson.id==previousPerson.id)
          {
          float speed=sqrt(pow(currentPerson.velocity.x,2)+pow(currentPerson.velocity.y,2));
          peopleSum=peopleSum+speed;
      
        }      
      }  
   }
   }
  float averageSpeed=peopleSum/currentPeople.length; 
   previousPeople=currentPeople; 
   
   //left most big pink one
   fill(255,8,252,50);
   ellipse(pinkX-800,700,diameter-300,diameter-300);
   fill(255,8,252,50);
   ellipse(pinkX-800,700,diameter-250,diameter-250);
   fill(255,8,252,40);
   ellipse(pinkX-800,700,diameter-200,diameter-200);
   fill(255,8,252,40);
   ellipse(pinkX-800,700,diameter-150,diameter-150);
   fill(255,8,252,40);
   ellipse(pinkX-800,700,diameter-100,diameter-100);
   fill(255,8,252,40);
   ellipse(pinkX-800,700,diameter-50,diameter-50);
   fill(255,8,252,30);
   ellipse(pinkX-800,700,diameter,diameter);
   fill(255,8,252,30);
   ellipse(pinkX-800,700,diameter+50,diameter+50);
   fill(255,8,252,20);
   ellipse(pinkX-800,700,diameter+100,diameter+100);
   fill(255,8,252,10);
   ellipse(pinkX-800,700,diameter+150,diameter+150);
   fill(255,8,252,10);
   ellipse(pinkX-800,700,diameter+200,diameter+200);
   
   
   //dark blue one from darkest to lightest
   fill(69,3,255,30);
   ellipse(blueX,300,diameter-300,diameter-300);
   fill(69,3,255,30);
   ellipse(blueX,300,diameter-250,diameter-250);
   fill(69,3,255,20);
   ellipse(blueX,300,diameter-200,diameter-200);
   fill(69,3,255,20);
   ellipse(blueX,300,diameter-150,diameter-150);
   fill(69,3,255,10);
   ellipse(blueX,300,diameter-100,diameter-100);
   fill(69,3,255,10);
   ellipse(blueX,300,diameter-50,diameter-50);
   fill(69,3,255,10);
   ellipse(blueX,300,diameter,diameter);
   
   
  
   //cyan one
   fill(0,249,255,30);
   ellipse(100,cyanY,diameter-300,diameter-300);
   fill(0,249,255,20);
   ellipse(100,cyanY,diameter-250,diameter-250);
   fill(0,249,255,20);
   ellipse(100,cyanY,diameter-200,diameter-200);
   fill(0,249,255,20);
   ellipse(100,cyanY,diameter-150,diameter-150);
   fill(0,249,255,10);
   ellipse(100,cyanY,diameter-100,diameter-100);
   fill(0,249,255,10);
   ellipse(100,cyanY,diameter-50,diameter-50);
   fill(0,249,255,10);
   ellipse(100,cyanY,diameter,diameter);
   
  
 
     
     
  //another tiny white one it goes NE
   fill(255,255,255,40);
   ellipse(whiteXTWO,whiteYTWO,diameter-450,diameter-450);
   fill(255,255,255,40);
   ellipse(whiteXTWO,whiteYTWO,diameter-500,diameter-500);
      
   
    
   
  
  //pink one
   fill(255,8,252,50);
   ellipse(pinkX,700,diameter-300,diameter-300);
   fill(255,8,252,45);
   ellipse(pinkX,700,diameter-250,diameter-250);
   fill(255,8,252,40);
   ellipse(pinkX,700,diameter-200,diameter-200);
   fill(255,8,252,40);
   ellipse(pinkX,700,diameter-150,diameter-150);
   fill(255,8,252,40);
   ellipse(pinkX,700,diameter-100,diameter-100);
   fill(255,8,252,30);
   ellipse(pinkX,700,diameter-50,diameter-50);
   fill(255,8,252,30);
   ellipse(pinkX,700,diameter,diameter);
   fill(255,8,252,30);
   ellipse(pinkX,700,diameter+50,diameter+50);
   fill(255,8,252,20);
   ellipse(pinkX,700,diameter+100,diameter+100);
   fill(255,8,252,20);
   ellipse(pinkX,700,diameter+150,diameter+150);
   fill(255,8,252,20);
   ellipse(pinkX,700,diameter+200,diameter+200);
   
   
   //tiny black one
   fill(0,0,0,100);
   ellipse(whiteX,whiteY,diameter-450,diameter-450);
   fill(0,0,0,70);
   ellipse(whiteX,whiteY,diameter-500,diameter-500);
  
   //tiny blue one turned cyan
   fill(0,249,255,30);
   ellipse(blueX+300,300,diameter-700,diameter-700);
   fill(0,249,255,20);
   ellipse(blueX+300,300,diameter-650,diameter-650);
   fill(0,249,255,20);
   ellipse(blueX+300,300,diameter-600,diameter-600);
   fill(0,249,255,10);
   ellipse(blueX+300,300,diameter-550,diameter-550);
   fill(0,249,255,10);
   ellipse(blueX+300,300,diameter-500,diameter-500);
   fill(0,249,255,10);
   ellipse(blueX+300,300,diameter-450,diameter-450);
   
   
  
   //purple one
   fill(107,3,255,40);
   ellipse(purpleX-1600,purpleY+800,diameter-300,diameter-300);
   fill(107,3,255,40);
   ellipse(purpleX-1600,purpleY+800,diameter-250,diameter-250);
   fill(107,3,255,40);
   ellipse(purpleX-1600,purpleY+800,diameter-200,diameter-200);
   fill(107,3,255,30);
   ellipse(purpleX-1600,purpleY+800,diameter-150,diameter-150);
   fill(107,3,255,30);
   ellipse(purpleX-1600,purpleY+800,diameter-100,diameter-100);
   fill(107,3,255,20);
   ellipse(purpleX-1600,purpleY+800,diameter-50,diameter-50);
   fill(107,3,255,20);
   ellipse(purpleX-1600,purpleY+800,diameter,diameter);
   fill(107,3,255,20);
   ellipse(purpleX-1600,purpleY+800,diameter+50,diameter+50);
   fill(107,3,255,20);
   ellipse(purpleX-1600,purpleY+800,diameter+100,diameter+100);
   fill(107,3,255,20);
   ellipse(purpleX-1600,purpleY+800,diameter+150,diameter+150);
   fill(107,3,255,10);
   ellipse(purpleX-1600,purpleY+800,diameter+200,diameter+200);
   
   
   //left dark blue one from darkest to lightest
   fill(170,3,255,30);
   ellipse(blueX-1100,300,diameter-300,diameter-300);
   fill(170,3,255,30);
   ellipse(blueX-1100,300,diameter-250,diameter-250);
   fill(170,3,255,30);
   ellipse(blueX-1100,300,diameter-200,diameter-200);
   fill(170,3,255,20);
   ellipse(blueX-1100,300,diameter-150,diameter-150);
   fill(170,3,255,20);
   ellipse(blueX-1100,300,diameter-100,diameter-100);
   fill(170,3,255,20);
   ellipse(blueX-1100,300,diameter-50,diameter-50);
   fill(170,3,255,10);
   ellipse(blueX-100,300,diameter,diameter);
   
   
   //tiny pink one
   fill(255,8,252,50);
   ellipse(400,tinyPinkY,diameter-700,diameter-700);
   fill(255,8,252,50);
   ellipse(400,tinyPinkY,diameter-650,diameter-650);
   fill(255,8,252,40);
   ellipse(400,tinyPinkY,diameter-600,diameter-600);
   fill(255,8,252,40);
   ellipse(400,tinyPinkY,diameter-550,diameter-550);
   fill(255,8,252,40);
   ellipse(400,tinyPinkY,diameter-500,diameter-500);
   fill(255,8,252,20);
   ellipse(400,tinyPinkY,diameter-450,diameter-450);
   
   
   //purple one
   fill(107,3,255,50);
   ellipse(purpleX,purpleY,diameter-300,diameter-300);
   fill(107,3,255,40);
   ellipse(purpleX,purpleY,diameter-250,diameter-250);
   fill(107,3,255,30);
   ellipse(purpleX,purpleY,diameter-200,diameter-200);
   fill(107,3,255,30);
   ellipse(purpleX,purpleY,diameter-150,diameter-150);
   fill(107,3,255,20);
   ellipse(purpleX,purpleY,diameter-100,diameter-100);
   fill(107,3,255,20);
   ellipse(purpleX,purpleY,diameter-50,diameter-50);
   fill(107,3,255,20);
   ellipse(purpleX,purpleY,diameter,diameter);
   fill(107,3,255,20);
   ellipse(purpleX,purpleY,diameter+50,diameter+50);
   fill(107,3,255,20);
   ellipse(purpleX,purpleY,diameter+100,diameter+100);
   fill(107,3,255,20);
   ellipse(purpleX,purpleY,diameter+150,diameter+150);
   fill(107,3,255,10);
   ellipse(purpleX,purpleY,diameter+200,diameter+200);
     
   //tiny cyan one
   fill(0,249,255,5);
   ellipse(800,tinyCyanY,diameter-600,diameter-600);
   fill(0,249,255,5);
   ellipse(800,tinyCyanY,diameter-550,diameter-550);
   fill(0,249,255,5);
   ellipse(800,tinyCyanY,diameter-500,diameter-500);
   fill(0,249,255,5);
   ellipse(800,tinyCyanY,diameter-450,diameter-450);
   fill(0,249,255,5);
   ellipse(800,tinyCyanY,diameter-400,diameter-400);
   fill(0,249,255,5);
   ellipse(800,tinyCyanY,diameter-350,diameter-350);
   fill(0,249,255,5);
   ellipse(800,tinyCyanY,diameter-300,diameter-300);
 
 float A=0.90;
 float B=1.0-A;
  
 previousAverage=previousAverage*A+(15*averageSpeed)*B;
 fill(0,0,0,previousAverage);
 rect(0,0,displayWidth,displayHeight);
     
   
  if(whiteTWOGoingNE==true)
   {
      whiteXTWO=whiteXTWO+10;
      whiteYTWO=whiteYTWO-10;
      if (whiteYTWO<-100){
         whiteTWOGoingNE=false;}
   }
   else
   {
      whiteXTWO=whiteXTWO-10;
      whiteYTWO=whiteYTWO+10;
      if (whiteYTWO>displayHeight+250){
          whiteTWOGoingNE=true;
      }
   }
 
   //white one that goes SW even though its boolean is called goingNE 
   if(goingNE==true)
   {
      whiteX=whiteX+10;
      whiteY=whiteY+10;
      if (whiteX>=1600){
         goingNE=false;}
   }
   else
   {
      whiteX=whiteX-10;
      whiteY=whiteY-10;
      if (whiteX<-300){
          goingNE=true;
      }
   }
   
      
   //tinypinkgoesUP!!!!
  if(tinyPinkGoesUp==true)
   {
     tinyPinkY=tinyPinkY-1.4;
     if (tinyPinkY<-200)
     {
       tinyPinkGoesUp=false;}
       
   }
   else
   {
     tinyPinkY=tinyPinkY+1.4;
     if (tinyPinkY>displayWidth+200)
     {
       tinyPinkGoesUp=true;}
   }

   
   //cyan one
   if(goingUp==true)
   {
     cyanY=cyanY-2;
     if (cyanY<-100){
        goingUp=false;}
   }
   else
   {
     cyanY=cyanY+2;
     if (cyanY>displayHeight+200)
     { 
       goingUp=true;}
   }

//pink goes right
  if(pinkGoingRight==true)
  {
     pinkX=pinkX+2;
     if (pinkX>1000){
       pinkGoingRight=false;}
   }
   else
   {
     pinkX=pinkX-2;
     if (pinkX<50){
       pinkGoingRight=true;
     }
   }
  
//the tiny middle cyan one goes up weeeeeeee 
  if(tinyCyanGoesUp==true)
  {
      tinyCyanY=tinyCyanY+2;
      if (tinyCyanY<50){
        tinyCyanGoesUp=false;}
  }
  else
  {
      tinyCyanY=tinyCyanY-2;
      if (tinyCyanY>displayHeight+200){
        tinyCyanGoesUp=true;
     }
  }
  
  
  if(blueGoesRight==true)
  {
    blueX=blueX+1.5;
    if (blueX>displayWidth+350){
      blueGoesRight=false;}
  }
  else
  {
    blueX=blueX-1.5;
    if (blueX<-350){
    blueGoesRight=true;
    }
  }
  
  //purplegoes SW!!!!!
  if(purpleGoesSW==true)
  {
    purpleX=purpleX-14;
    purpleY=purpleY+7;
    if (purpleY>displayWidth+350){
      purpleGoesSW=false;}
  }
  else
  {
    purpleX=purpleX+14;
    purpleY=purpleY-7;
    if (purpleY<-500){
    purpleGoesSW=true;
    }
  }
     
   //tinypinkgoesUP!!!!
  if(tinyPinkGoesUp==true)
   {
     tinyPinkY=tinyPinkY+1.4;
     if (tinyPinkY<-200)
     {
       tinyPinkGoesUp=false;}
       
   }
   else
   {
     tinyPinkY=tinyPinkY-1.4;
     if (tinyPinkY<-200)
     {
       tinyPinkGoesUp=true;}
   }
}
Written by Comments Off on final project: Artificial Linings Posted in FinalProject

Final Project Alex Walker

Finger Painting: The Painter’s Technological Aid

For this final project, I wanted to create something that I could potentially use in my painting practice. The first day we talked about sensors, I was fascinated by the idea of being able to control color with the movements of one’s body. Its original intent was to be a library for color that the painter had at his or her disposal in cause they could not think of the right color to use. It then progressed into a light source that cause the pigmentation in the painting to change color as you control the color with your hand. This hopefully would create interesting compositions while the artist is painting because the shapes and colors being shown would be changing constantly. I used the LeapMotion hand tracking sensor as my primary tool.  Using the code that translated the information from the sensor to processing, I used the coordinates of the palm to be connected to the elves of red, green, and blue.  Red is controlled by the movement on the x axis, Green by the movement ion the y axis, and Blue by the movement on the z axis.

import de.voidplus.leapmotion.*;
boolean sketchFullScreen() {
return true;}

LeapMotion leap;

void setup(){
  size(displayWidth, displayHeight, OPENGL);
  background(255);
  // ...

  leap = new LeapMotion(this);
}

void draw(){
  background (255);
  // ...
  int fps = leap.getFrameRate();


  // ========= HANDS =========
    
  for(Hand hand : leap.getHands()){


    // ----- BASICS -----
        
    int     hand_id          = hand.getId();
    PVector hand_position    = hand.getPosition();
    PVector hand_stabilized  = hand.getStabilizedPosition();
    PVector hand_direction   = hand.getDirection();
    PVector hand_dynamics    = hand.getDynamics();
    float   hand_roll        = hand.getRoll();
    float   hand_pitch       = hand.getPitch();
    float   hand_yaw         = hand.getYaw();
    boolean hand_is_left     = hand.isLeft();
    boolean hand_is_right    = hand.isRight();
    float   hand_grab        = hand.getGrabStrength();
    float   hand_pinch       = hand.getPinchStrength();
    float   hand_time        = hand.getTimeVisible();
    PVector sphere_position  = hand.getSpherePosition();
    float   sphere_radius    = hand.getSphereRadius();

  
    // ----- SPECIFIC FINGER -----
        
    Finger  finger_thumb     = hand.getThumb();
    // or                      hand.getFinger("thumb");
    // or                      hand.getFinger(0);

    Finger  finger_index     = hand.getIndexFinger();
    // or                      hand.getFinger("index");
    // or                      hand.getFinger(1);

    Finger  finger_middle    = hand.getMiddleFinger();
    // or                      hand.getFinger("middle");
    // or                      hand.getFinger(2);

    Finger  finger_ring      = hand.getRingFinger();
    // or                      hand.getFinger("ring");
    // or                      hand.getFinger(3);

    Finger  finger_pink      = hand.getPinkyFinger();
    // or                      hand.getFinger("pinky");
    // or                      hand.getFinger(4);        


    // ----- DRAWING -----
        
    hand.draw();
    // hand.drawSphere();
    // println(hand.getPosition());

    float myhandx = hand.getPosition().x;
    float myhandy = hand.getPosition().y;
    float myhandz = hand.getPosition().z;
    //println ("myhandx = " + myhandx); 
    //println ("myhandy="+myhandy);
    println ("myhandz="+myhandz);
    float myred = map(myhandx, 0,displayWidth, 0,255); 
    float mygreen= map(myhandy, 0,displayHeight, 0,255);
    float myblue= map(myhandz, 110,-25, 0,255);
    background (myred, mygreen, myblue);
    //fill (myred, mygreen,myblue); 
    //rect(0,0, displayWidth, displayHeight); 
    //textSize(displayHeight/2);
    //text("color", 100, displayHeight/2); 
    //fill(mygreen,myblue,myred);

    // ========= ARM =========
        
    if(hand.hasArm()){
      Arm     arm               = hand.getArm();
      float   arm_width         = arm.getWidth();
      PVector arm_wrist_pos     = arm.getWristPosition();
      PVector arm_elbow_pos     = arm.getElbowPosition();
    }
    


    // ========= FINGERS =========
        
    for(Finger finger : hand.getFingers()){
      
      
      // ----- BASICS -----
            
      int     finger_id         = finger.getId();
      PVector finger_position   = finger.getPosition();
      PVector finger_stabilized = finger.getStabilizedPosition();
      PVector finger_velocity   = finger.getVelocity();
      PVector finger_direction  = finger.getDirection();
      float   finger_time       = finger.getTimeVisible();


      // ----- SPECIFIC FINGER -----
            
      switch(finger.getType()){
        case 0:
          // System.out.println("thumb");
          break;
        case 1:
          // System.out.println("index");
          break;
        case 2:
          // System.out.println("middle");
          break;
        case 3:
          // System.out.println("ring");
          break;
        case 4:
          // System.out.println("pinky");
          break;
      }


      // ----- SPECIFIC BONE -----
            
      Bone    bone_distal       = finger.getDistalBone();
      // or                       finger.get("distal");
      // or                       finger.getBone(0);
            
      Bone    bone_intermediate = finger.getIntermediateBone();
      // or                       finger.get("intermediate");
      // or                       finger.getBone(1);
            
      Bone    bone_proximal     = finger.getProximalBone();
      // or                       finger.get("proximal");
      // or                       finger.getBone(2);

      Bone    bone_metacarpal   = finger.getMetacarpalBone();
      // or                       finger.get("metacarpal");
      // or                       finger.getBone(3);
            
            
      // ----- DRAWING -----
            
      // finger.draw(); // = drawLines()+drawJoints()
      // finger.drawLines();
      // finger.drawJoints();


      // ----- TOUCH EMULATION -----
            
      int     touch_zone        = finger.getTouchZone();
      float   touch_distance    = finger.getTouchDistance();
      
      switch(touch_zone){
        case -1: // None
          break;
        case 0: // Hovering
          // println("Hovering (#"+finger_id+"): "+touch_distance);
          break;
        case 1: // Touching
          // println("Touching (#"+finger_id+")");
          break;
        }
      }
    
    
      // ========= TOOLS =========
        
      for(Tool tool : hand.getTools()){
      
      
        // ----- BASICS -----
            
        int     tool_id           = tool.getId();
        PVector tool_position     = tool.getPosition();
        PVector tool_stabilized   = tool.getStabilizedPosition();
        PVector tool_velocity     = tool.getVelocity();
        PVector tool_direction    = tool.getDirection();
        float   tool_time         = tool.getTimeVisible();
      
      
        // ----- DRAWING -----
            
        // tool.draw();
      
      
        // ----- TOUCH EMULATION -----
            
        int     touch_zone        = tool.getTouchZone();
        float   touch_distance    = tool.getTouchDistance();
      
        switch(touch_zone){
          case -1: // None
            break;
          case 0: // Hovering
            // println("Hovering (#"+tool_id+"): "+touch_distance);
            break;
          case 1: // Touching
            // println("Touching (#"+tool_id+")");
            break;
        }
      }
  }
  
  
  // ========= DEVICES =========
    
  for(Device device : leap.getDevices()){
    float device_horizontal_view_angle = device.getHorizontalViewAngle();
    float device_verical_view_angle = device.getVerticalViewAngle();
    float device_range = device.getRange();
  }
    
}

// ========= CALLBACKS =========

void leapOnInit(){
  // println("Leap Motion Init");
}
void leapOnConnect(){
  // println("Leap Motion Connect");
}
void leapOnFrame(){
  // println("Leap Motion Frame");
}
void leapOnDisconnect(){
  // println("Leap Motion Disconnect");
}
void leapOnExit(){
  // println("Leap Motion Exit");
}

Feathered Vessel

Participants pilot a feathered vessel (more commonly known as a pigeon) by gently turning their faces in the direction in which they’d like to travel. Feathered Vessel creates an odd intersection between the militaristic concept of surveillance drones and the more mystic concept of becoming/taking control of an animal.

Click here for concepts and sketches from a nascent version of this project.

IMG_0089IMG_0087

Now for the technical stuff.

mapview3pigeonMapsMerged copyMINIMIZEDAbove is a significantly scaled down image of Feathered Vessel‘s map. It’s a composite of a bunch of satellite photos taken from 500 feet up. The map is 10,000 pixels by 10,000 with a DPI of 72. Initially, I thought I’d need to split the map into tiles and load them depending on where the view screen was, but Processing was able to handle the strain of repositioning the entire image every frame.

FaceOSC was used to sense the x and y rotations of participant’s faces. As FaceOSC is unable to sense faces in profile, I had to spend a lot of time making sure that side-to-side movement covered enough distance to prevent participants from turning their heads too far in an attempt to move further in a particular direction. I’ve come to appreciate the fine line between gimmicky controls and sleek movement.

In its current iteration, Feathered Vessel tracks face position, the map’s position, and time. If I were to build upon this project, I would try to implement a more complex event system where crossing certain thresholds causes various animated occurrences to happen, such as a car that speeds down a road or a field that caches on fire.

The code from this project can be found below. (Note: It won’t do much without its art assets. Feel free to contact me if you’d like access to them.)

//Miranda Jacoby
//EMS Interactivity Section A
//majacoby@andrew.cmu.edu
//Copyright Miranda Jacoby 2014

//Big thanks to Golan Levin for showing me how to use inputs from
//Kyle McDonald's FaceOSC program. 

import oscP5.*;
OscP5 oscP5;

float px, py; 
float vx, vy; 
int opacity;
int fTimer, countdown;
int moveVal, moveVal2, moveVal3;

boolean hasStarted;

int     found;
PVector poseOrientation = new PVector();

PImage map;
PImage falcon;
PImage falcon2;
PImage shadow;

//----------------------------------
void setup() {
  size(1920, 1080);//, OPENGL);
  
  map = loadImage("pigeonMapsMerged.png");
  falcon = loadImage("falcon.png");
  falcon2 = loadImage("falcon2.png");
  shadow = loadImage("falconShadow3.png");
  imageMode(CENTER);

  oscP5 = new OscP5(this, 8338);
  oscP5.plug(this, "found", "/found");
  oscP5.plug(this, "poseOrientation", "/pose/orientation");
  
  px = width /2; 
  py = height/2;
  vx = 0; 
  vy = 0;
 //falcon timer reset 
  countdown = 3000;//8000; //3500;
  //falcon movement reset
  moveVal = 0;
  moveVal2 = 0;
  moveVal3 = 0;
  
  //Face will not be tracked until mouse is clicked.
  noLoop();


}

//----------------------------------
void draw() {
  background (0);

  float ox = poseOrientation.x;
  float oy = poseOrientation.y;
  float oz = poseOrientation.z;

  drawMap();

  //Values for scaling FaceOSC control
  float poseOrientationScaleFactor = 2.00;
  float velocityDamping = 0.92;
  
  vx = vx - oy*poseOrientationScaleFactor;
  vy = vy - ox*poseOrientationScaleFactor;
  
  vx = vx * velocityDamping;
  vy = vy * velocityDamping;
  
  px = px + vx; 
  py = py + vy; 
  
  //println (nf(ox,1,3) + "\t" + nf(oy,1,3) + "\t" + nf(oz,1,3)); 
  falconTimer();
  falconEvent();
    if (px > 6000){
        px = 6000;
        
      }
    else if (px < -4000){         px = -4000;                }     else if (py > 5500){
        py = 5500;
        
      }
    else if (py < -4500){         py = -4500;                }       println("X: " + px);    println("Y: " + py);      //If it's been too long since a face was detected,   //decrement velocity and come to a stop.   int now = millis();   int elapsed = now - lastValidDataReceivedTime;   float slowDown = 0.45;   println ("The last time I received valid data was " + elapsed + " milliseconds ago.") ;   if (elapsed > 1000){
     vx = vx * slowDown;
     vy = vy * slowDown;
}

}
//---------------------------------

//Reset Values for new player
//when mouse is pressed and then released
void mouseClicked(){
  initVariables();
}  
//----------------------------------
//Initialize variables
void initVariables(){
  px = width /2; 
  py = height/2;
  vx = 0; 
  vy = 0;
 //falcon timer reset 
  countdown = 3000;//8000; 
  //falcon movement reset
  moveVal = 0;
  moveVal2 = 0;
  moveVal3 = 0;
  loop();
}
//----------------------------------
void drawMap()
{
  image(map, px, py);
}
//----------------------------------
void falconTimer()
{
 fTimer = millis() - countdown; //2 minutes
 if (countdown > 0){
 countdown = countdown - 1;
 }
 else if (countdown < 0){
   countdown = 0;
 }
 print("Countdown: " + countdown);
 
}
//----------------------------------
void falconEvent()
{
  if((countdown < 2001) & (countdown > 1600)){//3999)){
    //moveVal = 0;
    image(falcon,  vx + (width/3), (vy + (height)) - moveVal);
    moveVal = moveVal + 15;
         if(moveVal > 1600){
           moveVal = 1600; 
        }
     println("move: " + moveVal);
  }
  else if((countdown < 1001) & (countdown > 600)){//1999)){
    image(falcon2, (vx - (width/2))+ moveVal2, vy + (height/3));
    moveVal2 = moveVal2 + 15;
         if(moveVal2 > 10000){
           moveVal2 = 10000;
         } 
  }
  else if(countdown < 1){     //image(shadow, 0, 0 - moveVal3);     image(shadow, vx + (width/2), (vy + (2*height)) - moveVal3);     moveVal3 = moveVal3 + 20;          if(moveVal3 > 1600){
           moveVal3 = 1600; 
         }
  }
   println("PX: " + px);
   println("PY: " + py);
}
//----------------------------------
public void found (int i) { 
  found = i;
}
int lastValidDataReceivedTime = 0;
public void poseOrientation(float x, float y, float z) {
  poseOrientation.set(x, y, z);
  lastValidDataReceivedTime = millis();
}