YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Portmonitors
+ Collaboration diagram for Portmonitors:

Modules

 Examples
 Examples and tutorials about portmonitors.
 
 Available Portmonitors
 List of available portmonitors.
 

Detailed Description

What is a carrier?

In short, it is an extended functionality of a port implemented as a new carrier which allows to dynamically load at run–time script (or dynamically linked libraries such as .so/.dll) and plug it into the port of an existing module without changing the code or recompiling it. Using run-time scripts (currently written in Lua) or DLLs we can access and modify the data traveling through the port using a simple API. In this way extra functionalities of a component can be added during application development time and without the need to modify and rebuild the component itself.

Which functionalities are we talking about?

An example of port monitor. The output port of FaceDetector modules is extended with a plug-in which provides access to the outgoing data through scripting language (e.g., Lua)

What do I need to use portmonitor carrier?

How can I use port monitor?

You should connect two ports using the YARP 'portmonitor' carrier modifier and explicitly tells the carrier which type of plug-in you are using (lua or dll):

  $ yarp connect /out /in tcp+recv.portmonitor+type.lua+context.myapp+file.my_lua_script

This rather weird syntax can be read as follow. Connect port /out to /in using the tcp transport protocol. Chain the receiver (recv) side of the port /in to the plugin portmonitor with parameters: type=lua, context=myapp and file=my_lua_script ('.' here can be indeed interpreted as an assignment operator).

This connects '/out' to '/in' using tcp and a portmonitor carrier modifier on the receiver side. Alternatively the script can be plugged into the sender port:

  $ yarp connect /out /in tcp+send.portmonitor+type.lua+context.myapp+file.my_lua_script

or a DLL can be loaded instead of the Lua script:

  $ yarp connect /out /in tcp+send.portmonitor+type.dll+file.my_dll_file

Portmonitor life cycle and API

The life cycle of port monitor.

A callback function is assigned to each state (except Waiting) which can have a corresponding implementation in the user’s script. Using these callbacks, users have full control over the port’s data and can access it, modify it and decide whether to accept the data or discard it. The Port Monitor starts in the Create state in which ‘PortMonitor.create’ callback is called. The initialization of the user’s code can be done at this point. Returning a true value means that the user’s initialization was successful and the monitor object is able to start monitoring data from the port. When data arrives to the monitor, ‘PortMonitor.accept’ is called and an instance of YARP ‘Things’ object is passed to the callback function. In this callback, user can access (for reading purposes only) the data, check it and decide whether to accept or discard it. The return value of this function indicates whether the data should be delivered (accepted) or discarded. If the data is accepted, ‘PortMonitor.update’ is called, at which point the user has access to modify the data.

    PortMonitor.create = function(options)
        ...
        return true     --default
    end
    PortMonitor.destroy = function()
        ...
    end
    PortMonitor.accept = function(thing)
        ...
        return true     --default
    end
PortMonitor.update = function(thing)
    ...
    return thing
end
PortMonitor.update_reply = function(thing)
    ...
    return thing
end
PortMonitor.setparam = function(param)
    ...
end

PortMonitor.getparam = function()
    ...
    return param
end
PortMonitor.trig = function()
    ...
end
Note
Port monitor carrier looks for the global table name 'PortMonitor' in the user script and calls its corresponding functions if exist. Notice that the PortMonitor is a global variable and should not be altered or assigned to nil.
Here we only described the callbacks in Lua scripting language. Indeed the same callbacks are also available in C++ for implementing plug-ins as DLLs. Please refer to simple_dll for the details.

Port Arbitration

A port arbitrator is an extended functionality of an input port which can be configured to arbitrate data from multiple source based on some user–defined constraints.

An example of using port arbitrator (left) and the architecture of port arbitrator (right). Straight lines show the data flow and zigzag lines represent event flows

A port arbitrator consists of multiple port monitors, a set of selection constraints, an event container and a selector block. Port arbitrator extends the port's scripting API for setting constraints and altering events in the container. In fact, when a port monitor is used in an arbitrator, the user's script can access the extended API for arbitration.

A port monitor can be attached to each connection (Ci) going through the port arbitrator. It monitors the data from connection and inserts the corresponding events into a shared container. A port monitor can also remove an event (if previously inserted by itself) from the container. Normally events have infinite life time. This means that they remain valid in the container until they are explicitly removed by the monitor object. An event can also have a specific life time. A time event will be automatically removed from the container when its life time is over. For each connection Ci , there is a selection constraint written in first order logic as a boolean combination of the symbolic events. Upon the reception of data from a connection, the selector evaluates the corresponding constraint and, if satisfied, it allows the data to be delivered to the input port; otherwise the data will be discarded.

Beside the port monitor callbacks, there is a set of auxiliary functions which is offered by the PortMonitor. These auxiliary functions are used for the port arbitration (See An example of using port monitors for arbitrating multiple connections).

Examples and tutorials

See the Examples page

Further reading

See also [4] and [5]