PComp Final

In my last blog post regarding this project, I talked about the progress we’d made. We had fabricated a button into a baseball helmet, revamped the sketch so that it would run properly and built a home plate, which looked a little something like this:
At this time in our process, Grant and Katie and I had a sketch that – unbeknownst to us at the time – was about 85% done, a batting helmet that had functionality, and a hollowed out bat. Here’s what remained: coding the FSR’s, putting the vibrating motor sensor into the bat, mounting the Arduino 101 into the bat, making our code more specific and, most importantly, making sure that the bat, helmet and home plate worked in tandem with one another. We knew that in order to reach our goal of being done by Monday night – we wanted to give ourselves at least 24 hours of extra time – we had to start delegating certain tasks. Luckily for Grant and I, Katie is truly a master fabricator; she is the assistant technical director for the Tisch Grad acting program. It was decided that Grant and Katie would start to get more specific with the hardware while I would focus on the code. We would meet up this past Saturday and spend the weekend making sure everything worked together.
I knew that before I could start worrying about how to incorporate all three of the elements of the project together, they had to be working seamlessly individually. The helmet already done with, I focused first on the FSR’s. I wasn’t too concerned about the code on the Arduino side, I was more worried about making each FSR individually trigger something. Essentially, the FSR was going to need to act as a button; once it was pressed something would happen. But because the “button” needed to be on home plate and therefore needed to be stepped on, I figured it would be easiest and most in line with our ‘try-to-make-the-tech-hard-to-see’ aesthetic to stick with the FSR’s. I created some code in p5 from scratch to see if it would work and after tinkering for a few hours, each button triggered a different part of the sketch. Now onto the bat.
Building a home for the 101
Paneling for the Batters Box
Precision, precision, precision. The biggest issue that I faced in my midterm is that there was way too much delay with the bat. You would swing and would have to wait a second before the bat would swing with you. If I was going to try to simulate getting a hit from a professional baseball player, timing would be of the utmost importance. After making sure my ‘handshaking’ was working and removing every console log from the code, I feel there has been a vast improvement in the precision of the bat. However, the issue now lay with a different element of the bat: the vibrating motor.
Making an enclosure for the helmet
Threading vibrating motor through the bat
It was very important to me to make the user feel as if they really got a hit when playing this game. At first I thought I was going to need to use a haptic motor controller to set up different kinds of hits but resident Joe Mango showed me a much easier way: bypass the haptic motor controller and set a regular vibrating motor to a PWM pin. Switch back and forth between having it “high” and having it “low”. I was concerned that “high” wouldn’t be felt throughout the plastic bat but fortunately, the motor produced the perfect amount of vibration. My biggest issue now was how to let the arduino code know when something had been triggered in the p5 code. This lab proved to be instrumental in this working. There are still some issues with this vibrating motor that I will get to later.
Now that all three instruments were working separate from one another, it was time to try to make them work in unison. Daniel Shiffman informed us that in order to maximize efficiency, we would now need to consolidate our three huge pieces of code – we had a code for each mode and were triggering them in the html. While Grant focused on this, I tried to dig into how I was going to make the three elements work together. Turns out you cannot open multiple serial ports in the p5 editor. This was a very alarming shock. Here we were about a week away from everything being due and it just may not work. An hour and a half worth of office hours with Shawn Van Every – whom I cannot thank enough for all of his patience with me – all elements were running pretty well with one another.
Now on to fabrication. 
I let Katie know that the vibrating motor needed to be in the lower shaft of the bat and the arduino needed to be at the top. She put an enclosure in the bottom of the bat to isolate the motor, insulated it with foam to prevent additional movement, and cut the bat in half. This way I could have easy access to the motor should it cease to work. With the other half, she made a circular piece of wood to stabilize the center, ran the wire from the motor through that and up to the top where she made a piece of wood to screw to the arduino. Did I tell you she was a genius? She then spray painted the bat to make it look more realistic and less plastic. I think she succeeded.
Onto the home plate. We decided on three colors, Grant fixed the home screen to adjust them while Katie and I spray painted them. Katie added wood paneling to the sides also to give it more of a sheen. She then turned it around and made an enclosure for the Arduino and breadboard that was operating the FSR’s which featured a long wooden piece to prevent the board from moving around at all. With all of the fabrication now done, we decided to spend our additional time on Saturday utilizing the free theater Katie had in the Grad building to film the commercial/instructional video that you saw at the top of the page.
The final step in the process was the perf board. The arduino and Bluetooth that was hooked up to it were going to be moving around a LOT as they are in the main shaft of the bat. Not only do they need to be very stabilized to the bat but the connections need to be super stabilized as well. My first perf board was an utter failure. My second was a success but the header pins on the male to female wires kept breaking off. By my third perf board I became a soldering pro though and I feel like it looks and works pretty well.
 
            With everything done, Grant and I had a few hours to test out all the components together. While we were thrilled that they were working together, there is one area where there could be some improvement: the vibrating motor sensor. We just cannot get it to vibrate at the right time. It seems like there is too much happening even with all of the console logs removed. Perhaps it’s because there is too much in the preload but even when I removed the music files, there was still significant lag. At this point, I’m at a loss and I hope to pick your brain about how I can better correct this in the future.
 
            At the end of the day, this has been an amazing project to work on. It’s so bizarre to look back on that first sketch I did about baseball and think about how far I’ve come. There are so many people that deserve acknowledgement: Joe Mango, Shawn Van Every, Tom Igoe, Dan O’Sullivan and Dan Shiffman, Kat Sullivan, Jingwen Zhu, Justin Peake, Or Fleischer, and I’m sure there are more. Of course, none of this would have happened if not for the dedication and commitment of my partners Grant Henry and Katie Takacs.
 
I was sitting in Maryland over Thanksgiving. Grant and Katie had decided to get together the weekend after to work on fabrication while I took a few extra days and focused on the coding side of things. At one point, I got a text from them. It was a photo of that grass batters box. I couldn’t believe it; I had a grin from ear to ear. It was so noticeable my dad asked me what was up. I turned my phone to him and showed him the photo. I was just blown away by how awesome it was. “Man,” he said, “this is some group you got, huh?” It sure was.

ICM Final

UPDATE: FINAL CODE HAS BEEN ADDED TO THE BOTTOM OF THE PAGE

What Does It Take To Be A Major League Baseball Player?

I don’t know if a lot of you are aware but it is very, very difficult to be a Major League Baseball Player. In most professional sports, there are few steps: you play in college, you get drafted, and if you prove good enough you get to play professional football, hockey or basketball. This is not the case in Major League Baseball. If you are 100% the best player in college, if there has never been anyone like you to play the game at the rare age of 18 or 21 you are still placed in a brutal minor league system that can completely control your soul. Let’s take a look at a trailer for the film “A Player to be Named Later” for more information.

