ROS入门笔记(十二):动作编程 (C++)

文章目录

  • 01 导读
  • 02 功能包的创建
  • 03 在功能包中创建action(动作)
    • 3.1 自定义action
    • 3.2 在package.xml中添加功能包依赖
    • 3.3 在CMakeLists.txt添加编译选项
  • 04 功能包的源代码编写
    • 4.1 编写action_server.cpp
    • 4.2 编写action_client.cpp
  • 05 功能包的编译配置(编译节点)
  • 06 功能包的编译
  • 07 测试action_server和action_client
    • 7.1 运行action_server
    • 7.2 运行action_client

01 导读

C++代码必须通过编译生成可执行文件;

python代码是可执行文件,不需要编译;

  • 开发的功能包都放在catkin_ws这样一个工作空间里;
  • 新建的功能包取名为action_example;

工作模式的结构示意图如下:

什么是动作(action)

  • 一种问答通信机制;
  • 带有连续反馈;
  • 可以在任务过程中止运行;
  • 基于ROS的消息机制实现。

通信双方在ROS Action Protocal下进行交流通信是通过接口来实现,如下图:

Action的接口

  • goal:发布任务目标;
  • cancel:请求取消任务;
  • status:通知客户端当前的状态;
  • feedback:周期反馈任务运行的监控数据;
  • result:向客户端发送任务的执行结果,只发布一次。

我们可以看到,客户端会向服务器发送目标指令和取消动作指令,而服务器则可以给客户端发送实时的状态信息,结果信息,反馈信息等等,从而完成了service没法做到的部分.

02 功能包的创建

在catkin_ws/src/目录下新建功能包action_example,并在创建时显式的指明依赖roscpp和actionlib actionlib_msgs,依赖actionlib actionlib_msgs将作为基本数据类型用于定义我们的服务类型。打开命令行终端,输入命令:

$ cd ~/catkin_ws/src#创建功能包topic_example时,显式的指明依赖roscpp和std_msgs,
#依赖会被默认写到功能包的CMakeLists.txt和package.xml中
$ catkin_create_pkg action_example roscpp actionlib actionlib_msgs

03 在功能包中创建action(动作)

Action的工作原理是client-server模式,也是一个双向的通信模式。通信双方在ROS Action Protocol下通过消息进行数据的交流通信。client和server为用户提供一个简单的API来请求目标(在客户端)或通过函数调用和回调来执行目标(在服务器端)。

3.1 自定义action

利用动作库进行请求响应,动作的内容格式应包含三个部分,目标、反馈、结果。

在功能包action_example目录下新建action目录,然后在action_example/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

3.2 在package.xml中添加功能包依赖

action文件被转换成为C++,Python和其他语言的源代码:

查看package.xml, 确保它包含以下语句:

*部分ROS版本中的exec_depend需要改成run_depend

<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>

3.3 在CMakeLists.txt添加编译选项

##1 Find catkin macros and libraries
##1 if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
##1 is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTSroscppactionlib_msgs actionlib
)##2 Generate actions in the 'action' folder
add_action_files(FILESDoDishes.action
)##3 Generate added messages and services with any dependencies listed here
generate_messages(DEPENDENCIESactionlib_msgs
)

04 功能包的源代码编写

在新建的功能包action_example/src目录下新建两个文件action_server.cpp和action_client.cpp,并将下面的代码分别填入。

4.1 编写action_server.cpp

如何实现一个动作服务器:

  • 初始化ROS节点;
  • 创建动作服务器实例;
  • 启动服务器,等待动作请求;
  • 在回调函数中完成动作服务功能的处理,并反馈进度信息;
  • 动作完成,发送结束信息。

在action_example/src包中创建action_server.cpp文件:

#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include "action_example/DoDishesAction.h"typedef actionlib::SimpleActionServer<action_example::DoDishesAction> Server;// 收到action的goal后调用该回调函数
void execute(const action_example::DoDishesGoalConstPtr& goal, Server* as)
{ros::Rate r(1);action_example::DoDishesFeedback feedback;ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id);// 假设洗盘子的进度,并且按照1hz的频率发布进度feedbackfor(int i=1; i<=10; i++){feedback.percent_complete = i * 10;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);// 服务器开始运行server.start();ros::spin();return 0;
}

4.2 编写action_client.cpp

如何实现一个动作客户端:

  • 初始化ROS节点;
  • 创建动作客户端实例;
  • 连接动作服务端;
  • 发送动作目标;
  • 根据不同类型的服务端反馈处理回调函数。

在action_example/src包中创建action_client.cpp文件,并在其中粘贴以下內容:

#include <actionlib/client/simple_action_client.h>
#include "action_example/DoDishesAction.h"typedef actionlib::SimpleActionClient<action_example::DoDishesAction> Client;// 当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,const action_example::DoDishesResultConstPtr& result)
{ROS_INFO("Yay! The dishes are now clean");ros::shutdown();
}// 当action激活后会调用该回调函数一次
void activeCb()
{ROS_INFO("Goal just went active");
}// 收到feedback后调用该回调函数
void feedbackCb(const action_example::DoDishesFeedbackConstPtr& feedback)
{ROS_INFO(" percent_complete : %f ", feedback->percent_complete);
}int main(int argc, char** argv)
{ros::init(argc, argv, "do_dishes_client");// 定义一个客户端Client client("do_dishes", true);// 等待服务器端ROS_INFO("Waiting for action server to start.");client.waitForServer();ROS_INFO("Action server started, sending goal.");// 创建一个action的goalaction_example::DoDishesGoal goal;goal.dishwasher_id = 1;// 发送action的goal给服务器端,并且设置回调函数client.sendGoal(goal,  &doneCb, &activeCb, &feedbackCb);ros::spin();return 0;
}

05 功能包的编译配置(编译节点)

说明:

  • C++代码必须通过编译生成可执行文件;
  • python代码是可执行文件,不需要编译;

如何编译代码

  • 设置需要编译的代码和生成的可执行文件;
  • 设置链接库;
  • 设置依赖。

创建功能包action_example时,显式的指明依赖roscpp和std_msgs,依赖会被默认写到功能包的CMakeLists.txt和package.xml中。

在 CMakeLists.txt 文件末尾加入几条语句:

add_executable(action_client src/action_client.cpp)
target_link_libraries( action_client ${catkin_LIBRARIES})
add_dependencies(action_client ${${PROJECT_NAME}_EXPORTED_TARGETS})add_executable(action_server src/action_server.cpp)
target_link_libraries( action_server ${catkin_LIBRARIES})
add_dependencies(action_server ${${PROJECT_NAME}_EXPORTED_TARGETS})

这会生成两个可执行文件, action_clientaction_server, 默认存储到 devel space 目录下,具体是在~/catkin_ws/devel/lib/<package name> 中.

06 功能包的编译

$ cd ~/catkin_ws
$ catkin_make -DCATKIN_WHITELIST_PACKAGES="action_example"
$ source ~/catkin_ws/devel/setup.bash   # 刷新环境

07 测试action_server和action_client

7.1 运行action_server

第一步,打开一个命令行终端:

$ roscore

第二步,打开第二个命令行终端:

# 用rosrun <package_name> <node_name>启动功能包中的发布节点。
$ source ~/catkin_ws/devel/setup.bash    # 激活catkin_ws工作空间(必须有,必不可少)
$ rosrun action_example action_server

你将看到如下的输出信息:

[ INFO] [1588752334.514526874]: Dishwasher 1 is working.
[ INFO] [1588752344.515033939]: Dishwasher 1 finish working.  # Server节点启动后的日志信息

7.2 运行action_client

打开第三个命令行客户端:

$ source ~/catkin_ws/devel/setup.bash     # 激活catkin_ws工作空间(必须有,必不可少)
$ rosrun action_example action_client

你将会看到如下的输出信息:

[ INFO] [1588752334.233231877]: Waiting for action server to start.
[ INFO] [1588752334.513889608]: Action server started, sending goal.
[ INFO] [1588752334.514780017]: Goal just went active
[ INFO] [1588752334.515056866]:  percent_complete : 10.000000
[ INFO] [1588752335.516336080]:  percent_complete : 20.000000
[ INFO] [1588752336.516271562]:  percent_complete : 30.000000
[ INFO] [1588752337.516315111]:  percent_complete : 40.000000
[ INFO] [1588752338.515751638]:  percent_complete : 50.000000
[ INFO] [1588752339.515473734]:  percent_complete : 60.000000
[ INFO] [1588752340.516373053]:  percent_complete : 70.000000
[ INFO] [1588752341.515448200]:  percent_complete : 80.000000
[ INFO] [1588752342.515654876]:  percent_complete : 90.000000
[ INFO] [1588752343.515571413]:  percent_complete : 100.000000
[ INFO] [1588752344.516076162]: Yay! The dishes are now clean

现在,你已经成功地运行了你的第一个action_server和action_client程序。

