Controla la Nave UNIT vía Bluetooth con tu DualMCU ONE

Controla la Nave UNIT vía Bluetooth con tu DualMCU ONE

En este tutorial aprenderás a transformar tu teléfono inteligente en un control remoto inalámbrico para interactuar con un videojuego retro en tiempo real. La finalidad de esta práctica es lograr que puedas enviar comandos desde la pantalla de tu celular para dirigir una nave espacial en movimiento y esquivar obstáculos que aparecen en una pantalla externa. Al finalizar, habrás conseguido crear un sistema de juego portátil y dinámico, ideal para entender el funcionamiento de los controles inalámbricos en tus proyectos de electrónica y personalización de videojuegos.

Introducción

¿Quién no recuerda la emoción de pasar horas frente a una maquinita intentando esquivar meteoritos y naves espaciales en una pantalla? Hoy en día, los videojuegos portátiles han evolucionado de formas increíbles, pero el espíritu maker nos impulso a ir un paso más allá: construir, personalizar y controlar nuestro propio juego desde cero.

En este tutorial te mostraremos cómo llevar la interactividad a otro nivel utilizando la potencia de la tarjeta DualMCU ONE (ESP32 + RP2040). No solo reviviremos un clásico juego con la Nave UNIT mostrando toda la acción en tiempo real en una pantalla LCD con I2C, sino que eliminaremos por completo los cables de los botones tradicionales.

A través de la tecnología Bluetooth, convertiremos tu smartphone en un control inalámbrico avanzado. Desde tu pantalla táctil podrás enviar comandos para esquivar obstáculos, acelerar por el espacio y dominar el juego de forma fluida. Además, si quieres que tu nave tenga un estilo único, te daremos acceso a nuestro laboratorio de píxeles en vivo para que diseñes tus propios personajes en segundos. ¡Prepara tu tarjeta de desarrollo, enciende el Bluetooth de tu celular y despeguemos en esta aventura tecnológica!

Materiales

Para llevar a cabo esta práctica inalámbrica y dar vida al juego de la Nave UNIT, necesitaremos los siguientes componentes de hardware:

  • Tarjeta de desarrollo DualMCU ONE (ESP32 + RP2040): El cerebro de nuestra consola portátil, encargada de procesar el juego y recibir los datos inalámbricos.
  • Pantalla LCD 20×4 : El periférico donde visualizaremos el espacio, nuestra nave y los obstáculos generados en tiempo real.
  • Smartphone (Android): Actuará como nuestro control inalámbrico para el videojuego mediante una aplicación de terminal de comunicación serial.
  • Cables de conexión Qwiic (o si prefieres, cables DuPont): Esenciales para realizar el conexionado rápido y seguro de la pantalla hacia los pines de la placa de desarrollo.

Diagrama de conexión

Para las conexiones nos basaremos en el pinout de la tarjeta. Te mostramos cómo resolverlo en distintos casos y te explicamos ambas opciones; sin embargo, en UNIT Electronics usamos la entrada Qwiic siempre que es posible. NOTA: También es importante que verifiques el nombre de cada uno de los puertos.

En este caso, como lo indica la placa de izquierda a derecha, el primero será el pin SCL y después el SDA, los cuales se conectarán con sus respectivos pines de la conexión I2C en la LCD. El tercero lo dejaremos libre, ya que al ser una salida de 3.3V no le dará el brillo esperado a la pantalla; en su lugar, usaremos un cable DuPont directo al puerto de 5V de la DualMCU ONE, y por último conectaremos la GND.

Si optas por usar cables DuPont, la conexión se realizará prácticamente de la misma manera: deberás ubicar los puertos SDA y SCL en la DualMCU ONE y conectarlos con sus equivalentes en la LCD; las otras dos líneas serán para los 5V y GND, que van con sus respectivas alimentaciones.

Usando la conexión Qwiic.

Con cables DuPont.

Requerimientos Previos

Necesitarás descargar la aplicación Arduino Bluetooth Controller en tu smartphone.

