Lore Michael Lones

Using 5DT Data Gloves with Java

5DT Data Gloves come with a C-based API for accessing raw and calibrated data and gesture information. Individual gloves ship with a USB cable. When using this, data can be accessed from Java programs by building a JNI interface to the C library. This allows access to calibrated data and gestures. Writing the JNI code isn't hard, but I've not yet had any luck getting it to link to the data glove's C library.

Serial Interface

An easier approach is to use a serial connection. This comes as standard with the wireless kit, or as an optional extra with individual gloves. Once everything is connected and turned on, the serial connection provides a constant stream of raw sensor data. This can be read from Java using the RXTX library, available from here.

Note that most computers do not have a serial port these days, so you may have to use a serial adapter. I would recommend using a PCI Express-based serial adapter, since in my experience serial-to-USB adapters can not cope with the large throughput of data produced by the gloves. I use a Startech EC2S952 ExpressCard. Note that some cheaper cards make use of the USB interface rather than the PCI Express interface, and may therefore have the same limitations as serial-to-USB adapters.

Data is delivered as a sequence of binary packets, each comprising: a header value (0x3C), a glove type identifier, a version identifier, 16 sensor values, a checksum and a footer (0x3E). Sensor values are 12-bit and all other values are 8-bit. The only real challenge is extracting 12-bit values from a byte stream.

The Code

Working example code is available here.

First, find out the port name. On Windows, it will depend which COM port is associated with the adapter. You can find out by looking in the device manager (Start->Run... devmgmt.msc) under Ports. Note, however, that RXTX only works with COM ports up to 9, producing a PortInUseException for COM10 and above. If your adapter has been allocated a higher port number, then you should reallocate it (typically using the device manager). On Mac OS, have a look in /dev ('ls /dev' in Terminal) and see if there's anything with an appropriate sounding name.

Once you have the name of the port, you can create an RXTXPort object in Java. For example:

String osname = System.getProperty("os.name");
RXTXPort port;
if(osname.startsWith("Mac"))
 
portName = "/dev/tty.usbserial";
else if(osname.startsWith("Windows"))
 
portName = "COM5";
try {
 
port = new RXTXPort(portName);
}
catch(PortInUseException piuE) {
 
System.err.println("Glove connection failed: serial port "+portName+" in use or does not exist");
}

Next, you need to set up the communication protocol:

try {
 
port.setSerialPortParams(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
}
catch (UnsupportedCommOperationException ucoE) {
 
System.err.println("Glove connection failed: could not configure serial port");
}

An exception may be thrown at this point if your adapter's driver is not sufficiently up-to-date.

Assuming the connection was successfully established, you can now retrieve an input stream from the glove. For a reliable connection, it is advisable to wrap the input stream with a buffer:

InputStream in = port.getInputStream();
BufferedInputStream buffer = new BufferedInputStream(in);

Receiving packets is a simple case of calling buffer.read() repeatedly. However, interpreting the data is a bit more complicated, since the 12-bit sensor values are split over one-and-a-half bytes. This extract from the sample code shows how this can be done using bit-level operators:

boolean fullByte;
int data, value, s;
fullByte =
true;
for(s=2; s<18; s++) { // read sensor values
 
if(fullByte) { // do this when reading a full byte followed by a nibble
   
value = buffer.read(); // read first 8 bits of sensor value
   
value = value<<4; // shift along to make room for the other 4 bits
   
data = buffer.read(); // read next 8 bits from stream
   
value = value | data>>4; // copy 4 bits from this to complete the 12 bit sensor value
   
packet[s] = value;
 
}
 
else { // and this when reading a nibble followed by a byte
   
value = data<<8; // shift the 4 bits already loaded during reading of previous sensor value
   
value = value & 0xFFF; // discard the 4 bits we don't want
   
data = buffer.read(); // read the next 8 bits
   
value = value | data; // and put them in front of the existing 4 bits
   
packet[s] = value;
 
}
 
fullByte = !fullByte;
}
These web pages use Google Analytics to track visits. See Privacy Statement.
© Michael Lones 2005-2016. Page last updated 30th October, 2013.