ROS2从入门到精通1-1:详解ROS2话题通信机制与自定义消息

目录

  • 0 专栏介绍
  • 1 话题通信模型
  • 2 话题模型实现(C++)
  • 3 话题模型实现(Python)
  • 4 自定义消息

0 专栏介绍

本专栏旨在通过对ROS2的系统学习,掌握ROS2底层基本分布式原理,并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。

🚀详情:《ROS2从入门到精通》


1 话题通信模型

话题是一种单向通信通道,数据或信息以定义的格式传递其中。机器人组件可以订阅主题以接收信息,或者发布信息到主题以与其他组件分享。其中发布信息的节点称为发布者,接受信息的节点称为订阅者

在这里插入图片描述

举个例子,想象一个移动机器人,其中有一个负责读取传感器数据的组件,另一个负责控制电机。传感器组件可以在名为sensor_readings的话题中发布传感器读数信息。同时,控制组件可以订阅此话题以接收该信息并用于控制电机。

在 ROS 2 中,话题由中间件管理以确保消息可靠高效地传输。话题中的消息可以是任何可序列化的数据类型,例如整数、浮点数、字符串、矩阵等。

ROS 2 中的话题具有多对多通信的灵活性和可扩展性。例如,可以有多个组件订阅同一话题,或者多个组件发布数据到同一主题。此外,可以使用线程来连接单个机器人内部的组件,或者在网络中连接不同机器人之间的组件。

在这里插入图片描述

2 话题模型实现(C++)

实验目标:发布者发布控制消息到/turtle1/cmd_vel,控制乌龟其做圆周运动;订阅者订阅/turtle1/cmd_vel,在终端显示乌龟实时的位置坐标。

  • 发布者

    class PublisherNode : public rclcpp::Node
    {
        public:
            PublisherNode() : Node("lab_topic_pub") {
                publisher_ = create_publisher<geometry_msgs::msg::Twist>("/turtle1/cmd_vel", 10); 
            }
    
            void publish(geometry_msgs::msg::Twist msg) {
                publisher_->publish(msg);
            }
    
        private:
            rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr publisher_;
    };
    
    int main(int argc, char * argv[])                      
    {
        rclcpp::init(argc, argv); 
    
        auto node = std::make_shared<PublisherNode>();
        
        rclcpp::Rate loop_rate(10);
        while(rclcpp::ok()) {
            auto msg = geometry_msgs::msg::Twist();
            msg.linear.x = 0.5;
            msg.angular.z = 0.2;
            node->publish(msg);
            RCLCPP_INFO(node->get_logger(), "Publishing: x: %.2f, z: %.2f", msg.linear.x, msg.angular.z);
            loop_rate.sleep();
        }   
        
        rclcpp::shutdown();                                
        return 0;
    }
    
  • 订阅者(订阅的话题存在消息即触发回调函数)

    class SubscriberNode : public rclcpp::Node
    {
        public:
            SubscriberNode() : Node("lab_topic_sub")
            {
                subscriber_ = create_subscription<geometry_msgs::msg::Twist>(       
                    "/turtle1/cmd_vel", 10, std::bind(&SubscriberNode::OnPoseCallback, this, _1));
            }
    
        private:
            void OnPoseCallback(const geometry_msgs::msg::Twist & msg) const
            {
                RCLCPP_INFO(get_logger(), "Publishing: x: %.2f, z: %.2f", msg.linear.x, msg.angular.z);
            }
            
            rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr subscriber_; 
    };
    
    int main(int argc, char * argv[])                         
    {
        rclcpp::init(argc, argv);                 
        rclcpp::spin(std::make_shared<SubscriberNode>());     
        rclcpp::shutdown();                                  
        
        return 0;
    }
    

话题通信的效果如下所示:

在这里插入图片描述

计算图可视化为:

在这里插入图片描述

3 话题模型实现(Python)

