ROS通信机制

news2024/11/28 2:31:16

参考:
bilibili@Autolabor官方

回调函数:!

由外部中断激发而执行的函数,函数执行的时间不由函数本身控制,而是由外部激发

1、话题通信

​ publisher发布者,和subscriber订阅者通过topic相互连接,在同一个话题进行数据交换

publish一个0/1的信号,表示急停信号,推送到mobile_base/sensors/switch

1.1 使用场景

​ 不断更新,逻辑处理少

1.2 作用

​ 发布方以固定频率发送文本,订阅方接收文本并输出

1.3 话题通信的角色及其功能

​ master:管理者

​ 可以根据话题建立发布者和订阅者之间的连接

​ listener:订阅者

​ talker:发布者

1.4 话题通信的流程,涉及RPC与TCP协议

​ 1、talker在master注册一个话题advertise("话题名",RPC地址)

​ 2、listener在master申请订阅话题subscribe("话题名")

​ 3、若话题名匹配成功,master向listener提供话题的RPC地址

​ 4、listener通过RPC地址远程访问talker

​ 5、talker给listener发送响应,包含talker的TCP地址

​ 6、listener根据TCP地址访问talker

​ 7、talker给listener发送数据

​ 注:注册和订阅话题没有先后顺序

1.5 发布方实现 视频040

/*
	1.包含头文件
	2.初始化ROS节点
	3.创建节点句柄
	4.创建发布者对象
	5.编写发布逻辑并发布数据
*/
#include <sstream>  //实现字符串拼接
#include "ros.h"
#include "stc_msgs/String.h"

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,""); //避免中文乱码
    
    ros::init(argc,argv,"pub"); //初始化节点
    
    ros::NodeHandle nh; //创建Node句柄
    
    ros::Publisher pub = nh.advertise<std_msgs::String>("em_state",10); //创建发布者对象
    
    std_msgs::String msg; //创建发布消息
    
    
    
    ros::Rate rate(10); // 创建发布速率为10Hz
    
    int cnt=0;
    
    //ros::ok()若节点存活
    while(ros::ok()) //创建发布逻辑,循环发布数据
    {
        cnt++;
    	//msg.data = "hello" ;
        std::stringstream ss;
        ss << "hello --->" << count;
        msg.data = ss.str(); //将stringstream中的数据转换成字符串
        
     	pub.publish(msg);
        
     	rate.sleep();//和ros::Rate rate(10) 配合实现每秒10次
    }
    
    return 0;
}

1.6 订阅方实现 视频42

/*
	1.包含头文件
	2.初始化ROS节点
	3.创建节点句柄
	4.创建订阅者对象
	5.处理订阅到的数据
	6.声明spin函数
*/
#include <sstream>  //实现字符串拼接
#include "ros.h"
#include "stc_msgs/String.h"

void doMsg(const std_msgs::String::ConstPtr &mas)
{
	//通过msg获取并操作订阅到的数据
	ROS_INFO("订阅的数据是:%s",msg->data.c_str()); //以日志形式输出订阅到的数据
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,""); //避免中文乱码
    
    ros::init(argc,argv,"sub"); //初始化节点
    
    ros::NodeHandle nh; //创建Node句柄
    
    //ros::Subscriber sub = nh.subscribe("话题名",队列长度,回调函数名)
    ros::Subscriber sub = nh.subscribe("em_state",10,doMsg); //创建订阅者对象
    
    ros::spin(); //字面意思:回头,再次调用回调函数doMsg   
    return 0;
}

2 自定义msg的实现

​ 原因:msgs只是简单的文本文件,无法对数据进行复合

​ 特殊类型:Header包含时间戳以及ROS中常用的坐标帧信息

1.6.1 编写msg文件

//在src/package下新建msg文件夹,放入msg文件
//Person.msg
string name
int32 age
float32 height

1.6.2 编写配置文件

<!--在package.xml文件中进行配置-->
<!--添加依赖-->
<build_depend>smessage_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
# cmake 修改

find_package(
 #添加
 message_generation
)

#添加
add_message_files(
	FILES
	Person.msg
	#文件名2
)

#添加
generate_messages(
    DEPENDENCIES
    std_msgs
)

#添加
catkin_package(
	CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
)

add_dependencies(包名 ${PROJECT_NAME}_generate_message_cpp)

1.6.3 发布方 视频 注意预先设置vscode

