When we first met with Judy and Sherry, we discussed possible ideas to pursue. Angel was thinking of something related to body dysmorphia, while the folk in IA thought of cyberbullying. I suggested that both could be linked to the idea of “paranoia,” a common trait amongst victims/sufferers of either side. Hence the direction towards the wall of eyes was solidified. From project III, I knew I had no means of creating any physical model that would be satisfactory. I simply did not have the materials. Luckily, Angel was able to book a flight home, and was able to construct a very nice installation.
As for my part, I worked on coding the movement of the eyes, with the main difficulty and most important feature being that of having the eyes track a user/audience member. For that, I used ml5 object detector, specifically using cocossd in order to filter people specifically.
The main obstacle I ran into was calculating the angles of the center eyes from only the angles of the left and right-most eyes containing the cameras (distance from camera to person unknown). At first, I looked at it as if it were a bunch of triangles, using trigonometry in order to calculate the angles of all the other eyes. This however, did not make sense since, depending on which side you were standing, the right triangles that could be calculated would reverse, hence changing certain given sides/angles. I woke up one day with the solution suddenly popping into my head, instead of thinking of it as triangles, I should’ve thought of it as a semi-circle; that is to say, the angles of all the eyes between the two extremes will always be within the range of their angles as well (eg. left = 40deg, right = 90deg, all eyes will be in between 40 and 90deg). I asked Angel to give me the specific measurements between the eyes only on a horizontal plane.
This way, I could just divide the total distance into even parts then multiply it by the different distances to get the ratios correct. Unfortunately, while testing the hardware setup with Angel, he had a faulty board and fried one laptop, and semi-destroying a usb port in another. Because the second computer only had 3 usb ports, and we needed 3 ports for the 2 cameras and the arduino board, we could not complete a fully working model. We also had some trouble with certain permission problems, which we solved by using a web server extension on chrome.
The original proposal was to link it to IA’s project by using VR, in which case, we would have a rather blank installation, acting as a canvas for their project. I could relay the same information from js to arduino to their Unity project, creating a pseudo-VR interaction by tracking the player-character’s model in the scene as in real life. The scene in Unity then would be act as an extension- or enhancement to our installation, adding more substance to the overall scene. This could not come to fruition however, with IA’s lack of headsets, so instead we planned to have their project projected onto our board, so that the eyes in their Unity scene matched up with the eyes of our installation.
Link to slides: https://docs.google.com/presentation/d/1Ob-zI4aqY4aXSXJuv-g2Jrwu8ly6mCwcy_Dsef40Agw/edit?usp=sharing
Code:
p5: https://editor.p5js.org/khx201/sketches/xPnp68R_-
arduino:
#include <Servo.h>
Servo left;
Servo right;
Servo mid[16];
int pinNum[16] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18}; //set up to user's left to right looking at the wall
int leftDeg = 135;
int rightDeg = 45;
int sinl = 20;
int sinr = 20;
int centerZone = 19;
int deadZoneRange = 2;
void setup() {
Serial.begin(9600);
left.attach(2);
right.attach(19);
left.write(90);
right.write(rightDeg);
for (int i = 0; i<16; i++) {
mid[i].attach(pinNum[i]);
}
}
void loop() {
if (Serial.available() > 0) {
String inLine = Serial.readStringUntil('\n');
Serial.println(inLine);
sinl = inLine.substring(0,2).toInt(); //0 = right 39 = left
sinr = inLine.substring(2,4).toInt();
if (sinl > centerZone-deadZoneRange && sinl < centerZone+deadZoneRange) {
sinl = 0;
}
else {
sinl = constrain(map(sinl, 0, 39, 90, -90), -90, 90);
}
if (sinl > centerZone-deadZoneRange && sinl < centerZone+deadZoneRange) {
sinl = 0;
}
else {
sinr = constrain(map(sinr, 0, 39, 90, -90), -90, 90);
}
leftDeg = constrain(leftDeg + sinl, 0, 180);
rightDeg = constrain(rightDeg + sinr, 0, 180);
left.write(leftDeg);
right.write(rightDeg);
//space between = 52.25in + 4.75/ 16 spaces + 1/
//1.5 1.75 7.25 1 4.5 3 5.5 1.75 1.5 3.25 2.5 7.5 5.5 1 3 1.75
int dist = (leftDeg-rightDeg);
float uniDist = dist/52.25;
float adjDist[] = {
uniDist*1.5, uniDist*3.25, uniDist*10.5, uniDist*11.5,
uniDist*16, uniDist*19, uniDist*24.5, uniDist*26.25,
uniDist*27.75, uniDist*31, uniDist*33.5, uniDist*41,
uniDist*46.5, uniDist*47.5, uniDist*50.5, uniDist*52.25
};
for (int i=0; i<16; i++) {
mid[i].write((int)(leftDeg-adjDist[i]));
}
}
}