实验目标:发布者发布控制消息到/turtle1/cmd_vel,控制乌龟其做圆周运动;订阅者订阅/turtle1/cmd_vel,在终端显示乌龟实时的位置坐标。

  • 发布者
    class PublisherNode(Node):
        def __init__(self, name):
            super().__init__(name) 
            self.publisher_ = self.create_publisher(Twist, '/turtle1/cmd_vel', 10) 
    
        def publish(self, msg: Twist):
            self.publisher_.publish(msg)
    
  • 订阅者
    class SubscriberNode(Node):
        def __init__(self, name):
            super().__init__(name)
            self.subscirber_ = self.create_subscription(
                Twist, '/turtle1/cmd_vel', self.OnPoseCallback, 10
            ) 
    
        def OnPoseCallback(self, msg):
            self.get_logger().info(f"Publishing: x: {msg.linear.x:.2f}, z: {msg.angular.z:.2f}")
    	
    def main(args=None):                             
        rclpy.init(args=args)                        
        node = SubscriberNode("lab_topic_sub")
        rclpy.spin(node)                                        
        node.destroy_node()                                     
        rclpy.shutdown()   
    

话题通信的效果如下所示:

在这里插入图片描述

4 自定义消息

ROS2系统通过std_msgs封装了一些常用的原生数据类型,比如StringInt32Int64等,对于一些复杂数据应用场景,往往需要在std_msgs或其他消息库的基础上继续封装更高级的数据类型

自定义消息的通用流程如下:

  • 功能包下新建msg文件夹,在其中添加自定义消息xxx.msg
  • 功能包package.xml中添加编译依赖与执行依赖
    <buildtool_depend>rosidl_default_generators</buildtool_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}
    	"xxx.msg"
    	DEPENDENCIES xxx_msgs
    )
    
    ament_export_dependencies(rosidl_default_runtime)
    
  • 编译自定义消息,在install/<pkg_name>/include中生成由xxx.msg编译的C++可识别的xxx.hpp头文件
  • 引入xxx.hpp即可调用自定义消息

下面给出一个实例:

添加如下自定义消息,并按上面步骤配置依赖

# Person.msg
string name
string gender
uint8 age

geometry_msgs/Point position
    float64 x
    float64 y
    float64 z

定义一个发布者、一个订阅者测试自定义消息

  • 发布者
    // 初始化名为personPub的ROS节点, 该节点应在CMakeLists.txt中被构建为可执行文件
    ros::init(argc, argv, "personPub");
    // 创建节点句柄
    ros::NodeHandle pubNode;
    // 创建发布者, 该发布者属于pubNode节点, 发布话题为"/person/info",
    // 消息类型为"msgtest::Person", 发布队列长度为10
    ros::Publisher pub = pubNode.advertise<msg_lab::Person>("/person/info", 10);
    // 设置发布频率
    ros::Rate loopRate(10);
    while(ros::ok())
    {
        // 设置消息
        msg_lab::Person msg;
        msg.name = "winter";
        msg.gender = "man";
        msg.age = 20;
        msg.position.x = 10;
        msg.position.y = 20;
        msg.position.z = 30;
        // 发布消息
        pub.publish(msg);
        ROS_INFO("Publish Person Info[name: %s gender: %s age: %d pos: x-%.2f y-%.2f z-%.2f]", 
                msg.name.c_str(), msg.gender.c_str(), msg.age, msg.position.x, msg.position.y, msg.position.z);
        // 按循环频率延时
        loopRate.sleep();
    }
    
  • 订阅者
    void personInfoCallBack(const msg_lab::Person::ConstPtr &msg)
    {
        ROS_INFO("Subscribe Person Info[name: %s gender: %s age: %d pos: x-%.2f y-%.2f z-%.2f]", 
                    msg->name.c_str(), msg->gender.c_str(), msg->age, msg->position.x, msg->position.y, msg->position.z);
    }
    
    int main(int argc, char** argv)
    {
        // 初始化名为personSub的ROS节点, 该节点应在CMakeLists.txt中被构建为可执行文件
        ros::init(argc, argv, "personSub");
        // 创建节点句柄
        ros::NodeHandle subNode;
        // 创建订阅者, 该订阅者属于subNode节点, 订阅话题为"/person/info",
        // 订阅队列长度为10, 收到订阅消息后出发回调函数personInfoCallBack
        ros::Subscriber sub = subNode.subscribe("/person/info", 10, personInfoCallBack);
        // 循环等待回调函数
        ros::spin();
        return 0;
    }
    

