Kinetic Interface – Midterm Project (Emerald)

Course Name: Kinetic interface

Instructor: Moon

Partner: Ribirth

  • Description

Basically our project is an educational hotpot game. It shows players different time that different food need to be cooked in a hotpot. We use leap motion to enable the grab gesture of the player, so it gives a more physical sense of use chopsticks to get the food.

We have two stages, the first has a start button, and player should grab to start the game (also a “grab to start” instruction shown above the button). The second stage is the main gaming part, which contains all those food, hotpot, timer, and so on. We use “switch-case” to function the change of the stage. When you run the project, the default stage is stage 0 (the button part), and when it detects your grab gesture, it will switch to stage 1, which is the game part.

  

As you can see in the demo video at the bottom of this documentation, there is a timer on the right-top corner. If you grab different food to put into the pot, you will see the timer runs in different speed (because the time bar goes in same speed), which thus can show how long you have put certain food in the hotpot. The timer, as well as the time bar, will not start counting time until you put a food into the pot. Also, once it starts cooking, there will be words showing conditions of food under the time bar. For instance, at first it shows “NOT YET!”, some time later it shows “Ready!”, and if you still don’t take out the food, it will show “OVERCOOKED!”.

  • Process & Difficulties

The Process of this game is: grab the food – put the food into the pot – wait to take out the food from the pot – eat it/throw it away. I did meet many problems when coding this whole process. Fortunately we finally found the way to solve these problems.

In terms of grabing the food, the biggest problem at first is the food you grab can only be displayed within the certain range. I find the reason is because I have wrote the code “if (dist1 < 50 && HG > 0.6)” (dist1 stands for the distance between chopsticks and the plate of meat; HG stands for hand grab strength). To display the food you grab, we choose to stick every single image of different food to the chopsticks’ position, and tint the opacity to 0, so that the food images are transparent at first, and when you grab, the opacity will be tint again to 300. In this case, I find that there should be a bigger if statement outside “if (dist1 < 50 && HG > 0.6)”, which is “if (opacity1 == 0)”. So once you grab the food, the opacity changes to 300, and the “dist1 < 50” will not be the constrain any more.

We also think a lot about how to start cooking another food when you finish the previous one. For example, the pot range is 100 pixel from the center point, and you move the food to 100 – 200 pixel means you take out the food, more than 200 means you throw the food away. But this may cause a mess when playing the game. We also think of swipe to throw away, but finally we decide to stick to the grab gesture. Not only because we already have the HG variable, which can be much easier to code, but also loosening hand to let go the food makes more sense. So if HG is less than 0.6, the opacity I mentioned above will be tint again to 0, as well as the timer and time bar.

  • Other

We also add some effects to make the game more interesting.

  1. We add background music and “game start” sound effect.
  2. If you take out the food prematurely, you will see a sad face appear on the screen, and the color of food remains unchanged. If you take out the food on time, the color will slightly change and a smiling face will appear. If you take out it overcooked, sad face appear again and the color will turn to black.
  • Future Improvments

As the feedbacks during presentation, it will be better if we adjust the perspective of the pot. We can also add more sounf effects when putting the food into the pot. Maybe also add bubbles on the pot to create a sense of boiling.

  • Demo

import processing.sound.*;
SoundFile file;
SoundFile readyFile;
SoundFile no;
SoundFile yes;

//import
//  ddf.minim.*; 
//Minim minim;  
//AudioPlayer player; 



int stage = 0;
int time = 0;
int foodtime = 0; 


float opacity1 = 0;
float opacity2 = 0;
float opacity3 = 0;
float opacity4 = 0;
float opacity5 = 0;
float opacity6 = 0;


float handX, handY;
float HG;

PFont myFont;
PImage background;
PImage clock;
PImage star;
PImage timebar;
PImage start;
PImage table;

PImage meat;
PImage cabbage;
PImage shiitake;
PImage crab;
PImage goat;
PImage meatball;

PImage meat1;
PImage cabbage1;
PImage shiitake1;
PImage crab1;
PImage goat1;
PImage meatball1;

PImage pot;
PImage chopstick1;
PImage chopstick2;

PImage success;
PImage fail;


