Visual Crit – James Kyle

Description:

For this project, I aimed to create an interactive 8-bit type representation of a house that the user could interact with and change stuff about their environment with the interface. I decided to go with lights and represent their states in the virtual p5.js environment. The user can click the lamps in the virtual world and turn them on/off in the real world. The states of the lamps are reflected in the p5.js environment as well brightening up the surrounding environment when they are on. The user can also turn the lights on and off in the physical world and the light states would be again reflected in the virtual environment so the information goes both ways from p5.js to arduino and back.

No lights on
One lamp on
Both lamps on

 

Demo video:

https://youtu.be/KQ2YrnX2HL4http://

 

Circuit:

 

Arduino Code:

#include <string.h>

#define lamp1pin 10
#define lamp2pin 9
#define button1 3
#define button2 2


unsigned long debounceTimer1 = 0;
int debounceTime1 = 300;
bool DEBOUNCE1 = false;
bool firstCount1 = true;

unsigned long debounceTimer2 = 0;
int debounceTime2 = 300;
bool DEBOUNCE2 = false;
bool firstCount2 = true;


volatile int lamp1state = 0;
volatile int lamp2state = 0;


int inputData;

char buf[25];
String command;

int c;


void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);

  pinMode(lamp1pin, OUTPUT);
  pinMode(lamp2pin, OUTPUT);
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(button1), button1Pressed, CHANGE);
  attachInterrupt(digitalPinToInterrupt(button2), button2Pressed, CHANGE);

}


void button2Pressed() {
  if (!DEBOUNCE2) {
    DEBOUNCE2 = true;
    lamp2state = !lamp2state;
    digitalWrite(lamp2pin, lamp2state);
  }
}

void button1Pressed() {
  if (!DEBOUNCE1) {
    DEBOUNCE1 = true;
    lamp1state = !lamp1state;
    digitalWrite(lamp1pin, lamp1state);
  }
}

void loop() {

  int message1 = 10;
  int message2 = 20;

  //if main computer sent a command
  if ( Serial.available() > 0) {

    c = Serial.read();
    
//    if (c == 1) {
//      
//      digitalWrite(lamp1pin, HIGH);
//    }
    Serial.println(c);
    parseInput(c);
  }

  if (DEBOUNCE1 && firstCount1) {
    debounceTimer1 = millis();
    firstCount1 = false;
    message1 = 1 + lamp1state;
//    Serial.println(message1);
  }
  
  if (millis() - debounceTimer1 > debounceTime1) {
    DEBOUNCE1 = false;
    firstCount1 = true;
  }

  if (DEBOUNCE2 && firstCount2) {
    debounceTimer2 = millis();
    firstCount2 = false;
    message2 = 3 + lamp2state;
//    Serial.println(message2);
  }
  if (millis() - debounceTimer2 > debounceTime2) {
    DEBOUNCE2 = false;
    firstCount2 = true;
  }
  
  
}


void parseInput(int inputData) {


  int y = inputData;

    if (y == 1) { //1
      lamp1state = 1;
      digitalWrite(lamp1pin, HIGH);
    } else if (y == 2) { //2
      lamp1state = 0;
      digitalWrite(lamp1pin, LOW);
    }
    else if (y == 3) { //3
      lamp2state = 1;
      digitalWrite(lamp2pin, HIGH);
    } else if (y == 4) { //4
      lamp2state = 0;
      digitalWrite(lamp2pin, LOW);
    }

  
}

 

p5.js Code:

/*


- RGB to HSV Conversion Function from http://www.javascripter.net/faq/rgb2hsv.htm


*/




let serial;
let latestData = "waiting for data";
var outData;
var message;

let newFont;
let lightsEnable = true;

let x = 100;
let y = 100;

let width = 1700;
let height = 900;

let color = 300;
let baseSaturation = 40;
let baseBrightness = 30;

let table1X = 970;
let table2X = 630;
let table1Y = 200;

//Lightsource vector [on/off, x, y, Lamp Radius, Shine Radius]
let lightSources = [];

let updateLightSource = true;


