Communications
leJOS NXJ supports communications using Bluetooth and
USB. The NXJ communications classes are designed so that most of your
code is independent of whether you are using Bluetooth or USB – you can
write applications that work with both (see the example below).
And you can use Java streams, which are a very flexible and easy to use.
USB has the advantage of speed, but the cable
can be used only to connect a NXT to a PC. Bluetooth is slower, but
much flexible. It supports a multitude of methods of communicating NXT
to NXT, PC to NXT, Mobile phone to NXT, NXT to remote Bluetooth device,
etc.
The first step in communicating is to establish a connection.
A connection has an initiator and a receiver.
The receiver waits for a connection from the initiator.
The initiator connects to a specific device that must be waiting for a connection.
When the connection has been established, both ends of the connection can use it to
open input and output streams and read and write data.
In this tutorial we do not deal with the case where the NXT is an
initiator and the PC is a receiver, although this is possible for Bluetooth connections.
In most cases of PC to NXT or mobile phone to NXT communications,
it is more convenient for the NXT to be the receiver and the PC the initiator.
The initiator program may run on a PC (always for USB), another NXT,
a mobile phone or another device that supports the Bluetooth Serial Port Profile (SPP).
Some external devices, such as GPS Bluetooth devices only act as a receiver, so when
communicating with these devices, the NXT must act as the initiator. Note that such external
devices must implement SPP - this is the only profile that the NXT supports.
Receiver
A receiver program on the NXT waits for a connection by calling the waitForConnection()
method in the Bluetooth or USB class. These are:-
Even though the Bluetooth class returns a BTconnection object, and the USB class
returns a USBConnection object, both of classes implement the
NXTConnectiion interface. So an object of either class can be assigned
to an reference variable that implements that interface.
Bluetooth Example:
NXTConnection connection = Bluetooth.waitForConnection();
You need to ensure that Bluetooth power and
visibility are on before calling this method. The leJOS NXJ start-up
menu can be used to do this.
USB Example:
NXTConnection connection = USB.waitForConnection();
You need to ensure that the USB cable is connected before calling this method.
Here is an example program that selects between USB and Bluetooth at run time:
import lejos.nxt.*;
import lejos.nxt.comm.*;
import java.io.*;
/**
* sample of selecting channel at run time
*/
public class CommTest
{
public static void main( String[] args) {
LCD.drawString("right BT",0, 0);
NXTConnection connection = null;
if(Button.waitForPress() == 4){
LCD.drawString("waiting for BT", 0,1 );
connection = Bluetooth.waitForConnection();
} else {
LCD.drawString("waiting for USB", 0,1 );
connection = USB.waitForConnection();
}
DataOutputStream dataOut = connection.openDataOutputStream();
try {dataOut.writeInt(1234);}
catch (IOException e ) {System.out.println(" write error "+e);}
}
}
}
Back to top
Streams
Once a connection has been established, streams can then be opened by calling any of the following
methods in the NXTConnection interface:
-
InputStream openInputStream() throws IOException;
-
OutputStream openOutputStream() throws IOException;
-
DataInputStream openDataInputStream() throws IOException; (the example above did this)
-
DataOutputStream openDataOutputStream() throws IOException;
Data items can then be read from the DataInputStream by:
-
int read(byte b[]) throws IOException
-
int read(byte b[], int off, int len)throws IOException
-
boolean readBoolean() throws IOException
-
byte readByte() throws IOException
-
short readShort() throws IOException
-
readInt() throws IOException
-
char readChar() throws IOException
-
float readFloat() throws IOException
-
String readLine() throws IOException
Be aware: The stream read
methods are blocking – that is, they do not return until data is read.
If your program has other tasks that need attending to while waiting
for data, calls to the read methods should be made in a separate
thread.
Data can be written to the DataOutputStream by:
-
void write(byte b[], int off, int len) throws IOException
-
void writeBoolean(boolean v) throws IOException
-
void writeByte(int v) throws IOException
-
void writeShort(int v) throws IOException
-
void writeChar(int v) throws IOException
-
void writeInt(int v) throws IOException
-
void writeFloat(float v) throws IOException;
-
void writeChars (String value) throws IOException
Example of reading and writing integers using data streams (dis and
dos are a DataInputStream and DataOutputStream that has been opened):
for(int i=0;i <100;i++) {
int n = dis.readInt();
LCD.drawInt(n,7,0,1);
dos.writeInt(-n);
dos.flush();
}
Be aware: you must flush the output stream to be sure the data is actually transmitted.
Furthermore, it is possible for transmission to fail without throwing an exception.
The DataInputStream, DataOutputstream and NXTConnection can then be closed using the close() method.
The full example using BlueTooth is:
public class BTReceive {
public static void main(String [] args) throws Exception {
String connected = "Connected";
String waiting = "Waiting...";
String closing = "Closing...";
while (true) {
LCD.drawString(waiting,0,0);
NXTConnection connection = Bluetooth.waitForConnection();
LCD.clear();
LCD.drawString(connected,0,0);
DataInputStream dis = connection.openDataInputStream();
DataOutputStream dos = connection.openDataOutputStream();
for(int i=0;i<100;i++) {
int n = dis.readInt();
LCD.drawInt(n,7,0,1);
dos.writeInt(-n);
dos.flush();
}
dis.close();
dos.close();
LCD.clear();
LCD.drawString(closing,0,0);
btc.close();
LCD.clear();
}
}
}
To modify this example to work with USB, you only have to change Bluetooth.waitForConnection() to USB.waitForconnection()
Back to top
NXT Initiator
To initiate a Bluetooth connection from one NXT to another NXT, you first need to add the receiver NXT to
the initiator NXT’s Bluetooth devices.
To do this, you go to the Bluetooth menu in the leJOS NXJ start-up menu and select “Search”.
Providing the Bluetooth power is on and visibility is on for the
receiving NXT, it will be found and you can select “Add” to add it to
the initiator’s Bluetooth devices.
To check it is in the Devices list, you can select “Devices” from the Bluetooth menu of the initiator NXT.
You can then create a BTRemoteDevice class on the initiator NXT:
Example:
BTRemoteDevice btrd = Bluetooth.getKnownDevice(name);
You can connect to the remote device by its address, which you can get by:
You can then connect to the remote device by calling one of the connect() methods in the Bluetooth class:
Example:
BTRemoteDevice btrd = Bluetooth.getKnownDevice(name);
if (btrd == null) {
LCD.clear();
LCD.drawString("No such device", 0, 0);
Button.waitForPress();
System.exit(1);
}
BTConnection btc = Bluetooth.connect(btrd);
if (btc == null) {
LCD.clear();
LCD.drawString("Connect fail", 0, 0);
Button.waitForPress();
System.exit(1);
}
Having got a BTconnection object you can open the data input and output streams and read data as in the
receiver example above.
The complete BTConnectTest example, which works as the initiator program for the BTReceive receiver program, is:
public class BTConnectTest {
public static void main(String[] args) throws Exception {
String name = "NXT";
LCD.drawString("Connecting...", 0, 0);
BTRemoteDevice btrd = Bluetooth.getKnownDevice(name);
if (btrd == null) {
LCD.clear();
LCD.drawString("No such device", 0, 0);
Button.waitForPress();
System.exit(1);
}
BTConnection btc = Bluetooth.connect(btrd);
if (btc == null) {
LCD.clear();
LCD.drawString("Connect fail", 0, 0);
Button.waitForPress();
System.exit(1);
}
LCD.clear();
LCD.drawString("Connected", 0, 0);
DataInputStream dis = btc.openDataInputStream();
DataOutputStream dos = btc.openDataOutputStream();
for(int i=0;i<100;i++) {
try {
LCD.drawInt(i*30000, 8, 0, 2);
dos.writeInt(i*30000);
dos.flush();
} catch (IOException ioe) {
LCD.drawString("Write Exception", 0, 0);
}
try {
LCD.drawInt(dis.readInt(),8, 0,3);
} catch (IOException ioe) {
LCD.drawString("Read Exception ", 0, 0);
}
}
try {
LCD.drawString("Closing... ", 0, 0);
dis.close();
dos.close();
btc.close();
} catch (IOException ioe) {
LCD.drawString("Close Exception", 0, 0);
}
LCD.drawString("Finished",3, 4);
Button.waitForPress();
}
}
Back to top
PC Initiator
A PC program can initiate a connection to a NXT and open a Java data stream.
The API on the PC is different to the NXT API. See pcapidocs.
To connect to the NXT, you need a NXTComm object that can be obtained using the NXTCommFactory class:
Bluetooth Initiator
A NXTComm object to connect via Bluetooth can be obtained by:
NXTComm nxtComm = NXTCommFactory.createNXTComm(NXTCommFactory.BLUETOOTH);
The reason for using a factory method is that there are several implementations of comms drivers for
Bluetooth and USB on the PC and the one that is used depends on what
operating system you are using and the contents of he nxj.properties
file.
You can connect to the NXT by address or by do a Bluetooth inquiry:
To connect by address, you create a NXTInfo object using the constructor:
Example:
NXTInfo nxtInfo = new NXTInfo("NXT", "00:16:53:00:78:48");
To find the available NXTs doing a Bluetooth inquiry, you do:
NXTInfo[] nxtInfo = nxtComm.search("NXT",NXTCommFactory.BLUETOOTH)
Back to top
USB Initiator
The initiator sequence using USB is almost the same as for Bluetooth; You just have to use USB instead
of Bluetooth.in your code. While USB cannot use a device address , but you can use the NXT name.
NXTComm nxtComm = NXTCommFactory.createNXTComm(NXTCommFactory.USB);
To find the available NXT , you do:
nxtComm.search("MYNXT", NXTCommFactory.BLUETOOTH);
If there is only one NXT connected, you can use a null name parameter in the search() method.
Back to top
Using the NXTInfo object
Once you have a NXTInfo object,you can call the open() method of the NXTComm object to connect to the NXT:
Once the NXT is open, you can obtain an InputStream and an OutputSttream, by calling the
getInputStream() anf getOutputStream() methods of the NXTComm object:
From these you can construct a DataInputStream and a DataOutputStream and send data to the receiving NXT.
The complete BTSend sample is in the samples folder.
Back to top
Advanced Communications
In this section you will learn how to:
- Control one NXT with another NXT over Bluetooth
- Control an external Bluetooth device like a GPS receiver
- Communicate between a NXT and an RCX
Controlling a remote NXT
The RemoteNXT class allows one NXT running leJOS NXJ to control another, remote NXT, running NXJ or the
standard LEGO firmware. It uses the LEGO Communications Protocol (LCP) over Bluetooth to control the remote NXT.
Currently, the class is limited and I2C and RCX sensors are not supported, and the motors must be used
in a simple way as the regulation thread is not used.
To access a remote NXT, you use the constructor:
Example:
try {
LCD.drawString("Connecting...",0,0);
nxt = new RemoteNXT("NXT");
LCD.clear();
LCD.drawString("Connected",0,0);
} catch (IOException ioe) {
LCD.clear();
LCD.drawString("Conn Failed",0,0);
Button.waitForPress();
System.exit(1);
}
The name of the remote NXT must have already been added to the known devices of the initiating NXT by
do a Bluetooth search followed by “Add” fron the leJOS NXJ Bluetooth menu.
The constructor opens the connection and creates instances of the remote motor and sensor ports.
It is then possible to get access to information about the remote NXT by using the methods:
-
public String getBrickName()
-
public String getBluetoothAddress()
-
public int getFlashMemory()
-
public String getFirmwareVersion()
-
public String getProtocolVersion()
Example:
LCD.drawString(nxt.getBrickName(), 0, 6);
LCD.drawString(nxt.getFirmwareVersion(), 0, 7);
LCD.drawString(nxt.getProtocolVersion(), 4, 7);
LCD.drawInt(nxt.getFlashMemory(), 6, 8, 7);
There are also methods that act on the remote NXT:
A remote Battery object is created that can be used to get the voltage of the remote battery using the normal Battery methods.
Example:
LCD.drawString( "Battery: " + nxt.Battery.getVoltageMilliVolt() 0,4);
Objects are also created for the sensor ports of the remote NXT. These are accessed as S1, S2, S3 and S4.
Local sensor objects can then be created using these ports and use exactly as if they were connected to a local sensor port.
Example:
LightSensor light = new LightSensor(nxt.S1);
LCD.drawString("Light: " + light.readValue(),0,5);
Motor objects are created for the remote motors. They are named A, B and C.
These can be used in the normal way, e.g:
nxt.A.setSpeed(360);
nxt.A.forward();
nxt.A.stop();
nxt.A.backward();
Back to top
External Bluetooth devices
The NXT can connect to external Bluetooth devices that implement the Serial Port Profile (SPP).
Such devices can be searched for on the Bluetooth menu and added to the known devices.
An example of such a device is an external Bluetooth GPS receiver. These can be used to obtain to obtain
the geographic location of a robot
leJOS supports external Bluetooth GPS receivers that support the NMEA protocol via the GPS and NMEASentence
classes. NMEASentence is a utility class used by GPS, and is not directly accessed.
One such device that has been tested with leJOS NXJ is the Holux M-1200.
Most such devices have a PIN that is required to connect to them, but it may have a default value such as “0000”.
To connect to a GPS device, you do:
final byte[] pin = {(byte) '0', (byte) '0', (byte) '0', (byte) '0'};
BTRemoteDevice btGPS = Bluetooth.getKnownDevice(name);
if (btrd == null) {
LCD.drawString("No such device", 0, 0);
Button.waitForPress();
System.exit(1);
}
btGPS = Bluetooth.connect(btrd.getDeviceAddr(), pin);
if(btGPS == null)
LCD.drawString("No Connection", 0, 1);
Button.waitForPress();
System.exit(1)
}
LCD.drawString("Connected!", 0, 1);
GPS gps = null;
InputStream in;
try {
in = btGPS.openInputStream();
gps = new GPS(in);
LCD.drawString("GPS Online", 0, 6);
} catch(Exception e) {
LCD.drawString("GPS Connect Fail", 0, 6);
Button.waitForPress();
System.exit(1);
}
As you see from this example, the GPS constructor takes the input stream from the Bluetooth connection as a parameter:
The GPS class starts thread and uses the NMEASentence class to process
messages (known as sentences) from the Bluetooth device. Messages such as
the $GPGGA sentence that gives the current latitude, longitude and
altitude, are processed.
To read the current values of latitude, longitude and altitude, you use the methods:
-
public float getLatitude()
-
public float getLongitude()
-
public float getAltitude()
You can also get the time stamp corresponding to these values by:
Back to top
Communicating with the RCX
IR communication with the RCX can be done using the Mindsensors NRLink RCX IR adapter. The software abstraction
of this device is the RCXLink class. The constructor is:
For example:
RCXLink link = new RCXLink(SensorPort.S1);
The NRLink-Nx supports a set of macros in ROM and EEPROM that can be used to send messages to the RCX using the LEGO
RCX IR protocol. The EEPROM macos can be overwritten allowing the user
to define their own macros.
Macros can be run by:
There are convenience methods for running the ROM macros:
-
public void beep()
-
public void runProgram(int programNumber)
-
public void forwardStep(int id)
-
public void backwardStep(int id)
-
public void setRCXRangeShort()
-
public void setRCXRangeLong()
-
public void powerOff()
-
public void stopAllPrograms()
A new macro in the EEPROM address range can be defined by:
There is a convenience method to define and run a macro:
Back to top
|