void setup() {


  size(600, 600);
  background(255);

  leapMotion_setup();
  myFont = createFont("Skia-Regular_Bold", 32);
  textFont(myFont);

  file = new SoundFile(this, "bgm.mp3");
  file.loop();
  //minim = new
  //  Minim(this); 
  readyFile = new SoundFile(this, "ready.mp3");
  no = new SoundFile(this, "no.mp3");
  yes = new SoundFile(this, "yes.mp3");


  background = loadImage("background.jpg");
  start = loadImage("start.png");
  table = loadImage("table.jpg");

  meat = loadImage("meat.png");
  cabbage = loadImage("cabbage.png");
  shiitake = loadImage("shiitake.png");
  crab = loadImage("crab.png");
  goat = loadImage("goat.png");
  meatball = loadImage("meatball.png");

  pot = loadImage("pot.png");
  chopstick1 = loadImage("chopstick.png");
  chopstick2 = loadImage("chopstick.png");

  meat1 = loadImage("meat1.png");
  cabbage1 = loadImage("cabbage1.png");
  shiitake1 = loadImage("shiitake1.png");
  crab1 = loadImage("crab1.png");
  goat1 = loadImage("goat1.png");
  meatball1 = loadImage("meatball1.png");

  timebar = loadImage("timebar.png");
  star = loadImage("star.png");
  clock = loadImage("clock.png");
  success = loadImage("success.png");
  fail = loadImage("fail.png");
}

void draw() {



  leapMotion_draw();



  switch( stage ) {
  case 0: 
    stage_opening();
    break;
  case 1:
    stage_play();

    break;
  case 2:
    break;
  }
}




void stage_opening() {

  pushMatrix();
  background(background);
  imageMode(CENTER);
  translate(width/2, height/2);
  scale(0.5);
  image(start, 0, 0);
  popMatrix();
  
  stroke(10);
  fill(252, 98, 80);
  text("Crab to Strat!",200,200);

  if (HG>0.6) {
    readyFile.play();
    pushMatrix();
    background(background);
    //background(255);
    imageMode(CENTER);
    translate(width/2, height/2);
    scale(0.4);
    image(start, 0, 0);
    //player.play();
    popMatrix(); 
    time ++;
    println(time);
    if (time>10) {
      stage = 1;
    }
  }
}

// add interaction here

//if (mousePressed) {
//  stage = 1;
//}
//background(255, 255, 0);
//fill(255);
//text("StartPage", 10, 20);



void stage_play() {
  background(255);
  image(table, 0, 0, width*2, height*2);
  image(meat, 70, 200, 100, 100);
  image(cabbage, 70, 350, 100, 100);
  image(shiitake, 540, 200, 100, 100);
  image(crab, 540, 350, 100, 100);
  image(goat, 210, 470, 100, 100);
  image(meatball, 400, 470, 100, 100);
  image(timebar, 250, 170, 700, 500);


  pushStyle();
  imageMode(CENTER);
  image(pot, width/2, height/2, 369, 232);
  popStyle();

  pushMatrix();
  pushStyle();
  translate(handX, handY);
  rotate(PI/1.2);
  imageMode(CENTER);
  image(chopstick1, 0, 15, 150, 15);
  popStyle();
  popMatrix();

  pushMatrix();
  pushStyle();
  translate(handX, handY);
  rotate(PI/1.1);
  imageMode(CENTER);
  image(chopstick2, 0, -15, 150, 15);
  popStyle();
  popMatrix();

  pushStyle();
  tint(255, 255, 255, opacity1);
  image(meat1, handX-60, handY+20, 40, 50);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity2);
  image(cabbage1, handX-60, handY+20, 40, 80);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity3);
  image(shiitake1, handX-60, handY+20, 30, 30);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity4);
  image(crab1, handX-60, handY+20, 40, 50);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity5);
  image(goat1, handX-60, handY+20, 50, 50);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity6);
  image(meatball1, handX-60, handY+20, 30, 30);
  popStyle();

  float dist1 = dist(handX, handY, 120, 200 );
  float dist2 = dist(handX, handY, 120, 350 );
  float dist3 = dist(handX, handY, 590, 220 );
  float dist4 = dist(handX, handY, 590, 370 );
  float dist5 = dist(handX, handY, 290, 490 );
  float dist6 = dist(handX, handY, 480, 480 );
  float dist_drop = dist(handX-30, handY+30, 300, 300);


  image(star, 50+foodtime*3, 115, 400, 400);
  image(clock, 520, 60, 140, 120);

 // ====  meat ==== //

  if (opacity1 == 0) {
    if (dist1 < 50 && HG > 0.6) {
      opacity1 = 300;
    }
  }
  if (opacity1 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
    text(foodtime/6, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity1 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity1);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity1-280);
    image(meat1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity1 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity1);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity1);
    image(meat1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity1 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity1);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity1 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity1 = 0;
  }


  // ====  cabbage ==== //


  if (opacity2 == 0) {
    if (dist2 < 50 && HG > 0.6) {
      opacity2 = 300;
    }
  }
  if (opacity2 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
    text(foodtime/2, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity2 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity2);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity2-280);
    image(cabbage1, handX-60, handY+20, 40, 80);
    popStyle();
  } else if (opacity2 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity2);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity2);
    image(cabbage1, handX-60, handY+20, 40, 80);
    popStyle();
  } else if (opacity2 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity2);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity2 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity2 = 0;
  }


  // ====  shiitake ==== //
  if (opacity3 == 0) {
    if (dist3 < 50 && HG > 0.6) {
      opacity3 = 300;
    }
  }
  if (opacity3 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
    text(foodtime/2, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity3 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity3);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity3-280);
    image(shiitake1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity3 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity3);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity3);
    image(shiitake1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity3 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity3);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity3 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity3 = 0;
  }

  // ====  crab ==== //
  if (opacity4 == 0) {
    if (dist4 < 50 && HG > 0.6) {
      opacity4 = 300;
    }
  }
  if (opacity4 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
  text(foodtime/3, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity4 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity4);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity4-280);
    image(crab1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity4 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity4);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity4);
    image(crab1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity4 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity4);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity4 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity4 = 0;
  }


  // ====  goat ==== //
  if (opacity5 == 0) {
    if (dist5 < 50 && HG > 0.6) {
      opacity5 = 300;
    }
  }
  if (opacity5 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
  text(foodtime/7, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity5 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity5);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity5-280);
    image(goat1, handX-60, handY+20, 50, 50);
    popStyle();
  } else if (opacity5 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity5);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity5);
    image(goat1, handX-60, handY+20, 50, 50);
    popStyle();
  } else if (opacity5 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity5);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity5 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity5 = 0;
  }


  // ==== meatball ==== //
  if (opacity6 == 0) {
    if (dist6 < 50 && HG > 0.6) {
      opacity6 = 300;
    }
  }
  if (opacity6 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
  text(foodtime/4, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity6 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity6);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity6-280);
    image(meatball1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity6 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity6);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity6);
    image(meatball1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity6 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity6);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity6 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity6 = 0;
  }
}

