http://epirsch.blogspot.com/2008/02/jna-love-nxt.html
good news for the struggle to get ECLIPSE JAVA and bluetooth together.
Since Emmanuel Pirsch only presented the base of the project, with just an example how start a prog on the brick, we could try out our skills making this in an ECLIPSE project and making classes for some sensors.
It worked!
So what did we do?
added the exception classes.
I saw the timeout is used totally to search for devices before starting the program, so i reduced the time-out to 5 seconds, can be probably even less. (The C++ and the C# libs connect within a few seconds if all is well.)
Later on Emmanuel Pirsch suggested the possibility to connect directly to the brick (see his comment) we tried his suggestion and this worked, reducing the waiting time to nearly nothing. (You have to do the search first to get the exact name, after that, you can use this name.)
I tested this projects and our sketchy classes with HSL homebrew for playing a sound on the brick, the lightsensor (Custom) and the I2C sensors(sonar, clock for the moment). It works!
The direct commands must be used without the starting code (which chooses between expecting a response or not, this is indicated in the method.)
Playing a sound uses command 0x03 freq freq duration duration 0x00
Reading a sensor: 0x07 port 0x00 and expecting back a byte[15] (so not the byte[18] of C++)
public void playSound(int freq, int duration) { Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(6); command.put((byte)0x03);//direct command play tone command.put((byte)freq); command.put((byte)(freq >>8)); command.put((byte)duration); command.put((byte)(duration>>8)); command.put((byte)0x00); fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, false, command, command.capacity(), null, 0, status); System.out.println(status.getStatus().toString()); } public int getBattery() { Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(1); command.put((byte)0x0B);//direct command get battery byte[] response = new byte[4]; //this 4 bytes are vital to get the following readings right fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, true, command, command.capacity(), response, response.length, status); return response[0]; } public int readSensor(int port) { //used for the lightsensor Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(3); command.put((byte)0x07);//direct command read sensor command.put((byte)port); command.put((byte)0x00); byte[] response = new byte[15];//expected back fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, true, command, command.capacity(), response, response.length, status); //the values are not really what they should be at the moment??? int raw=((0xff & response[5]) | (response[6] << adc="((0xff" best="((0xff" calcu="((0xff"> |
while changing this in the connect method: timeout 5 instead of 30.
Pointer iNXTIterator= fantom.nFANTOM100_createNXTIterator(true, 5, status); |
Alternative in case you already have the name available:
In the Fantom interface add:
Pointer nFANTOM100_createNXT(String resourceString, Status status, boolean checkFirmwareVersion);
Then in the NXT.java class:
private Pointer directConnect()throws UnableToCreateNXTException { Status status= new Status(); Pointer iNXT = fantom.nFANTOM100_createNXT("BTH::5brickXT::00:16:53:01:BA:74::8", status, false ); if (Status.Statuses.SUCCESS.equals(status.getStatus())) { return iNXT; } else { throw new UnableToCreateNXTException( " not able to create connection" ); } } |
and adding the exceptions: (in the package treelaws.mindstorm)
package treelaws.mindstorm; public class NXTNotFoundException extends Exception { public NXTNotFoundException(final String message) { super(message); } } package treelaws.mindstorm; public class UnableToCreateNXTException extends Exception { public UnableToCreateNXTException(final String message) { super( message ); } } |
then adding the throw in some methods, requiring this:
public NXT(String name) throws NXTNotFoundException, UnableToCreateNXTException private Pointer connect(String name) throws NXTNotFoundException, UnableToCreateNXTException |
and changing the exceptions ( in method connect) to include the message:
throw new UnableToCreateNXTException( " not able to create connection" ); throw new NXTNotFoundException( " no nxt found" ); |
The lejos in the brick still does not allow a new connection (after having had a connection) it has to be restarted.
Later on I tested the more complicated I2C sensors: the sonar, and the clock, all went well, here is the class:
| package treelaws.mindstorm; import java.nio.ByteBuffer; import com.sun.jna.Pointer; import treelaws.fantom.Fantom; import treelaws.fantom.Status; public class I2Csensor { private static Fantom fantom = Fantom.INSTANCE; private Pointer nxtPointer; int myPort; String sensorName; public I2Csensor (int port, Pointer NXTPointer, String name ) { myPort = port; nxtPointer = NXTPointer; sensorName = name; setUpI2CSensor(); } public int setUpI2CSensor() { //used for the distance, clock, compass, acceleration sensors Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(4); command.put((byte)0x05);//setinputmode command.put((byte)myPort);//port command.put((byte)0x0B);//sensortype LOWSPEED_9V command.put((byte)0x00);//sensormode byte[] response = new byte[2]; fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, true, command, command.capacity(), response, response.length, status); return response[0]; //status } public int getStatusI2CSensor() { //used for the distance Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(2); command.put((byte)0x0E);//setinputmode command.put((byte)myPort);//port byte[] response = new byte[1]; fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, true, command, command.capacity(), response, response.length, status); return response[0]; //number of bytes ready to read } public int readI2C() { int value = -999; Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(6); command.put((byte)0x0F);//LSWRITE command.put((byte)myPort); //port command.put((byte)2);//lenght of bytes to send if ( sensorName == "sonar" || sensorName == "compass") { //sonar and compass command.put((byte)1);//length of bytes to receive sonar command.put((byte)0x02);//sonar address sonar: 0x02 command.put((byte)0x42);//register to read sonar: 0x42 } if ( sensorName == "clock" ) { command.put((byte)1);//length of bytes to receive command.put((byte)0xD0);//sonar address clock: 0x02 command.put((byte)0x00);//register to read clock seconds: 0x42 } fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, false, command, command.capacity(), null, 0, status); int nb = 1; //number of bytes to read if ( waitI2CSensor( nb) ) value = readBytesI2CSensor( nb) ; return value; } p public int getStatusI2CSensor() { Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(2); command.put((byte)0x0E);//setinputmode command.put((byte)myPort);//port byte[] response = new byte[1]; fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, true, command, command.capacity(), response, response.length, status); return response[0]; //number of bytes ready to read } public int readI2C() { int value = -999; //System.out.println( "--startread---" + port ); Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(6); command.put((byte)0x0F);//LSWRITE command.put((byte)myPort); //port command.put((byte)2);//lenght of bytes to send if ( sensorName == "sonar" || sensorName == "compass") { //sonar and compass command.put((byte)1);//length of bytes to receive sonar command.put((byte)0x02);//sonar address sonar: 0x02 command.put((byte)0x42);//register to read sonar: 0x42 } if ( sensorName == "clock" ) { command.put((byte)1);//length of bytes to receive command.put((byte)0xD0);//address clock: 0xD0 command.put((byte)0x00);//register to read clock seconds: 0x00 - seconds } fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, false, command, command.capacity(), null, 0, status); int nb = 1; //number of bytes to read if ( waitI2CSensor( nb) ) value = readBytesI2CSensor( nb) ; return value; } public boolean waitI2CSensor( int numberBytes) { int nB = getStatusI2CSensor(); while ( nB < nb =" getStatusI2CSensor();" status=" new" command=" ByteBuffer.allocate(4);" response =" new" sensorname ="=" a =" response[3]">>4) *6;//otherwise the number of seconds will be jumping System.out.println("clock " + response[0] + " " + response[1] + " " + response[2] + " "+ response[3] + " " + response[4]+ " " + response[5]+ " " + response[6]); return a; } if ( sensorName == "sonar" || sensorName == "compass") { return 0xff & response[3]; } //value read, starting from 5 return -999;//no known sensor } } |
To make a map of the surroundings, we also need a motor class, a sketch using the tacholimit:
| package treelaws.mindstorm; import com.sun.jna.Pointer; import java.nio.ByteBuffer; import treelaws.fantom.*; import treelaws.fantom.Status; public class motor { private static Fantom fantom = Fantom.INSTANCE; private Pointer nxtPointer; private int motorPort; int MOTORON = 0x01; int BRAKE = 0x02; int REGULATED = 0x04; int REGULATION_MODE_IDLE = 0x00; int REGULATION_MODE_MOTOR_SPEED = 0x01; int REGULATION_MODE_MOTOR_SYNC = 0x02; int MOTOR_RUN_STATE_IDLE = 0x00; int MOTOR_RUN_STATE_RAMPUP = 0x10; int MOTOR_RUN_STATE_RUNNING = 0x20; int MOTOR_RUN_STATE_RAMPDOWN = 0x40; public motor (int port, Pointer NXTPointer) { motorPort = port; nxtPointer = NXTPointer; } public void reset() { Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(2); command.put((byte)0x0A);//reset command.put((byte)motorPort);//port fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, false, command, command.capacity(), null, 0, status); System.out.println("reset" + " " + status.code); } public void speedMotor( int power, int turnratio) { Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(13); command.put((byte)0x04);//LSREAD command.put((byte)motorPort);//port command.put((byte)power);//power -100 - 100 command.put((byte)MOTORON );//mode command.put((byte)REGULATION_MODE_MOTOR_SYNC );//regulation synchronized command.put((byte)(128 - turnratio) );//turnratio command.put((byte)REGULATION_MODE_MOTOR_SPEED );//runstate command.put((byte)0x50 );//tacholimit = 0 command.put((byte)0x00 );//tacholimit = 0>> 8 command.put((byte)0x00 );//tacholimit = 0>> 16 command.put( (byte)0x00 );//tacholimit = 0>> 24 command.put( (byte)0x00 );//tacholimit = 0>> 32 command.put( (byte)0x00 );//closing fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, false, command, command.capacity(), null, 0, status); } public void stopMotor() { Status status= new Status(); ByteBuffer command= ByteBuffer.allocate(12); command.put((byte)0x04);//LSREAD command.put((byte)motorPort);//port command.put((byte)0x00);//power -100 - 100 command.put( (byte)REGULATED );//mode command.put( (byte)REGULATION_MODE_MOTOR_SYNC );//regulation command.put( (byte)0x00 );//turnratio command.put( (byte)MOTOR_RUN_STATE_IDLE );//runstate command.put( (byte)0x00 );//tacholimit = 0 command.put( (byte)0x00 );//tacholimit = 0 command.put( (byte)0x00 );//tacholimit = 0 command.put( (byte)0x00 );//tacholimit = 0 command.put( (byte)0x00 );//tacholimit = 0 fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, false, command, command.capacity(), null, 0, status); } } |

With a bit of JAVA Graphic, i got this result, NXT scanning for objects, using compass and sonar, some strange effects have to be investigated,
some other effects are resulting from the sonar, which is not a straightforward linear razorsharp distance device!
Connection setup XP or VISTA (tested for both)
Needed:
- installing NXT Mindstorms CD (this installs the fantom lib)
- bluetooth dongle
You have to install a comport:
In bluetooth manager Search for device
Wizard, manual key 1234
ready with wizard
first use connect method in the JAVA project with search for device
copy name of brick BTH::name of device::Mac-address::comport
then you can switch to directConnect
Troubleshooting:
After having worked with a fantom lib project yesterday, today it won't connect!
I had to redo the COMPORT settings. Desinstall existing COMPORTS, do a search, give the preconfigured key, check the ports again.
Possible cause: the Brick was running from my laptop on XP, and Michel tested it from VISTA. This might have reconfigured the brick???
Big problem with the fantom lib or this kind of interface: writing commands does not seem to be working.
(see solution...:-( )
LSWRITE is ok to check registers, reading values etc, but LSWRITE to the command register with a command has no effect. Testing for several I2C sensors, compaas, camera, and clock. The clock has a RAM, which can be written to using C++ (my own classes in the Anders lib).
This is the code:
public void sendCommand(byte cmd)
{
System.out.println(" sendCommand " + cmd);
Status status= new Status();
ByteBuffer command= ByteBuffer.allocate(7);
command.put((byte)0x0F);//LSWRITE
command.put((byte)myPort); //port
command.put((byte)3);//length of bytes to send
command.put((byte)0);//length of bytes to receive camera
command.put((byte)0x02);//camera address camera: 0x02
command.put((byte)0x41);//command address
command.put((byte)cmd);//command byte to send
fantom.nFANTOM100_iNXT_sendDirectCommand(nxtPointer, false, command, command.capacity(), null, 0, status);
System.out.println( "sendcommand back: " + nb + " char= " + cmd + " " + myPort ) ;
pause(100); //should check I2C status
}
This means that reading values from the usual I2C sensors is possible (Compass, Clock, Tilt for instance) but no changes can be made, nor the camera can be put in the following objects mode.
Solution: the bluetooth connection is on a master- slave basis which means that writing registers is not possible. So reading from sensors is ok, but starting the camera, or setting the time in the clock sensor is not possible.
reference:
http://nxtasy.org/2006/12/23/fantomtalk/
http://mindstorms.lego.com/Overview/NXTreme.aspx
0 comments:
Post a Comment