Bueno por fin hemos acabado con todo lo que tiene que ver con este robot de lego.
Lo cierto es que ya hace casi dos semanas que lo devolvimos y más de un mes que dejamos de hacer prácticas con él, pero hemos tenido que retrasar la despedida por culpa de los exámenes.
Solo decir que aunque parezca un robot majo, trabajar con cigarro ha sido un infierno. Desmontarlo ha sido uno de los mayores placeres de este año y es que, aunque empezó muy bien llevar las prácticas al día ha acabado por ser un auténtico reto, que en ocasiones nos ha superado a todos (no, no seguimos pensando soluciones, el último post está cerrado hace ya muucho). Pero bueno al final hasta le hemos cogido cariño (sobre todo el señor X, que le ha tratado com a un auténtico hijo).
Así que nada, el señor X (desde este año un auténtico experto en java) y bender (el típico amigo pringao) se despiden del mundo robótico para siempre.
Suerte a todos los pringaos que quieran gozar de los placeres del nxt el año que viene, que os va a hacer falta xD.
Como el nombre indica esta práctica contiene ejercicios para comprobar la localización del robot en un entorno dado.
VISUALIZACIÓN DEL MAPA Y LAS PARTÍCULAS
Para comenzar a trabajar con el robot, lo primero es crear el mapa en el que se van a desarrollar las distintas pruebas. Dicho mapa se encuentra en un fichero .bin que le pasamos al filtro de partículas. Para poder mostrar los resultado por el LCD del robot se pinta el mapa con las medidas dadas en el enunciado.
DISEÑO DEL RADAR
En este apartado hay que crear un radar que funcione con los parámetros propuestos en el enunciado. Para ello hay que usar el sensor de ultrasonido montado sobre un motor, mediante el que realizar barridos.
Es importante destacar la utilización de RangeReadings, una clase en la que se guardan las mediciones y los ángulos obtenidos.
Para comprobar que nuestro radar funcionaba de forma correcta creamos una serie de casos prueba, en los que fuera muy sencillo comprobar el resultado. Por ello mostramos las mediciones del radar por pantalla en forma de histrograma.
Cuando vimos que los resultado era correctos pasamos a trabajar con el siguiente apartado.
RECONOCIMIENTO DE POSICIÓN Y ORIENTACIÓN
Para realizar el reconocimiento de posición modificamos el radar para que genere un histograma con las distancias obtenidas independientemente de la orientación.
Para ello el robot pasa por una etapa de aprendizaje en la que se toman medidas sobre 5 localizaciones distintas dentro del mapa y se guardan en un fichero. Como nuestro sensor de ultrasonido es muy impreciso al principio no obtuvimos buenos resultados por lo que acabamos optando por mejorar el código un poco, haciendo que el sensor tomase 5 mediciones de cada punto que guardabamos en un array. Una vez obtenidas estas medidas realizamos la mediana para quedarnos con el valor más "preciso". En un primer momento pensamos en realizar la media, pero finalmente decidimos cambiar de opinión ya que la mediana es menos sensible ante los valores extremos.
En cuanto a la orientación, una vez reconocido el punto en que te encuentras utilizamos la información obtenida con el radar anterior mediante rotaciones del RangeReading actual hasta hacerlo coincidir con el de referencia (punto en el que se encuentra). Teniendo en cuenta que el mapa era bastante simétrico, y que como ya hemos comentado nuestro sensor es bastante impreciso estamos contentos con nuestro resultado ya que el robot consiguió reconocer la mayoría de puntos, y siempre que este paso se hizo bien el ángulo también se adivinó.
RETO DE AUTO-LOCALIZACIÓN
Este es sin duda el apartado más difícil al que nos hemos enfrentado en este curso, y es que conseguir autolocalizarse con los medios a nuestro alcance no es tarea fácil. Para empezar hay que tener en cuenta que este apartado se basa en gran medida en el anterior, ya que para recorrer los 5 puntos fijados en el mapa de forma correcta en necesario saber en primero lugar en que punto te encuentras y con que orientación, y si eso falla todo lo demás ira detrás. Suponiendo que el robot hiciera esta primera parte de forma correcta, habría que empezar a trabajar con las partículas, para poder ir corrigiendo el error que produce el movimiento por el mapa, de forma que la acumulación de errores sea la menor posible, consiguiendo así resultados mucho más precisos. En estos momentos aún seguimos trabajando en este apartado.
Con esta nueva práctica comenzamos a indagar en el campo de la auto-localización, comenzando por el método de filtro de partículas (explicado de forma bastante amplia en el enunciado de la práctica).
En este caso no se trataba de implementar dicho método (lejos ya contiene una serie de clases que lo hacen*) , sino de entenderlo para poder usarlo correctamente.
*CLASES DE LEJOS: LineMap, MCLParticleSet, Line, Point, Movement.
MODELO DE MOVIMIENTO MEDIANTE LA CLASE MCLParticleSet
Una vez entendido cómo funciona de forma teórica el filtro de partículas habia que llevarlo a la práctica. Para ello creamos un pequeño mapa (new LineMap...) en el que creamos 100 partículas (new MCLParticleSet (map,numPartículas)), a las que aplicamos un cierto error en distancia y ángulo con setDistanceNoiseFactor y setAngleNoiseFactor, error que habíamos calculado previamente realizando diversas mediciones y hallando la desviación típica de dicho error.
Una vez hecho esto las situamos en el punto de partida con setLocation, y nos creamos una pequeña función con la el robot realizaba una trayectoria en forma de cuadrado. Mientras el robot avanza las partículas van actualizando su posición, se van moviendo con applyMove, mostrándose los resultados por pantalla.
Si juegas con el error en la distancia y el ángulo puedes comprobar como varían los resultados. Mientras que con errores pequeños la trayectoria en cuadrado es claramente visible, si introduces un error un poco más grande, las partículas se dispersan por toda la pantalla obteniendo como resultado un manchurrón negro que poco tiene que ver con el movimiento del robot.
CÁLCULO DE TRAYECTORIAS
En este caso se trata de conseguir que el robot llegue a unas coordenadas introducidas por pantalla y acabe con una cierta orientación.
Para la primera implementacion (pathfollow1) el robot tiene que orientarse hacia el punto, avanzar en linea recta hacia él, y por útimo corregir su orientación si fuese necesario.
Para este problema hemos usado la clase vector, que ya habíamos implementado para prácticas anteriores. Un vector de este tipo se construye con dos coordenadas, y tiene funciones muy útiles como getAngulo o getMódulo. Partiendo de la base de que nuestro robot está siempre en el eje de coordenadas (0,0), es fácil obtener la trayectoria gracias al uso de dichas funciones, y llevarla a cabo por medio de travel y rotate.
Para la segunda versión de pathfollow hay realizar trayectorias en forma de arco, y finalmente corregir la orientación (de nuevo solo si es necesario).
Este apartado es bastante más complejo que el anterior, y nos llevo mucho más tiempo obtener la solución. Finalmente creemos que, en el fondo, es como aquellos problemas infernales del bachillerato de encuentra la circunferencia que pase por dos puntos y sea tangente a la recta dada (en este caso el eje de abscisas), qué se le va a hacer. Así obtenemos el centro del arco y el ángulo, que es lo que nos queda, se calcula hallando el ángulo que forman el destino con el centro del arco a partir del eje de ordenadas.
Con todo esto sacamos una fórmula, muy bien pero ¿funciona de verdad o es otro fracaso más? Cigarro no es un buen sitio para probarla porque la mitad de las veces hace lo que quiere así que tuvimos que hacer esto de abajo para probarla cómodamente.
Funciona bien y todo. Abajo, cómo se comporta en el mundo real™:
Porúltimo hemos intentado dar repuesta a la pregunta: ¿Sería posible realizar una trayectoria compuesta por dos arcos, de maneraque se alcanzase el punto de destino y la orientación correctos sin necesidad de rotar adicionalmente una vez llegados al punto de destino?
En una primera aproximación se nos ha ocurrido que sería buena idea hacer un waitpoint a mitad de camino. Con el primer arco te desplazarías hacia dicho punto, por lo que tu orientación ya comenzaría corregirse. Y con el segundo arco llegarías al punto de destino. Gracias a este segundo arco podrías realizar trayectorias en zig-zag o en forma de S, logrando acabar con la orientación correcta.
Con una segunda pensada tenemos lo siguiente:
Podría calcularse una trayectoria más eficiente usando además una recta aunque esto se saldría de lo que dice el guión de la práctica.
En estas dos semanas nos hemos dedicado a desarrollar ciertos programas de navegación, ayudándonos de los sensores de contacto, ultrasonido y luz.
En lineas generales esta práctica ha consistido en dejar al robot navegando en busca de un cierto punto de destino evitando los obtáculos que encontrase a su paso.
Para trabajar comodamente con los sensores hemos tenido que cambiar el aspecto de nuestro robot (Cigarro, la encuesta salió positiva!!). Como puede verse en la imagen, hemos situado el sensor de ultrasonido en la parte superior montado sobre un motor con el fin de poder realizar los barridos. A los dos lados del robot, en la parte delantera están los dos sensores de luz, formando un ángulo de unos 45 y -45º, y finalmente, el sensor de contacto con su parachoques.
También cabe mencionar, que para esta práctica ha sido necesario implementar comportamientos (para ello es necesario usar la clase Behavior).
COMPORTAMIENTO DE EVITACIÓN DE OBSTÁCULOS USANDO SENSORES DE CONTACTO
Como describe el nombre del apartado, se trataba de esquivar los obstáculos usando sensores de contacto. En este caso los obstáculos eran latas con un cierto peso. No hay que olvidar que el objetivo final es llegar a la meta. Por tanto, es fácil distinguir los comportamiento que el robot tiene que llevar a cabo: Avanzar hacia delante y esquivar los obstáculos.
El robot tiene activado el comportamiento de ir para alante. Cuando el sensor de contacto advierte la presencia de un obstáculo salta el comportamiento esquivar, y una vez que el objeto ha sido sobrepasado se vuelve a activar el avanzar.
Avanzar: action: navegador.forward(). supress:navegador.stop(). takeControl:siempre true (es el comportamiento principal).
Esquivar: action: realizar el giro (travel, rotate,...) supress: vacio. takeControl: verdad si touch.isPressed().
COMPORTAMIENTO DE EVITACIÓN DE OBSTÁCULOS USANDO EL SENSOR DE ULTRASONIDOS.
Este aparto es sin duda el mayor reto al que nos hemos enfrentado hasta el momento, y al que le hemos dedicado mayor tiempo durante estas semanas. A pesar de ello los resultados hasta el momento no son tan buenos como a nosotros nos hubiera gustado.
La temática de este ejercicio es muy similar a la del anterior, solo que esta vez no será necesario chocar con el objeto para saber que está ahí, sino que usaremos métodos más sofisticados.
El robot deberá avanzar hacia delante realizando barridos con el sensor de ultrasonido. Si en ese barrido se detecta algún obstáculo hay que "guardar" su posición para no impactar con él. Es decir, de nuevo volvemos a tener dos comportamientos claramente diferenciados: Avanzar hacia delante (esta vez sensado con el ultrasonido) y esquivar.
Para llevar a cabo el comportamiento esquivar es necesario usar el método de navegación local conocido como VFF (Virtual Forces Field). Para este método hay que calcular la fuerza atractiva de tu punto de destino así como la fuerza repulsiva del obstáculo. Una vez que tienes los dos vectores puedes sumarlos, obteniendo así el vector resultante que determine el próximo movimiento del robot (evitando que impacte contra el obstáculo). Estos vectores deben actualizarse contínuamente, hasta que el objeto haya sido superado.
¿Problemas? Muchos. Para empezar la incertidumbre en el eje y del sensor nos juega malas pasadas por lo que tuvimos que tomar medidas como realizar un segundo barrido, a parte del que va haciendo el robot cuando viaja hacia delante, que en cada ángulo halle tres distancias y devuelva la menor de ellas. También da muchísimos problemas la actualización de las coordenadas a medida que nos vamos moviendo. Esto lo solucionamos separando las rotaciones de los desplazamientos en línea recta. En los desplazamientos hacia delante utilizamos prácticamente las mismas fórmulas que en la práctica 1 y en las rotaciones simplemente aumentamos el ángulo del vector en sus coordenadas polares.
Aquí podemos ver un esquemático del funcionamiento:
Y un vídeo en el que se ve la movida:
COMPORTAMIENTO IR HACIA LA LUZ En este caso el robot tiene que avanzar hacia la luz, representada por un foco. Ahora nuestros comportamientos son avanzar y buscarluz. Pensando un poco en la solución reconocimos 4 posibles situaciones a las que deberíamos enfrentarnos:
1: El robot no encuentra la luz: en ese caso debe girar hasta que la detecte, y comenzar a avanzar hacia ella.
2: El sensor derecho detecta más luz que el izquierdo: La lámpara está a la derecha, hay que girar hacia ese mismo lado.
3:El sensor izquierdo detecta más luz que el derecho: Igual que en el caso anterior, pero girando en el sentido contrario.
4:Ambos sensores detectan la misma luz: El foco está en frente, hay que andar recto hacia el.
BuscarLuz: action: resolución de los casos anteriores. supress: vacio. takeControl: devolverá verdadero o falso según la luz captada por los sensores.
Tanto para este como para el siguiente apartado merece la pena dar una vuelta por la API de lejos, ya que estamos usando sensores de luz del modelo anterior, el RCX, y hay ciertos métodos de la clase RCXLightSensor que están obsoletos y conviene usar lo menos posible. Además es necesario calibrar el robot cada vez que vaya a usarse, ya que la luz del ambiente puede variar, por lo que si no nos adaptamos al entorno, nuestro programa dejará de funcionar.
COMPORTAMIENTO IR HACIA LA LUZ EVITANDO OBSTÁCULOS Una vez implementados los ejercicios anteriores, obtener realizar este apartado resulta relativamente sencillo, ya que solo es necesario unir el comportamiento de buscar luz, al de avanzar hacia delante y esquivar obstáculo. Para este apartado podíamos elegir entre usar el sensor de contacto o el de ultrasonido. Nosotros nos hemos decantado por el de contacto, ya que su implementación es más simple y controlamos mejor su funcionamiento.
Esta semana nuestro robot ha crecido, ha echado cuerpo y ha aprendido a extraer información del entorno gracias a sus sensores: desde la iluminación de la habitación, hasta la carga de la bateria.
Para ello hemos tenido que implantarle estos sensores y luchar un poco con Cigarro para encontrar la forma de colocarlos todos de la mejor forma posible. La mayoría de ellos no fueron difíciles de ubicar, pero con el de ultrasonidos tuvimos que ejercitar la imaginación para conseguir que pueda apuntar hacia delante o hacia el lado. Tras gastar más de la mitad del celo decidimos optar por crear esa especie de plataforma circular que permite enforcar el sensor hacia donde nosotros queramos.
OBTENIENDO INFORMACIÓN
En este apartado había que sacar por pantalla cierta información como el nombre del robot, los valores del sensor de luz y del de ultrasonido, la memoria RAM disponible y la información de la batería.
Para obtener la información del ultrasonido utilizamos getDistance(), para la luz readValue() y getNormalizedLightValue(), para la batería getVoltageMilliVolt(), y por último para la memoria libre tuvimos que hurgar bastante en la documentación de la API hasta encontrar, bajo la clase Runtime el método freeMemory().
CONTROL DEL ROBOT POR SONIDO
Este apartado trata de hacer ruidos raros y asustar mucho a Cigarro. Para ello hay que elegir el porcentaje de decibelios a partir del cual el robot debía reaccionar.
En principio el robot permanece parado, recogiendo mediciones del micrófono con readValue(). Cuando se de la palmada el microfono la recogerá y el robot empezará a andar. Con la segunda palmada el robot vuelve a su estado inicial de espera (parado). Hemos incluído también un par de sleeps estratégicamente situados para dejar al sensor reestablecer su valor, si no salía de los bucles demasiado rápido y la ejecución tenía muchísimos problemas.
BUMP & GO! USANDO SENSORES DE CONTACTO
Para esta sección hay que poner a andar el robot en cualquier dirección con el sensor de contacto conectado. Cuando el sensor se pulsa ( sensor.isPressed()) el robot se para y ejecuta un método al que hemos llamado pasoAtrás. Como su nombre indica el robot realiza un pequeño movimiento hacia atrás para retirarse del obstáculo que ha detectado, y luego realiza un giro aleatorio gracias a la función random().
BUMP & GO! USANDO SENSORES DE ULTRASONIDO
El código para este apartado es muy similar al anterior, de hecho, se puede usar el mismo procedimiento de pasoAtrás, solo que esta vez usamos el sensor de ultrasonido, y por tanto, evitamos el obstáculo antes de la colisión. De nuevo volvemos a usar getDistance().
COMPORTAMIENTO SIGUE-PARED PARA SALIR DE UN LABERINTO
Como su nombre indica se trata de hacer un programa para el robot con el fin de que este pueda seguir la pared de una habitación sorteando esquinas, objetos apoyados, etc.
Para ello hay que ir tomando mediciones con el sensor de ultrasonido dirigido hacia la pared con un ángulo aproximado de 45º, y ir obteniendo datos del mismo para ir corrigiendo la ruta del robot.
Como podéis ver, el robot campa a sus anchas por nuestras casas como uno más yendo a la cocina a por algo de picoteo.
CALIBRACIÓN DEL SENSOR DE ULTRASONIDOS
Aquí el reto consiste en medir experimentalmente las características de nuestro sensor de ultrasonidos.
Primero comprobamos el rango de distancias para las que el sensor da una señal fiable. El resultado es [5cm, 240cm]. El rango de ángulos para el que las mediciones son válidas es [-45, 45] aproximadamente.
La siguiente comprobación es saber si el sensor tiene un error sistemático o no. Para ello tomamos medias perpendicularmente a una pared, los resultados son en cm:
Distancia en X
20
30
40
50
60
70
80
90
100
Distancia medida
23
32
42
52
62
72
81
92
101
Existe un error sistemático de media 1.8cm en las medidas del sensor de ultrasonidos.
El siguiente paso es calcular la incertidumbre de la medida en el eje X y en el eje Y independientemente. Para el eje X colocamos el robot a distintas distancias respecto a la pared y medimos, todas las medidas están en cm:
Distancia X
x1
x2
x3
x4
x5
x6
x7
x8
x9
x10
Media del error
40
42
42
42
42
42
43
42
42
42
43
2,2
50
52
53
52
52
52
52
52
52
52
52
2,1
60
62
62
62
62
62
62
62
62
62
62
2
70
72
72
72
72
72
72
73
72
72
72
2,1
80
81
81
81
82
81
82
82
82
82
81
1,5
90
92
92
92
91
92
92
92
92
91
92
1,8
100
102
102
101
102
102
102
102
101
102
102
1,8
110
112
112
113
112
112
112
113
112
112
112
2,2
120
122
122
123
122
122
122
122
123
122
122
2,2
Podemos deducir que el error no depende de la distancia ya que el error medio no cambia respecto a la misma.
Para la incertidumbre en el eje y colocamos un objeto a distintas distancias en el eje x y lo fuimos desplazando por el eje y hasta que dejabamos de recibir una medida válida. Los resultados han sido:
Distancia X
40
10
11
11
11
11
13
10
12
12
10
50
13
13
13
13
13
13
12
14
13
13
60
15
16
16
17
15
15
16
16
17
17
70
20
20
20
20
19
20
20
19
20
19
80
12
14
14
14
13
13
13
12
13
13
90
8
8
8
8
9
9
8
9
9
9
100
10
10
10
10
10
10
10
9
10
10
110
7
7
7
8
8
7
8
7
8
7
120
5
6
5
5
5
5
5
5
6
5
En este caso puede comprobarse que tiene una fuerte dependencia respecto a la distancia al robot. Las distancias en teoría deberían mostrar una figura elíptica aunque en nuestro caso hay que echarle imaginación para verla pero la elipse estar está, creednos. La culpa de este error se la echamos al sensor que el pobre no puede defenderse. Matrices de covarianza a distintas distancias del robot:
En esta semana lo más destacable fue, sin duda, el bautizo de nuestro robot con el noble nombre de Cigarro. ¿Cambiaremos su nombre la semana que viene? sólo Dios sabe.
En cuanto a la práctica 1, ésta podría dividirse en dos etapas. La primera correspondiente a la instalacion y uso de eclipse, y la segunda destinada a la creación de pequeñas aplicaciones para el robot.
En lo que se refiere a la parte de uso del eclipse no hay mucho que añadir, unicamente hay que tener cuidado en la configuración de los "external tools" (que nos ayudan a compilar, enlazar y enviar programas al robot desde eclipse). Aseguraos de rellenar bien los campos, y cuidado con VMware, parece que la versión 6.0 tiene algunos problemas a la hora de reconocer el robot.
En cuanto a la descarga de eclipse, solo es necesario acceder a la sección de descargas de la propia página de eclipse para conseguir la ultima versión. (Si introducís eclipse en la shell y lo descargáis del enlace recomendado obtendréis una versión anterior y que no se puede actualizar).
PRÁCTICAS:
CONTROL BÁSICO DEL MOTOR
Lo primero era enseñarle a Cigarro a moverse como Dios manda para lo que tuvimos que aprender a manejar los motores. Esta parte se divide en tres programas:
BASIC MOTOR 1:
Al pulsar el boton el motor conectado al puerto A empieza a girar. Button.waitForPress(); Motor.A.forward(); Cuando se pulsa el boton de nuevo el motor para. Button.waitForPress(); Motor.A.stop();
BASIC MOTOR 2:
Al pulsar el botón derecho el motor conectado al puerto A gira 45º a derecha, y viceversa con el botón izquierdo. Para ello hacemos uso de Motor.A.rotate() y Button.waitForPress().
BASIC MOTOR 3:
En este caso hay que obtener el mismo resultado que en el apartado anterior pero usando la funcion rotateTo(). Hay que tener en cuenta que la función rotateTo() gira hasta que la odometría del robot marca el ángulo pedido, es decir, que si la ejecutamos dos veces seguidas con el mismo ángulo, la segunda no producirá ningún cambio, ya que la odometría ya marca los grados solicitados. Por ello hay que usar la función resetTachoCount() para resetear la odometría.
VISUALIZACIÓN DE LA ODOMETRÍA DEL ROBOT:
En la solución de este problema mostramos por pantalla la odometría del motor B. El giro del motor lo consegimos con la función getTachoCount(). Para que los giros esten siempre comprendidos entre 0 y 360º acotamos el rango de valores haciendo uso de resetTachoCount() cada vez que se exceden estos valores.
CUADRADO DE CALIBRACIÓN DE MOVIMIENTO:
Al ejecutar la aplicación el robot realiza una trayectoria en forma de cuadrado. Las funciones necesarias para este apartado son navegador.travel() y navegador.steer(). Este apartado esta vinculado con el siguiente. Para poder realizar la matriz de covarianzas pusimos un rotulador al robot para que pintara sus trayectorias. Luego hay que anotar el error cometido en cada vuelta.
Como puede verse el cuadrado no es perfecto, trasteamos con los parámetros del constructor de la clase TachoPilot, variando un poco el ángulo de giro y reduciendo la velocidad pero de ninguna manera esto se solucionaba, no pasa nada, lo importante es tener salud. Como siempre se produce el mismo error, sobre todo en los giros, pensamos que podría fallar la rueda trasera giratoria así que mandamos a Cigarro a boxes para probar con varios tipos de ruedas fijas:
Tampoco sirvió de nada. Acabamos dándonos por vencidos y dejamos la que viene en el manual y es que en cuanto a ruedas al tío Lego no hay quien le tosa.
Por ello podemos concluir que este error en el giro es sistemático, y ante eso poco podemos hacer...
CÁLCULO DE LA MATRIZ DE COVARIANZAS:
Para hallar la matriz de covarianza no hay mas que seguir la fórmula indicada en el enunciado.
Nosotros hemos tomado como origen de coordenadas el punto (0,0). Tras realizar el experimento 10 veces, las coordenadas de llegada obtenidas han sido : (2.6,-3.4),(2.9,-3.1),(2.3,-2.6),(3.0,-2.8),(2.9,-3.6),(2.9,-3.9),(3.1,-3.8),(3.3,-2.8),(3.7,-3.1),(3.1,-3.1), por lo que la matriz de covarianzas ha quedado de la siguiente manera:
[ 1.276 -0.023 ] [ -0.023 1.756 ]
VISUALIZACIÓN DE LA TRAYECTORIA:
Aquí el reto es que, a medida que el robot se desplaza por el mundo, vaya dibujando su trayectoria en pantalla con escala píxel/cm. Este punto fue el más difícil de implementar ya que este trazado ha de ser en tiempo real. Al final, superándonos a nosotros mismos, lo hemos conseguido y puede mostrar todo tipo de pirueta que pueda realizar Cigarro. Ved el vídeo en el que traza el cuadrado del punto anterior en pantalla:
Quisimos ir más allá y probamos con una trayectoria curvilínea a ver si funcionaba igual de bien poniendo un humilde menú para elegir entre embos trayectos, el resultado nos dejó con las patas vueltas, véanlo:
(* Para resolver las dudas sobre los comando a utilizar recomendamos mirar el NXJ Tutorial. A nosotros nos ha sido de gran ayuda.)
Hoy hemos tenido la primera práctica con nuestro robot Lego mindstorms NXT. Se trataba solo de instalar el entorno de desarrollo leJOS y probar un par de aplicaciones.
En cuanto al desarrollo de la práctica en el ordenador del laboratorio no hemos tenido ningún problema. El leJOS NXJ 0.8.5 ya estaba instalado en los ordenadores, por lo que solo hemos tenido que seguir los pasos indicados en el enunciado para probar las aplicaciones HelloWorld, LCDUI, y por último nxjbrowse que permite gestionar los archivos del robot desde el ordenador de forma gráfica.
Si hablamos ahora de nuestro ordenador personal, aquí la cosa se complica. Aconsejamos antes de empezar echar un vistazo a su web y prestar especial atención a los prerrequisitos que se pueden encontrar en la sección tutorial y dependen de tu sistema operativo.
No es extraño que no se cumpla algún prerrequisito en nuestro caso, que vamos a instalarlo en una ubuntu, tuvimos que instalar varios paquetes que faltaban, estos son: ant, sun-java6-jdk, libusb-dev y libbluetooth-dev.
Una vez cumplidos los prerrequisitos ya podemos descargar el software desde aquí e instalarlo siguiendo las instrucciones. Y eso es todo, al menos en teoría ya que en nuestra ubuntu corriendo en VMware Player sobre un Windows XP a la hora de 'flashear' el firmware con nxjflash borraba el actual pero no instalaba el nuevo dejando el ladrillo en lo que se llama 'modo de actualización de firmware' en el que no se muestra nada en pantalla y se emite un 'click' periódicamente. La salida de nxjflash era la siguiente:
>: sudo nxjflash Building firmware image. VM file: /home/jmoral/lejos_nxj/bin/lejos_nxt_rom.bin Menu file: /home/jmoral/lejos_nxj/bin/StartUpText.bin VM size: 52752 bytes. Menu size: 38016 bytes. Total image size 91008/94208 bytes. Locating device in firmware update mode. Found NXT: %%NXT-SAMBA%% 1 an error occurred: Failed to open device in SAM-BA mode.
Como todos los pasos anteriores se habían ejecutado con éxito no conseguíamos averiguar el por qué del error que al final parece ser de cómo el VMware Player reconoce el ladrillo conectado por USB, actualizando el VMware a su versión Workstation el problema queda solucionado.