Note: This tutorial assumes that you have completed the previous tutorials: Writing a Simple Publisher and Subscriber (euslisp).
(!) 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.

Writing Simple Service and Client (EusLisp)

Description: This tutorial covers how to write a service and client node in euslisp.

Tutorial Level: BEGINNER

Next Tutorial: Using EusLisp (roseus) to control rtmtros robots

Writing a Service Node

Here we'll create the service ("add_two_ints_server") node which will receive two ints and return the sum.

Change directory into the beginner_tutorials package, you created in the earlier tutorial,

$ roscd beginner_tutorials

Please make sure you have followed the directions in the previous tutorial for creating the service needed in this tutorial, creating the AddTwoInts.srv (be sure to choose the right version of build tool you're using at the top of wiki page in the link).

The Code

Create the euslsp/add-two-ints-server.py file within the beginner_tutorials package and paste the following inside it:

   1 #!/usr/bin/env roseus
   2 ;;;
   3 ;;; euslisp version of ros_tutorials/rospy_tutorials/005_add_two_ints
   4 ;;;
   5 (ros::load-ros-manifest "roseus")
   6 
   7 ;;;
   8 (defun add-two-ints (req)
   9   (let ((m (send req :response)))
  10     (format *error-output* "Returning [~d + ~d = ~d]~%"
  11             (send req :a) (send req :b)
  12             (+ (send req :a) (send req :b)))
  13     (send m :sum  (+ (send req :a) (send req :b)))
  14     m))
  15 ;;;
  16 ;;;
  17 (ros::roseus "add_two_ints_server")
  18 (ros::advertise-service "add_two_ints" roseus::AddTwoInts #'add-two-ints)
  19 (do-until-key
  20  (ros::spin-once))

Don't forget to make the node executable:

chmod +x euslisp/add-two-ints-server.l

The Code Explained

Now, let's break the code down.

There's very little to writing a service using roseus. We declare our node using (ros::roseus "add_two_ints_server") and then declare our service:

  18 (ros::advertise-service "add_two_ints" roseus::AddTwoInts #'add-two-ints)

This declares a new service named add_two_ints with the AddTwoInts service type. All requests are passed to handle_add_two_ints function. handle_add_two_ints is called with instances of AddTwoIntsRequest and returns instances of AddTwoIntsResponse.

Just like with the subscriber example,

  19 (do-until-key
  20  (ros::spin-once))

keeps your code from exiting until the service is shutdown.

Writing the Client Node

The Code

Create the euslsp/add-two-ints-client.lfile within the beginner_tutorials package and paste the following inside it:

   1 #!/usr/bin/env roseus
   2 ;;;
   3 ;;; euslisp version of ros_tutorials/rospy_tutorials/005_add_two_ints
   4 ;;;
   5 (ros::load-ros-manifest "roseus")
   6 
   7 ;;;
   8 ;;;
   9 (ros::roseus "add_two_ints_client")
  10 
  11 (when (setq *arguments* (member "add-two-ints-client.l" lisp::*eustop-argument*
  12  :test #'substringp))
  13   (cond ((= (length *arguments*) 1)
  14          (setq x (random 10)
  15                y (random 20)))
  16         ((= (length *arguments*) 3)
  17          (setq x (read-from-string (elt *arguments* 1))
  18                y (read-from-string (elt *arguments* 2))))
  19         (t
  20          (ros::ros-error "Usage: ~A [x y]~%" (elt *arguments* 0))
  21          (exit 1))))
  22 
  23 (ros::wait-for-service "add_two_ints")
  24 (dotimes (i 100)
  25   (setq req (instance roseus::AddTwoIntsRequest :init))
  26   (send req :a x)
  27   (send req :b y)
  28   (setq before (ros::time-now))
  29   (case (mod i 3)
  30     (0 (setq res (ros::service-call "add_two_ints" req t)))
  31     (1 (setq res (ros::service-call "add_two_ints" req nil)))
  32     (2 (setq res (ros::service-call "add_two_ints" req))))
  33   (setq after (ros::time-now))
  34   (format t "~d + ~d = ~d~ (~A sec)~%" (send req :a) (send req :b) (send res :sum) (send (ros::time- after before) :to-sec))
  35   (unix:sleep 1))

Don't forget to make the node executable:

$ chmod +x euslisp/add-two-ints-client.l

The Code Explained

Now, let's break the code down.

The client code for calling services is also simple. For clients, we first call:

  23 (ros::wait-for-service "add_two_ints")

This is a convenience method that blocks until the service named add_two_ints is available. Next we create a handle for calling the service:

  25   (setq req (instance roseus::AddTwoIntsRequest :init))
  26   (send req :a x)
  27   (send req :b y)

Because we've declared the type of the service to be AddTwoInts, it does the work of generating the AddTwoIntsRequest object for you (you're free to pass in your own instead).

  30     (0 (setq res (ros::service-call "add_two_ints" req t)))
  31     (1 (setq res (ros::service-call "add_two_ints" req nil)))
  32     (2 (setq res (ros::service-call "add_two_ints" req))))

call (ros::service-call) function with argument of "add_two_ints" and req. The return value is an AddTwoIntsResponse object.

Building your nodes

We use CMake as our build system and, yes, you have to use it even for EusLisp nodes. This is to make sure that the autogenerated EusLisp code for messages and services is created.

Go to your catkin workspace and run catkin_make.

# In the catkin workspace
$ cd ~/catkin_ws
$ catkin_make

Try it out!

In a new terminal, run

$ rosrun beginner_tutorials add_two_ints_server.l

In a new terminal, run

$ rosrun beginner_tutorials add_two_ints_client.l 4 5

And you will get

Requesting 4+5
4 + 5 = 9

And the server will print out

Returning [4 + 5 = 9]

Wiki: ROS/Tutorials/WritingServiceClient(euslisp) (last edited 2019-09-20 01:50:38 by Guilherme Affonso)