【ROS2】MOMO的鱼香ROS2(四)ROS2入门篇——ROS2节点通信之话题与服务
ROS2节点通信之话题与服务点
- 引言
- 1 理解从通信开始
- 1.1 TCP(传输控制协议)
- 1.2 UDP(用户数据报协议)
- 1.3 基于共享内存的IPC方式
- 2 ROS2话题
- 2.1 ROS2话题指令
- 2.2 话题之RCLPY实现
- 2.2.1 编写发布者
- 2.2 2 编写订阅者
- 2.2.3 运行测试
- 3 ROS2服务
- 3.1 ROS2服务指令
- 3.2 服务之RCLPY实现
- 3.2.1 编写客户端
- 3.2 2 编写服务端
- 3.2.3 运行测试
引言
笔者跟着鱼香ROS的ROS2学习之旅
学习参考:
【ROS2机器人入门到实战】
笔者的学习目录
- MOMO的鱼香ROS2(一)ROS2入门篇——从Ubuntu操作系统开启
- 【ROS2】MOMO的鱼香ROS2(二)ROS2入门篇——ROS2初体验
- ROS2】MOMO的鱼香ROS2(三)ROS2入门篇——ROS2第一个节点
专业术语认识
- TCP(传输控制协议)
- UDP(用户数据报协议)
1 理解从通信开始
通信的目的是在计算机系统中实现不同组件、进程或设备之间的信息和数据传递。通过通信,各个实体可以共享信息、协调行动并实现协同工作。在计算机领域,通信是构建分布式系统、网络和协议的基础。
通信的原理涉及两个主要方面:通信协议和通信方式。
通信协议定义了数据的格式、传输方式、错误检测和纠正等规则,以确保可靠的数据传输。
通信方式涉及了不同的通信介质和技术,包括网络通信和进程间通信(IPC)。
1.1 TCP(传输控制协议)
使用ping命令进行基于UDP的网络通信:
# 修改为自己的ip地址
ping 192.168.2.42
ping 192.168.2.36
1.2 UDP(用户数据报协议)
使用nc命令进行基于TCP的网络通信:
# 终端1
nc -l 1234
# 终端2
echo "Hello, TCP!" | nc 127.0.0.1 1234
关于TCP的通信可以参考笔者的博客:【Python】基于socket函数的TCP通信
1.3 基于共享内存的IPC方式
基于共享内存的进程间通信(IPC)方式
通过ipcs命令查看当前系统中的共享内存段:
ipcs -m
使用ipcrm命令删除不再需要的共享内存段:
ipcrm -m <shmid>
2 ROS2话题
一个节点发布数据到某个话题上,另外一个节点就可以通过订阅话题拿到数据。
ROS2话题通信其实还可以是1对n,n对1,n对n的。
同一个话题,所有的发布者和接收者必须使用相同消息接口。
2.1 ROS2话题指令
1.查看所有话题
ros2 topic list
# 增加查看消息类型
ros2 topic list -t
2.打印实时话题内容
ros2 topic echo <topic_name>
3.查看主题信息
ros2 topic info <topic_name>
2.2 话题之RCLPY实现
创建功能包
cd ROS_WS/colcon_ws/src
ros2 pkg create imu_py --build-type ament_python --dependencies rclpy
创建节点文件
cd ROS_WS/colcon_ws/src/imu_py
touch imu_publisher.py
touch imu_subscribe.py
2.2.1 编写发布者
imu_publisher.py
# -*- coding: utf-8 -*-
"""
1.查看映射端口
ls /dev/ttyUSB*
2.更改端口的权限
sudo chmod 777 /dev/ttyUSB0
"""
import rclpy
from rclpy.node import Node
# 话题接口
from sensor_msgs.msg import Imu # imu接口
# Usart Library
import serial# imu接收数据类型
class IMUPublisher(Node):def __init__(self,name):super().__init__(name) # 继承父类,初始化名称self.get_logger().info("大家好,我是%s!" % name)self.publisher_node = self.create_publisher(Imu, 'imu_data', 1) # 创建发布imu数据的发布者到话题:imu_data上# 串口初始化self.IMU_Usart = serial.Serial(port='/dev/ttyUSB0', # 串口baudrate=115200, # 波特率timeout=0.001 # 由于后续使用read_all按照一个timeout周期时间读取数据# imu在波特率115200返回数据时间大概是1ms,9600下大概是10ms# 所以读取时间设置0.001s)# 接收数据初始化self.ACC_X: float = 0.0 # X轴加速度self.ACC_Y: float = 0.0 # Y轴加速度self.ACC_Z: float = 0.0 # Z轴加速度self.GYRO_X: float = 0.0 # X轴陀螺仪self.GYRO_Y: float = 0.0 # Y轴陀螺仪self.GYRO_Z: float = 0.0 # Z轴陀螺仪self.roll: float = 0.0 # 横滚角self.pitch: float = 0.0 # 俯仰角self.yaw: float = 0.0 # 航向角self.leve: float = 0.0 # 磁场校准精度self.temp: float = 0.0 # 器件温度self.MAG_X: float = 0.0 # 磁场X轴self.MAG_Y: float = 0.0 # 磁场Y轴self.MAG_Z: float = 0.0 # 磁场Z轴self.Q0: float = 0.0 # 四元数Q0.0self.Q1: float = 0.0 # 四元数Q1self.Q2: float = 0.0 # 四元数Q2self.Q3: float = 0.0 # 四元数Q3# 判断串口是否打开成功if self.IMU_Usart.isOpen():print("open success")else:print("open failed")# 回调函数返回周期time_period = 0.001self.timer = self.create_timer(time_period, self.timer_callback)def timer_callback(self):"""定时器回调函数"""# ----读取IMU的内部数据-----------------------------------try:count = self.IMU_Usart.inWaiting()if count > 0:# 发布sensor_msgs/Imu 数据类型imu_data = Imu()imu_data.header.frame_id = "map"imu_data.header.stamp = self.get_clock().now().to_msg()imu_data.linear_acceleration.x = self.ACC_Ximu_data.linear_acceleration.y = self.ACC_Yimu_data.linear_acceleration.z = self.ACC_Zimu_data.angular_velocity.x = self.GYRO_X * 3.1415926 / 180.0 # unit transfer to rad/simu_data.angular_velocity.y = self.GYRO_Y * 3.1415926 / 180.0imu_data.angular_velocity.z = self.GYRO_Z * 3.1415926 / 180.0imu_data.orientation.x = self.Q0imu_data.orientation.y = self.Q1imu_data.orientation.z = self.Q2imu_data.orientation.w = self.Q3self.publisher_node.publish(imu_data) # 发布imu的数据self.get_logger().info(f'发布了指令:{imu_data.header.frame_id}') #打印一下发布的数据# --------------------------------------------------------# print('读取中')except KeyboardInterrupt:if serial != None:print("close serial port")self.IMU_Usart.close()def main(args=None):"""ros2运行该节点的入口函数编写ROS2节点的一般步骤1. 导入库文件2. 初始化客户端库3. 新建节点对象4. spin循环节点5. 关闭客户端库"""rclpy.init(args=args) # 初始化rclpynode = IMUPublisher("imu_publisher") # 新建一个节点rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)rclpy.shutdown() # 关闭rclpy
2.2 2 编写订阅者
imu_subscribe.py
# -*- coding: utf-8 -*-
import rclpy
from rclpy.node import Node
# 话题接口
from sensor_msgs.msg import Imu # imu接口class IMUSubscribe(Node):def __init__(self,name):super().__init__(name)self.get_logger().info("大家好,我是%s!" % name)self.imu_subscribe_node = self.create_subscription(Imu, 'imu_data',self.imu_callback, 1) # 创建发布imu数据的发布者到话题:imu_data上def imu_callback(self, imu_data):self.get_logger().info(f'收到[{imu_data.header.frame_id}]命令')def main(args=None):rclpy.init(args=args) # 初始化rclpynode = IMUSubscribe("imu_subscribe") # 新建一个节点rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)rclpy.shutdown() # 关闭rclpy
2.2.3 运行测试
修改下setup.py
entry_points={'console_scripts': ["imu_publisher=imu_py.imu_publisher:main", "imu_subscribe=imu_py.imu_subscribe:main",],},
发布节点
colcon build --packages-select imu_py
source install/setup.bash
ros2 run imu_py imu_publisher
订阅节点
source install/setup.bash
ros2 run imu_py imu_subscribe
可视化
rqt
上图中的节点名称取决于下图
3 ROS2服务
服务分为客户端和服务端,服务-客户端模型也可以称为请求-响应模型,不同于话题是没有返回的,适用于单向或大量的数据传递。而服务是双向的,客户端发送请求,服务端响应请求。
注意:
同一个服务(名称相同)有且只能有一个节点来提供
同一个服务可以被多个客户端调用
3.1 ROS2服务指令
启动服务端
ros2 run examples_rclpy_minimal_service service
1.查看所有服务
ros2 service list
2.手动调用服务
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 5,b: 10}"
3.查看服务接口类型
ros2 service type <service_name>
4.查找使用某一接口的服务
ros2 service find example_interfaces/srv/AddTwoInts
3.2 服务之RCLPY实现
创建节点文件
cd ROS_WS/colcon_ws/src/imu_py
touch imu_client.py
touch imu_server.py
3.2.1 编写客户端
imu_client.py
# -*- coding: utf-8 -*-
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoIntsclass ServiceClient(Node):def __init__(self,name):super().__init__(name)self.get_logger().info("节点已启动:%s!" % name)self.client_ = self.create_client(AddTwoInts,"add_two_ints_srv") def result_callback_(self, result_future):response = result_future.result()self.get_logger().info(f"收到返回结果:{response.sum}")def send_request(self, a, b):while rclpy.ok() and self.client_.wait_for_service(1)==False:self.get_logger().info(f"等待服务端上线....")request = AddTwoInts.Request()request.a = arequest.b = bself.client_.call_async(request).add_done_callback(self.result_callback_)def main(args=None):rclpy.init(args=args) # 初始化rclpynode = ServiceClient("service_client") # 新建一个节点# 调用函数发送请求node.send_request(3,4)rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)rclpy.shutdown() # 关闭rclpy
3.2 2 编写服务端
imu_server.py
# -*- coding: utf-8 -*-
import rclpy
from rclpy.node import Node
# 导入接口
from example_interfaces.srv import AddTwoIntsclass ServiceServer(Node):def __init__(self,name):super().__init__(name)self.get_logger().info("节点已启动:%s!" % name)self.add_ints_server_ = self.create_service(AddTwoInts,"add_two_ints_srv", self.handle_add_two_ints) def handle_add_two_ints(self,request, response):self.get_logger().info(f"收到请求,计算{request.a} + {request.b}")response.sum = request.a + request.breturn responsedef main(args=None):rclpy.init(args=args) # 初始化rclpynode = ServiceServer("service_server") # 新建一个节点rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)rclpy.shutdown() # 关闭rclpy
3.2.3 运行测试
修改下setup.py
entry_points={'console_scripts': ["imu_client=imu_py.imu_client:main", "imu_server=imu_py.imu_server:main"],},
发布节点
colcon build --packages-select imu_py
source install/setup.bash
ros2 run imu_py imu_client
订阅节点
source install/setup.bash
ros2 run imu_py imu_server
可视化
rqt
相关文章:

【ROS2】MOMO的鱼香ROS2(四)ROS2入门篇——ROS2节点通信之话题与服务
ROS2节点通信之话题与服务点 引言1 理解从通信开始1.1 TCP(传输控制协议)1.2 UDP(用户数据报协议)1.3 基于共享内存的IPC方式 2 ROS2话题2.1 ROS2话题指令2.2 话题之RCLPY实现2.2.1 编写发布者2.2 2 编写订阅者2.2.3 运行测试 3 R…...
2022年山东省职业院校技能大赛高职组云计算赛项试卷第三场-公有云
2022年山东省职业院校技能大赛高职组云计算赛项试卷 目录 2022年职业院校技能大赛高职组云计算赛项试卷 【赛程名称】云计算赛项第三场-公有云 【任务1】公有云服务搭建[10分] 【适用平台】华为云 【题目1】私有网络管理[0.5分] 【题目2】云实例管理[0.5分] 【题目3】数…...

现代 NLP:详细概述,第 1 部分:transformer
阿比吉特罗伊 一、说明...

记一次Mac端mysql重置密码
在执行mysql命令的时候,报如下的错误,表示不支持mysql命令: zsh: command not found: mysql 1. 先查看mysql服务是否存在 在系统偏好设置中查看: 2. 发现mysql服务已经在运行,可能因为/usr/local/bin目录下缺失mysq…...
【开题报告】基于java的流浪之家动物领养网站的设计与开发
1.选题背景 流浪之家动物领养网站的设计与开发背景主要源于对流浪动物保护和宠物领养问题的关注。随着城市化进程加快,越来越多的流浪动物出现在城市中,它们面临着食物、住所和医疗资源的缺乏。同时,许多爱心人士希望能够给流浪动物一个温暖…...