Una vez que tengas la app instalada, y antes de comenzar a cargar el código de nuestro videojuego, es necesario preparar el entorno de desarrollo en el IDE de Arduino. Para que el sistema reconozca la DualMCU ONE, debemos instalar el Driver CH340 (haz clic para descargar e instalar el controlador) y dar de alta los paquetes correspondientes.

Sigue estos pasos para configurarlo todo de una sola vez:

  1. En el IDE de Arduino, dirígete a Archivo > Preferencias.
  2. Busca la casilla llamada Gestor de URLs Adicionales de Tarjetas.
  3. Copia y pega las siguientes cuatro URLs en esa casilla (separadas por una coma):
https://github.com/UNIT-Electronics/DualMCU-ONE/releases/download/V2.0.0/package_Uelectronics_rp2040_index.json, https://github.com/UNIT-Electronics/Uelectronics-ESP32-Arduino-Package/releases/download/v1.0.0/package_Uelectronics_ESP32_index.json, https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json, https://espressif.github.io/arduino-esp32/package_esp32_index.json

4. Haz clic en Aceptar.

Configuración y Alta de Tarjetas

Una vez añadidas las URLs, dirígete al menú superior y abre el Gestor de Tarjetas en:

Herramientas > Placa > Gestor de tarjetas...

En la barra de búsqueda de la izquierda, realiza las siguientes búsquedas e instala las opciones indicadas:

1. Para los chips RP2040

  • ¿Qué buscar?
    Escribe rp2040 en el buscador.
  • ¿Qué descargar?
    Selecciona e instala la tarjeta Raspberry Pi Pico/RP2040 desarrollada por Earle Philhower. Este paquete descarga el compilador base para que el IDE pueda procesar el chip de la consola.

2. Para la ESP32

  • ¿Qué buscar?
    Escribe esp32 en el buscador.
  • ¿Qué descargar?
    Selecciona e instala el paquete ESP32 desarrollado por Espressif Systems. Esta descarga incluye los controladores y librerías inalámbricas oficiales de fábrica.

3. Para las tarjetas y herramientas de UNIT Electronics

  • ¿Qué buscar?
    Escribe UNIT en el buscador.
  • ¿Qué descargar?
    Aquí nos aparecerán las dos tarjetas oficiales de UNIT Electronics RP2040 y UNIT Electronics ESP32 que dimos de alta con los primeros enlaces; debemos proceder a instalar ambas.

Por último, no olvides instalar las librerías para la pantalla desde el Gestor de librerías:

  • LiquidCrystal_I2C: Ya que utilizaremos el adaptador de pines para la comunicación I2C.

Preparación del Entorno IDE

Primero deberás identificar en qué puertos COM está asignada tu tarjeta, para lo cual debes tenerla conectada a la PC.

Windows + X > Administrador de dispositivos > Puertos (COM y LPT)...

En este caso, se identifican como el puerto COM8 para la Raspberry Pi Pico y el puerto COM6 para el ESP32 (este último lo reconocerás fácilmente por utilizar el chip USB-SERIAL CH340). Ahora ya podemos crear cada uno de los sketches en el Arduino IDE, comenzando por el de la Raspberry Pi Pico.

Archivo > Nuevo sketch...

Al seleccionar la placa y el puerto, recuerda elegir la configuración correcta para cada una o se generará un error al intentar subir el programa.

Herramientas > Placa > UNIT Electronics RP2040 > Raspberry Pi Pico...

Configuración para la ESP32

El procedimiento será el mismo: crearemos un Nuevo sketch y cambiaremos las rutas de selección. Te dejamos el ejemplo visual para evitar errores:

Herramientas > Placa > UNIT Electronics ESP32 > UNIT Dual MCU ESP32...

Código del Proyecto

Programa para Raspberry Pi Pico (Núcleo del Juego)

