共两部分:Server和Client
1.SimpleActionServer:actionlib_tutorials/Tutorials/SimpleActionServer(ExecuteCallbackMethod) - ROS Wiki
2.SimpleActionClient:
actionlib_tutorials/Tutorials/SimpleActionClient - ROS Wiki
第一部分:使用Execute回调编写简单操作服务器
Description:本教程介绍如何使用simple_action_server库创建斐波那契动作服务器。此示例操作服务器生成斐波那契序列,目标是序列的顺序,反馈是计算的序列,结果是最终序列。
1.创建Action Messages
在编写Action之前,定义目标、结果和反馈信息非常重要。创建的.action文件中定义了Action的目标、结果和反馈话题的类型和格式。
1)创建actionlib_tutorials/action/Fibonacci.action文件:
#goal definition
int32 order
---
#result definition
int32[] sequence
---
#feedback
int32[] sequence
2).修改CMakeList.txt
·添加actionlib_msgs包到find_package宏变量里面:
find_package(catkin REQUIRED COMPONENTS actionlib_msgs)
·使用add_action_files宏声明要生成的操作:
add_action_files(
DIRECTORY action
FILES Fibonacci.action
)
·调用generate_messages宏,不要忘记对actionlib_msg和其他消息包(如std_msg)的依赖关系:
generate_messages(
DEPENDENCIES actionlib_msgs std_msgs # Or other packages containing msgs
)
·将actionlib_msg添加到catkin_package宏,如下所示:
catkin_package(
CATKIN_DEPENDS actionlib_msgs
)
注意:有时您必须设置package.xml文件,因为我们正在生成消息,所以您必须在清单文件上声明,在运行时您必须生成消息。您可以插入下面的行。
<exec_depend>message_generation</exec_depend>
按下面步骤在你的action文件夹中创建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文件夹中python脚本文件generation.py手动编译)
2.写一个简单的服务器
首先:创建actionlib_tutorials/src/fibonacci_server.cpp文件,并参考下面代码:
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_; // 节点句柄必须在这一行之前创建,否则会报错
11 std::string action_name_;
12 // 创建用来发布“反馈/结果”的Message
13 actionlib_tutorials::FibonacciFeedback feedback_;
14 actionlib_tutorials::FibonacciResult result_;
15
16 public:
17 //此处的bind()函数可以从网上搜一下看,在这里就是执行了函数executeCB参数是this指针
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); //1Hz的频率执行循环
33 bool success = true;
34
35 // 将初始值压入反馈sequence队列
36 feedback_.sequence.clear();
37 feedback_.sequence.push_back(0);
38 feedback_.sequence.push_back(1);
39
40 // 将信息发布到终端
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 // 开始执行action
44 for(int i=1; i<=goal->order; i++)
45 {
46 // 检查preempted是否已经被客户端请求
47 if (as_.isPreemptRequested() || !ros::ok())
48 {
49 ROS_INFO("%s: Preempted", action_name_.c_str());
50 // 设置action的状态到as_的preempted中
51 as_.setPreempted();
52 success = false;
53 break;
54 }
55 feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
56 // 发布反馈
57 as_.publishFeedback(feedback_);
58 // 这个延时不是必要的,因为计算速度1Hz足够快
59 r.sleep();
60 }
61
62 if(success)
63 {
64 result_.sequence = feedback_.sequence;
65 ROS_INFO("%s: Succeeded", action_name_.c_str());
66 // 设置状态成功,退出
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 }
代码详解:
1).头文件,包含了action文件的使用的常见的库函数等;
1 #include <ros/ros.h>
2 #include <actionlib/server/simple_action_server.h>
2).上面.action文件自动编译产生的,或者用python脚本生成;
3 #include <actionlib_tutorials/FibonacciAction.h>
3).action类中被保护的变量,在这里创建了 ros节点句柄和action服务器的句柄,其中action服务器在下面的构造函数中构造,另外这里创建了要发布的反馈和结果;
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_;
4).在构造函数里创建了action服务器as_,并且赋值其中的变量:nh_,name还有可选函数executeCB(其参数为this,_1是占位符);同样action_name_赋值为name;
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 }
5).executeCB函数创建,参数是常量指针,指向了goal;
29 void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal)
30 {
6).函数内容:
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]);
7).一个重要的功能是一个action客户端能发请求使当前的目标计算结束。频率是设置客户端抢占服务器的速度。
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]);
8).这里是斐波那契数列的中间结果放在反馈队列中,并通过ROS_INFO发布到控制台,一边计算一边循环发布;
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 }
9).成功后的状态设置;
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 }
10).主函数。
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 }
3.编译Compiling
1)添加下面到CMakeLIstanbul.txt
add_executable(fibonacci_server src/fibonacci_server.cpp)
target_link_libraries(
fibonacci_server
${catkin_LIBRARIES}
)
add_dependencies(
fibonacci_server
${actionlib_tutorials_EXPORTED_TARGETS}
)
完成之后,前后大概这个样子
4.运行试试(终端输入)
1)roscore
2)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
3)检查一下发布的话题
rostopic list -v
4)你会看到
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
5)作图显示
rqt_graph
OK!!