Skip to content

Process

Ideation & sketches

To begin the ideation phase, first I started by determining what type of interaction the project would have, then ideas based on the analogue research, some where more like a mat, like a board game, framing the shape of the hands, using just buttons and after some more ideas, I explored the concept of developing this game in a wearable, specifically gloves.

I ended up liking the most the glove idea since it would be a real challenge for me, and after some interviews with some friends they also liked that idea, among with my local and global instructors.

When I re-presented my idea in the global class, the comments where to first focus first on the dinamic of the wearable (game), recommending to not create a new one, but take one as a reference and adaptt it.

I also got some comments in the focus groups from Nuria and Erika, recommending me to explore the idea of the wearable as a way of interacting with some games via serial port instead of just the wearable. After thinking it through, I decided to find a way of making the gloves work on their own, without the need to connect to a computer. This recommendation helped me to start thinking on the outputs that I would need to integrate like a little screen to visualize the score, or a button to reset, etc.

To further define the project, I began to ask myself questions about aspects that I still had to resolve, and answering them from what I knew, as possibilities to explore:

Doing this exercise really helped me to see all the things I was missing, and sometimes even one question led to other three, or answering one automatically answered another.

First tests electronics

To have a clear idea the basics of the electronic required for this project, I began to make a few test using first only two sensors, then adding one more no see how easily or hard it was to add another pin of interaction.

I used ChatGPT to develop the codes. The initial prompt was:

This is going to be C++ code, and it will work as follows: I'm going to use three Neopixels to indicate which color goes with which. I'll only use three colors, the RGB ones. I'll have one GND wire and two others on different pins. Each of these three wires has one of the Neopixels I mentioned. So, if one of the Neopixels on the pin wires is blue, and the GND wire is also blue, I should connect those wires. If I connect the green wire with the blue GND wire, it's incorrect and the code shouldn't work. The colors should be random. Neopixel controlling GND on D10, Neopixel wire 1 on A0

To make it work I had to keep upgrading Chat on what to change, since each time there was something not working the way I expected:

The color of the neo pixels weren't following the idea of the game, there wasn’t a relation that the code could understand in other to determine whether winning or losing, the match between neo pixels was wrong, it didn’t register when the correct match was carried on, the time of action was to short, etc.

Non working test

The key part to make ChatGPT understand how the interaction of matching was going to be carried on was by referencing the code I used to develop a glove that could be play as a piano, that code was also developed with ChatGPT, and it worked by INPUT_PULLUP and INPUT_LOW.

3 neo pixels (working)

Code

#include <Adafruit_NeoPixel.h>

// ----- PINES -----
#define PIN_GND  D4
#define PIN_C1   D1
#define PIN_C2   D2

#define CABLE1_IN D6
#define CABLE2_IN D7

#define PIN_RESTART D9

#define NUMPIXELS 1

