/** @file tools/sdk/java/Format.java @author Luke Tokheim, luke@motionnode.com @version 1.0 (C) Copyright GLI Interactive LLC 2007. All rights reserved. The coded instructions, statements, computer programs, and/or related material (collectively the "Data") in these files contain unpublished information proprietary to GLI Interactive LLC, which is protected by US federal copyright law and by international treaties. The Data may not be disclosed or distributed to third parties, in whole or in part, without the prior written consent of GLI Interactive LLC. The Data is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose. */ package MotionNode.SDK; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import java.util.Vector; /** The Format class methods read a single binary message from a MotionNode service and return an object representation of that message. This is layered (by default) on top of the {@link Client} class which handles the socket level binary message protocol.
Example usage:
// Connect to port 32078 on localhost.
Client client = new Client(null, 32078);
while (true) {
if (client.waitForData()) {
while (true) {
// Block on the open connection until a message comes in.
{@link ByteBuffer} data = client.{@link Client#readData};
if (null == data) {
break;
}
// Create an associative container from the binary message.
Map preview = Format.Preview(data);
// Iterate through the container.
for (Map.Entry entry: preview.entrySet()) {
float[] euler = entry.getValue().getEuler();
System.out.println("Euler = [" + euler[0] + "," + euler[1] + "," + euler[2] + "]");
}
}
}
}
*/
public class Format {
/**
MotionNode services send a list of data elements. The {@link Format}
functions create a map from integer id to array packed data for each
service specific format.
This is an abstract base class to implement a single format specific
data element. The idea is that a child class implements a format specific
interface (API) to access individual components of an array of packed
data.
For example, the {@link PreviewElement} class extends this class
and provides a {@link PreviewElement#getEuler} method to access
an array of {x, y, z} Euler angles.
*/
abstract public class Elementnull otherwise
@see #getShortData
*/
protected float[] getFloatData(int base, int length)
{
float[] result = new float[length];
if ((null != data) && (base + length <= data.size())) {
for (int i=0; inull otherwise
@see #getFloatData
*/
protected short[] getShortData(int base, int length)
{
short[] result = new short[length];
if ((null != data) && (base + length <= data.size())) {
for (int i=0; iLocal orientation is defined relative to the start pose. The start pose is defined at take intitialization or by the user.
Preview element format:
id => [global quaternion, local quaternion, local euler, local translation]
id => {Gqw, Gqx, Gqy, Gqz, Lqw, Lqx, Lqy, Lqz, rx, ry, rz, tx, ty, tz}
Euler angles are computed on the server side based on the current local quaternion orientation.
@return a three element array {x, y, z} of Euler angles in radians or null if there is no available data @see #getQuaternion */ public float[] getEuler() { return getFloatData(8, 3); } /** Get a 4-by-4 rotation matrix from the current global or local quaternion orientation. Specified as a sixteen element array in row-major order. @param local set to true get the local orientation, otherwise returns the global orientation @return a sixteen element array that defines a 4-by-4 transformation matrix in row-major order or the idenitity if there is no available data @see #getQuaternion */ public float[] getMatrix(boolean local) { return quaternion_to_R3_rotation(getQuaternion(local)); } /** Get the global or local unit quaternion that defines the current orientation. @param local set to true get the local orientation, otherwise returns the global orientation @return a four element array{w, x, y, z} that defines a
unit length quaternion q = w + x*i + y*j + z*k or zeros
if there is no available data
*/
public float[] getQuaternion(boolean local)
{
if (local) {
return getFloatData(4, 4);
} else {
return getFloatData(0, 4);
}
}
/**
Get x, y, and z of the current estimate of linear acceleration.
Specified in g.
@return a three element array {x, y, z} of linear
acceleration channels specified in g or zeros if there is no
available data
*/
public float[] getAccelerate()
{
return getFloatData(11, 3);
}
} // class PreviewElement
/**
The Sensor service provides access to the current un-filtered sensor signals
in real units. The Sensor service sends a map of N data elements.
Use this class to wrap a single Sensor data element such that we can access
individual components through a simple API.
Sensor element format:
id => [accelerometer, magnetometer, gyroscope]
id => {ax, ay, az, mx, my, mz, gx, gy, gz}
*/
public class SensorElement extends Element-9.8 meters/sec^2.
Domain varies with configuration. Maximum is [-6, 6]
g.
@return a three element array {x, y, z} of acceleration
in gs or zeros if there is no available data
*/
public float[] getAccelerometer()
{
return getFloatData(0, 3);
}
/**
Get a set of x, y, and z values of the current un-filtered
gyroscope signal. Specified in degrees/second.
Valid domain is [-500, 500] degress/second.
@return a three element array {x, y, z} of angular velocity
in degrees/second or zeros if there is no available data
*/
public float[] getGyroscope()
{
return getFloatData(6, 3);
}
/**
Get a set of x, y, and z values of the current un-filtered
magnetometer signal. Specified in uT (microtesla).
Domain varies with local magnetic field strength. Expect values
on [-60, 60] uT (microtesla).
@return a three element array {x, y, z} of magnetic field
strength in uT (microtesla) or zeros if there is no
available data
*/
public float[] getMagnetometer()
{
return getFloatData(3, 3);
}
} // class SensorElement
/**
The Raw service provides access to the current uncalibrated, unprocessed
sensor signals in signed integer format. The Raw service sends a map of
N data elements. Use this class to wrap a single Raw data element
such that we can access individual components through a simple API.
Raw element format:
id => [accelerometer, magnetometer, gyroscope]
id => {ax, ay, az, mx, my, mz, gx, gy, gz}
All sensors output 12-bit integers. Process as 16-bit short integers on the server side.
*/ public class RawElement extends Element
Valid domain is [0, 4095].
{x, y, z} of raw
accelerometer output or zeros if there is no available data
*/
public short[] getAccelerometer()
{
return getShortData(0, 3);
}
/**
Get a set of x, y, and z values of the current unprocessed
gyroscope signal.
Valid domain is [0, 4095].
{x, y, z} of raw
gyroscope output or zeros if there is no available data
*/
public short[] getGyroscope()
{
return getShortData(6, 3);
}
/**
Get a set of x, y, and z values of the current unprocessed
magnetometer signal.
Valid domain is [0, 4095].
N Preview data elements from a packed binary input
message. Each of the N elements has an integer id and an array of
M floating point values.
@param buffer raw binary input message, for example directly from
a call to {@link Client#readData}
@return a {@link java.util.Map}N Sensor data elements from a packed binary input
message. Each of the N elements has an integer id and an array of
M floating point values.
@param buffer raw binary input message, for example directly from
a call to {@link Client#readData}
@return a {@link java.util.Map}N Sensor data elements from a packed binary input
message. Each of the N elements has an integer id and an array of
M floating point values.
@param buffer raw binary input message, for example directly from
a call to {@link Client#readData}
@return a {@link java.util.Map}N elements from a packed byte array. Each
element has an id and a array of M elements. The incoming
byte buffer must have exactly the number of bytes to complete N
elements. N is computed based on the size of the input buffer
and the length of each float array.
@param buffer raw binary message input, for example directly from
a call to {@link Client#readData}
@param length the number of values in a single element's float array
@return a {@link java.util.Map}M elements.
The incoming byte buffer must have exactly the number of bytes to complete
N elements. N is computed on the fly based on the
size of the input buffer and the length of each short integer array.
@param buffer raw binary message input, for example directly from
a call to {@link Client#getSample}
@param length the number of values in a single element's short
integer array
@return a {@link java.util.Map}