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
{
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();
}
}