Manejo de tareas en LeJOS: clase Arbitrator

arbitroEn el los artículos Control de tareas en RobotC y Control de prioridades de tareas en RobotC vimos como manejar tareas en RobotC. En este artículo vamos a ver el manejo de tareas en LeJOS: clase Arbitrator. La mejor forma de manejar las tareas y sus prioridades en LeJOS es mediante la clase Arbitrator. Este método consiste en crear unas tareas denominadas comportamientos, no muy complejas, que en su conjunto crearán el programa que deseemos implementar.

Modelo de programacion basado en comportamientos:

Los programas que hemos escrito en nuestro robot presentan la apariencia habitual de un modelo de programacion estructurado. El flujo de ejecucion comienza en un punto y se van sucediendo instrucciones que modi can los actuadores de nuestro robot. En artículos anteriores hemos aprendido a crear nuevos threads y permitir que haya varios flujos de ejecucion en paralelo. A medida que la dificultad de la tarea a realizar aumenta, el codigo se vuelve cada vez mas complejo y difícil de escalar.

Un modelo de programacion basado en comportamientos permite simpli car el diseño de nuestros programas. Ahora nuestro codigo estara compuesto de varios comportamientos. Los comportamientos son tasks (tareas) relativamente simples e independientes, es decir, no necesitan de otros comportamientos para su ejecucion: Avanzar, esquivar obstaculo, coger pelota, rotar 360 grados, encender leds, etc. Una vez de finidos los comportamientos tendremos que establecer una política de activación de los mismos. Por ejemplo podríamos tener un automata de estados finitos que activara uno o varios comportamientos según las necesidades del robot.

Otra alternativa es utilizar un arbitro que se encargue de elegir el comportamiento mas adecuado para cada momento en funcion de algun criterio. LeJOS dispone de un paquete llamado lejos.subsumption que permite programar nuestra aplicacion bajo este paradigma. Cada uno de nuestros comportamientos debera escribirse en una clase Java e implementar el interfaz Behavior. Este interfaz obliga a implementar tres métodos:

public boolean takeControl(): Metodo que indicará si este comportamiento deberá activarse en este momento o no. Por ejemplo, si nuestro comportamiento se encarga de esquivar un obstaculo, su funcion takeControl() deberá devolver true cuando haya un obstaculo cerca del robot.

public void action(): Método que se ejecutará cuando se active el comportamiento.Por tanto deberá contener todas las instrucciones que desempeñaran la labor para la que ha sido creado el comportamiento.

public void suppress(): Metodo que se ejecutara cuando se desactive el comportamiento. Si es necesario devolver el robot a un determinado estado, aquí sera el sitio para hacerlo. Un comportamiento será desactivado cuando otro comportamiento tome el control en su lugar.

Clase Arbitrator y prioridades de los comportamientos:

Una vez creados nuestros comportamientos deberemos crear un objeto de tipo Arbitrator, que se encargará de activar y desactivar los comportamientos. El constructor de Arbitrator acepta como parametro un array de comportamientos (en el programa de ejemplo podéis como hacerlo). Todos estos comportamientos serán los candidatos a activarse durante la ejecución del programa.

Cuando se ejecute el método start() de nuestro objeto de tipo Arbitrator se pondrá en marcha el arbitro que activa la ejecucion de los comportamientos. La poltica que se utiliza es una poltica de prioridades (tasks con prioridades). Tienen mayor prioridad aquellos comportamientos cuyo índice del array sea mayor. El arbitro recorrera el array de comportamientos desde el fi nal hasta el comportamiento que ocupe la posicion 0 y ejecutará el metodo takeControl() de cada comportamiento. Si alguno de esos metodos devuelve true, se ejecutará una iteracion de ese comportamiento llamando a su metodo action().

Este arbitro se encargará contnuamente de evaluar que comportamiento es el que hay que ejecutar. En caso de que otro comportamiento distinto al actual tenga que ser ejecutado, se llamará el método supress() del comportamiento actual y despues el método action() del nuevo comportamiento.

Programa de ejemplo:

Como programa de ejemplo hemos puesto un clásico, el Bump&Go. Es un ejemplo sencillo, así que podréis comprender mejor como funciona la clase Arbitrator. En este caso tenemos dos comportamientos: Avanza y Esquiva. Uno se encargará de ir en línea recta, y el otro de esquivar cuando detecte un obstáculo. Por último el Arbitro se encargará de gestionarlo todo.

Bump&Go2

Cada comportamiento va en una clase distinta, y el Arbitro también, por lo que tendremos tres archivos (con una clase cada uno). Uno será el de la clase Avanza:

import lejos.robotics.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.forward();
Motor.C.forward();
}
}

Otro el de la clase Esquiva:

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

public class Esquiva implements Behavior {

public TouchSensor touch = new TouchSensor(SensorPort.S1);

public boolean takeControl() {
return touch.isPressed();
}

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

public void action() {
Motor.A.backward();
Motor.C.backward();
try{
Thread.sleep(500);
}catch(Exception e) {}

Motor.A.stop();
try{
Thread.sleep(500);
}catch(Exception e) {}
Motor.C.stop();
}
}

Y finalmente el de la clase Bump&Go, que es el arbitro:

import lejos.robotics.subsumption.*;

public class BumpAndGo {

public static void main(String [] args) {
Behavior b1 = new Avanza();
Behavior b2 = new Esquiva();
Behavior [] bArray = {b1, b2};
Arbitrator arby = new Arbitrator(bArray);
arby.start();
}
}

Esta es una manera muy cómoda de gestionar tareas, amén de que facilita mucho la programación de programas complejos dividiéndolos en tareas. Si tenéis alguna duda, os recomiendo que os paséis por el foro y preguntéis.

Comments are closed.