【古月居《ros入门21讲》学习笔记】10_话题消息的定义与使用

目录

说明:

1. 话题模型

2. 实现过程(C++)

自定义话题消息

Person.msg文件内容

Person.msg文件内容说明

编译配置

在package.xml文件中添加功能包依赖

在CMakeLists.txt中添加编译选项

编译生成语言相关文件

创建发布者代码(C++)

创建订阅者代码(C++)

配置代码编译规则

配置内容说明

编译并运行

编译

运行

扩展

3. 实现过程(Python)

创建发布者代码(Python)

创建订阅者代码(Python)

运行


说明:

1. 本系列学习笔记基于B站:古月居《ROS入门21讲》课程,且使用的Ubuntu与ROS系统版本与课程完全一致;

虚拟机版本Linux系统版本ROS系统版本
VMware WorkStation Pro 16Ubuntu18.04Melodic


2. 课程中的所有示例代码均已跑通,且对Pyhon版本的代码也都做了运行验证,并附带验证过程(错误均已修正);

3. 本节是整个笔记的第10节,对应视频课程的第12节,请自行对应学习;

4. 整个系列笔记基本已经完结,但部分章节仍需润色修改 ,后面会陆续发布,请大家持续关注,      创作不易,感谢支持!
 


1. 话题模型

image-20230525103444411

2. 实现过程(C++)

自定义话题消息

cd ~/catkin_ws/src/learning_topic
mkdir msg
cd msg
touch Person.msg

Person.msg文件内容
string name // 名字
uint8 sex   // 性别:分为3种,男、女、未知,下面以012宏定义做表示判断
uint8 age   // 年龄
​
uint8 unknown = 0 
uint8 male = 1    
uint8 female = 2
Person.msg文件内容说明

Person.msg文件里定义的内容跟语言无关的,这既不是c++,也不是python,这里面的string uint8表示在不同的程序里面扩展成对应该种程序的表示方法,可以类比单片机里无符号整型变量类型unsigned int来理解,缩写就是uint。

cd ~/catkin_ws/src/learning_topic
mkdir msg

注意:新建的这个文件夹名字不能随便命名,只能叫msg,否则编译会报错,CMakeList文件中有说明,要放在名叫msg文件夹中。

image-20230525105802095

cd msg
touch Person.msg

(注意:这里的文件名首字母P一定要大写!否则后面会报错)

打开Person.msg文件,把定义的内容复制到文件里并保存,

(注意:输入的内容中,注释不要,空格不能用tab键缩进,否则后面也会报错)

image-20230525143629177

编译配置

路径:~/catkin_ws/src/learning_topic

在package.xml文件中添加功能包依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

build_depend:编译依赖

exec_depend:运行依赖

image-20230525134244239

在CMakeLists.txt中添加编译选项
find_package(......message_generation)

image-20230525142005844

add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)

add_message_files: 把我们定义的Person.msg文件,做为我们定义的接口;

generate_messages:编译Person.msg文件的时候需要用到一些依赖于ROS已有的库或包,

我们这里用到的依赖是std_msgs,我们前面看到的string,uint8都是在std_msgs里面做定义的

image-20230525142153143

catkin_package(......message_runtime)

image-20230525142706463

编译生成语言相关文件
cd ~/catkin_ws
catkin_make

image-20230525144332516

编译成功之后可以在~/catkin_ws/devel/include/learning_topic下看到Person.msg文件编译生成的C++的头文件Person.h

image-20230525145008343

创建发布者代码(C++)

cd ~/catkin_ws/src/learning_topic/src
touch person_publisher.cpp

  • 初始化ROS节点;

  • 向ROS Master注册节点信息,包括发布消息的话题名,话题中的消息类型;

  • 创建消息数据;

  • 按照一定频率循环发布消息,