训狗技术从初级到高级,专业有效的训狗训犬教程
一、教程描述 现在大部分人家里都会养些宠物,比如狗狗,虽然狗狗的一些行为习惯跟遗传有关,但是主人后天的影响也会给狗狗带来改变,本套教程教你纠正狗狗的不良行为,可以让你与狗愉快地玩耍。本套训狗教程,…...

如何让机器人具备实时、多模态的触觉感知能力?
人类能够直观地感知和理解复杂的触觉信息,是因为分布在指尖皮肤的皮肤感受器同时接收到不同的触觉刺激,并将触觉信号立即传输到大脑。尽管许多研究小组试图模仿人类皮肤的结构和功能,但在一个系统内实现类似人类的触觉感知过程仍然是一个挑战…...
datax
DataX DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL、SQL Server、Oracle、PostgreSQL、HDFS、Hive、HBase、OTS、ODPS 等各种异构数据源之间高效的数据同步功能。 https://github.com/alibaba/DataX Features DataX本身作为数据同…...

【Java】SpringBoot快速整合WebSocket实现客户端服务端相互推送信息
目录 什么是webSocket? webSocket可以用来做什么? WebSocket操作类 一:测试客户端向服务端推送消息 1.启动SpringBoot项目 2.打开网站 3.进行测试消息推送 4.后端进行查看测试结果 二:测试服务端向客户端推送消息 1.接口代码 2.使…...

