ROS 三种通信编程入门:【话题通信】【服务通信】【动作通信】

2023-05-16

目录

  • 一、创建工作空间
  • 二、ROS通信编程
    • 2.1 话题编程
    • 2.2 服务编程
    • 2.3 动作编程
  • 五、总结
  • 六、参考资料

本文内容: 学习古月居 ROS 教学课件和相关视频,练习课件上的话题通信、服务通信编程代码示例。

一、创建工作空间

1.1 什么是工作空间

  • 工作空间(workspace)是一个存放工程开放相关文件的文件夹,它包括:
文件夹含义
src代码空间(Source Space)
build编译空间(Build Space)
devel开发空间(Development Space)
install安装空间(Install Space)
  • 一个工作空间的大致文件层次如下图所示:
    在这里插入图片描述
  • 而我们后面的编程文件主要是放在 package 下面。

1.2 创建工作空间

  • 上面意义讲解完了, 现在开始创建工作空间
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace

在这里插入图片描述

  • 编译工作空间(后续的编译都是以这两句命令编译的)。
cd ~/catkin_ws/
catkin_make

在这里插入图片描述

  • 下面设置环境变量,让其对所有终端都有效。
  • 首先编辑环境文件:
sudo nano ~/.bashrc

在这里插入图片描述

  • 在文件末尾添加一条命令:source /home/zcj/catkin_ws/devel/setup.bash(其中 zcj 是用户名,修改为自己的用户名)。
    在这里插入图片描述
  • 修改完毕后,使用下面的命令立即生效文件。
source ~/.bashrc

在这里插入图片描述

  • 如果想要知道环境变量,可以使用下面的命令检查环境变量。
echo $ROS_PACKAGE_PATH

在这里插入图片描述
1.3 创建功能包

命令格式:catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
同一个工作空间下,不允许存在同名功能包
不同工作空间下,允许存在同名功能包

  • 在 src 下面,创建功能包,并附带依赖包。
cd ~/catkin_ws/src
catkin_create_pkg learning_communication std_msgs rospy roscpp
  • 修改完毕后,编译一下工作空间。
cd ~/catkin_ws
catkin_make

二、ROS通信编程

2.1 话题编程

2.1.1 话题编程流程

步骤过程
第一步创建发布者
第二步创建订阅者
第三步添加编译选项
第四步运行可执行程序

在这里插入图片描述

2.1.2 发布者

  • 首先在 ~/catkin_ws/src/learning_communication/src 下创建一个 talker.cpp 文件
cd ~/catkin_ws/src/learning_communication/src
gedit talker

在这里插入图片描述

  • 复制粘贴以下代码。
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char **argv)
{
	//ROS节点初始化
	ros::init(argc, argv, "talker");
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
	ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
	//设置循环的频率
	ros::Rate loop_rate(10);
	int count = 0;
	while(ros::ok())
	{
		//初始化std_msgs::String类型的消息
		std_msgs::String msg;
		std::stringstream ss;
		ss<<"hello world"<<count;
		msg.data = ss.str();
		//发布消息
		ROS_INFO("%s", msg.data.c_str());
		chatter_pub.publish(msg);
		//循环等待回调函数
		ros::spinOnce();
		//接受循环频率延时
		loop_rate.sleep();
		++count;
	}
	return 0;
}

2.1.3 订阅者:

  • 实现步骤:
    1. 初始化 ROS 节点
    2. 订阅需要的话题
    3. 循环等待话题消息,接收到消息后进入回调函数
    4. 在回调函数中完成消息处理
  • 首先在同目录下创建一个 listener.cpp 文件。
    在这里插入图片描述
  • 复制粘贴以下代码。
#include "ros/ros.h"
#include "std_msgs/String.h"
//接收到订阅的消息,会进入消息的回调函数
void chatterCallback(const std_mmsgs::String::ConstPtr& msg)
{
	//将接收到的消息打印处理
	ROS_INFO("I heard: [%s]",msg->data.c_str());
}
int main(int argc, char **argv)
{
	//初始化ROS节点
	ros::init(argc, argv, "listener");
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
	ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
	//循环等待回调函数
	ros::spin();
	return 0;
}

2.1.4 编译代码

  • 首先要配置编译文件 CMakeLists.txt。
  • 进入到 ~/catkin_ws/src/learning_commuication 下,会有一个 CMakeLists.txt 文件,编辑此文件。
