Saltar al contenido

Emular el Teclado y el Ratón con Arduino - GAMEPAD con Pro Micro

¡Bienvenido a la página web de Wexter Home! Hoy te voy enseñar cómo puedes emular el teclado y el ratón con Arduino. Para hacerlo lo más entretenido posible me gustaría enseñarte a utilizar las librerías Keyboard y Mouse de forma práctica. El objetivo, aparte de aprender a utilizar dichas librerías, es crear un mando de PlayStation para jugar al ordenador, es decir, un gamepad. 

Objetivos del proyecto - Emular el teclado y el ratón

Además de aprender a emular el teclado y el ratón con Arduino, esta es la primera parte de una serie en la que voy a crear un gamepad con el que poder jugar a cualquier juego. Sin embargo, hoy me voy a centrar en desarrollar un primer prototipo que me permita jugar a World of Tanks.

World of Tanks es un juego multijugador online masivo en el que cada jugador controla un vehículo blindado y tiene que intentar destruir al enemigo. Mi objetivo va a ser poder conducir el vehículo, apuntar y disparar. En el juego hay más controles pero para simplificar este primer prototipo solo voy a desarrollar éstos. 

Materiales necesarios para crear el gamepad con Arduino

Para mover el tanque con el teclado, como en la mayoría de juegos, se utilizan o las flechas o las letras W, A, S y D. Para simular dichas teclas necesito 4 botones. Los 4 botones van a ser los típicos pulsadores físicos. Gracias a que puedo utilizar las resistencias internas de cada pin digital de Arduino, me puedo ahorrar resistencias externas. Para ello tendré que configurar los pines digitales a los que conecte  estos botones como INPUT_PULLUP.

Para poder apuntar con el cañón, y con apuntar me refiero a girar la cámara, se utiliza el ratón. Yo en mi mando lo haré con un joystick

Por último necesito disparar a los enemigos. En World of Tanks esto se hace con el botón izquierdo del ratón. De momento esto lo puedo simular con el botón que tiene integrado el joystick.

El resto de materiales que necesito son cables, una placa protoboard, y lo más importante, el «cerebro del mando», un microcontrolador. Para este proyecto voy a utilizar un Arduino Pro Micro. 

Keyboard y Mouse con Arduino Pro Micro

La verdad es que al principio pensé en utilizar un Arduino Nano para el proyecto, sin embargo, cuando compilé la primera versión del programa no funcionaba. Después de investigar me di cuenta de que las librerías Keyboard y Mouse solo son compatibles con el microcontrolador Atmega32u4. 

Esto quiere decir que NO puedo utilizar las placas Arduino Uno, Mega y Nano para este proyecto, ya que no están basadas en este modelo de Atmega. Entre los Arduinos que tienen un microcontrolador Atmega32u4, el más pequeño es el Arduino Pro Micro, así que yo voy a utilizar este. 

Esquema eléctrico y conexión

Ahora voy a montar el primer prototipo según el esquema eléctrico que hay justo abajo. Como puedes ver es muy sencillo. Cada botón hay que conectarlo a un pin digital. Las dos salidas analógicas del joystick, VRx y VRy, a dos entradas analógicas y la salida del botón integrado del joystick, SW, a otro pin digital.

Joystick con Pro Micro

Código con las librerías Keyboard y Mouse

Ahora que ya tengo el circuito montado, falta programar el Arduino Pro Micro para que todo funcione. Voy a utilizar las librerías Keyboard y Mouse. Son librerías estándar de Arduino por lo que ya están incluidas en el IDE, pero como ya sabes, solo se pueden utilizar en las placas de Arduino que estén basadas en el microcontrolador Atmega32u4. 

El programa que he hecho tiene en total 5 funciones. En la función void setup inicializo los pines digitales a los que he conectado el pulsador del joystick y los 4 botones que representan la A, la W, la S y la D. Por decirlo de alguna manera también inicializo lo que serían las librerías Keyboard y MouseEn la función void loop simplemente llamo a tres funciones que he creado.

Emular el teclado con Arduino y la librería Keyboard

La primera función que he creado se llama wasdButtonsControl, y como su propio nombre indica, se encarga del control de dichos botones. Básicamente he asociado cada botón a una letra. Si por ejemplo pulso el botón que he conectado al pin digital 4, envío una W como si fuera el teclado. Si pulso el botón conectado al pin digital 5 envío una A, y así con los otros dos botones y letras que quedan. 

Emular el ratón con Arduino y la librería Mouse

La segunda función se llama mouseClicksControl. Se encarga de gestionar aquellos pulsadores que simulan los botones del ratón. En este primer prototipo solo estoy trabajando con el click izquierdo del ratón, que como ya te he dicho lo emulo con el pulsador del joystick. La función que he creado revisa si he pulsado el joystick y si es así envío un click izquierdo del ratón con la función Mouse.click(MOUSE_LEFT).

La tercera y última función la he llamado mouseMovementControl. Yo diría que es la parte más complicada del programa sin dudas. Lo primero que hago es leer las entradas analógicas a las que tengo conectado el joystick. Los dos valores que recibo están en un rango de 0 a 1024, pero de todas formas lo compruebo con un if

Después, con la función map, paso los dos valores recibidos a un rango de 0 a mouseVelocity, que en principio vale 20. Como el joystick en su posición central devuelve 512 y no 0, tengo que restarle a los dos valores convertidos previamente el valor de 512 convertido al mismo rango entre 0 y mouseVelocity