import de.voidplus.leapmotion.*;

LeapMotion leap;

void leapMotion_setup() {

  leap = new LeapMotion(this);
  
}


// ======================================================
// 1. 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");
}


void leapMotion_draw() {

  int fps = leap.getFrameRate();
  for (Hand hand : leap.getHands ()) {


    // ==================================================
    // 2. Hand

    int     handId             = hand.getId();
    PVector handPosition       = hand.getPosition();
    PVector handStabilized     = hand.getStabilizedPosition();
    PVector handDirection      = hand.getDirection();
    PVector handDynamics       = hand.getDynamics();
    float   handRoll           = hand.getRoll();
    float   handPitch          = hand.getPitch();
    float   handYaw            = hand.getYaw();
    boolean handIsLeft         = hand.isLeft();
    boolean handIsRight        = hand.isRight();
    float   handGrab           = hand.getGrabStrength();
    float   handPinch          = hand.getPinchStrength();
    float   handTime           = hand.getTimeVisible();
    PVector spherePosition     = hand.getSpherePosition();
    float   sphereRadius       = hand.getSphereRadius();

    // --------------------------------------------------
    // Drawing
    //hand.draw();
    
    handX = hand.getPosition().x;
    handY = hand.getPosition().y;
    
    HG = handGrab;

    // ==================================================
    // 3. Arm

    if (hand.hasArm()) {
      Arm     arm              = hand.getArm();
      float   armWidth         = arm.getWidth();
      PVector armWristPos      = arm.getWristPosition();
      PVector armElbowPos      = arm.getElbowPosition();
    }


    // ==================================================
    // 4. Finger

    Finger  fingerThumb        = hand.getThumb();
    // or                        hand.getFinger("thumb");
    // or                        hand.getFinger(0);

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

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

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

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


    for (Finger finger : hand.getFingers()) {
      // or              hand.getOutstretchedFingers();
      // or              hand.getOutstretchedFingersByAngle();

      int     fingerId         = finger.getId();
      PVector fingerPosition   = finger.getPosition();
      PVector fingerStabilized = finger.getStabilizedPosition();
      PVector fingerVelocity   = finger.getVelocity();
      PVector fingerDirection  = finger.getDirection();
      float   fingerTime       = finger.getTimeVisible();

      // ------------------------------------------------
      // Drawing

      // Drawing:
      // finger.draw();  // Executes drawBones() and drawJoints()
      //finger.drawBones();
      //finger.drawJoints();

      // ------------------------------------------------
      // Selection

      


      // ================================================
      // 5. Bones
      // --------
      // https://developer.leapmotion.com/documentation/java/devguide/Leap_Overview.html#Layer_1

      Bone    boneDistal       = finger.getDistalBone();
      // or                      finger.get("distal");
      // or                      finger.getBone(0);

      Bone    boneIntermediate = finger.getIntermediateBone();
      // or                      finger.get("intermediate");
      // or                      finger.getBone(1);

      Bone    boneProximal     = finger.getProximalBone();
      // or                      finger.get("proximal");
      // or                      finger.getBone(2);

      Bone    boneMetacarpal   = finger.getMetacarpalBone();
      // or                      finger.get("metacarpal");
      // or                      finger.getBone(3);

      // ------------------------------------------------
      // Touch emulation

      int     touchZone        = finger.getTouchZone();
      float   touchDistance    = finger.getTouchDistance();

      switch(touchZone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#" + fingerId + "): " + touchDistance);
        break;
      case 1: // Touching
        // println("Touching (#" + fingerId + ")");
        break;
      }
    }


    // ==================================================
    // 6. Tools

    for (Tool tool : hand.getTools()) {
      int     toolId           = tool.getId();
      PVector toolPosition     = tool.getPosition();
      PVector toolStabilized   = tool.getStabilizedPosition();
      PVector toolVelocity     = tool.getVelocity();
      PVector toolDirection    = tool.getDirection();
      float   toolTime         = tool.getTimeVisible();

      // ------------------------------------------------
      // Drawing:
       tool.draw();

      // ------------------------------------------------
      // Touch emulation

      int     touchZone        = tool.getTouchZone();
      float   touchDistance    = tool.getTouchDistance();

      switch(touchZone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#" + toolId + "): " + touchDistance);
        break;
      case 1: // Touching
        // println("Touching (#" + toolId + ")");
        break;
      }
    }
  }


  // ====================================================
  // 7. Devices

  for (Device device : leap.getDevices()) {
    float deviceHorizontalViewAngle = device.getHorizontalViewAngle();
    float deviceVericalViewAngle = device.getVerticalViewAngle();
    float deviceRange = device.getRange();
  }
}