cd ..
ll
gedit CMakeLists.txt

在这里插入图片描述

  • 复制粘贴以下代码。
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})

在这里插入图片描述

  • 然后返回到工作空间,开始编译工作空间。
cd ~/catkin_ws
catkin_make

在这里插入图片描述
在这里插入图片描述

  • 如果编译时出现了大量未定义的引用错误,那么就是刚刚在 CMakeLists.txt 内配置时打错了字母,我就遇到了。。。折腾了好久。

2.1.5 运行可执行文件

  • 编译完成后,重新打开两个终端:一个运行发布者;另一个运行订阅者。
  • 然后现在有三个终端了,首先第一个终端运行 roscore 命令,然后下一个终端运行 talker 命令实现发布者端口,最后一个终端运行 listener 命令实现订阅者端口。
roscore
rosrun learning_communication talker
rosrun learning_communication listener

在这里插入图片描述
2.1.6 自定义话题消息

  • 首先创建一个 msg 文件夹。
mkdir ~/catkin_ws/src/learning_communication/msg
cd ~/catkin_ws/src/learning_communication/msg
sudo nano Person.msg

在这里插入图片描述

  • 复制粘贴如下代码:
string name
uint8 sex
uint8 age

uint8 unknown=0
uint8 male=1
uint8 female=2
  • 返回到上级目录,编辑 package.xml 文件。
cd ..
gedit package.xml

在这里插入图片描述

  • 在其中添加以下功能包依赖。
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

在这里插入图片描述

说明:部分 ROS 版本中 exec_depend 需要修改为 run_depend

  • 然后使用命令 gedit CMakeLists.txt 编辑编译文件。
    在这里插入图片描述
  • 添加如下内容(打字眼神不好的可以复制粘贴):
  • message_generation
    在这里插入图片描述
  • 注意别看错了位置。
    在这里插入图片描述
  • CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
    在这里插入图片描述
  • 开始编译。
cd ~/catkin_ws
catkin_make

在这里插入图片描述

  • 查看自定义消息:
rosmsg show Person

在这里插入图片描述

2.2 服务编程

2.2.1 服务编程流程

步骤过程
第一步创建服务器
第二步创建客户端
第三步添加编译选项
第四步运行可执行程序

在这里插入图片描述
2.2.2 自定义服务请求与应答

  • 首先要创建一个 srv 文件。
mkdir ~/catkin_ws/src/learning_communication/srv
cd ~/catkin_ws/src/learning_communication/srv
sudo nano AddTwoInts.srv

在这里插入图片描述

  • 复制粘贴以下代码:
int64 a
int64 b
---
int64 sum
  • 在 package.xml 中添加功能包依赖。

说明:在第二部分添加过了就可以不用再添加了。

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
  • 使用命令 gedit CMakeLists.txt 编辑 CMakeLists.txt 文件。
    在这里插入图片描述
  • 在文件中添加编译选项:
    在这里插入图片描述
    在这里插入图片描述
  • 上面两个修改的部分,在话题编程中已经添加过了。
  • 新修改的地方如下,添加一个服务文件:
    在这里插入图片描述

2.2.3 实现一个服务器与客户端

  • .../learning_communication/src 下创建 server.cpp 和 client.cpp 文件并复制粘贴相应的代码。
    在这里插入图片描述
  • server.cpp
#include<ros/ros.h>
#include"learning_communication/AddTwoInts.h"
//service回调函数,输入参数req,输出参数res
bool add(learning_communication::AddTwoInts::Request &req,learning_communication::AddTwoInts::Response &res)
{
	//将输入的参数中的请求数据相加,结果放到应答变量中
	res.sum=req.a+req.b;
	ROS_INFO("request: x=%1d,y=%1d",(long int)req.a,(long int)req.b);
	ROS_INFO("sending back response:[%1d]",(long int)res.sum);
	return true;
}
int main(int argc,char **argv)
{
	//ROS节点初始化
	ros::init(argc,argv,"add_two_ints_server");
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个名为add_two_ints的server,注册回调函数add()
	ros::ServiceServer service=n.advertiseService("add_two_ints",add);
	//循环等待回调函数
	ROS_INFO("Ready to add two ints.");
	ros::spin();
	return 0;
}
  • client.cpp