实测效果如下:

在这里插入图片描述

完整代码通过下方博主名片联系获取


🔥 更多精彩专栏

  • 《ROS从入门到精通》
  • 《Pytorch深度学习实战》
  • 《机器学习强基计划》
  • 《运动规划实战精讲》

👇源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系👇

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【最新版源码】快递平台独立版小程序源码|带cps推广营销流量主+前端

源码介绍&#xff1a; 快递代发快递代寄寄件小程序可以对接易达云洋一级总代 快递小程序&#xff0c;接入云洋/易达物流接口&#xff0c;支持选择快递公司&#xff0c;三通一达&#xff0c;极兔&#xff0c;德邦等&#xff0c;功能成熟 如何收益: 1.对接第三方平台成本大约4…

CoAP计算机协议,应用于物联网

什么是CoAP协议&#xff1f; CoAP&#xff08;Constrained Application Protocol&#xff0c;受限应用协议&#xff09;是一种专为物联网&#xff08;IoT&#xff09;设备和资源受限网络设计的应用层协议。它的诞生也是由于物联网设备大多都是资源限制型的&#xff0c;比如 CP…

【GPT-SOVITS-02】GPT模块解析

说明&#xff1a;该系列文章从本人知乎账号迁入&#xff0c;主要原因是知乎图片附件过于模糊。 知乎专栏地址&#xff1a; 语音生成专栏 系列文章地址&#xff1a; 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…

Java之SpringBoot基础夯实——八股文【2024面试题案例代码】

1、什么是 Spring Boot&#xff1f; Spring Boot 是一个开源的Java开发框架&#xff0c;由Pivotal团队开发&#xff0c;其核心目标是简化新Spring应用的初始搭建和开发流程。它以Spring框架为基础&#xff0c;通过自动配置和约定优于配置的原则&#xff0c;极大程度地减少了手…

HarmonyOS(鸿蒙)ArkUI组件

方舟开发框架&#xff08;简称ArkUI&#xff09;为HarmonyOS应用的UI开发提供了完整的基础设施&#xff0c;包括简洁的UI语法、丰富的UI功能&#xff08;组件、布局、动画以及交互事件&#xff09;&#xff0c;以及实时界面预览工具等&#xff0c;可以支持开发者进行可视化界面…

嵌入式学习之Linux系统编程篇笔记——系统编程初探

配套视频学习链接&#xff1a;https://www.bilibili.com/video/BV1zV411e7Cy?p2&vd_sourced488bc722b90657aaa06a1e8647eddfc 目录 Linux系统编程的基本认识 什么是Linux系统编程? 什么是系统编程 系统编程的作用 怎么学习Linux系统编程? Linux系统编程基本程序框…

马斯克大模型Grok-1已开源,目前为止最大的开源大语言模型

&#x1f989; AI新闻 &#x1f680; 马斯克大模型Grok-1已开源&#xff0c;目前为止最大的开源大语言模型 摘要&#xff1a;马斯克上一周就在x上预告将开源自己的大模型&#xff0c;等了一周&#xff0c;就在刚刚&#xff0c;马斯克的大模型 Grok-1 开源了&#xff0c;Grok-…

【Canvas与艺术】砂落字现

【注意】 本作代码需要在服务器端执行&#xff0c;不可用浏览器直接打开运行。 如何安装服务器端请参考&#xff1a;https://www.cnblogs.com/heyang78/p/3339235.html 【原理】 雨粒子落下时&#xff0c;如果当前点不是黑点&#xff0c;则化身为金字的一个像素点。 【效果…

USB - USB Gadget on Linux

February, 2012. Embedded Linux Conference 2012. Agenda Introduction to USB USB Gadget API Existing Gadgets Design your own Gadget Demo Conclusio About the Author Software engineer at Adeneo Embedded Linux, Android Main activities: – BSP adaptation – Driv…

PXVDI企业级PVE免费桌面虚拟化部署教程ProxmoxVE