I asked this question to give you a better idea of why I love this sport so much: it’s not just a sport it’s a story that grows and changes every single year and never gets boring. There are truly millions of examples of this but let’s stick with one that happened this past year. For those who don’t know, pitchers rarely get the chance to hit. A typical batter will get upwards of 600 – 700 opportunities to get a hit and a pitcher may get like…50 at most. Michael Lorenzon, a pitcher for the Reds this year – got five. Five opportunities to just get a hit. On around August 12th, Michael Lorenzon’s father – whom he was very close with – passed away. After returning from a bereavement list, Lorenzon was put into the game for his team.

This is why I love baseball.

As is true with all things you love, you want to know more about it and maybe try to instill some of that information in others.

When I started learning coding awhile ago, I was a bit terrified because I was in an unfamiliar place. However, when I started using baseball statistics in coding, the experience of discomfort lessened. Coding became secondary, a byproduct of needing to learn how to make baseball more accessible. I started with a simple baseball game:

When I made this, I was super excited. I had finally made a baseball game! Very strange to look back on it now. The evolution of the game is entirely thanks to the introduction of JSON files. They gave me the opportunity to take real baseball data – of which there is an abundance – and apply it to my work. I’ll never forget being late to a bar that night because I was so excited to make this:

After I had fun with this, I decided why not mix the two, which led me to my final. How cool would it be if I could take real data and use it to show the difference in a pitchers arsenal. I’ve seen plenty of videos and .gif’s but something about visualizing the data got me really excited. Luckily, I found two amazing partners – and fellow baseball fans – in Katie Takacs and Grant Henry and after countless hours we made what can only best be shown in a local host.

Here is the final code:

var gameMode = ‘EASY’;

//EASY MODE
var x = 380;
var y = 285;
var speed = 3.5;
var speedb = 0;
var accx = -0.01;
var deg = 0;

var serial;
var serialTwo;
var serialThree;
var ballX, ballY, ballZ;
var batX, batY, batZ;
var portName = ‘/dev/cu.AdafruitEZ-Link71f3-SPP’; ///dev/cu.AdafruitEZ-Link71f3-SPP; for accelerometer
var portNameTwo = ‘/dev/cu.AdafruitEZ-Link743a-SPP’; ///dev/cu.AdafruitEZ-Link743a-SPP; for buttons
var portNameThree = ‘/dev/cu.usbmodem1421′;//’/dev/cu.usbmodem1411’; or whatever port you’re plugged into for FSR’s
var w = 35;

var prevBallY;
var counter = 150;
var batspeed = 5;

//hits counter variables
var score = 0;
var imgScore;
var bringEm;
var shaggy;
var noMatter;

var swinging = false;
//var getHit = false;

var inData;
var outByte = 0;

//HARD MODE
var sensorValue = 5;
var ball, pitchSelector, data, data2;
var bigList = [];
var speedHard = 3;

//p is from 0-4 and determines which pitcher’s stat’s we’re accessing: 0 is Thor, 1 is kershaw, etc
var p = 1;
//k is however many pitches the pitcher has in their arsenal
var k = 4;
// r is the minimumim vel for each pitcher
var r = 30;
//b is second real value in PitchMapMin
var b = 101.4;
//s is first real value in PitchMapMov
var s = -9.0;
//q is second real value in PitchMapMov
var q = 5;

// changes colors in the switch to make colors unanimous across the board
var cOne = 255;
var cTwo = 255;
var cThree = 0;
var cFour = 244;
var cFive = 66;
var cSix = 66;

//pitchers display variables
var currentImg;
var kershaw;
var mo;
var thor;
var wake;
var yu;

//Wake’s variables. Adj makes his movement start earlier, Knuckle allows for his wacky movement
// to be in the code
var wakeAdj = 400;
var knuckle = 0;

// making JSON data global.
var PitchMax;
var PitchMin;
var PitchMapMov;
var PitchMapMax;
var PitchMapMin;
var PitchMapMov;
var PitchrandomSpeed;
var PitchSpeed;

//GAME MODE
var speedc = 1;

// timer variables
var clockStart = 60;
var interval;

var modeEasy = false;
var modeHard = false;
var modeGame = false;
var modeMenu = false;
function preload() {
img = loadImage(‘backgroundField.png’);
image2 = loadImage(‘Bat.png’);
image3 = loadImage(‘baseball.png’);
image4 = loadImage(‘mainMenu3.png’);
mySound = loadSound(‘Cheer.mp3’);

// load pitchers images
kershaw = loadImage(‘kershawTag2.png’);
mo = loadImage(‘moTag.png’);
thor = loadImage(‘thorTag.png’);
wake = loadImage(‘wakeTag.png’);
yu = loadImage(‘yuTag.png’);

// load easter egg sounds
bringEm = loadSound(‘BringEmOut.wav’);
shaggy = loadSound(‘Boombastic.wav’);
noMatter = loadSound(‘WinNoMatter.wav’);

//load pitcher data
data = loadJSON(‘ReorderedPitcherData.json’, gotData);
data2 = loadJSON(‘ReorderedPitcherData2.json’, gotData2);
}