#include<cstdlib>
#include<ros/ros.h>
#include"learning_communication/AddTwoInts.h"
int main(int argc,char **argv)
{
	//ROS节点初始化
	ros::init(argc,argv,"add_two_ints_client");
	//从终端命令行获取两个加数
	if(argc!=3)
	{
		ROS_INFO("usage:add_two_ints_client X Y");
		return 1;
	}
	//创建节点句柄
	ros::NodeHandle n;
	//创建一个client,请求add_two_ints_service
	//service消息类型是learning_communication::AddTwoInts
	ros::ServiceClient client=n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");
	//创建learning_communication::AddTwoInts类型的service消息
	learning_communication::AddTwoInts srv;
	srv.request.a=atoll(argv[1]);
	srv.request.b=atoll(argv[2]);
	//发布service请求,等待加法运算的应答请求
	if(client.call(srv))
	{
		ROS_INFO("sum: %1d",(long int)srv.response.sum);
	}
	else
	{
		ROS_INFO("Failed to call service add_two_ints");
		return 1;
	}
	return 0;
}

2.2.4 编译代码

  • 首先返回上一目录,并编辑 CMakeLists.txt 文件。
    在这里插入图片描述
  • 设置编译文件、链接库和依赖。
add_executable(server src/server.cpp)
target_link_libraries(server ${catkin_LIBRARIES})
add_dependencies(server ${PROJECT_NAME}_gencpp)

add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client ${PROJECT_NAME}_gencpp)

在这里插入图片描述

  • 然后返回到工作空间,开始编译。
cd ~/catkin_ws
catkin_make

在这里插入图片描述
在这里插入图片描述

  • 有一些警告信息,可以忽视。
  • 如果编译错误,那就是眼神不好打错字母了,重新对照一样找出错误就行了。

2.2.5 运行可执行文件

  • 还是跟第二部分的话题编程一样执行方式:用三个终端分别运行一条命令。
roscore
rosrun learning_communication server
rosrun learning_communication client 整数1 整数2

在这里插入图片描述

2.3 动作编程

2.3.1 动作编程简介

  • 什么是动作?
    1. 一种问答通信机制;
    2. 带有连续反馈;
    3. 可以在任务过程中止运行;
    4. 基于 ROS 的消息机制实现。

在这里插入图片描述
在这里插入图片描述

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

2.3.2 自定义动作消息

  • 创建一个 action 文件。
mkdir ~/catkin_ws/src/learning_communication/action
cd ~/catkin_ws/src/learning_communication/action
sudo nano DoDishes.action

在这里插入图片描述

  • 复制粘贴以下内容:
#定义目标信息
uint32 dishwasher_id
---
#定义结果信息
uint32 total_dishes_cleaned
---
#定义周期反馈的消息
float32 percent_complete
  • 返回上一级,并打开编辑 package.xml 文件。
cd ..
gedit 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 编译文件。
    在这里插入图片描述
  • 修改位置如下:
    在这里插入图片描述
  • DIRECTORY action FILES DoDishes.action
  • DEPENDENCIES actionlib_msgs
    在这里插入图片描述

2.3.3 实现动作服务器与客户端

  • 进入到 src 文件夹下,创建 DoDishes_server.cpp 与 DoDishes_client.cpp 文件,并在里面粘贴如下代码:
    在这里插入图片描述
  • DoDishes_server.cpp
#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "learning_communication/DoDishesAction.h"
typedef actionlib::SimpleActionServer<learning_communication::DoDishesAction> Server;
// 收到action的goal后调用该回调函数
void execute(const learning_communication::DoDishesGoalConstPtr &goal, Server *as)
{
	ros::Rate r(1);
	learning_communication::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 hNode;
	// 定义一个服务器
	Server server(hNode, "do_dishes", boost::bind(&execute, _1, &server), false);
	// 服务器开始运行
	server.start();
	ros::spin();
	return 0;
}
  • DoDishes_client.cpp
