Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
doc:beginner:controlling_turtlesim_2 [2014/03/12 14:42] – created hmess | doc:beginner:controlling_turtlesim_2 [2015/05/11 16:58] (current) – removed gkazhoya | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Controlling turtlesim from Lisp ====== | ||
- | **Description: | ||
- | |||
- | **Previous Tutorial:** [[doc: | ||
- | **Next Tutorial:** [[doc: | ||
- | ===== Updating the dependencies ===== | ||
- | In this tutorial we will re-use the package '' | ||
- | |||
- | |||
- | |||
- | |||
- | ==== Updating ROS dependecies ==== | ||
- | |||
- | |||
- | ==== Updating cram dependecies ==== | ||
- | |||
- | Now open '' | ||
- | |||
- | <code lisp> | ||
- | (defsystem cram-beginner-tutorial | ||
- | :depends-on (roslisp cram-language turtlesim-msg cl-transforms geometry_msgs-msg) | ||
- | :components | ||
- | ((:module " | ||
- | :components | ||
- | ((:file " | ||
- | | ||
- | </ | ||
- | |||
- | ===== Updating the Lisp Package ===== | ||
- | |||
- | We also want to add '' | ||
- | <code lisp> | ||
- | (defpackage cram-beginner-tutorial | ||
- | (:nicknames :tut) | ||
- | (:use #:cpl #:roslisp #: | ||
- | </ | ||
- | |||
- | ===== Writing the communication glue code ===== | ||
- | |||
- | Now it's time to use roslisp to connect to turtlesim. Turtlesim creates one ROS topic namespace per turtle. For each turtle name (turtle1, turtle2, etc.) it publishes the pose of the turtle on a '' | ||
- | |||
- | ==== The code ==== | ||
- | |||
- | Open the file '' | ||
- | |||
- | === hydro === | ||
- | |||
- | <code lisp> | ||
- | (in-package :tut) | ||
- | |||
- | (defvar *color-value* (make-fluent :name : | ||
- | (defvar *turtle-pose* (make-fluent :name : | ||
- | |||
- | (defvar *color-sub* nil "color ROS subscriber" | ||
- | (defvar *pose-sub* nil "pose ROS subscriber" | ||
- | (defvar *cmd-vel-pub* nil " | ||
- | |||
- | (defun init-ros-turtle (name) | ||
- | " | ||
- | (setf *color-sub* (subscribe (format nil " | ||
- | " | ||
- | #' | ||
- | (setf *pose-sub* (subscribe (format nil " | ||
- | " | ||
- | #' | ||
- | (setf *cmd-vel-pub* (advertise (format nil " | ||
- | " | ||
- | |||
- | (defun color-cb (msg) | ||
- | " | ||
- | (setf (value *color-value*) msg)) | ||
- | |||
- | (defun pose-cb (msg) | ||
- | " | ||
- | (setf (value *turtle-pose*) msg)) | ||
- | |||
- | (defun send-vel-cmd (lin ang) | ||
- | " | ||
- | (publish *cmd-vel-pub* (make-message " | ||
- | : | ||
- | :x lin) | ||
- | : | ||
- | :z ang)))) | ||
- | </ | ||
- | |||
- | === groovy and older === | ||
- | |||
- | <code lisp> | ||
- | (in-package :tut) | ||
- | |||
- | (defvar *color-value* (make-fluent :name : | ||
- | (defvar *turtle-pose* (make-fluent :name : | ||
- | |||
- | (defvar *color-sub* nil "color subscription client" | ||
- | (defvar *pose-sub* nil "pose subscription client" | ||
- | (defvar *cmd-vel-pub* nil " | ||
- | |||
- | (defun init-ros-turtle (name) | ||
- | " | ||
- | (setf *color-sub* (subscribe (format nil " | ||
- | " | ||
- | #' | ||
- | (setf *pose-sub* (subscribe (format nil " | ||
- | " | ||
- | #' | ||
- | (setf *cmd-vel-pub* (advertise (format nil " | ||
- | " | ||
- | |||
- | (defun color-cb (msg) | ||
- | " | ||
- | (setf (value *color-value*) msg)) | ||
- | |||
- | (defun pose-cb (msg) | ||
- | " | ||
- | (setf (value *turtle-pose*) msg)) | ||
- | |||
- | (defun send-vel-cmd (lin ang) | ||
- | " | ||
- | (publish *cmd-vel-pub* (make-message " | ||
- | | ||
- | | ||
- | </ | ||
- | |||
- | === The code explained === | ||
- | |||
- | In '' | ||
- | |||
- | We use callback functions '' | ||
- | |||
- | A fluent is a proxy around a value with support for notification on change. Further, fluents can be combined to so-called fluent networks. There will be some more explanations about fluents later in this tutorial. | ||
- | |||
- | ===== Experimenting in the REPL ===== | ||
- | |||
- | Now let's try it out. Open your Lisp REPL and make sure that you loaded the system '' | ||
- | |||
- | <code lisp> | ||
- | CL-USER> (ros-load: | ||
- | ... | ||
- | CL-USER> (in-package :tut) | ||
- | </ | ||
- | |||
- | For experiments in the REPL, we want to initialize a Lisp ROS node and then call '' | ||
- | |||
- | Make sure '' | ||
- | |||
- | Enter the following commands: | ||
- | |||
- | <code lisp> | ||
- | TUT> (start-ros-node " | ||
- | [(ROSLISP TOP) INFO] 1292688669.674: | ||
- | [(ROSLISP TOP) INFO] 1292688669.687: | ||
- | [(ROSLISP TOP) INFO] 1292688669.688: | ||
- | [(ROSLISP TOP) INFO] 1292688669.689: | ||
- | [(ROSLISP TOP) INFO] 1292688669.691: | ||
- | [(ROSLISP TOP) INFO] 1292688670.875: | ||
- | </ | ||
- | |||
- | The name of the node is arbitrary. We need to call '' | ||
- | |||
- | <code lisp> | ||
- | TUT> (init-ros-turtle "/ | ||
- | </ | ||
- | |||
- | This calls our function '' | ||
- | |||
- | Now we should start up turtlesim in a new terminal: | ||
- | |||
- | <code bash> | ||
- | $ rosrun turtlesim turtlesim_node | ||
- | </ | ||
- | |||
- | (Note: if you're using turtlesim for the first time, you might need to compile the package first: '' | ||
- | |||
- | You will see the turtlesim window: | ||
- | |||
- | {{: | ||
- | |||
- | Notice that thanks to ROS, we could subscribe to the topics even before they had been advertised by the turtlesim. | ||
- | |||
- | We are ready for experiments now. Let's see if the fluents are containing the right values: | ||
- | |||
- | <code lisp> | ||
- | TUT> | ||
- | [TURTLESIM-MSG:< | ||
- | X: | ||
- | | ||
- | Y: | ||
- | | ||
- | | ||
- | 0.0d0 | ||
- | | ||
- | 0.0d0 | ||
- | | ||
- | | ||
- | TUT> | ||
- | [TURTLESIM-MSG:< | ||
- | R: | ||
- | 179 | ||
- | G: | ||
- | 184 | ||
- | B: | ||
- | 255] | ||
- | </ | ||
- | |||
- | You see that the value of the fluents contain structured data, which contains the pose and color information as provided by the turtlesim simulator. | ||
- | |||
- | Let's see if the pose changes if we move the turtle. Start up '' | ||
- | |||
- | <code bash>$ rosrun turtlesim turtle_teleop_key</ | ||
- | |||
- | Try evaluating '' | ||
- | <code lisp> | ||
- | TUT> | ||
- | [TURTLESIM-MSG:< | ||
- | X: | ||
- | | ||
- | Y: | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | 0.0d0 | ||
- | | ||
- | | ||
- | </ | ||
- | As the pose fluent has been updated, the subscribers seem to work. | ||
- | |||
- | |||
- | ==== Fluents ==== | ||
- | |||
- | Now let's play around with fluents a little bit more. | ||
- | |||
- | Notice how in the checks before, we used the function '' | ||
- | |||
- | Fluents allow us to wait for specific events. For instance, we can wait for the '' | ||
- | <code lisp> | ||
- | TUT> (wait-for (< (fl-funcall #' | ||
- | 5.0)) | ||
- | </ | ||
- | The code above constructs a fluent network. The expression | ||
- | <code lisp> | ||
- | (fl-funcall #' | ||
- | </ | ||
- | returns a new fluent that contains the '' | ||
- | <code lisp> | ||
- | (< (fl-funcall #' | ||
- | 5.0) | ||
- | </ | ||
- | returns a fluent that is either '' | ||
- | |||
- | Execute the above expression. If the turtle' | ||
- | |||
- | |||
- | === Moving the turtle === | ||
- | |||
- | Let's see if we can also move the turtle from LISP. Try the following: | ||
- | <code lisp> | ||
- | TUT> (dotimes (i 10) (send-vel-cmd 1 1) (sleep 1)) | ||
- | </ | ||
- | We use the '' | ||
- | |||
- | == Next == | ||
- | |||
- | |||
- | Now that we have functions and fluents to connect to the turtlesim, let's implement some simple plans. | ||
- | |||
- | [[doc: |