2021/04/18

El gusanito revive en un trabajo práctico: intro

El gusanito


Hace unos años me sentía frustrado por que personas menores que yo con mejor motricidad obtenían mejores resultados en el juego Slither.io pese a yo tener una mejor visión estratégica, fenómeno que tambien ocurre con UrbanTerror y con Fornite y me imagino que con cualquier otro video juego de tiempo real.


Con respecto a Urban Terror tengo una idea que en algún momento concretaré, pero relacionado a Slither.io pasé de la idea a la práctica y llegué bastante lejos, te resumo lo que hice antes:


El gusanito va hacia donde esté el cursor del mouse, lo cual a mi me complica pues tengo que ver el escenario y a la vez dónde está el cursor.


Slither.io
Slither.io


Por la naturaleza de la interfaz, que viene a ser rotativa como el Gyruss, me parece que conviene usar un controlador de tipo Paddle y más o menos lo implementé con un encoder rotativo y una placa EDU-CIAA-NXP tal que se hace pasar por un mouse.

A medida que el encoder gira, el programa transforma en movimientos de mouse tal que hacen una circunferencia pero no terminé de hacer la matemática y algún otro problema tuve y le ganó otra prioridad y cayó en el olvido.

Todo eso está mucho más largo en:


Slither - 1 - Intro
Slither - 2 - encoder con edu-ciaa-nxp
Slither - 3 - usb mouse con edu-ciaa-nxp
Slither - 4 - usb mouse y encoder con edu-ciaa-nxp

 

El trabajo práctico


En la materia Introducción a los Sistemas Embebidos del CEIoT se nos encomendó desarrollar una aplicación tal que:
  1. Debe emplearse la placa NUCLEO
  2. Puede ser una aplicación diferente (no necesariamente domótica)
  3. Puede utilizar los sensores vistos o agregar los nuevos
  4. Debe usar al menos una entrada analógica
  5. Debe usar comunicación serie
  6. Realizar la temporización del sistema basada en interrupciones y uso de timers

La placa NUCLEO es la que estamos usando para todos los ejercicios

Los sensores vistos, al momento de escribir esto fueron botones, sensor de gas vía i2c, potenciómetro y sensor de temperatura vía entrada analógica y supongo que luego veremos teclado matricial y sensor de movimiento al menos.

La verdad es que aunque no trabajo de esto, ya tengo bastante experiencia y sólo el punto 6 me resulta un desafío, así que podía inventarme una aplicación boba que cumpliera para poder aprobar o buscarme algo más difícil para aprender y ahí recordé al gusanito, me aferré al segundo requerimiento y pensé en cómo rescatarlo para el trabajo práctico.

 

Una reflexión muy personal

 

Como alumno, uno puede estar cursando algo por el conocimiento o la certificación, esto último se traduce en la aprobación y si querés entrar en detalles, la nota. Yo soy partidario de cursar, hacer trabajos prácticos, laboratorios y rendir exámenes por el conocimiento y que la certificación sea un efecto colateral.

En esta materia en particular, la verdad verdad es que voy a profundizar el conocimiento, pues ya he tomado varios cursos que más o menos cubren lo mismo y he practicado mucho por mi cuenta. Aunque no me interesa mayormente, en términos objetivos el resultado más importante de esta cursada resulta ser la certificación.

Como docente, entiendo que distintas personas sepan más o menos del tema de antemano y tendría la tentación de pedirle a cada una más o menos según su condición. A mi y a los ingenieros electrónicos que asisten les pediría más que a los estudiantes de sistemas, que pueden estar en el horno por que todo es nuevo.

Y podría hacerlo en términos de acompañar su aprendizaje, pero no en términos de certificación, no le puedo pedir más a quien más sabe, pues estaría discriminando y o forzando mi visión sobre como debe ver la vida esa persona. De todos modos para otorgar la certificación lo que importa en última instancia es lo que la persona sabe, no si lo acquirió ahora o antes.

Entonces, si alguien ya sabe todo, para aprobar le pediría lo mismo que a quien entra sin saber nada. Digo "pediría" pues por más que soy docente aún no he logrado por falta de experiencia y agravado por lo remoto poder discernir claramente cuáles alumnos saben más que otros.

Ok, pero cuando se trata de mí, hace mucho que no soy mero alumno, acompaño al docente y soy docente de mi mismo, entonces, si tengo tiempo, debo elevar la vara, tal como hice con el trabajo práctico de la reciente materia Basic Digital Design


Volviendo al trabajo práctico


