martes, 9 de noviembre de 2010

Mindstorms NXT - LeJOS (Seguir una línea negra)

El objetivo de este ejercicio consiste en programar al robot, para que utilizando el sensor de luz, pueda encontrar, y seguir una trayectoria marcada con una línea negra, pintada sobre una superficie plana.


Se muestra a continuación un par de fotografías que ilustran el modelo de robot utilizado, para la resolución del problema:



La siguiente fotografía corresponde a la trayectoria (marcada por una línea negra) a seguir por el robot:


Solución

En general, para los cuatro ejercicios presentados, como parte de la práctica, se utilizó para programar al robot, una arquitectura conocida como: “subsumption architecture”, la cual consiste básicamente en una arquitectura para robots reactivos, altamente asociada con robótica basada en comportamientos.

En la arquitectura mencionada, se descompone comportamiento inteligente en varios módulos “simples” de comportamiento, los cuales son organizados en capas. Cada capa implementa una meta en particular del agente, y capas más altas, son incrementalmente abstractas. La meta de cada capa subsume la de capas que se encuentran por debajo de ésta. En el caso preciso de este ejercicio la capa más baja representa el estar “fuera de la línea”, donde el robot al encontrarse en esta situación, comienza a hacer giros incrementales, de izquierda a derecha, hasta que se encuentra con una línea negra; es en este momento, que toma control la capa más elevada, y que básicamente se encarga de mover al robot hacia delante, mientras lo que el sensor de luz “vea”, sea una línea negra.

El código para lograr lo anterior, se encuentra divido en tres clases: LineFollower.java, OutOfLine.java, y DriveForward.java. La primera de ellas actúa básicamente como un regulador, para decidir qué comportamientos deben ser activados, mientras que las otras dos, aluden a los comportamientos descritos en el párrafo anterior, de manera correspondiente.

Se muestra a continuación el código de cada una de las tres clases:

LineFollower.java
import lejos.nxt.*;
import lejos.robotics.navigation.*;
import lejos.robotics.subsumption.*;

public class LineFollower {
 
 public static void main(String[] args){
  Pilot pilot = new TachoPilot(5.6f, 11.25f, Motor.A, Motor.C);
  LightSensor light = new LightSensor(SensorPort.S3);
  pilot.setTurnSpeed(180);
  
  Behavior b1 = new OutOfLine(pilot, light);
  Behavior b2 = new DriveForward(pilot, light);
  Behavior [] behaviorArray = {b1, b2};
  Arbitrator arbitrator = new Arbitrator(behaviorArray);
  
  LCD.drawString("Line Follower", 2, 2);
  Button.waitForPress();
  arbitrator.start();
 }

}

OutOfLine.java

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

public class OutOfLine implements Behavior, SensorPortListener{

 private Pilot pilot;
 private LightSensor light;
 private int sweep;
 private boolean suppress;
 private boolean outOfBlackLine;

 public OutOfLine(Pilot pilot, LightSensor light){
  this.pilot = pilot;
  this.light = light;
  suppress = false;
  outOfBlackLine = false;
  SensorPort.S3.addSensorPortListener(this);
 }

 public void stateChanged(SensorPort port, int oldValue, int newValue){
  if(light.readValue() > 35)
   outOfBlackLine = true;
 }

 public boolean takeControl(){
  if(outOfBlackLine){
   LCD.clear();
   LCD.drawString("OutOfLine", 2, 2);
   outOfBlackLine = false;
   return true;
  } else
   return false;
 }

 public void suppress(){
  suppress = true;
 }

 public void action(){
  sweep = 10;
  while(!suppress){
   pilot.rotate(sweep, true);
   while(!suppress && pilot.isMoving())
    Thread.yield();
   sweep*=-2;
  }
  pilot.stop();
  suppress = false;
 }
}

DriveForward.java

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

public class DriveForward implements Behavior, SensorPortListener{
 
 private Pilot pilot;
 private LightSensor light;
 private boolean seenBlackLine;
 
 public DriveForward(Pilot pilot, LightSensor light){
  this.pilot = pilot;
  this.light = light;
  seenBlackLine = false;
  SensorPort.S3.addSensorPortListener(this);
 }
 
 public void stateChanged(SensorPort port, int oldValue, int newValue){
  if(light.readValue() <= 35)
   seenBlackLine = true;  
 }
 
 public boolean takeControl(){
  if(seenBlackLine){
   LCD.clear();
   LCD.drawString("DriveForward", 2, 2);
   seenBlackLine = false;
   return true;
  } else
   return false;
 }
 
 public void suppress(){
  pilot.stop();
 }
 
 public void action(){
  pilot.forward();
  while(light.readValue() <= 35)
   Thread.yield();
 }

}

Finalmente, se adjunta un video, donde se puede apreciar al robot ejecutando la tarea encomendada, en la pista anteriormente mostrada:


No hay comentarios:

Publicar un comentario