#include "ros/ros.h"
#include "actionlib/client/simple_action_client.h"
#include "learning_communication/DoDishesAction.h"
typedef actionlib::SimpleActionClient<learning_communication::DoDishesAction> Client;
// 当action完成后会调用该回调函数一次
void doneCallback(const actionlib::SimpleClientGoalState &state
	, const learning_communication::DoDishesResultConstPtr &result)
{
	ROS_INFO("Yay! The dishes are now clean");
	ros::shutdown();
}
// 当action激活后会调用该回调函数一次
void activeCallback()
{
	ROS_INFO("Goal just went active");
}
// 收到feedback后调用该回调函数
void feedbackCallback(const learning_communication::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
	learning_communication::DoDishesGoal goal;
	goal.dishwasher_id = 1;
	// 发送action的goal给服务端,并且设置回调函数
	client.sendGoal(goal, &doneCallback, &activeCallback, &feedbackCallback);
	ros::spin();
	return 0;
}

2.3.4 编译代码

  • 返回上一级,并编辑 CMakeLists.txt 文件。
    在这里插入图片描述
  • 添加以下代码:
add_executable(DoDishes_server src/DoDishes_server.cpp)
target_link_libraries(DoDishes_server ${catkin_LIBRARIES})
add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})

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

在这里插入图片描述

  • 返回到工作空间,开始编译:
cd ~/catkin_ws
catkin_make

在这里插入图片描述

  • 警告信息忽略:
    在这里插入图片描述
  • 如果编译错误,那就是眼神不好打错字母了,重新对照一样找出错误就行了。

2.3.5 运行可执行文件

  • 同样的,三个终端分别运行三句命令。
roscore
rosrun learning_communication DoDishes_client
rosrun learning_communication DoDishes_server

在这里插入图片描述

五、总结

  • 在配置编译文件的时候很麻烦,且如果眼神不太好打错字了,到后面就很容易编译出错,我碰到好几次了,反复查找,就那么一个字母,折腾死人。
  • 其中代码部分我没有太深究,这里只是做演示,有兴趣的话可以研究下这些代码,就差不多在 ROS 通信编程上有了个入门了。

六、参考资料

[1] ROS基础——话题、服务、动作编程
[2] 第2讲:ROS基础.pdf——提取码:ifcf

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS 三种通信编程入门:【话题通信】【服务通信】【动作通信】 的相关文章

