Hello World

Goal: Setup a new package storing a simple CLIPS program.

Tutorial level: Beginner

Time: 20 minutes

Background

The basic usage of CLIPS involves having a CLIPS environment and some CLIPS code to run inside of it using the CLIPS inference engine.

Prerequisites

You will need to have the ROS2 CLIPS-Executive installed and sourced in your environment.

Hello World

The goal of this tutorial is to setup a CLIPS environment, such that it loads a small CLIPS program, which consists of a rule to print “hello world”, using the ROS2 CLIPS-Executive.

1 Workspace Setup

For the reminder of this tutorial, it is assumed that you work in a dedicated workspace cx_tutorial_ws:

mkdir -p ~/ros2/cx_tutorial_ws/src

Next, you will create a package that will be populated with CLIPS code:

ros2 pkg create --build-type ament_cmake --license Apache-2.0 cx_tutorial_agents --dependencies cx_bringup

In particular, let us create directories params and clips to host configuration files and CLIPS source code:

mkdir -p ~/ros2/cx_tutorial_ws/src/cx_tutorial_agents/{params,clips}

2 Install Directories via CMake

Make sure the new directories are also installed with the package by adding the following line to the CMakeLists.txt:

install(DIRECTORY params clips DESTINATION share/${PROJECT_NAME})

The full CMakelists.txt should look like this (after removing some unnecessary sections):

cmake_minimum_required(VERSION 3.8)
project(cx_tutorial_agents)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)

install(DIRECTORY params clips DESTINATION share/${PROJECT_NAME})

ament_package()

With the general setup out of the way, it is time to add some CLIPS code!

3 Adding a CLIPS File

Navigate to the clips directory and download the example CLIPS file using the following command:

cd ~/ros2/cx_tutorial_ws/src/cx_tutorial_agents/clips
 wget -O hello_world.clp https://raw.githubusercontent.com/fawkesrobotics/ros2-clips-executive/master/tutorials/cx_tutorial_agents/clips/hello_world.clp

This adds the file hello_world.clp, containing a simple rule that prints out hello world when it is fired:

(defrule hello-world
=>
  (println "hello world")
)

Here, the rule condition (statements before =>) is empty, meaning it can be fired in any situation. The Rule effect (statements after =>) is a function invocation for println, which logs a line (including newline characters CR+LF) to the stdout router (see also here).

In order to execute the code, a suitable configuration for the ROS2 CLIPS-Executive node is required to load the file into a CLIPS environment and to run it.

4 Configuring the ROS2 CLIPS-Executive

To achieve this, navigate to the params directory and download the example configuration file using the following command:

cd ~/ros2/cx_tutorial_ws/src/cx_tutorial_agents/params
wget -O hello_world.yaml https://raw.githubusercontent.com/fawkesrobotics/ros2-clips-executive/master/tutorials/cx_tutorial_agents/params/hello_world.yaml

This adds the file hello_world.yaml with the following content:

/**: # placeholder to work with any ROS node regardless of namespace
  ros__parameters:
    autostart_node: true
    environments: ["hello_world"]

    hello_world:
      plugins: ["files"]
      watch: ["facts", "rules"]

    files:
      plugin: "cx::FileLoadPlugin"
      pkg_share_dirs: ["cx_tutorial_agents"]
      load: ["clips/hello_world.clp"]

The top of the file specifies the ROS node(s) for which the parameters below it applies. Here you can use a placeholder /** that matches to any node name regardless of the namespace.

/**: # placeholder to work with any ROS node regardless of namespace
  ros__parameters:

Then, an environment with the name "hello_world" is created and the lifecycle node is instructed to activate itself on startup.

autostart_node: true
environments: ["hello_world"]

For this particular environment, the list of plugins is specified. In this case only a single plugin is needed (called files here). Further, the watch level of CLIPS is configured (see Basic Programming Guide (PDF)) to monitor both facts and rules.

hello_world:
  plugins: ["files"]
  watch: ["facts","rules"]

The FileLoadPlugin, which can load files to CLIPS environments. It is configured to look for files in the current package and to load the file created above.

files:
  plugin: "cx::FileLoadPlugin"
  pkg_share_dirs: ["cx_tutorial_agents"]
  load: ["clips/hello_world.clp"]

This concludes the setup for the example. The next step is to build and execute the code.

5 Running The Code

Now it is time to build the package and to source the workspace. We recommend to use a symlink-based installation so that changes to your installed CLIPS files are applied without the need to rebuild the package.

cd ~/ros2/cx_tutorial_ws/
colcon build --symlink-install
source install/setup.bash

In order to run the code you can run the cx_node directly and passing the parameter file to it:

cd ~/ros2/cx_tutorial_ws/
ros2 run cx_clips_env_manager cx_node  --ros-args --params-file src/cx_tutorial_agents/yaml/hello_world.yaml

Alternatively, you can use the launch file of the cx_bringup package, with the benefit of leveraging the ament index in order to lookup the location of the parameter file instead of relying on a full path:

ros2 launch cx_bringup cx_launch.py manager_config:=hello_world.yaml package:=cx_tutorial_agents

In either case, you will see in the log output that the rule was indeed fired:

[cx_node-1] [hello_world] [INFO] FIRE    1 hello-world: *
[cx_node-1] hello_world] [INFO] hello world

Additionally, a log is created in the ROS logging directory (typically in ~/.ros/log), forwarding the respective CLIPS logs of the hello_world environment to a file hello_world_<timestamp>.log. After executing the example, the log file will contain the following lines:

[<timestamp>] [hello_world] [info] FIRE    1 hello-world: *
[<timestamp>] [hello_world] [info] hello world
[<timestamp>] [hello_world] [info] ==> f-1     (executive-finalize)

The first two lines show the output of the CLIPS inference engine run that is automatically triggered after loading all plugins.

[<timestamp>] [hello_world] [info] FIRE    1 hello-world: *
[<timestamp>] [hello_world] [info] hello world

Once the run is completed, the node idles until it is shut down, which then causes the ROS2 CLIPS-Executive to assert the executive-finalize fact and then to run the inference engine again (see Usage).

[<timestamp>] [hello_world] [info] ==> f-1     (executive-finalize)

Summary

You created a package with your first custom configuration for the ROS2 CLIPS-Executive, including some CLIPS code. This involved preparing directories for configuration and CLIPS files via CMake, a yaml configuration to setup a CLIPS environment with the FileLoadPlugin and finally a CLIPS file defining a simple rule to print hello world.

Next Steps

Next, you will learn how to interface with ROS via the RosMsgsPlugin by providing continuous monitoring of a turtle in the turtlesim simulator.