Aegidius
 Plüss   Aplulogo
     
 www.aplu.ch      Print Text 
© 2021, V10.4
 
  NxtLib
 
 

 

First example: Border Follower (NxtJLib for J2SE)

Purpose: The NXT rover (standard model with two motors) equipped with a light sensor that distinguishes between a white and a black floor advances along a white-to-black border. The rover moves on a wiggly line and changes from a left to a right curve when the sensor 'sees' the black offshore region.

First you should check the light levels when the sensor detects the the white or back floor. This is very easy, just execute ReadLightSensor.java:

// ReadLightSensor.java

import
 ch.aplu.nxt.*;
import
 ch.aplu.util.*;

public
 class ReadLightSensor
{
  
private final int period = 1000;  // ms

  
public ReadLightSensor()
  
{
    NxtRobot robot 
= new NxtRobot();
    LightSensor ls 
= new LightSensor(SensorPort.S1);
    robot.
addPart(ls);
    Console.
init();
    
System.out.println("LightSensor getValue() returns:");

    
int time = 0;
    
while (!QuitPane.quit())
    
{
      
System.out.println("On " + time/1000 + " s: " + ls.getValue());
      Tools.
delay(period);
      time 
+= period;
    
}
    robot.
exit();
  
}

  
public static void main(String[] args)
  
{
    
new ReadLightSensor();
  
}
}


 Execute ReadLightSensor using WebStart (NXT brick with leJOS firmware needed.

QuitPane is a simple but useful class to display a modeless dialog with a quit button. quit() shows the dialog, when it is not yet shown and returns true, when the button is hit.

Now we put the robot on the white and black floor and take an average value as trigger level, in our case 400. Using the class Gear, it is quite simple to write BorderFolloer.java:

// BorderFollower.java

import ch.aplu.nxt.*;
import ch.aplu.util.*;

public class BorderFollower implements LightListener
{
  private final int triggerLevel = 400;
  private Gear gear;
 
  public BorderFollower()
  {
    NxtRobot robot = new NxtRobot();

    LightSensor ls = new LightSensor(SensorPort.S1);
    robot.addPart(ls);
    ls.addLightListener(this, triggerLevel);

    gear = new Gear();
    gear.setSpeed(20);
    robot.addPart(gear);
    gear.forward();
  
    while (!QuitPane.quit());
    robot.exit();
  }
   
  public void bright(SensorPort port, int level)
  {
    gear.leftArc(0.2);
  }  
  
  public void dark(SensorPort port, int level)
  { 
    gear.rightArc(0.2);
  } 
    
  public static void main(String[] args)
  {
    new BorderFollower();
  }
}

   

Execute BorderFollower using WebStart (NXT brick with leJOS firmware needed.


Discussion: We use the Java Event Model and register a LightListener. Because BorderFollower implements a LightListener, addLightListener() is called with the parameter this. Whenever the given trigger level is crossed from dark to bright, the callback method bright() is invoked, whenever the trigger level is crossed from bright to dark, the callback method dark() is invoked. Evidently the event-based program is quite different (and is more elegant) as a program where the light sensor is constantly polled using getValue().

 

Second example: Light Barrier (NxtJLib for J2SE)

Purpose: A NXT brick with a light sensor is used to construct a light barrier. A pocket lamp placed some distance from the brick illuminates the sensor. Whenever the light is dimed due to the passage of an object, a bright-to-dark event is triggered and a dimout counter increased. It is typical for an object-oriented design to model the light barrier by a class LightBarrier that isolates the internal mechanism of the device from the application program. Because a LightBarrier is a special kind of a NxtRobot, the class LightBarrier is derived from NxtRobot. This is a very simple and obvious use of a class hierarchy with the following class diagram:

   

// LightBarrier.java

import ch.aplu.nxt.*;

public class LightBarrier extends NxtRobot
  implements LightListener
{
  private LightSensor ls;
  private int dimouts = 0;

  public LightBarrier()
  {
    ls = new LightSensor(SensorPort.S1);
    addPart(ls);
    ls.addLightListener(this, 400);
    ls.activate(false);
  }

  public void bright(SensorPort port
, int level)
  {
    ls.activate(true);
  }

  public void dark(SensorPort port, int level)
  {
    ls.activate(false);
    dimouts++;
    System.out.println("nb of dimouts: " + dimouts);
    Tools.delay(2000);  // Inhibit for a while
  }

  public int getDimouts()
  {
    return dimouts;
  }
}

We use the light barrier to count the revolutions of a NXT rover turning on a circle and to stop it, when the number of revolutions is 3. This is a very simple situation, where two NXT bricks are used at the same time.

// LightBarrierApp.java

import ch.aplu.nxt.*;
import ch.aplu.util.*;

public class LightBar
{
  public LightBarrierApp()
  {
    LightBarrier lb = new LightBarrier();

    NxtRobot robot = new NxtRobot();
    Gear gear = new Gear();
    robot.addPart(gear);
    gear.leftArc(0.3);

    boolean isRunning = true;
    while (!QuitPane.quit())
    {
      if (lb.getDimouts() == 3 && isRunning)
      {  
        gear.stop();
        isRunning = false;
      }
    }  
    lb.disconnect();
    robot.exit();
  }

  public static void main(String[] args)
  {
    new LightBarrierApp();
  }
}

   

Execute LightBarrierApp using WebStart (NXT brick with leJOS firmware needed.


Discussion: To get a feedback of the correct functioning of the light barrier, activate() turns the sensor LED on, when light is detected and off, when it is dimed. The application polls the LightSensor's getDimouts() and stops the gear, when 3 is returned. The boolean flag isRunning assures that the stop() command is only sent once.

If you have always the same NXT bricks, it is convenient to use the NxtRobot(String btName) constructor to avoid the annoying question for the Bluetooth friendly name.

Be careful that disconnect() is called for both NxtRobots. We use disconnect() for the LightSensor and exit() for the NxtRobot, which invokes disconnect() and System.exit(0), in order to terminate the program.

In a somewhat more elegant design, LightSensor could be expanded to generate a callback when a certain dimout count is reached. Consider it a challenge to do it yourself.