Un Tetris hecho de luces, sobre una réplica del Green Building del MIT

En 2012, un grupo de estudiantes del MIT convirtió la fachada del Green Building en una pantalla gigante para jugar Tetris en vivo. Este proyecto reproduce ese hack en formato escritorio: una réplica impresa en 3D del edificio con una matriz de 9×13 = 117 LEDs direccionables y un gamepad mini para mover las piezas.

El cerebro es la Feather RP2040 PropMaker de Adafruit corriendo CircuitPython, y los LEDs son una tira de NeoPixels tipo "pebble" (esféricos, con pitch generoso para que cada uno entre limpio en una grilla impresa). Una batería LiPo de 1200 mAh permite jugarlo en portátil.

Cómo se juega

Vista frontal de la matriz de 117 NeoPixels encendida con piezas de Tetris

El control viene de un gamepad mini I2C con seesaw: trae joystick, botones A y B, y un botón Start. La lógica de juego es directa:

Gamepad mini I2C con joystick y botones, conector STEMMA QT

  • Joystick: mueve la pieza activa a izquierda y derecha (y rota con un movimiento corto).
  • Botón A: rota la pieza.
  • Botón B: drop instantáneo: la pieza cae hasta el fondo.
  • Botón Start: inicia partida y también pausa.

Lista de materiales

# Componente Qty Para qué sirve
1 Placa RP2040 Feather PropMaker (o RP2040 compatible) 1 Microcontrolador principal corriendo CircuitPython
2 Tira de 117 LEDs direccionables WS2812 / NeoPixel 1 Grilla 9×13 de píxeles
3 Gamepad I2C (joystick + botones) 1 Control de las piezas
4 Switch deslizable SPDT 1 Encendido y apagado del sistema
5 Cable JST de 4 pines (I2C) 1 Conexión gamepad con la placa
6 Lámina de acrílico negro 30×30 cm 1 Difusor frontal sobre los LEDs
7 Batería LiPo 3.7 V (≥1000 mAh) 1 Alimentación portátil
8 Cable ribbon 4 hilos (~50 cm) 1 Cableado interno entre placas
9 Filamento PLA para imprimir el edificio ~300 g Estructura del edificio y grilla

Diseño del circuito

Feather RP2040 PropMaker conectada al edificio impreso en 3D

La placa RP2040 se conecta de tres formas:

  1. NeoPixels → un pin de datos digital (cualquier GPIO libre, en CircuitPython funciona bien por DMA).
  2. Gamepad → bus I2C (SDA + SCL) por el conector JST 4 pines.
  3. Batería LiPo → entrada dedicada de la placa (la mayoría de las Feather RP2040 incluyen circuito de carga).

El switch deslizable corta la línea positiva entre la batería y la placa.

Imprimir el edificio

El proyecto incluye archivos .stl con:

  • La carcasa exterior del edificio (estructura).
  • Una grilla interna que sirve de matriz: 9 columnas × 13 filas. Cada celda aloja un LED tipo pebble. La grilla es lo que da el efecto "píxel" cuadrado; sin esto la luz se vería como una mancha continua.
  • Una tapa trasera para la batería y la electrónica.

Filamento sugerido: PLA negro mate. El acrílico negro al frente difumina las fuentes puntuales: la combinación de negro mate más acrílico negro semitransparente hace que cuando los LEDs están apagados la pantalla parezca un edificio "normal", y cuando encienden, los píxeles se ven nítidos.

Tiempo estimado de impresión: 8 a 12 horas dependiendo de tu impresora y configuración. Recomendación: imprimir a 0.2 mm de altura de capa, 15% de relleno, sin soportes para la grilla.

Cableado paso a paso

  1. Inserta la tira de NeoPixels en la grilla impresa, empezando por la esquina inferior izquierda. Verifica el orden serpenteado (de izquierda a derecha en la fila 1, de derecha a izquierda en la fila 2, y así sucesivamente): esto importa porque el código mapea índices lineales a coordenadas (x, y).
  2. Suelda los tres cables (5V, GND, DATA) del primer LED a tres pads del RP2040 Feather: VBAT, GND y un GPIO libre (por ejemplo D5).
  3. Conecta el gamepad al puerto JST del Feather (en placas con STEMMA QT es plug and play; si tu gamepad usa otro tipo de conector, usa un cable adaptador a Dupont).
  4. Cablea el switch en serie con el cable positivo de la batería: corta el cable rojo y suelda ambos extremos a los pines exteriores del SPDT.
  5. Carga el firmware y prueba antes de cerrar la caja: si algún LED parpadea con color erróneo, casi siempre es un cable de datos invertido o un GND flotante.

Código (CircuitPython)

Carga el firmware de CircuitPython más reciente compatible con RP2040 en tu placa. Copia las librerías a la carpeta /lib:

  • adafruit_seesaw
  • neopixel
  • adafruit_ticks (para timing del game loop)

Estructura del code.py:

Python
import board
import neopixel
import time
from adafruit_seesaw.seesaw import Seesaw
from adafruit_seesaw.digitalio import DigitalIO
from adafruit_seesaw.analoginput import AnalogInput

