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 |
Useful links¶
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();
}