Skip to content

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.