First, you need to run the components you wish to control and the genomix server. For example, to use the 'demo-ros' compiled for the ROS middleware, run the following commands:
% roscore & # the ROS communication node. % genomixd & # A genomix server % demo-ros -b # The 'demo' component compiled for ROS.
Then, start MATLAB and make sure the
matlab-genomix installation directory is
% matlab & >> userpath('<prefix>/lib/matlab')
<prefix> is the path configured during the installation step).
From MATLAB, connect to the running genomix server. By default, the connection
is made on
8080, but this can be overriden by passing some
>> client = genomix.client('example.com:80'); % connection to example.com:80 >> client = genomix.client; % connection to localhost:8080 client = client with no properties.
On success, these commands return a
client handle returned by a successful connection to load new
components in MATLAB. Components may have specific load options. You can check
the available options before loading a given component with the extra
>> client.load('demo', '-h') ans = Usage: client.load('demo', [-h], [client options]) Client options: -i|--name instance name -t|--topic_timeout timeout subsciptions after that many seconds
For instance, loading the 'demo' component without specific options:
>> demo = client.load('demo') demo = component with properties: genom_state: [function_handle] Monitor: [function_handle] Stop: [function_handle] GetSpeed: [function_handle] abort_activity: [function_handle] MoveDistance: [function_handle] SetSpeed: [function_handle] Mobile: [function_handle] connect_service: [function_handle] connect_port: [function_handle] kill: [function_handle] GotoPosition: [function_handle]
On success, a handle on the
demo component is returned. Each property in the
returned handle is a service or port of the component.
In case of error, it might be that the client cannot be found automatically by
genomix. In this case, you need to specify the load path. This can be done
either by using the 'rpath' handle subcommand (see next section) or by
specifying the full path to the client.
genom3 clients are found in the
…/lib/genom/*/plugins directory, where
* denotes the middleware used,
so the following would be required if the demo ros client was installed to the
>> demo = client.load('/home/jdoe/lib/genom/ros/plugins/demo.so');
It can be inconvenient to specify the load path for each component. The
client handle command allows to specify a list of paths where genomix will
search in order.
demo ros client was for instance installed in the
the following can be used:
>> client.rpath('/home/jdoe/lib/genom/ros/plugins') ans = '/home/jdoe/lib/genom/ros/plugins' >> demo = client.load('demo');
You need to set the
rpath only once for all load requests done with a
client instance, but you can issue multiple
rpath commands in
order to specify a list of paths to be searched in order.
The component handle returned after a successful load is used to invoke remote services. Some services may require input arguments. If you don’t pass any, there are prompted interactively:
>> demo.GotoPosition(); double posRef: Goto position in m (0) > 1.0
posRef input argument was asked because
invoked without any argument.
You can also check the required input arguments by using the
>> demo.GotoPosition('-h') ans = Usage: demo.GotoPosition [-a|-ack] [-t|-timeout secs] [-f|-flat] [-args] [-h] [--] input [callback] Input dictionary: double posRef: Goto position in m (0)
Finally, you can pass required argument as a flat list, or using a MATLAB
struct with appropriate fields:
>> demo.GotoPosition(-1.0); >> s = struct(); >> s.posRef = 1.0; >> demo.GotoPosition(s);
request handle is returned for each invoked service. This handle can be
used to query the service result after completion:
>> r = demo.GetSpeed(); >> r.status ans = done >> r.result ans = speedRef: '::demo::SLOW'
A result is valid only if the request has the status
done. If the service
invocation was not successful, the request has the status
error and the
exception property of the request handle is filled with details:
>> r = demo.GotoPosition(2.0) r = request with properties: status: 'error' result:  exception: [1x1 struct] >> r.exception ans = ex: '::demo::TOO_FAR_AWAY' detail: [1x1 struct] >> r.exception.detail ans = overshoot: 1
All services can be invoked without blocking. This is especially useful for long lasting actions, where you do not want your MATLAB program to be blocked waiting for the completion of the service.
The first way to invoke a service asynchronously is to use the
-a option of
the service invocation:
>> r = demo.GotoPosition('-a', 1.0) r = request with properties: status: 'sent' result:  exception: 
Here the request handle
r is returned immediately. It has the status
initially, meaning that the request was successfully sent but has not completed
yet. Later on, it is possible to wait for completion with the
wait method of
the request handle, with or without a timeout:
>> r.wait(0.1) % wait at most 100ms Error using genomix.request/wait (line 125) timeout >> r.wait % wait until completion or error >> r r = request with properties: status: 'done' result: [1x1 struct] exception: 
Or you can also do some polling:
>> while strcmp(r.status, 'sent') pause(0.1); end
The second way to invoke a service asynchronously is to pass a callback as the last argument of a the service invocation:
>> r = demo.GotoPosition(0.0, @(r) disp(['callback with status: ' r.status])) callback with status: sent r = request with properties: status: 'sent' result:  exception: 
The callback function is invoked each time the request status is updated
sent. In the example above it is invoked when the status changes to
after a successful invocation.
Callback events are processed implicitly each time a 'genomix' object is
accessed (e.g. checking the status of any ongoing request, or calling any
service of any component, etc.). 'genomix' also provides an explicit
method in client handles for checking pending events, that can be invoked
anywhere in your code:
>> client.update callback with status: done
In this example, the callback registered in the previous request invocation was
triggered because the asynchronous request had completed at the time the
update method was invoked.
In addition to functions for calling services, it is also possible to read the
data ports of components. For instance, the
demo component has a port called
>> p = demo.Mobile() p = Mobile: [1x1 struct] >> p.Mobile ans = position: 0 speed: 0
Ports are always read synchronously.