jueves, 26 de marzo de 2009

Siguiendo lineas

Esta práctica ha sido con toda seguridad la más difícil hasta ahora.

Se trata de seguir una línea negra sobre fondo blanco, hasta ahí bien. El problema es utilizar los comportamientos de leJos.
Desde un principio pensamos que lo mejor sería utilizar dos comportamientos:
1. Avanzar, siempre takeControl siempre devuelve verdadero. Lo único que hace es poner la velocidad adecuada y avanzar. Al salir detiene los motores.
2. Girar, takeControl devuelve verdadero cuando detecta blanco en el sensor. En la clase principal lo hemos calibrado, 0->negro, 100->blanco. Como sabemos que varía un poco, le pusimos verdadero siempre que detecta más de 80.
Lo que hace es girar 10º a un lado y a otro, 20º después, 30º, 40º, ... de esta forma encontramos el más cercano. Como normalmente estará cerca, no perderemos demasiado tiempo. Al salir detiene los motores.

La implementación fue sencilla, pero llegaron los problemas. Aún seguimos sin saber por qué, pero una vez que se metía en un comportamiento, y a pesar de que el arbitro sabía que debía darle el control a otro (eso indicaban los takeControl), nunca cambiaba. De esta forma, como calibramos primero el blanco y luego el negro, simplemente avanzaba como si no hubiera un mañana.
Para nuestra desesperación, a pesar de las multiples trazas, lo único que hacía que cambiase el control era poner sleeps después de las ejecuciones. Eso nos daba un plazo (de la misma duración que el sleep) para cambiar. Si se pasaba ese plazo, vuelta a lo de antes.

Como último intento, copia&pega&colorea del ejemplo del enunciado. Lo copiamos, funcionaba, y lo retocamos para que se comportase para seguir líneas (copiar&pegar del proyecto anterior) y... sorpresa!! FUNCIONA!! Estuvimos planteándonos colgar los dos códigos y ofrecer una recompensa por encontrar las 7 diferencias, pero si son iguales!!

Ahora ya sólo quedaba resolver algún problemilla, y es que de vez en cuando, el robot se paraba al salir de la línea, y sólo continuaba si volvías a meterlo. Unas trazas y pruebas más tarde, descubrimos el problema.
Para realizar la acción de girar, se giraba con steer, retornando inmediatamente, y para conseguir parar si encontraba negro, nos metíamos en un bucle con un sleep. El bucle sólo finalizaba al encontrar negro o cuando la rueda dejaba de moverse.
El problema era que si se ponía a girar, e inmediatamente encontraba negro, se ejecutaba alguna instrucción de las de parada (en los supress) y detenía las ruedas. Sin embargo, hasta que no termina la acción de girar, no ejecuta la acción de avanzar, y esta nunca termina porque sorprendetemente, ismoving seguía retornando verdadero, y como la luz no cambia, ahí se queda.

Tuvimos que rediseñarlo completamente para eliminar estos sleep, y ahora gira de 5º en 5º y comprueba la luz.





Como no podemos subir archivos, escribo aquí el código utilizado:

import lejos.nxt.*;
import lejos.subsumption.*;

public class SeguirLineas
{
public static void main(String [] args) {

LightSensor LuzP3 = new LightSensor (SensorPort.S3);

LuzP3.setFloodlight(true);

LCD.clear();
LCD.drawString("Calibrar",3,4);
LCD.drawString("alto",5,6);
Button.waitForPress();
LuzP3.calibrateHigh();

LCD.clear();
LCD.drawString("Calibrar",3,4);
LCD.drawString("bajo",5,6);
Button.waitForPress();
LuzP3.calibrateLow();


Behavior b1 = new Avanza();
Behavior b2 = new Gira(LuzP3);
Behavior [] bArray = {b1, b2};
Arbitrator arby = new Arbitrator(bArray);
arby.start();
}
}



import lejos.subsumption.*;
import lejos.nxt.*;
import lejos.navigation.*;

public class Gira implements Behavior
{
public LightSensor luz;
private Pilot navigator = new Pilot(5.6f, 11.25f, Motor.A, Motor.C);

public Uno (LightSensor sensor)
{
luz=sensor;
}

public boolean takeControl() {
//Consideramos blanco más de un 80% de luz (sobre lo calibrado)
LCD.clear();
LCD.drawInt(luz.readValue(), 3, 4);
if (luz.readValue()>80)
LCD.drawString("true", 3, 6);
else
LCD.drawString("false", 3, 6);

return (luz.readValue()>80);
}
public void suppress() {
navigator.stop();
}

public void action() {
navigator.stop();
navigator.setSpeed(180);

for (int i=10; i<180>=20; i=i+10)
{
MoverPeroParar ( 2*i-10);

if (luz.readValue()>=20)
{
MoverPeroParar (-2*i);

}
}

navigator.stop();
}

private void MoverPeroParar (int cantidad)
{
int contador=0;

if (cantidad>0)
{
while (luz.readValue()>=20 && contador=20 && contador>cantidad)
{
contador = contador-5;
navigator.steer(200,-5,true);
try {Thread.sleep(20);} catch (Exception e) {}
}
}
}

}


