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.- Fire animation >> Generative animation using Perlin noise
- Fire animation>> Color pallet
-
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.
- “a” key is pressed:
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; } }