• +4917626969472
  • info@ur-techpartner.de

ROS Basics (13/17) – Implement Action (Action Server)

Robot Operating System(ROS1/ROS2) ROS Programming

ROS Basics – Implement Action (Action Server)

In previous blog, we have define an action message named “Timer.action”. Now we will learn how to implement it by writing a program for action server. Like topics and services, actions are also implemented as callback-based mechanism. In order to implement action, a package “actionlib” is used.

Creating Action Server

We can create an action server that may implement any action available in ROS. However, here we will use “Timer.action”, that we have defined ourselves in previous blog. We will use the class “SimpleActionServer” of the package “actionlib” to implement a basic action server.

Again we will create action server file in the same package “ros_basics” that we are already using for explaining various examples.

Go to the package

Run the command

roscd ros_basics/src

Also run

ls

(To verify that the action_server file is not already created.

Now create the file “action_server.py”

For this run the command

touch action_server.py

Run the command to give execute permission

chmod +x action_server.py

Open the file using “gedit” command

Run in terminal

gedit action_server.py

Copy and paste following code in it.

#! /usr/bin/env python
import rospy
import time

import actionlib
from ros_basics.msg import TimerAction, TimerGoal, TimerResult

def do_timer(goal):
start_time = time.time()
time.sleep(goal.time_to_wait.to_sec())
result = TimerResult()
result.time_elapsed = rospy.Duration.from_sec(time.time() - start_time)
result.updates_sent = 0
server.set_succeeded(result)

rospy.init_node('timer_action_server')
server = actionlib.SimpleActionServer('timer', TimerAction, do_timer, False)
server.start()
rospy.spin()

 

All above executed commands are shown in figure below

The file “action_server.py” will look like in figure below

Save and close the file

Explaining the Code in Python file “action_server.py”

Now we will go through the key parts of the code

import time

(“time” package is imported to use the timer functionality of the server)

import actionlib

(“actionlib” package is imported as it provides the class SimpleActionServer, that we will use in our code)
from ros_basics.msg import TimerAction, TimerGoal, TimerResult
(We have already learned that after executing “catkin_make”, many classes were auto-generated from our “Timer.action” file. We are importing three of those classes)

def do_timer(goal):
start_time = time.time()
time.sleep(goal.time_to_wait.to_sec())

(A function do_timer() is defined. This function will be invoked when the server node receives a new goal. The argument passed to this function is an object of TimerGoal class. It corresponds to the goal part of the file “Timer.action” that we defined in previous blog. The “time_to_wait” field is a variable in goal part of the file “Timer.action”. We used standard python time.sleep() function to sleep for the time requested in the goal.)

result = TimerResult()
result.time_elapsed = rospy.Duration.from_sec(time.time() – start_time)
result.updates_sent = 0

(In these code of line, we created an object result of the class TimerResult. This corresponds to the result part of the file Timer.action. This result has two variables “time_elapsed”, and “updates_sent” as defined in Timer.action file. We calculated the time by subtracting saved start time from current time. We also set updates_sent equal to 0. Because so far we are not sending any updates).

server.set_succeeded(result)

(In the final line of the function, we tell SimpleActionServer that we achieved the goal successfully by calling the function set_succeeded, and pass the result.

rospy.init_node(‘timer_action_server’)

(Initialize the node timer_action_server)

server = actionlib.SimpleActionServer(‘timer’, TimerAction, do_timer, False)
server.start()

(We are now creating an object “server” for SimpleActionServer class. The first argument “timer” is the name of the server that will be advertised (we will see it when server is running). The second argument “TimerAction “ is the type of the action that server is handling. The third argument “do_timer” is a callback function. The fourth argument is “False” which means we disabled auto-starting feature of the server. An then we started the server explicitly using start() function of the server in next line)

rospy.spin()

(we used ROS spin() loop to wait for the goals to arrive)

Executing “action_server.py” file

Now we will execute the file action_server.py, and will see if every thing is working fine.

Open a terminal and run the command.

rosrun ros_basics action_server.py

The command terminal will look like figure below

Open a new terminal and run the command

rostopic list

you can see a list of topics as follows

/rosout
/rosout_agg
/timer/cancel
/timer/feedback
/timer/goal
/timer/result
/timer/status

here, timer is the action server (or we can say timer name-space) and five topics are listed which are used to manage the action.

We can further see the types of topics.

Run the command

rostopic info /timer/goal

We can see the information about topic in figure below

It can be viewed that the topic timer/goal is of type “ros_basics/TimerActionGoal” message.

We can check the details of the message as follows

run the command

rosmsg show ros_basics/TimerActionGoal

We can see that there is a variable named time_to_wait of type duration which can be accessed as “goal.time_to_wait”. However, we can see extra fields in the message. These extra fields are used by action server and action client to keep track of the process.

However, we do not need to bother about extra fields, we only work with the TimerGoal message, that we have defined in our “.action” file.

We can also see the details of the TimerGoal message

Run the command in terminal

rosmsg show TimerGoal

You can see in figure below that only our defined fields will be displayed now.

As you have successfully implemented action server and verified that it is running. In next blog we will create an action client that will communicate with the action server.

No comments