/**
 * 该例程将发布/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include <ros/ros.h>
#include "learning_topic/Person.h"
​
int main(int argc, char **argv)
{
    // ROS节点初始化
    ros::init(argc, argv, "person_publisher");
​
    // 创建节点句柄
    ros::NodeHandle n;
​
    // 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    ros::Publisher person_info_pub = n.advertise<learning_topic::Person>("/person_info", 10);
​
    // 设置循环的频率
    ros::Rate loop_rate(1);
​
    int count = 0;
    while (ros::ok())
    {
        // 初始化learning_topic::Person类型的消息
        learning_topic::Person person_msg;
        person_msg.name = "Tom";
        person_msg.age  = 18;
        person_msg.sex  = learning_topic::Person::male;
​
        // 发布消息
        person_info_pub.publish(person_msg);
​
        ROS_INFO("Publish Person Info: name:%s  age:%d  sex:%d", 
                  person_msg.name.c_str(), person_msg.age, person_msg.sex);
​
        // 按照循环频率延时
        loop_rate.sleep();
    }
​
    return 0;
}

image-20230525152240349

创建订阅者代码(C++)

cd ~/catkin_ws/src/learning_topic/src
touch person_subscriber.cpp

初始化ROS节点;

订阅需要的话题;

循环等待话题消息,接收到消息后进入回调函数;

在回调函数中完成消息处理。

/**
 * 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include <ros/ros.h>
#include "learning_topic/Person.h"
​
// 接收到订阅的消息后,会进入消息回调函数
void personInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Subcribe Person Info: name:%s  age:%d  sex:%d", 
             msg->name.c_str(), msg->age, msg->sex);
}
​
int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc, argv, "person_subscriber");
​
    // 创建节点句柄
    ros::NodeHandle n;
​
    // 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    ros::Subscriber person_info_sub = n.subscribe("/person_info", 10, personInfoCallback);
​
    // 循环等待回调函数
    ros::spin();
​
    return 0;
}

image-20230525154634297

配置代码编译规则

将下面6行内容复制到CMakeLists.txt文件中,

add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})
add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)
​
add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)
配置内容说明

add_executable:

将person_publisher.cpp和person_subscriber.cpp代码文件编译成person_publisher与person_subscriber可执行文件;

target_link_libraries:

把编译生成的可执行文件person_publisher与person_subscriber跟ROS相关的一些库做连接的,比如调用的C++的接口;

add_dependencies:

有一些代码是动态生成的,而可执行文件也需要与动态生成的程序产生依赖关系,所以这个就是用来动态的和刚才生成的头文件Person.h产生依赖关系的;

复制到CMakeLists.txt文件中的位置如下:

image-20230525155453179

编译并运行

编译
cd ~/catkin_ws
catkin_make

image-20230525160916698

运行
roscore
rosrun learning_topic person_subscriber
rosrun learning_topic person_publisher

第一步:打开ROS Master;

第二步:运行订阅者person_subscriber,让其先等待着发布者发布消息数据,

第三步:运行发布者person_publisher,让其发布消息数据,

image-20230525162541324

扩展

如果把启动ROS_Master的roscore关掉,发布者与订阅者依然在发布和接收消息数据,此时ROS_Master的结束对两者并无影响,

因为ROS_Master是帮助节点建立连接的,一旦连接创立,ROS_Master在这里的作用就不再存在了,但关掉ROS_Master后,

如果有第三个节点要加入进来的话,是无法再建立连接的。

image-20230526155216489

3. 实现过程(Python)

创建发布者代码(Python)

cd ~/catkin_ws/src/learning_topic/scripts
touch person_publisher.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将发布/person_info话题,自定义消息类型learning_topic::Person
​
import rospy
from learning_topic.msg import Person
​
def velocity_publisher():
    # ROS节点初始化
    rospy.init_node('person_publisher', anonymous=True)
​
    # 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    person_info_pub = rospy.Publisher('/person_info', Person, queue_size=10)
​
    #设置循环的频率
    rate = rospy.Rate(10) 
​
    while not rospy.is_shutdown():
        # 初始化learning_topic::Person类型的消息
        person_msg = Person()
        person_msg.name = "Tom";
        person_msg.age  = 18;
        person_msg.sex  = Person.male;
​
        # 发布消息
        person_info_pub.publish(person_msg)
        rospy.loginfo("Publsh person message[%s, %d, %d]", 
                person_msg.name, person_msg.age, person_msg.sex)
​
        # 按照循环频率延时
        rate.sleep()
​
if __name__ == '__main__':
    try:
        velocity_publisher()
    except rospy.ROSInterruptException:
        pass

image-20230526161126127

创建订阅者代码(Python)

cd ~/catkin_ws/src/learning_topic/scripts
touch person_subscriber.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person
​
import rospy
from learning_topic.msg import Person
​
def personInfoCallback(msg):
    rospy.loginfo("Subcribe Person Info: name:%s  age:%d  sex:%d", 
             msg.name, msg.age, msg.sex)
​
def person_subscriber():
    # ROS节点初始化
    rospy.init_node('person_subscriber', anonymous=True)
​
    # 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    rospy.Subscriber("/person_info", Person, personInfoCallback)
​
    # 循环等待回调函数
    rospy.spin()
​
if __name__ == '__main__':
    person_subscriber()

image-20230526162129583

注意:给person_publisher.py 和 person_subscriber.py文件赋予作为程序文件执行的权限,

点击person_publisher.py文件,右键,属性,权限,勾选(允许作为程序文件执行),

person_subscriber.py文件操作同上,python文件不需要编译,直接运行即可。

image-20230526162441381

运行

roscore
rosrun learning_topic person_subscriber.py
rosrun learning_topic person_publisher.py

第一步:打开ROS Master;

第二步:运行订阅者person_subscriber.py,让其先等待着发布者发布消息数据,

第三步:运行发布者person_publisher.py,让其发布消息数据,

image-20230526163111027

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

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

相关文章

wifi8 Multi-AP介绍

作为一种结构&#xff0c;multi-AP最早在wifi7的草案中被提出。 但是wifi7估计不会加入。 现在变成了wifi8的路线。 比如下面是一种设想。总体是以若干BSS为单位。 每个BSS的信息都可以在CC处得到。这样就是一种基于CC的总控的MAP。 总控分为两个TDMA&#xff0c; 第一个TD…

数据结构算法-分支定界算法

引言 应该记得这一张图片&#xff0c;在A星算法里面说过 那么现在说的是换一种方式实现 如何实现&#xff1f; 之前不撞南墙不回头的方法-深度优先搜索 的方式 广度优先搜索方式 广度优先搜索&#xff1a;就是说按照顺序入队 并且搜索扩展节点 探测四面八方&#xff0c;如此循环…

Redis面试题:分片集群相关问题

目录 面试官&#xff1a;redis的分片集群有什么作用 面试官&#xff1a;Redis分片集群中数据是怎么存储和读取的&#xff1f; 面试官&#xff1a;redis的分片集群有什么作用 候选人&#xff1a;分片集群主要解决的是&#xff0c;海量数据存储的问题&#xff0c;集群中有多个m…

java第20章节

一.线程简介 二.创建线程 1.继承Thread类 Thread类中常用的两个构造方法如下&#xff1a; public Thread():创建一个新的线程对象。 public Thread(String threadName):创建一个名称为threadName的线程对象。 继承Thread类创建一个新的线程的语法如下&#xff1a; public c…

Vue拖拽div移动位置

<div id"TestDiv" mousedown"OnMouseDown"></div> css #TestDiv { position: absolute;left: 50%;top: 50%;width: 100px;height: 100px;z-index: 999;background-color: red; } 处理函数 const OnMouseDown(e:any)> {let videoBox:any…

游戏缺少d3dx9_43.dll修复方法分享,快速解决dll缺失问题

在计算机使用过程中&#xff0c;我们常常会遇到一些错误提示&#xff0c;其中之一就是“找不到d3dx9_43.dll文件”。这个错误通常出现在运行某些游戏或应用程序时&#xff0c;d3dx9_43.dll是一个动态链接库文件&#xff0c;它是DirectX 9的一部分&#xff0c;用于支持游戏中的3…

建筑行业有哪些好用的项目管理软件或者OA系统?

建筑行业有哪些好用的项目管理软件或者OA系统&#xff1f; 在现代社会中&#xff0c;系统已经成为了企业人事信息化、项目管理等方面必不可少的工具。尤其是对于建筑行业的工程项目管理和人事OA而言&#xff0c;借助系统进行协同、计划、控制等方面的工作&#xff0c;已经成为…

新手小白必看!一文带你了解跨境电商独立站

对于很多新手跨境电商来说&#xff0c;或许你对亚马逊、ebay、速卖通这些跨境电商平台已经有所了解&#xff0c;那你知道跨境电商独立站吗&#xff1f;应该也有不少朋友对跨境电商独立站感兴趣&#xff0c;特别是现在各大跨境电商平台越来越卷&#xff0c;很多跨境卖家都开始通…

手把手教你通过CODESYS V3进行PLC编程(三)

教程背景 通过之前的教程&#xff0c;我们已经为大家演示了宏集MC-Prime控制器的连接、试运行和CODESYS的安装&#xff0c;并创建了一个计数器项目。在本期教程中&#xff0c;我们将进一步深入&#xff0c;教大家如何使用CODESYS的可视化界面。 一、两种可视化方式 在CODESYS…

代码混淆的原理和方法详解

代码混淆的原理和方法详解摘要移动App的广泛使用带来了安全隐患&#xff0c;为了保护个人信息和数据安全&#xff0c;开发人员通常会采用代码混淆技术。本文将详细介绍代码混淆的原理和方法&#xff0c;并探讨其在移动应用开发中的重要性。 引言随着移动应用的普及&#xff0c;…

C语言数组的距离(ZZULIOJ1200:数组的距离)

题目描述 已知元素从小到大排列的两个数组x[]和y[]&#xff0c; 请写出一个程序算出两个数组彼此之间差的绝对值中最小的一个&#xff0c;这叫做数组的距离 。 输入&#xff1a;第一行为两个整数m, n(1≤m, n≤1000)&#xff0c;分别代表数组f[], g[]的长度。第二行有m个元素&a…

无人机覆盖路径规划综述

摘要&#xff1a;覆盖路径规划包括找到覆盖某个目标区域的每个点的路线。近年来&#xff0c;无人机已被应用于涉及地形覆盖的多个应用领域&#xff0c;如监视、智能农业、摄影测量、灾害管理、民事安全和野火跟踪等。本文旨在探索和分析文献中与覆盖路径规划问题中使用的不同方…

JavaScript 的初步学习下篇

函数 语法格式 创建函数/函数声明/函数定义 function 函数名(形参列表) {函数体return 返回值; }函数调用 函数名(实参列表) // 不考虑返回值 返回值 函数名(实参列表) // 考虑返回值 注: 函数定义并不会执行函数体内容, 必须要调用才会执行. 调用几次就会执行几次. js 中…

【华为数通HCIP | 网络工程师】821刷题日记-BFD和VRRP 及重点(1)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

Java 基础学习(四)操作数组、软件开发管理

1 操作数组 1.1.1 System.arraycopy 方法用于数组复制 当需要将一个数组的元素复制到另一个数组中时&#xff0c;可以使用System.arraycopy方法。它提供了一种高效的方式来复制数组的内容&#xff0c;避免了逐个元素赋值的繁琐过程。相对于使用循环逐个元素赋值的方式&#x…

使用Wordpress 从0-1 制作一个博客网站

一. 做网站准备 购买域名 域名使用的是二级域名&#xff1a;blog.zmrw.net&#xff08;在浏览器可以提前预览网站制作后效果&#xff09; 购买服务器 服务器使用A2 Hosting 购买Wordpress 主题 主题使用的是 Porto 主题 二. 开始建站 1. 将域名添加至 Cloudflare 2. 将…

井盖倾斜监测方式,智能井盖传感器效果

大家是否都曾经想过&#xff0c;为什么路面上的井盖容易发生事故&#xff1f;其实这主要是因为井盖倾斜或者位移等异常状态出现时&#xff0c;由于人员巡查的范围较大从而无法及时察觉所导致的。为了保障道路行人和车辆的安全&#xff0c;对于井盖的监测需要不断完善和升级。而…

Google分析中的基础概念

当提到Google分析时&#xff0c;我们通常指的是一种用于跟踪和分析网站和应用程序数据的工具。在使用Google分析之前&#xff0c;了解其基础概念对于正确配置和有效使用该工具非常重要。 1、帐户&#xff08;Account&#xff09;&#xff1a;帐户是Google分析中的最高层级。一…

【Axure高保真原型】区间评分条

今天和大家分享区间评分条的原型模板&#xff0c;我们可以左右拖动移动滑块到指定位置&#xff0c;评分条上方会根据两个滑块所在的位置&#xff0c;自动计算出对应的区间范围&#xff1b;这个原型模板使用也很简单&#xff0c;只需要在里面填写区间的最大值&#xff0c;即可自…

python——第十五天

面向对象和面向对象编程 面向对象编程&#xff1a; C语言是一门面向过程的编程语言&#xff01;&#xff01;&#xff01; 面向对象的编程思想 就是分门别类的一种能力 面向对象的概念 类&#xff1a; 对一类事物的统称 对象&#xff1a; 一类事物中的具体案例 面向对象的…