Remade in China – Journal (Emerald)

10/25

I found market in China really a place that uses plenty of plastic bags and produces plastic waste everyday. Not like supermarkets and shops, sellers in a market don’t ask customers for money if customers want plastic bags. They will even use two plastic bags if you buy meat or something heavy. What’s more, in some markets, you can see wasted plastic bags everywhere on the ground. People they don’t care about the plastic waste, maybe because they are not aware of the plastic pollution.

10/30

I saw a video on Youtube about plastic recycling. It shows the process of turning plastic bottles into food grade plastic pallets.

   

11/1

In today’s class we made projects out of plastic waste, that we collected from a week. My group made a planet using those plastic cups, plastic bags, as well as starbuck straws. We first squeezed those plastic bags in order to make the core of the planet. Then we use hot glue to glue the cups to the core. These cups represents the short and tall buildings on the earth. Then we stuck starbuck straws onto the core, and also use scissor to cut a tree-like shape so that the straws look like trees.

After we’ve done it, we hang it to the fence as a decoration.

Video Response

Bag it is really a meaningful video about the over-usage of plastic bags/packages. After watching it, every time I go to a shop I will think of this video and all those images of plastic bags hurting the animals. However it is hard to avoid plastic in my daily life, but I can try to reduce the use of plastic bags. For instance if I buy something in Family Mart, the shopper will ask if I need a plastic bag and I will say no.

I was also surprised by the working conditions of melting and recycling plastic in Asian countries, and impressed by the word “But the human rights and labor issues related with that, and the toxicity issues of some of the open plastic melting that they do, to me that do not fit into a recycling model. It’s more important to reduce what we consume, and to reuse things that have already been made.” So in daily life we may use usable bottles, consume less plastic bottled drinks, use our own shopping bags. We may also reuse some plastic containers to store food or other things.

11/6 – short interview film

Partners: Kristine, Emma

Description: We decided to went to Jinqiao residential hall to look for Ayis who may know the process of waste recycling. But at first we encountered some problems. We asked if we can interview them or just ask several questions about their job, but the Ayis we found were not willing to talk about collecting garbages, let alone letting us record the interviewing process.

