Note: This tutorial assumes that you have completed the previous tutorials: 使用目标反馈方法(goal callback method)编写一个简单的行为服务器. |
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. |
编写一个简单客户端线程
Description: 本教程涵盖了使用simple_action_client库来创建一个平均行为客户端。示例程序循环一个线程,创建一个行为客户端,然后发送目标到行为服务器。Tutorial Level: INTERMEDIATE
Next Tutorial: 使用其他节点运行一个行为服务器和客户端
Contents
Show EOL distros:
代码
首先,使用你最喜欢的编辑器创建actionlib_tutorials/src/averaging_client.cpp,然后使用以下内容进行填充:
1 #include <ros/ros.h>
2 #include <actionlib/client/simple_action_client.h>
3 #include <actionlib/client/terminal_state.h>
4 #include <actionlib_tutorials/AveragingAction.h>
5 #include <boost/thread.hpp>
6
7 void spinThread()
8 {
9 ros::spin();
10 }
11
12 int main (int argc, char **argv)
13 {
14 ros::init(argc, argv, "test_averaging");
15
16 // 创建一个行为客户端
17 actionlib::SimpleActionClient<actionlib_tutorials::AveragingAction> ac("averaging");
18 boost::thread spin_thread(&spinThread);
19
20 ROS_INFO("Waiting for action server to start.");
21 ac.waitForServer();
22
23 ROS_INFO("Action server started, sending goal.");
24 // 发送目标到行为
25 actionlib_tutorials::AveragingGoal goal;
26 goal.samples = 100;
27 ac.sendGoal(goal);
28
29 //等待行为返回
30 bool finished_before_timeout = ac.waitForResult(ros::Duration(30.0));
31
32 if (finished_before_timeout)
33 {
34 actionlib::SimpleClientGoalState state = ac.getState();
35 ROS_INFO("Action finished: %s",state.toString().c_str());
36 }
37 else
38 ROS_INFO("Action did not finish before the time out.");
39
40 // 关闭节点,在退出前加入线程
41 ros::shutdown();
42 spin_thread.join();
43
44 //exit
45 return 0;
46 }
代码解释
现在让我们分块的解释代码。
- actionlib/server/simple_action_client.h是行为库,实现简单行为客户端。
- actionlib/client/terminal_state.h 定义目标可能的状态。
这里包含从上面的Averaging.action文件中生成的消息。这个头文件自动从AveragingAction.msg生成。对于更多消息定义的信息,查看msg页面。
这个包含boost线程库用于循环示例中的线程。
这是一个简单的函数用于循环线程,该函数会在代码之后用到。这个线程会在后台循环ros节点。
在行为定义中的行为客户端模板,制定和行为服务器通信的消息类型。行为客户端构造函数会加载两个参数,包括需要连接的服务名和一个可选的布尔类型用于循环一个线程。这里创建的行为客户端使用服务名和自动循环选项为false作为参数,这意味着一个必须创建一个线程。
18 boost::thread spin_thread(&spinThread);
这里创建一个线程,然后在后台开启一个ros节点。通过使用这个方法你可以创建多个线程用于你的行为客户端,如果有必要的话。
由于行为服务器有可以没有挂起或运行,行为客户端将在继续之前等待行为服务器开启。
这里创建一个目标消息,设置目标值并且发送到行为服务器。
现在行为客户端在继续之前,等待目标结束。超时时间设置为30秒,这意味着函数会在30秒后如果目标没有完成,将会返回false。
如果在超时之前目标完成,将会报告目标状态,否则通知用户目标没有在限定时间内完成。
现在目标完成,我们报告目标状态,我们需要关闭ros节点并且子啊退出之前加入到我们的线程中。
编译 & 运行客户端
添加如下行到你的CMakeLists.txt文件:
rosbuild_add_executable(averaging_client src/averaging_client.cpp)
add_executable(averaging_client src/averaging_client.cpp) target_link_libraries(averaging_client ${catkin_LIBRARIES})
在你运行catkin_make之后,在一个新终端开启roscore:
$ roscore
然后运行客户端:
$ rosrun actionlib_tutorials averaging_client
你会看到类似如下输出:
[ INFO] 1250806286.804217000: Started node [/test_averaging], pid [9414], bound on [aqy], xmlrpc port [35466], tcpros port [55866], logging to [~/ros/ros/log/test_averaging_9414.log], using [real] time [ INFO] 1250806287.828279000: Waiting for action server to start.
检查你的客户端运行正常,列出发布的话题:
$ rostopic list -v
你会看到类似如下输出:
Published topics: * /averaging/goal [actionlib_tutorials/AveragingActionGoal] 1 publisher * /averaging/cancel [actionlib/GoalID] 1 publisher * /rosout [roslib/Log] 1 publisher * /rosout_agg [roslib/Log] 1 publisher Subscribed topics: * /time [unknown type] 2 subscribers * /rosout [roslib/Log] 1 subscriber * /averaging/feedback [unknown type] 1 subscriber * /averaging/status [unknown type] 1 subscriber * /averaging/result [unknown type] 1 subscriber
另外,你可以查看节点:
$ rxgraph &
$ rosrun rqt_graph rqt_graph &
这里展示了你的客户端订阅反馈、状态和期望的结果通道,以及发布目标和期望取消通道。说明客户端运行正常。
连接服务器和客户端
为了下一步使用你的行为,你需要按下Ctrl-C关闭行为客户端,然后 使用其他节点运行行为服务器和客户端.