C语言 linux文件操作(一)
文章目录 一、linux文件权限1.1文件描述符1.2文件描述符的范围和默认值1.3打开文件和文件描述符1.4标准文件描述符1.5文件描述符的重定向和关闭1.6I/O 操作1.7使用文件描述符进行进程通信1.8资源限制 二、C语言文件读写2.1open 函数2.2 flags参数详解2.3 lseek 函数 一、linux文…...

007、控制流
先看下本篇学习内容: 通过条件来执行 或 重复执行某些代码 是大部分编程语言的基础组成部分。在Rust中用来控制程序执行流的结构主要就是 if表达式 与 循环表达式。 1. if表达式 if表达式允许我们根据条件执行不同的代码分支。我们提供一个条件,并且做出…...

将学习自动化测试时的医药管理信息系统项目用idea运行
将学习自动化测试时的医药管理信息系统项目用idea运行 背景 学习自动化测试的时候老师的运行方式是把医药管理信息系统项目打包成war包后再放到tomcat的webapp中去运行,于是我想着用idea运行会方便点,现在记录下步骤方便以后查找最开始没有查阅资料&am…...
k8s 的YAML文件详解
一、yaml文件简介 Kubernetes只支持YAML和JSON格式创建资源对象,JSON格式用于接口之间消息的传递,适用于开发;YAML格式用于配置和管理,适用于云平台管理,YAML是一种简洁的非标记性语言。 1)yaml的语法规则&…...