Fortunately, we finally found a work and an Ayi who agreed to be interviewed. They told us that in terms of Jinqiao Dorm, it actually has both inner workers and external workers. The inner workers are only responsible for collecting garbages within the dorm buildings, as well as cleaning the common areas on each floor. They would throw the garbages in a big garbage can outside the building, and the external workers will collect these garbages and categorize those garbages. Everyday there will be garbage truck coming to pick up those garbages and then carry them to garbage disposal station.

Link to our video: https://drive.google.com/file/d/1EhRnXtxi52cBBX8F2mnNLjAMLxhnIIOw/view?ts=5bea95c2

11/8

Today our group (Milly, Allison, and I) use different kinds of plastic packages and cut them into a rectangle shape, and then iron them together to get a thick, rectangle material. We also cut cat shape out of a kind of light-reflecting plastic package and iron them onto the thick rectangle. Then we use white pen to draw the outline of the cat, as well as their facial expressions. Finally we add two pieces as both the sides, and made it into a handbag.

We also noticed that when ironing, the temperature shouldn’t be too high and the iron cannot stay too long on the plastic, otherwise the plastic will be melted and lose its shape.

11/13

I saw a news on Weibo, which is a video of a delivery man teaching people how to unpack a box-packed package correctly, so that the box can be recycled. He says the express company he works in is going to recycle tens of millions of cardboard boxes during the period of “double 11”, and this amount to cut down 100 thousands trees fewer.

The link: https://m.weibo.cn/1974576991/4305082029640390

11/25

The person who filmed this video was trying to remake parts out of HDPE plastic. He heated the oven to 350 degree so that he can melt that plastic. HDPE plastic becomes soft at this degree, and can be easily shaped.

  

 

11/27 – final start

We tried to make a device that can cut plastic bottles into strings according to videos online, such as: https://www.youtube.com/watch?v=yLt-ebcNUnE

The first device we made just look like the thing in the picture above. But it didn’t work very well, that it is hard for us to hold the bottle, and the string it cut was uneven and easy to be broken. Then Marcela helps to adjust the interval between two screws to a more thiner interval, however, maybe because the blade is not sharp enough, or the patterns on the bottles we use are too complicated, the device we made cannot work well with the bottles.

11/29

After last class Marcela made another device that can cut bottles into strings. We tried it in today’s class but somehow still cannot cut perfect strings. I think the reason is the bottles we have are either too soft or having too many patterns, so it is really hard to control. But since there are some plastic strings ready to be use, Katie and I tried to knit the strings using the way of knitting a sweater.

12/4

Originally we wanted to weave the plastic like it shows in this video. We first drew every point of where the strings should be on this circle but then the problem that we encountered at this stage was that we found the plastic being too slippery, which was impossible for us to stabilize every string at right place.

      

We then thought of using a cardboard to replace the circle because we could actually cut through these points at different edges so that the string wouldn’t move. Unfortunately, it still didn’t work due to the inflexibility of the plastic string, that we could not make a knot on the plastic string. This entire process took us the entire class time, due to the lack of time, we thought that we could just use the plastic strings to make something that would retain its property.

12/6

Since we failed to weave plastic string on that circle last class, we decided to make a bucket this time. We found this picture of how to weave a bucket online as our guideline.

We followed the steps on this instruction and cut a big plastic bottle to make this flower shape thing. And then we cut plastic strings and weave the bucket. But for the reason that plastic is too slippery, it is really hard to keep the plastic strings still without moving. This time we use paper tape to tape the columns to enhance the force of friction and then we successfully did this plastic bucket.

12/11

We tried to make a bucket without the tape, so we cut another two bottles today. But the thing is due to so many patterns on the bottle, the string we used to braid didn’t fit well with the columns. What’s more, also because of the slippery plastic, the string would always slip away from those columns. So unfortunately we failed to make

12/13

Although we failed last time, we decide to try again today. This time we find two same bottles without patterns, which should be able to use the cutting tool to cut through.

We successfully get this plastic string by using this cutting tool. Then we also cut a bottle to make the bottom and columns part.

Finally we made this small basket with a handle on it!

PS: Definitely such a basket is not the only thing we can make from plastic strings. From this whole process I think the most important thing is that we’ve learned the techniques of knitting and braiding plastic strings into a real subject. We also think that if we could have a frame of a shape or a subject that we want to use the plastic string to knit/weave/braid into, then its availability can even be more widespread in the future. And since the plastic is really hard and steady, at least it can be knit/weave/braid into surfaces for furnitures like chairs, hammock, etc. In conclusion, having the chance to actually experience with different types of plastics really helped me to have an even deeper understanding of plastics.

