ROS2 Topics和Services

news2024/12/23 2:20:48

本文主要介绍ROS的Topics概念,如何创建Publisher和Subscriber,通过Topic在ROS程序间通信;介绍ROS的Services概念,如何创建Client和Server并建立通信。
更多内容,访问专栏目录获取实时更新。

ROS Topics

Topics可以被视为一种具名的总线,用于节点间交换数据,通过Topics可以发布和订阅消息,实现单向的流式通信。需要注意的重点包括:

  • 单向流式通信(发布/订阅模式)
  • 匿名通信
  • 每个Topic都有特定的消息格式
  • 可以在ROS节点中通过Python, C++等多种语言实现
  • 一个节点可以拥有多个Topic

Publisher in Python

在ROS2基础编程一文中,我们已经创建了工作空间和工作包,在此基础上,来通过Python实现一个Topic的发布者。
my_py_pkg工作包下创建一个新的文件robot_news_station.py
在这里插入图片描述
robot_news_station.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.msg import String  # do not forget to add package dependency

class RobotNewsPublisherNode(Node):
  def __init__(self):
    super().__init__("robot_news_publisher")

    self.robot_name = "HiRobot"
    self.publisher = self.create_publisher(String, "robot_news", 10)
    self.timer = self.create_timer(1, self.publish_news)
    self.get_logger().info("Robot News Publisher has been started")

  def publish_news(self):
    msg = String()
    msg.data = "Hi, this is " + str(self.robot_name) + " from the robot news publisher"
    self.publisher.publish(msg)


def main(args=None):
  rclpy.init(args=args)
  node = RobotNewsPublisherNode()
  rclpy.spin(node)
  rclpy.shutdown()


if __name__ == "__main__":
  main()

还需要添加依赖包引用,修改package.xml文件:
在这里插入图片描述

然后装载我们的新节点,修改setup.py:
在这里插入图片描述

之后执行下面的指令就可以启动我们的publisher了:

colcon build --packages-select my_py_pkg --symlink-install
source ~/.bashrc
ros2 run my_py_pkg robot_news_station
ros2 topic echo /robot_news

Subscriber in Python

创建订阅者的方式与创建发布者类似,这里我们添加了一个名为robot_news_subscriber.py的文件:

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.msg import String  # do not forget to add package dependency

class RobotNewsSubscriberNode(Node):
  def __init__(self):
    super().__init__("robot_news_subscriber")

    self.subscriber = self.create_subscription(String, "robot_news", self.subscribe_news_callback, 10)
    self.get_logger().info("Robot News Subscriber has been started")

  def subscribe_news_callback(self, msg):
    self.get_logger().info(msg.data)


def main(args=None):
  rclpy.init(args=args)
  node = RobotNewsSubscriberNode()
  rclpy.spin(node)
  rclpy.shutdown()


if __name__ == "__main__":
  main()

不要忘记修改setup.pycolcon build编译。之后同时运行publisher和subscriber就可以看到右侧命令行里的subscriber每1s收到一条来自publisher的信息,并打印:
在这里插入图片描述

使用命令行工具调试Topics

ros2 topic list
ros2 topic info <topic_name>  # 查看所有激活的topic
ros2 topic echo <topic_name>   # 创建一个订阅者监听发布的消息
ros2 interface show <msg_type>  # 显示话题消息的类型
ros2 topic hz <topic_name>  # 获取发布频率
ros2 topic bw <topic_name>  # 获取消息的长度,byte width
ros2 topic pub <topic_name>  <msg_type> <msg_data>  # 发布一个topic
ros2 topic pub -r 10 /robot_news example_interfaces/msg/String "{data: 'hello from robot'}"
ros2 node list
ros2 info <node_name>
ros2 run <pkg_name> <node_name> --ros-args -r __node:=<new_node_name>
ros2 run <pkg_name> <node_name> --ros-args -r __node:=<new_node_name> -r <topic_name>:=<new_topic_name>

Ros Services

前文提到Topics实现的是单向的传输,通过发布/订阅模式建立连接,但用在一些需要请求/回复的分布式系统中就不太合适了。
Services可以帮助我们实现请求/回复的通信模式,一条消息用于请求,一条用于回复,ROS节点以字符串名称提供服务,客户端通过发送请求消息并等待回复来调用服务,从而建立持久性的连接。