function setup() {
  createCanvas(width, height);

  //Lamps initiation
  lightSources[0] = [0, table1X, table1Y, 40, 200];
  lightSources[1] = [0, table2X, table1Y, 40, 200];
  lightSources[2] = [0, table1X, table1Y, 40, 200];
  
  
  serial = new p5.SerialPort();

  serial.list();
  serial.open('/dev/tty.usbmodem14301');

  serial.on('connected', serverConnected);

  serial.on('list', gotList);

  serial.on('data', gotData);

  serial.on('error', gotError);

  serial.on('open', gotOpen);

  serial.on('close', gotClose);
}

function serverConnected() {
  print("Connected to Server");
 }
 
 function gotList(thelist) {
  print("List of Serial Ports:");
 
  for (let i = 0; i < thelist.length; i++) {
   print(i + " " + thelist[i]);
  }
 }
 
 function gotOpen() {
  print("Serial Port is Open");
 }
 
 function gotClose(){
  print("Serial Port is Closed");
  latestData = "Serial Port is Closed";
 }
 
 function gotError(theerror) {
  print(theerror);
 }
 
 function gotData() {
   let currentString = serial.readLine();
   trim(currentString);
   if (!currentString) return;
   console.log(currentString);
   latestData = currentString;

   if (latestData/10 >= 2) {
     lightSources[1][0] = latestData - 20;
   } else {
    lightSources[0][0] = latestData - 10; 
   }
 }
 
function draw() {

  colorMode(HSB);
  background(128, 20, 70);

  push();
  rectMode(CENTER);
  fill(50);
  rect(width/2, height/2,width - 100, height - 100);
  pop();

  //Couch
  drawCouch(800, 200, 80, 200, 0, 50, 40, 80);

  //Chairs
  drawCouch(980, 300, 80, 80, PI/2, 50, 40, 80);
  drawCouch(620, 300, 80, 80, -PI/2, 50, 40, 80);

  //Coffee table
  drawTable(800, 300, 80, 200, PI, 30, 40, 30);

  //Lamp tables
  drawTable(table1X, table1Y, 80, 80, 0, 30, 40, 30);
  drawTable(table2X, table1Y, 80, 80, 0, 30, 40, 30);

  for (k = 0; k < lightSources.length; k++) {
    fill(200, 40, 60);
    drawLamp(lightSources[k][1], lightSources[k][2], lightSources[k][3]);
  }



  for (n = 0; n < lightSources.length; n++) {
    if (lightSources[n][0] == 1) {
      turnLightOn(lightSources[n][1], lightSources[n][2], lightSources[n][3], lightSources[n][4]);
    }
  }

  push();
  fill(0);
  textSize(14);
  text(latestData, 10, 20);
  pop();

  push();
  fill(0);
  textSize(14);
  text(message, 10, 40);
  pop();

  var d = 3;
  d = int(d);

  // serial.write(int(2));
 
}


function updateLightState(lightIndex) {
  lightIndex = Number(lightIndex);
  if (lightSources[lightIndex][0] == 1) {
      lightSources[lightIndex][0] = 0;
      if (lightIndex == 2) { 
        outData = 2;
      } else if (lightIndex == 1){
        outData = 4;
      }
      // print(message);
      serial.write(int(outData));
  }

  else if (lightSources[lightIndex][0] == 0) {
      lightSources[lightIndex][0] = 1;
      if (lightIndex == 2) { 
        outData = 1;
      } else if (lightIndex == 1){
        outData = 3;
      }
      // print(message);
      serial.write(int(outData));
  }
}

function checkIfLampClicked(x, y) {

  for (n = 0; n < lightSources.length; n++) {
    let currX = lightSources[n][1];
    let currY = lightSources[n][2];
    let currR = lightSources[n][3];

    let distance = sqrt(pow((currX-x),2) - pow((currY-y),2));

    if (distance <= currR) {
      //Toggle lamp state
      updateLightState(n);
      return;
    }
  }
}

function keyPressed() {

  updateLightState(key);

}



function turnLightOn(x, y, lampRadius, shineRadius) {
  var centerX = x;
  var centerY = y;


  //Iterating through each point in square to brighten color if inside lamp shine radius
  for (i = 0; i < 2*shineRadius; i = i+5) {
    for (j = 0; j < 2*shineRadius; j = j+5) {
      var currX = centerX - shineRadius + i;
      var currY = centerY - shineRadius + j;

      var dist2Center = sqrt(pow((centerX - currX),2) + pow((centerY - currY),2));

      if (dist2Center <= shineRadius) {
        var currColor = get(currX, currY);
        hsvConversion = rgb2hsv(currColor[0], currColor[1], currColor[2]);

        colorMode(HSB);
        stroke(hsvConversion[0], hsvConversion[1]+40, hsvConversion[2]+20);
        strokeWeight(7);
        point(currX, currY);
      }

    }
  }
 
  strokeWeight(0);
}



function drawCouch(x, y, width, height, theta, couchH, couchS, couchB) {

  let couchHeight = width;
  let couchWidth = height;
  let armWidth = couchWidth*1/5;
  let armHeight = couchHeight*4/5;
  let backWidth = couchWidth;
  let backHeight = couchHeight*2/5;

  //Base Couch
  push();
  angleMode(RADIANS);
  rectMode(CENTER);
  translate(x, y);
  rotate(theta);
  // translate(transRadius - transRadius*cos(theta), -transRadius*sin(theta));

  strokeWeight(2);
  stroke(0);
  fill(couchH, couchS, couchB);
  rect(0, 0, couchWidth, couchHeight, 0, 0, 10, 10);

  //Arm rests
  fill(couchH, couchS, couchB - 20);
  rect(-couchWidth/2, armHeight - couchHeight, armWidth, armHeight, 10, 10, 10, 10);
  rect(couchWidth/2, armHeight - couchHeight, armWidth, armHeight, 10, 10, 10, 10);

  //Backing
  fill(couchH, couchS, couchB - 25);
  rect(0, (armHeight/2 - couchHeight/2) + (backHeight/2 - couchHeight/2), backWidth, backHeight, 0, 0, 30, 30);
  strokeWeight(0);


  pop();

}

function drawTable(x, y, width, height, theta, couchH, couchS, couchB) {

  let tableHeight = width;
  let tableWidth = height;

  //Base Couch
  push();
  angleMode(RADIANS);
  rectMode(CENTER);
  translate(x, y);
  rotate(theta);
  // translate(transRadius - transRadius*cos(theta), -transRadius*sin(theta));

  //Table top
  strokeWeight(2);
  stroke(0);
  fill(couchH, couchS, couchB);
  rect(0, 0, tableWidth, tableHeight);

  //Top pattern
  strokeWeight(2);
  stroke(0);
  fill(couchH, couchS, couchB + 40);
  rect(0, 0, tableWidth - 10, tableHeight - 10);

  pop();

}


function drawLamp(x, y, radius, couchH, couchS, couchB) {

  let tableHeight = width;
  let tableWidth = height;

  //Base Couch
  push();

  //Lamp
  fill(couchH, couchS, couchB);
  ellipse(x, y, radius);

  pop();

}



function rgb2hsv (r,g,b) {
 var computedH = 0;
 var computedS = 0;
 var computedV = 0;

 //remove spaces from input RGB values, convert to int
 var r = parseInt( (''+r).replace(/\s/g,''),10 );
 var g = parseInt( (''+g).replace(/\s/g,''),10 );
 var b = parseInt( (''+b).replace(/\s/g,''),10 );

 if ( r==null || g==null || b==null ||
     isNaN(r) || isNaN(g)|| isNaN(b) ) {
   alert ('Please enter numeric RGB values!');
   return;
 }
 if (r<0 || g<0 || b<0 || r>255 || g>255 || b>255) {
   alert ('RGB values must be in the range 0 to 255.');
   return;
 }
 r=r/255; g=g/255; b=b/255;
 var minRGB = Math.min(r,Math.min(g,b));
 var maxRGB = Math.max(r,Math.max(g,b));

 // Black-gray-white
 if (minRGB==maxRGB) {
  computedV = minRGB;
  return [0,0,computedV];
 }

 // Colors other than black-gray-white:
 var d = (r==minRGB) ? g-b : ((b==minRGB) ? r-g : b-r);
 var h = (r==minRGB) ? 3 : ((b==minRGB) ? 1 : 5);
 computedH = 60*(h - d/(maxRGB - minRGB));
 computedS = (maxRGB - minRGB)/maxRGB;
 computedV = maxRGB;
 return [computedH,computedS*100,computedV*100];
}

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.