// ----- NEOPIXELS -----
Adafruit_NeoPixel ledGND(NUMPIXELS, PIN_GND, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC1 (NUMPIXELS, PIN_C1, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel ledC2 (NUMPIXELS, PIN_C2, NEO_GRB + NEO_KHZ800);

// ----- VARIABLES -----
int colorGND;
int colorC1;
int colorC2;

int colores[3][3] = {
  {255, 0, 0},     // rojo
  {0, 255, 0},     // verde
  {0, 0, 255}      // azul
};

bool bloqueo = false;

unsigned long tiempoInicio = 0;
bool esperandoMatch = false;
int cableEnJuego = 0;

// -----------------------------
void setup() {
  Serial.begin(115200);

  ledGND.begin();
  ledC1.begin();
  ledC2.begin();

  pinMode(CABLE1_IN, INPUT_PULLUP);
  pinMode(CABLE2_IN, INPUT_PULLUP);
  pinMode(PIN_RESTART, INPUT_PULLUP);

  randomSeed(analogRead(26));

  generarColores();
}

// -----------------------------
void loop() {

  if (bloqueo) {
    if (digitalRead(PIN_RESTART) == LOW) {
      bloqueo = false;
      generarColores();
      delay(250);
    }
    return;
  }

  if (esperandoMatch && (millis() - tiempoInicio > 2000)) {
    fallo();
    return;
  }

  int c1 = digitalRead(CABLE1_IN);
  int c2 = digitalRead(CABLE2_IN);

  // PRIMER TOQUE
  if (!esperandoMatch) {

    if (c1 == LOW) {
      esperandoMatch = true;
      tiempoInicio = millis();
      cableEnJuego = 1;
      Serial.println("Cable 1 tocado");
    }

    if (c2 == LOW) {
      esperandoMatch = true;
      tiempoInicio = millis();
      cableEnJuego = 2;
      Serial.println("Cable 2 tocado");
    }
  }

  // MATCH SOLO CONTRA GND
  if (esperandoMatch) {

    if (cableEnJuego == 1 && c1 == LOW) {
      if (colorC1 == colorGND) exito();
      else fallo();
    }

    if (cableEnJuego == 2 && c2 == LOW) {
      if (colorC2 == colorGND) exito();
      else fallo();
    }
  }
}

// -----------------------------
void exito() {
  Serial.println("✔ ¡Correcto!");
  esperandoMatch = false;
  delay(200);
  generarColores();
}

// -----------------------------
void generarColores() {

  esperandoMatch = false;

  colorGND = random(0, 3);

  int correcto = random(1, 3); // 1 o 2

  if (correcto == 1) {
    colorC1 = colorGND;

    do { colorC2 = random(0, 3); }
    while (colorC2 == colorGND);
  }
  else {
    colorC2 = colorGND;

    do { colorC1 = random(0, 3); }
    while (colorC1 == colorGND);
  }

  // Nunca iguales
  while (colorC1 == colorC2) {
    colorC2 = (colorC2 + 1) % 3;
  }

  // Mostrar colores
  ledGND.setPixelColor(0, colores[colorGND][0], colores[colorGND][1], colores[colorGND][2]);
  ledC1.setPixelColor(0, colores[colorC1][0], colores[colorC1][1], colores[colorC1][2]);
  ledC2.setPixelColor(0, colores[colorC2][0], colores[colorC2][1], colores[colorC2][2]);

  ledGND.show();
  ledC1.show();
  ledC2.show();

  Serial.println("---- NUEVOS COLORES ----");
  Serial.print("GND = "); Serial.println(colorGND);
  Serial.print("C1  = "); Serial.println(colorC1);
  Serial.print("C2  = "); Serial.println(colorC2);
  Serial.println("------------------------");
}

// -----------------------------
void fallo() {
  Serial.println("❌ ERROR");

  ledGND.setPixelColor(0, 255, 255, 255);
  ledC1.setPixelColor(0, 255, 255, 255);
  ledC2.setPixelColor(0, 255, 255, 255);

  ledGND.show();
  ledC1.show();
  ledC2.show();

  delay(700);

  ledGND.clear(); ledGND.show();
  ledC1.clear(); ledC1.show();
  ledC2.clear(); ledC2.show();

  bloqueo = true;
  esperandoMatch = false;

  Serial.println("Reiniciar con botón");
}

4 neo pixels (working)

#include <Adafruit_NeoPixel.h>

// ----- PINES -----
#define PIN_GND     D4   // NeoPixel GND
#define PIN_C1      D1   // NeoPixel C1
#define PIN_C2      D2   // NeoPixel C2
#define PIN_C3      D3   // NeoPixel C3

#define CABLE1_IN   D6   // Entrada digital cable 1
#define CABLE2_IN   D7   // Entrada digital cable 2
#define CABLE3_IN   D8   // Entrada digital cable 3

#define PIN_RESTART D9   // Botón reinicio

#define NUMPIXELS 1

// ----- NEOPIXELS -----
Adafruit_NeoPixel ledGND(NUMPIXELS, PIN_GND, NEO_GRB + NEO_KHZ800);
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);

// ----- VARIABLES -----
int colorGND;
int colorC1;
int colorC2;
int colorC3;

int colores[3][3] = {
  {255, 0, 0},   // rojo
  {0, 255, 0},   // verde
  {0, 0, 255}    // azul
};

bool bloqueo = false;
unsigned long tiempoInicio = 0;
bool esperandoMatch = false;
int cableEnJuego = 0;

// -----------------------------
void setup() {
  Serial.begin(115200);

  ledGND.begin();
  ledC1.begin();
  ledC2.begin();
  ledC3.begin();

  pinMode(CABLE1_IN, INPUT_PULLUP);
  pinMode(CABLE2_IN, INPUT_PULLUP);
  pinMode(CABLE3_IN, INPUT_PULLUP);
  pinMode(PIN_RESTART, INPUT_PULLUP);

  randomSeed(analogRead(26));

  generarColores();
}

// -----------------------------
void loop() {

  if (bloqueo) {
    if (digitalRead(PIN_RESTART) == LOW) {
      bloqueo = false;
      generarColores();
      delay(250);
    }
    return;
  }

  int c1 = digitalRead(CABLE1_IN);
  int c2 = digitalRead(CABLE2_IN);
  int c3 = digitalRead(CABLE3_IN);

  // Verificar tiempo límite de 5 segundos
  if (esperandoMatch && (millis() - tiempoInicio > 5000)) {
    Serial.println("⏳ Tiempo agotado: no se hizo match");
    fallo();
    return;
  }

  // Primer toque de cualquier cable
  if (!esperandoMatch) {
    if (c1 == LOW) { esperandoMatch = true; tiempoInicio = millis(); cableEnJuego = 1; Serial.println("Cable 1 tocado — 5 segundos para coincidir."); }
    if (c2 == LOW) { esperandoMatch = true; tiempoInicio = millis(); cableEnJuego = 2; Serial.println("Cable 2 tocado — 5 segundos para coincidir."); }
    if (c3 == LOW) { esperandoMatch = true; tiempoInicio = millis(); cableEnJuego = 3; Serial.println("Cable 3 tocado — 5 segundos para coincidir."); }
  }

  // Detectar si el cable coincide con GND
  if (esperandoMatch) {
    if (cableEnJuego == 1 && c1 == LOW) { if (colorC1 == colorGND) exito(); else fallo(); }
    if (cableEnJuego == 2 && c2 == LOW) { if (colorC2 == colorGND) exito(); else fallo(); }
    if (cableEnJuego == 3 && c3 == LOW) { if (colorC3 == colorGND) exito(); else fallo(); }
  }
}

// -----------------------------
void exito() {
  Serial.println("✔ ¡Correcto!");
  esperandoMatch = false;
  delay(200);
  generarColores();
}

// -----------------------------
// Generar colores: 1 cable coincide, los otros dos iguales y distintos de GND
// -----------------------------
void generarColores() {
  esperandoMatch = false;

  colorGND = random(0, 3);  // Color GND

  // Elegir cuál cable será correcto
  int cableCorrecto = random(1,4); // 1,2 o 3

  // Color incorrecto (distinto a GND)
  int colorIncorrecto;
  do { colorIncorrecto = random(0,3); } while(colorIncorrecto == colorGND);

  // Inicialmente todos los cables incorrectos
  colorC1 = colorC2 = colorC3 = colorIncorrecto;

  // Reemplazar el cable correcto
  if (cableCorrecto == 1) colorC1 = colorGND;
  if (cableCorrecto == 2) colorC2 = colorGND;
  if (cableCorrecto == 3) colorC3 = colorGND;

  // Mostrar en neopixels
  ledGND.setPixelColor(0, colores[colorGND][0], colores[colorGND][1], colores[colorGND][2]);
  ledC1.setPixelColor(0, colores[colorC1][0], colores[colorC1][1], colores[colorC1][2]);
  ledC2.setPixelColor(0, colores[colorC2][0], colores[colorC2][1], colores[colorC2][2]);
  ledC3.setPixelColor(0, colores[colorC3][0], colores[colorC3][1], colores[colorC3][2]);

  ledGND.show();
  ledC1.show();
  ledC2.show();
  ledC3.show();

  Serial.println("---- Nuevos Colores ----");
  Serial.print("GND = "); Serial.println(colorGND);
  Serial.print("C1  = "); Serial.println(colorC1);
  Serial.print("C2  = "); Serial.println(colorC2);
  Serial.print("C3  = "); Serial.println(colorC3);
  Serial.println("------------------------");
}

// -----------------------------
void fallo() {
  Serial.println("❌ ERROR");

  ledGND.setPixelColor(0, 255, 255, 255);
  ledC1.setPixelColor(0, 255, 255, 255);
  ledC2.setPixelColor(0, 255, 255, 255);
  ledC3.setPixelColor(0, 255, 255, 255);

  ledGND.show();
  ledC1.show();
  ledC2.show();
  ledC3.show();

  delay(700);

  ledGND.clear(); ledGND.show();
  ledC1.clear(); ledC1.show();
  ledC2.clear(); ledC2.show();
  ledC3.clear(); ledC3.show();

  bloqueo = true;
  esperandoMatch = false;

  Serial.println("Juego detenido — presiona reinicio.");
}

Here my notes of the adjustments I made in the prompt to get to the working codes:

Design & Fabrication

once you start designing and fabricating your first tests, you can link both at the bottom of the page with footnotes


"This step of the process was important because i learnt to draft my own pattern digitally. The first tests of this can be seen here on the right, find half- or test-fabrication files here1"


Prototypes

To visualize the components and their distribution on the hand more realistically, I downloaded a hand model from Sketchfab and quickly created the components in Rhinoceros using their real 1:1 dimensions. This allowed me to move them around, see how they would sit, and then sketch with an accurate reference.

IN PROGRESS… I was exploring the idea of making this wearable by parts, so that it can “build up” on the hands; and so here's some ideas of how to have the sensors and neo pixels in the fingers.

prototypes are your first step towards shaping your final piece, product, material et cetera


Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Mentoring notes

Mentors in all sessions may share with you their comments, notes, advise, projects and technical equipment to check out. This is good place to share those, so that you can find them later on when you need them the most!

Half-fabrication files


  1. Test file: 3d modelling test