ROS入门笔记(十二):动作编程 (C++)相关推荐

  1. ROS入门笔记(二):ROS安装与环境配置及卸载(重点)

    ROS入门笔记(二):ROS安装与环境配置及卸载(重点) 文章目录 1 ROS安装步骤 1.1 ROS版本 1.2 确定Ubuntu版本号 1.3 安装ROS 1.3.1 Ubuntu初始环境配置 1 ...

  2. ROS学习笔记十二:使用roswtf

    ROS学习笔记十二:使用roswtf 在使用ROS过程中,roswtf工具可以为我们提供ROS系统是否正常工作的检查作用. 注意:在进行下列操作之前,请确保roscore没有运行. 检查ROS是否安装 ...

  3. ROS学习笔记十二:使用gazebo在ROS中仿真

    想要在ROS系统中对我们的机器人进行仿真,需要使用gazebo. gazebo是一种适用于复杂室内多机器人和室外环境的仿真环境.它能够在三维环境中对多个机器人.传感器及物体进行仿真,产生实际传感器反馈 ...

  4. Python语言入门这一篇就够了-学习笔记(十二万字)

    Python语言入门这一篇就够了-学习笔记(十二万字) 友情提示:先关注收藏,再查看,12万字保姆级 Python语言从入门到精通教程. 文章目录 Python语言入门这一篇就够了-学习笔记(十二万字 ...

  5. ROS入门笔记(十):编写与测试简单的消息发布器和订阅器(C++)

    ROS入门笔记(十):编写与测试简单的消息发布器和订阅器(C++) 文章目录 01 导读 02 功能包的创建 03 功能包的源代码编写 3.1 编写发布器节点(talker.cpp) 3.2 编写订阅 ...

  6. 深度学习入门笔记(二十):经典神经网络(LeNet-5、AlexNet和VGGNet)

    欢迎关注WX公众号:[程序员管小亮] 专栏--深度学习入门笔记 声明 1)该文章整理自网上的大牛和机器学习专家无私奉献的资料,具体引用的资料请看参考文献. 2)本文仅供学术交流,非商用.所以每一部分具 ...

  7. ROS Noetic入门笔记(二)ROS Noetic创建工作空间和功能包

    ROS Noetic入门笔记(一)在ubuntu20.04中安装ROS Noetic并简单测试 ROS Noetic入门笔记(二)ROS Noetic创建工作空间和功能包 ROS Noetic入门笔记 ...

  8. ROS入门笔记(九):编写ROS的第一个程序hello world(重点)

    ROS入门笔记(九):编写ROS的第一个程序hello world(重点) 文章目录 1 Catkin工作空间 1.1 创建catkin工作空间 1.2 编译工作空间 1.3 设置环境变量 1.4 检 ...

  9. ROS入门笔记(七):详解ROS文件系统

    ROS入门笔记(七):详解ROS文件系统 文章目录 01 Catkin编译系统 1.1 Catkin特点 1.2 Catkin工作原理 1.3 使用`catkin_make`进行编译 02 Catki ...

最新文章

  1. 分布式系统设计原理与方案
  2. java c c 的应用_javac 简单应用
  3. SAP系统与MES系统的数据协同技术方案
  4. 分布式缓存Redis介绍
  5. 缓存数据库面试 - redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?
  6. Windows Store 开发总结——文件操作
  7. java回收内存_JAVA之内存回收
  8. atitit 短信验证码的源码实现  .docx
  9. docker常用操作(八) docker安装Zookeeper
  10. 【步骤详解】畅捷通T+Cloud无代码集成钉钉群机器人示例
  11. zyf的简单数学题(找规律)
  12. 【报错】进程已结束,退出代码-1073740791 (0xC0000409)
  13. AIME数学竞赛信息大全
  14. pytorch转onnx报错的可能原因traced region did not have observable data dependence
  15. IGBT的双脉冲测试实验
  16. [MP3]MP3固件持续分享(2019.1.25)
  17. spring框架使用JavaMailSenderImpl发送邮件
  18. 2019春招宇视科技嵌入式面试
  19. 西部光伏电站不景气 屋顶光伏春天将至
  20. OAuth安全相关问题

热门文章

  1. 北大OJ(POJ 3237)鸡兔同笼
  2. 网易云深度学习第二课notebook1
  3. sap netweaver 7.02_sap顾问工作内容,岗位职责
  4. eclipse启动mysql报错_Eclipse+mysql+java Eclipse中运行没有问题,但打包后运行不了,也不报错,求高手指点...
  5. 记一次生产数据库系统内存使用过高的案例
  6. 深入解析:DBA_OBJECTS中的OBJECT_ID与DATA_OBJECT_ID的区别
  7. 解读年度数据库PostgreSQL:如何处理并发控制(一)
  8. MySQL 分页优化中的 “ INNER JOIN方式优化分页算法 ” 到底在什么情况下会生效?
  9. 带你了解 HBase 数据模型和 HBase 架构
  10. AOC萌新探索:搭建和体验在线AOC环境