Overview

ROSClingo provides a generic way by which an ASP program may be used within the popular open-source Robot Operating System (ROS). To be more precise, the ROSClingo package integrates the ASP solver clingo 4 into the ROS service and actionlib architecture. The ROSoClingo package is build on top of ROSClingo and is specialized for the purpose of (interactive) task planning for robots. By running as a ROS actionlib ROSoClingo provides an elegant way to processes observations and requests issued. ROSoClingo provides a number of solving modes specialized for different user scenarios and allows for an easy customation of the solving precedure.

Installation

The ROS(o)Clingo package is build for ROS indigo on ubuntu 14.04, although ROS hydro on ubuntu 12.04 was also tested. And depends on the python module of gringo (version 4.5.4). In the follwing it is assumed that ubuntu 14.04 is used and running.

ROSClingo

Setup necessary libraries

A c++11 conforming compiler, gcc version 4.8 (earlier versions will not work):

sudo apt-get install gcc-4.8 <br>
sudo apt-get install g++-4.8

Bison and other tools for parsing and making:

sudo apt-get install bison
sudo apt-get install re2c
sudo apt-get install scons

NOTE: the above automatically pulls in the correct versions of the following tools/libraries (provided Ubuntu 14.04 is used); for more advanced setups, see the Gringo INSTALL file.

Installing ROS

To install ROS indigo please follow steps from the ROS page. Afterwards you need to set up a catkin workspace. You find a tutorial explaining how to do so here.

Download and build gringo.so python module

You need to build the gringo python module (4.5.4) on your computer. You can obtain the source here. Note that this can be placed anywhere in your filesystem. Unpack the archive, cd into the unpacked folder (gringo-4.5.4-source), and do the following:

scons configure --build-dir=release

You will then need to to configure the build/release.py file. Assuming you are using python2.7 and it is located in /usr/include/python2.7 modify the following variables in build/release.py:

CPPPATH = ['/usr/include/python2.7']
WITH_PYTHON = 'python2.7'
WITH_TBB = 'tbb'

Now run:

scons --build-dir=release pyclingo

Finally, add to ~/.bashrc the line - replacing ${GRINGO_PATH} with the path to the gringo-4.5.4 source folder:

PYTHONPATH=$PYTHONPATH:${GRINGO_PATH}/build/release/python/

Build ROSClingo

Download and install the software - replacing ${CATKIN_PATH} with the path for your catkin workspace:

cd ${CATKIN_PATH}/src
wget https://www.cs.uni-potsdam.de/wv/projects/rosoclingo/rosclingo-2.0.tar.xz
tar -zxvf rosclingo.tar.gz
cd ..
catkin_make

ROSoClingo

After ROSClingo is installed correctly download and install ROSoClingo - replacing ${CATKIN_PATH} with the path for your catkin workspace:

cd ${CATKIN_PATH}/src
wget https://www.cs.uni-potsdam.de/wv/projects/rosoclingo/rosoclingo-2.0.tar.xz
tar -zxvf rosoclingo.tar.gz
cd ..
catkin_make

ROSClingo

Usage

Startup

When starting ROSClingo you may pass gringo control options as command line parameter. In addition you may use -f PATH_TO_FILE to add ASP encodings to clingo.

Service

While ROSClingo is running it provides a service rosclingo/control to modify the encoding. The service expects a ROSClingoControl type as parameter consisting of a XML string describing the modifications. The following commands are currently supported:

add, assign_external, cleanup_domains, ground, load, release_external, restart, get_externals, get_stats

With the exception of the last three, the commands correspond directly to the functions described at http://potassco.sourceforge.net/gringo.html The command get_externals returns all external atoms of the current grounding, while get_stats returns the stats of the solver. The restart command generates a new solver object with the comandline arguments given at program start. All commands must be enclosed in a <commands> tag and are executed in order. Example:

<commands>
<add name=NAME_OF_THE_PROGRAM_TO_BE_ADDED>
    <parameter_definition  name=NAME_OF_THE_PARAMETER/>
    ...
    <program> PROGRAM </program>
</add>
<assign_external name=EXTERNAL_TO_BE_ASSIGNED value=TRUTH_VALUE_TO_BE_ASSIGNED/>
<cleanup_domains/>
<ground>
    <program name=NAME_OF_THE_PROGRAM_TO BE_GROUNEDED>
        <parameter value=VALUE_OF_THE_PARAMETER/>
        ...
    </program>
    ...