【Pytorch】Pytorch或者CUDA版本不符合问题解决与分析
NVIDIA CUDA Toolkit Release Notes Package installation issues INSTALL PYTORCH 先声毒人:最好资料就是上面三份资料,可以通过官网明确的获取一手信息,你所遇到的99%的问题都可以找到,明确的解决方案,建议最好看…...

『精』CSS 小技巧之BEM规范
『精』CSS 小技巧之BEM规范 文章目录 『精』CSS 小技巧之BEM规范一、什么是BEM?二、BEM要怎么用?三、不用BEM会少个胳膊吗?💊四、Sass与BEM的结合🎈五、块与修饰符应放在一块👿参考资料💘推荐博…...

vue3-12
需求是用户如果登录了,可以访问主页,如果没有登录,则不能访问主页,随后跳转到登录界面,让用户登录 实现思路,在用户登录之前做一个检查,如果登录了,则token是存在的,则放…...

操作系统期末复习
分段存储管理方式 某采用段式存储管理的系统为装入主存的一个作业建立了如下段表: 段号 段长 主存起始地址 0 660 210 1 140 3300 2 100 90 3 580 1237 4 960 1959 (1)计算该作业访问[0,432],[1&am…...

element el-table实现可进行横向拖拽滚动
【问题】表格横向太长,表格横向滚动条位于最底部,需将页面滚动至最底部才可左右拖动表格,用户体验感不好 【需求】基于elment的el-table组件生成的表格,使其可以横向拖拽滚动 【实现】灵感来源于这篇文章【Vue】表格可拖拽滚动&am…...

【兔子王赠书第14期】《YOLO目标检测》涵盖众多目标检测框架,附赠源代码和全书彩图!
文章目录 写在前面YOLO目标检测推荐图书本书特色内容简介作者简介 推荐理由粉丝福利写在后面 写在前面 小伙伴们好久不见吖,本期博主给大家推荐一本关于YOLO目标检测的图书,该书侧重目标检测的基础知识,包含丰富的实践内容,是目标…...
WPF 基础入门(样式)
3.1 一般样式 <Grid Margin"10"><TextBlock Text"Style test" Foreground"Red" FontSize"20"/> </Grid> 3.2内嵌样式 直接在控件上定义样式,如下所示: <Grid Margin"10">…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...

算法打卡第18天
从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7…...

【Java多线程从青铜到王者】单例设计模式(八)
wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本,sleep也是可以指定时间的,也就是说时间一到就会解除阻塞,继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒),wait能被notify提前唤醒…...
k8s从入门到放弃之Pod的容器探针检测
k8s从入门到放弃之Pod的容器探针检测 在Kubernetes(简称K8s)中,容器探测是指kubelet对容器执行定期诊断的过程,以确保容器中的应用程序处于预期的状态。这些探测是保障应用健康和高可用性的重要机制。Kubernetes提供了两种种类型…...

英国云服务器上安装宝塔面板(BT Panel)
在英国云服务器上安装宝塔面板(BT Panel) 是完全可行的,尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎,虽然官方主要面向中国大陆…...
scan_mode设计原则
scan_mode设计原则 在进行mtp controller设计时,基本功能设计完成后,需要设计scan_mode设计。 1、在进行scan_mode设计时,需要保证mtp处于standby模式,不会有擦写、编程动作。 2、只需要固定mtp datasheet说明的接口即可…...

【HTML】HTML 与 CSS 基础教程
作为 Java 工程师,掌握 HTML 和 CSS 也是需要的,它能让你高效与前端团队协作、调试页面元素,甚至独立完成简单页面开发。本文将用最简洁的方式带你掌握核心概念。 一、HTML,网页骨架搭建 核心概念:HTML通过标签定义内…...