Detector de distracción python/Arduino

Introducción

Este proyecto te permite controlar tu ordenador portátil usando gestos con la mano. Utilizaremos un sensor de gestos conectado a una placa Arduino (con capacidad HID nativa) para traducir tus movimientos en acciones como mover el cursor del ratón, hacer clics o incluso ejecutar atajos de teclado. Es una forma innovadora de interactuar con tu PC y aprender sobre sensores de gestos y la emulación de dispositivos de entrada (HID).

Materiales Necesarios

  • Placa Arduino con capacidad HID nativa (como Arduino Leonardo, Micro, Pro Micro, o placas basadas en ESP32-S2/S3)

  • Sensor de Gestos (por ejemplo, el PAJ7620U2, que reconoce varios gestos como arriba, abajo, izquierda, derecha, cerca, lejos, etc.)

  • Protoboard

  • Cables Jumper (generalmente macho-hembra para conectar el sensor a la placa)

  • Cable USB (adecuado para tu placa Arduino)

Esquema de Montaje

El montaje se centra en conectar el sensor de gestos a la placa Arduino mediante la interfaz I2C (generalmente).

Conexiones:

  • Sensor de Gestos (ej. PAJ7620U2):

    • VCC → Pin 3.3V o 5V del Arduino (consulta la hoja de datos de tu sensor).

    • GND → Pin GND del Arduino.

    • SDA (Serial Data) → Pin SDA del Arduino (Pin 2 en Leonardo/Micro).

    • SCL (Serial Clock) → Pin SCL del Arduino (Pin 3 en Leonardo/Micro).

    • INT (Interrupt – Opcional) → Un pin digital del Arduino (si se usa para detectar gestos de forma más eficiente).

  •  

Código de Arduino

#include <Wire.h> // Necesario para la comunicación I2C
// Incluye aquí la biblioteca específica para tu sensor de gestos
// Por ejemplo, para el PAJ7620U2: #include "paj7620.h"
#include <Mouse.h>    // Necesario para emular el ratón (solo en placas HID compatibles)
#include <Keyboard.h> // Necesario para emular el teclado (solo en placas HID compatibles)

// --- Constantes y Variables ---
// Define aquí las constantes para la sensibilidad del movimiento, etc.
int mouseSensitivity = 5; // Ejemplo: cuántos píxeles mover por gesto

// --- Configuración (Setup) ---
void setup() {
  Serial.begin(9600); // Para depuración (opcional)
  Wire.begin();       // Inicia la comunicación I2C

  // Inicializa el sensor de gestos según su biblioteca
  // Ejemplo: if (paj7620Init()!= 0) { Serial.println("Error al iniciar PAJ7620"); while(1); }
  Serial.println("Sensor de gestos inicializado.");

  // Inicializa la emulación de Ratón y Teclado
  Mouse.begin();
  Keyboard.begin();
  Serial.println("Control HID iniciado. Mueve la mano sobre el sensor.");
}

// --- Bucle Principal (Loop) ---
void loop() {
  // Variable para almacenar el gesto detectado
  uint8_t gestureDetected; // O el tipo de dato que devuelva tu biblioteca

  // Lee el gesto del sensor usando su biblioteca
  // Ejemplo: gestureDetected = paj7620ReadGesture();

  // Procesa el gesto detectado
  switch (gestureDetected) {
    case GESTURE_UP: // (Usa las constantes definidas por tu biblioteca)
      Serial.println("Gesto: Arriba");
      Mouse.move(0, -mouseSensitivity, 0); // Mueve el cursor hacia arriba
      break;
    case GESTURE_DOWN:
      Serial.println("Gesto: Abajo");
      Mouse.move(0, mouseSensitivity, 0); // Mueve el cursor hacia abajo
      break;
    case GESTURE_LEFT:
      Serial.println("Gesto: Izquierda");
      Mouse.move(-mouseSensitivity, 0, 0); // Mueve el cursor a la izquierda
      break;
    case GESTURE_RIGHT:
      Serial.println("Gesto: Derecha");
      Mouse.move(mouseSensitivity, 0, 0); // Mueve el cursor a la derecha
      break;
    case GESTURE_FORWARD: // Gesto de acercar la mano
      Serial.println("Gesto: Adelante (Clic Izquierdo)");
      Mouse.click(MOUSE_LEFT);
      delay(100); // Pequeña pausa para evitar clics múltiples
      break;
    case GESTURE_BACKWARD: // Gesto de alejar la mano
       Serial.println("Gesto: Atrás (Clic Derecho)");
       Mouse.click(MOUSE_RIGHT);
       delay(100);
       break;
    // Añade más casos para otros gestos que tu sensor soporte
    // Por ejemplo, GESTURE_CLOCKWISE, GESTURE_WAVE, etc.
    // Podrías mapearlos a scroll, atajos de teclado (Keyboard.press()), etc.

    // case GESTURE_CLOCKWISE:
    //   Serial.println("Gesto: Giro horario (Scroll Abajo)");
    //   Mouse.move(0, 0, -1); // Scroll hacia abajo
    //   delay(50);
    //   break;
    // case GESTURE_ANTICLOCKWISE:
    //   Serial.println("Gesto: Giro antihorario (Scroll Arriba)");
    //   Mouse.move(0, 0, 1); // Scroll hacia arriba
    //   delay(50);
    //   break;

    default:
      // No se detectó un gesto conocido o no hay gesto
      break;
  }

  // Pequeña pausa para no saturar lecturas/acciones
  delay(50);
}

Código de Python

  1. Necesitas tener Python instalado en tu ordenador.

  2. Necesitas instalar la biblioteca pyserial. Puedes hacerlo abriendo una terminal o símbolo del sistema y ejecutando: pip install pyserial