import lejos.subsumption.*;
import lejos.nxt.*;

public class Avanza implements Behavior
{
public boolean takeControl()
{
return true;
}

public void suppress() {
Motor.A.stop();
Motor.C.stop();
}

public void action() {
Motor.A.setSpeed(360);
Motor.C.setSpeed(360);
Motor.A.forward();
Motor.C.forward();
}

}

miércoles, 25 de marzo de 2009

Practica Opcional: Proyectos en la red

Hoy hemos estado buscando distintos proyectos en internet sobre el robot Lego. El que más nos ha sorprendido ha sido un robot que era capaz de resolver un cubo de rubik en menos de un minuto!
El creador de este proyecto es Daniele Benedettelli un ingeniero industrial italiano.
Lo más curioso de este robot es que usa muy pocas piezas, algunos datos técnicos que hemos encontrado han sido los siguientes:
- Un servomotor actúa de junta prismática que empuja el lado del cubo
- Un servomotor rota la plataforma giratoria del robot
- Un servomotor tiene una doble función para ayudar el brazo empujador a acomodar el brazo en el soporte y para sujetar el cubo mientras la base inferior rotatoria gira.
- Dos sensores de contacto como detectores de límite de los brazos
- Un sensor de luz para encontrar la posición inicial de la base rotatoria.

Pero mejor verlo vosotros mismos:

Esquivando con multihilo

Esta práctica consiste en usar dos threads distintos para que el robot esquive objetos de una forma simple.

Tenemos un hilo para cada rueda. La derecha siempre está avanzando, mientras que la izquierda detecta si hay un objeto a menos de 50 cm (30 de Bender) del sensor de ultrasonidos utilizado. En ese caso detiene la rueda durante 200 ms. En caso contrario avanza.

De esta forma Bender girará a la izquierda siempre que encuentre un objeto a menos de 30 cm.


lunes, 23 de marzo de 2009

Un día en el campo

Hoy Bender se ha dado una vueltecita por el campo.



Ha jugado con la fauna de la zona...


y ha comprobado que no es un robot del campo:


Recorrido en ocho

Para esta práctica Bender debía hacer un recorrido en forma de ocho utilizando la clase Pilot.
Lo que no nos quedo muy claro es si tenía que recorrer 1 metro en forma de ocho, o sí debía recorrer un metro recto, hacer un lazo, recorrer otro metro, y hacer el otro lazo. Así que lo hicimos de las dos formas, así no hay confusión.

Lo más difícil en esta práctica eran los lazos. Empezando por el ocho corto, debía recorrer en los 360º, 50 cm. Sin embargo no tenemos ninguna forma explícita de saber eso. Hicimos una prueba utilizando steer, y con un cálculo un poco a ojo, conseguimos que recorriera 52 cm.



Para el ocho largo era más complicado, porque al recorrer más distancia, debía estar más ajustado. El recorrido sería avanzar 1 metro, girar 270º (tres cuartos), avanzar otro metro, y volver a girar otros 270º en el sentido contrario. Calculamos cuanto debía recorrer en esos 270º->235.62. Finalmente recorre 239 y acaba prácticamente en el mismo sitio desde el que partió.

jueves, 12 de marzo de 2009

Buscando "La Luz"

Bender ha abierto un poco los ojos y ahora es capaz de distinguir la luz y la oscuridad. Tanto le ha gustado este nuevo sentido, que la busca ansiosamente.

Comienza a caminar, y si encuentra un salto un poco brusco, y detecta menos luz, dará un paso atrás y se girara hacia cualquier lado una cantidad aleatoria, si en ese nuevo lugar hay aún menos luz que antes, volverá a girar, así hasta que encuentre más luz que en el último giro.

Pero eso no es todo. Si después de un rato avanzando nota que pierde demasiada luz, se dará media vuelta por donde ha venido.

Observémoslo:

viernes, 6 de marzo de 2009

Práctica 2: El rebotador

¡BENDER QUIERE SER LIBRE!

Pero antes necesita aprender algunas cosas...



Caca... por las paredes no se sube



¡Así sí!

Práctica 1: Enséñamelo todo

Este es Bender algo más funcional, de momento ya se mueve con sus tres motores.
Tiene tres opciones, rotar 45º las ruedas hacia adelante, moverse continuamente adelante, o moverse continuamente atrás. El botón escape sale del programa. Para parar sin salir, en este caso hay que rotar.
Además Bender nos enseña lo que está haciendo en cada momento mediante mensajes en la pantalla.

¡Cuidado que se escapa!