index2018-10-16

Week 6 ~ Serial Communication

Here is a rundown of how I made two computers talk:

First I set up the first computer, the arduino. To do this I assembled the circuit by connecting a wire from the 5V pin on the arduino to a hole in the power bus on my breadboard. I also connected a wire from one of the ground pins on the arduino to a hole in the ground bus of my breadboard. Finally I connected two wires across the breadboard, one from power bus to power bus, and the other from ground bus to ground bus - this ensures that there is voltage all the way around my breadboard.

Next I added a potentiometer. To this I connected the middle leg of the potentiometer to analog pin 1 on the arduino. The other two legs of the potentiometer are connected to power and ground. The reason I am connected to an analog input pin here is because the arduino is going to need to read the varying values that are coming in when a person turns the knob of the potentiometer.

Before I can do anything serially between my laptop and my arduino I need to tell my arduino to read the potentiometer values and then write them to Serial. The code to do that is below:

void setup() {
 Serial.begin(9600); 
}
 
void loop() {
 int potentiometer = analogRead(A1);
 int mappedPot = map(potentiometer, 0, 1023, 0, 255);
 Serial.write(mappedPot);
 delay(1);
}

I double checked that this was working by printing the values of mappedPot to the Serial monitor with this line of code: Serial.println(mappedPot). Now that I know my arduino is set up I can finally start writing code for my laptop to be able to communicate with the arduino.

First I set up my index.html file. I dropped in four empty div tags which I will be using to add video to with javascript. Code below:

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="stylez.css">
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->
        <p id="log"></p>
        <div id="video-one"></div>
        <div id="video-two"></div>
        <div id="video-three"></div>
        <div id="video-four"></div>
        <script src="p5/p5.min.js"></script>
        <script src="p5/addons/p5.dom.js"></script>
        <script src="p5/addons/p5.sound.js"></script>
        <script src="p5/p5.serialport.js"></script>
        <script src="cereal.js"></script>
    </body>
</html>

After adding the correct p5 files to my project directory I created a file called cereal.js. This is where all of my javascript will go. My goal was to create a webpage that showed different scary movie clips depending on the rotation of the potentiometer. First I wrote my setup() code.

function setup() {
	createCanvas(windowWidth, windowHeight);
	createHTML();  
	
	video = createVideo('one.mp4');
	video.parent('video-one')

	videoTwo = createVideo('two.mp4');
	videoTwo.parent('video-two');
	videoThree = createVideo('three.mp4');
	videoThree.parent('video-three');
	videoFour = createVideo('four.mp4');
	videoFour.parent('video-four');

	serial = new p5.SerialPort();      
	serial.on('data', serialEvent);
	serial.open(portName); 
}

The most important parts of the code above are that I am attaching an actual video element to its own html element. Then I am creating a new instance of SerialPort and calling the serialEvent function whenever data comes through. In addition writing the project code I also have the p5 SerialControl app running with the correct port enabled. The serialEvent function is below:

function serialEvent() {
	inData = Number(serial.read());
	printData(inData);
	toggleVid(inData);
}

In the function above I am printing the data, or the value of my potentiometer, to the browser using yet another function called printData. I am also calling another function called toggleVid. This is the function that tells the browser to play or pause the videos. Here is the code for the toggleVid function:

function toggleVid(dataValue) {
  if (dataValue > 20) {
		playing = true;
    video.loop();
  } else {
		video.pause();
		playing = false;
  }

  if (dataValue > 70) {
		playVideo(videoTwo);
  } else {
		pauseVideo(videoTwo);
  }

  if (dataValue > 100) {
		playVideo(videoThree);
  } else {
		pauseVideo(videoThree);
  }

  if (dataValue > 150) {
		playVideo(videoFour);
  } else {
		pauseVideo(videoFour);
  }
}

function playVideo(videoEl) {
	videoEl.loop();
	videoEl.style('opacity', '1');
}

function pauseVideo(videoEl) {
	videoEl.pause();
	videoEl.style('opacity', '0');
}

Here is a video of me turning the potentiometer to manipulate the videos in my webpage:

Here is my full cereal.js file:

var serial;                        
var portName = '/dev/cu.usbmodem14311'; 
var inData;   

var playing = false;
var video;
var button;
var videoTwo;
var videoThree;
var videoFour;

var log;

function setup() {
	createCanvas(windowWidth, windowHeight);
	createHTML();  
	
	video = createVideo('one.mp4');
	video.parent('video-one')

	videoTwo = createVideo('two.mp4');
	videoTwo.parent('video-two');
	videoThree = createVideo('three.mp4');
	videoThree.parent('video-three');
	videoFour = createVideo('four.mp4');
	videoFour.parent('video-four');

	serial = new p5.SerialPort();      
	serial.on('data', serialEvent);
	serial.open(portName); 
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

function draw() {
	background('#000000');
}

function serialEvent() {
	inData = Number(serial.read());
	printData(inData);
	toggleVid(inData);
}

function createHTML() {
	log = createElement('p', 'incoming data goes here');
	log.attribute('aria-label', 'incoming data');
	log.attribute('aria-role', 'alert');
	log.attribute('aria-live', 'polite');
	log.style('color', 'white');
	log.style('z-index', '9999');
	log.position(10, 40);
}

function printData(inString) {
	log.html('~scariness~ ' + inString);
}

function toggleVid(dataValue) {
  if (dataValue > 20) {
		playing = true;
    video.loop();
  } else {
		video.pause();
		playing = false;
  }

  if (dataValue > 70) {
		playVideo(videoTwo);
  } else {
		pauseVideo(videoTwo);
  }

  if (dataValue > 100) {
		playVideo(videoThree);
  } else {
		pauseVideo(videoThree);
  }

  if (dataValue > 150) {
		playVideo(videoFour);
  } else {
		pauseVideo(videoFour);
  }
}

function playVideo(videoEl) {
	videoEl.loop();
	videoEl.style('opacity', '1');
}

function pauseVideo(videoEl) {
	videoEl.pause();
	videoEl.style('opacity', '0');
}