Kinetic Interfaces – week 6: Leap Motion (Emerald)

For this assignment we are going to use the leap motion and to create some interaction between screen and hand movement. I’m really interested in the gesture, so I tried the grab gesture this time.

Basically I build a simple interaction, that user can move his hand and grab the small ball, which are randomly generated, on the screen. When you keep the grab gesture, you hold the ball in your hand and you can drag this ball to anywhere you want. Then if you loose your hand at this time, the ball will be placed at the certain point.

Because I only want a hand, without those text and the arm, to appear on the screen, I comment out the hand.draw(). And instead, I function the finger.drawBones(), so it will only show the finger bones on the screen. I also change the stroke weight of finger bones, so they may look more like a hand.

To function the grab gesture, I add a variable called HG to get the hand grab index, and if the index is larger than 0.6, the system will think you grab, then the ball will move with your hand.

if (dis1 < 50 && HG > 0.6){
balls.get(0).x = handX;
balls.get(0).y = handY;
}

if (dis2 < 50 && HG > 0.6){
balls.get(1).x = handX+10;
balls.get(1).y = handY+10;
}

float handX, handY;
float HG;


ArrayList<Ball> balls = new ArrayList<Ball>();

void setup() {
  size(600, 600);
  background(255);

  leapMotion_setup();

  for (int i=0; i<2; i++) {
    balls.add(new Ball(random(100, width-100), random(100, height-100), color(random(255), random(255), random(255))));
  }
}

void draw() {
  background(255);
  leapMotion_draw();


  for (int i=0; i<balls.size(); i++) {
    Ball b = balls.get(i);
    b.display();
  }

  float dis1 = dist(balls.get(0).x, balls.get(0).y, handX, handY);
  float dis2 = dist(balls.get(1).x, balls.get(1).y, handX, handY);
  
  if (dis1 < 50 && HG > 0.6){
    balls.get(0).x = handX;
    balls.get(0).y = handY;
  }
  
  if (dis2 < 50 && HG > 0.6){
    balls.get(1).x = handX+10;
    balls.get(1).y = handY+10;
  }
  
 
}


class Ball {
  float x, y;
  color c;

  Ball(float _x, float _y, color _c) {
    x = _x;
    y = _y;
    c = _c;
  }

  void display() {
    noStroke();
    fill(c);
    ellipse(x, y, 40, 40);
  }
}

import de.voidplus.leapmotion.*;

LeapMotion leap;

void leapMotion_setup() {

  leap = new LeapMotion(this);
  
}


// ======================================================
// 1. 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");
}


