In this tutorial we are going to present how to synchronise an RDF Graph between multiple agents. Each agents run its own kDB server. There are two transports available for the automatic RDF Graph Synchronisation, one using ROS topics and the other one using a MQTT broker. The ROS topics approach allows a fully decentralized system. While the MQTT approach allows to interoperate with non-ROS systems, or in case isolation is implemented through the use of ROS domain id. At the moment, it is not possible to synchronise the same RDF Graph using both ROS topics and a MQTT broker.

Setting up

For this tutorial, we will use three agents, with namespaces agent0, agent1, agent2. In three different terminals, the ROS kDB server for each of those agents can be started with:

ros2 run ros_kdb kdb_server --ros-args -r __ns:=/agent0 -p db_port:=10142
ros2 run ros_kdb kdb_server --ros-args -r __ns:=/agent1 -p db_port:=10143
ros2 run ros_kdb kdb_server --ros-args -r __ns:=/agent2 -p db_port:=10144

And we will synchronise an RDF Graph that contains a semantic map of the environment, as used in the triple stores tutorial. Synchronisation of a graph can be initiated using a krQL query, which can be executed using the kdb_server/krql_query service call (or as a parameter to the ROS kDB Server, as shown in the configuring kDB Server tutorial).

Synchronisation using ROS2 transport

The following krql query will be used to start a synchronisation using ROS2 transport for the http://askco.re/examples#map RDF Graph:

start graph sync: { uri: http://askco.re/examples#map }

This can be done by running the following command line:

ros2 service call /agent0/kdb_server/krql_query ros_kdb_interfaces/srv/QueryDatabase 'queries: [ { query: "start graph sync: { uri: http://askco.re/examples#map }"} ]'
ros2 service call /agent1/kdb_server/krql_query ros_kdb_interfaces/srv/QueryDatabase 'queries: [ { query: "start graph sync: { uri: http://askco.re/examples#map }"} ]'
ros2 service call /agent2/kdb_server/krql_query ros_kdb_interfaces/srv/QueryDatabase 'queries: [ { query: "start graph sync: { uri: http://askco.re/examples#map }"} ]'

The service call should show the following if it was successful:

ros_kdb_interfaces.srv.QueryDatabase_Response(results=[''], successes=[True], success=True)

Or for instance, if an error occurs, it should show an error such as:

ros2 service call /agent1/kdb_server/sqm_query ros_kdb_interfaces/srv/QueryDatabase 'queries: [ { query: "start graph sync: { uri: http://askco.re/examples#map }"} ]'

Synchronisation using MQTT transport

The following krql query will be used to start a synchronisation using MQTT transport, with a localhost broker, for the http://askco.re/examples#map RDF Graph:

start graph sync: 
  uri: http://askco.re/examples#map
  transport: mqtt
  mqtt_broker: tcp://localhost:1883

For this example to run, it is necesserary to have a running MQTT broker on localhost, for instance, by installing the mosquitto broker. Alternatively, it is possible to use a broker on a distance machine, this would require to adjust the mqtt_broker field above.

This can be done by running the following command line:

ros2 service call /agent0/kdb_server/sqm_query ros_kdb_interfaces/srv/QueryDatabase 'queries: [ { query: "start graph sync: { uri: http://askco.re/examples#map, transport: mqtt, mqtt_broker: tcp://localhost:1883 }"} ]'
ros2 service call /agent1/kdb_server/sqm_query ros_kdb_interfaces/srv/QueryDatabase 'queries: [ { query: "start graph sync: { uri: http://askco.re/examples#map, transport: mqtt, mqtt_broker: tcp://localhost:1883 }"} ]'
ros2 service call /agent2/kdb_server/sqm_query ros_kdb_interfaces/srv/QueryDatabase 'queries: [ { query: "start graph sync: { uri: http://askco.re/examples#map, transport: mqtt, mqtt_broker: tcp://localhost:1883 }"} ]'

Adding data and testing synchronisation

To test the synchronisation of data between the three agents, we need to start modifying the triple store in http://askco.re/examples#map. For details on how to do that we suggest checking the Getting Started with ROS or the triple stores tutorials. For the purpose of this tutorials we have prepared three turtle files that can be loaded in the triple stores: map_0.ttl, map_1.ttl and map_2.ttl.

To load the content of map_0.ttl in agent0 database:

ros2 service call /agent0/kdb_server/insert_triples ros_kdb_interfaces/srv/InsertTriples "
graphname: 'http://askco.re/examples#map'
format: 'ttl'
content: '`cat map_0.ttl`'"

The following command can then be used to query the database to check the results:

ros2 run ros_kdb pretty_query --sparql --default-dataset "http://askco.re/examples#map" "PREFIX ex: <http://askco.re/examples#>
PREFIX ssn: <http://www.w3.org/ns/ssn/>

SELECT ?object_uri ?class ?xcoord ?ycoord
{ 
  ?object_uri a ?class ;
        ex:location [ ex:x ?xcoord; ex:y ?ycoord ] .
}" --ros-args -r __ns:=/agent0

Replace agent0 with agent1 and agent2 to check in the database of other agents. For all agents, it should show:

0 http://askco.re/examples#03643194-0cbe-4701-89e5-8dd1f758e09e http://askco.re/examples#table http://www.w3.org/2001/XMLSchema#decimal(10.0) http://www.w3.org/2001/XMLSchema#decimal(12.0)

If it does not, wait a few seconds and try again, there can be delay in the synchronization.

As an exercise, you can use map_1.ttl and map_2.ttl to add data in other agents and check how it propagate.