YARP  2.3.70
Yet Another Robot Platform
Using port monitors for arbitrating multiple connections
Author
Ali Paikan

Description

This example demonstrates how to use port monitor to coordinate different modules by arbitrating their connections in the input port. Each port monitor can be set with a selection rule (constraint). The rule is simply written in first order logic (boolean expression) based on some symbolic name. We call these symbols as events. Port monitors from peer connections (the connections to the same input port) can set (add) or unset (remove) events in a shared event record. If an event is set, it has a true value in the corresponding boolean expression; otherwise it is false. When data arrives to the port from a connection, the corresponding port monitor evaluate the boolean expression and if it is true (the constraint is satisfied), the data can be delivered to the port; otherwise it is discarded.

A port monitor can set the selection rule (for its own connection) using `PortMonitor.setConstraint()'. For example:

    PortMonitor.setConstraint("e_line_selected and not e_ball_selected")

Or to set or unset an event:

    PortMonitor.setEvent("e_line_selected")
    PortMonitor.unsetEvent("e_line_selected")

The following keywords are reserved and cannot be used for event's name:

    { true, false, not, and, or }

This simple example shows the arbitration of two different connections to the same port of "yarpview" using Port Monitor object.


arbitration.png

The connection from the third "test_grabber" module (/Selector/grabber) is used as an auxiliary connection to choose between "/Ball/grabber" and "/Line/grabber". To achieve this, its selection rule in the 'selector_monitor.lua' is simply set to 'false'. The module runs in low frequency (every 3 seconds) and plays as a selector between two other modules by setting/removing some events which are used as constraint in 'ball_monitor.lua' and 'line_monitor.lua'. As the result, yarpview switches between different images coming from "/Ball/grabber" and "/Line/grabber" periodically.

Requirements

  • Enable and compile portmonitor carrier (ENABLE_yarpcar_portmonitor_carrier=ON in YARP cmake).
  • Set LUA_CPATH to include Yarp-Lua binding library (e.g., export LUA_CPATH=";;;$YARP_ROOT/build/lib/lua/?.so")

Running the example

  • Open a terminal and run yarpserver
       $ yarpserver
    
  • Open another terminal (lets call this the receiver terminal) )and change to the 'image_modification' directory and run the application using yarpmanager:
       $ cd $YARP_ROOT/example/portmonitor/arbitration
       $ yarpmanager-console --application TestArbitratorImage.xml 
    
  • run the modules and connect the ports
       >> run
       >> connect
    
  • To stop the application, in the yarpmanager's console, type:
        >> stop
        >> exit
    

Scripts

ball_monitor.lua

-- loading lua-yarp binding library
require("yarp")

--
-- create is called when the port monitor is created 
-- @return Boolean
--
PortMonitor.create = function()
    -- set the constraint here 
    PortMonitor.setConstraint("e_ball_selected")
    return true;
end

line_monitor.lua

-- loading lua-yarp binding library
require("yarp")

--
-- create is called when the port monitor is created 
-- @return Boolean
--
PortMonitor.create = function()
    -- set the constraint here 
    PortMonitor.setConstraint("e_line_selected")
    return true;
end

sel_monitor.lua

-- loading lua-yarp binding library
require("yarp")

--
-- create is called when the port monitor is created 
-- @return Boolean
--
PortMonitor.create = function()
    -- set the constraint here 
    -- Notice that we never want to receive image data from
    -- this connection (/Selector/grabber)
    PortMonitor.setConstraint("false")       
    switchDisplay = false;
    return true;
end

-- 
-- destroy is called when port monitor is destroyed
--
PortMonitor.destroy = function()
    -- unset the all events on destroy
    PortMonitor.unsetEvent("e_line_selected")
    PortMonitor.unsetEvent("e_ball_selected")
end

--
-- accept is called when the port receives new data
-- @param thing The Things abstract data type
-- @return Boolean
-- if false is returned, the data will be ignored 
-- and update() will never be called
PortMonitor.accept = function(thing)
    print("selector: PortMonitor.accept()")
    if switchDisplay == true then
        switchDisplay = false
        PortMonitor.unsetEvent("e_line_selected")
        PortMonitor.setEvent("e_ball_selected")
    else
        switchDisplay = true
        PortMonitor.setEvent("e_line_selected")
        PortMonitor.unsetEvent("e_ball_selected")
    end
    return true
end