Service Server in Python

ros2 interface show example_interfaces/srv

执行上面的指令,你能看到example_interface包里提供了哪些服务,这里我们使用AddTwoInts来演示如何创建一个service server
add_two_ints_server.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts


class AddTwoIntsServerNode(Node):
  def __init__(self):
    super().__init__("add_two_ints_server")
    self.server = self.create_service(AddTwoInts, "add_two_ints", self.callback_add_two_ints)
    self.get_logger().info("Add Two Ints Server has started")

  def callback_add_two_ints(self, request, response):
    response.sum = request.a + request.b
    self.get_logger().info(str(request.a) + " + " + str(request.b) + " = " + str(response.sum))
    return response


def main(args=None):
  rclpy.init(args=args)
  node = AddTwoIntsServerNode()
  rclpy.spin(node)
  rclpy.shutdown()


if __name__ == "__main__":
  main()

编译并运行,通过ros2 service list就能在服务列表里看到我们启动的服务了。
在这里插入图片描述

ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 3, b: 4}"

执行上面的指令就可以在命令行里调用我们创建的service。

Service Client in Python

add_two_ints_client.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts


def main(args=None):
  rclpy.init(args=args)
  
  node = Node("add_two_ints_no_oop")
  client = node.create_client(AddTwoInts, "add_two_ints")
  while not client.wait_for_service(1):
    node.get_logger().warn("Waiting for server Add Two Ints...")

  request = AddTwoInts.Request()
  request.a = 3
  request.b = 8
  future = client.call_async(request)
  rclpy.spin_until_future_complete(node, future)

  try:
    response = future.result()
    node.get_logger().info(str(request.a) + " + " + str(request.b) + " = " + str(response.sum))
  except Exception as e:
    node.get_logger().error("Service call failed %r" % (e,))


  rclpy.shutdown()


if __name__ == "__main__":
  main()

使用命令行工具调试Services

ros2 service list
ros2 service type <service_name>
ros2 interface show <service type>
ros2 service call <service_name> <service_type> <value>
ros2 run <pkg_name> <node_name> --ros-args -r <service_name>:=<new_service_name>

ROS Interface

ROS应用之间有三种通信接口:messages, services和actions,ROS2使用IDL(interface definition language)来描述这些接口,使得在不同应用,不同编程语言间进行交互更加简单。例如前文提到的Topic和Service:

Topic:

  • Name:话题名
  • 消息定义:Msg,如example_interfaces/msg/Int64

Service:

  • Name: 服务名
  • 服务定义:Srv,如example_interfaces/srv/AddTwoInts (包含request和response)

创建自定义的Msg

创建一个新的工作包my_robot_interfaces,移除目录下的includesrc文件夹,并新建msg文件夹:
在这里插入图片描述
msg文件夹下新建msg定义文件: HardwareStatus.msg

int64 temperature
string debug_message

更新package.xml,添加:

<build_depend>rosidl_default_generators</build_depend>
 <exec_depend>rosidl_default_runtime</exec_depend>
 <member_of_group>rosidl_interface_packages</member_of_group>

更新CMakeLists.txt,添加:

find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/HardwareStatus.msg"
)

ament_export_dependencies(rosidl_default_runtime)
ament_package()

然后编译工作包,就可以在其他工程中使用该Msg定义了。

使用自定义的Msg

my_py_pkg工作包下创建一个新的publisher:hw_status_publisher.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from my_robot_interfaces.msg import HardwareStatus


class HardwareStatusPublisherNode(Node):
  def __init__(self):
    super().__init__("hardware_status_publisher")
    self.hw_status_publisher = self.create_publisher(HardwareStatus, "hardware_status", 10)
    self.timer = self.create_timer(1, self.publish_hw_status)
    self.get_logger().info("Hardware Status Publisher has been started")
  
  def publish_hw_status(self):
    msg = HardwareStatus()
    msg.temperature = 45
    msg.debug_message = "No error"
    self.hw_status_publisher.publish(msg)


def main(args=None):
  rclpy.init(args=args)
  node = HardwareStatusPublisherNode()
  rclpy.spin(node)
  rclpy.shutdown()