</ground>
<load file=PATH_TO_THE_FILE/>
<release_external name=EXTERNAL_TO_BE_RELEASED/>
<get_externals/>
<get_stats/>
<restart/>
</commands>

The return value of a service call is a xml string with the requested information, as well as information whether the commands where executed successfully, i.e.:

<return>
<success>
    True
</success>
</return>

Actionlib

For solving the ASP problem ROSClingo provides an Acationlib interface. A solving request is issued by sending ROSClingo a ROSClingoGoal data type. ROSClingoGoals consist of a XML string describing the assumption given to Clingo for the solve call.

<assumptions>
<assumption name=ATOM_TO_BE_ASSUMED value=TRUTH_VALUE_OF_THE_ATOM/>
...
</assumptions>

The result of a ROSClingo solve call is of the type ROSClingoResult and includes three values:

Please note that calling the ROSClingo service while a goal is issued results in ROSClingo aborting the request.

Examples

Running the one-shot blocks world example

The one-shot approach tries to solve the problem given as an instance with a fixed number of actions do/3. The number of actions may be changed via command line parameter of rosclingo -c max=N. The default is 14. Please run in different terminals:

roscore
rosrun rosclingo run.py -f [PATH TO rosclingo]/example/instance.lp -f [PATH TO rosclingo]/example/toh.lp
python [PATH TO rosclingo]/example/start.py

The expected outcome in the last terminal is:

##### result
result: sat
interrupted: False
answerset: ['do(arm,putdown(2),12)', 'do(arm,putdown(1),10)', 'do(arm,pickup(2),5)', 'do(arm,putdown(4),4)', 'do(arm,pickup(3),11)', 'do(arm,putdown(3),6)', 'do(arm,pickup(4),1)', 'do(arm,putdown(b),2)', 'do(arm,pickup(4),13)', 'do(arm,pickup(3),3)', 'do(arm,pickup(1),7)', 'do(arm,putdown(3),14)', 'do(arm,putdown(c),8)', 'do(arm,pickup(2),9)']
#####

Running the incremental blocks world example

The incremental approach tries to solve the problem by increasing the number of allowed actions each time the solver returns unsat as result. WARNING: This may result in an infinite loop, if no solution is possible. Please run the following commands in different terminals to run the example:

roscore
rosrun rosclingo run.py -f [PATH TO rosclingo]/example/instance.lp -f [PATH TO rosclingo]/example/itoh.lp
python [PATH TO rosclingo]/example/istart.py

The expected outcome in the last terminal is:

solving with horizon 0
solving with horizon 1
solving with horizon 2
solving with horizon 3
solving with horizon 4
solving with horizon 5
solving with horizon 6
solving with horizon 7
solving with horizon 8
solving with horizon 9
solving with horizon 10
solving with horizon 11
solving with horizon 12
solving with horizon 13
solving with horizon 14
##### result<br>
result: sat<br>
interrupted: False<br>
answerset: ['do(arm,pickup(4),13)', 'do(arm,putdown(1),10)', 'do(arm,pickup(3),3)', 'do(arm,putdown(3),14)', 'do(arm,pickup(3),11)', 'do(arm,pickup(2),9)', 'do(arm,putdown(c),8)', 'do(arm,pickup(4),1)', 'do(arm,putdown(4),4)', 'do(arm,pickup(2),5)', 'do(arm,putdown(2),12)', 'do(arm,putdown(3),6)', 'do(arm,pickup(1),7)', 'do(arm,putdown(b),2)']<br>
#####

ROSoClingo

ROSoClingo Architecture

Usage<

To function properly ROSoClingo needs two running instances of ROSClingo named “controller” and “planner”. The planner holds the ASP programm generating the task plan while the controller controls its execution. For communication purposes ROSoClingo provides an actionlib interface to issue requests to the planner and two topics for incoming / outcoming messages. Their usage is optional and depends on the mode the controller is running.

Controller

The controller modifies the planner’s encoding as well as the execution of the found task plan. There are currently 5 modes implemented available to be used in the rosoclingo/modes folder.

static.fixed.recording.lp
static.incremental.recording.lp
dynamic.fixed.recording.lp
dynamic.incremental.recording.lp
dynamic.incremental.reset.lp
dynamic.incremental.dyn_reset.lp

