Actionlib是ROS非常重要的库,像执行各种运动的动作,例如控制手臂去抓取一个杯子,这个过程可能复杂而漫长,执行过程中还可能强制中断或反馈信息,这时Actionlib就能大展伸手了。

1.原理

1.1功能

在任何一个比较大的基于ROS的系统,都会有这样的情况,向某个节点发送请求执行某一个任务,并返回相应的执行结果,这种通常用ROS的服务(services)完成。然而,有一些情况服务执行的时间很长,在执行中想要获得任务处理的进度,或可能取消执行任务,Actionlib就能实现这样的功能,它是ROS的一个非常重要的库。可以实现一些简单的状态机功能,算的上是SMACH的一个弱化版。

1.2框架

如下图所示, Actionlib的框架实际是一种特殊的客户-服务的模式。除了服务请求的功能外,还可以实时获取服务器执行任务的进度状态,以及强制中断服务的功能。

2.例子

下面以洗碟子为例子,实现客户端调用服务器执行洗盘子的动作。这个例子是官网的一个改进版本,涵盖actionli的基本功能,例如获取服务器执行任务的进度状态,强制终端服务的功能,服务活动状态提示。

2.1服务服务端实现

服务端实现了服务器执行任务的反馈信息,中断抢占功能。具体实现较为简单,反馈信息通过发布反馈的消息实现,中断抢占通过注册中断毁掉函数实现,代码如下:

//这是actionlib的服务端

#include <first_actionlib_sample/DoDishesAction.h>
#include <actionlib/server/simple_action_server.h> //这样定义下会用起来简洁许多
typedef actionlib::SimpleActionServer<first_actionlib_sample::DoDishesAction> Server; class DoDishesActionServer
{
public:
DoDishesActionServer(ros::NodeHandle n):
server(n, "do_dishes",
boost::bind(&DoDishesActionServer::ExecuteCb, this, _1), false)
{
//注册抢占回调函数
server.registerPreemptCallback(boost::bind(&DoDishesActionServer::preemptCb, this));
} //启动服务
void Start()
{
server.start();
} //回调函数,在此添加代码实现你要的功能
void ExecuteCb(const first_actionlib_sample::DoDishesGoalConstPtr& goal) {
// 在次添加你所要实现的功能
ROS_INFO("Received goal,the dish id is :%d", goal->dishwasher_id);
//反馈
first_actionlib_sample::DoDishesFeedback feedback;
ros::Rate rate();
int cur_finished_i = ;
int toal_dish_num = ;
for(cur_finished_i = ; cur_finished_i <= toal_dish_num; cur_finished_i++)
{
if(!server.isActive())break; ROS_INFO("Cleanning the dish::%d", cur_finished_i);
feedback.percent_complete = cur_finished_i/10.0;
server.publishFeedback(feedback);
rate.sleep();
}
first_actionlib_sample::DoDishesResult result;
result.toal_dishes_cleaned = cur_finished_i; if(server.isActive())server.setSucceeded(); } //中断回调函数
void preemptCb()
{
if(server.isActive()){
server.setPreempted();//强制中断
}
} Server server;
}; int main(int argc, char** argv) {
ros::init(argc, argv, "do_dishes_server");
ros::NodeHandle n;
//初始化,绑定回调函数 DoDishesActionServer actionServer(n);
//启动服务器,等待客户端信息到来
actionServer.Start();
ros::spin();
return ;
}

2.2客户端实现

客户端注册了三个毁掉函数,DoneCb,ActivCb,FeedbackCb,分别地,DoneCb:用于监听服务器任务执行完后的相应消息以及客户端的相应处理,ActivCb:服务器任务被激活时的消息提示以及客户端的相应处理,FeedbackCb:接收服务器的反馈消息以及客户端的相应处理。代码如下:

//这是actionlib的客户端

#include <first_actionlib_sample/DoDishesAction.h>
//#include <actionlib_msgs/GoalStatusArray.h>
#include <actionlib/client/simple_action_client.h> //这样定义下会用起来简洁许多
typedef actionlib::SimpleActionClient<first_actionlib_sample::DoDishesAction> Client; class DoDishesActionClient {
private:
// Called once when the goal completes
void DoneCb(const actionlib::SimpleClientGoalState& state,
const first_actionlib_sample::DoDishesResultConstPtr& result) {
ROS_INFO("Finished in state [%s]", state.toString().c_str());
ROS_INFO("Toal dish cleaned: %i", result->toal_dishes_cleaned);
ros::shutdown();
} // 当目标激活的时候,会调用一次
void ActiveCb() {
ROS_INFO("Goal just went active");
} // 接收服务器的反馈信息
void FeedbackCb(
const first_actionlib_sample::DoDishesFeedbackConstPtr& feedback) {
ROS_INFO("Got Feedback Complete Rate: %f", feedback->percent_complete);
}
public:
DoDishesActionClient(const std::string client_name, bool flag = true) :
client(client_name, flag) {
} //客户端开始
void Start() {
//等待服务器初始化完成
client.waitForServer();
//定义要做的目标
first_actionlib_sample::DoDishesGoal goal;
goal.dishwasher_id = ;
//发送目标至服务器
client.sendGoal(goal,
boost::bind(&DoDishesActionClient::DoneCb, this, _1, _2),
boost::bind(&DoDishesActionClient::ActiveCb, this),
boost::bind(&DoDishesActionClient::FeedbackCb, this, _1));
//等待结果,时间间隔5秒
client.waitForResult(ros::Duration(10.0)); //根据返回结果,做相应的处理
if (client.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
printf("Yay! The dishes are now clean");
else {
ROS_INFO("Cancel Goal!");
client.cancelAllGoals();
} printf("Current State: %s\n", client.getState().toString().c_str());
}
private:
Client client;
}; int main(int argc, char** argv) {
ros::init(argc, argv, "do_dishes_client");
DoDishesActionClient actionclient("do_dishes", true);
//启动客户端
actionclient.Start();
ros::spin();
return ;
}

另一个客户端的实现代码基本相同,只是节点的名字有所不同,这里略去,详细实现请查看附件的源码。主要用于测试抢占中断功能。

2.3CMakeLists编写 

cmake_minimum_required(VERSION ..)
project(first_actionlib_sample) find_package(catkin REQUIRED COMPONENTS
actionlib
actionlib_msgs
roscpp
rospy
std_msgs
) ## Generate actions in the 'action' folder
add_action_files(
DIRECTORY action
FILES
DoDishes.action
) ## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
actionlib_msgs# std_msgs
) catkin_package() ###########
## Build ##
###########
include_directories(
${catkin_INCLUDE_DIRS}
) ## Declare a C++ executable
add_executable(do_dishes_action_client_node src/DoDishesActionClient.cpp)
add_executable(do_dishes_action_client_node1 src/DoDishesActionClient1.cpp)
add_executable(do_dishes_action_server_node src/DoDishesActionServer.cpp) ## Add cmake target dependencies of the executable
## same as for the library above
add_dependencies(do_dishes_action_client_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(do_dishes_action_client_node1 ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(do_dishes_action_server_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
target_link_libraries(do_dishes_action_client_node
${catkin_LIBRARIES}
)
target_link_libraries(do_dishes_action_client_node1
${catkin_LIBRARIES}
)
target_link_libraries(do_dishes_action_server_node
${catkin_LIBRARIES}
)

2.4package.xml编写

添加actionlib的编译和执行依赖,如下

<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<run_depend>actionlib</run_depend>
<run_depend>actionlib_msgs</run_depend>

2.5测试

2.5.1 启动

消息反馈和中断抢占的演示,首先启动服务器,然后分别启动两个客户端,执行命令如下:

首先,启动服务器
rosrun first_actionlib_sample do_dishes_action_server_node
然后,启动客户端1
rosrun first_actionlib_sample do_dishes_action_client_node
接着,启动客户端2

rosrun first_actionlib_sample do_dishes_action_client_node1

2.5.2 结果

服务器结果如下:

[ INFO] [1477561873.888082387]: Received goal,the dish id is :
[ INFO] [1477561876.795322950]: PreemptCb!
[ INFO] [1477561876.795370142]:
[ INFO] [1477561876.795428811]: Set Preempted!
[ INFO] [1477561876.888346882]: Received goal,the dish id is :
[ INFO] [1477561886.888599364]:

客户端1被被客户端2中断结果如下:

[ INFO] [1477561873.888199741]: Goal just went active
[ INFO] [1477561873.888272439]: Got Feedback Complete Rate: 0.100000
[ INFO] [1477561874.888483533]: Got Feedback Complete Rate: 0.200000
[ INFO] [1477561875.888816424]: Got Feedback Complete Rate: 0.300000
[ INFO] [1477561876.795693526]: Finished in state [PREEMPTED]
[ INFO] [1477561876.795754009]: Toal dish cleaned:
Current State: PREEMPTED

客户端2结果显示如下:

[ INFO] [1477561876.888648770]: Goal just went active
[ INFO] [1477561876.888753797]: Got Feedback Complete Rate: 0.100000
[ INFO] [1477561877.888792417]: Got Feedback Complete Rate: 0.200000
[ INFO] [1477561878.888906824]: Got Feedback Complete Rate: 0.300000
[ INFO] [1477561879.888699775]: Got Feedback Complete Rate: 0.400000
[ INFO] [1477561880.888896675]: Got Feedback Complete Rate: 0.500000
[ INFO] [1477561881.889008655]: Got Feedback Complete Rate: 0.600000
[ INFO] [1477561882.888785829]: Got Feedback Complete Rate: 0.700000
[ INFO] [1477561883.888789072]: Got Feedback Complete Rate: 0.800000
[ INFO] [1477561884.888667138]: Got Feedback Complete Rate: 0.900000
[ INFO] [1477561885.888919402]: Got Feedback Complete Rate: 1.000000
[ INFO] [1477561886.889587174]: Finished in state [SUCCEEDED]
[ INFO] [1477561886.889736499]: Toal dish cleaned:
Yay! The dishes are now cleanCurrent State: SUCCEEDED

3.源码

下载地址:the_first_actionlib_sample

ROS知识(15)----Actionlib的使用(一)的更多相关文章

  1. ROS知识(5)----消息与服务的示例

    ROS中已经定义了较多的标准类型的消息,你可以用在这些标准类型的消息上再自定义自己的消息类型.这个在复杂数据传输很有用,例如节点和服务器进行交互时,就可能用到传输多个参数到服务器,并返回相应的结果.为 ...

  2. ROS知识(17)----Actionlib使用的例子

    1.Actionlib原理 英文版:DetailedDescription 翻译版:actionlib的身世之谜 2.Actionlib官方教程 Actionlib是ros的重要部件,对于复杂动作的执 ...

  3. ROS知识(2)----理解ROS系统结构

    学习新事物,方法高于技术本身,如果没有把握"BIG PICTURE"的话很难理解进去.通过以下几点进行理解ROS: ROS实际上不是操作系统,他只是一个通信的框架,一个代码管理的架 ...

  4. ROS知识(1)----ROS Jade安装

    ROS入门难,进去之后会是很简单,这是很多人的经验.但是今天安装ROS就吃了闭门羹,安装成功后,回顾发现,关键是操作系统Ubantu14.04没有安装好,一些系统包没有及时更新导致的.这里总结下ROS ...

  5. ROS知识(24)——ros::spin()和spinOnce的含义及其区别

    1.ros::spin()和spinOnce含义 如果在节点中如果订阅了话题,那么就必须要调用ros::sping()或者ros::spinOnce()函数去处理话题绑定的回调函数,否则该节点将不会调 ...

  6. ROS知识(23)——行为树Behavio Tree原理

    机器人的复杂行为的控制结构CA(Contrl Architecture)通常使用有限状态机来实现,例如ROS提供的smach.行为树是另外一种实现机器人控制的方法,ROS下代表的开源库有pi_tree ...

  7. ROS知识(20)----使用Master_API查询Master管理的节点话题服务内容

    在一些应用中会需要获取master的uri地址,发布的话题,订阅的话题,发布的服务,节点的信息等等.这些功能我们通常可一通过rosnode list, rosnode info, rostopic l ...

  8. ROS知识(18)----Pluginlib原理

    目录 Overview Example Providing a Plugin Registering/Exporting a Plugin The Plugin Description File Re ...

  9. ROS知识(14)----局部避障的动态窗口算法(DWA)及其调试的方法

    Dynamic Window Approach(DWA)是重要的局部轨迹规划算法,ROS中使用了DWA算法获得了很好的局部路径规划的效果.具体的教程可参考官方的导航调试资料Navigation Tun ...

随机推荐

  1. LaTeX技巧206:使用gather输入多行公式的技巧

    上文中提到了几个输入多行公式的环境,gather也是其中之一,gather输入的好处是每一行,他都会按照前文的编号计数器进行向下计数,这样保证了公式编号的连贯性.所以,当我们输入公式的每一行公式需要独 ...

  2. 【ContestHunter】【弱省胡策】【Round7】

    Prufer序列+高精度+组合数学/DP+可持久化线段树 Magic 利用Prufer序列,我们考虑序列中每个点是第几个插进去的,再考虑环的连接方式,我们有$$ans=\sum_{K=3}^n N^{ ...

  3. TortoiseSVN 和 VisualSVN

    ylbtech-Miscellaneos:TortoiseSVN 和 VisualSVN 1. TortoiseSVN 百科返回顶部 1-1.百科 TortoiseSVN 是 Subversion 版 ...

  4. 第三章 消息摘要算法--MD5

    注意:本节内容主要参考自<Java加密与解密的艺术(第2版)>第6章“验证数据完整性--消息摘要算法” 3.1.消息摘要算法:防止消息在传递过程中被篡改. 原理:任何消息经过消息摘要算法后 ...

  5. Libnids读书笔记 (转)

    一.当日工作(或学习)内容及进展情况(以条目式陈述,必要时配图说明) Libnids读书笔记: Libnids(Library Network Intusion Detection System)网络 ...

  6. Hash dump神器 (转)

    在Win7 x64位下无压力测试通过. 0 / INTRO========= Quarks PwDump 是一个Win32环境下的系统授权信息导出工具,目前除此之外没有任何一款工具可以导出如此全面的信 ...

  7. 算法-强连通分量和Kosaraju算法

    有向图中,连通性比较好理解,如果两个顶点V和顶点W是可达的,可以称之为强连通的,即存在路径A→B,同时也存在一条有向路径B→A.从之前的有向环的判定过程中其实我们可以得到一个结论就是两个是强连通的当且 ...

  8. 杨晓峰-Java核心技术-9 HashMap Hashtable TreeMap MD

    目录 第9讲 | 对比Hashtable.HashMap.TreeMap有什么不同? 典型回答 考点分析 知识扩展 Map 整体结构 有序 Map HashMap 源码分析 容量.负载因子和树化 精选 ...

  9. ubuntu16.04下部署tomcat9和java8启动一次需要七八分钟

    一.环境如下 Ubuntu16.04  +tomcat9+openjdk1.8 二.问题 在tomcat的bin下执行./startup.sh 如下图没有问题 root@bogon:/usr/apac ...

  10. 利用Docker搭建java项目开发环境

    一.需求 一台 Ubuntu 16.0.4 LTS ,安装了Docker服务,Rancher服务,也制作了Tomcat相关的image,接下来我们就来说一下如何快速的构建一个开发环境和测试环境 二.步 ...