Fifth example: Trapped robot (NxtJLibA autonomous mode)
Purpose: Use the NXT brick as an autonomous rover with a light sensor. Move the rover on a black floor. Whenever the rover leaves the floor, move it back, so that it remains trapped on the black area forever.
The package NxtJLibA provides an addon to the leJOS NXJ library with a clean OOP design. Programs can be ported from the direct mode using the package NxtJLib with very little effort because the class design of NxJLibA and NxtJLib is the same, despite the implementations are very different: NxtJLibA uses the leJOS NXJ distribution extensively, while NxtJLib is independent of the leJOS iCommand distribution.
The program makes use of the light sensor's event method bright() that is triggered when the reflected light level exceeds the given trigger level. When the rover quits the black area, it moves back and turns, then it moves forward again.
// TrappedRobot.java
import ch.aplu.nxt.*;
import lejos.nxt.Button;
public class TrappedRobot implements LightListener
{
private final int triggerLevel = 525;
private Gear gear;
public TrappedRobot()
{
NxtRobot robot = new NxtRobot();
LightSensor ls = new LightSensor();
robot.addPart(ls);
ls.addLightListener(this, triggerLevel);
ls.activate(true);
gear = new Gear();
gear.setSpeed(30);
robot.addPart(gear);
gear.forward();
while (!Button.ESCAPE.isPressed()) {}
robot.exit();
}
public void bright(SensorPort port, int level)
{
gear.backward(500);
gear.left(500);
gear.forward();
}
public void dark(SensorPort port, int level)
{
}
public static void main(String[] args)
{
new TrappedRobot();
}
}
Discussion: In order to prevent the program to terminate when the constructors comes to the end, we let it loop until the Escape button is hit. All work is done by the event method that runs in its own thread.
If the program should be ported to the direct mode using NxtJLib, just replace
while (!Button.ESCAPE.isPressed()) {}
by
while (!QuitPane.quit()) {}
and change the related import from
import lejos.nxt.Button;
to
import ch.aplu.util.QuitPane;
(In order to compile, download and run the program, the leJOS NXJ programming environment has to be installed. After this, download the NxtJLibA package and follow the installation instructions.)
Sixth example: Bluetooth communication (NxtJLibA autonomous mode)
Purpose: A first NXT rover moves on a random path. It steers a second NXT rover that performs a similar movement.
The package NxtJLibA contains a class Transceiver that implements a Bluetooth transmitter-receiver in order to exchange information as pairs of integers. When "switched on", the transceiver searches the recipient's transceiver to establish the connection. If the search fails, it enters a listening mode and waits for the recipient's transceiver to connect. With this peer-to-peer concept, it is of no importance which NXT is switched on first.
The controlling robot is called master, the guided robot is called slave.
The code for the slave is quite simple because the incoming data from the master triggers an event callback method received() that gets the pair of integer sent by the master. The callback method notifyConnection() is called when the connection is established or lost. The interface Command defines the communication protocol.
// SlaveRobot.java
// Receive commands from MasterRobot
import ch.aplu.nxt.*;
import lejos.nxt.*;
public class SlaveRobot
implements TransceiverListener
{
private interface Command
{
int FORWARD = 1;
int BACKWARD = 2;
int LEFT = 3;
int RIGHT = 4;
int STOP = 5;
int SETSPEED = 6;
}
private final String recipient = "NXT";
private Gear gear;
private Transceiver tr;
public SlaveRobot()
{
NxtRobot robot = new NxtRobot();
gear = new Gear();
robot.addPart(gear);
gear.setSpeed(30);
tr = new Transceiver(recipient);
tr.addTransceiverListener(this);
robot.addPart(tr);
tr.switchOn(); // Blocks until connected
Tools.putSleep(); // Wait for termination
robot.exit();
}
public void received(int state, int value)
{
switch (state)
{
case Command.FORWARD:
gear.forward();
break;
case Command.BACKWARD:
gear.backward();
break;
case Command.LEFT:
gear.left();
break;
case Command.RIGHT:
gear.right();
break;
case Command.STOP:
gear.stop();
break;
case Command.SETSPEED:
gear.setSpeed(value);
break;
}
}
public void notifyConnection(boolean connected)
{
if (!connected)
Tools.wakeUp(); // Terminate program
}
public void isListening()
{}
public static void main(String[] args)
{
new SlaveRobot();
}
}
After switching on its transceiver, the master sends the commands to the slave using the method send() that takes a pair of integers. The rover moves on a polygon with random angles.
// MasterRobot.java
import ch.aplu.nxt.*;
import java.util.Random;
public class MasterRobot
{
private interface Command
{
int FORWARD = 1;
int BACKWARD = 2;
int LEFT = 3;
int RIGHT = 4;
int STOP = 5;
int SETSPEED = 6;
}
private final String recipient = "NXT5";
public MasterRobot()
{
NxtRobot robot = new NxtRobot();
Transceiver tr = new Transceiver(recipient);
robot.addPart(tr);
Gear gear = new Gear();
robot.addPart(gear);
tr.switchOn(); // Blocks until connected
tr.send(Command.SETSPEED, 30);
gear.setSpeed(30);
Random rnd = new Random();
for (int i = 0; i < 5; i++)
{
tr.send(Command.FORWARD, 0);
gear.forward(3000);
int turnTime = 100 + rnd.nextInt(700);
tr.send(Command.LEFT, 0);
gear.left(turnTime);
}
tr.send(Command.STOP, 0);
gear.stop();
robot.exit();
}
public static void main(String[] args)
{
new MasterRobot();
}
}
Discussion: The constructor's thread is put in a wait state by calling Tools.putSleep(). When the master closes the Bluetooth communication, notifyConnection(false) is invoked and Tools.wakeUp() notifies the waiting thread to continue. Do not forget to call exit() to release all resources.
As stated before, you do not have to care whether the master or the slave program is started first. But when one of them is started, you must wait for about 5 seconds to start the other, because during this time each program searches mutually for a waiting recipient.
|