if __name__ == "__main__":
  main()

不要忘记在package.xml中添加对my_robot_interface的依赖,并把新的节点加载到setup.py并编译。运行haredware_status_publisher并监听,可以看到如下的效果:
在这里插入图片描述

创建自定义的Srv

my_robot_interfaces工作包目录下创建srv文件夹,并新建文件ComputerRectangleArea.srv

float64 length
float64 width
---
float64 area

更新CMakeLists.txt
在这里插入图片描述
成功编译了工作包后我们就能够获得自定义的Srv了
在这里插入图片描述

如有错误,欢迎留言或来信指正:hbin6358@163.com

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

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

相关文章

SQL数据库多层嵌套 json转sql建表语句,SQL数据库里数组里对象数据怎么创建

1. uniapp sqlite 一个数组包含对象嵌套对象通过主外键方式插入数据库&#xff1a; // 假设有一个对象数组&#xff0c;对象中包含嵌套对象 const objectsArray [{parentObject: {id: 1,name: Parent 1,// 其他父对象属性},childObject: {id: 11,parentId: 1,name: Child 1 o…

TOPSIS综合评价

TOPSIS法&#xff08;Technique for Order Preference by Similarity to an Ideal Solution&#xff09;是一种常用的综合评价方法&#xff0c;该方法根据有限个评价对象与理想化目标的接近程度进行排序&#xff0c;是在现有的对象中进行相对优劣的评价。 TOPSIS法的原理是通过…

Github 2024-05-29 C开源项目日报 Top10

