Jean-Marc Le Roux Web, RIAs and chocolate spaghettis…

30Sep/113

NAO AS3 API released as open-source

Long time no see! As you can imagine I'm quite busy with Minko and Flash 11 stuff right now. Still, I would like to introduce some related work. Do you know Nao?

Nao is a quite impressive humanoïd robot. It has a lot of features, from text-to-speech to face recognition. And of course, it can walk and look around... seeing it in action is actually completely amazing! As I introduced Aerys' work to Aldebaran, they asked me to work on an ActionScript 3.0 wrapper for Nao's remote APIs as a part of a bigger project I will speak about soon.

So I did a complete (dynamic) wrapper of Nao's API and you can now fully control the robot from any Flash application using only ActionScript 3.0. So how does it work? It's actually quite simple:

var broker : ALBroker = new ALBroker();
 
// connect to the remote server
broker.connect("host", "login", "password");
// wait for an actual device to be available
broker.addEventListener(ALEvent.DEVICE_AVAILABLE, function(e : Event) : void
{
  // set the first available device as the "current device"
  broker.currentDevice = broker.devices[0];
 
  // call the "say" method from the "ALText2Speech" module
  broker.ALTextToSpeech.say("Hello world!");
});

So what is happening here?

  • We create an ALBroker and we connect it to the remote server using our Aldebaran Developers Program credentials.
  • We wait for the ALEvent.DEVICE_AVAILABLE event to be dispatched. When it is dispatched, it means at least one of the robots associated with our account is live and ready to be used. Therefore, we set it as the "current device" to be used by the ALBroker and future method calls will be sent to this device.
  • We call the "say" method from the "ALText2Speech" module. Indeed, methods with common goals and semantics are grouped inside "modules". This method does exactly what its name says: it will make the robot talk and say "Hello world!" (quite possibly the most awesome "Hello world!" I could ever write if you ask me...).

As you can see it is very straight forward and there isn't much configuration required. And you can make the robot talk, run, look around... with just one line of code! But how does it work exactly?

Dynamic Classes

Dynamic classes are one of my favorite ActionScript 3.0 features. It makes it possible to fully customize the behavior of an object when method are called or properties are read/written. To use this feature, your class must simply extend the Proxy class and you can then override the following methods (in the flash_proxy namespace):

  • getProperty(name : *) : * is called when you try to read a dynamic  that is not declared by the class
  • callProperty(name : *, ...arguments) : * is called when you try to call a method that is not declared by the class

You can find all the overridable methods in the Proxy class documentation.

In this case, I have 2 dynamic classes:

  • ALBroker: "getProperty" is overriden so when you access the "ALSomeModule" property it returns the corresponding ALModule object
  • ALModule: "callProperty" is overriden so when you call the "myMethod" method the corresponding ALMethod object is returned

Thanks to dynamic classes, we don't have to write and maintain dozens of classes to handle all the available modules and methods. We just have to make it fully dynamic and raise the proper exceptions when the server says the module/method does not actually exists.

Return Value Callbacks And Events Bubbling

The whole API is about calling remote methods and getting return values. Getting and calling the methods using dynamic classes is easy. But what about getting the return value? The main problem here is that those function calls are asynchronous. Therefore, we have to listen to some event to know when the method call return value is available.

We also might want to be able to listen to all the "return value" events of:

  • A single method call
  • All the calls of a specific method
  • All the methods of a specific module
  • All the modules of a specific broker

The first one is done using ALMethodCall objects. Everytime a remote method is called, it returns a unique ALMethodCall  object that will dispatch an ALMethodEvent.RESULT event when the actual return value - issued by the remote method call - is available.

The rest is done by simply catching that event and making it bubble to the ALMethod object that issued the ALMethodCall. Bubbling is easy: when the ALMethod creates the ALMethodCall, it starts listening the ALMethodEvent.RESULT event and re-dispatches it. We do the same with ALModule listening all its ALMethod objects, and ALBroker listening to all its ALModule objects.

Using this technique, listening to the ALMethodEvent.CALL/ALMethodEvent.RESULT event on a broker will make it possible to track every remote method calls and return values. And it is very helpful to monitor what is going on and debug your application!

Because the "addEventListener" syntax is a bit verbose when dealing with single method calls, I also added the ALMethodCall.onComplete(callback : Function) method that does exactly the same thing with a smoother syntax:

broker.ALText2Speech.say("Hello World!")
                    .onResult(sayCompleteHandler);

The main difference is that the callback function will be wrapped inside a listener function. Therefore the callback won't be called with an ALMethodEvent argument but rather with the actual return value of the remote method call.

Network Protocols

The Nao APIs use XMLRPC embed inside XMPP. The XMLRPC (de)serialization is homemade but the XMPP protocol is handled using seesmic. Seesmic works pretty well but I had to go through a lot of code to disable some "trace" method calls that were flooding the console. Still, its a little price to pay to have a fully functional XMPP library!

Get the sources

You can get the sources of the NAO AS3 API on GitHub.

Comments (3) Trackbacks (5)
  1. This looks nice!
    +1 for the jQuery-like syntax of the asynchronous call. ;)

  2. Uber Cool!!! Now where can i get Nao?


Leave a comment