/*
	发布person.msg格式的消息
	1.包含头文件
	2.初始化ROS节点
	3.创建节点句柄
	4.创建发布者对象
	5.编写发布逻辑并发布数据
*/
#include "包名/Person.h" //导入包
#include "ros.h"
#include "stc_msgs/String.h"

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,""); //避免中文乱码
    
    ros::init(argc,argv,"pub"); //初始化节点
    
    ros::NodeHandle nh; //创建Node句柄
    
    ros::Publisher pub = nh.advertise<包名::Person>("em_state",10); //创建发布者对象
    
    包名::Person msg; //创建发布消息
    msg.name = "张三";
    msg.age = 1;
    msg.height = 1.65;
    
    ros::Rate rate(1); // 创建发布速率为10Hz
        
    while(ros::ok()) //创建发布逻辑,循环发布数据
    {
        
        msg.age+=1; // 修改数据
        
     	pub.publish(msg);
        
     	rate.sleep();//和ros::Rate rate(10) 配合实现每秒10次
    	
        ros::spinOnce(); //官方建议,目前不用
    }
    
    return 0;
}
1.6.6 订阅方
/*
	发布person.msg格式的消息
	1.包含头文件
	2.初始化ROS节点
	3.创建节点句柄
	4.创建订阅者对象
	5.处理订阅到的数据
	6.调用spin()函数
*/
#include "包名/Person.h" //导入包
#include "ros.h"
#include "stc_msgs/String.h"

void doMsg(const 包名::Person::ConstPtr &person)
{
	//通过msg获取并操作订阅到的数据
	ROS_INFO("订阅的数据是:%s,%d,%.2f",person->name.c_str(),person->age,person->height); //以日志形式输出订阅到的数据
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,""); //避免中文乱码
    
    ros::init(argc,argv,"sub"); //初始化节点
    
    ros::NodeHandle nh; //创建Node句柄
    
    ros::Subscriber sub = nh.Subscribe("em_state",10,doMsg); //创建发布者对象
    
    ros::spin();
    
    return 0;
}

2、服务通信 srv文件

​ server和client进行请求和相应

适用性:对实时性有要求,需要一定的逻辑处理

2.1理论模型

​ 角色:

​ Master

​ Server

​ Client

​ 流程:

​ master根据话题实现server和client的连接

​ 1、server向master注册信息,话题与地址

​ 2、client向master注册话题

​ 3、master向client返回ROSRPC格式的地址

​ 4、建立TCP连接,实现Clinet和Server的通信

​ 注:必须是服务端(server)先启动和注册,之后client发送请求才有效

// 创建srv文件夹
//编写请求与响应内容

int32 num1
int32 num2
//请求跟响应隔3个-
---
int32 sum
<!---修改package.xml--->
<!---添加依赖--->

<bulid_depend>message_generation</bulid_depend>
<exec_depend>message_runtime</exec_depend>
## 修改cmakelist.txt
find_package(catkin REQUIRED COMPONENTS
	roscpp
	rospy
	std_msgs
	message_generation
)
## 添加
add_service_files(
	FILES
	文件名.srv
)

## 添加
generate_messages(
	DEPENDENCIES
	std_msgs
)
## 添加
catkin_package(
	CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
)

编译完成后生成 请求名.h、响应名.h 头文件

c++实现 ?(查看topic是否存在,检验是话题名还是服务名)

  1. 配置文件

    devel/include路径查看

    添加到 c_cpp_properties.json中的includePath中

  2. server.cpp 服务端:解析处理客户端的数据并给出响应

    //1. 头文件
    #include "ros/ros.h"
    #include "包名/srv文件夹下的名称.h"
    
    bool doSums(包名::功能名::Request &request,
               包名::功能名::Response &response){
        //处理请求:解析数字
        int num1 = request.num1;
        int num2 = request.num2;
        //查看解析结果
        ROS_INFO("num1=%d, num2=%d",num1,num2);
        
        //组织响应:求和输出
        int sum = num1+num2;
        response.sum = sum;
        
        return true;
    }
    int main(int argc, char *argv[])
    {
        //节点初始化
        ros::init(argc,argv,"节点名");
        //创建节点句柄
        ros::NodeHandler nh;
        //创建服务对象
        ros::serviceServer 服务端名 = nh.advertiseService("话题名",回调函数(doSums));
        
        //spin
        ros::spin()
    }
    

    添加配置文件 CmakeList.txt

    add_executable(名称 src/被执行的文件.cpp)
    ## 防止编译顺序引发的异常
    add_dependencies(名称 ${PROJECT_NAME}_gencpp)
    target_link_libraries(名称
    	${catkin_LIBRARIES}
    )
    
  3. client.cpp 客户端

    //1. 头文件
    #include "ros/ros.h"
    #include "包名/srv文件夹下的名称.h"
    
    // main传递的是,参数数量和参数值
    int main(int argc, char *argv[])
    {
        //节点初始化
        ros::init(argc,argv,"节点名");
        //创建节点句柄
        ros::NodeHandler nh;
        //创建客户端对象
        ros::ServiceClient 客户端名 = nh.serverce<客户端名称::服务名>("话题名");
        
        //组织请求(固定请求)
        客户端名::服务名 ai;
        ai.request.num1 = 100;
        ai.request.num2 = 200;
        
        //组织请求(自定义传值)
        if(argc !=3){
            ROS_INFO("args num error");
        }else{
    		ai.request.num1 = atoi(argv[1]);
            ai.request.num2 = atoi(argv[2]);
        }
        
        //处理响应
        bool flag = client.call(servise对象(ai));
        if(flag)
        {
            ROS_INFO("Response TRUE");
            ROS_INFO("SUM=%d",ai.response.sum);
        }else{
    
        	ROS_INFO("G");
        }
        //spin
        ros::spin()
    }
    

    添加配置文件 CmakeList.txt

    add_executable(名称 src/被执行的文件.cpp)
    
    ## 防止编译顺序引发的异常
    add_dependencies(名称 ${PROJECT_NAME}_gencpp)
    
    target_link_libraries(名称
    	${catkin_LIBRARIES}
    )
    
    
    

    客户端优化

    先启动客户端时,若服务端未开启,则抛出异常,

    设定:在客户端发请求时,若服务端未开启,则挂起等待服务端启动,而不是直接退出抛异常

    在调用call之前加入下面命令之一

    1、client.waitForExistence()

    2、ros::service::waitForService("服务名")

