Note: This tutorial assumes that you have completed the previous tutorials: Set-up and first steps. |
Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Creating a CRAM package
Description: In this tutorial you will learn how to set up a ROS package to use the CRAM plan languageTutorial Level: BEGINNER
Next Tutorial: Controlling turtlesim from Lisp
Contents
Creating the ROS package
First we need to create a ROS package. It needs to depend on roslisp_runtime and on cram_language.
roscreate-pkg cram_tutorial roslisp_runtime cram_language
That was easy. Now we need to set up the lisp infrastructure.
Setting up the Lisp infrastructure
Setting up the Common Lisp part is a little more work. First we need to create a Lisp 'project file', i.e. an asdf system.
Note: ROS is still based on asdf 1.x so no asdf 2.0 features should be used.
After we created the system, we need to create a Common Lisp package (i.e. the equivalent to C++ namespaces).
Creating an asdf system
Switch into the root directory of the cram_tutorial package and create the file cram-tutorial.asd. You shouldn't use underscores but dashes in asd file names. The reason is that the system that is defined in the asd file should be named like the file itself and in Lisp it is very uncommon to use underscores.
The code
Put the following content into cram-tutorial.asd:
(defsystem cram-tutorial :depends-on (roslisp cram-language) :components ((:module "src" :components ((:file "package") (:file "tutorial" :depends-on ("package"))))))
The code explained
The first line defines the name of the system. It should be named like the file name in which it is defined. Then we define the dependencies of the system, i.e. other systems that need to be loaded before we load our system.
Finally we define the components of the system. A component is sort of a sub-system of a system and might be either a module (i.e. a sub-directory) or a file. asdf knows some more component types but they are not relevant for us most of the time. We define that the system knows a sub-directory src. Further, we define that this module contains two files, one for the package definition package.lisp and one with the actual tutorial code tutorial.lisp that has exactly one dependency, the component package. We will create these two source files next. Dependencies inside the system can be all components that are known in the current scope. That means that a component can only depend on components that are defined in the same parent component. Please note that the file extension must be left out when defining files.
Creating the Lisp Package
Lisp packages are the equivalent to C++ namespaces or to python modules. Lisp packages cannot be hierarchic. We can define which other packages should be used, i.e. which symbols should be accessible without a package prefix. Further, we can define which symbols should be exported from the package.
The code
Create a sub-directory src in your package. Then create the file package.lisp and put the following code into it:
(defpackage cram-tutorial (:nicknames :tut) (:use #:cpl #:roslisp))
The code explained
We define a package with the name cram-tutorial. Packages in Common Lisp can have an arbitrary number of nicknames. Finally, we define that the package uses two packages, the package cpl which is the package of the cram plan language, and the package roslisp. Please note that most Common Lisp packages actually use the package common-lisp which exports all symbols of the Common Lisp standard. The packages cpl and common-lisp cannot be used together because the cram language re-defines some of the symbols of the common-lisp package and thus cpl and common-lisp would conflict.
Exporting the asdf system to ROS
To actually load the asdf system, all files referenced in the system definition must be present. Create the file src/tutorial.lisp with the following content:
(in-package :tut)
This just selects the namespace of the file by the nickname ":tut" we defined in package.lisp. We will fill it with more content in later tutorials.
To make the system visible to the ROS infrastructure, create a directory asdf in the package cram_tutorial. Change into it and create a symbolic link that points to the asd file:
mkdir asdf cd asdf ln -s ../cram-tutorial.asd .
Now we are ready to compile and load our new system. Launch Emacs and load the Lisp REPL. Enter the following command:
(ros-load:load-system "cram_tutorial" :cram-tutorial)
You need to load the system every time before you use it, experts would build their own shortcuts to this command or use the rosemacs function "," > ros-load-system > cram_tutorial > cram-tutorial.
The first parameter names the ROS package in which to search for the system, the second parameter names the system to be loaded. Executing the above command should load our new asdf system. Now the package cram-tutorial should be defined. Test it by evaluating
(in-package :tut)
Now that we have created our first cram package, let's try controlling the ROS turtlesim from it..