Copia este código y pégalo directamente en tu sketch de la Raspberry Pi Pico y haz clic en la flecha de cargar. El proceso será automático; no tienes que presionar ningún botón físico en la placa, ya que el Arduino IDE se encargará de gestionar todo.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Configuración de la pantalla LCD 20x4 mediante I2C
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Sprites personalizados creados en el Laboratorio de Píxeles
byte naveUNIT[8] = {   
  B01000,
  B11110,
  B00111,
  B11001,
  B11001,
  B00111,
  B11110,
  B01000 
         };
byte asteroide[8] = { 
  B00000,
  B10101,
  B01110,
  B11111,
  B11111,
  B01110,
  B10101,
  B00000
 };

// Variables globales del videojuego
int distancia = 0;
unsigned long tiempoAnterior = 0;
int asteroideX = 19;
int asteroideY = 3;  // Fila inicial del obstáculo
int naveY = 3;       // Fila inicial de la nave (Fila 2 o Fila 3)

// Configuración dinámica de velocidad
const int VELOCIDAD_INICIAL = 180; 
int velocidadActual = VELOCIDAD_INICIAL;

void reiniciarPartida() {
  distancia = 0;
  asteroideX = 19;
  asteroideY = 3;
  naveY = 3;
  velocidadActual = VELOCIDAD_INICIAL; 
  tiempoAnterior = millis(); 
  
  lcd.clear();
  lcd.setCursor(4, 0);
  lcd.print("NAVE UNIT");
}

void setup() {
  // Inicializa la comunicación serie interna con el módulo ESP32 para el Bluetooth
  Serial1.begin(115200);

 
  // OPCIÓN A: Conexión mediante Puerto Qwiic
  Wire.setSDA(4); 
  Wire.setSCL(5);
  
  // OPCIÓN B: Conexión mediante Pines Estándar (Descomenta estas dos líneas si no usas Qwiic y comenta las anteriores)
  // Wire.setSDA(20); 
  // Wire.setSCL(21);
  Wire.begin(); 
  
  // Inicialización de la pantalla LCD con luz de fondo
  lcd.init();
  lcd.backlight();
  
  // Guardamos los caracteres en la memoria CGRAM (Nave = 0, Asteroide = 1)
  lcd.createChar(0, naveUNIT);
  lcd.createChar(1, asteroide);
  
  reiniciarPartida(); 
}

void loop() {
  bool registrarSalto = false;

  // --- 1. LECTURA EXCLUSIVA DEL BLUETOOTH (Vía ESP32) ---
  if (Serial1.available()) {
    char datoInalambrico = Serial1.read();
    // Si recibimos el comando 'C' desde el smartphone, activamos el salto
    if (datoInalambrico == 'C') {
      registrarSalto = true;
    }
  }

  // --- EJECUCIÓN DEL MOVIMIENTO / SALTO ---
  if (registrarSalto) {
    lcd.setCursor(2, naveY);
    lcd.print(" "); // Borramos la posición vieja de la nave
    naveY = (naveY == 3) ? 2 : 3; // Alternamos de forma instantánea entre la fila 2 y 3
  }

  // --- 2. MOTOR PRINCIPAL DEL JUEGO ---
  if (millis() - tiempoAnterior > velocidadActual) {
    tiempoAnterior = millis();
    distancia++;

    // Incremento progresivo de la dificultad según la distancia recorrida
    int reduccion = (distancia / 200) * 20; 
    velocidadActual = constrain(VELOCIDAD_INICIAL - reduccion, 40, VELOCIDAD_INICIAL);

    // Renderizado del marcador de puntuación (Formato 000m)
    lcd.setCursor(0, 1);
    lcd.print("Distancia: ");
    if(distancia < 100) lcd.print("0");
    if(distancia < 10)  lcd.print("0");
    lcd.print(distancia);
    lcd.print("m");
    
    // Limpieza de la estela del asteroide
    lcd.setCursor(asteroideX, asteroideY);
    lcd.print(" ");
    asteroideX--;
    
    // Si el obstáculo llega al límite izquierdo, se reposiciona al azar en el extremo derecho
    if (asteroideX < 0) {
      asteroideX = 19;
      asteroideY = random(2, 4); // Elige al azar la fila 2 o la fila 3
    }
    
    // Dibujamos el asteroide en su nueva coordenada
    lcd.setCursor(asteroideX, asteroideY);
    lcd.write(1);
    
    // Dibujamos la Nave UNIT en su nueva coordenada
    lcd.setCursor(2, naveY);
    lcd.write(0);
    
    // --- 3. DETECCIÓN CRÍTICA DE COLISIÓN (GAME OVER) ---
    if (asteroideX == 2 && asteroideY == naveY) {
      lcd.clear();
      lcd.setCursor(2, 1);
      lcd.print("CORTO CIRCUITO");
      lcd.setCursor(3, 2);
      lcd.print("Record: ");
      lcd.print(distancia);
      lcd.print("m");
      lcd.setCursor(1, 3);
      lcd.print("Reiniciando 10s...");
      
      delay(10000); // Espera de cortesía antes de volver a empezar
      reiniciarPartida(); 
    }
  }
}