NUM_PIXELS = 117          # 9 columnas x 13 filas
COLS, ROWS = 9, 13
PIN = board.D5

pixels = neopixel.NeoPixel(PIN, NUM_PIXELS, brightness=0.3, auto_write=False)

i2c = board.I2C()
gamepad = Seesaw(i2c, addr=0x50)
js_x = AnalogInput(gamepad, 14)
js_y = AnalogInput(gamepad, 15)
btn_a = DigitalIO(gamepad, 5)
btn_b = DigitalIO(gamepad, 1)
btn_start = DigitalIO(gamepad, 0)

# Mapeo serpenteado: (x, y) -> indice lineal en la tira
def xy_to_index(x, y):
    if y % 2 == 0:
        return y * COLS + x
    else:
        return y * COLS + (COLS - 1 - x)

# Las 7 piezas tetromino (S, Z, L, J, T, O, I), cada una con sus rotaciones
TETROMINOES = {
    "I": [[(0,0),(1,0),(2,0),(3,0)], [(0,0),(0,1),(0,2),(0,3)]],
    "O": [[(0,0),(1,0),(0,1),(1,1)]],
    "T": [[(0,0),(1,0),(2,0),(1,1)],
          [(1,0),(0,1),(1,1),(1,2)],
          [(1,0),(0,1),(1,1),(2,1)],
          [(0,0),(0,1),(1,1),(0,2)]],
    # ... S, Z, L, J
}

def draw_piece(piece, x, y, color):
    for (dx, dy) in piece:
        gx, gy = x + dx, y + dy
        if 0 <= gx < COLS and 0 <= gy < ROWS:
            pixels[xy_to_index(gx, gy)] = color
    pixels.show()

def game_loop():
    grid = [[0] * COLS for _ in range(ROWS)]
    piece = TETROMINOES["T"][0]
    px, py = 4, 0
    last_fall = time.monotonic()
    while True:
        # Lectura del joystick
        if js_x.value < 200:  px = max(0, px - 1)
        if js_x.value > 800:  px = min(COLS - 1, px + 1)
        if not btn_a.value:   piece = rotate(piece)
        if not btn_b.value:   py = drop_to_bottom(grid, piece, px, py)

        # Caída con tick
        if time.monotonic() - last_fall > 0.5:
            py += 1
            last_fall = time.monotonic()

        pixels.fill(0)
        draw_grid(grid)
        draw_piece(piece, px, py, (255, 80, 0))

game_loop()

Esto es un esqueleto. La lógica completa (rotaciones de las 7 piezas, detección de líneas, scoring, niveles de velocidad) está en el repo del proyecto en Adafruit Learn: son ~300 líneas de Python comentado.

Calibración del brillo

Los NeoPixels consumen mucho cuando están al máximo. Con 117 píxeles en blanco puro al 100% puedes pedirle a la batería más de 3 A, lo que un LiPo de 1200 mAh no entrega de forma segura sostenida.

Recomendado: brightness=0.2 o 0.3. Combinado con el acrílico difusor, los colores se ven saturados y el consumo medio se mantiene bajo 500 mA, con lo que la batería rinde 2 a 3 horas de juego continuo.

Variantes y mejoras

  • Modo competitivo de a dos: agrega un segundo gamepad I2C en otra dirección del bus para que dos jugadores compitan en pantallas espejadas.
  • Tabla de récords: guarda el high score en la flash interna usando microcontroller.nvm, así el puntaje sobrevive a un apagado.
  • Música: la Feather RP2040 PropMaker ya trae amplificador de audio I2S integrado, así que solo necesitas conectar un parlante pequeño para reproducir la melodía clásica de Tetris.
  • Sensor de inclinación: un MPU6050 puede gatillar el drop cuando "agitas" el edificio, sumando un control gestual.

Personalización para Chile

En Chile puedes conseguir los componentes equivalentes en MechatronicStore. La Feather RP2040 PropMaker de Adafruit es difícil de encontrar localmente, pero cualquier placa RP2040 con CircuitPython cumple la misma función para el juego (pierdes solo el amplificador de audio integrado, que es opcional):

  • Seeed XIAO RP2040 (SKU GS1-5): $7.790 CLP, RP2040 compatible con CircuitPython.
  • Matriz LED RGB WS2812 (SKU GN3-12): $17.800 CLP, LEDs direccionables del mismo tipo que los NeoPixel.
  • Módulo joystick analógico (SKU G-201): $1.790 CLP, para el control de las piezas.
  • Mini switch SPDT 3 pines (SKU GF1-14): $290 CLP, encendido y apagado.
  • Batería LiPo 3.7 V (SKU XM5-2): para alimentación portátil.
  • Cables Dupont macho a macho (SKU C-417): $2.990 CLP, para el cableado interno.
  • Filamento PLA negro SUNLU 1 kg (SKU SL-008): $13.390 CLP, para imprimir el edificio y la grilla.

Recursos

  • Tutorial original (inglés): MIT Green Building NeoPixel Tetris
  • Plataforma: Adafruit Learning System (código CircuitPython y archivos .stl disponibles en la guía original).

Versión chilena con componentes en stock local en MechatronicStore.