Preface
All the Actionlib tutorials have been translated on the Chinese ROS page server and you can view the total directory if you are interested: http://wiki.ros.org/cn/actionlib_tutorials/Tutorials
describe
This tutorial covers using the simple_action_server library to create a Fibonacci behavior server.This behavior server tutorial generates the results of a Fibonacci sequence, a sequential sequence of targets, a feedback sequence computed by itself, and a final sequence.
Create Behavior Message
Before you start writing behaviors, it's important to define goals, results, and feedback messages.Behavior messages are automatically generated from the.action'file and can be viewed for more behavior file information actionlib File.This file defines the type and text format of feedback topics for objectives, results, and behaviors.Create an actionlib_tutorials/action/Fibonacci.action file using your favorite text editor and add it with the following:
#goal definition int32 order --- #result definition int32[] sequence --- #feedback int32[] sequence
In order to automatically generate message files in the make process, you need to add some small content to CMakeLists.txt.
- Add the actionlib_msgs package as a parameter to the find_package macro, just like this (this line might have been added if you used CMakeLists.txt generated by catkin_create_package):
find_package(catkin REQUIRED COMPONENTS actionlib_msgs)
- Note that CMake requires find_package actionlib_msgs (message_generation does not need to be explicitly listed because it is implicitly referenced by actionlib_msgs).
- Use the add_action_files macro to declare the behavior you want to generate:
add_action_files( DIRECTORY action FILES Fibonacci.action )
- Call the generate_messages macro, and don't forget to rely on actionlib_msgs and other message packages, such as std_msgs:
generate_messages( DEPENDENCIES actionlib_msgs std_msgs # Or other packages containing messages )
- catkin_package also specifies CATKIN_DEPEND to actionlib_msgs.message_runtime automatically passes dependencies.
Now follow the steps below to automatically generate an msg file of your action file and view the results.
$ cd ../.. # Return to the top level of your catkin workspace $ catkin_make $ ls devel/share/actionlib_tutorials/msg/ FibonacciActionFeedback.msg FibonacciAction.msg FibonacciFeedback.msg FibonacciResult.msg FibonacciActionGoal.msg FibonacciActionResult.msg FibonacciGoal.msg $ ls devel/include/actionlib_tutorials/ FibonacciActionFeedback.h FibonacciAction.h FibonacciFeedback.h FibonacciResult.h FibonacciActionGoal.h FibonacciActionResult.h FibonacciGoal.h
To manually generate a message file from this file, use the genaction.py script from the actionlib_msgs package.
Write a simple server
Code
First, create actionlib_tutorials/src/fibonacci_server.cpp using your favorite editor, then populate it with the following:
#include <ros/ros.h> #include <actionlib/server/simple_action_server.h> #include <actionlib_tutorials/FibonacciAction.h> class FibonacciAction { protected: ros::NodeHandle nh_; actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; // NodeHandle instance must be created before this line. Otherwise strange error occurs. std::string action_name_; // create messages that are used to published feedback/result actionlib_tutorials::FibonacciFeedback feedback_; actionlib_tutorials::FibonacciResult result_; public: FibonacciAction(std::string name) : as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false), action_name_(name) { as_.start(); } ~FibonacciAction(void) { } void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal) { // helper variables ros::Rate r(1); bool success = true; // push_back the seeds for the fibonacci sequence feedback_.sequence.clear(); feedback_.sequence.push_back(0); feedback_.sequence.push_back(1); // publish info to the console for the user ROS_INFO("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i", action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]); // start executing the action for(int i=1; i<=goal->order; i++) { // check that preempt has not been requested by the client if (as_.isPreemptRequested() || !ros::ok()) { ROS_INFO("%s: Preempted", action_name_.c_str()); // set the action state to preempted as_.setPreempted(); success = false; break; } feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]); // publish the feedback as_.publishFeedback(feedback_); // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes r.sleep(); } if(success) { result_.sequence = feedback_.sequence; ROS_INFO("%s: Succeeded", action_name_.c_str()); // set the action state to succeeded as_.setSucceeded(result_); } } }; int main(int argc, char** argv) { ros::init(argc, argv, "fibonacci"); FibonacciAction fibonacci("fibonacci"); ros::spin(); return 0; }
Code Interpretation
Now let's explain the code in blocks.
#include <ros/ros.h> #include <actionlib/server/simple_action_server.h>
actionlib/server/simple_action_server.h, a behavior library used to implement simple behavior.
#include <actionlib_tutorials/FibonacciAction.h>
This contains the behavior messages generated from the above Fibonacci.action file.This is from FibonacciAction.msg Automatically generated in the file.For more details on message definitions, see msg Interface.
protected: ros::NodeHandle nh_; actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; // NodeHandle instance must be created before this line. Otherwise strange error occurs. std::string action_name_; // create messages that are used to published feedback/result actionlib_tutorials::FibonacciFeedback feedback_; actionlib_tutorials::FibonacciResult result_;
These are the protected variables in the behavior class.During the process of creating the behavior, the node handle is constructed and passed to the behavior server.Construct a behavior server in the behavior constructor, and the behavior server is described below.Create feedback and result messages for publishing in line behavior.
FibonacciAction(std::string name) : as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false), action_name_(name) { as_.start(); }
In the behavior constructor, the behavior server is created.The behavior server gets a node handle, the behavior name, and the choice of an executeCB parameter.In this example, a behavior server is created that takes a callback function (executeCB) as a parameter.
void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal) {
Now call the executeCB function and create it in the constructor.The callback function passes a pointer to the target message.Note: This is a boost shared pointer with a given " ConstPtr".
ros::Rate r(1); bool success = true; // push_back the seeds for the fibonacci sequence feedback_.sequence.clear(); feedback_.sequence.push_back(0); feedback_.sequence.push_back(1); // publish info to the console for the user ROS_INFO("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i", action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);
Create internal parameters for row behavior.In this routine, publish ROS_INFO to let the user specify that the behavior is running.
// start executing the action for(int i=1; i<=goal->order; i++) { // check that preempt has not been requested by the client if (as_.isPreemptRequested() || !ros::ok()) { ROS_INFO("%s: Preempted", action_name_.c_str()); // set the action state to preempted as_.setPreempted(); success = false; break; } feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
An important component of a behavior server is to allow a behavior client to request cancellation of the current target execution.When a client requests preemption of the current target, the behavior server should cancel the target, perform an important cleanup, and then call the function setPreempted(), which signals that the behavior has been requested to preempt by the user.Set the level of the check preemption request server to the server system.
// publish the feedback as_.publishFeedback(feedback_); // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes r.sleep(); }
Here, the Fibonacci sequence is assigned to the feed back variable, which is then published through the feedback channel provided by the behavior server.The behavior then continues to loop and post feedback.
if(success) { result_.sequence = feedback_.sequence; ROS_INFO("%s: Succeeded", action_name_.c_str()); // set the action state to succeeded as_.setSucceeded(result_); } }
Once the behavior has completed calculating the Fibonacci sequence, the behavior client will be notified that the operation was set successfully.
int main(int argc, char** argv) { ros::init(argc, argv, "fibonacci"); FibonacciAction fibonacci("fibonacci"); ros::spin(); return 0; }
Finally, the main function creates the behavior and the spins node.The behavior runs and waits for the receiving target.
Compile
Add the following lines to your CMakeLists.txt:
add_executable(fibonacci_server src/fibonacci_server.cpp) target_link_libraries( fibonacci_server ${catkin_LIBRARIES} ) add_dependencies( fibonacci_server ${actionlib_tutorials_EXPORTED_TARGETS} )
The complete CMakeLists.txt is as follows:
cmake_minimum_required(VERSION 2.8.3) project(actionlib_tutorials) find_package(catkin REQUIRED COMPONENTS roscpp actionlib actionlib_msgs) find_package(Boost REQUIRED COMPONENTS system) add_action_files( DIRECTORY action FILES Fibonacci.action ) generate_messages( DEPENDENCIES actionlib_msgs std_msgs ) catkin_package( CATKIN_DEPENDS actionlib_msgs ) include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) add_executable(fibonacci_server src/fibonacci_server.cpp) target_link_libraries( fibonacci_server ${catkin_LIBRARIES} ) add_dependencies( fibonacci_server ${actionlib_tutorials_EXPORTED_TARGETS} )
Running Behavior Server
Open roscore in a new terminal$ roscore
Then run the behavior server:
$ rosrun actionlib_tutorials fibonacci_server
You can see output like this:
[ INFO] 1250790662.410962000: Started node [/fibonacci], pid [29267], bound on [aqy], xmlrpc port [39746], tcpros port [49573], logging to [~/ros/ros/log/fibonacci_29267.log], using [real] time
To check if your behavior is working properly, check the list of published topics:
$ rostopic list -v
You can see output like this:
Published topics: * /fibonacci/feedback [actionlib_tutorials/FibonacciActionFeedback] 1 publisher * /fibonacci/status [actionlib_msgs/GoalStatusArray] 1 publisher * /rosout [rosgraph_msgs/Log] 1 publisher * /fibonacci/result [actionlib_tutorials/FibonacciActionResult] 1 publisher * /rosout_agg [rosgraph_msgs/Log] 1 publisher Subscribed topics: * /fibonacci/goal [actionlib_tutorials/FibonacciActionGoal] 1 subscriber * /fibonacci/cancel [actionlib_msgs/GoalID] 1 subscriber * /rosout [rosgraph_msgs/Log] 1 subscriber
In addition, you can view the nodes:
$ rqt_graph
This shows that your behavior server is publishing feedback, status, and expected channel results, as well as target subscriptions and expected target cancellation channels.The behavior server is up and running properly.
Send a target to the behavior server
For the next step in using your behavior, you need to use Ctrl-C to shut down the behavior server, and then Write a simple behavior client.