Skip to content

Deliverables

Below are the deliverables of the project and the planning.

BoM bill of materials

Quantity Price
ESP32 microcontroller 1 $20
WS8213b LED strip 8meters/960 LEDs $84
12V Air Pump 2 $20
Relays 2 $8

Slide show

Story telling script

FABRICADEMY 2023/24 Date: 22 March | 15:00 - 20:00 | Video script

Title of the video | Re-Humanizing Sensing Student | Hala Amer Location | 3rd floor classroom (303) Scheduled date and time | 22 March | 15:00 - 20:00

References:

  • https://www.youtube.com/watch?v=6KzbI3WUmsU
  • https://www.youtube.com/watch?v=CrYRJSvlmuI
  • https://www.youtube.com/watch?v=LQf6ZF778dU

Setting/Scenegrophy:

  • Two tanks (1x1m), 5m from the projection screen
  • Screen showing the room on the other side

Models: Crowd of around 5 people (Fabricademy students)

  • Hala
  • Barbara
  • Juli
  • Regina
  • Emma

SCRIPT:

TITLE SEQUENCE Re-Humanizing Sensing by Hala Amer CMC inflating

OPENING SCENE: INTRODUCTION Recording: showing the objects in the spaces without any motion, making it clear that there are two separate spaces Music: quiet Model: none Tools: lighting setup Camera: panning around showing the spaces + stills of the tanks, closeups of the tanks

SCENE 1 - ABSTRACT RECORDING: People walking into each space

MUSIC: footsteps + mechanical whirring/starting MODEL: random legs TOOLS: CAMERA: close to ground, front

SCENE 2 - COMING TO LIFE RECORDING: Facial recognition software starts to frame a face and the emotion is highlighted which begins to gradually change the light in the space and the object begins to move as well

MUSIC: mechanical sounds, pumps, water bubbling, sand moving, inflating objects MODELS: fabricademy students TOOLS: CAMERA: closeup of objects and details, showing the screen framing a face, panning to show the movement of object and people beginning to look at it

SCENE 5 - RANGE OF EMOTIONS RECORDING: Showing the range of emotions (colors, motions, and light)

MUSIC: mechanical sounds, pumps, water bubbling, sand moving, people walking around MODELS: TOOLS: CAMERA: panning to show overall movements, showing the movements of each tank throughout all the different emotions (fully for each case)

LAST SCENE: CONNECTIONS RECORDING: People walking out (reverse of people walking in) One person remaining behind on each end looking at each other, person next to the object grabbing the movement by the person on camera side to show the established connection between them

MUSIC: silence MODELS: two people one on each end TOOLS: CAMERA: closeup of hands grabbing, wide shot of the people looking at each other

NECESSARY SHOTS:

  • Closeups of tanks still
  • Closeup of biobots still (not moving/inflating)
  • Closeup of the biobots textures
  • Panning showing tanks with the screen behind it (people walking on the other side)
  • Wideview of the water tank inflating
  • Closeup of the water tank bubbles
  • Closeups of the water tanks with the biobots
  • Closeups of the sand tank with the biobots
  • Closeup of the sand tank showing sand trickling down
  • Wideview showing the colors changing on sand tank
  • Wideview showing the colors changing on water tank
  • Closeup of feet walking in and out
  • View of people from the screen looking at the movement
  • Closeup of hand closing in and squeezing/touching biobots

NECESSARY SOUND RECORDINGS:

  • Shoes/feet walking
  • Bubbles in water
  • Sand movement
  • Pump turning on and off (with relay click)
  • Biobots moving

Credits:

CONCEPT & RESEARCH Hala Amer

PROJECT MENTORING & SUPPORT Petra Garajová

ASSISTIVE MENTORING Emma, Julia & Gerard

VIDEO PRODUCTION Lina Córdoba Manuela Reyes Natalie Dobreva Petra Garajová Hala Amer

VIDEO ASSISTANTS

SOUND RECORDINGS Lina Córdoba Manuela Reyes Natalie Dobreva Petra Garajová Hala Amer

FABRICATION FILES

Code Example

#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_NeoPixel.h>

const char* ssid = "Iaac-Wifi P100";
const char* password = "EnterIaac22@";
const char* thingspeak_read_api_key = "M6NP3QNQUWXCWY9F";
const char* thingspeak_channel_id = "2406762";

#define LED_PIN 27
#define NUM_LEDS 400
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

int currentRed = 0, currentGreen = 0, currentBlue = 0;
const int relayPin1 = 33;  // Pump 1
const int relayPin2 = 13;  // Pump 2

unsigned long previousMillis = 0;
const long interval = 5000;

unsigned long lastPumpMillis1 = 0;
unsigned long lastPumpMillis2 = 0;
bool pumpState1 = false;
bool pumpState2 = false;
float lastIntensity = -1;
long colorData = 0;
float intensity = 0;
bool transitioning = false;
int emotionNumber = 0;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("WiFi Connected Successfully");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  strip.begin();
  strip.show();
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
  digitalWrite(relayPin1, LOW);
  digitalWrite(relayPin2, LOW);
}

