Java NAOqi SDK

Warning

The API presented here is still under development and may change in the future.

Introduction

The Java NAOqi SDK provides Java bindings to call remote services, create new services and react to events.

Requirements

  • Java 1.6 or higher.

Available on

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

How to use

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:

In eclipse

Add the qimessaging.jar as an external jar in the properties of your project.

From the command line

# Compile your application
javac -cp /path/to/qimessaging.jar YourClass.java

# Run your application
java -cp /path/to/qimessaging.jar:. YourClass

On NAO

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.

Getting Started

Calling a remote service

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");

	}

}

Creating a new service

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"

Reacting to events

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.