void leapMotion_draw() {

  int fps = leap.getFrameRate();
  for (Hand hand : leap.getHands ()) {


    // ==================================================
    // 2. Hand

    int     handId             = hand.getId();
    PVector handPosition       = hand.getPosition();
    PVector handStabilized     = hand.getStabilizedPosition();
    PVector handDirection      = hand.getDirection();
    PVector handDynamics       = hand.getDynamics();
    float   handRoll           = hand.getRoll();
    float   handPitch          = hand.getPitch();
    float   handYaw            = hand.getYaw();
    boolean handIsLeft         = hand.isLeft();
    boolean handIsRight        = hand.isRight();
    float   handGrab           = hand.getGrabStrength();
    float   handPinch          = hand.getPinchStrength();
    float   handTime           = hand.getTimeVisible();
    PVector spherePosition     = hand.getSpherePosition();
    float   sphereRadius       = hand.getSphereRadius();

    // --------------------------------------------------
    // Drawing
    //hand.draw();
    
    handX = hand.getPosition().x;
    handY = hand.getPosition().y;
    
    HG = handGrab;
    //println(HG);

    // ==================================================
    // 3. Arm

    if (hand.hasArm()) {
      Arm     arm              = hand.getArm();
      float   armWidth         = arm.getWidth();
      PVector armWristPos      = arm.getWristPosition();
      PVector armElbowPos      = arm.getElbowPosition();
    }


    // ==================================================
    // 4. Finger

    Finger  fingerThumb        = hand.getThumb();
    // or                        hand.getFinger("thumb");
    // or                        hand.getFinger(0);

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

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

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

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


    for (Finger finger : hand.getFingers()) {
      // or              hand.getOutstretchedFingers();
      // or              hand.getOutstretchedFingersByAngle();

      int     fingerId         = finger.getId();
      PVector fingerPosition   = finger.getPosition();
      PVector fingerStabilized = finger.getStabilizedPosition();
      PVector fingerVelocity   = finger.getVelocity();
      PVector fingerDirection  = finger.getDirection();
      float   fingerTime       = finger.getTimeVisible();

      // ------------------------------------------------
      // Drawing

      // Drawing:
      // finger.draw();  // Executes drawBones() and drawJoints()
      strokeWeight(14);
      finger.drawBones();
      //finger.drawJoints();

      // ------------------------------------------------
      // Selection

      


      // ================================================
      // 5. Bones
      // --------
      // https://developer.leapmotion.com/documentation/java/devguide/Leap_Overview.html#Layer_1

      Bone    boneDistal       = finger.getDistalBone();
      // or                      finger.get("distal");
      // or                      finger.getBone(0);

      Bone    boneIntermediate = finger.getIntermediateBone();
      // or                      finger.get("intermediate");
      // or                      finger.getBone(1);

      Bone    boneProximal     = finger.getProximalBone();
      // or                      finger.get("proximal");
      // or                      finger.getBone(2);

      Bone    boneMetacarpal   = finger.getMetacarpalBone();
      // or                      finger.get("metacarpal");
      // or                      finger.getBone(3);

      // ------------------------------------------------
      // Touch emulation

      int     touchZone        = finger.getTouchZone();
      float   touchDistance    = finger.getTouchDistance();

      switch(touchZone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#" + fingerId + "): " + touchDistance);
        break;
      case 1: // Touching
        // println("Touching (#" + fingerId + ")");
        break;
      }
    }


    // ==================================================
    // 6. Tools

    for (Tool tool : hand.getTools()) {
      int     toolId           = tool.getId();
      PVector toolPosition     = tool.getPosition();
      PVector toolStabilized   = tool.getStabilizedPosition();
      PVector toolVelocity     = tool.getVelocity();
      PVector toolDirection    = tool.getDirection();
      float   toolTime         = tool.getTimeVisible();

      // ------------------------------------------------
      // Drawing:
       tool.draw();

      // ------------------------------------------------
      // Touch emulation

      int     touchZone        = tool.getTouchZone();
      float   touchDistance    = tool.getTouchDistance();

      switch(touchZone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#" + toolId + "): " + touchDistance);
        break;
      case 1: // Touching
        // println("Touching (#" + toolId + ")");
        break;
      }
    }
  }


  // ====================================================
  // 7. Devices

  for (Device device : leap.getDevices()) {
    float deviceHorizontalViewAngle = device.getHorizontalViewAngle();
    float deviceVericalViewAngle = device.getVerticalViewAngle();
    float deviceRange = device.getRange();
  }
}

Digital Fab – Final Project (Emerald)

  • Process

During the proposal presentation I got a feedback that it may be better to change the base to a thing that user can hold, and I think it really makes sense. So I designed a hold for it and after I have the sketch, I started to build models in Rhino. The screwdriver should be divided into two parts, the spinning part and the hold. I made the hold top part hollow inside and also split it, so that I can put the spinning part inside.

Then I saved them as .STL file and send them to 3d-printer. After they are printed I noticed a thing, that the round-corners were not printed successfully. In order not to print the whole thing again (which takes a long time), I designed such two things to hold the handles.

  

I assembled all these things and used hot glue to strengthen the joints. I also take down the pointed part on a real screwdriver and glued it into the hole I made on the spinning part.

But now it is hard to let this screwdriver stand on the table. So finally I used the website “makercase”, and it gave me such a sketch according to the conditions I typed in. Then I added the circle on one of the sides to make a hole which can hold the screwdriver.

The whole thing looks like this:

 

  • Difficulties
  1. The quality of 3d printing is much lower than my expectation, so the things printed were not fit with each other. I had to try very hard to use emery paper to polish them.
  2. Next time I have to spend more time on modeling, because it is really important to take support into consideration. Some part I need it to be hollow, but at the same time hard to be printed without support. For this project I printed with support, and then I used tweezers, pliers, electric drill, etc, nearly everything to take off those supports. Really terrible.

Kinetic Interface – week 4+5: Pixels and Introduction to Computer Vision (Emerald)

For this assignment we need to program an interactive or alternated portraiture with pixel iteration or manipulation. So thinking of the bouncing ball, I decided to make a webcam which combines the bouncing feature.

Also, I wanted to create a sense of meteors, so I drew squares instead of ellipse. What’s more, because they are meteors, it is not good to create 1000 squares, in which case the squares will bounce everywhere and not looks like meteors at all. So I just created 300 squares, and at the same time adjust the opacity so that the trail of the moving square will last for a longer time.

I also make the pixel color random between a small range, so it may add a little bit color to the image.

Digital Fabrication – Assignment3: Using a 3D printer (Emerald Dou)

This assignment requires to make a 3D model in Rhino and then use the 3D printer to print the model out. I used the same 3D model I made in Rhino as my assignment 2.

So first I saved the model as STL file and send it to the computer which connects to the 3D printer. I scaled the model to 50mm width and applied the high quality file and then started printing. However, this time the model was able to be printed completely because the top part of the headphone is too thin, and I didn’t choose to add more support.

Then I decided to print a bigger one, adding more support to it as well. This time the printing process completed successfully, the only thing is I can’t take the support thing out.

    

Digital Fabrication – Final Project Proposal (Emerald Dou)

Instructor: Marcela

Project Title: Hand-friendly Screwdriver

  • Project Statement of Purpose

I bought a full-length mirror witch can stand on the ground online several weeks ago, and when I  received it I realized that I had to assemble it by myself. Although I finally did it, twisting so many screws using a normal screw driver really hurts my hand. In our daily life, it may be unescapable that we have to assemble something, like furniture, small tools, etc. As a result, a screw driver which won’t hurt user’s hand, as well as being easy to use seems to be necessary. So to prevent twisting screws from hurting hands, which is simple but is the chief purpose of my project, I decided to make a different type of screwdriver. It is easy to use and friendly to user’s hand. I would like to make it look like a little machine, with the head part of a screw driver in the front. There is also a handle in the back, so that I can turn the handle to get the head part spin, and then to twist the screws.

  • Literature and Art, Perspectives and Contexts

In the reading “Hybrid Reassemblage: An Exploration of Craft, Digital Fabrication and Artifact Uniqueness”, Amit Zoran and Leah Butchley talks about the restoration of broken art pieces. It shows a clear view of how they combine technology with broken pieces, such as the vast and the bowl they talked about in the article. No matter combining a real thing with technologies or combining different technologies together, it visually inspired me and tells me how can people combine things together.

I also searched online about digital fabrication projects, and I found a video on Youtube which shows the engines produced by 3d printing technology. The maker of this project prints out everything he needs for an engine and assembles them, and we can see these gears spin and work quite well with each other.

( https://www.youtube.com/watch?v=bhZv04JzE9I )

Basically this is the inspiration of my project, for the reason that it gives me a sense of rotation and I immediately think of the bad experience of using a screw driver.

 

  • Project Significance

First, compared to common screw driver, this project apparently reduces pain and pressure to user’s hand, for the reason that it only needs user to turn the handle instead of trying hard to twist screwdrivers. Second, compared to electric screwdriver, this one doesn’t need to be charged so you can use it anytime. It is also easier to control the strength you put, while electric screwdriver will possibly over twist the screws, causing certain degree of damage to materials.

Since it is still a screwdriver, it should be intended for people who love to or have to assemble/make things. Another group of potential audiences might be females. Because generally speaking females are physically less strong then males, so may be easier to feel hurt in doing such things.

  • Project Design & Production

Above is the sketch of my project. As you can see, it has a head part (which just looks the same as the pointed part of a screwdriver), a movable part, a handle, and a base. When using this device, the base will not move and can withstand the thing you are screwing. Only the movable part will move forward with the process of screwing the screw into the thing. Inside the movable case, there is a device that is fixed and also enables the rotation of the head and the handle. I plan to 3D print all these head, connecting rod, and the handle. For the shell (movable part and the base), I would like to use laser cutter to cut several pieces of board, and then put them up to make a box-like container.

Considering the movement, I have thought of a structure, and if you look from the side, it should look like this:

It allows only one horizontal direction movement, so that the movable part can only move forward and backward, and also won’t fall down from the base.

 

Digital Fabrication – Assignment 2 (Emerald Dou)

For this assignment I decided to build a headphone in Rhino.

So first I searched a picture online, and used “PictureFrame” command to insert the picture into Rhino.

Then according to the picture, I started to build a 3d headphone. I realized that because the headphone is symmetric, “mirror” command may be very useful in this case. Here I created half of the rectangles and mirror them, and then use the loft function, as well as “cap” to close two ends.

   

And same with other parts:

For the ear muff parts, it should have some space for ears. As a result, I drew a cylinder and then make it intersect with the ear muff. I subtract the muff with the cylinder, and it becomes like this, which is the final version.