3、参数服务器通信

​ 开辟空间存放data,各个节点都可以从data中存取数据,共享模式。

image-20230308100531766

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402423.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式5——自定义Spring框架

1、Spring核心功能结构 Spring大约有20个模块&#xff0c;由1300多个不同的文件构成。这些模块可以分为&#xff1a;核心容器、AOP和设备支持、数据访问与集成、Web组件、通信报文和集成测试等。下面是Spring框架的整体架构图&#xff1a; 核心容器由beans、core、context 和 …

Vue脚手架的安装(保姆级教程)

Vue脚手架的安装&#xff08;保姆级教程&#xff09; 文章目录Vue脚手架的安装&#xff08;保姆级教程&#xff09;1.下载vscode2.node下载5.Vue脚手架的安装6.创建Vue项目7.项目的运行1.下载vscode vscode下载地址 2.node下载 node下载 1.打开cmd node -vnpm -v2.在node的…

linux入门---vim的配置

这里写目录标题预备知识如何配置vimvim一键配置预备知识 在配置vim之前大家首先得知道一件事就是vim的配置是一人一份的&#xff0c;每个用户配置的vim都是自己的vim&#xff0c;不会影响到其他人&#xff0c;比如说用户xbb配置的vim是不会影响到用户wj的&#xff0c;虽然不同…

开源写作平台WriteFreely(折腾篇)

设置向导 除了直接修改 config.ini 之外&#xff0c;你还可以进入容器用命令行进行设置 在 SSH 客户端执行下面的命令 # 生成 config.ini docker exec -it writefreely ./writefreely --config也可以通过群晖的 终端机 一步一步跟着填入就可以了&#xff0c;但是需要说明的是…

Zhong__Celery基本使用详解

时间&#xff1a;2023.03.10环境&#xff1a;python3/centos/redis目的&#xff1a;演示celery基本使用的详细案例说明&#xff1a;python依赖的版本以requirement.txt文件为测试基准 不同版本可能存在差异作者&#xff1a;Zhong简介简介及概念介绍部分不会很详细 主要看demo项…

【HTTP协议与Web服务器】

HTTP协议与Web服务器浏览器与服务器通信过程HTTP的请求报头HTTP请求报头结构HTTP的请求方法HTTP应答报头HTTP应答报头结构应答状态web服务器的c语言实现浏览器与服务器通信过程 浏览器与Web服务器再应用层通信使用的是HTTP协议&#xff0c;而HTTP协议在传输层使用的是TCP协议。…

深度学习必备知识——模型数据集Yolo与Voc格式文件相互转化

在深度学习中&#xff0c;第一步要做的往往就是处理数据集,尤其是学习百度飞桨PaddlePaddle的小伙伴&#xff0c;数据集经常要用Voc格式的&#xff0c;比如性能突出的ppyolo等模型。所以学会数据集转化的本领是十分必要的。这篇博客就带你一起进行Yolo与Voc格式的相互转化&…

数据库系统概论