function setup() {
createCanvas(800, 650);
angleMode(DEGREES);
startTimer();
noMatter.onended(startTimer);

//starts at Kershaw
currentImg = kershaw;
//sensorValue = 1;

serial = new p5.SerialPort(“localhost”, 8083);
serial.on(‘list’, printList);
serial.on(‘data’, serialEvent);
serial.on(‘open’, openPort);
serial.list();
serial.open(portName);

serialTwo = new p5.SerialPort(“localhost”, 8081);
serialTwo.on(‘list’, printList);

serialTwo.on(‘data’, serialEventTwo);
serialTwo.on(‘open’, openPortTwo);

serialTwo.open(portNameTwo);
serialThree = new p5.SerialPort(“localhost”, 8082);
serialThree.on(‘list’, printList);

serialThree.on(‘data’, serialEventThree);
serialThree.on(‘open’, openPortThree);
serialThree.open(portNameThree);
textSize(24);

}
function draw() {
clear();
image(img, -30, -50, width+30, height);
// batMove();
// if(getHit === true){
// //console.log(“buzz?”);
// serial.write(“C”);
// console.log(‘writing c’)
// //console.log(serial.write);
// }
// if(getHit === false){
// serial.write(“L”);
// console.log(‘writing L’)
// }

// background(0);
// fill(255);
// text(batX + ” ” + batY + ” ” + batZ, width/2, height/2);

if (ballX === 0 && ballY === 0 && ballZ === 0 && clockStart === 60){
modeMenu = true;
modeEasy = false;
modeHard = false;
modeGame = false;

}
if(modeMenu === true){

image(image4, 0, 0, width+40, height);
modeEasy = false;
modeHard = false;
modeGame = false;
}

if (ballX > 400){
clear();
modeEasy = true;
modeMenu = false;
modeHard = false;
modeGame = false;
clockStart = 59;
score = 0;
}

if(modeEasy === true) {
//console.log(“why aren’t you swinging”);
printTimerShmimer();
printScore();
baseball();
pitch();
returnball();
bat();
contact();
}

if (ballY > 400){
clear();
modeEasy = false;
modeHard = true;
modeMenu = false;
modeGame = false;
clockStart = 59;
score = 0;
}

if(modeHard === true){
//what causes the ball itself to move
if(typeof ball != “undefined”){
ball.display();
ball.move();
if(ball.inScreen()) {
for (var i = 0; i < data.pitchers[p].pitches.length ; i++){
for (var j = 0; j < data.pitchers[p].pitches[i][“Frequency”]/10; j++){
bigList.push(i);
}
}
pitchSelector = bigList[floor(random(bigList.length))];
//console.log(“pitch selection” + pitchSelector);
ball = new Thor(pitchSelector);

//console.log(“Sensor Value: ” + sensorValue);
}
// pitchDisplay();

}

printScore();
printTimerShmimer();
bat();
contactHard();
// changePitcher();
}

if (ballZ > 400){
clear();
modeHard = false;
modeGame = true;
modeMenu = false;
modeEasy = false;
clockStart = 59;
score = 0;
}

if(modeGame === true){

//pitcher image display
if (typeof currentImg != “undefined”) {
image(currentImg, 80, 5, 125, 250);
}

//what causes the ball itself to move
if(typeof ball != “undefined”){
ball.display();
ball.move();
barDisplay();
if(ball.inScreen()) {
for (var i = 0; i < data2.pitchers[p].pitches.length ; i++){
for (var j = 0; j < data2.pitchers[p].pitches[i][“Frequency”]/10; j++){
bigList.push(i);
}
}
pitchSelector = bigList[floor(random(bigList.length))];
//console.log(“pitch selection” + pitchSelector);
ball = new Thor2(pitchSelector);

//console.log(“Sensor Value: ” + sensorValue);
}
pitchDisplay();
}
//console.log(PitchrandomSpeed);

pitchText();
pitchDisplay();
printScore();
printTimerShmimer();
bat();
contactGame();
changePitcher();
adjustStats();

}
}

//baseball display
function baseball() {
fill(255);
ellipseMode(CORNER);
ellipse(x, y, w, w);
image(image3, x, y, w-1, w-1);
}

//baseball movement
function pitch() {
y = y + speed;
x = x + speedb;
// speedb = speedb + accx * 2;

if (y >= height*2.5) {
y = 235;
}
}

//baseball restarts
function returnball() {
if (x > 800 || x < -100 || y > height*1.65 || y < -900) {
baseball();
x = 380;
y = 285;
speed = 3;
speedb = 0;
}
}
//batter up
function bat() {
translate(245, 450);
rotate(deg);
noStroke();
fill(100, 100, 100, 0);
image(image2, 0, 0, 25, 180);
// console.log(“bat”);
// console.log(swinging);
if (swinging) {
deg = deg – batspeed;
}

if (deg <= -180) {
deg = 0;
swinging = false;
}

var diffY = ballY – prevBallY;

if (batX > 105 && batX < 120 && counter > 150) {
swinging = true;
counter = 0 ;

}
// console.log(deg);
counter++;
prevBallY = ballY;

if (y < 225 || x < 0) {
serial.write(“L”);
}
}

//bat hits ball
function contact() {
var diff = deg + 90;
image(image2, 0, 0, 25, 180);

if (abs(diff) < 10) {
if (y > 442 && y < 558) {
if (!mySound.isPlaying()) {
mySound.play();
serial.write(“C”);
speed = speed * random(-4, -1);
speedb = speedb + random(-10, 5);
// see addScore function…
addScore();
}
}
}
}
//}

// send when an event occurs *GAME MODE*
function Thor2(pitch/*frequency*/) {
this.x = 375;
this.y = 220;
this.speedHard = 1;
this.speedc = 0;

this.w = 10;

this.rgb = [0,200,100];

// noprotect
switch (pitch){
//knuckleball will be
case 0:
//red…fastball
this.rgb = [cFour,cFive,cSix];
//console.log(this.rgb);
break;
case 1:
//yellow… curveball
this.rgb = [cOne,cTwo,cThree];
//console.log(this.rgb);
break;
case 2:
//turqouise … change-up
this.rgb = [66,244,235];
//console.log(this.rgb);
break;
case 3:
//purple… slider
this.rgb = [125,66,244];
//console.log(this.rgb);
break;
case 4:
//lime green…sinker
this.rgb = [0,255,0];
//console.log(this.rgb);
break;
case 5:
// blue …cutter
this.rgb = [0, 0, 205];
//console.log(this.rgb);
break;
case 6:
//orange…two-seamer
this.rgb = [255,165, 0];
//console.log(this.rgb);
break;
default:
this.rgb = [0,200,100];
//console.log(‘no color was passed into ball’);
}

PitchMax = data2.pitchers[p].pitches[pitch].MaxVelo;
PitchMin = data2.pitchers[p].pitches[pitch].MinVelo;
PitchxMov = data2.pitchers[p].pitches[pitch].xMov;
//mapping of maximum velocity
PitchMapMax = map(PitchMax, 50, b, 0, 8);
//mapping of minimum velocity
PitchMapMin = map(PitchMin, r, b, 0, 8);
// mapped xMov of fastball
PitchMapMov = map(PitchxMov, s, q, -7, 4);

// pitch velo will randomly vary between max and min
PitchrandomSpeed = random(PitchMapMax, PitchMapMin);
PitchSpeed = Math.round(random(PitchMin, PitchMax));

this.display = function(){
fill(this.rgb[0],this.rgb[1],this.rgb[2], 100);
image(image3, this.x, this.y, this.w, this.w);
ellipseMode(CORNER);
ellipse(this.x, this.y, this.w-1, this.w-1);
}

this.move = function(){
this.y = this.y + this.speedHard + PitchrandomSpeed;
this.x = this.x + this.speedc;

if(this.y> wakeAdj) {
this.x = this.x + PitchMapMov + knuckle;
}

if (this.y > 400){
this.w = this.w +2;
}

if (this.y < 219) {
this.w = this.w – 1.65;
}

};

this.inScreen = function(){
if (this.y < 225 || this.x < 0) {
serial.write(“L”);
}
if(this.y > height*2 || this.y < -500) {
return true;
}
};
}