void transitionToColor() {
  static unsigned long lastTransitionMillis = 0;
  static int step = 0;
  const int transitionSteps = 50;
  const int stepDelay = 10;

  if (!transitioning) return;

  unsigned long currentMillis = millis();
  if (currentMillis - lastTransitionMillis > stepDelay) {
    float progress = (float)step / (float)transitionSteps;
    int redValue = currentRed + (int)((colorData >> 16 & 0xFF) * intensity - currentRed) * progress;
    int greenValue = currentGreen + (int)((colorData >> 8 & 0xFF) * intensity - currentGreen) * progress;
    int blueValue = currentBlue + (int)((colorData & 0xFF) * intensity - currentBlue) * progress;

    for (int i = 0; i < NUM_LEDS; i++) {
      strip.setPixelColor(i, strip.Color(redValue, greenValue, blueValue));
    }
    strip.show();

    lastTransitionMillis = millis();
    step++;

    if (step > transitionSteps) {
      transitioning = false;
      step = 0;
      currentRed = redValue;
      currentGreen = greenValue;
      currentBlue = blueValue;
    }
  }
}

void pumpControl() {
  unsigned long currentMillis = millis();
  Serial.println("PUMP CONTROL");

  // If intensity is less than 0.3, keep pumps off
  if (intensity <= 0.3) {
    digitalWrite(relayPin1, LOW);
    digitalWrite(relayPin2, LOW);
    Serial.println("LOW INTENSITY PUMP OFF");
    return;
  }

  // Turn on pumps based on detected emotion
  if (pumpState1 && (currentMillis - lastPumpMillis1 > 5000)) {  // Pump on duration
    digitalWrite(relayPin1, LOW);                                     // Turn pump 1 off
    pumpState1 = false;
    Serial.println("Pump 1 turned off");
    return;
  } 
  if (pumpState2 && (currentMillis - lastPumpMillis2 > 10000)) {  // Pump on duration
    digitalWrite(relayPin2, LOW);                                       // Turn pump 2 off
    pumpState2 = false;
    Serial.println("Pump 2 turned off");
    return;
  } 
  if (!pumpState1 && !pumpState2) {
    // Check detected emotion and turn on respective pumps
    Serial.println("pumping");
    Serial.println(emotionNumber);
    if (intensity > 0.3) {
      if (emotionNumber == 1) {         // Angry
        digitalWrite(relayPin1, HIGH);  // Turn pump 1 on
        digitalWrite(relayPin2, HIGH);  // Turn pump 2 on
        pumpState1 = true;
        pumpState2 = true;
        lastPumpMillis1 = currentMillis;
        lastPumpMillis2 = currentMillis;
        Serial.println("Pump 1 and 2 turned on (Angry)");
      } else if (emotionNumber == 2) {  // Sad
        digitalWrite(relayPin2, HIGH);  // Turn pump 2 on
        pumpState2 = true;
        lastPumpMillis2 = currentMillis;
        Serial.println("Pump 2 turned on (Sad)");
      } else if (emotionNumber == 3) {  // Happy
        digitalWrite(relayPin1, HIGH);  // Turn pump 1 on
        pumpState1 = true;
        lastPumpMillis1 = currentMillis;
        Serial.println("Pump 1 turned on (Happy)");
      } else if (emotionNumber == 4) {  // Surprise
        digitalWrite(relayPin1, HIGH);  // Turn pump 1 on
        pumpState1 = true;
        lastPumpMillis1 = currentMillis;
        Serial.println("Pump 1 turned on (Surprise)");
      } else if (emotionNumber == 5) {  // Disgust
        digitalWrite(relayPin2, HIGH);  // Turn pump 2 on
        pumpState2 = true;
        lastPumpMillis2 = currentMillis;
        Serial.println("Pump 2 turned on (Disgust)");
      } else if (emotionNumber == 6) {  // Fear
        digitalWrite(relayPin1, HIGH);  // Turn pump 1 on
        digitalWrite(relayPin2, HIGH);  // Turn pump 2 on
        pumpState1 = true;
        pumpState2 = true;
        lastPumpMillis1 = currentMillis;
        lastPumpMillis2 = currentMillis;
        Serial.println("Pump 1 and 2 turned on (Fear)");
      }
    }
  } else {
    Serial.println("DOING NOTHING");
  }
}

void fetchData() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    HTTPClient http;
    String serverPath = "http://api.thingspeak.com/channels/" + String(thingspeak_channel_id) + "/feeds/last.json?api_key=" + String(thingspeak_read_api_key);
    http.begin(serverPath);
    int httpResponseCode = http.GET();

    if (httpResponseCode == 200) {
      String payload = http.getString();
      Serial.println("Received data from ThingSpeak:");
      Serial.println(payload);

      long newColorData = strtol(payload.substring(payload.indexOf("field1\":\"") + 9, payload.indexOf("\",\"field2\"")).c_str(), NULL, 16);
      float newIntensity = payload.substring(payload.indexOf("field2\":\"") + 9, payload.indexOf("\"}")).toFloat();
      int newEmotionNumber = payload.substring(payload.indexOf("field3\":\"") + 9, payload.indexOf("}")).toInt();
      Serial.println(newEmotionNumber);

      if (newIntensity == 0) { // No faces detected, turn off the light
        colorData = 0;
        intensity = 0;
      } else if (newColorData != colorData || newIntensity != intensity || newEmotionNumber != emotionNumber) {
        colorData = newColorData;
        intensity = newIntensity;
        emotionNumber = newEmotionNumber;
        transitioning = true;            // Start new transition
        previousMillis = currentMillis;  // Update time stamp for fetch interval
      }
    } else {
      Serial.print("Error on HTTP request, code: ");
      Serial.println(httpResponseCode);
    }
    http.end();
  }
}

void loop() {
  fetchData();
  transitionToColor();
  pumpControl();

}

How-Tos & Tutorials

---