Tal y como vimos en el artículo de RobotC Vehículos de Braitenberg en RobotC los vehículos de Braitenberg fueron concebidos por el investigador Italo-Autriaco Valentino Braitenberg para ilustrar de manera evolutiva las habilidades de agentes simples. En el artículo de hoy implementaré un par de comportamientos de vehículos de Braitenberg en LeJOS.
Repaso a los ejemplos de vehículos de Braitenberg:
Repetiré aquí los ejemplos más claros y sencillos de vehículos de Braitenberg :
Un primer agente tiene un sensor detector de luz que estimula directamente a su única rueda, implementado las siguientes reglas:
- Más luz produce un movimiento más rápido.
- Menos luz produce un movimiento más lento.
- La oscuridad produce que se quede quieto.
Este comportamiento puede ser interpretado como una criatura que teme a la luz y que se mueve rápido para salir de ella. Su objetivo es encontrar un hueco oscuro en el que ocultarse.
Un segundo agente algo más complicado tiene dos sensores de luz (izquierdo y derecho), cada uno estimulando a la rueda de su mismo lado. Obedece las siguientes reglas:
- Más luz en la derecha → la rueda derecha gira más rapido → gira hacia la izquierda, fuera de la luz.
- Más luz en la izquierda → la rueda izquierda gira más rapido → gira hacia la derecha, fuera de la luz.
Este es más eficiente como un comportamiento para escapar de la fuente de luz, ya que la criatura puede moverse en diferentes direcciones, y tiene a orientarse hacia la dirección desde la que procede menos luz.
En otra variación las conexiones son negativas o innovadoras:
- Más luz en la derecha → la rueda derecha gira más lento → gira hacia la derecha, hacia la luz.
- Más luz en la izquierda → la rueda izquierda gira más lento → gira hacia la izquierda, hacia la luz.
En este caso el agente huye de la oscuridad, moviéndose hacia la luz.
Configuración de motor y sensores de luz:
Aunque hasta ahora hemos estado usando los motores en LeJOS de la manera genérica (accediendo al atributo A, B, o C de la clase Motor), es posible definir los motores con el nombre que elijamos, los cual nos facilitará las cosas a la hora de manejarlos. Para ello usaremos el método constructor de la clase de objetos Motor. Esto se hace de la siguiente manera:
Motor nombre_motor = new Motor(MotorPort.puerto): Creamos un objeto de la clase Motor, cuyo su nombre será el indicado, y que estará anclado al puerto que hayamos elegido(A, B o C).
Respecto a los sensores de luz es importante decir que cuando se declaran (tal y como vimos en el artículo 6 de la serie LeJOS) están en modo activo (con el LED encendido. En estos programas no nos interesa que tengan el LED encendido, ya que nos interfiere a la hora de captar la luz ambiente. Para activarlo o desactivarlo existe el siguiente método de la clase LightSensor:
void setFloodlight(boolean encender): Enciende el LED en caso de que encender sea true, y lo apaga en caso de que encender sea false.
Con estos dos apuntes ya podemos programar nuestro vehículo de Braitenberg.
Vehículo de Braitenberg en LeJOS:
Como ya habréis supuesto los vehículos de Braitenberg no son problemas muy complejos de resolver con LeJOS. En este caso vamos a implementar el segundo comportamiento:
- Más luz en la derecha → la rueda derecha gira más rapido → gira hacia la izquierda, fuera de la luz.
- Más luz en la izquierda → la rueda izquierda gira más rapido → gira hacia la derecha, fuera de la luz.
Por tanto será un robot estilo cucaracha, que huye de la luz y se refugia en la oscuridad. Necesitaremos construir el robot con dos sensores de luz y dos motores. Es importante que los sensores de luz miren más o menos hacia los lados y no hacia adelante, o no podremos medir bien la cantidad de luz que proviene de cada lado. Con un ángulo de 45º es suficiente, como el robot que hemos construido nosotros:
A la hora de configurar los sensores de luz es importante que los pongáis en modo pasivo como os indiqué en el apartado anterior del artículo, para que la luz del LED no nos entorpezca en nuestro cometido. Ponedle nombres intuitivos a los motores y a los sensores, como motorDerecho, sensorIzquierdo… Así se os hará mucho más fácil programarlos, y ver qué es lo que falla en caso de problemas. El código del programa sería así:
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.LightSensor;
import lejos.nxt.Motor;
import lejos.nxt.MotorPort;
import lejos.nxt.SensorPort;
public class Braitenberg {
public static void main(String[] args) {
LightSensor sluzizq = new LightSensor(SensorPort.S4);
LightSensor sluzder = new LightSensor(SensorPort.S1);
Motor motorizq = new Motor(MotorPort.C);
Motor motorder = new Motor(MotorPort.A);
int umbral = 18;
sluzizq.setFloodlight(false);
sluzder.setFloodlight(false);
motorizq.forward();
motorder.forward();
LCD.drawString(“Valor de sluzizq:”, 0, 1);
LCD.drawString(“Valor de sluzder:”, 0, 5);
while(!Button.ESCAPE.isPressed()){
LCD.drawInt(sluzizq.readValue(), 5, 3);
LCD.drawInt(sluzder.readValue(), 5, 7);
if (sluzder.readValue() > umbral){
motorder.setSpeed((sluzder.readValue()*sluzder.readValue()) – 200);
} else{
motorder.setSpeed(0);
}
if (sluzizq.readValue() > umbral){
motorizq.setSpeed((sluzizq.readValue()*sluzizq.readValue()) – 200);
} else{
motorizq.setSpeed(0);
}
}
}
}
Una pequeña explicación de algunas líneas:
8 – Aquí definimos un valor umbral de oscuridad, para el que creamos que nuestro robot-cucaracha está en un sitio suficientemente oscuro como para sentirse seguro y pararse. Este valor lo usaremos posteriormente en las líneas28 y 33.
18 y 19 – Recordad apagar los LED.
29 y 34 – Pondremos que la velocidad de los motores sea directamente proporcional a la cantidad de luz que recibimos, tal y como dice Braitenberg. En este caso será igual al cuadrado del valor leído menos un número que elijamos nosotros para moderar la velocidad, por ejemplo 200 o 300.
Y aquí tenéis este vídeo que nos ha quedado bastante chulo:
Ante cualquier duda podéis visitar el foro.