Warning
The API presented here is still under development and may change in the future.
The Java NAOqi SDK provides Java bindings to call remote services, create new services and react to events.
OS | Comment |
---|---|
Windows 32 bits | No 64 bits support |
Linux 32 and 64 bits | Tested with Ubuntu 12.04 LTS, but should work fine on any recent distribution. |
Mac OSX | |
NAOqi OS 2.0 and higher | Running on NAO V4 and V5 |
Android 4.0 | Experimental |
There is one .jar per platform, because the implementation uses a C++ dynamic library using JNI.
Use the .jar as you would do for any 3rd party Java library:
Add the qimessaging.jar as an external jar in the properties of your project.
# Compile your application
javac -cp /path/to/qimessaging.jar YourClass.java
# Run your application
java -cp /path/to/qimessaging.jar:. YourClass
Warning
Using Java on NAO is not supported by Aldebaran. Hence Java is not present on the system image.
However, you may try to install and configure Java on your robot for research or experiment purpose.
Step | Action |
---|---|
Download the JRE 32bits from Oracle’s website. | |
Upload then extract it somewhere on the robot. scp jre-7u60-linux-i586.tar.gz nao@nao.local:
ssh nao@nao.local
tar xvfz jre-7u60-linux-i586.tar.gz
mkdir /home/nao/java
mv jre1.7.0_60 /home/java
|
|
Copy the qimessaging-atom jar on the robot. For instance in: /home/nao/java/qimessaging-atom.jar scp qimessaging-jar.gz nao@nao.local:java/
|
|
Create a sourceme file looking like: nano /home/nao/java/sourceme
export JAVA_HOME=/home/nao/java/jre
export PATH=$PATH:/home/nao/java/jre/bin
export CLASSPATH=/home/nao/java/qimessaging-atom.jar
|
|
Compile your code and upload the .class files to the robot. (see section Compiling from the command line) | |
Run source sourceme and use the command line to run your Java application. |
import com.aldebaran.qimessaging.*;
public class SayHello {
public static void main(String[] args) throws Exception {
Application app = new Application(args);
Session session = new Session();
Future<Void> fut = session.connect("tcp://nao.local:9559");
fut.get();
com.aldebaran.qimessaging.Object tts = null;
tts = session.service("ALTextToSpeech");
boolean ping = tts.<Boolean>call("ping").get();
if (!ping) {
System.out.println("Could not ping TTS");
} else {
System.out.println("Ping ok");
}
System.out.println("Calling say");
tts.call("say", "Hello, world");
}
}
import com.aldebaran.qimessaging.*;
import com.aldebaran.qimessaging.Object;
public class App
{
public static void main(String[] args) throws Exception {
Application app = new Application(args);
String address = "tcp://127.0.0.1:9559";
Session session = new Session();
QimessagingService service = new HelloService();
DynamicObjectBuilder objectBuilder = new DynamicObjectBuilder();
objectBuilder.advertiseMethod("greet::s(s)", service, "Greet the caller");
Object object = objectBuilder.object();
service.init(object);
System.out.println("Connecting to: " + address);
Future<Void> fut = session.connect(address);
fut.get();
System.out.println("Registering hello service");
session.registerService("hello", objectBuilder.object());
app.run();
}
}
Where HelloService implementation looks like this:
import com.aldebaran.qimessaging.*;
public class HelloService extends QimessagingService
{
public String greet(String name) {
return "Hello, " + name;
}
}
In order for the service to run, you should first run a master, and then connect your Java service to it:
$ /path/to/cpp/sdk/bin/qi-master
$ java App
You can then call the advertised methods of the hello service as you would do for any other NAOqi service, or using qicli
$ /path/to/cpp/sdk/bin/qicli hello.greet "world"
import com.aldebaran.qimessaging.Application;
import com.aldebaran.qimessaging.CallError;
import com.aldebaran.qimessaging.Future;
import com.aldebaran.qimessaging.Object;
import com.aldebaran.qimessaging.Session;
public class ReactToEvents {
private Object tts;
private Object memory;
private CallBack callback;
public class CallBack {
private Object tts;
public CallBack(Object tts) {
this.tts = tts;
}
public void onTouch(java.lang.Object value) {
float data = (Float) value;
if (data == 1.0) {
try {
tts.call("say", "ouch");
} catch (CallError error) {
System.err.println(error.getMessage());
}
}
}
}
public void run(String[] args) throws Exception {
String url = "tcp://nao.local:9559";
if (args.length == 1) {
url = args[0];
}
Application application = new Application(args);
Session session = new Session();
Future<Void> fut = session.connect(url);
fut.get();
tts = session.service("ALTextToSpeech");
callback = new CallBack(tts);
memory = session.service("ALMemory");
Object subscriber = memory.<Object>call("subscriber",
"FrontTactilTouched").get();
subscriber.connect("signal::(m)", "onTouch::(m)", callback);
application.run();
}
public static void main(String[] args) throws Exception {
ReactToEvents reactor = new ReactToEvents();
reactor.run(args);
}
}
This example does not use the familiar ALMemory.subscribeToEvent method, but a new generic Signal system, bridged to the old API through the ALMemory.subscriber method.
This method returns a com.aldebaran.qimessaging.Object, which has a signal named signal, on which we can connect our callback.
The main advantage of this new approach is that it no longer required you register a module in order to monitor events.
Note that at this point you have to specify the “signature”, of both the signal, and the callback function we want to call:
“m” stands for anything, which means that signal accepts all instances of java.lang.Object, and that the callback should accept a java.lang.Object as parameter. The effective type of the argument will vary depending on what was passed to signal, for instance a java.lang.Integer or a java.lang.String.
Warning
The Application constructor must be called exactly once in the main Java process for the type system and the event loop to work.