A static mode ignores all outside input and publishes the task plan to the topic /rosoclingo/out, if one is found, and terminates rosoclingo if no plan is possible within a maximal horizon. A dynamic mode forwards received messages and goal requests to the planner and organizes a successive execution of the task plan’s actions. The mode terminates rosoclingo if the maximum horizon is reached with no task plan. A fixed mode grounds the planer’s encoding to the maximal horizon before trying to find a task plan. If the planner returns unsatisfiable, rosoclingo is terminated. An incremental mode only extends the planner’s horizon if no plan is found for the current one. After the extension the planner is called again to find a plan with the new horizon. This continues until either a plan is found or the maximum horizon is reached in which case rosoclingo terminates. A recording mode keeps all information accumulated during plan execution. The reset mode sets the current state as inital state every specified number of steps, thus forgetting all information between these steps. The dyn_reset mode functions as the reset mode, with the exception that the reset is initialized each time a goal request is terminated and not every number of steps. The maximum horizon may be changed via command line option -c steps=S and the number of steps before reset with -c r=R. Both S and R are integers. To implement these modes the controller’s encoding must respect the following special key words:

Currently the following commands are supported by rosoclingo. Additional commands may be added into the ROSCommands class in the rosoclingo/nodes/commands.py file.

Planner

The planner’s encoding is divided into four program parts.

To function properly with rosoclingo the planner’s encoding must respect the following special predicates:

As well as the externals:

Actionlib Interface

A ROSoClingo actionlib goal has the format ROSoClingoGoal(string request, string[] information). With request being the goal forwarded to the planner and information an array containing additonal information about the goal not needed by the solver but by other ROS nodes. The gringo.parse_term function must be able to parse the string request, i.e. request must resemble an ASP atom.

Communication Interface - Topics

ROSoClingo opens two topics rosoclingo/in for messages to rosoclingo and by extension the planner and rosoclingo/out for messages from rosoclingo to other ROS nodes. The message format of rosoclingo/in is ROSoClingoIn(string id, string value), with id identifying the source of the message and value its content. An incoming message results in the controller external event(info,new_messages,0) to become true until the command assign_messages is issued. The string value must be parsable by gringo.parse_term.

Analog to rosoclingo/in, the message format of rosoclingo/out is ROSoClingoOut(string id, string action), with id identifying the actuator requested to execute an action. Note that the controller’s external event(info,pending_actions,0) is true as long as the set of outgoing_messages.id is not a subset of the set incoming_messages.id. Meaning that each action issued to an actuator needs a response from the actuator signifying the termination of the action’s execution.

Examples

Some of the examples need you to get additional packages in your catkin workspace:

cd ${CATKIN_PATH}/src
wget https://www.cs.uni-potsdam.de/wv/projects/rosoclingo/examples.tar.xz
cd ..
catkin_make

Running the incremental blocks world example

This runs the incremental blocks world problem from the ROSClingo package. NOTE: In contrast to the ROSClingo example this one has an upper limit for the number of actions to solve the problem (specified py steps). Thus no infinite loop is possible. Pelease run in different terminals:

roscore
rosrun rosclingo run.py __name:=controller -f [PATH TO rosoclingo]/modes/static.incremental.recording.lp -c steps=20
rosrun rosclingo run.py __name:=planner -f [PATH TO rosclingo]/example/instance.lp -f [PATH TO rosclingo]/example/itoh.lp
rosrun rosoclingo run.py run.py
rostopic echo /rosoclingo/out

The expected outcome on the /rosoclingo/out topic is:

id: solver
action: [do(arm,pickup(4),13), do(arm,putdown(2),12), do(arm,pickup(2),9), do(arm,putdown(b),2), do(arm,pickup(4),1), do(arm,putdown(3),6), do(arm,pickup(1),7), do(arm,pickup(3),3), do(arm,putdown(4),4), do(arm,putdown(c),8), do(arm,pickup(2),5), do(arm,putdown(1),10), do(arm,putdown(3),14), do(arm,pickup(3),11)]
---

Running the mailbot example in a static mode

A robot is given requests of delivering objects from one office to an other. Whenever a delivery request is issued, the robot has to navigate to the office requesting the delivery, pick up the respective object, and then navigate and deliver the object at the destination office. Requests may be canceled at any time, resulting in the object being delivered back to it’s origin if already picked up. To start the example in a static.fixed.recording mode please run the following commands in different terminals:

roscore
rosrun rosclingo run.py __name:=controller -f [PATH TO rosoclingo]/modes/static.fixed.recording.lp -c steps=14
rosrun rosclingo run.py __name:=planner -f [PATH TO rosoclingo_aspprograms]/mailbot/instances/graph_bench.lp -f [PATH TO rosoclingo_aspprograms]/mailbot/mailbot/requests/request01.lp -f [PATH TO rosoclingo_aspprograms]/mailbot/mailbot -c slots=1 -c x=2 -c y=2
rosrun rosoclingo run.py run.py

The graph_bench.lp file contains a description of the environment as shown in the figure below with 1 to 4 being offices to pickup and deliver package. The starting position of the mailbot is c(1). The request01.lp file contains the request bring(1,3) issued at time step 0, stating that the robot should deliver a package from office 3 to office 1. The task plan found is published in the /rosoclingo/out topic. The same problem may be solved in an incremental mode by changing static.fixed.recording above into static.fixed.recording.

Running the mailbot example in a dynamic mode

To utilitize dynamic modes a ROSoClingo client node needs running to issue requests and actions issued by ROSoClingo need to be executeded (or simulated). The following commands start ROSoClingo in dynamic.incremental.recording mode:

roscore
rosrun rosclingo run.py __name:=controller -f [PATH TO rosoclingo]/modes/dynamic.incremental.recording.lp -c steps=14
rosrun rosclingo run.py __name:=planner -f [PATH TO rosoclingo_aspprograms]/mailbot/instances/graph_bench.lp -f [PATH TO rosoclingo_aspprograms]/mailbot/mailbot -c slots=1 -c x=2 -c y=2
rosrun rosoclingo run.py run.py
rosrun rosoclingo_interfaces fulfill.py
rosrun rosoclingo_examples mailbot_manual.py

The dynamic.incremental.recording mode may be changed to another dynamic mode to experiment. Note that the dynamic.fixed.recording mode may cause problems because requests are not issued fast enough before the task plan is executed.

Running the mailbot example with gazebo simulation

The environment is now simulated by the Gazebo 3D simulator using an openly accessible world model available for the Willow Garage offices. The robot is a TurtleBot equipped with a Microsoft Kinect 3D scanner, which is a cost-effective and well supported robot suitable for small delivery tasks. To start the example please run the following commands in different terminals:

export ROBOT_INITIAL_POSE="-y -8 -x 7 -z 0 -R 0 -P 0 -Y 0"
roslaunch rosoclingo_gazebo mailbot_scenario.launch

This sets up and starts the gazebo simulator. The Willow Gerage environment is loaded and the turtle bot is placed in an open space (open1).

rosrun rosoclingo run-1.0.py --file [PATH TO rosoclingo_aspprograms]/mailbot/instances/graph_wg.lp --file [PATH TO rosoclingo_aspprograms]/mailbot/mailbot.lp

This terminal runs the ROSoClingo actionlib server with an ASP encoding of the mailbot problem and an instance file describing the Willow Gerage environment.

roslaunch rosoclingo_interfaces mailbot_interfaces.launch

This terminal runs the interface layer, transforming actions found in the task plan into actionlib requests. Note that while go actions are simulated by gazebo, pickup and deliver actions are abstracted into just succeeding.

 rosrun rosoclingo_examples mailbot.py

This terminal runs a ROSoClingo actionlib client. To issure requests to the mailbot, please specify the origin, the destination and the object. E.g. to deliver a box of chocolate from o9 to o14 type o9 o14 box_of_chocolate.

This instance of the mailbot problem supports office o1-o14 and any kind object (string without space). Requests issued may be canceled by typing the request id provided. Any number of requests may be issued, but only 3 will be considered by the ASP encoding at the same time. All others wait until a slot becomes available.

If the robot is not able to traverse a path (e.g. because it is blocked by an obstacle) the ASP encoding derives this information from a failed go action and tries to find an alternative route. You may declare paths as (un-)blocked yourself by running the un_block interface in a new terminal:

rosrun rosoclingo_interface un_block.py

With b FORM TO the path from FROM to TO is marked as blocked and with u FROM TO unblocked again. All paths between waypoints may be found in the instance file graph_wg (named connection(FROM,TO)).

Literature

Videos

Legacy