Lo que me he propuesto es:

  • Usar la placa NUCLEO (requerimiento 1).
  • Un encoder rotativo para determinar el giro (requerimientos 3 y 6).
  • Un potenciómetro para el radio de giro (requerimiento 4).
  • Un potenciómetro opcional para la resolución (requerimiento 4).
  • La conexión serie para implementar algún protocolo de mouse (requerimiento 5).

 

El requerimiento 2 más que un requerimiento es una libertad, lo cumple la aplicación misma.

Los problemas

Encoder rotativo

Lo del encoder rotativo ya lo había resuelto antes, tengo que ver si me sirve y quizás corregir. Tambien agregar los potenciómetros.

¿Qué es lo de la resolución? Si jugás un rato observarás que si ponés el cursor bien cerca del bicho a ojo diría que tenés como unos cinco grados de resolución, si lo ponés bien lejos, un grado. El problema es que el encoder rotativo que tengo es de unos 10 grados. Lo que puedo hacer es que no tenga, no sé como se dice, ¿la misma relación de giro? O sea, que esos 10 grados se traduzcan en un solo grado.

Lo puedo lograr por sofware, claro, o con mecánica, introduciendo un componente extra con un engranaje que haga la reducción. Comprenderás que esto está muy alejado de mi torpeza, no será así.

Para el trabajo práctico me quedaré con los 10 grados pero quizás agregue un potenciometro para cambiar la escala, veremos.

Radio de giro

Esto tiene que ver con la resolución pero no en grados, en el perímetro recorrido.

Sobre este tema y la resolución me falta reflexionar e investigar bastante y probablemente quede fuera del trabajo práctico tal profundidad y me contente con algo básico

Comunicación serie

Podría negociar con la cátedra usar USB, que es más difícil que lo que voy a hacer, pero la realidad es que ya lo hice con la EDU-CIAA-NXP. Mientras exploraba encontre que existe inputattach que permite recibir por comunicación serie un protocolo de mouse o teclado y conectarlo como si fuera tal dispositivo, soporta un montón de protocolos.

Me dije entonces, ha llegado la hora de aprender a hacer ingeniería inversa de protocolos seriales de mouse y como probablemente sea el punto crítico, será el primer tema a resolver, a publicar en unos días o si fracaso, enterrar en el olvido algunos años más hasta que reviva con otra excusa.



Teclado hexadecimal USB: una pausa para los aspectos físicos

Como he logrado un éxito parcial y mi teclado presenta las funciones básicas, augurando sino un éxito completo al menos esquivar el fracaso, ya podría ir prestando atención a como voy a poner el Teensy dentro del gabinete del teclado, para lo cual debo considerar los siguientes aspectos:


  • Debe entrar en el lugar que tengo pensado sin que toque al circuito existente.
  • Debe exponer al exterior el conector.
  • Debe quedar accesible el botón de reprogramación sin necesidad de abrir el gabinete.
  • Debe quedar fijo, tal que al conectar el cable USB o al oprimir el botón de reprogramación no se suelte.

 

Lo que no tendré en cuenta pues supera mi capacidad y tiempo, es el tema de interferencias electromagnéticas y la disipación de la temperatura. Con respecto a lo primero, apostaré a que no pase nada y a lo último, tendré la precaución de que dejar espacio entre el chip y el gabinete.

 

Extra: quitar los pines

 

Por ahora nada me ha llevado más tiempo y producido más frustración que quitar los pines. Primero, intenté con paciencia quitar el plástico de los pines, para contrarrestar el efecto "la unión hace la fuerza", cada pin por separado es evidentemente más sencillo que la tira completa. Nada, estaba muy firme, le dí con el disco de corte de torno de mano a un lado y pude quitar todo el plástico.

Para desoldar los pines, tuve que desarrollar una técnica que comparto:

En lugar de calentar la soldadura, calentar el pin desde el lado contrario, se puede hacer con dos a la vez para compensar los movimientos, la punta del soldador queda trabada. Cuando comienza a moverse y recién en ese momento, con una pinza lo retirás. No toques con la pinza antes pues se enfría.

 [foto]

Pese al método, tuve un brote de impaciencia y perdí uno de los through holes, por suerte el de GND, hay otro por ahí.

 

Colocación del Teensy


Para medir el lugar pude haber hecho un esfuerzo intelectual y con un calibre medir con gran precisión, pero me agarró un cierto infantilismo y me pareció más pintoresco poner un poco de plastilina debidamente protegida con un plástico y poner el circuito en su posición, para que ésta se aplaste y tome la medida del hueco:


Plastilina antes
Plastilina antes

 
 
Aún así tenía la esperanza de poder usar el calibre, hace pocos meses adquirí uno mediocre pero de metal tras haber pasado casi treinta años de haber perdido el excelente que tenía, pero no hizo falta medir, a ojo se vé claramente que sin los pines la plaquita entra holgadamente y al estar levemente separada por el conector del plástico, cumple quizás con una leve ventilación:
 
 
Plastilina despues
Plastilina despues
 


Salida para el conector


Para exponer el conector al exterior un lamentable y desprolijo orificio alcanza. 

 

Acceso al botón de reprogramación


Otro triste agujero, con el beneficio extra de que al entrar la pieza en éste, produce una traba que va a servir para que al conectar el cable la placa se mantenga en su lugar.


Botón de reprogramación
Botón de reprogramación


 

La fijación


Había pensado usar cuatro pines y "clavarlos" en el plástico del fondo pero ya viste que lo mío no es el trabajo de precisión, va con la pistola plástica adhesiva.


 

Extra: periférico

 

En otro cajón tengo un touchpad cuyo rescate y adaptación a USB me ha servido de base para esta experiencia. Tuve la fantasía de quitarle las teclas de las flechas y ponerlo ahí, pero es una atrocidad y le quita lo retro. Luego pensé en una especie de cajoncito y que salga por un costado, pero sería frágil y desprolijo. Me quedé entonces con la idea de una ampliación, poner el touchpad en algún gabinetito copado y hacelo conectable.

Ya me conozco y si voy por ese camino no voy a terminar nunca. Lo que hice entonces es dejar un conector RJ-1, el del teléfono, que era lo que tenía a mano y tiene cuatro cables. El cajón de la basura sigue rindiendo frutos, alguien dijo "las noticias de hoy envolverán el pescado de mañana", yo puedo decir que la basura del ayer encontrará conmigo su destino, en algún momento.

No bien terminé de poner la masilla en el gabinete del teclado me dí cuenta de que pude haber puesto un conector ps/2, con lo cual me serviría para conectar cualquier legacy, pero bueno, ya pasó, si lo necesito fabricaré el cable adaptador.

Queda para cuando implemente el programa más completo del teclado incorporar el touchpad, no creo que implique ninguna dificultad.

Siguiendo el manual, ya dejo soldados los cables en los pines apropiados.


BoardData PinClock Pin (IRQ)
Teensy 3.6
Teensy 3.5
Teensy 3.2
Teensy 3.1
Teensy 3.0
Any
except 13 &
analog-only
pins
Any
except 13 &
analog-only
pins
Teensy LCAny
except 13
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 14, 15, 20, 21, 22, 23
Teensy 2.0Any, except 115, 6, 7, 8
Teensy 1.0Any0, 1, 2, 3, 4, 6, 7, 16
Teensy++ 2.0Any, except 60, 1, 2, 3, 18, 19, 36, 37
Teensy++ 1.0Any0, 1, 2, 3, 18, 19, 36, 37


Interior final con puerto para ampliación
Interior final con puerto para ampliación


 

Retoque final


Un poco de LEM y no te digo que nuevo, pero al menos parece limpio. 

Final
Final


En lo físico lo único que me ha faltado es conectar el switch de AP/X al Teensy para... no sé para qué, cualquier cambio de modo lo voy a hacer apretando varias veces NumLock.


Y aquí tenés la prueba de que funciona:

0123456789ABCDEF






2021/04/17

Teclado Hexadecimal USB: Versión 1 funcionando

Venís de la intro y un mini POC.

 

Tras mirar bastante el código  de PS2Keyboard, que es la clase que lee el teclado PS2 y observar el comportamiento de Keyboard, que es la clase que se hace pasar por un teclado USB, he logrado comprender bastantes cosas, empezando por las limitaciones.

                           [PS2Keyboard]
                               /   \
  PC <-- USB -->[Keyboard] Teensy   <-- ps2 --> Teclado
                               \   /
                               [ps2]


Usando PS2Keyboard y Keyboard, ya tengo un segundo prototipo, que funciona con lo básico, pero no puedo hacer que me funcionen las demás teclas como las flechas ni el NumLock.
 

PS2Keyboard

PS2Keyboard es de más alto nivel, toma las secuencias de código que provienen del teclado y las convierte en caracteres de 8 bits. Mapea las teclas especiales como "print screen" y "capslock" a un código arbitrario.