import serial
import time

# --- Configuración ---
# ¡IMPORTANTE! Reemplaza 'COM4' con el puerto serie correcto de tu Arduino Leonardo/Micro.
# En Linux/Mac puede ser algo como '/dev/ttyACM0' o '/dev/tty.usbmodemXXXX'
# Puedes encontrar el puerto en el IDE de Arduino (Herramientas -> Puerto).
SERIAL_PORT = 'COM4' # Ajusta esto a tu puerto
BAUD_RATE = 9600     # Debe coincidir con Serial.begin(9600) en Arduino
# --- Fin Configuración ---

print(f"Intentando conectar al puerto {SERIAL_PORT} a {BAUD_RATE} baudios...")

try:
    # Inicializa la conexión serie
    # timeout=1 significa que esperará hasta 1 segundo por datos
    arduino = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
    # Espera un momento para que se establezca la conexión física y lógica
    time.sleep(2)
    print("Conexión establecida. Esperando datos del sensor de gestos...")

    while True:
        try:
            # Lee una línea de datos enviada por el Arduino
            # readline() lee hasta encontrar un salto de línea ('\n')
            if arduino.in_waiting > 0: # Comprueba si hay datos disponibles
                line = arduino.readline().decode('utf-8').strip()

                # Si la línea no está vacía, la imprimimos
                if line:
                    print(f"Arduino dice: {line}")
                    # Aquí podrías añadir lógica adicional si quisieras que Python
                    # reaccionara a gestos específicos (ej. lanzar una app),
                    # aunque el control del cursor/teclado lo hace Arduino.

            # Pequeña pausa para no sobrecargar la CPU,
            # ajusta si necesitas más o menos reactividad
            time.sleep(0.02)

        except serial.SerialException as e:
            print(f"Error de lectura del puerto serie: {e}")
            print("Puede que el Arduino se haya desconectado.")
            break # Sale del bucle si hay un error de lectura grave
        except KeyboardInterrupt:
            print("\nDeteniendo el script por el usuario.")
            break # Permite detener el script con Ctrl+C
        except UnicodeDecodeError:
            # A veces pueden llegar datos corruptos, los ignoramos
            print("Error de decodificación, ignorando datos...")
            pass
        except Exception as e:
            print(f"Ocurrió un error inesperado: {e}")
            time.sleep(1) # Espera antes de reintentar

except serial.SerialException as e:
    print(f"ERROR: No se pudo conectar al puerto {SERIAL_PORT}.")
    print(f"Detalles: {e}")
    print("Verifica lo siguiente:")
    print("1. ¿Está el Arduino conectado al PC?")
    print(f"2. ¿Es '{SERIAL_PORT}' el puerto correcto? (Compruébalo en el IDE de Arduino)")
    print("3. ¿Hay otro programa usando el puerto? (Cierra el Monitor Serie del IDE)")
    print("4. En algunas placas, puede que necesites esperar unos segundos tras conectarla.")

finally:
    # Asegúrate de cerrar el puerto al salir del script (incluso si hay error)
    if 'arduino' in locals() and arduino.is_open:
        arduino.close()
        print("Puerto serie cerrado.")
    print("Script finalizado.")

Explicación del Código

 

  • Comunicación I2C (Wire.h):

    • Esta biblioteca estándar de Arduino se usa para comunicarse con el sensor de gestos, que típicamente utiliza el protocolo I2C. Wire.begin() inicia la comunicación.

  • Biblioteca del Sensor de Gestos (Ej: paj7620.h):

    • Necesitarás una biblioteca específica para tu modelo de sensor. Esta biblioteca simplifica la inicialización del sensor (paj7620Init()) y la lectura de los gestos (paj7620ReadGesture()), traduciendo las señales del sensor en constantes fáciles de usar (como GESTURE_UPGESTURE_LEFT, etc.).

  • Emulación HID (Mouse.h y Keyboard.h):

    • Estas bibliotecas solo funcionan en placas Arduino específicas (Leonardo, Micro, Pro Micro, Due, Zero, ESP32-S2/S3, etc.) que tienen capacidad USB nativa. Permiten que el Arduino se presente al ordenador como un ratón o un teclado estándar, sin necesidad de instalar drivers adicionales.

    • Mouse.begin() y Keyboard.begin() inicializan estas funcionalidades.

    • Mouse.move(x, y, rueda) mueve el cursor x píxeles horizontalmente, y píxeles verticalmente y mueve la rueda de scroll.

    • Mouse.click(BOTON) simula un clic del botón especificado (MOUSE_LEFTMOUSE_RIGHTMOUSE_MIDDLE).

    • Keyboard.press(TECLA) y Keyboard.release(TECLA) simulan presionar y soltar una tecla. Keyboard.write('c') escribe un carácter. Se pueden usar para atajos (ej. Keyboard.press(KEY_LEFT_CTRL); Keyboard.write('c'); Keyboard.releaseAll(); para Copiar).

  • Lógica del loop():

    • El código lee continuamente el sensor.

    • Si detecta un gesto definido, entra en la estructura switch.

    • Cada case corresponde a un gesto reconocido por la biblioteca del sensor.

    • Dentro de cada case, se ejecuta la acción HID correspondiente (mover el ratón, hacer clic, etc.).

    • Se usan pequeños delay() para evitar acciones múltiples no deseadas con un solo gesto y para dar tiempo al sensor y al PC a procesar.

Este proyecto es una excelente demostración de cómo combinar sensores con la capacidad HID de Arduino para crear interfaces de control personalizadas.