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

本文涉及的产品
资源编排,不限时长
简介: ROS入门笔记(十二):动作编程 (C++)

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 COMPONENTS
  roscpp
  actionlib_msgs 
  actionlib
)
##2 Generate actions in the 'action' folder
add_action_files(
  FILES
  DoDishes.action
)
##3 Generate added messages and services with any dependencies listed here
generate_messages(
  DEPENDENCIES
  actionlib_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的频率发布进度feedback
    for(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的goal
    action_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})

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创建VPC和VSwitch
本场景主要介绍如何利用阿里云资源编排服务,定义资源编排模板,实现自动化创建阿里云专有网络和交换机。
阿里云资源编排ROS使用教程
资源编排(Resource Orchestration)是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。编排模板同时也是一种标准化的资源和应用交付方式,并且可以随时编辑修改,使基础设施即代码(Infrastructure as Code)成为可能。 产品详情:https://www.aliyun.com/product/ros/
目录
相关文章
|
3月前
|
Ubuntu 机器人 Linux
|
30天前
|
存储 传感器 编解码
ROS机器视觉入门:从基础到人脸识别与目标检测
前言 从本文开始,我们将开始学习ROS机器视觉处理,刚开始先学习一部分外围的知识,为后续的人脸识别、目标跟踪和YOLOV5目标检测做准备工作。我采用的笔记本是联想拯救者游戏本,系统采用Ubuntu20.04,ROS采用noetic。 颜色编码格式,图像格式和视频压缩格式 (1)RGB和BGR:这是两种常见的颜色编码格式,分别代表了红、绿、蓝三原色。不同之处在于,RGB按照红、绿、蓝的顺序存储颜色信息,而BGR按照蓝、绿、红的顺序存储。 rgb8图像格式:常用于显示系统,如电视和计算机屏幕。 RGB值以8 bits表示每种颜色,总共可以表示256×256×256=16777216种颜色
138 70
|
2月前
|
存储 传感器 编解码
ROS机器视觉入门:从基础到人脸识别与目标检测
【11月更文挑战第9天】从本文开始,我们将开始学习ROS机器视觉处理,刚开始先学习一部分外围的知识,为后续的人脸识别、目标跟踪和YOLOV5目标检测做准备工作。
145 56
|
3月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
427 67
|
3月前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
375 12
|
2月前
|
消息中间件 存储 安全
|
3月前
|
传感器 机器人 数据处理
ROS 编程入门的介绍
【10月更文挑战第13天】ROS(Robot Operating System)是一种开源的机器人软件框架,广泛用于机器人开发中。通过使用 ROS,开发者可以轻松创建和管理机器人应用程序。在本节中,我们将介绍如何创建一个 ROS 功能包并实现一些基本功能。
|
3月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
93 1
|
3月前
|
存储 安全 编译器
【C++打怪之路Lv1】-- 入门二级
【C++打怪之路Lv1】-- 入门二级
34 0
|
3月前
|
自然语言处理 编译器 C语言
【C++打怪之路Lv1】-- C++开篇(入门)
【C++打怪之路Lv1】-- C++开篇(入门)
39 0

推荐镜像

更多