2016/07/26

Slither - 4 - usb mouse y encoder con edu-ciaa-nxp

Viene de  Slither - 3 - usb mouse con edu-ciaa-nxp

Ahora, hay que combinar el código del mouse [1] con el del encoder [2]. Esto está en [3].

La idea es que al llamar a Mouse_Tasks(), hay que avisarle que ha hecho el encoder.

Me imagino que la forma correcta de programarlo hubiese sido activar las interrupciones de los pines a donde conectemos el encoder y hacer la lógica correspondiente.

Sin embargo, a mi me parece que por como viene el ejemplo

   Mouse_Tasks();
   /* Sleep until next IRQ happens */
   __WFI();


lo que está ocurriendo es que se habilitó la interrupción de USB y cuando __WFI() lo detecta sigue con el bucle, o sea, no se está llamando a ninguna función por la interrupción.

O sea, yo tendría que habilitar las interrupciones sin darle un handler y poner algo como:

   Encoder_Tasks();
   Mouse_Tasks();
   /* Sleep until next IRQ happens */
   __WFI();


Probablemente tendría que agregar lógica en cada *_Tasks() para ver si me llamaron por mi interrupción o por otra.


Como no sé nada de interrupciones aún, voy a poner inline Encoder_Tasks() y mala suerte, ver como responde.

El código resultante es buena parte del encoder, pero tuve que modificar las firmas de Mouse_Tasks() y  Mouse_UpdateReport() para que reciban los valores del encoder.








[1] https://github.com/cpantel/ciaa/tree/master/slither.io/STANDALONE/usbDeviceHID_mouse

[2] https://github.com/cpantel/ciaa/tree/master/slither.io/encoder

[3] https://github.com/cpantel/ciaa/tree/master/slither.io/STANDALONE/usbDeviceHID_mouse_encoder

Slither - 3 - usb mouse con edu-ciaa-nxp

Viene de Slither - 2 - encoder con edu-ciaa-nxp


En clase recibí el trabajo de adaptación a CIAA de Pablo Ridolfi y la gente de la CIAA sobre los ejemplos de NXP para que la placa funcione como teclado[1]. Mirando fijo y buscando un poco en Internet, hallé el código necesario[2] para que funcione como mouse e hice la adaptación[3], que no hace más que decirle a la máquina "movete a la derecha un poco" cada tanto.

Hasta donde alcanzo a comprender no es un ejemplo bare metal y usa interrupciones, que no era lo que yo deseaba aún, pues me autoimpuesto terminar de agotar el recurso de NO usar interrupciones por cuestiones didácticas.

Para que no tengas que descubrirlo vos, te cuento que main() tiene un loop:

   Keyboard_Tasks();
   /* Sleep until next IRQ happens */
   __WFI();


y Keyboard_Tasks() llama a Keyboard_UpdateReport(), donde para cada tecla