Programa del Módulo ESP32 (Enlace Bluetooth)

Ahora, para el código del control Bluetooth el proceso es idéntico al anterior: pégalo en el sketch configurado para la placa UNIT DualMCU ESP32 y súbelo al hardware.

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void setup() {
  // Comunicación serie interna hacia la DualMCU Raspberry Pi Pico
  Serial2.begin(115200, SERIAL_8N1, 16, 17); 
  SerialBT.begin("NaveUNIT_Control"); 
}

void loop() {
  if (SerialBT.available()) {
    char comando = SerialBT.read();
    
    // Filtramos los comandos comunes que envía el modo Gamepad de la app:
    // 'C' = Tu botón personalizado
    // 'U' = Flecha Arriba (Up)
    // 'D' = Flecha Abajo (Down)
    // '1','2','3','4','X','A' = Botones de acción comunes en la app
    if (comando == 'C' || comando == 'c' || 
        comando == 'U' || comando == 'u' || 
        comando == 'D' || comando == 'd' || 
        comando == '1' || comando == '2' || 
        comando == 'X' || comando == 'x' || comando == 'A') {
          
      Serial2.print('C'); // Le manda la señal unificada de 'Salto' al Raspberry Pi Pico
    }
  }
  delay(10);
}

Con los programas cargados, es momento de configurar el control. Abre la aplicación en tu teléfono móvil para establecer el enlace con la DualMCU ONE.

Dentro de la lista de dispositivos disponibles, selecciona NaveUNIT_Control para establecer la conexión inalámbrica de forma exitosa.

Posteriormente, abriremos la opción de GamePad. Te dejamos mapeadas más configuraciones en el código por si deseas expandir el mando en tus proyectos futuros; sin embargo, para esta práctica en específico, la letra “C” actuará como nuestro botón “X” principal en la interfaz visual.

Así lucirá la interfaz del control digital en tu pantalla, y presionando el botón asignado podrás cambiar de dirección la nave instantáneamente.

En el código encontrarás más botones configurados, por si en algún momento deseas reciclar el fragmento para otros proyectos.

Te retamos a superar el récord (aunque a esa velocidad, ¡puede que sea imposible!).

Diseña tus Sprites en el Laboratorio de Píxeles

Una de las características más atractivas del ecosistema DualMCU ONE y las pantallas LCD es la capacidad de modificar la memoria gráfica interna (CGRAM) para proyectar ilustraciones propias de 5×8 píxeles. Esto nos abre las puertas para convertir un juego en una experiencia completamente personalizada.

Para facilitarte el proceso de creación binaria sin necesidad de calcular manualmente los unos y ceros de cada fila, hemos integrado nuestro Laboratorio de Píxeles interactivo.

Instrucciones de uso:

  1. Haz clic sobre los cuadros de la cuadrícula verde de abajo para activar o desactivar los píxeles (puedes rediseñar la Nave UNIT o dar vida a un nuevo asteroide).
  2. Conforme vayas pintando, el recuadro gris de la derecha generará automáticamente el bloque de código correspondiente en tiempo real.
  3. Asegúrate de tener seleccionada la opción Arduino y el modo I2C.
  4. Copia las líneas de bytes generadas (las que comienzan con B00...) e intégralas en las variables correspondientes del código principal.

