Skip to content

16. Interface and application programming

Assignment

  • Group assignment
    compare as many tool options as possible

  • Individual assignment write an application that interfaces with an input &/or output device that you made

Group Assignment

Individual Assignment

Planning

I planned to design an application using Processing for my final project.

Scenario:

  • INPUT
    Processing application interfaces with sensor boards I created at week#14 and gets light data via serial.
  • OUTPUT
    Processing application displays flame animation, and the size of fire changes according to the light value.
  • INTERACTION
    When I put a fire wood branch into a hole of the table I created at week#8, the size of flame animation increases.

Sensor test

The sensor boards were networked and the value was visualized using Processing application at week14.

  • Sensor Boards

  • Graph @ Processing @ week14

  • Video The graph changes when a sensor board is covered.

Fire animation

  • Research
    I referred to some processing codes below and combined/modified them to fit my final project.

  • Calibration
    As the light condition depends on the location, I added the function that measure the light condition at normal state and covered state ( wood branch is inserted in a hole ).

    • “a” key is pressed:
      The average of light value at normal state will be detected.
    • “s” key is pressed:
      The average of light value when the board is covered will be detected.

First Animation

The size of flame changes between normal state value and covered state value.

Second Animation

Since common noise value was used for all boards, the movement of flames looked same. So I improved the program so that the noise values for each board were separated and allowed to move individually.

Interaction

Processing code (Second Animation)

//----------------------------------------------------------
// Flame r2
//----------------------------------------------------------

import processing.serial.*;

PVector[] offset1;
PVector[] offset2;

float scale = 0.01;
color c1, c2;
int[] flame_palette; // flame colors
float[] R = {150,150,150,150,150};  //Flame radius

float nz=0.01;  // noise for color
float step=0.02;

//---------
Serial myPort;  // Create object from Serial class
int val;      // Data received from the serial port
int cnt= 0;

int ltL=0;  // sensor data low
int ltH=0;  // sensor data high
int ltDat=0; // sensor data

int node = 0;   
int[] nodeID = {'1','2','3','4','5'};

boolean reqDat=false;

float eps = 0.5;
float[] filter = {0,0,0,0,0};

final int MDstart = 0;    // application mode
final int MDclbOpn = 1;
final int MDclbCls = 2;
final int MDnormal = 3;
int appMode=MDstart;

float[] clbOpn = {0,0,0,0,0}; // calibration normal status
float[] clbCls = {0,0,0,0,0}; // calobration covered status
boolean isClbOpn = false;
boolean isClbCls = false;
int clbCnt=0;
int clbNum=10;  // Average of 10 times

//---- setup ------------------------------------------------

void setup(){
  size(1920, 1080);
  noStroke();
  offset1 = new PVector[5];
  offset2 = new PVector[5];

  for (int i=0; i<5; i++){
  offset1[i] = new PVector(random(10000), random(10000));
  offset2[i] = new PVector(random(10000), random(10000));

}
  colorMode(RGB);

  // generate flame color palette 
   flame_palette = new int[256];
   for (int i=0; i<64; i++)
    {
      flame_palette[i]  = color(i<<2, 0, 0, i<<3);      // Black to red
      flame_palette[i+64]  = color(255, i<<2, 0); // Red to yellow
      flame_palette[i+128]  = color(255, 255, i<<2); // Yellow to white,
   //   flame_palette[i+192]  = color(255, 255, 255);   // White
      flame_palette[i+192]  = color(255, i<<1, 0);   // Red again
    }

  myPort = new Serial(this, "/dev/cu.usbserial-A90808PQ", 9600);  // Mac

}

//---- draw ------------------------------------------------

void draw(){
  background(0);
  sendAdd();   // send address to board

  switch(appMode){
    case MDstart:
        fill(255, 255, 255);
        textSize(16);
         text("Please calibrate   a: open mode   s: close mode" , 100, 100);
        break;
    case MDclbOpn:
        fill(255, 255, 255);
        textSize(16);
        text("Calibration Open Mode" , 100, 100);
        text("clbOpn[0]="+clbOpn[0]+"    clbCls[0]="+clbCls[0], 100,150);
        text("clbOpn[1]="+clbOpn[1]+"    clbCls[1]="+clbCls[1], 100,200);
        text("clbOpn[2]="+clbOpn[2]+"    clbCls[2]="+clbCls[2], 100,250);
        text("clbOpn[3]="+clbOpn[3]+"    clbCls[3]="+clbCls[3], 100,300);
        text("clbOpn[4]="+clbOpn[4]+"    clbCls[4]="+clbCls[4], 100,350);
        break;

    case MDclbCls:
        fill(255, 255, 255);
        textSize(16);
        text("Calibration Close Mode" , 100, 100);
        text("clbOpn[0]="+clbOpn[0]+"    clbCls[0]="+clbCls[0], 100,150);
        text("clbOpn[1]="+clbOpn[1]+"    clbCls[1]="+clbCls[1], 100,200);
        text("clbOpn[2]="+clbOpn[2]+"    clbCls[2]="+clbCls[2], 100,250);
        text("clbOpn[3]="+clbOpn[3]+"    clbCls[3]="+clbCls[3], 100,300);
        text("clbOpn[4]="+clbOpn[4]+"    clbCls[4]="+clbCls[4], 100,350);
      break;

    case MDnormal:
      drawFlame(0, width / 5, height / 5, R[0]);
      drawFlame(1, width*3 / 5, height / 5, R[1]);
      drawFlame(2, width*1 / 5, height*3 / 5, R[2]);
      drawFlame(3, width*3 / 5, height*3 / 5, R[3]);
      drawFlame(4, width*2/5, height*2/5, R[4]);
      break;
  }

}

//---- draw  Flame------------------------------------------------

void drawFlame(int i, int xx, int yy, float RR){
  pushMatrix();
  translate(xx, yy);

  for(float radious = RR; radious > 0; radious -= 2){

    float c = noise(nz)*RR;
    nz += step;  
    fill(flame_palette[int(c)]);

    beginShape();
    for(float angle = 0; angle < 360; angle += 0.5){
      float radian = radians(angle);  
      float x = radious * cos(radian);
      float y = radious * sin(radian);

      float nx = x + map(noise(x * scale + offset1[i].x, y * scale + offset1[i].y, frameCount * 0.015), 0, 1, -200, 200);
      float ny = y + map(noise(x * scale + offset2[i].x, y * scale + offset2[i].y, frameCount * 0.015), 0, 1, -200, 200);

      vertex(nx, ny);
    }
    endShape(CLOSE);
  }
  popMatrix();

}

//---- Serial Interupt ------------------------------------------------
void serialEvent(Serial myPort) {
  readLight();

}


//---- Read Light sensor data ------------------------------------------

void readLight(){  
 val = myPort.read();         // read it and store it in val

  switch(cnt){     
      case 0:
      ltL = val;
      cnt = 1;
      break;

   case 1:
      ltH = val;     
      ltDat = 256*ltH + ltL;
      filter[node] = (1-eps)*filter[node] + eps*ltDat;
       println ("light" + node + "= " + filter[node]);  

      cnt = 0;
      reqDat=false;

      chkCalib();

      node++;
      node=node%5;

      break;   
  }



}

//---- Send board address  ------------------------------------------

void sendAdd(){
  if(!reqDat){

        myPort.write( nodeID[node]); 
        println ("write node"+ node + "=" + nodeID[node]);  
       reqDat=true;
  }
}
//---- Callibration  ------------------------------------------

void chkCalib(){
  if(isClbOpn && appMode != MDclbOpn)
  {  appMode=MDclbOpn;
     clbCnt=0;
     for(int i=0; i<5; i++){
       clbOpn[i]=0;
     }
  }
  if(isClbCls && appMode != MDclbCls)
  {  appMode=MDclbCls;
     clbCnt=0;
     for(int i=0; i<5; i++){
       clbCls[i]=0;
     }
  }


  switch(appMode){
    case MDclbOpn:
       if(isClbOpn){
            clbOpn[node]+=filter[node];
            println ("calib open bord " + node +"=" + clbOpn[node]);
            clbCnt++;
            if(clbCnt == 5*clbNum){
              for(int i=0; i<5; i++){
               clbOpn[i]=clbOpn[i]/clbNum;
               }
               clbCnt=0;
              println ("calib open finished");
             isClbOpn = false;
          }
       }
      break;

    case MDclbCls:
      if(isClbCls){
         clbCls[node]+=filter[node];
          println ("calib close bord " + node +"=" + clbCls[node]);
          clbCnt++;
        if(clbCnt == 5*clbNum){
          for(int i=0; i<5; i++){
             clbCls[i]=clbCls[i]/clbNum;
           }
         clbCnt=0;
          println ("callib close finished");
         isClbCls = false;
        } 
      }
       break;
     case MDnormal:  
        if(filter[node]<clbOpn[node]){filter[node]=clbOpn[node];}
        if(filter[node]>clbCls[node]){filter[node]=clbCls[node];}   
          R[node]=map(filter[node],clbOpn[node],clbCls[node],50,160);
       break; 
  }

}


void keyPressed(){

  if (key == 'a'){
    println ("a is pressed");
    isClbOpn = true;
    isClbCls = false;

  }

  if (key == 's'){
    println ("s is pressed");
    isClbOpn = false;
    isClbCls = true;

  }

  if (key == 'd'){
    appMode = MDnormal;
     isClbOpn = false;
     isClbCls = false;

    println ("d is pressed");
    //   node=0;

  }

 }

Files