Deliverables¶
GANTT¶
START PLANNING!
The project development will take place practically on only two months (January and February), leaving March to work on the video, booklet, and final arrangements; so, I organize all the things I need to do to archive this project in time, using the website clickup, which have many ways to organize the information, making it a really good tool to keep track on everything.
I decided to use this site instead of doing it in a document since in it I can register when I'm done with one task, it will also remind me via email that I have pending work to do, or that I missed a deadline.
Here the link to my Gannt
BoM bill of materials¶
Materials¶
| Material | Qty | Description | Price (MXN) | Link |
|---|---|---|---|---|
| Fabric | 2m | Neoprene | $200.00 | Physical store |
| Conductive thread | 1pc | stainless steel | $270.51 | amazon |
| Conductive Fabric | 1pc | Zinc | $174.27 | adafruit.com |
| Conductive Tape | 1pc | Copper (1in) | $305.99 | amazon |
| Neopixels | 8 pcs | ws2812b neopixel | $471.37 | amazon |
| Microcontroller | 2 pcs | XiaoEsp 32 S3 | $250.00$ | amazon |
| Welding | 1pc | tin/lead (60/40) | $59.00 | Steren |
| Metallic safety pins | 34 pcs | Diameter 7.5mm, Zinc | $12.99 | Parisina |
| Powerbank | 2pc | Power Bank de 5,000 mAh USB | $199.00 | Steren |
Machinery and tools¶
| Machinery | Tools |
|---|---|
| Laser cutter | Multimeter |
| Sewing machine | Fabric scissors |
| Soldering iron | |
| Cutter | |
| Needles |
Slide show¶
Story telling script¶
01¶

02¶