🕹️ Laboratorio de Píxeles: Nave UNIT & LCD Customizer

Diseña tus propios personajes u obstáculos en tiempo real. Modifica la cuadrícula de abajo, genera tus bits y cópialos directamente.

💡 Tip: Al usar el módulo adaptador de tu pantalla, debes cambiar la opción “Interfacing” de Parallel a I2C.

Compatible con modos Paralelo e I2C de forma dinámica

Herramienta original por maxpromer

Conclusiones

Llevar a cabo este proyecto nos permite entender el verdadero potencial de la DualMCU ONE cuando se combina con tecnologías inalámbricas y periféricos de visualización. Al finalizar esta práctica, hemos alcanzado varios aprendizajes clave:

  • Control Inalámbrico Eficiente: Aprendimos cómo el microcontrolador RP2040 puede interactuar de forma nativa y transparente con el módulo ESP32 mediante comandos seriales (Serial1), permitiéndonos delegar la carga de la conectividad Bluetooth sin consumir recursos de procesamiento del bucle principal del videojuego.
  • Dominio de la memoria CGRAM: Al integrar el Laboratorio de Píxeles, descubrimos cómo las pantallas LCD no están limitadas a mostrar texto plano o caracteres alfanuméricos de fábrica. La capacidad de reescribir sus bancos de memoria internos nos permite diseñar gráficos personalizados (Sprites) para crear videojuegos dinámicos y adaptados a nuestras necesidades.
  • Flexibilidad en el Desarrollo de Hardware: Comprobamos la versatilidad de la placa de UNIT Electronics al permitirnos elegir libremente entre usar el ecosistema plug-and-play de los conectores físicos RP-JST (Qwiic) con los pines 4 y 5, o bien realizar puentes directos mediante los pines estándar 20 y 21, ofreciendo soluciones dinámicas para cualquier tipo de prototipo.

Con este control por Bluetooth y tus propios diseños de píxeles corriendo en la pantalla, has transformado una simple tarjeta de desarrollo en una auténtica consola de videojuego portátil con control inalámbrico. ¡Es hora de compartir tu récord de distancia en el espacio y seguir explorando el universo maker con UNIT Electronics!

Glosario

Para comprender mejor los conceptos técnicos utilizados a lo largo de este tutorial, te presentamos una breve definición de los términos clave:

  • CGRAM (Character Generator RAM): Memoria volátil del controlador de la pantalla LCD que permite al programador definir y almacenar hasta 8 caracteres o gráficos personalizados (sprites) de 5×8 píxeles.
  • DualMCU ONE: Tarjeta de desarrollo híbrida diseñada por UNIT Electronics que integra dos potentes microcontroladores en una misma placa: el RP2040 (arquitectura ARM) y el ESP32 (conectividad inalámbrica).
  • I2C (Inter-Integrated Circuit): Protocolo de comunicación serial síncrona que utiliza únicamente dos líneas de datos (SDA y SCL) para conectar múltiples periféricos, como pantallas o sensores, optimizando el uso de pines en el microcontrolador.
  • Pinout: Esquema o mapa gráfico que detalla la distribución, funciones y etiquetas físicas de cada uno de los pines de un circuito integrado o tarjeta de desarrollo.
  • Qwiic / RP-JST: Sistema de conexión rápida basado en conectores JST de 4 pines con un paso de 1 mm, diseñado para enlazar dispositivos I2C de forma segura y libre de soldaduras (Plug and Play).
  • Sprite: Gráfico o mapa de bits bidimensional que representa a un personaje, objeto u obstáculo móvil dentro de la lógica visual de un videojuego.

Bibliografía

Si deseas profundizar en la documentación técnica oficial y en las herramientas utilizadas para el desarrollo de esta práctica, puedes consultar las siguientes fuentes:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *