20220314 update
发现生成action头文件处漏了两个点,需要在CMakeLists.txt中添加库和生成action信息的指令,更新的地方会有20220314update—start和20220314update—end这个标记


ROS学习笔记六:action-server/action-client

以下是最后一种通信机制action-server/action-client,尽管与service/client通信机制很像,它与service/client通信机制还是有很关键的不同点的:

  • 那就是多对多的action-server与action-client的交流机制
    service/client通信机制中service和client通信是单对单的,当client发送一个**“请求”后,只有当它接收到service的“响应"信息才能执行其他操作,可以理解为这是一种单通道的封闭式通信,而
    action-server与action-client通信就不受这种限制,action-client对server发出一个
    "请求"**后,还可以执行其他操作。

与service/client通信相似的是:

  • action-client需要知道它出发的“请求”的接收者的名称(serviceName)
  • action-server也需要知道“响应"信息的接收对象是“谁”

当然,action-servers和action-clients的框架里面还有很多功能和变量,可以在http://wiki.ros.org/actionlib 中查看,这里只列出一个简单的应用。

一.创建一个action-server的包

①依然使用catkin_simple功能来创建package
cs_create_pkg example_action_server roscpp actionlib

②然后在新建的package中创建一个actionpackage用来存储action messages的信息,方法与创建service messages一样。
cd example_action_server
mkdir action

③惯例,在package.xml文件中添加两行生成消息文件的语句:

<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>

二.定义action-server消息

与之前定义msg消息和service消息很相似,都需要建立一个对应格式的消息文件

  • publishers/subscribers的消息文件格式是: .msg
  • service/client的消息文件格式是: .srv
  • action-server/action-client的消息文件格式是: .action

其中,service messages比起简单的messages要复杂一些,而action的消息跟service的消息很类似,也有分多个区域,总体上要稍微复杂一点
service消息有两个消息区域

  • request
  • response

action消息有三个消息区域

  • goal
  • result
  • feedback

以下是本例要创建的一个action消息
①先进入到action的文件夹,创建一个名称为demo.action的文件:
cd action
touch demo.action

②然后写入如下内容:

#goal definition
int32 input
---
#result definition
int32 output
int32 goal_stamp
---
#feedback
int32 fdbk

三个消息区域通过三个连字符分隔开,最上面的是goad,中间的是result,最下面的feedback,“#”开头的注释语句不是必须的,可以省略。
注意,顺序不可以打乱,严格按照以上顺序排列

20220314update—start
③ 打开 CMakeLists.txt
添加对应的库和指定文件,这部分跟第二种通信方式,client/service非常接近

find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
tf
std_msgs
std_srvs
actionlib
actionlib_msgs
message_generation
geometry_msgs
)add_action_files(FILESdemo.action
)generate_messages(DEPENDENCIESstd_msgsactionlib_msgsgeometry_msgs
)

确保有这部分就可以,

20220314update—end

④跟着就可以进行编译生成action消息类型的头文件了
catkin_make
生成的头文件在

~/ros_ws/devel/include/packageName

这里的packageName是example_action_server,里面有7个头文件,如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6bPgFG85-1647246035810)(//img-blog.csdn.net/20180317165922917?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L1dpbGxfWWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
其中,以demoAction.h为主,其他六个头文件都包含在该头文件中,要调用该包中的action消息类型,只需要知道demoAction.h这个头文件的名称即可。


三.创建一个action server节点

以下是一个action server节点的代码:

#include<ros/ros.h> //惯例添加
#include <actionlib/server/simple_action_server.h> //这是一个library里面一个做好的包(simple_action_server)里面的头文件
#include<example_action_server/demoAction.h> //这个头文件是重点,在上一部分生成的action消息的头文件int g_count = 0;
bool g_count_failure = false;class ExampleActionServer {private:ros::NodeHandle nh_;  // 节点句柄actionlib::SimpleActionServer<example_action_server::demoAction> as_;//创建一个名称为"as_"的“SimpleActionServer”,SimpleActionServer是一个在actionlib里面的类(在actionlib的包中有定义),消息类型为example_action_server::demoAction,即上部分定义的action消息类型// 以下三个是与client交流传递的消息类型example_action_server::demoGoal goal_; // 接收clients发送的goal message的变量example_action_server::demoResult result_; // 保存result结果信息的变量,当完成goad的请求后将结果信息发送给clientexample_action_server::demoFeedback feedback_; //在这个例子中没有用到feedback信息,它起一个反馈作用,将一定信息反馈给client,具体参数根据实际需要设定,如 as_.publishFeedback(feedback_); ,就可以将变量“feedback_”发送给clientpublic:ExampleActionServer(); //在类定义之外定义构造函数的主体~ExampleActionServer(void) {}// Action接口void executeCB(const actionlib::SimpleActionServer<example_action_server::demoAction>::GoalConstPtr& goal);
};ExampleActionServer::ExampleActionServer() :as_(nh_, "example_action", boost::bind(&ExampleActionServer::executeCB, this, _1),false)
//执行上述构造函数:成员as_将通过指定的节点句柄(nh_)来实例化, 并在接收到goad消息后执行一个函数(executeCB),这个函数是类(ExampleActionServer)中的一个成员方法(member method)
// 在这里定义了server的名称叫为“example_action”,这个名称很重要,server和client通信需要知道这个名字
//“this”会告诉“boost::bind”这个函数是类的成员
//“_1”被“boost::bind”用来通知“simple action server”,回调函数(executeCB)只取一个数值
//“false”的意思是暂时不启动这个server(在这个构造函数中的后面会启动server)
{ROS_INFO("in constructor of exampleActionServer...");as_.start(); //在上述的初始化参数使用false,先不启动action server,到这里才启动,就是要确保server的实例化对象要先完成之后再启动这个实例化对象,避免出现意外状况
}//下面是具体的executeCBD(成员方法)的执行函数
//example_action_server::demoAction上部分定义的action消息类型
void ExampleActionServer::executeCB(const actionlib::SimpleActionServer<example_action_server::demoAction>::GoalConstPtr& goal) {//result消息由两个成员组成,一个是“input”,它保存的是clients发送过来的goal消息,另一个是“goal_stamp”,记录接收goal消息的次数g_count++; // 从server启动开始追踪被执行的goal消息数量result_.output = g_count; // 在这里使用在类中定义过的成员变量result_result_.goal_stamp = goal->input;//检测clients和server是否保持同步状态if (g_count != goal->input) {ROS_WARN("hey--mismatch!");ROS_INFO("g_count = %d; goal_stamp = %d", g_count, result_.goal_stamp);g_count_failure = true; //set a flag to commit suicideROS_WARN("informing client of aborted goal");as_.setAborted(result_); // 这个函数的意思是放弃这个goad并发送result消息通知client}else {as_.setSucceeded(result_); // 这个函数的意思是成功执行这个goad并发送result消息通知client}
}int main(int argc, char** argv) {ros::init(argc, argv, "demo_action_server_node"); //初始化,命名该节点ROS_INFO("instantiating the demo action server: ");ExampleActionServer as_object; // 创建类(ExampleActionServer)的一个实例化对象ROS_INFO("going into spin");// 从这里开始,所有的工作都是在action server中的成员方法(executeCB())完成的// 在action server(example_action)下有五个topic: cancel, feedback, goal, result, statuswhile (!g_count_failure && ros::ok()) {ros::spinOnce(); }return 0;
}

四.创建一个action client节点

在和action server同一个package中建立一个example_aciton_client.cpp文件,以下是一个action client节点的代码:

#include<ros/ros.h>
#include <actionlib/client/simple_action_client.h> //与server一样,client也需要使用actionlib library里面的头文件,只是使用的是simple_action_client.h
#include<example_action_server/demoAction.h> //上一部分定义的action messages文件//下面这个函数是非必要的,当goal完成时就会调用这个函数一次,但这也是一种访问server中“result”消息的便捷方式
void doneCb(const actionlib::SimpleClientGoalState& state,const example_action_server::demoResultConstPtr& result) {ROS_INFO(" doneCb: server responded with state [%s]", state.toString().c_str());int diff = result->output - result->goal_stamp;ROS_INFO("got result output = %d; goal_stamp = %d; diff = %d", result->output, result->goal_stamp, diff);
}int main(int argc, char** argv) {ros::init(argc, argv, "demo_action_client_node"); //初始化,命名节点int g_count = 0;//这是一个与server兼容的goal消息的对象example_action_server::demoGoal goal;实例化一个类型为“example_action_server::demoGoal”的对象actionlib::SimpleActionClient<example_action_server::demoAction> action_client("example_action", true);//action_client是“actionlib::SimpleActionClient”实例化的对象,使用的消息类型是“example_action_server::demoAction”// “example_action”是server的名字,在action server节点中命名的//参数“true”是为了说明新的client将作为一个单线程运行// 以下开始连接server:ROS_INFO("waiting for server: ");bool server_exists = action_client.waitForServer(ros::Duration(5.0)); //等待5秒,若括号内不设置时间,会一直等待// 有一点很奇怪,好像并没有等地5秒,但是如果server没有运行却会很快会有返回值if (!server_exists) {ROS_WARN("could not connect to server; halting");return 0; // 输出一个警报消息,这部分也是非必要的}ROS_INFO("connected to action server"); // 成功连接while (true) {// 开始给goal消息赋值g_count++;goal.input = g_count; // 这只是一个按序列编号发送的goal消息//action_client.sendGoal(goal); // 只发送goal消息action_client.sendGoal(goal, &doneCb); // 在发送goal消息时可以使用一个额外的回调函数来检测goal的执行情况//    action_client.sendGoal(goal, &doneCb, &activeCb, &feedbackCb); //可以同时调用多个回调函数bool finished_before_timeout = action_client.waitForResult(ros::Duration(5.0));//等待result消息5秒,同样,去掉括号内的数值,会一直等待//若没有接收到result消息,则发出警报if (!finished_before_timeout) {ROS_WARN("giving up waiting on result for goal number %d", g_count);return 0;} else {//否则,就说明server反馈了result消息给我们}}return 0;
}

这里的client和server是在同一个package里面的,很多时候同一个server有很多个clients,而且都是在不同的package,这时候就需要在package.xml文件里面添加action messages包的依赖项,同时还要在client节点的文件中加上action messages的头文件。

还需要在CMakeLists.txt文件中添加:
①Boost所在package的依赖项

find_package(Boost REQUIRED COMPONENTS system thread)

②生成两个节点的可执行程序的命令:

cs_add_executable(example_action_server src/example_action_server.cpp)
cs_add_executable(example_action_client src/example_action_client.cpp)

最后进行编译就完成了
catkin_make


五.运行action-server/action-client节点

运行节点前,请确保已经运行了roscore

分别在两个不同的terminal中启动server和client:
rosrun example_action_server example_action_server
rosrun example_action_server example_action_client

在client的端口会有如下输出:

[ INFO] [1521442053.251384877]:  doneCb: server responded with state [SUCCEEDED]
[ INFO] [1521442053.251542525]: got result output = 2242; goal_stamp = 2242; diff = 0
[ INFO] [1521442053.254128683]:  doneCb: server responded with state [SUCCEEDED]
[ INFO] [1521442053.254174911]: got result output = 2243; goal_stamp = 2243; diff = 0
[ INFO] [1521442053.257378829]:  doneCb: server responded with state [SUCCEEDED]
[ INFO] [1521442053.257444954]: got result output = 2244; goal_stamp = 2244; diff = 0
[ INFO] [1521442053.264676774]:  doneCb: server responded with state [SUCCEEDED]
[ INFO] [1521442053.264862612]: got result output = 2245; goal_stamp = 2245; diff = 0
[ INFO] [1521442053.267605141]:  doneCb: server responded with state [SUCCEEDED]
[ INFO] [1521442053.267730561]: got result output = 2246; goal_stamp = 2246; diff = 0

当节点运行后,可以查看当前有几个topic正在运行:
rostopic list
会有如下输出:

/example_action/cancel
/example_action/feedback
/example_action/goal
/example_action/result
/example_action/status
/rosout
/rosout_agg

可知有5个新的topic在example_action下被运行,可以通过查看命令观察它们输出:
例如查看goal的消息:
rostopic echo example_action/goal
会有如下输出:

---
header: seq: 63929stamp: secs: 1521442598nsecs: 441791983frame_id: ''
goal_id: stamp: secs: 1521442598nsecs: 441792381id: /demo_action_client_node-63930-1521442598.441792381
goal: input: 63930
---
header: seq: 63930stamp: secs: 1521442598nsecs: 443889821frame_id: ''
goal_id: stamp: secs: 1521442598nsecs: 443890098id: /demo_action_client_node-63931-1521442598.443890098
goal: input: 63931

在这个例程里面使用的**“simple”action-server library** 不能同时处理多个goals,也不能让它们排成队列,一个接一个处理,通俗地讲就是只有一个坑,被人占了就没地儿去了,所以选用action-server library时要考虑清楚想要的特性是什么。

ROS学习笔记六:action-server/action-client相关推荐

  1. ROS学习笔记六:理解ROS服务和参数

    ROS学习笔记六:理解ROS服务和参数 主要介绍ROS服务和参数,同时使用命令行工具rosservice和rosparam. ROS service service是节点之间互相通信的另一种方式,se ...

  2. CSR867x学习笔记:SPP Server and Client

    为了让CSR867x的开发更容易,现与思度科技联合推出CSR867x学习板[淘宝链接:思度科技CSR开发板]. 技术交流QQ群号:743434463 开发板会员QQ群号:725398389(凭订单号入 ...

  3. ROS 学习笔记(三):自定义服务数据srv+server+client 示例运行

    ROS 学习笔记(三):自定义服务数据srv+Server+Client 示例运行 一.自定义服务数据: 1.向功能包添加自定义服务文件(AddTwoInts.srv) cd ~/catkin_ws/ ...

  4. Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  5. ROS学习笔记(一)补充篇 参考创客制造

    我将ROS的CPP部分分成7个部分: 1.基础的node param 2.动态调节参数 3.关于TF变换 4.actionlib 5.插件技术 6.movebase 7.nodelet技术 前言 相比 ...

  6. ROS学习笔记(八): ROS通信架构

    ROS学习笔记(八): ROS通信架构 文章目录 01 Node & Master 1.1 Node 1.2 Master 1.3 启动master和node 1.4 rosrun和rosno ...

  7. Ethernet/IP 学习笔记六

    Ethernet/IP 学习笔记六 EtherNet/IP defines two primary types of communications: explicit and implicit (Ta ...

  8. ROS学习笔记七:使用rqt_console和roslaunch

    ROS学习笔记七:使用rqt_console和roslaunch 本节主要介绍在调试时使用的rqt_console和rqt_logger_level,以及一次性打开多个节点的工具roslaunch. ...

  9. ROS学习笔记四:理解ROS节点

    ROS学习笔记四:理解ROS节点 本节主要介绍ROS图形概念,讨论ROS命令行工具roscore.rosnode和rosrun. 要求 要求已经在Linux系统中安装一个学习用的ros软件包例子: s ...

  10. ROS学习笔记(1):发布者和订阅者

    ROS学习笔记(1):publishers and subscribers 1.ros通信简介 2.C++中的类与对象 3.publishers/subscribers 4.常用指令 1.ros通信简 ...

最新文章

  1. 20145321 《Java程序设计》第7周学习总结
  2. 计算机网络第七章:网络安全
  3. TI CC2530的BasicRF与Zstack的同与异(重点讲了MAC层)
  4. ant 合并 jar
  5. shell循环,判断介绍,以及实例
  6. Google新项目:从一条线开始,完成地球的绘制
  7. 纠结的rename命令
  8. Codeforces 964B(贪心)
  9. Keepalived高可用(原理、安装、启动、单实例配置、双实例双主配置实战篇)
  10. XPS Viewer 无法设置权限账户 - 无法激活此计算机上的任何权限管理账户
  11. Python函数的定义使用、return返回值、参数传递方式、结合字典列表循环的使用以及将函数存储在模块中
  12. 计算机专业软件工程的二本大学有哪些,全国软件工程专业大学排名 一本二本大学名单...
  13. UC Android官方下载,手机uc浏览器下载并安装-uc浏览器app最新版本v13.3.9.1119 安卓官方版 - 极光下载站...
  14. C语言 将一个3*3的矩阵转置,用函数和指针实现
  15. cocos2d-x 4.0 学习之路(七)场景切换
  16. 求n的阶乘并显示过程
  17. 几本.Net的经典书籍
  18. Gartner年度趋势预测汇总整理(2006年-2023年)
  19. vmware:end kernel panic not syncing
  20. vue+axios 实现Excel下载

热门文章

  1. 基于MAC地址划分VLAN
  2. keras求两向量间的余弦值
  3. 冷色系清新调、日系清新调 、电影色调复古风、欧美风复古,用曲线就可以调了!!!...
  4. Fengshui(双向bfs看风水···)
  5. HDU - 4565 So Easy! 矩阵快速幂
  6. 流星蝴蝶剑5.18公测(转自官方)
  7. 两个PDF怎么合并一个pdf
  8. Struts2 框架项目新建教程(strut 2.5.20)(基于IDEA)
  9. [概率论]艾波寧捎信(poisson分布)
  10. 如何避免对话冲突-《关键对话》笔记与心得