Se usa asi:

 if (keyboard.available()) {
    // read the next key
    char c = keyboard.read();

Si oprimis la tecla "4", recibís un "4" (ascii 52 o 0x34).

Tocando el código de la librería:

[$ARDUINO_FOLDER/hardware/teensy/avr/libraries/PS2Keyboard/PS2Keyboard.cpp]

 

     while (1) {
           s = get_scan_code();
           if (!s) return 0;
           if (s == 0xF0) {
                   state |= BREAK;
                   Serial.println("BREAK");
           } else if (s == 0xE0) {
                   state |= MODIFIER;
                   Serial.println("MODIFIER");

 

Si oprimís "4", en el serial emitís un BREAK, si oprimís flecha arriba, MODIFIER, MODIFIER, BREAK, pero para consumir unos caracteres inútiles por ahora.

 

Toqué un poco en el .h:

[$ARDUINO_FOLDER/hardware/teensy/avr/libraries/PS2Keyboard/PS2Keyboard.h]

// Every call to read() returns a single byte for
// each keystroke.  These configure what byte will
// be returned for each "special" key.  To ignore
// a key, use zero.
#define PS2_TAB                      9
#define PS2_ENTER                   13
#define PS2_BACKSPACE                7
#define PS2_ESC                     27
#define PS2_INSERT                  65     // 0
#define PS2_DELETE                  68     // 127
#define PS2_HOME                    66     // 0
#define PS2_END                     69     // 0
#define PS2_PAGEUP                  67     // 25
#define PS2_PAGEDOWN                70     // 26
#define PS2_UPARROW                 11
#define PS2_LEFTARROW                8
#define PS2_DOWNARROW               10
#define PS2_RIGHTARROW              21
 

 

 Y con eso tengo las letras A-F en donde quería.

 

 La versión actual queda:


include <PS2Keyboard.h>

const int DataPin = 5;
const int IRQpin =  3;

PS2Keyboard keyboard;

void setup() {
  keyboard.begin(DataPin, IRQpin);
  delay(1000);
}

void loop() {
 if (keyboard.available()) {
    char c = keyboard.read();
    Keyboard.print(c);
  }
}

 

El resto

ps2

ps2 es de bajo nivel, recibe sin interpretar cada código desde el teclado:

  for (;;) { /* ever */ 
    code = kbd.read();
    Serial.println(code, HEX);

Si oprimís la tecla "4", recibís:

6B
F0
6B

Aparentemente 6B es 4-keypress y F06B es 4-keyrelease

Si oprimís flecha arriba:

E0
75
E0
F0
75

Afirmaría que E075 es upArrow-keypress y E0F075 upArrow-keyrelease.

A ver, qué pasa si hago:

  • oprimir 4  
  • oprimir flecha
  • soltar flecha
  • soltar 4

6B -> 4 keypress
E0
75 -> flecha keypress
E0
F0
75 -> flecha keyrelease
F0
6B -> 4 keyrelease

Bien, si ahora oprimo el 4 y espero, aparece el 6B, si no me apuro en soltar, se llena de 6B. Ya está bien clarito, llegó el momento de mapear todo...

 


key presskey release
printscreenE012E07C



E0F07CE0F012
scroll lock7E






F07E



pauseE11477E1F014F077





backspace66






F066



num lock77






F077



insertE070





E0F070


homeE06C





E0F06C


page upE07D





E0F07D


deleteE071





E0F071


endE069





E0F069


page downE07A





E0F07A


up arrowE075





E0F075


left arrowE06B





E0F06B


down arrowE072





E0F072


right arrowE074





E0F074


esc76






F076



/E04A





E0F04A


*7C






F07C



-7B






F07B



76C






F06C



875






F075



97D






F07D



+79






F079



46B






F06B



573






F073



674






F074



169






F069



272






F072



37A






F07A



enterE05A





E0F05A


070






F070



.71






F071



Intuyo que si pudiera activar el NumLock, las teclas marcadas en verde enviarían otros códigos.


El código referenciado está en

$ARDUINO_FOLDER/libraries/ps2/ps2.h

$ARDUINO_FOLDER/libraries/ps2/ps2.cpp

 

Próximos pasos

Tengo que examinar Keyboard para ver si puedo enviar esos códigos directamente o tengo que hacer alguna conversión y quizás prender y apagar el LED. En otras palabras, que el teclado funcione de modo transparente salvo los reemplazos de teclas objetivo del ejercicio.