当前位置: 首页 > news >正文

【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机器人入门到实战】
笔者的学习目录

  1. MOMO的鱼香ROS2(一)ROS2入门篇——从Ubuntu操作系统开启
  2. 【ROS2】MOMO的鱼香ROS2(二)ROS2入门篇——ROS2初体验
  3. ROS2】MOMO的鱼香ROS2(三)ROS2入门篇——ROS2第一个节点

专业术语认识

  1. TCP(传输控制协议)
  2. 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&#xff08;传输控制协议&#xff09;1.2 UDP&#xff08;用户数据报协议&#xff09;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命令的时候&#xff0c;报如下的错误&#xff0c;表示不支持mysql命令&#xff1a; zsh: command not found: mysql 1. 先查看mysql服务是否存在 在系统偏好设置中查看&#xff1a; 2. 发现mysql服务已经在运行&#xff0c;可能因为/usr/local/bin目录下缺失mysq…...

【开题报告】基于java的流浪之家动物领养网站的设计与开发

1.选题背景 流浪之家动物领养网站的设计与开发背景主要源于对流浪动物保护和宠物领养问题的关注。随着城市化进程加快&#xff0c;越来越多的流浪动物出现在城市中&#xff0c;它们面临着食物、住所和医疗资源的缺乏。同时&#xff0c;许多爱心人士希望能够给流浪动物一个温暖…...

训狗技术从初级到高级,专业有效的训狗训犬教程

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

如何让机器人具备实时、多模态的触觉感知能力?

人类能够直观地感知和理解复杂的触觉信息&#xff0c;是因为分布在指尖皮肤的皮肤感受器同时接收到不同的触觉刺激&#xff0c;并将触觉信号立即传输到大脑。尽管许多研究小组试图模仿人类皮肤的结构和功能&#xff0c;但在一个系统内实现类似人类的触觉感知过程仍然是一个挑战…...

datax

DataX DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台&#xff0c;实现包括 MySQL、SQL Server、Oracle、PostgreSQL、HDFS、Hive、HBase、OTS、ODPS 等各种异构数据源之间高效的数据同步功能。 https://github.com/alibaba/DataX Features DataX本身作为数据同…...

【Java】SpringBoot快速整合WebSocket实现客户端服务端相互推送信息

目录 什么是webSocket&#xff1f; webSocket可以用来做什么? WebSocket操作类 一&#xff1a;测试客户端向服务端推送消息 1.启动SpringBoot项目 2.打开网站 3.进行测试消息推送 4.后端进行查看测试结果 二&#xff1a;测试服务端向客户端推送消息 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、控制流

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

将学习自动化测试时的医药管理信息系统项目用idea运行

将学习自动化测试时的医药管理信息系统项目用idea运行 背景 学习自动化测试的时候老师的运行方式是把医药管理信息系统项目打包成war包后再放到tomcat的webapp中去运行&#xff0c;于是我想着用idea运行会方便点&#xff0c;现在记录下步骤方便以后查找最开始没有查阅资料&am…...

k8s 的YAML文件详解

一、yaml文件简介 Kubernetes只支持YAML和JSON格式创建资源对象&#xff0c;JSON格式用于接口之间消息的传递&#xff0c;适用于开发&#xff1b;YAML格式用于配置和管理&#xff0c;适用于云平台管理&#xff0c;YAML是一种简洁的非标记性语言。 1&#xff09;yaml的语法规则&…...

【Pytorch】Pytorch或者CUDA版本不符合问题解决与分析

NVIDIA CUDA Toolkit Release Notes Package installation issues INSTALL PYTORCH 先声毒人&#xff1a;最好资料就是上面三份资料&#xff0c;可以通过官网明确的获取一手信息&#xff0c;你所遇到的99%的问题都可以找到&#xff0c;明确的解决方案&#xff0c;建议最好看…...

『精』CSS 小技巧之BEM规范

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

vue3-12

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

操作系统期末复习

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

element el-table实现可进行横向拖拽滚动

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

【兔子王赠书第14期】《YOLO目标检测》涵盖众多目标检测框架,附赠源代码和全书彩图!

文章目录 写在前面YOLO目标检测推荐图书本书特色内容简介作者简介 推荐理由粉丝福利写在后面 写在前面 小伙伴们好久不见吖&#xff0c;本期博主给大家推荐一本关于YOLO目标检测的图书&#xff0c;该书侧重目标检测的基础知识&#xff0c;包含丰富的实践内容&#xff0c;是目标…...

WPF 基础入门(样式)

3.1 一般样式 <Grid Margin"10"><TextBlock Text"Style test" Foreground"Red" FontSize"20"/> </Grid> 3.2内嵌样式 直接在控件上定义样式&#xff0c;如下所示&#xff1a; <Grid Margin"10">…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...