文章目录前言基础篇&#xff1a;1-5章第 1 章 绪论1.1 数据库系统概述1.2 数据模型1.3 数据库系统的结构1.4 数据库系统的组成1.5 小结第 2 章 关系数据库1.关系模型1.1 关系数据结构1.2 关系完整性约束实体完整性、参照完整性、用户定义完整性2.关系代数8种关系代数运算符并 ∪…

「媒体邀约」如何选择适合的媒体公关,媒体服务供应商

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 每天胡老师也会接到大量关于媒体方面的询问&#xff0c;胡老师也都一一的很耐心的进行了解答&#xff0c;也都很详细的做了媒体规划和媒体传播方案&#xff0c;但有的朋友还是很犹豫&…

关于 @Aspect 注解的使用

一、Spring AOPAOP(Aspect Oriented Programming) 是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面&#xff0c;即解剖对象的内部&#xff0c;将那些影响了多个类的公共行为抽取到一个可重用模块里&#xff0c;减少系统的重复代码&#xff0c;降低模块间的耦合度…

Hive小结

Hive的定义hive是一个建立在Hadoop上的开源数据仓库软件&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;基于表提供了一种类似SQL的查询模型&#xff0c;称为hive查询语言&#xff08;HQL&#xff09;&#xff0c;用于访问和分析存储在Hadoop文件中的大型数…

Uipath Excel 自动化系列12-InsertDeleteSheet(新增删除Sheet)

活动描述 Insert Sheet 新增Sheet:在 Excel 文件中插入工作表,该活动需与Use Excel File 活动选择的 Excel 文件一起使用。 Delete Sheet 删除Sheet:从 Excel 文件中删除指定工作表,该活动需与Use Excel File 活动选择的 Excel 文件一起使用。 使用如下图&#xff1a; Inser…

【React教程】一、React简介

一、React简介 React是一个用于构建用户界面的JavaScript库&#xff0c;它是Facebook的内部项目&#xff0c;用来架设Instagram的网站,并于2013年5月开源。React主要用于构建Ul&#xff0c;很多人认为React 是 MVC 中的 V&#xff08;视图&#xff09;。由于拥有较高的性能&…

计算机组成原理——计算机系统概述

文章目录计算机系统的组成计算机硬件冯诺依曼结构计算机的功能部件计算机软件系统软件和应用软件三个级别的语言计算机的性能指标字长数据通路宽度主存容量运算速度计算机系统的组成 计算机系统由硬件系统和软件系统组成&#xff1a; 硬件是指有形的物理设备&#xff0c;是计…

【CICD】如何编写 .gitlab-ci.yml 文件

⏳ CICD 指的是持续集成/持续交付&#xff08;continuous integration/ continuous delivery&#xff09;&#xff0c;是为了满足互联网、金融公司快速迭代项目的需要而提出的一种软件开发思想。大致思路是通过编写自动化脚本&#xff0c;使新代码必须通过一些规则核查后才能部…

自定义控件(?/N) - 事件分发

一、外部传递到ViewGroup中Activity会通过 getWindow( ) 获取PhoneWindow对象并调用它的superDispatchTouchEvent( )&#xff0c;该方法会调用它&#xff08;PhoneWindow&#xff09;的内部类 DecorView 的 superDispatchTouchEvent( )&#xff0c;而它&#xff08;DecorView&a…

【Docker】P1 初识 Docker 以及 Ubuntu 安装 Docker

初识 Docker 以及 Ubuntu 安装 Docker初识 Docker故事引入DockerUbuntu 安装 Docker读完本文&#xff0c;你应当会理解这两句话&#xff1a; Docker 可以大大简化运维部署相关操作&#xff0c;可以规避一些 bug&#xff1b; Docker 是一种容器技术&#xff0c;解决软件跨环境迁…

使用Houdini输出四面体网格并输出tetgen格式

我们的目标是从houdini输出生成的四面体&#xff0c;希望是tetgen格式的。 众所周知&#xff0c;houdini是不能直接输出四面体的。 有三方案去解决&#xff1a; 输出点云ply文件&#xff0c;然后利用tetgen生成网格。输出Hounidi内置的.geo格式文件&#xff0c;然后写个脚本…

[Java Web]Request对象 | 超1w字带你熟悉Servlet中的request请求

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;输出优质文章 ⭐所属专栏&#xff1a;Java Web ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601; 目录 Reque…

Codeforces Round 857 (Div. 2)【A-C】

文章目录A. Likes【贪心、模拟】B. Settlement of Guinea Pigs【贪心】C. The Very Beautiful Blanket【构造、观察】链接传送门A. Likes【贪心、模拟】 分析 为了使得当前时间点赞的尽可能大&#xff0c;那么前面的赞的数目也要尽可能大&#xff0c;所以前面把能赞的都要先赞…