ev3dev – keypad USB

Ter o LEGO Mindstorms EV3 a correr uma versão quase standard de Debian Linux começa agora a revelar as suas vantagens: podemos atirar-lhe com quase tudo o que tivermos na nossa gaveta de sucata… como por exemplo um teclado numérico USB:

USB Keypad (roline)

O sistema operativo reconhece-o como um teclado convencional:

root@ev3dev:~# dmesg
usb 1-1.4.1: new low-speed USB device number 7 using ohci
input: USB-compliant keyboard as /devices/platform/ohci.0/usb1/1-1/1-1.4/1-1.4.1/1-1.4.1:1.0/0003:0B38:0003.0001/input/input2
hid-generic 0003:0B38:0003.0001: input: USB HID v1.10 Keyboard [USB-compliant keyboard] on usb-ohci.0-1.4.1/input0
input: USB-compliant keyboard as /devices/platform/ohci.0/usb1/1-1/1-1.4/1-1.4.1/1-1.4.1:1.1/0003:0B38:0003.0002/input/input3
hid-generic 0003:0B38:0003.0002: input: USB HID v1.10 Mouse [USB-compliant keyboard] on usb-ohci.0-1.4.1/input1
root@ev3dev:~# lsusb
Bus 001 Device 007: ID 0b38:0003 Gear Head Keyboard
Bus 001 Device 006: ID 058f:9254 Alcor Micro Corp. Hub

(o teclado tem embutido um hub USB de 2 portas daí o segundo device USB reportado)

O sistema operativo cria entradas do tipo ‘event#’ em ‘/dev/input’ assim como apontadores com descritivos mais legíveis:

ls /dev/input/by-id/ -la
lrwxrwxrwx 1 root root  10 Aug 13 23:38 usb-0b38_USB-compliant_keyboard-event-if01 -> ../event2
lrwxrwxrwx 1 root root  10 Aug 13 23:38 usb-0b38_USB-compliant_keyboard-event-kbd -> ../event1

De modo que o teclado pode ser referido por um destes dois ficheiros:

  • /dev/input/event1
  • /dev/input/usb-0b38_USB-compliant_keyboard-event-kbd

Enquanto que o sufixo “event1” é variável, o descritivo “by-id” não é – no meu laptop Ubuntu o mesmo comando retorna:

~$ ls /dev/input/by-id/ -la
lrwxrwxrwx 1 root root  10 Aug 13 23:38 usb-0b38_USB-compliant_keyboard-event-if01 -> ../event19
lrwxrwxrwx 1 root root  10 Aug 13 23:38 usb-0b38_USB-compliant_keyboard-event-kbd -> ../event18

por isso é preferível utilizar o descritivo “by-id”.

Não é suficiente ler os valores deste ficheiro – o primir de uma tecla gera gera um código de vários caracteres aparentemente ininteligiveis:

~$ cat /dev/input/event1
w��S�VSw��S�VEw��S�Vw��S�Ww��S�Ww��S��Sw��S��Ew��S��^C

A solução é usar o comando ‘showkey -s’ para descodificar. Por exemplo premindo a tecla ‘4’ com e sem ‘NumLock’ activo resulta:

cat /dev/input/by-id/usb-0b38_USB-compliant_keyboard-event-kbd > showkey -s
  • Sem Numlock: “^[[D”
  • Com NumLock: “4”

Felizmente isto só é necessário se quisermos ler directamente o teclado. Em situações normais, quando os nossos programas estão a correr, o próprio sistema operativo pode fazer esse trabalho por nós. No caso do ev3dev podemos ler uma única tecla a partir da consola com o seguinte comando bash:

read -s -n 1 Tecla < /dev/tty1

O parâmetro ‘-s’ serve para correr em modo silencioso (i.e. a tecla não é simultâneamente escrita na consola) e o parâmetro ‘-n 1’ força a leitura de um único caracter (quanto ao pipe ‘< /dev/tty1’ descobri entretanto que tanto faz referir /dev/tty0 como /dev/tty1 portanto a partir daqui refiro a consola do ev3dev como /dev/tty1… porque sim)

O script abaixo junta esta informação com a obtida anterior a respeito dos motores e permite controlar a rotação do motor com as teclas ‘4’ (LEFT) e ‘6’ (RIGHT), terminado com a tecla ‘ENTER’.

#!/bin/bash

#chmod +x controlkey.sh

tput clear > /dev/tty1
setfont /usr/share/consolefonts/Lat15-TerminusBold32x16.psf.gz
echo -n "Prima tecla" > /dev/tty1

while true; do

  read -s -n 1 char < /dev/tty1
  if [[ "$char" = "" ]]; then
    break
  fi

  case "$char" in

  4) echo "LEFT" > /dev/tty1

     echo   0 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp
     echo   1 > /sys/class/tacho-motor/tacho-motor0/run
     echo   50 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp
     sleep 1s
     echo   0 > /sys/class/tacho-motor/tacho-motor0/run
     echo   0 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp

    ;;

  6) echo "RIGHT" > /dev/tty1

     echo   0 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp
     echo   1 > /sys/class/tacho-motor/tacho-motor0/run
     echo   -50 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp
     sleep 1s
     echo   0 > /sys/class/tacho-motor/tacho-motor0/run
     echo   0 > /sys/class/tacho-motor/tacho-motor0/duty_cycle_sp

    ;;
   esac

done

echo "Bye!" > /dev/tty1