if(!ciaaReadInput(#tecla#)) {
   HID_KEYBOARD_REPORT_SET_KEY_PRESS(g_keyBoard.report, 0x#letra#);


dependiendo de la #tecla# oprimida se agrega al reporte una #letra#

Para el mouse es casi igual,

   Mouse_Tasks();
   /* Sleep until next IRQ happens */
   __WFI();



y Mouse_Tasks() llama a Mouse_UpdateReport():

   setXYMouseReport(g_mouse.report, x, y);

con un x que se va incrementando, así que se va para la derecha cada vez más rápido.

Sigue en Slither - 4 - usb mouse y encoder con edu-ciaa-nxp

[1] https://github.com/cpantel/ciaa/tree/master/slither.io/STANDALONE/usbDeviceHID_keyboard

[2] https://github.com/micromint/LPCOpen-keil-lpc43xx/tree/master/applications/lpc18xx_43xx/examples/usbd_rom/usbd_rom_hid_mouse

[3] https://github.com/cpantel/ciaa/tree/master/slither.io/STANDALONE/usbDeviceHID_mouse

2016/07/17

Slither - 2 - encoder con edu-ciaa-nxp

Viene de  Slither - 1 - Intro

Tengo tres maneras...


El encoder no sirve para "producción", en una hora seguramente quedará destruido, hay que construir algo más sólido.

Mientras lo voy a usar pues es apropiado para el prototipo

La página del vendedor dice que 00 ->01 ->11 -> 10, pero la realidad es que a la vista prenden ambos y apagan ambos.



[1] dice "VERY SLOWLY rotate" y ahí se puede ver que si ocurre esa secuencia, ok, podemos seguir.

El problema que se me plantéa ahora es usar lo que ya sé en la edu-ciaa-nxp pero adaptando 5v a 3.3v o tener que aprender sobre un arduino. La ventaja del segundo camino es que el ejemplar final va a ser sobre arduino o atmega o attiny, pero el objetivo de este ejercicio es aprender y no necesariamente por el camino más corto.

El camino de edu-ciaa-nxp

Yo, electrónica 0.1, vivo en el stackoverflow del hardware, copio y pego, no entiendo casi nada.

Tengo dos cajitas con transistores. Una no sé que son y la otra 2n2222, busqué "2n2222 5v 3.3v" y hallé vía imágenes el circuito que necesitaba. Lo probé primero con una fuente de 5v y dos pilas AA, ok, le doy 5v por un lado sale 3.x por el otro.

Sería completamente irresponsable de mi parte compartir lo que hice pues no calculé las resistencia, nada, copié y medí con el tester.

Aún así, lo voy a poner, pero ya sabés:





El primer desafío fue como enterarme de si estaba siendo leido el encoder. El hecho de mostrar por el puerto serial afecta pues se pierden pasos.

Despues de varios intentos llegué a esta forma:

  • leer pines
  • resolver para que lado giró
  • reportar una vez cada tanto

de este modo, casi no se pierden pasos, solo al girarlo muy rápido que no me importa mucho. Además se parece mucho a lo que va a resultar: que no se va a reportar cada evento si no una acumulación de eventos en un período. Cuando no haya movimiento, nada se reportará. Cuando sea lento será un sólo evento. Cuando sea rápido, el resultado.

Pero el camino no está acolchado de pétalos de rosa. Aparecen movimientos en el sentido contrario espúreos.

Esta salida corresponde a  varios giros a la izquierda finalizando con uno a la derecha, con reportes cada un segundo aproximadamente:

left:    skip: 1 error:  right: 
left:    skip: 1 error:  right: 
left:    skip: 1 error:  right: 
left: 15 skip: 1 error:  right: 1
left: 9  skip: 1 error:  right: 1
left:    skip: 1 error:  right: 
left: 22 skip: 1 error:  right: 4
left:    skip: 1 error:  right: 
left:    skip: 1 error:  right: 
left: 59 skip: 1 error:  right: 5
left:    skip: 1 error:  right: 
left: 1  skip: 1 error:  right: 17


Este es el reporte con los estados actuales, futuros y la acción reportada de girar a velocidad intermedia, de una caso de los peores:

state: 1 nextState: 3 L  
state: 3 nextState: 2 L  
state: 2 nextState: 3 R  
state: 3 nextState: 2 L  
state: 2 nextState: 0 L  
state: 0 nextState: 1 L  
state: 1 nextState: 3 L  
state: 3 nextState: 2 L 

state: 2 nextState: 3 R  
state: 3 nextState: 2 L  
state: 2 nextState: 0 L  
state: 0 nextState: 2 R  
state: 2 nextState: 0 L  
state: 0 nextState: 1 L  
state: 1 nextState: 3 L  
state: 3 nextState: 1 R  


Siendo estas las transiciones:

         00 -> 10 -> 11 -> 01 -> 00 : Left

         00 -> 01 -> 11 -> 10 -> 00 : Right


Las transiciones parecen estar bien, el sampleo supongo que tambien, los eventos del encoder son unos pocos en 500000. Adivino que hay rebotes. Dado que lo estoy girando con la mano, suena razonable, más que no tengo un, no sé como se llama... ¿dial? ¿perilla?

El código está en [2] y debe ser copiado en un clone de [3] dentro de examples o donde más te guste, ajustando correctamente el Makefile.mine. Tambien debe estar la sapi_bm en modules.


¡¡¡¡Perdón por la globales!!!! Como dijo Trinity rescatando a Neo de las manos del Merovingo, I don't have time for this shit.

El próximo paso será, con la comunicación usb funcionando, acumular y reportar los movimientos como un desplazamiento en alguno de los ejes. Despues, el movimiento circular.

Sigue en Slither - 3 - usb mouse con edu-ciaa-nxp




[1] http://henrysbench.capnfatz.com/henrys-bench/arduino-sensors-and-input/keyes-ky-040-arduino-rotary-encoder-user-manual/

[2] https://github.com/cpantel/ciaa/tree/master/slither.io/encoder

[3] https://github.com/ciaa/Firmware/tree/release/1.0.x

Slither - 1 - Intro

Slither[1] es un simpático juego online tipo snake[2], es multiplayer y el gusanito se alimenta tanto de la comida que va creciendo en el tablero como de los otros gusanos al morir, lo que ocurre al chocar la cabeza contra el cuerpo de algún otro.

Se maneja mediante el mouse para apuntar hacia donde ir y el botón principal para acelerar. El gusano va hacia donde esté el cursor del mouse, lo cual no es muy amigable para hacer maniobras bruscas y más para mi que no soy muy diestro y al estar prestando atención a la ubicación de la comida y los demás gusanos, se me corre el puntero del mouse y eventualmente hago maniobras incorrectas.

Me imaginé que si tuviera un paddle[3] me iría mejor, así que decidí hacerme uno.

¿Por que mejor no te lo comprás? me podrías preguntar. Pues, por que no alcanza, hay que hacer algunas configuraciones para que el movimiento "circular" del paddle, en una sola dimensión, o sea, que gire para un lado u otro, se convierta en un movimiento de rotación alrededor de un punto del puntero en dos dimensiones.

No dije "el puntero del mouse", pues está claro que el puntero se puede mover con el mouse, el teclado o un joystick. Si tuviera un paddle debería escribir un programa y modificar alguna configuración para que se hiciera esa conversión en la máquina. Y probablemente tendría que configurar o iniciar algo cada vez que lo use.

Me parece mejor hacer un paddle que se haga pasar por un mouse y genere el movimiento de rotación por si mismo, que funcione igual en cualquier equipo que entienda un mouse.

La tarea entonces es hacer algo que gire, medirlo, transformarlo en dos desplazamientos en X e Y para finalmente pasarlo a la computadora como si fueran eventos de un mouse.

Necesito además tres botones:

  • El botón principal para acelerar.
  • Un botón para aumentar el radio.
  • Otro para disminuirlo.
Los dos últimos son "internos" al dispositivo, ajustan el radio de giro, la computadora no los conoce.

El escenario de uso es:
  • Posicionarse sobre el gusano
  • Conectar el paddle
  • Aumentar el radio, el puntero se desplazará hacia arriba
  • Usar
  • En cualquier momento, se puede cambiar el radio
Las actividades iniciales que hay que llevar a cabo son:
  • Inyectar eventos, ya sea como mouse usb o serial.
  • Leer un encoder rotativo.
  • Transformar un desplazamiento en una sola dimensión en un movimiento circular.
  • Construir un encoder rotativo resistente.
  • Interfasear componentes.

Los elementos de los que dispongo son:

  • Microcontroladores
    • edu-ciaa-nxp [4]
    • teensy [5]
    • attiny85
    • attiny85 con uart usb
    • atmega 328
  • Sensores
    • encoder rotativo tipo potenciómetro
    • encoder de un mouse de bolita
    • cámara sensora de un mouse óptico.


Esta es la idea más general:

   +----+   +------------+   +----------------+   +--------+
   | PC +---+ usb/serial +---+ transformación +---+ sensor +
   +----+   +------------+   +----------------+   +--------+


La edu-ciaa-nxp es la más potente de las opciones, la mejor para hacer debug, la que más dispositivos tiene y además tiene una importante comunidad [6] pero es overkill para producción. Probablemente se pueda registrar como un mouse serial con sencillez.

Teensy tiene el hardware y las librerías para registrase como mouse, teclado, joystick, midi y me parece que pendrive, pero tambien es overkill

Attiny85 serviría para algunas pruebas, pues sólo tiene 6 pines. El que tiene uart usb tiene 4, dos los usa en la uart.

Atmega 328 sería lo más económico, pero me obligaría a incursionar en conectarle la electrónica extra para comunicarse ya sea uart o usb.

Tengo un poquito de experiencia en todos salvo Attiny85. Atmega 328 incluso lo he programado con ISP y tengo una entrada casi lista para publicar.

El encoder tipo potenciómetro es apto para experimentar pero no para uso pesado.

El otro encoder me traería un desafío de tipo mecánico.

El sensor del mouse óptico vé en dos dimensiones, pero con que registre en una sola mirando alguna superficie del elemento giratorio, alcanzaría. El único problema es que no puedo hallar el USB que tenía, así que voy a usar un PS/2 con un adaptador a USB, es lo que hay...

Adicionalmente, en lugar de usar las partes del mouse, mejor se podría modificar al mouse.


                        +------------------------------------+
            |              mouse                 |
   +----+   | +-----+   +---------+   +--------+ |
   | PC +-----+ usb +---+  micro  +---+ sensor + |
   +----+   | +-----+   +-+-----+-+   +--------+ |
            |             |     |                |
            |     +-------+-+ +-+-------+        |
            |     | botón 1 | | botón 2 |        |
            |     +---------+ +---------+        |
            +------------------------------------+


El microcontrolador en el medio haría la conversión a (X,Y) e interpretaría a los botones, mmh, quizás alcance con 6 entradas/salidas. En ese caso el Attiny85 sería lo más sencillo y barato.


Apuntaré a esta última solución, pero aprovecharé la facilidad de uso de la edu-ciaa-nxp para los prototipos, quizás luego pase por teensy.



Voy a tener que seguir mi habitual método de planificación adaptativa, que es mucho más adaptativa que planificación y más o menos se parece a esto:


  • Inyectar eventos usb
    • Con teensy
    • Con edu-ciaa-nxp
  • Transformación
    • Con papel y lápiz
    • Con php en la pc
    • Con c en la pc
    • Con c en edu-ciaa-nxp
    • Con c en teensy/attiny/atmega
  • Lectura encoder
    • Encoder existente
    • Encoder construido
  • Construcción encoder
    • Con piezas giratorias de mouse mecánico
    • Con sensor óptico
  • Interfases
    • 5v a 3.3v para conectar encoder existente a edu-ciaa-nxp
    • modificar los mensajes del sensor óptico con edu-ciaa-nxp
    • con solución final
Como hay múltiples caminos posibles, no los hago explícitos, pero el éxito de algunos puntos produce que no haga falta transitar todos.

Sigue en Slither - 2 - encoder con edu-ciaa-nxp

[1] http://slither.io/

[2] https://en.wikipedia.org/wiki/Snake_%28video_game%29

[3] https://en.wikipedia.org/wiki/Game_controller#Paddle

[4]  http://proyecto-ciaa.com.ar/devwiki/doku.php?id=desarrollo:edu-ciaa:edu-ciaa-nxp

[5] https://www.pjrc.com/teensy/

[6] http://proyecto-ciaa.com.ar/ y sus varios foros
https://groups.google.com/forum/#!forum/ciaa-firmware
https://groups.google.com/forum/#!forum/ciaa-hardware
https://groups.google.com/forum/#!forum/ciaa-ide
https://groups.google.com/forum/#!forum/ciaa-linux