对初学者而言,Ros的Action有些奇怪,所以有必要做一个简单的例子来描述它的作用。
本教程介绍使用情况 simple_action_server 库来创建斐波那契动作服务器。例如,动作服务器生成斐波那契序列,目标是序列顺序,反馈是计算序列,结果是最终序列。
- Creating the Action Messages
- Writing a Simple Server
- The Code
- The Code Explained
- Compiling
- Running the Action server
- Sending a Goal to the Action Server
1 生成Action消息
在编写动作之前,定义目标、结果和反馈是非常重要的。操作信息是从 .action 有关操作文件的更多信息,请参考文件自动生成 actionlib 文档。本文件定义了反馈主题的目标、结果和类型和格式。创建你喜欢的编辑器 actionlib_tutorials/action/Fibonacci.action,并将以下内容放入其中:
https://raw.githubusercontent.com/ros/common_tutorials/hydro-devel/actionlib_tutorials/action/Fibonacci.action
#goal definition int32 order --- #result definition int32[] sequence --- #feedback int32[] sequence
在制作过程中自动生成消息文件需要 CMakeLists.txt 添加一些内容。
-
像这样将 actionlib_msgs 包添加到 find_package 如果使用宏参数( catkin_create_package 生成 CMakeLists.txt,也可添加):
find_package(catkin REQUIRED COMPONENTS actionlib_msgs)
-
注意CMake需要find_package actionlib_msgs(message_generation不需要显式列出,actionlib_msgs隐式引用).
-
-
使用 add_action_files 宏来声明要生成的操作:
add_action_files( DIRECTORY action FILES Fibonacci.action )
-
调用 generate_messages 宏,不要忘记对 actionlib_msgs 以及其他消息包(如 std_msgs)的依赖:
generate_messages( DEPENDENCIES actionlib_msgs std_msgs # Or other packages containing msgs )
-
像这样将 actionlib_msgs 添加到 catkin_package 宏:
catkin_package( CATKIN_DEPENDS actionlib_msgs )
-
catkin_package 还仅将 CATKIN_DEPEND 指定到 actionlib_msgs。对 message_runtime 自动发生传输依赖。
-
注:有时你必须设置你 package.xml,由于我们正在生成信息,您必须在清单文件中声明您在运行时必须生成信息。您可以插入以下行程。
<exec_depend>message_generation</exec_depend>
现在通过以下操作自动生成您的操作文件 msg 文件,并查看结果。
$ cd ../.. # Go back 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
请使用此文件手动生成消息文件 actionlib_msgs 包中的脚本 genaction.py。
二、写简单的Action Server
首先,创建你喜欢的编辑器 actionlib_tutorials/src/fibonacci_server.cpp,并将以下内容放入其中:
Toggle line numbers
1 #include <ros/ros.h> 2 #include <actionlib/server/simple_action_server.h> 3 #include <actionlib_tutorials/FibonacciAction.h> 4 5 class FibonacciAction 6 { 7 protected: 8 9 ros::NodeHandle nh_; 10 actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; // NodeHandle instance must be created before this line. Otherwise strange error occurs. 11 std::string action_name_; 12 // create messages that are used to published feedback/result 13 actionlib_tutorials::FibonacciFeedback feedback_; 14 actionlib_tutorials::FibonacciResult result_; 15 16 public: 17 18 FibonacciAction(std::string name) : 19 as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false), 20 action_name_(name) 21 { 22 as_.start(); 23 } 24 25 ~FibonacciAction(void) 26 { 27 } 28 29 void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal) 30 { 31 // helper variables 32 ros::Rate r(1);&nbp; 33 bool success = true; 34 35 // push_back the seeds for the fibonacci sequence 36 feedback_.sequence.clear(); 37 feedback_.sequence.push_back(0); 38 feedback_.sequence.push_back(1); 39 40 // publish info to the console for the user 41 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]); 42 43 // start executing the action 44 for(int i=1; i<=goal->order; i++) 45 { 46 // check that preempt has not been requested by the client 47 if (as_.isPreemptRequested() || !ros::ok()) 48 { 49 ROS_INFO("%s: Preempted", action_name_.c_str()); 50 // set the action state to preempted 51 as_.setPreempted(); 52 success = false; 53 break; 54 } 55 feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]); 56 // publish the feedback 57 as_.publishFeedback(feedback_); 58 // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes 59 r.sleep(); 60 } 61 62 if(success) 63 { 64 result_.sequence = feedback_.sequence; 65 ROS_INFO("%s: Succeeded", action_name_.c_str()); 66 // set the action state to succeeded 67 as_.setSucceeded(result_); 68 } 69 } 70 71 72 }; 73 74 75 int main(int argc, char** argv) 76 { 77 ros::init(argc, argv, "fibonacci"); 78 79 FibonacciAction fibonacci("fibonacci"); 80 ros::spin(); 81 82 return 0; 83 }
四、解释Action Server代码
下文一点一点解释代码细节
Toggle line numbers
1 #include <ros/ros.h> 2 #include <actionlib/server/simple_action_server.h> 3
actionlib/server/simple_action_server.h 是用于实现简单动作的动作库。
Toggle line numbers
3 #include <actionlib_tutorials/FibonacciAction.h> 4
这包括从上面显示的 Fibonacci.action 文件生成的操作消息。这是从 FibonacciAction.msg 文件自动生成的标头。有关消息定义的更多信息,请参阅消息页面。
Toggle line numbers
7 protected: 8 9 ros::NodeHandle nh_; 10 actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; // NodeHandle instance must be created before this line. Otherwise strange error occurs. 11 std::string action_name_; 12 // create messages that are used to published feedback/result 13 actionlib_tutorials::FibonacciFeedback feedback_; 14 actionlib_tutorials::FibonacciResult result_;
这些是动作类的受保护变量。节点句柄在构造动作期间被构造并传递到动作服务器。动作服务器是在动作的构造函数中构造的,下面已经讨论过了。创建反馈和结果消息以在操作中发布。
Toggle line numbers
18 FibonacciAction(std::string name) : 19 as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false), 20 action_name_(name) 21 { 22 as_.start(); 23 }
在动作构造函数中,创建了动作服务器。动作服务器接受节点句柄、动作名称和可选的 executeCB 参数。在此示例中,操作服务器是使用 executeCB 的参数创建的。
Toggle line numbers
29 void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal) 30 {
现在创建了构造函数中引用的 executeCB 函数。回调函数被传递一个指向目标消息的指针。注意:这是一个 boost 共享指针,通过将“ConstPtr”附加到目标消息类型的末尾来给出。
Toggle line numbers
32 ros::Rate r(1); 33 bool success = true; 34 35 // push_back the seeds for the fibonacci sequence 36 feedback_.sequence.clear(); 37 feedback_.sequence.push_back(0); 38 feedback_.sequence.push_back(1); 39 40 // publish info to the console for the user 41 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]);
这里创建了动作的内部。在此示例中,发布 ROS_INFO 以让用户知道该操作正在执行。
Toggle line numbers
43 // start executing the action 44 for(int i=1; i<=goal->order; i++) 45 { 46 // check that preempt has not been requested by the client 47 if (as_.isPreemptRequested() || !ros::ok()) 48 { 49 ROS_INFO("%s: Preempted", action_name_.c_str()); 50 // set the action state to preempted 51 as_.setPreempted(); 52 success = false; 53 break; 54 } 55 feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
动作服务器的一个重要组成部分是允许动作客户端请求取消当前目标执行的能力。当客户端请求当前目标被抢占时,动作服务器应该取消目标,执行必要的清理,并调用函数 setPreempted(),这表明该动作已被用户请求抢占。设置动作服务器检查抢占请求的速率由服务器的实现者决定。
Toggle line numbers
56 // publish the feedback 57 as_.publishFeedback(feedback_); 58 // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes 59 r.sleep(); 60 }
这里将斐波那契数列放入反馈变量中,然后发布到动作服务器提供的反馈通道上。然后动作继续循环和发布反馈。
Toggle line numbers
62 if(success) 63 { 64 result_.sequence = feedback_.sequence; 65 ROS_INFO("%s: Succeeded", action_name_.c_str()); 66 // set the action state to succeeded 67 as_.setSucceeded(result_); 68 } 69 }
一旦动作完成了斐波那契数列的计算,动作就会通过设置成功通知动作客户端动作完成。
Toggle line numbers
75 int main(int argc, char** argv) 76 { 77 ros::init(argc, argv, "fibonacci"); 78 79 FibonacciAction fibonacci("fibonacci"); 80 ros::spin(); 81 82 return 0; 83 }
最后是 main 函数,创建动作并旋转节点。该操作将运行并等待接收目标。
五、如何编译?
在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}
)
最小的整个 CMakeLists.txt 看起来像这样:
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} )
六、运行 Action server
开启一个新终端
$ roscore
运行action功能包-节点:
$ rosrun actionlib_tutorials fibonacci_server
您将看到类似于以下内容的内容:
-
[ 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
要检查您的操作是否正常运行,请列出正在发布的主题:
$ rostopic list -v
您将看到类似于以下内容的内容:
-
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
或者,您可以查看节点:
$ rqt_graph
正在上传…重新上传取消正在上传…重新上传取消正在上传…重新上传取消
这表明您的操作服务器正在按预期发布反馈、状态和结果通道,并按预期订阅目标和取消通道。操作服务器已启动并正常运行。
注意:要想调用Action Server,还需要Action Server客户端,清继续看下文:
《ROS知识:Action【02】编写简单Action客户端》