Final Project

Exquisite Corpse

My final project draws inspiration from the 1920s Surrealist parlor drawing game Exquisite Corpse.

Exquisite Corpse is a game in which “each participant takes turns writing or drawing on a sheet of paper, folding it to conceal his or her contribution, and then passing it to the next player for a further contribution.”

This project is a touch-based digital take on the original drawing game, where users are invited to interact with a panel of touch-sensitive icons that trigger a sequence of corresponding visuals in a web browser. The images are generated randomly based on the user’s touch and are projected onto a screen or wall in front of the user.

Touch-Based Digital Exquisite Corpse

Visual Diagram

Fritzing Diagram (Circuit)

This project requires a simple circuit with a solderless breadboard, (1M and 220K) resistors, and jumper wires.

Components/ Bill of Materials

Touch Panel

-Bare conductive paint (black)
-paper
-canvas
-frame
-laser-cut wooden or acrylic overlay

Circuit


-solderless breadboard
-microcontroller (Arduino Uno) with USB cable
-jumper wires
-resistors (1M and 220K)
-alligator clips

Other

-laptop
-projector
-Arduino IDE
-p5.js
-p5.js serialport library

Arduino Code

#include <CapacitiveSensor.h>

int ledPin1 = 3;
int ledPin2 = 5;
int ledPin3 = 7;
int ledPin4 = 12;

//Receiver Pins = 2, 10, 11, 13
//Sensor Pins =  4, 6, 8, 18

CapacitiveSensor   cs_2_4 = CapacitiveSensor(2, 4);
CapacitiveSensor   cs_10_6 = CapacitiveSensor(10, 6);
CapacitiveSensor   cs_11_8 = CapacitiveSensor(11, 8);
CapacitiveSensor   cs_13_1 = CapacitiveSensor(13, 18);

void setup()
{
  cs_2_4.set_CS_Timeout_Millis(100);
  cs_10_6.set_CS_Timeout_Millis(100);
  cs_11_8.set_CS_Timeout_Millis(100);
  cs_13_1.set_CS_Timeout_Millis(100);

  Serial.begin(9600);

  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(ledPin4, OUTPUT);
}

void loop()
{
  long start = millis();
  long total1 =  cs_2_4.capacitiveSensor(30);
  long total2 =  cs_10_6.capacitiveSensor(30);
  long total3 =  cs_11_8.capacitiveSensor(30);
  long total4 = cs_13_1.capacitiveSensor(30);

  int state1 = 0;
  int state2 = 0;
  int state3 = 0;
  int state4 = 0;



  if (total1 > 100) {
    digitalWrite(ledPin1, HIGH);
    state1 = 1;
  }

  else if (total2 > 100) {
    digitalWrite(ledPin2, HIGH);
    state2 = 1;
  }

  else if (total3 > 100) {
    digitalWrite(ledPin3, HIGH);
    state3 = 1;
  }

  else if (total4 > 100) {
    digitalWrite(ledPin4, HIGH);
    state4 = 1;
  }
  else {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin4, LOW);
  }


  //  Serial.print(millis() - start);        // check on performance in milliseconds
  //  Serial.print("\t");                    // tab character for debug window spacing

  //Serial.print("Sensor1: ");
  Serial.print(state1);                  // print sensor output 1
  Serial.print(",");
  //Serial.print("Sensor2: ");
  Serial.print(state2);                  // print sensor output 2
  Serial.print(",");
  //Serial.print("Sensor3: ");
  Serial.print(state3);                // print sensor output 3
  Serial.print(",");
  //Serial.print("Sensor4: ");
  Serial.println(state4);                // print sensor output 4

delay(1);
}

p5.js Code

let heads = [];
let headCount = 7;
let torsos = [];
let torsoCount = 7;
let feet = [];
let feetCount = 7;
let previousStates = [0, 0, 0, 0];

let serial;
let portName = "/dev/tty.usbmodem143301";

let outByte;

let partsToShow = [];
let bodyParts = [];
let sensors = [];

function preload() {
  for (let i = 0; i < headCount; i++) {
    heads[i] = loadImage(`images/head${i}.jpeg`);
  }
  for (let i = 0; i < torsoCount; i++) {
    torsos[i] = loadImage(`images/torso${i}.jpeg`);
  }
  for (let i = 0; i < feetCount; i++) {
    feet[i] = loadImage(`images/feet${i}.jpeg`);
  }
}

function setup() {
  createCanvas(windowWidth, 810); // FIX CANVAS SIZE TO SCALE FOR SCREEN PROJECTOR
  serial = new p5.SerialPort();

  serial.open(portName);

  serial.on("data", serialEvent);
  bodyParts = [heads, torsos, feet];
}

function draw() {
  sensorButtons();
  displayImages();
}

function displayImages() {
  background(255);
  imageMode(CENTER);
  if (partsToShow[0]) {
    image(partsToShow[0], width / 2, 135);
  }
  if (partsToShow[1]) {
    image(partsToShow[1], width / 2, 405);
  }
  if (partsToShow[2]) {
    image(partsToShow[2], width / 2, 675);
  }
}

function serialEvent() {
  if (serial.available() > 0) {
    let inString = serial.readStringUntil("\r\n");

    if (inString.length > 0) {
      //create an array and split at the empty space or tab character?
      let sensorArray = split(inString, ",");

      if (sensorArray.length > 3) {
        sensors[0] = Number(sensorArray[0]);
        sensors[1] = Number(sensorArray[1]);
        sensors[2] = Number(sensorArray[2]);
        sensors[3] = Number(sensorArray[3]);
      }
    }
  }
}

function sensorButtons() {
  for (let i = 0; i < sensors.length; i++) {
    if (sensors[i] != previousStates[i]) {
      previousStates[i] = sensors[i];
      if (sensors[i] == 1) {
        if (i < sensors.length - 1) {
          partsToShow[i] = random(bodyParts[i]);
        } else {
          for (let i = 0; i < partsToShow.length; i++) {
            partsToShow[i] = false;
          }
        }
      }
    }
  }
}

Testing

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s