根据Github Trendings的统计,今日(2024-05-29统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10C++项目3PHP项目1PHP:流行的Web开发脚本语言 创建周期:4710 天开发语言:C, PHP协议类型:OtherStar数量:37340 个Fork数量:7657 次…

SpringBoot 微服务中怎么获取用户信息 token

SpringBoot 微服务中怎么获取用户信息 token 当我们写了一个A接口&#xff0c;这个接口需要调用B接口&#xff0c;但是B接口需要包含请求头内容&#xff0c;比如需要用户信息、用户id等内容&#xff0c;由于不在同一个线程中&#xff0c;使用ThreadLocal去获取数据是无法获取的…

[java基础揉碎]文件IO流

目录 文件 什么是文件 文件流​编辑 常用的文件操作 创建文件方式一 创建文件方式二 创建文件方式三 tip:为什么new file 了还有执行createNewFile?new File的时候其实是在内存中创建了文件对象, 还没有在磁盘中, 当执行createNewFile的时候才是往磁盘中写入​编辑 …

申请的商标名称相同或近似,如何解决!

最近遇到一些首次申请注册商标的主体&#xff0c;基本想的名称都是两个字或或者两个字加通用词&#xff0c;还有用的行业描述词或缺乏显著特征词&#xff0c;这样去申请注册商标&#xff0c;普推知产老杨分析这样去直接申请注册大概率驳回。 两个字基本上注册的差不多了&#…

推券客CMS淘宝优惠券网站源码

推券客CMS淘宝优惠券网站源码是一个以PHPMySQL进行开发的PHP淘宝客优惠券网站。支持电脑站、手机站以及微信公众号查券。支持多级代理返利和阿里妈妈最新的渠道管理等功能。 五大优势 一、全开源 推券客cms网站程序数据库完全开源,目前市场上基本都是以下2种淘宝客系统 第一…

Redis:redis基础

Redis Remote Dictionary Service即远程字典服务 一个基于内存的key-value结构数据库,在开发中常常作为缓存存储不经常被改变的数据 基于内存存储,读写性能高 在企业中应用广泛 Redis介绍 用C语言开发的开源高性能键值对数据库,可以达到10w的qps,可以存储丰富的value类型…

从alpine构建预装vcpkg的docker image用于gitea actions CI

动机 想要构建一个基于vcpkg的交叉编译容器平台用于cpp项目的CI&#xff08;自动集成&#xff09;&#xff0c;此处仅提供最基础的image&#xff0c;amd64的机子上构建完成后大小为533兆&#xff08;着实不小&#x1f613;&#xff09;&#xff0c;各位看官可以在此基础上自行…

Gradle的学习

1.1 Gradle的优势 一款最新的&#xff0c;功能最强大的构建工具&#xff0c;用它逼格更高 使用Groovy或Kotlin代替XML&#xff0c;使用程序代替传统的XML配置&#xff0c;项目构建更灵活 丰富的第三方插件&#xff0c;让你随心所欲使用 完善Android,Java开发技术体系 1.2 …

Filebeat进阶指南:核心架构与功能组件的深度剖析

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《洞察之眼&#xff1a;ELK监控与可视化》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是ELK 2、FileBeat在ELK中的角色 二、Fil…

树莓派4B 学习笔记1:TF卡系统盘烧录_初次启动_远程端连接配置

今日开始学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; TF卡系统盘烧录_初次启动_远程端连接配置 目录 格式化SD卡&#xff1a; 烧录系统Win32DiskImager&#xff1a; Raspberry Pi Imager镜像烧写&#xff1a; 树莓派官网资料…

教育装备之先导小型五轴加工中心

随着制造业的快速发展和技术的不断进步&#xff0c;对高端技术人才的需求日益增长。五轴联动技术作为解决异性复杂零件高效优质加工问题的重要手段&#xff0c;受到了广泛关注。因此&#xff0c;培养掌握五轴联动技术的专业人才显得尤为重要。 先导小型五轴加工中心提供了真实的…

「数据结构」队列

目录 队列的基本概念 队列的实现 头文件queue.h 实现函数接口 1.初始化和销毁 2.出队列和入队列 3.获取队头元素和队尾元素 4.队列长度判空 后记 前言 欢迎大家来到小鸥的博客~ 个人主页&#xff1a;海盗猫鸥 本篇专题&#xff1a;数据结构 多谢大家的支持啦&#xff…

对比表征学习(一)Contrastive Representation Learning

对比表征学习&#xff08;二&#xff09;Sentence Embedding 主要参考翁莉莲的Blog&#xff0c;本文主要聚焦于对比损失函数 对比表示学习&#xff08;Contrastive Representation Learning&#xff09;可以用来优化嵌入空间&#xff0c;使相似的数据靠近&#xff0c;不相似的数…

玩转STM32-通用同步/异步收发器USART(详细-慢工出细活)

CPU与外围设备之间的信息交换或计算机与计算机之间的信息交换称为通信。基 本的通信方式有两种&#xff0c;即并行通信和串行通信。文章目录 一、串行通信基础1.1 串行通信的方式1.2 串行通信的数据传输形式1.3 波特率 二、STM32的USART的结构特征&#xff08;了解&#xff09;…

采集EthernetIP IO从站设备数据 转 profinet IO协议项目案例

1 文档说明 设置网关采集EthernetIP IO设备数据把采集的数据转成profinet IO协议转发给其他系统。 2 准备工作 仰科网关。支持采集EthernetIP IO数据&#xff0c;profinet IO协议转发。电脑。IP设置成192.168.1.198&#xff0c;和网关在同一个网段。网线、12V电源。 3 网关…

MySQL8报错Public Key Retrieval is not allowedz 怎么解决?

问题描述 当我们使用数据库管理工具连接mysql8的时候&#xff0c;可能遇到报错&#xff1a; Public Key Retrieval is not allowed 解决办法 1、在连接属性中配置allowPublicKeyRetrieval设置为true 2、在连接URL中加上配置allowPublicKeyRetrieval为true

《软件方法(下)》8.3.4.6 DDD话语“聚合”中的伪创新(1)

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 8.3 建模步骤C-2 识别类的关系 8.3.4 识别关联关系 8.3.4.6 DDD话语“聚合”中的伪创新 DDD话语中也有“聚合”。Eric Evans的“Domain-Driven Design: Tackling Complexity in the…

「光储充放」一体充电站-一文读懂光储充放充电站

“光储充放”一体充电站作为一种储能充电的新形式渐渐走进人们的生活&#xff0c;全国很多地区都开始陆续投放运营“光储充放”一体充电站&#xff0c;今天的这篇文章&#xff0c;就带大家全面了解“光储充放”这一新型充电站。 头图来源 | 视觉中国 01 政策背景 早在2020年…