Services

    

Hardware

No additional hardware is needed for this tutorial

The MRLClient is a client adapter which allows other Java programs to interoperate with MyRobotLab.  Although the myrobotlab.jar can be included and used in a Java program directly, it may sometimes be desirable to communicate over the network with an adapter.

The MRLClient jar is a small binary which uses the network to send and recieve messages to a running MyRobotLab instance.  Other network adapters could be created for languages besides Java, but currently only Java is supported.

Example 1 - Sending a "Hello World" message to a GUI.

Services are key in MyRobotLab.  Services are the basic building blocks which can do useful things like voice recognition, face tracking, or moving servos.  A Service sends and recieves messages.  In this example we are going to run one simple Java program which will send a "Hello World" message to a running instance of MyRobotLab.

1.1 Starting MyRobotLab with a Logging Service

Step 1. - Download MyRobotLab from here and unzip it into a directory.
Step 2. - Start the jython.bat or jython.sh depending on the operating system your using.
Step 3. - Copy and paste the following Jython script to the Jython editor. Press exec - to execute the script.

from org.myrobotlab.service import Logging
from org.myrobotlab.service import RemoteAdapter
from org.myrobotlab.service import Runtime

remote = Runtime.createAndStart("remote","RemoteAdapter")
logger = Runtime.createAndStart("logger","Logging")

This will start 2 new services.  The RemoteAdapter is needed to recieve messages from an external (out of process) source.  Additionally, a Logging service named "logger" is started too.  You should see 2 new tabs appear named "logger" and "remote".

Now MyRobotLab is running a Runtime, RemoteAdapter, Logging, and GUIService.  It's ready to recieve and display some messages.  The RemoteAdapter will by default listen on UDP and TCP ports 6767.

1.2 Using the MRLClient.jar in a Java Application to Send Messages

Step 1 - Download the MRLClient.jar from here and unzip it into the classpath of your application.
Step 2 - The following code can be added to your application to send messages to the running MyRobotLab instance.

TestHarness.java

package org.myrobotlab.client;

import org.myrobotlab.framework.Message;

public class TestHarness implements Receiver {
    
    public static void main(String[] args) {

        TestHarness test = new TestHarness();
        
        // create the client with a unique name
        MRLClient mrl = new MRLClient("myApp");
        // register the client with the running MyRobotLab
        mrl.register("localhost", 6767, test);
        // subscribe to a service & method - in this case logger.log(Message)
        mrl.subscribe("log", "logger", "receive", Message.class);
        for (int i = 0; i < 100; ++i)
        {
            // send message to logger.log(Message) 
            // since logger.log accepts all types since its input
            // is a Message
            mrl.send("logger", "log", "Hello World " + i);
        }
    }

    @Override
    public void receive(Message msg) {
        System.out.println(msg.data[0]);        
    }

}

Yay, the messages are showing up on the Logger !!!

Lets go through the what is happening in detail.
First a new MRLClient is created with a unique name.  This is similar to all services, which must each have a unique name.  Messaging is done using these names.  Each message has a sender and the name of the service of destination.  In this case our MRLClient unique name is "myApp".

        // create the client with a unique name
        MRLClient mrl = new MRLClient("myApp");

The next step is to register with the MyRobotLab.  This allows other services to send messages to the MRLClient, and the MRLClient's messages to appropriately find the right destination service.

        // register the client with the running MyRobotLab
        mrl.register("localhost", 6767, test);

The only things left now is to send the message.  In order to do so you must know the name of the service, and the method you wish to invoke with an appropriate parameter (if one exists).  We are going to invoke the "log" message on the Logging service named "logger".  The javadoc shows the Logging.log method accepts a Message as a parameter, but this happens to be a "special" method which accepts all or any input parameter datatypes.  The Logging.log method was created such that it intercepts and logs the entire message type.  And since Message can hold any data type in its Object array - it will log everything.

Use the send method to send a message. 

            mrl.send("logger", "log", "Hello World " + i);

The send method signature follows this pattern :
send ( serviceName, method, parameters ... )
Another example would be 

            mrl.send("motor01", "attach", "arduino01", 9, 4);

This example is invoking motor01's attach method with 3 parameters (controllerNae, powerPin, dirPin).

 

1.3 UDP vs TCP Messages

The default communication method with external sources uses UDP.  This is a fast, connectionless communication protocol.  It has less overhead than TCP, however, it does not guarantee delivery.  This can be useful for noisy sensors, or streaming video.  It may not be the preferred protocol for control messages.  MyRobotLab supports TCP too which guarantees message delivery.

To use TCP rather than UDP, another parameter is used when creating the MRLClient - MRLClient.COMMUNICATION_TYPE_TCP

        // create the client with a unique name and use TCP
        MRLClient mrl = new MRLClient("myApp", MRLClient.COMMUNICATION_TYPE_TCP);

 

1.4 Using the MRLClient.jar in a Java Application to Receive Messages

So how do you receive data bacck from a running MyRobotLab ?  Well, the previous application TestHarness.java did that as well.

The "subscribe" method subscribes to a particular service, method and return data type. When that method is executed a message comes back with the return value.  One of the signatures for subscribe is the following :

subscribe(outMethod, serviceName, inMethod, params ...)

 

        mrl.subscribe("log", "logger", "receive", Message.class);

 

The TestHarness.java program subscribed to the log method of the logger service. Here is an example of what 

    @Override
    public void receive(Message msg) {
        System.out.println(msg.data[0]);        
    }
printed out to the console : 
 
{"MSGID":"null""timeStamp":"""name":"logger""sender":"myApp""sendingMethod":"send""status":"null""msgType":"null""method":"log""dataClass":"java.lang.String""data":"[Ljava.lang.Object;@3f96ee"}
 
This represents Messages coming from MyRobotLab and being sent to our client application.
 
FInally this is what the GUIService looks like after the TestHarness.java has run.
 
The route from the logger to myApp was put in when 
        mrl.subscribe("log", "logger", "receive", Message.class);
was executed.  You can see some routes already existed from the logger to the gui.  This is because when the gui service starts it checks the registery and sets up some route which might be appropriate.  One of these routes is from the logger to graphics "logger" tab - so that the messages would display in the gui.
 
Notice also there are no routes to the remote adapter, although the MRLClient sends them directly to the RemoteAdapter listening on port 6767, the RemoteAdapter routes the messages automatically to the appropriate service.  The lines and arrows in the graph are more closely akin to adapters and listeners.  The arrows are pointing to services which have registered for events/messages from other services.