// send when an event occurs *HARD*
function Thor(pitch/*frequency*/) {
this.x = 375;
this.y = 220;
this.speedHard = 3.5;
this.speedb = 0;

this.w = 10;

this.rgb = [0,200,100];

// noprotect
switch (pitch){
//knuckleball will be
case 0:
//red…fastball
this.rgb = [cFour,cFive,cSix];
//console.log(this.rgb);
break;
case 1:
//yellow… curveball
this.rgb = [cOne,cTwo,cThree];
//console.log(this.rgb);
break;
case 2:
//turqouise … change-up
this.rgb = [66,244,235];
//console.log(this.rgb);
break;
case 3:
//purple… slider
this.rgb = [125,66,244];
//console.log(this.rgb);
break;
case 4:
//lime green…sinker
this.rgb = [0,255,0];
// console.log(this.rgb);
break;
case 5:
// blue …cutter
this.rgb = [0, 0, 205];
// console.log(this.rgb);
break;
case 6:
//orange…two-seamer
this.rgb = [255,165, 0];
//console.log(this.rgb);
break;
default:
this.rgb = [0,200,100];
// console.log(‘no color was passed into ball’);
}

PitchMax = data.pitchers[p].pitches[pitch].MaxVelo;
PitchMin = data.pitchers[p].pitches[pitch].MinVelo;
PitchxMov = data.pitchers[p].pitches[pitch].xMov;
//mapping of maximum velocity
PitchMapMax = map(PitchMax, 50, b, 0, 8);
//mapping of minimum velocity
PitchMapMin = map(PitchMin, r, b, 0, 8);
// mapped xMov of fastball
PitchMapMov = map(PitchxMov, s, q, -7, 4);

// pitch velo will randomly vary between max and min
PitchrandomSpeed = random(PitchMapMax, PitchMapMin);
PitchSpeed = Math.round(random(PitchMin, PitchMax));

this.display = function(){
fill(this.rgb[0],this.rgb[1],this.rgb[2], 100);
image(image3, this.x, this.y, this.w, this.w);
ellipseMode(CORNER);
ellipse(this.x, this.y, this.w-1, this.w-1);
}

this.move = function(){
this.y = this.y + this.speedHard;
this.x = this.x + this.speedb;

if(this.y> wakeAdj) {
this.x = this.x + PitchMapMov + knuckle;
}

if (this.y > 400){
this.w = this.w +2;
}

if (this.y < 219) {
this.w = this.w – 1.70;
serial.write(“L”);
}

};

this.inScreen = function(){
if (this.y < 225 || this.x < 0) {
serial.write(“L”);
}

if(this.y > height*2 || this.y < -500) {
return true;
}
};
}

function gotData(){
ball = new Thor(0);
}

function gotData2(){
ball = new Thor2(0);
}

// bat hits ball
function contactHard() {
var diff = deg + 90;
image(image2, 0, 0, 25, 180);

if (abs(diff) < 10) {
if (ball.y > 442 && ball.y < 558 && ball.x > 325 && ball.x < 450) {
if (!mySound.isPlaying()) {
serial.write(“C”);
mySound.play();
ball.speedHard = ball.speedHard – 15;
ball.speedb = ball.speedb + random(-10,5);

// see addScore function…
addScore();
}
}
}
}

// bat hits ball
function contactGame() {
var diff = deg + 90;
image(image2, 0, 0, 25, 180);

if (abs(diff) < 10) {
if (ball.y > 442 && ball.y < 558 && ball.x > 325 && ball.x < 450) {
if (!mySound.isPlaying()) {
serial.write(“C”);
mySound.play();
ball.speedHard = ball.speedHard – 15;
ball.speedc = ball.speedc + random(-10,5);

// see addScore function…
addScore();
}
}
}
}

//score counter
function addScore() {
//add one
score++;

//Easter egg sounds
if (score == 5) {
bringEm.play();
}
if (score == 10) {
shaggy.play();
}
}

//scroll through the pitchers when right arrow is pressed
function changePitcher() {
if (sensorValue == 1) {
if (currentImg == kershaw) {
currentImg = thor;
}
}
if (sensorValue == 2) {
if(currentImg == thor) {
currentImg = yu;
}
}
if (sensorValue == 3) {
if(currentImg == yu) {
currentImg = mo;
}
}
if (sensorValue == 4) {
if (currentImg == mo) {
currentImg = wake;
}
}
if (sensorValue == 5) {
if (currentImg == wake) {
currentImg = kershaw;
}
}
}

function adjustStats(){
if(sensorValue == 1){
thorSpecifics();
}
if(sensorValue == 2){
yuSpecifics();
}
if(sensorValue == 3){
moSpecifics();
}
if (sensorValue == 4) {
wakeSpecifics();
}
if(sensorValue == 5){
kershawSpecifics();
}
}

//Displays the score
function printScore() {
textAlign(LEFT);
fill(255, 200);
textSize(40);
textStyle(BOLD);
// image(imgScore, 300, 15, 220, 150);
text(“HITS ” + score, width-350, 185);

if (score == 5){
fill(0, 200);
// textSize(40);
text(“HITS ” + score, width-350, 185);
textAlign(CENTER);
text( “HOMERUN!”, width/2, 50);
}

if (score == 10) {
fill(0, 200);
// textSize(40);
text(“HITS ” + score, width-350, 185);
textAlign(CENTER);
text( “Grant Slam!”, width/2, 50);
}

if (score == 15){
fill(0, 200);
// textSize(40);
text(“HITS ” + score, width-350, 185);
textAlign(CENTER);
text( “Fasten Your Seatbelts!”, width/2, 50);
}

if (score == 20){
fill(0, 200);
// textSize(40);
text(“HITS ” + score, width-350, 185);
textAlign(CENTER);
textSize(20);
text( “Wicked Clutch Hittah!”, width/2, 50);
}
}

function barDisplay(){
noStroke();
fill(90, 200);
rect(25, 545, 190, 40);
}

function pitchText(){
textStyle(BOLD);
textAlign(CENTER);
textSize(10);
text(“PITCH | SPEED”, 120, 540);
}
function textDisplay(){
strokeWeight(2);
stroke(50);
textSize(20);
textStyle(BOLD);
textAlign(CENTER);

}