随机推荐

  • .Net6.0系列-6 .Net 6LinQ(二)常用扩展方法

    一 本节学习LinQ的扩展方法 LinQ的where返回的IEnumerable 所有的括号中都可以写lamada表达式 list 数组等都可以用LinQ 以下这些方法都是可以和Where一起使用的 Count 返回的是满足条件的个数 An
  • postman简单上手教程

    1 xff1a postman浏览器已经停止更新了 xff0c 所以下面介绍的是app版本 2 xff1a 打开postman xff0c 创建自己的测试目录 xff0c 点加号创建 xff0c 这里我创建了test project 3 x
  • 实战microPython(06)-OLED屏的使用(2)

    实战microPython 06 OLED屏的使用 2 David Zou 2018 11 27 大家好 xff0c 上次介绍了OLED显示屏的相关知识 xff0c 今天 xff0c 我们进入实战 xff0c 学习如何使用OLED显示屏 如
  • C++实现HTTP上传

    插件中需要一个上传文件的功能 xff0c 我跟老大说 xff0c 我想FTP上传 xff0c 老大一瞪眼 xff0c 那还得再布个FTP服务器 xff0c 直接用HTTP上传多简单 那么C 43 43 如何将文件上传HTTP服务器上呢 xf
  • RTK和GPS定位

    首先 xff0c 简要说一下GPS和RTK的工作原理 GPS定位的基本原理是 xff0c 测量出已知位置的卫星到地面GPS接收器之间的距离 xff0c 然后接收器通过与至少4颗卫星通讯 xff0c 计算与这些卫星间的距离 xff0c 就能确
  • 基于VC6的UAV地面站(GCS)程序及源代码

    此地面站 xff08 GCS603 xff09 是早年针对北航一款小飞控开发的 xff0c 那个时候APM好像都才刚刚问世 程序具备了简单地面站的基本功能 xff0c 如界面绘制 串口数据读写 数据记录 数据帧的合成与解析 航线设置等 此程
  • ArduPlane plane 部分功能与代码移植到 GCC(Atmel studio 6.2)版本的程序源代码 HelloPilot

    几年前由于当时 ArduPlane xff08 Ver2 76 xff09 的开发环境为arduino ide 开发尤其是调试环境非常不友好 xff0c 要进行程序调试及跟踪非常不方便 xff0c 同时出于学习掌握arduplane代码原理
  • 简单的说说飞控硬件研发过程中的各种坑

    我们的飞控 xff0c 从当初第一个概念设计到现在 xff0c 历时好几年 xff0c 目前经过上百架次的试飞 xff0c 功能已经基本完备 回首前面走过的历程 xff0c 不说尸横遍野吧 xff0c 至少也是血泪斑斑 有无数的坑需要投入大
  • 1、无人系统控制站软件开发平台 CSS(Control Station Studio)概述

    1 初衷 在CSS之前 xff0c 通过参与开发数个大中型无人机地面控制站项目 xff0c 在GCS xff08 Ground Control Station xff09 设计与实现方面积累了一些经验和感悟 在先前的开发过程中 xff0c
  • .Net6.0系列-7 .Net 6LinQ(三)常用扩展方法

    一 投影 把集合中的每一项转换为另一种类型使用的是Select 方法 where 的返回集合是Enumerable 返回的是T的全部字段 而Select是可以返回集合的任意需要的字段 find 是在lamada表达式中的使用 以上两个是Li
  • 一款适于作为飞行试验平台的小四轴设计

    四轴虽小 xff0c 但也是第7版改进设计了 xff0c 定型了 xff01 优点 1 安全性高 作为实验平台 xff0c 最大的风险来自于失控 小四轴 xff08 是的 xff0c 它现在还没名字 xff09 可靠的旋翼保护圈以及其他保护
  • 上手Nucleo H743ZI 开发板下载失败问题解决方法

    准备研究Stm32H7 xff0c 买了块Nucleo H743ZI开发板回来研究 之前一直使用的是stm32F4 xff0c 开发环境为keil 5 13 43 STM32F4xx DFP 2 10 0 st linkV2 开工之前仔细读
  • 固定翼武德充沛,多旋翼费拉不堪

    实际飞行测试 同样的动力组合 xff1a 2205电机 43 5030 3叶桨 同样的动力电池 xff1a 2200ma xff0c 3s xff0c 20c 基本一致的起飞全重 xff1a 固定翼680g xff0c 多轴700g 续航时
  • PH7系统简介

    PH7系统简介 PH7是什么 xff1f 狭义的PH7是一套以无人机飞控为典型应用案例 xff0c 涵盖无人车或船 GCS数据采集 伺服控制 AHRS 地面模拟仿真系统等的通用控制器代码框架 xff0c 该框架以Stm32CubeMx生成代
  • 小型无人机的布线与布局设计

    小型无人机的布线与布局设计 xff0c 似乎看上去像是在总体设计当中一个细枝末节 xff0c 是往往会被忽略掉的部分 但实际上 xff0c 布线与布局虽然不像飞控算法设计 飞行平台气动设计是总体设计当中最核心和最重要的部分 xff0c 但却
  • Bread Board Pilot 即将发布

    Bread Board Pilot xff08 简称BBP xff09 为基于 PH7 代码框架 xff08 PH7 系统简介 xff09 的一款飞控快速原型开发板 相比传统飞控板 xff0c BBP 的硬件设计具有以下突出特点 xff1a
  • Mavlink 协议硬解析主要代码

    int MAVLinkProtocol ParseMsg BYTE arMsgBuf MSGVALUE pMavMsg CString amp strMsgText Function Parameters arMsgBuf 为完整的 mav
  • 网络调试助手(NetAssist)不能正常创建TCP Serve连接问题

    一 问题由来 第一次使用网络调试助手 xff08 NetAssist xff09 建立服务端 xff08 TCP Server xff09 连接时碰到链接失败的问题 xff0c 如图所示 xff0c 其原因在于本地主机端口8080被其他进程
  • postman调用J-WSSE认证方式接口

    J WSSE认证方式的内容包括 xff1a 用户名 密码 nonce 时间戳 nonce是一个随机字符串 xff1b 时间戳 Created 为W3DTF格式 xff1b 密码创建方式为 xff1a PasswordDigest 61 Ba
  • ROS 三种通信编程入门:【话题通信】【服务通信】【动作通信】

    目录 一 创建工作空间二 ROS通信编程2 1 话题编程2 2 服务编程2 3 动作编程 五 总结六 参考资料 本文内容 xff1a 学习古月居 ROS 教学课件和相关视频 xff0c 练习课件上的话题通信 服务通信编程代码示例 一 创建工