actionlib
2021/11/24 6:10:22
本文主要是介绍actionlib,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
actionlib
前言
- Actionlib是ROS中一个很重要的库,类似service通信机制,actionlib也是一种请求响应机制的通信方式,actionlib主要弥补了service通信的一个不足,就是当机器人执行一个长时间的任务时,假如利用service通信方式,那么publisher会很长时间接受不到反馈的reply,致使通信受阻。当service通信不能很好的完成任务时候,actionlib则可以比较适合实现长时间的通信过程,actionlib通信过程可以随时被查看过程进度,也可以终止请求,这样的一个特性,使得它在一些特别的机制中拥有很高的效率
简介
- 那么什么是 action?
- 一种问答通信机制
- 带有连续的反馈
- 可以在任务过程中止运行
- 基于ROS的消息机制实现
- 多对多的action-server与action-client的交互机制
客户端-服务器交互
- actionlib 使用 client-server工作模式,ActionClient 和 ActionServer 通过 "ROS Action Protocol" 进行通信,"ROS Action Protocol" 以 ROS 消息方式进行传输。此外 ActionClient 和 ActionServer 为用户提供了一些简单的接口,用户使用这些接口可以完成 goal 请求(client-side)和 goal 执行(server-side)
- ActionClient 和 ActionServer 之间使用action protocol通信,action protocol 就是预定义的一组 ROS message,这些 message 被放到 ROS topic 上在 ActionClient 和 ActionServer 之间进行传输实现二者的沟通
ROS Message:
- goal:用于向服务器发送任务目标
- cancel:用于向服务器发送取消请求
- status:用于通知客户端系统中每个目标的当前状态
- feedback:用于周期反馈任务运行的监控数据
- result:用于向client发送任务的执行结果,这个topic只会发布一次
创建action功能包
- 依然使用 catkin_simple 功能来创建 package
catkin_create_pkg dodishes roscpp actionlib actionlib_msgs
- 然后在新建的package中创建一个action文件夹用来存储action messages的信息,方法与创建service messages一样
cd dodishes mkdir action
- 惯例,在package.xml文件中添加两行生成消息文件的语句
<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
定义action文件
- ROS系统在action文件(文件名后缀为.action)中定义了上述 goal、result、feedback 等消息,每部分用 “---” 分隔
- 这些文件被放置在包的 ./action 目录
例如:./action/DoDishes.action
./action/DoDishes.action # 定义目标消息 # Define the goal uint32 dishwasher_id # Specify which dishwasher we want to use --- # Define the result # 定义结果消息 uint32 total_dishes_cleaned --- # Define a feedback message # 定义周期反馈消息 float32 percent_complete
基于这个 .action 文件,需要生成 6 条消息,以便客户端和服务器进行通信
功能包配置
package.xml
- 在package.xml文件中添加以下几行
<build_depend>actionlib</build_depend> <build_depend>actionlib_msgs</build_depend> <exec_depend>actionlib</exec_depend> <exec_depend>actionlib_msgs</exec_depend>
CMakeLists.txt
- 在CMakeLists.txt文件中添加以下几行
find_package(catkin REQUIRED COMPONENTS actionlib_msgs actionlib ) add_action_files(DIRECTORY action FILES DoDishes.action ) generate_messages( DEPENDENCIES actionlib_msgs ) catkin_package( CATKIN_DEPENDS actionlib_msgs )
编写action_server
- 在dodishes/src中创建DoDishes_server.cpp文件
#include <ros/ros.h> #include <actionlib/server/simple_action_server.h> // 这是一个library里面一个做好的包(simple_action_server)里面的头文件 #include "dodishes/DoDishesAction.h" // 这个头文件是重点,在上一部分生成的action消息的头文件 // 为服务端数据类型定义别名 typedef actionlib::SimpleActionServer<dodishes::DoDishesAction> Server; // 收到action的goal后调用该回调函数 void execute(const dodishes::DoDishesGoalConstPtr & goal, Server * as) { ros::Rate r(1); dodishes::DoDishesFeedback feedback; ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id); // 假设洗盘子的进度,并且按照1hz的频率发布进度feedback for (int i = 1; i <= 10; i++) { feedback.percent_complete = i * 10; // 发布feedback as->publishFeedback(feedback); r.sleep(); } // 当action完成后,向客户端返回结果 ROS_INFO("Dishwasher %d finish working.", goal->dishwasher_id); as->setSucceeded(); } int main(int argc, char** argv) { ros::init(argc, argv, "do_dishes_server"); ros::NodeHandle n; // 定义一个服务器 Server server(n, "do_dishes", boost::bind(&execute, _1, &server), false); // 其中的参数n,就是NodeHandle。而“do_dishes”,是你给server起的名字 // boost::bind(&execute, _1, &server)是当收到新的goal时候需要的返回函数 // false的意思是暂时不启动这个server server.start(); // 服务器开始运行 ros::spin(); return 0; }
总结:
- 初始化ROS节点;
- 创建action_server实例;
- 启动服务器,等待action请求;
- 在回调函数中完成动作服务功能的处理,并反馈进度信息;
- action完成,发送结束信息
编写action_client
- 在dodishes/src中创建DoDishes_client.cpp文件
#include <ros/ros.h> #include <actionlib/client/simple_action_client.h> // 这是一个library里面一个做好的包(simple_action_server)里面的头文件 #include "dodishes/DoDishesAction.h" // 这个头文件是重点,在上一部分生成的action消息的头文件 // 为客户端数据类型定义一个别名 typedef actionlib::SimpleActionClient<dodishes::DoDishesAction> Client; // 当服务器完成后会调用该回调函数一次 void doneCb(const actionlib::SimpleClientGoalState & state, const dodishes::DoDishesResultConstPtr & result) { ROS_INFO("Yay! The dishes are now clean"); ros::shutdown(); } // 当服务器激活后会调用该回调函数一次 void activeCb() { ROS_INFO("Goal just went active"); } // 收到feedback后调用该回调函数 void feedbackCb(const dodishes::DoDishesFeedbackConstPtr & feedback) { ROS_INFO(" percent_complete : %f ", feedback->percent_complete); } int main(int argc, char **argv) { ros::init(argc, argv, "do_dishes_client"); // 定义一个客户端,连接名为do_dishes的服务器,开启自循环线程 Client client("do_dishes", true); ROS_INFO("Waiting for action server to start."); client.waitForServer(); // 客户端等待服务器函数 // 可以传递一个ros::Duration作为最大等待值,程序进入到这个函数开始挂起等待 // 服务器就位或者达到等待最大时间退出,前者返回true,后者返回false ROS_INFO("Action server started, sending goal."); dodishes::DoDishesGoal goal; // 创建一个action的goal goal.dishwasher_id = 1; // 定义盘子的目标,也就是洗一个盘子 // 发送action的goal给服务器端,并且设置回调函数 client.sendGoal(goal, &doneCb, &activeCb, &feedbackCb); ros::spin(); return 0; }
总结:
- 初始化ROS节点;
- 创建action_client实例;
- 连接action服务端;
- 发送action goal;
- 根据不同类型的服务端反馈处理回调函数
编译配置
CMakeLists.txt
add_executable(DoDishes_client src/DoDishes_client.cpp) target_link_libraries( DoDishes_client ${catkin_LIBRARIES}) add_dependencies(DoDishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS}) add_executable(DoDishes_server src/DoDishes_server.cpp) target_link_libraries( DoDishes_server ${catkin_LIBRARIES}) add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})
这篇关于actionlib的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享