QiMessaging Java bindings

Warning

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

Introduction

QiMessaging provides Java bindings to call remote services, create new services and react to events.

Requirements

  • Java 1.6 or higher.

Available on

  • Windows 32 bits (no 64bits support)
  • Linux 32 and 64 bits (tested with Ubuntu 12.04 LTS, but should work fine on any recent distribution)
  • 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.

Just use the .jar as you would do for any 3rd party Java library:

In eclipse

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

From the command line

javac -cp /path/to/qimessaging.jar YourClass.java

java -cp /path/to/qimessaging.jar:. YourClass

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 sercive 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);
	}
}

Note: 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.

Notes

  • The Application constructor must be called exactly once in the main Java process for the type system and the event loop to work.