FABRICATION FILES¶
Click here to download the file to laser cut the necessary fabric pieces: Laser cut plans
I recommend that you first try and verify how to use the fabric you are going to use, since in my experience using spandex can be a bit complicated and can be the determining factor for whether the pieces turn out well or not, since they can lose their shape depending on which direction the pieces are facing.
Codes¶
Unfortunately, I couldn't connect the two gloves wirelessly, so the codes must be loaded into each hand individually, but the same code works on both hands since I assigned the sensors and neopixels the same way on both hands.
All codes were generated using the artificial intelligence ChatGPT
All the dynamics work with INPUT_PULLUP. Touching the correct finger with the thumb (GND) sets the pin to LOW.
01. Lightning Reflex¶
This code is played by touching the finger whose neopixel lights up; it will get faster each time.
#include <Adafruit_NeoPixel.h>
// -----------------------------------
// PINES
// -----------------------------------
#define PIN_C1 D1 // NeoPixel C1
#define PIN_C2 D2 // NeoPixel C2
#define PIN_C3 D3 // NeoPixel C3
#define PIN_C4 D4 // NeoPixel C4
#define CABLE1_IN D5 // Entrada cable 1
#define CABLE2_IN D8 // Entrada cable 2
#define CABLE3_IN D9 // Entrada cable 3
#define CABLE4_IN D10 // Entrada cable 4
#define NUMPIXELS 1
// -----------------------------------
// NEOPIXELS
// -----------------------------------
Adafruit_NeoPixel ledC1(NUMPIXELS, PIN_C1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC2(NUMPIXELS, PIN_C2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC3(NUMPIXELS, PIN_C3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC4(NUMPIXELS, PIN_C4, NEO_GRB + NEO_KHZ800);
// -----------------------------------
// VARIABLES DEL JUEGO
// -----------------------------------
unsigned long tiempoInicio;
int tiempoLimite = 5000; // 5 segundos para reaccionar
int ronda = 0;
int ledActivo = 0;
// -----------------------------------
// FUNCIONES
// -----------------------------------
void clearAll() {
ledC1.clear(); ledC2.clear(); ledC3.clear(); ledC4.clear();
ledC1.show(); ledC2.show(); ledC3.show(); ledC4.show();
}
void encenderLED(int led, int r, int g, int b) {
clearAll();
if (led == 1) { ledC1.setPixelColor(0, r, g, b); ledC1.show(); }
if (led == 2) { ledC2.setPixelColor(0, r, g, b); ledC2.show(); }
if (led == 3) { ledC3.setPixelColor(0, r, g, b); ledC3.show(); }
if (led == 4) { ledC4.setPixelColor(0, r, g, b); ledC4.show(); }
}
void fallo() {
Serial.println("❌ FALLASTE — Reinicio");
for (int i = 0; i < 3; i++) {
ledC1.setPixelColor(0, 255, 0, 0);
ledC2.setPixelColor(0, 255, 0, 0);
ledC3.setPixelColor(0, 255, 0, 0);
ledC4.setPixelColor(0, 255, 0, 0);
ledC1.show(); ledC2.show(); ledC3.show(); ledC4.show();
delay(200);
clearAll();
delay(200);
}
ronda = 0;
tiempoLimite = 5000; // Reiniciar a 5 segundos
delay(400);
iniciarRonda();
}
void iniciarRonda() {
ronda++;
Serial.print("➡ Nueva ronda: ");
Serial.println(ronda);
// LED aleatorio
ledActivo = random(1, 5);
// Color aleatorio
int r = random(50, 256);
int g = random(50, 256);
int b = random(50, 256);
encenderLED(ledActivo, r, g, b);
tiempoInicio = millis();
}
void acierto() {
Serial.println("✔ Correcto!");
// Efecto verde rápido
for (int i = 0; i < 2; i++) {
encenderLED(ledActivo, 0, 255, 0);
delay(120);
clearAll();
delay(120);
}
// Disminuir solo 3 ms por ronda
if (tiempoLimite > 300) tiempoLimite -= 3;
delay(200);
iniciarRonda();
}
int leerCable() {
if (digitalRead(CABLE1_IN) == LOW) return 1;
if (digitalRead(CABLE2_IN) == LOW) return 2;
if (digitalRead(CABLE3_IN) == LOW) return 3;
if (digitalRead(CABLE4_IN) == LOW) return 4;
return 0;
}
// -----------------------------------
// SETUP
// -----------------------------------
void setup() {
Serial.begin(115200);
ledC1.begin();
ledC2.begin();
ledC3.begin();
ledC4.begin();
ledC1.setBrightness(80);
ledC2.setBrightness(80);
ledC3.setBrightness(80);
ledC4.setBrightness(80);
pinMode(CABLE1_IN, INPUT_PULLUP);
pinMode(CABLE2_IN, INPUT_PULLUP);
pinMode(CABLE3_IN, INPUT_PULLUP);
pinMode(CABLE4_IN, INPUT_PULLUP);
randomSeed(analogRead(26));
iniciarRonda();
}
// -----------------------------------
// LOOP
// -----------------------------------
void loop() {
// Tiempo agotado
if (millis() - tiempoInicio > tiempoLimite) {
fallo();
return;
}
int lectura = leerCable();
if (lectura != 0) {
clearAll();
delay(50);
if (lectura == ledActivo) {
acierto();
} else {
fallo();
}
delay(200);
}
}
02. Remeber the secuence¶
It's a simple dynamic; it will generate a random sequence, adding a new step each time until the person makes a mistake or takes too long.
#include <Adafruit_NeoPixel.h>
// -----------------------------------
// PINES
// -----------------------------------
#define PIN_C1 D1 // NeoPixel C1
#define PIN_C2 D2 // NeoPixel C2
#define PIN_C3 D3 // NeoPixel C3
#define PIN_C4 D4 // NeoPixel C4
#define CABLE1_IN D5 // Entrada cable 1
#define CABLE2_IN D8 // Entrada cable 2
#define CABLE3_IN D9 // Entrada cable 3
#define CABLE4_IN D10 // Entrada cable 4
#define NUMPIXELS 1
// -----------------------------------
// NEOPIXELS
// -----------------------------------
Adafruit_NeoPixel ledC1(NUMPIXELS, PIN_C1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC2(NUMPIXELS, PIN_C2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC3(NUMPIXELS, PIN_C3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC4(NUMPIXELS, PIN_C4, NEO_GRB + NEO_KHZ800);
// -----------------------------------
// COLORES FIJOS
// -----------------------------------
int colorC1[3];
int colorC2[3];
int colorC3[3];
int colorC4[3];
#define MAX_SEC 200
int secuencia[MAX_SEC];
int longitud = 0;
int pasoJugador = 0;
bool bloqueo = false;
unsigned long tiempoInicio;
// velocidad base
int tiempoPaso = 550;
// -----------------------------------
// FUNCIONES
// -----------------------------------
void generarColores() {
for (int i = 0; i < 3; i++) {
colorC1[i] = random(80, 256);
colorC2[i] = random(80, 256);
colorC3[i] = random(80, 256);
colorC4[i] = random(80, 256);
}
Serial.println("---- COLORES NUEVOS ----");
}
void clearAll() {
ledC1.clear(); ledC2.clear(); ledC3.clear(); ledC4.clear();
ledC1.show(); ledC2.show(); ledC3.show(); ledC4.show();
}
void encenderLED(int led) {
clearAll();
if (led == 1) { ledC1.setPixelColor(0, colorC1[0], colorC1[1], colorC1[2]); ledC1.show(); }
if (led == 2) { ledC2.setPixelColor(0, colorC2[0], colorC2[1], colorC2[2]); ledC2.show(); }
if (led == 3) { ledC3.setPixelColor(0, colorC3[0], colorC3[1], colorC3[2]); ledC3.show(); }
if (led == 4) { ledC4.setPixelColor(0, colorC4[0], colorC4[1], colorC4[2]); ledC4.show(); }
}
void mostrarLED(int led, int t) {
encenderLED(led);
delay(t);
clearAll();
delay(120);
}
void mostrarSecuencia() {
Serial.println("Mostrando secuencia...");
for (int i = 0; i < longitud; i++) {
mostrarLED(secuencia[i], tiempoPaso);
}
}
void fallo() {
Serial.println("❌ ERROR — Jugador perdió");
for (int i = 0; i < 3; i++) {
ledC1.setPixelColor(0, 255, 255, 255);
ledC2.setPixelColor(0, 255, 255, 255);
ledC3.setPixelColor(0, 255, 255, 255);
ledC4.setPixelColor(0, 255, 255, 255);
ledC1.show(); ledC2.show(); ledC3.show(); ledC4.show();
delay(200);
clearAll();
delay(200);
}
// Reiniciar automáticamente
generarColores();
longitud = 1;
secuencia[0] = random(1, 5);
pasoJugador = 0;
tiempoPaso = 550;
delay(300);
mostrarSecuencia();
tiempoInicio = millis();
}
// -----------------------------------
// SETUP
// -----------------------------------
void setup() {
Serial.begin(115200);
ledC1.begin();
ledC2.begin();
ledC3.begin();
ledC4.begin();
// BRILLO MEDIO
ledC1.setBrightness(80);
ledC2.setBrightness(80);
ledC3.setBrightness(80);
ledC4.setBrightness(80);
pinMode(CABLE1_IN, INPUT_PULLUP);
pinMode(CABLE2_IN, INPUT_PULLUP);
pinMode(CABLE3_IN, INPUT_PULLUP);
pinMode(CABLE4_IN, INPUT_PULLUP);
randomSeed(analogRead(26));
generarColores();
longitud = 1;
secuencia[0] = random(1, 5);
mostrarSecuencia();
tiempoInicio = millis();
}
// -----------------------------------
// LOOP
// -----------------------------------
void loop() {
// límite de tiempo
if (millis() - tiempoInicio > 5000) {
fallo();
return;
}
int lectura = 0;
if (digitalRead(CABLE1_IN) == LOW) lectura = 1;
if (digitalRead(CABLE2_IN) == LOW) lectura = 2;
if (digitalRead(CABLE3_IN) == LOW) lectura = 3;
if (digitalRead(CABLE4_IN) == LOW) lectura = 4;
if (lectura != 0) {
mostrarLED(lectura, 200);
if (lectura == secuencia[pasoJugador]) {
pasoJugador++;
if (pasoJugador == longitud) {
// cada 10 aciertos -> aumentar velocidad
if (longitud % 10 == 0 && tiempoPaso > 150) {
tiempoPaso -= 60;
}
longitud++;
if (longitud >= MAX_SEC) longitud = MAX_SEC - 1;
secuencia[longitud - 1] = random(1, 5);
delay(250);
mostrarSecuencia();
pasoJugador = 0;
tiempoInicio = millis();
}
} else {
fallo();
}
delay(150);
}
}
I would say that these are the basic codes to be able to later have more difficult or challenging dynamics; it could be determined that only one color should be paid attention to, and the person must not only react to any light that turns on, but pay attention and discern before acting, etc.