function printList(portList) {
for (var i = 0; i < portList.length; i++) {
// println(i + ” ” + portList[i]);
}
}

function openPort() {
serial.write(‘x’);
console.log(“port 1”);
}

function openPortTwo() {
serialTwo.write(‘x’);
console.log(“port 2”);
}

function openPortThree() {
serialThree.write(‘x’);
console.log(“port 3″);
}
//accelerometer/vibrating sensor
function serialEvent() {
var inString = serial.readStringUntil(‘\r\n’);
if (inString.length > 0) {
if (inString !== ‘hello’) {
var values = split(inString, ” “);
if (values.length > 0) {
batX = Number(values[0]);
// batY = Number(values[1]);
// batZ = Number(values[2]);
}
//console.log(batX);

}
serial.write(‘x’);
}
}
// button
function serialEventTwo() {
var inStringTwo = serialTwo.readLine();
if (inStringTwo.length > 0) {
inStringTwo = inStringTwo.trim();
sensorValue = inStringTwo;
//console.log(sensorValue);
//sensorValue = Number(inString/4);
}
}

//FSR’s
function serialEventThree(){
var inStringThree = serialThree.readStringUntil(‘\r\n’);
//console.log(inStringThree);

if (inStringThree.length > 0) {
if(inStringThree !== ‘hello’) {
var valuesFSR = split(inStringThree, ” “);
if (valuesFSR.length > 2) {
ballX = Number(valuesFSR[0]);
ballY = Number(valuesFSR[1]);
ballZ = Number(valuesFSR[2]);
//console.log(ballX);
}
}
serialThree.write(‘x’);

}

}

function thorSpecifics(){
p = 0;
k = 5;
r = 50;
s = -9.0;
q = 5.0;
b = 101.4;
cOne = 255;
cTwo = 255;
cThree = 0;
cFour = 244;
cFive = 66;
cSix = 66;
bigList = [];
wakeAdj = 400;
knuckle = 0;
pitchMapMov = map(PitchxMov, s, q, -7, 4);
}

function yuSpecifics(){
p = 2;
k = 7;
r = 50;
s = -10.0;
q = 10.0;
b = 101.4
cOne = 255;
cTwo = 255;
cThree = 0;
cFour = 244;
cFive = 66;
cSix = 66;
bigList = [];
wakeAdj = 400;
knuckle = 0;
pitchMapMov = map(PitchxMov, s, q, -7, 4);
}

function moSpecifics (){
p = 3;
k = 1;
r = 50;
s = -10.0;
q = 5.0;
b = 101.4;
cOne = 0;
cTwo = 0;
cThree = 205;
cFour = 244;
cFive = 66;
cSix = 66;
bigList = [];
wakeAdj = 400;
knuckle = 0;
pitchMapMov = map(PitchxMov, s, q, -7, 4);
}

function wakeSpecifics(){
p = 4;
k = 1;
r = 40;
s = -9;
q = 5;
b = 77.0;
cOne = 255;
cTwo = 255;
cThree = 0;
cFour = 255;
cFive = 105;
cSix = 180;
wakeAdj = 250;
pitchMapMov = 0;
knuckle = random(-10, 10);
bigList = [];
}

function kershawSpecifics(){
p = 1;
k = 4;
r = 30;
s = -9.0;
q = 5.0;
b = 101.4;
cOne = 255;
cTwo = 255;
cThree = 0;
cFour = 244;
cFive = 66;
cSix = 66;
wakeAdj = 400;
knuckle = 0;
pitchMapMov = map(PitchxMov, s, q, -7, 4);
bigList = [];
}

