Desde hace algunos meses las flechas de dirección de mi teclado empezaron a fallar. Concretamente, mientras escribo este post, no sirve la tecla Flecha izquierda y Flecha arriba
Puedo vivir sin la de la izquierda, pero como bien saben, la de arriba sirve para el historial de comandos de la terminal.

Así que, como no quería comprar un nuevo teclado y tenía mi ESP32-S3-WROOM me dispuse a emular las 4 flechas de dirección aprovechando que esta placa tiene soporte USB HID para actuar como teclado.
Eligiendo botones
Se puede conectar cualquier sensor compatible con la ESP y Arduino, pero yo no quería usar botones (push buttons) porque quería algo que pudiera colocar en mi escritorio sin tener que soldar.
Quería algo simple, algo improvisado, así que recordé que
existe touchRead en mi ESP, que en pocas palabras
permite la Detección táctil capacitiva.
Lo único que iba a necesitar era tocar los pines con mi dedo, y opcionalmente conectar 4 cables.
Simular teclado con la ESP32 S3 WROOM
Con la ESP32 S3 WROOM podemos simular un teclado completo nativamente gracias a:
#include "USB.h"
#include "USBHIDKeyboard.h"
Luego en el setup:
Keyboard.begin();
USB.begin();
Y en cualquier momento podemos enviar una tecla:
Keyboard.press(KEY_UP_ARROW);
delay(50);
Keyboard.releaseAll();
Podemos enviar prácticamente todas las teclas de un teclado normal, y puede ser en respuesta a cualquier sensor o acción.
Nota: no olvides que para que esto funcione, el cable USB tipo C debe estar conectado en el conector izquierdo de la placa.
Detección táctil capacitiva
Esta ESP y muchas otras tienen un sensor touch
incorporado en varios pines. Podemos leer de cualquier
pin soportado usando touchRead y nos devolverá un touch_value_t
que al momento de escribir esto es un uint32_t.
En mi caso específico el pin me arrojaba valores menores a 40000 cuando no lo tocaba, y valores mayores a 100000 cuando lo hacía, así que establecí mi umbral en 50000.
Puede que esto cambie en tu caso, así que es importante que calibres
usando algo como Serial.println(touchRead(pin))
Otra cosa importante es que no todos los GPIO de la ESP sirven para leer toques, por ello es que he usado el 1,2,4 y 5. El 3 también sirve.
Reemplazar flechas de dirección
Yo solo quería enviar 4 teclas: las flechas de dirección, y quería hacer eso al tocar un simple cable.
Además de esto quería cambiar el color del LED RGB incorporado en cada pulsación.
Veamos el platformio.ini que tiene
la dependencia del control del LED (Adafruit NeoPixel).
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:freenove_esp32_s3_wroom]
platform = espressif32
board = freenove_esp32_s3_wroom
framework = arduino
lib_deps =
adafruit/Adafruit NeoPixel
monitor_speed = 115200
Luego el código C++:
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include "USB.h"
#include "USBHIDKeyboard.h"
#define PIN_RGB 48
#define NUM_RGB 1
const int PIN_ABAJO = 1;
const int PIN_ARRIBA = 2;
const int PIN_DERECHA = 4;
const int PIN_IZQUIERDA = 5;
const int umbralDetectarCableTocado = 50000;
USBHIDKeyboard Keyboard;
Adafruit_NeoPixel ledRgb(NUM_RGB, PIN_RGB, NEO_GRB + NEO_KHZ800);
void setup()
{
Serial.begin(115200);
Serial.println("Hola mundo");
Keyboard.begin();
USB.begin();
ledRgb.begin();
ledRgb.setBrightness(255);
}
/*
Estas banderas evitan que se mantenga
presionada una tecla. Puedes modificarlo según te convenga, yo
he deshabilitado esa parte porque se detecta muy rápido
*/
bool tocandoArriba = false;
bool tocandoAbajo = false;
bool tocandoIzquierda = false;
bool tocandoDerecha = false;
void loop()
{
bool mover = false;
if (touchRead(PIN_ARRIBA) > umbralDetectarCableTocado)
{
if (!tocandoArriba)
{
Keyboard.press(KEY_UP_ARROW);
delay(50);
Keyboard.releaseAll();
tocandoArriba = true;
mover = true;
}
}
else
{
tocandoArriba = false;
}
if (touchRead(PIN_ABAJO) > umbralDetectarCableTocado)
{
if (!tocandoAbajo)
{
Keyboard.press(KEY_DOWN_ARROW);
delay(50);
Keyboard.releaseAll();
tocandoAbajo = true;
mover = true;
}
}
else
{
tocandoAbajo = false;
}
if (touchRead(PIN_IZQUIERDA) > umbralDetectarCableTocado)
{
if (!tocandoIzquierda)
{
Keyboard.press(KEY_LEFT_ARROW);
delay(50);
Keyboard.releaseAll();
tocandoIzquierda = true;
mover = true;
}
}
else
{
tocandoIzquierda = false;
}
if (touchRead(PIN_DERECHA) > umbralDetectarCableTocado)
{
if (!tocandoDerecha)
{
Keyboard.press(KEY_RIGHT_ARROW);
delay(50);
Keyboard.releaseAll();
tocandoDerecha = true;
mover = true;
}
}
else
{
tocandoDerecha = false;
}
if (mover)
{
static uint16_t hue = 0;
ledRgb.setPixelColor(0, ledRgb.gamma32(ledRgb.ColorHSV(hue * 256)));
ledRgb.show();
hue = (hue + 1) % 360;
}
delay(10);
}
Básicamente es un:
if(touchRead(pin) > umbral){
enviarTecla();
}
Combinado con unas banderas para que no se mantenga presionado como lo explico en los comentarios:
Estas banderas evitan que se mantenga presionada una tecla. Puedes modificarlo según te convenga, yo he deshabilitado esa parte porque se detecta muy rápido y envía varias pulsaciones en un toque muy pequeño
Y después de cargar el código simplemente cambié el tipo C al conector de la izquierda y todo funciona perfectamente.
Circuito
No hay circuito pues es muy simple. Basta con, literalmente, tocar los pines de la ESP32 S3 con tu dedo, ya sea directamente o a través de un cable (o cualquier material conductor) como yo lo he hecho.
Conclusión
Finalmente acomodé mi teclado como se ve en la siguiente imagen:

Como ya había anunciado previamente, estoy haciendo un teclado TCP con WebSockets pero todavía no lo he publicado. Yo creo que será este mismo código + WS, pues físicamente tendremos las 4 flechas de dirección (para acceso instantáneo) e inalámbricamente tendremos todas las teclas.