什么是PXVDI&#xff1f; PXVDI是一款基于Proxmox VE为底层的可商用的免费云桌面套件。对熟悉PVE的人来说&#xff0c;这点非常的点赞。首先是PVE是免费的&#xff0c;其次PVE的免费云桌面方案也极为少数。 根据官方提出的价格清单&#xff0c;免费版和商业版在功能上主要的区…

使用CURL命令确定Access-Control-Allow-Origin问题

一、问题描述 有前端小伙伴反馈ajax请求遇到跨域问题&#xff0c;也让后端小伙伴设置了跨域允许&#xff0c;但诡异的事情是在前端小伙伴的微信开发者工具中Network headers中看到了两行&#xff1a;Access-Control-Allow-Origin&#xff0c;其中居然出现了&#xff1a;“Acce…

51单片机—DS18B20温度传感器

目录 一.元件介绍及原理 二&#xff0c;应用&#xff1a;DS18B20读取温度 一.元件介绍及原理 1.元件 2.内部介绍 本次元件使用的是单总线 以下为单总线的介绍 时序结构 操作流程 本次需要使用的是SKIP ROM 跳过&#xff0c; CONVERT T温度变化&#xff0c;READ SCRATCHPAD…

Linux:系统初始化,内核优化,性能优化(2)

优化ssh协议 Linux&#xff1a;ssh配置_ssh配置文件-CSDN博客https://blog.csdn.net/w14768855/article/details/131520745?ops_request_misc%257B%2522request%255Fid%2522%253A%2522171068202516800197044705%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fb…

redis 常见的异常

目录 一、缓存穿透 1、概念 解决方案 &#xff08;1&#xff09;布隆过滤器 (2)、缓存空对象 二、缓存雪崩 1、概念 解决方案 &#xff08;1&#xff09;redis高可用 &#xff08;2&#xff09;限流降级 &#xff08;3&#xff09;数据预热 一、缓存穿透 1、概念 缓…

JavaWeb后端——分层解耦 IOC DI

分层/三层架构概述 三层架构&#xff1a;Controller、Service、Dao 解耦/IOC&DI概述 分层解耦 容器称为&#xff1a;IOC容器/Spring容器 IOC 容器中创建&#xff0c;管理的对象&#xff0c;称为&#xff1a;bean 对象 IOC&DI入门 实现 IOC&DI 需要的注解&#…

【MySQL】 MySQL的内置函数——日期函数、字符串函数、数学函数、聚合函数、其他函数

文章目录 MySQL1. 日期函数1.1 查看时间1.2 对时间进行计算 2. 字符串函数2.1 字符串查找2.2 字符串修改显示 3. 数学函数4. 聚合函数5. 其他函数 MySQL 1. 日期函数 在MySQL中&#xff0c;提供了多种时间函数供我们使用&#xff0c;其中包括用于查看时间的函数和计算日期的函数…

基于java+springboot+vue实现的高校教师工作量管理系统(文末源码+Lw+ppt)23-451

摘 要 高校教师工作量管理系统采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的java进行编写&#xff0c;使用了springboot框架。该系统从两个对象&#xff1a;由管理员和教师来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对…

Jmeter文件上传不成功问题

前言 最近好忙呀&#xff0c;项目上线然后紧接着又客户培训了&#xff0c;由于项目有个模块全是走配置的&#xff0c;所以导致问题不断&#xff0c;近期要培训为了保障培训时客户同时操作的情况&#xff0c;所以把我从功能端抽出来做压测了&#xff0c;之前安排了2个同事写压测…

数据结构的基本框架以及泛型

目录 集合框架复杂度大O的渐进表示法 装包(箱)或者拆包(箱)装包拆包 泛型泛型的上界泛型方法求最大值 集合框架 Java的集合框架,Java Collection Framework 又被称为容器container, 定义在java.util包下的一组 interfaces 和其实现类 classes interface: 接口 abstracb class…

基于Linux内核的socket编程(TCP)的C语言示例

原文地址&#xff1a;https://www.geeksforgeeks.org/socket-programming-cc/ 服务端&#xff1a; #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h>#…