ROS(o)Clingo

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.

Contents

1.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.

1.1 ROSClingo

1.1.1. Setup necessary libraries

A c++11 conforming compiler, gcc version 4.8 (earlier versions will not work):
sudo apt-get install gcc-4.8
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.

1.1.2. Installing ROS

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

1.1.3. 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-4.5.4} with the path to the gringo-4.5.4 source folder:
PYTHONPATH=$PYTHONPATH:${gringo-4.5.4}/build/release/python/

1.1.4. Build ROSClingo

Download and install the software - replacing ${CATKIN_PATH} with the path for your catkin workspace:
cd ${CATKIN_PATH}/src
wget http://cs.uni-potsdam.de/rosoclingo/2.0/rosclingo.tar.gz
tar -zxvf rosclingo.tar.gz
cd ..
catkin_make

1.2. 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 http://cs.uni-potsdam.de/rosoclingo/2.0/rosoclingo.tar.gz
tar -zxvf rosoclingo.tar.gz
cd ..
catkin_make

2. ROSClingo

2.1. Usage

2.1.1. 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.

2.1.2. 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 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>

2.1.3. 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.
Example:
<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:
result a string (either "sat", "unsat" or "unknown") stating the result of the clingo solve call
interrupted a boolean indicating whether the solving process was interrupted or not
answerset the answer set as a list of strings
Please note that calling the ROSClingo service while a goal is issued results in ROSClingo aborting the request.

2.2. Examples

2.2.1. 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)']
#####

2.2.2. 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
result: sat
interrupted: False
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)']
#####

3. ROSoClingo

ROSoClingo Architecture

3.1. 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.

3.1.1. 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:
do(controller,Command,1) Stating that rosoclingo should execute Command.
holds(Fluent,1) Stating that Fluent should be set to true in the controller's next solve call.
event(save,Fluent,0)) An external stating that the inital value of Fluent is true.
event(info,result(sat),0) An external stating that the last solve call of the planner was satisfiable.
event(info,result(unsat),0) An external stating that the last solve call of the planner was unsatisfiable.
event(info,pending_actions,0) An external stating that the rosoclingo system still has pending actions (see below /rosoclingo/out topic).
event(info,new_messages,0) An external stating that the rosoclingo system still has messages that need to be forwarded to the planner (see Actionlib and /rosoclingo/in topic).
event(info,request_reset,0) An external stating that a reset of the planner is requested.
Currently the following commands are supported by rosoclingo. Additional commands may be added into the ROSCommands class in the rosoclingo/nodes/commands.py file.
assign_externals(E,V) Assigns the value V to the external E in the planner's encoding (same as the gringo.so function).
assign_messages(T) Sets the external event(ID,V,T) to true for all currently pending messages, with ID = message.id and V = message.value.
commit_actions(T) Publishes a ROSoClingoOut(R,A) message to the /rosoclingo/out topic for each yet unpublished action do(R,A,T) of the time step T. Also sets the planner's external event(commit,do(R,A),T) to true.
exit Terminates rosoclingo.
ground(T) Grounds the planner's state, transition and query program part with T as parameter.
idle Does nothing.
initialize Grounds the planner's base program part as well as the state and query program part with 0 as parameter.
publish Publishes the planner's answer set to the /rosoclingo/out topic.
release_external(E) Releases the external E in the planner's encoding (same as the gringo.so function).
release_step(T) Releases all externals of the time step T that are not made true previously.
reset(T) Sets all event externals to false and afterwards event(save,F,0) to true for all fluents F that are true at time step T. Also deletes all tracted commited actions and messages in the rosoclingo system as well as freeing all terminated goal request slots for later use.
solve Issues a solve request to the planner.
status_update(T) Updates all goal requests issued to rosoclingo in respect to time step T of the task plan.

3.1.2. Planner

The planner's encoding is divided into four program parts.
base Containing all static domain information as well as the inital state and a definition of goal states.
state(t) Containing static fluent rules and external events.
transition(t) Containing action description and regular fluent rules.
query(t) Containing rules checking for a goal state.
To function properly with rosoclingo the planner's encoding must respect the following special predicates:
rslot(ID) A set of identifiers for goal requests. May be reused after the controller issued a reset command.
status(ID,S,T) Changing the status of the goal request ID to S at time step T. Allowed status are accepted, rejected, succeeded and canceled. These correspond to the actionlib status of ROS.
do(R,A,T) Requesting the execution of action A by actuator R at time step T.
holds(F,T) Identifying the fluent F as true at time step T. This is important for the reset command, and may be omitted if reset is not used.
As well as the externals:
query(T) Identifying the time step T as the current horizon of the task plan.
event(ID,Request,T) Connecting the goal identifier ID with a specific goal request Request at time step T.
event(ID,cancel,T) Stating that the goal request ID is cancelled at time step T.
event(commit,do(R,A),T) Committing the actuator R to action A at time step T of the task plan.
event(S,C,T) For each message the planner is able to receive, with S being the source of the message, C the content and T the time step the message is received. Note that this also includes all possible results C of an action the actuator S executed.

3.1.3. 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.

3.1.4. 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.

3.2. Examples

Some of the examples need you to get additional packages in your catkin workspace:
cd ${CATKIN_PATH}/src
wget http://cs.uni-potsdam.de/rosoclingo/1.0/rosoclingo_aspprograms.tar.gz
wget http://cs.uni-potsdam.de/rosoclingo/1.0/rosoclingo_examples.tar.gz
wget http://cs.uni-potsdam.de/rosoclingo/1.0/rosoclingo_interfaces.tar.gz
wget http://cs.uni-potsdam.de/rosoclingo/1.0/rosoclingo_robots.tar.gz
wget http://cs.uni-potsdam.de/rosoclingo/1.0/rosoclingo_gazebo.tar.gz
tar -zxvf rosoclingo_aspprograms.tar.gz
tar -zxvf rosoclingo_examples.tar.gz
tar -zxvf rosoclingo_interfaces.tar.gz
tar -zxvf rosoclingo_robots.tar.gz
tar -zxvf rosoclingo_gazebo.tar.gz
cd ..
catkin_make

3.2.1 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)]
---

3.2.2 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.recoding 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.

3.2.3 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.

3.2.4 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)").

4. Literature

  1. Benjamin Andres, David Rajaratnam, Orkunt Sabuncu and Torsten Schaub. Integrating ASP into ROS for Reasoning in Robotics. In Proceedings of LPNMR'15. [BibTeX] [PDF]
    1. Extended version
    2. Encoding
    3. Instance
  2. Benjamin Andres, Philipp Obermeier, David Rajaratnam, Orkunt Sabuncu and Torsten Schaub. ROSoClingo: A ROS package for ASP-based robot control. In CoRR, abs/1307.7398, http://arxiv.org/abs/1307.7398, 2013. [BibTeX] [PDF]
  3. Benjamin Andres, Philipp Obermeier, David Rajaratnam, Orkunt Sabuncu and Torsten Schaub. ROSoClingo: A ROS package for ASP-based robot control. In Proceedings of RSS-CP13, 2013. [BibTeX] [PDF]

5. Videos

Please visit our youtube channel to see ROSoClingo in action!

6. Legacy

You may find a version ROSoClingo 1.0 here.