Por último compruebo si el movimiento del joystick es significativo, comparando los valores obtenidos con una constante que he creado y con la función Mouse.move muevo el ratón.

Te dejo el código aquí abajo. Si este tutorial te está sirviendo de ayuda, ¡suscríbete a mi canal de Youtube para seguir aprendiendo mucho más sobre Arduino!

#include <Keyboard.h>
#include <Mouse.h>

const int Wbutton = 7;
const int Abutton = 6;
const int Sbutton = 4;
const int Dbutton = 5;
const int joystickVRx = A0;
const int joystickVRy = A1;
const int joystickButton = 3;
const int mouseVelocity = 20;
const int joystickTolerance = mouseVelocity/6;
const int joystickCenter = mouseVelocity/2;
const int FPS = 60;

void wasdButtonsControl(int wbutton, int abutton, int sbutton, int dbutton);
void mouseMovementControl(int joystickvrx, int joystickvry, int mousevelocity, 
                          int joysticktolerance, int joystickCenter);
void mouseClicksControl(int leftClick);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(Wbutton, INPUT_PULLUP);
  pinMode(Abutton, INPUT_PULLUP);
  pinMode(Sbutton, INPUT_PULLUP);
  pinMode(Dbutton, INPUT_PULLUP);
  pinMode(joystickButton, INPUT_PULLUP);

  Keyboard.begin();
  Mouse.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  wasdButtonsControl(Wbutton, Abutton, Sbutton, Dbutton);
  mouseMovementControl(joystickVRx, joystickVRy, mouseVelocity, joystickTolerance, joystickCenter);
  mouseClicksControl(joystickButton);
  delay(1000/FPS);
}

void wasdButtonsControl(int wbutton, int abutton, int sbutton, int dbutton){
  if(!digitalRead(wbutton)){
    Keyboard.press('w');
  } 
  
  else{
    Keyboard.release('w');
  }
  
  if(!digitalRead(abutton)){
    Keyboard.press('a');
  }
  else{
    Keyboard.release('a');
  }
  
  if(!digitalRead(sbutton)){
    Keyboard.press('s');
  }
  else{
    Keyboard.release('s');
  }

  if(!digitalRead(dbutton)){
    Keyboard.press('d');
  }
  else{
    Keyboard.release('d');
  }
}

void mouseMovementControl(int joystickvrx, int joystickvry, int mousevelocity, 
                          int joysticktolerance, int joystickcenter){
  int VRxlecture = analogRead(joystickvrx);
  int VRylecture = analogRead(joystickvry);

  //Comprueba si hay algún error en la lectura
  if(VRxlecture>=0 && VRxlecture<=1024 && VRylecture>=0 && VRylecture<=1024){
    int xMove = map(VRxlecture, 0, 1024, 0, mousevelocity);
    int yMove = map(VRylecture, 0, 1024, 0, mousevelocity);

    xMove = xMove - joystickcenter;
    yMove = yMove - joystickcenter;

    if(abs(xMove) < joysticktolerance){
      xMove = 0;
    }

    if(abs(yMove) < joysticktolerance){
      yMove = 0;
    }
    
    //El tercer argumento es el scroll
    Mouse.move(xMove, yMove, 0);
  }
}


void mouseClicksControl(int leftClick){
  if(!digitalRead(leftClick)){
    Mouse.click(MOUSE_LEFT);
  }
}

 

Resultados de emular el teclado y el ratón con Arduino

Nada mas terminar de programar, he ido a World of Tanks a probar si funcionaba y ha sido un auténtico desastre. Los botones no iban y el joystick  iba pero muy mal. La buena noticia es que solucionarlo ha sido bastante fácil, simplemente eran dos errores de código.

Por cierto, el código anterior ya está corregido y debería funcionar sin problemas. Volviendo a los errores, el primer error es que para simular los botones estaba utilizando la función Keyboard.write. He probado con otra función que se llama Keyboard.press y ya se ha solucionado.

Respecto al joystick, cuando lo llevaba totalmente hacia arriba o a la izquierda dejaba de funcionar. Esto es porque en la condición que compruebo si el valor leído de las entradas está entre 0 y 1024 el 0 no estaba incluido. 

Una vez solucionados estos errores el prototipo ya ha funcionado como esperaba, cumpliendo todas mis expectativas. Está claro que hay muchas cosas que mejorar pero para ser la primera versión no está nada mal.

Gamepad con Arduino

Conclusiones y futuras mejoras del Gamepad

Mientras estaba jugando me he dado cuenta de varias cosas. La primera es que los botones físicos necesitan algún tipo de almohadilla porque me duelen los dedos al jugar con ellos. Lo segundo es que necesito un Joystick con una mejor sensibilidad para poder mover el ratón o lo que sería la cámara en el juego con mayor precisión.

Además es obvio que faltan muchos botones por añadir. Ni siquiera puedo apuntar para disparar a los enemigos, pero esto era algo que ya sabía que iba a ocurrir desde el principio, así que no me preocupa.

Las conclusiones de este primer prototipo es que necesito un Joystick con muchas más sensibilidad para poder mover el ratón con más precisión. También necesito diseñar una PCB para conectar todos los componentes e imprimir lo que sería la carcasa del mando porque la verdad es que con la placa protoboard es muy incómodo de utilizar. Por último, está claro que necesito agregar más controles para poder jugar a cualquier juego.

Si quieres poner en práctica tus conocimientos de Arduino pulsa aquí ¡Proyectos con Arduino Espectaculares! y descubre nuevos proyectos.