function pitchDisplay(){
//kershaw
if(currentImg == kershaw && sensorValue == 5 && pitchSelector == 0 && ball.y > height){
textDisplay();
//red
fill(255, 102, 102);
text(“Fastball: ” + PitchSpeed + ” MPH”, 120, 570);
}
if(currentImg == kershaw && sensorValue == 5 && pitchSelector == 1 && ball.y > height){
textDisplay();
//yellow
fill(255, 255, 0);
text(“Curveball: ” + PitchSpeed + ” MPH”, 120, 570);
}
if(currentImg == kershaw && sensorValue == 5 && pitchSelector == 2 && ball.y > height){
textDisplay();
//cyan
fill(66, 244, 235);
text(“Change-Up: ” + PitchSpeed + ” MPH”, 120, 570);
}
if(currentImg == kershaw && sensorValue == 5 && pitchSelector == 3 && ball.y > height){
textDisplay();
//purple
fill(236, 179, 255);
text(“Slider: ” + PitchSpeed + ” MPH”, 120, 570);
}

//Thor
if(currentImg == thor && sensorValue == 1 && pitchSelector == 0 && ball.y > height){
textDisplay();
//red
fill(255, 102, 102);
text(“Fastball: ” + PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == thor && sensorValue == 1 && pitchSelector == 1 && ball.y > height){
textDisplay();
//yellow
fill(255, 255, 0);
text(“Curveball: ” + PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == thor && sensorValue == 1 && pitchSelector == 2 && ball.y > height){
textDisplay();
//cyan
fill(66, 244, 235);
text(“Change-Up: ” + PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == thor && sensorValue == 1 && pitchSelector == 3 && ball.y > height){
textDisplay();
//purple
fill(236, 179, 255);
text(“Slider: ” + PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == thor && sensorValue == 1 && pitchSelector == 4 && ball.y > height){
textDisplay();
//green
fill(0, 255, 0);
text(“Sinker: ” + PitchSpeed + ” MPH”, 120, 570);
}
// Darvish
if(currentImg == yu && sensorValue == 2 && pitchSelector == 0 && ball.y> height){
textDisplay();
//red
fill(255, 102, 102);
text(“Fastball: “+ PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == yu && sensorValue == 2 && pitchSelector == 1 && ball.y>height){
textDisplay();
//yellow
fill(255, 255, 0);
text(“Curveball: ” + PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == yu && sensorValue == 2 && pitchSelector == 2 && ball.y>height){
textDisplay();
//cyan
fill(66, 244, 235);
text(“Change-Up: “+ PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == yu && sensorValue == 2 && pitchSelector == 3 && ball.y>height){
textDisplay();
//purple
fill(236, 179, 255);
text(“Slider: “+ PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == yu && sensorValue == 2 && pitchSelector == 4 && ball.y>height){
textDisplay();
//green
fill(0, 255, 0);
text(“Sinker: ” + PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == yu && sensorValue == 2 && pitchSelector == 5 && ball.y>height){
textDisplay();
//blue
fill(102, 163, 255);
text(“Cutter: “+ PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == yu && sensorValue == 2 && pitchSelector == 6 && ball.y>height){
textDisplay();
//orange
fill(255, 165, 0);
text(“Two-Seam: “+ PitchSpeed + ” MPH”, 120, 570);
}
//Rivera
if(currentImg == mo && sensorValue == 3 && pitchSelector == 0 && ball.y>height){
textDisplay();
//red
fill(255, 102, 102);
text(“Fastball: “+ PitchSpeed + ” MPH”, 120, 570);
}

if(currentImg == mo && sensorValue == 3 && pitchSelector == 1 && ball.y>height){
textDisplay();
//blue
fill(102, 163, 255);
text(“Cutter: “+ PitchSpeed + ” MPH”, 120, 570);
}
//Wakefield
if(currentImg == wake && sensorValue == 4 && pitchSelector == 0 && ball.y>height){
textDisplay();
//pink
fill(255, 105, 180);
text(“Knuckleball: “+ PitchSpeed + ” MPH”, 120, 570);
}
}

//Timer Interval Set – run function every 1000millis
function startTimer() {
clockStart = 60;
//console.log(‘timer starting’);
interval = setInterval(timerShmimer, 1000);
}

//Timer subtract and stop when you get to 0
function timerShmimer() {
clockStart–;

if (clockStart === 0) {
clockStart = 0;
clearInterval(interval);
noMatter.play();
}
}

//display for Timer
function printTimerShmimer() {
textSize(40);
fill(255, 200);
textAlign(LEFT);
text(” TIME ” + clockStart, width-400, height-520);
// text(clockStart, width-200, height-525);
}
//SWITCH BETWEEN THE MODES**PITCHERS IN GAME MODE
function keyPressed() {
if (keyCode == UP_ARROW) {
swinging = true;
} else if (keyCode == RIGHT_ARROW) {
gameMode = ‘EASY’;
} else if (keyCode == LEFT_ARROW){
gameMode = ‘HARD’;
} else if (keyCode == DOWN_ARROW){
gameMode = ‘GAME’;
}

if (keyCode == ENTER) {
if (currentImg == kershaw) {
sensorValue = 1;
currentImg = thor;
} else if (currentImg == thor) {
sensorValue = 2;
currentImg = yu;
} else if (currentImg == yu) {
sensorValue = 4;
currentImg = wake;
} else if (currentImg == wake) {
sensorValue = 3;
currentImg = mo;
} else if (currentImg == mo) {
sensorValue =5;
currentImg = kershaw;
}
}
return false;

}

//swings the bat upon click
function mousePressed() {
// console.log(“mouse pressed”);
swinging = true;
}

function keyPressed() {
if (keyCode == UP_ARROW) {
gameMode = ‘MENU’;
} else if (keyCode == RIGHT_ARROW) {
gameMode = ‘EASY’;
} else if (keyCode == LEFT_ARROW){
gameMode = ‘HARD’;
} else if (keyCode == DOWN_ARROW){
gameMode = ‘GAME’;
}

if (keyCode == ENTER) {
if (currentImg == kershaw) {
sensorValue = 1;
currentImg = thor;
} else if (currentImg == thor) {
sensorValue = 2;
currentImg = yu;
} else if (currentImg == yu) {
sensorValue = 4;
currentImg = wake;
} else if (currentImg == wake) {
sensorValue = 3;
currentImg = mo;
} else if (currentImg == mo) {
sensorValue =5;
currentImg = kershaw;
}
}
return false;

}

Every Time We Say Goodbye

When we received this assignment I had a narrative in mind that I was very anxious to explore and, not wanting to force my ideas on anyone in the class,  I decided to go it alone. This wasn't necessarily the best choice: I don't know a thing about After Effects or Photoshop. With that said, I knew I had a little extra time to pursue the project so I figured I'd give it a shot.

Having already had a fully fledged narrative in mind, the first part of the process was quite easy. It was everything thereafter that was a complete nightmare. I knew I wanted to use and old man character but I didn't want to rely on my non-existent Illustrator skills to create one. Instead I decided to use photos of someone that I knew would be in abundance online: Samuel Beckett. With that solution a new problem arose. How was I going to be able to use photoshop to turn Beckett into the character I needed him to be?

Enter Rebecca's Photoshop tutorial. Thanks to her screen record of that class I was able to do all the things I needed to do with Beckett and all of my other characters. When it came to learning After Effects however, I stuck to the simple basics: the pin tool, keyframes, etc.

There were definitely sometimes I had to adapt my narrative to limited After Effects ability I had but I think the changes ended up working. While the animation in and of itself is no great shakes to look at, I'm proud that the story is - I think - clear and the message is similar to the one I intended to tell at the assignments outset. 

Virtual Batting Cage Updates

img_7512

We’ve made a lot of progress in the past couple weeks on our project, mostly in terms of Fabrication and computing. We’ve constructed a helmet equipped with two buttons – one to toggle between pitchers and one to take you to the home screen. The purpose of the pitcher button – located on the  brim of the helmet – is to simulate what a hitter may do physically while at the plate. While the .gif below is meant as a comedic exaggeration, it’s not uncommon for a batter to touch the brim of his helmet before taking a pitch; there may be some valuable tar there to make his hands stick to his bat better.

We’ve also constructed a place for the batter to stand when they are taking their ‘at-bat’. The next step for this will be to integrate FSR’s into the home plate. We would also like to signal where the batter should stand.

img_0541img_0542img_0550-1img_0547img_0558img_0560fullsizerender

In terms of the coding, we are making some real great strides as well. Here is a sketch showing what the final background will look like:

And here is a video showing what the final code will look like in terms of pitchers.

Finally there is a preview of what this will look like when this is all tied together.

The Virtual Batting Cage

“Baseball is dull only to dull minds”

I am a baseball fan. Have been since I was a little kid and will likely be till the day I die. To me the sport transcends the physical space it is played on and enters into a narrative and symbolic realm. When you tend to be vocal about baseball like I am, you hear a lot of rebukes: “How hard could it be?” “Why are the players so fat?” “It’s so boring.” Well, to quote the great Red Barber, “Baseball is dull only to dull minds” and I guess I intend to do some sharpening. My ICM finale will attempt to educate users about baseball by having them play the sport themselves. I hope to show them the nuance, the beauty and the difficulty of the sport both visually and physically.
I know a good amount about baseball, which is to say I know about…oh, let’s say 30% of what baseball has to teach. One area that I struggle with is pitch recognition. For those unfamiliar, a pitcher has a certain arsenal with which he throws i.e. a fastball, a changeup, a curveball and a slider. If I were to describe these pitches to you they would sound very different but when they are moving at 90+ MPH, they’re hard to tell the difference. How can I create something that helps pitch recognition but isn’t just me sitting down at a screen and watching baseball highlights?

“Baseball is ninety percent mental and the other half is physical”


Over the summer I started working for a baseball website that does exactly what I am looking to do. I guess I was sort of curious as to how I could make this visual experience a more interactive one. For my PComp Midterm, I took the following sketch and replaced the mouse-pressed bat with an actual physical bat but this was just the beginning. What I aim to do with my ICM final is to make this a full-fledged experience. There will be a home plate that is essentially a trigger for three different modes. If you tap on the green part of the plate, the p5 sketch will throw fastballs right down the middle; this will be “Easy Mode”. If you tap on the yellow part of the plate, there will be a “Hard Mode” that features more challenging pitches like curveballs and sliders. If you press the red part “Game Mode”, an image will appear in the top left hand corner of the sketch featuring a pitcher who you will face off against.
Due to the fact that this is both a PComp and an ICM final, I’ve spent a bit more time focusing on the physical elements first as I feel that it will dictate what the ICM final ends up looking like. Truth be told though, it wasn’t until I play test the PComp idea that I got a lot of great feedback on what the ICM sketch should incorporate. Below is a tentative sketch as to what the screen will look during “Game Mode”.
img_7388
As you can see, there’s a mound and a ball being thrown towards you. There’s a batter’s box and a home plate, which will resemble what the user is actually standing on: a grass batters box next to a home plate. In the top left hand corner will be the face of the pitcher you are facing off against. Below him will be his arsenal. In the center of the screen there will be a scoreboard keeping track of how much time you have left to accrue hits and a hit counter.

Code

Luckily, a big part of the actual code is done due to my midterm, but there is still a lot left to accomplish. I need to create my own JSON file with various pieces of data from the pitchers we want to incorporate into the sketch. I need to figure out a way to map that data so that it appears accurately and realistically into the sketch too. After that, we can work on the other, more aesthetic features. Work has already begun on creating a button that can switch between different pitchers and is featured below (code here).

More?

As of now, there are still a lot of things that can be added and subtracted from the experience. I’m interested in providing as much information as possible while maintaining clarity in the sketch. The last thing I would want would be for the user to be overloaded with information. I would like to provide just enough for them to develop a genuine curiosity about baseball so that they might pursue an interest in it in the future.

The Future   

Ultimately, I would love to take this an put it into an even more immersive 3D experience. I feel like you’ll be able to get a good understanding of pitch recognition on a 2D plain, but you won’t be able to fully get it until you experience it in 3D.

Update!

Since last week, there have been a lot of strides made, here are a few of them:

Frequency.

The particular sketch that you are looking at is not only representative of the arsenal that Noah “Thor” Syndergaard threw in the 2016 season but also represents how frequently he threw said pitch:

Stadium and Scoreboard

This sketch shows a close resemblance to what the final product will look like. The pitchers will be able to be rotated (here it is using the keypressed function but in the final you will press a button located on the helmet (see video)), and a scoreboard will tally how many hits you’ve gathered.

Button 

A very cranky girlfriend uses the button function

Bill of Materials and Diagram

So attached below are the bill of materials and Fritzing diagram for my final project.

Starting with the B.O.M:

Item Amount Cost
Plastic Baseball Bat 1 $3.09
Arduino 101 1 $39.95
Mini Motor Disc 3 $5.85/$1.95 each
Haptic Motor Controller 1 $7.95
Force Sensing Resistors 4 $31.80/$7.95 each
Full sheet 1/2″ Ply 1 free
Fake Grass/Turf 2 free
Batting Helmet 2 $59.90/$29.95 each
Total: $148.54

As of right now, the plan is to replace the Arduino Uno that was used for the mid-term with an Arduino 101 and its built in accelerometer. My group and I are also interested in possibly making a custom built bat but as of now, we’re going to stick with the plastic model. The force sensing resistors will be placed on top of home plate and will be used to change game modes and the mini motor disc and haptic motor controller will be placed inside of the bat so that they can vibrate whenever the user gets a hit. The ply will be cut to make a more realistic batters box and will be covered in fake turf. This is solely an aesthetic choice, one that hopefully makes the atmosphere a bit more vibrant.

In terms of the Fritzing: I feel like this will change a lot because my group is interested in getting away from the Arduino 101 but I figured it would be helpful to include the schematic used for the mid-term in case it was needed in the future. Unfortunately, the Fritzing software doesn’t include the proper model of accelerometer used (the ADXL335 is included but looks drastically different from the one I used) nor the proper Bluetooth but I think it portrays a somewhat accurate schematic.

screen-shot-2016-11-09-at-1-26-34-am

 

 

 

Genre and p5

So for this assignment, I wanted to play around with the sound library in p5 by visualizing different genres on my bass. I was curious if there was any visible difference between funk and classical or rock and something more harmonic when the notes were given a form. I'm curious to see what happens if I play a p5 sketch before I play the video of me with the bass to see if people can guess what genre this is. Unfortunately, the audio that I got from my Mac speakers is... nothing short of awful. But it's mostly there to prove that what I am playing is what is occurring in the sketch. The code is at the very bottom of the sketch. 

var song;
var fft;
var button;
var mic;

var volhistory = [];

function toggleSong() {
background(255);
}

function setup() {
createCanvas(400, 400);
mic = new p5.AudioIn();
mic.start();
angleMode(DEGREES);
button = createButton('toggle');
button.mousePressed(toggleSong);
//song.play();
fft = new p5.FFT();
fft.setInput(mic);
}

function draw() {
// background(0);
var spectrum = fft.analyze();
var vol = mic.getLevel();
stroke(random(255), random(255), random(255));
for (var i=0; i var amp = spectrum[i];
var y = map(amp, 0, 256, height, 0);
ellipse(i, y, vol*200, vol*200);
}
// volhistory.push(vol);
stroke(255);
noFill();
}
// translate(width / 2, height / 2);
// beginShape();
// for (var i = 0; i < 360; i++) {
// var r = map(volhistory[i], 0, 1, 10, 100);
// var x = r * cos(i);
// var y = r * sin(i);
// vertex(x, y);
// }
// endShape();

// if (volhistory.length > 360) {
// volhistory.splice(0, 1);
// }
// //ellipse(100, 100, 200, vol * 200);
// }

Stopmotion

I have been thinking about this class since I signed up for it. My background before this program was in theater, especially original, ensemble based theater. While ITP has been a blast so far, it’s been difficult for me to focus solely on content and story in ICM, PComp or Fabrication so I was really looking forward to animation. I’ve had two characters stuck in my head for some time now and all I know about them is that…one is an old man, and one is an old dog. I know the old man is lonely, that his wife has passed and that he talks to her. I know the dog’s days are numbered. I also know Samuel Beckett is a very influential part of my life and so is the comedy of the tragic.

For this first project, I just wanted to bring these two characters to life. I plan to work with them a lot this semester and I wanted to start to get a sense of what they were like. I had the idea that this old man visits his wife’s grave everyday only to find the flower he’d placed there the day before eaten to the stem. I figured it’d be a nice exercise in futility if he came back every day, pondered who ate the flower, placed a new flower there only to walk off before realizing it was his own dog who’d eaten the flower. The man isn’t necessarily upset by all of this for the same reason that Camus posited Sisyphus was happy: at least he has a task. It’s definitely a study in Waiting for Godot meets Sisyphus.

Anyhow, I presented the idea to my group and they were – luckily for me – super gung ho about it. I have to say, from the top, this was the most pleasant group experience I’ve had at ITP and perhaps in my time as an artists. We communicated well, bounced ideas off one another, helped each other grow, and – most importantly – each filled a very specific role: I led most of the concept and storyboarding, Jixuan really took charge of the artistic direction and aesthetic and Roi took the lead on the filming and editing. With that said, all three of us contributed on everything, but still there was a point person. Even the building of the clay figures was a holy collaborative experience. All parts of the process – storyboarding, buying the materials at Blick, setting up the shots, filming, editing, sound editing – involved valuable input from all of us.

At the end of the day, I’m really proud of the work we created. It isn’t exactly what I had in mind but it took on a life of it’s own for sure and I’m really excited to continue exploring these two characters lives.

BABIP Comparisons

The below is an example and is much better viewed in full screen

 

So for this assignment I knew that I wanted to do something with baseball data. Luckily for me, baseball data is plentiful and easy to access; my go to is Fangraphs.

It’s easy to visualize baseball data but difficult to do so in a way that can be revealing. Anyone can great a histogram of all the HR’s that have been hit in June or by left handed batters, but that data visualization doesn’t really serve to reveal anything. I was curious in how the data can inform me of something that I didn’t know before.

In the past ten years or so, or definitely since the release of the novel and movie Moneyball, the baseball world has been obsessed with sabermetrics which is the application of statistical analysis to baseball. One of the key statistics to come out of the sabermetrics movement has been BABIP which can be described in depth if you click the link in the sketch. For better or worse though, it’s essentially a comparative statistic that reveals how lucky a batter has been in a given stretch. There is a career BABIP that is only created after 1,000 at-bats, and a players more recent numbers are compared to his career numbers to see if he’s getting luckier than usual or not.

This sketch is the beginning of what I hope to be a bigger project which is generating my own Fantasy Baseball draft software. I’d love for users to be able to have these sort of visual comparisons for a lot more fields than just BABIP.

No Laughing Matter

The first idea I had for this project came to me very quickly. Originally, I wanted to get a piece of wood, put two toy soldiers on opposite ends and use DC and Servo motors to have them pass something from the right side to the left. Knowing that would be very difficult in a short span of time, I simplified my idea. I would keep the object going from right to left but make it look like it’s orbiting! Maybe I could make a few planets pop out from the wood and orbit around one another? Nah, still too complex to do in less than a week. The idea of things popping out a bit really stuck with me though, it reminded me of old storybooks, which got me thinking about comic books. I used to be a big Batman nerd and the frame of the Joker laughing from "The Killing Joke" always stuck out in my mind so I figured why not try to do that.

I started by creating a model out of cardboard. I designed the background in illustrator and photoshop. Once I was happy with the background, I hand traced the Joker’s body onto the cardboard. This was just so I could get a reference of how much mat I needed to buy and how big I wanted my canvas to be. After the initial canvas was set I cut out a rough sketch of the Joker’s head on cardboard. I wanted the background to be the famous image but I wanted the project to have some depth hence making a different, slightly larger head. I knew I could take this head and put it on something – likely wood – that would have my motor enclosed in it.

Happy with the dimensions of all my things I made my Joker image on Photoshop/Illustrator which took quite a bit of time. Before I etched that on anything though I needed to decide what I was going to be etching on. I know I wanted to use mat board but how much and what color? I decided to have a green background covered up by a black mat board with the words HA cut out from it repeatedly. I figured this would give me depth and make the HA’s pop a bit more. I knew I had to incorporate the Joker Purple into the project too and that I would either want his face or his gloves to be white. So I went out and bought a bunch of green, purple, white and black mat from Blick.

I took my black mat and cut out the HA’s and it came out…ok. I was dumb and didn’t realize that the tiny part of the A’s would fall out because they wouldn’t be attached to anything. Also, because there were so many HA’s spread out over such a large canvas, some cut out very easily where as others were a bit more stubborn. With the HA’s cut out, rather then cut again I thought it would be cool to write in the section that was missing from the A’s myself. I thought by having a more human element, the HA’s would convey a tone closer to that of the Joker’s than a clean and neat one.

With the background done, I etched the Joker’s body and face for the background. Instead of using the laser to cut this though, I cut it out by hand with a box cutter, which went through the mat really easily and saved me a lot of time; it would’ve taken forever to cut out the joker the way I wanted I think. With the background fully done, all I needed to do now was find something that would let me attach a servo to it and elevate the Joker’s head and make the actual Joker head. I found perfect wood block in the shop and bore a 1” hole into it with the drill press (I measured the servo before hand to make sure the size was correct). I then bore a 0.5” hole into the side so that I could run my wire through it. Originally I was going to drill my servo into the block of wood but there was no need as the servo fit snuggly into the hole.

I measured out a proper size for the Joker’s head and etched it in purple and green mat. I wanted to cut out the hair from the green mat and cut out the space where it would go in the purple but when I tried to do it by hand it was super sloppy and didn’t look too great. By this point in the project, I hadn’t used the white mat at all and I was curious to see what the etch would look like on it. What came out was sort of glossy and had a nice…sheen to it I guess you could say. I figured I could take the purple gloves from the purple mat, cut them out and glue them to the white head to continue to add depth and when I tried it I was really pleased with the result.

With all the different components now made, all that remained was figuring out positioning for the wood block. I glued one of the plastic detachable servo motor pieces to the point on the Joker’s head that I wanted it to pivot from and attached it to the servo. I moved the block to a place where I was happy with and glued it with wood glue to that spot. There was so much surface area to cover with glue so I knew that the slightly heavy block wouldn’t be going anywhere.

Once the glue was set, I programmed the servo and gave it a test run and it turned out really well!