【一学就会的ROS基础入门教程 】03-1 ROS基础编程:ROS工作空间的创建、话题topic的发布与接收、以及话题消息的自定义使用

2023-05-16

【一学就会的ROS基础入门教程 】03-1 ROS基础编程:ROS工作空间的创建、话题topic的发布与接收、以及话题消息的自定义使用

  • 文前白话
    • 1、创建工作空间与功能包
        • 关于工作空间的介绍
        • 创建开发工作空间主要的终端操作命令步骤
        • 创建功能包
    • 2、简单的话题发布与接收
      • 发布者Publisher的编程实现(发布 Topic)
      • 订阅者Suberscriber的编程实现(接收 Topic)
      • 注:实现语言C++ 和 Python
    • 3、话题消息的自定义与使用

文前白话

本篇系列博客是依据哔站视频 【古月居】ROS 21讲 入门教程,学习整理,用于记录实践过程,加强学习,在系列整理的章节引导篇博客中,附带课程的课件和代码,需要的可以自行翻阅下载,共同学习。水平有限,若有整理错误之处,还请给予留言反馈,不胜感激。

系列整理的章节引导篇博客链接: 一学就会的ROS基础入门教程系列.

  • 本篇从ROS的相关应用编程继续学习: ROS工作空间的创建、话题topic的发布与接收、以及话题消息的自定义使用。

1、创建工作空间与功能包

关于工作空间的介绍

在这里插入图片描述
在这里插入图片描述

  • 具体的文件夹理解:
  • src : 存放代码的空间(功能包的代码、配置文件、lunach文件)
  • build: 编译空间(存放编译过程中产生的中间文件)
  • devel: 开发空间(编译生成的可执行文件、库、脚本)
  • Install: 安装空间 (install 指令生成的结果存放空间)

创建开发工作空间主要的终端操作命令步骤

在这里插入图片描述

  • 具体的步骤解析:
  • 1、从创建工作空间&初始化(创建文件夹src)
    在这里插入图片描述

在这里插入图片描述
2、在工作空间下进行编译:

在这里插入图片描述

  • 编译结果:

在这里插入图片描述

  • 再执行:
  • catkin_make install

在这里插入图片描述

创建功能包

  • 主要的命令流程:

在这里插入图片描述

  • 实际操作:在创建的 src 文件夹下:
  • 执行创建命令:

在这里插入图片描述

  • 生成功能包的两个标配文件:

在这里插入图片描述

  • CMakeLists.txt 和 package.xml 的作用:

功能包必须有的文件,package.xml 是介绍功能包的信息:名称、版本、功能、开发者信息、开源许可证、依赖信息等等。
CMakeLists.txt :描述功能包编译的规则,编译时候需要依赖的库

在这里插入图片描述

  • 其中生成的文件夹:src 放置功能包的代码文件(如cpp文件)、Include 放置 头文件(如c++的.h头文件)

  • 为了使功能包生效,进行编译:

在这里插入图片描述

  • 编译完成后,要运行功能包的某一个程序文件,先要设置一下工作空间的环境变量:
    执行:
source devel/setup.bash

在这里插入图片描述

  • 设置以后,才能让系统找得到工作空间,并且找到工作空间对应的功能包

在这里插入图片描述

  • echo $ROS_PACKAGE_PATH 是 ros 自身的环境变量,它会通过环境变量查找所有ros功能包的路径, 只有经过 设置功能包的 source devel/setup.bash 后, ROS_PACKAGE_PATH (ros 自身的环境变量)才会包含创建的工作空间的路径,才能找到对应的功能包,运行程序文件。

  • 为了避免每次创建功能包,忘记执行环境变量的配置,可以将 source devel/setup.bash 命令复制添加到 .bashrc 的配置文件里面:
    ** .bashrc在根目录下: (CTRL+h 可以显示隐藏文件)**
    在这里插入图片描述
    在这里插入图片描述

  • 这样,就不用每次都在终端进行这个工作空间的环境变量的配置。(重启终端生效)

2、简单的话题发布与接收

发布者Publisher的编程实现(发布 Topic)

原理图示:

在这里插入图片描述

  • 具体的操作:

1、创建功能包:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
2、创建话题发布者的代码

  • 发布话题的逻辑步骤:
    在这里插入图片描述

  • 话题发布代码


/**
 * 该例程将发布turtle1/cmd_vel话题,消息类型geometry_msgs::Twist
 */
 
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>

int main(int argc, char **argv)
{
	//1、 (初始化)ROS节点初始化
	ros::init(argc, argv, "velocity_publisher");  // "velocity_publisher"节点名称; argc, argv  初始化的参数输入

	//2、(注册) 创建节点句柄,管理节点的资源
	ros::NodeHandle n;    

	// 3、(创建消息)创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10
	// 队列理解:发布的频率较高,不能及时接收,就先存到队列中去
	//(如果队列满了,就会把时间较久的数据抛出掉,留下10个最新的数据)。
	ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);

	// 4、(发布消息)设置循环的频率
	ros::Rate loop_rate(10);

	int count = 0;
	while (ros::ok())  
	{  //while 循环主要就是封装数据、并发布数据、延时满足频率进入到下次循环
	    // 初始化geometry_msgs::Twist类型的消息
		geometry_msgs::Twist vel_msg;   // 类
		vel_msg.linear.x = 0.5;   // 运动的线速度  m/s
		vel_msg.angular.z = 0.2;   // 角速度  弧度/m

	    // 发布消息
		turtle_vel_pub.publish(vel_msg);  
		//调用方法发布数据,数据内容会通过ROS底层系列的通讯机制,将数据压入队列,队列通过底层的以太网
		//的ros—topic 的 tcp 通讯机制不断的发出去,这里通过下面的ROS_INFO,输出信息,告知客户端,信息发送的状态
		ROS_INFO("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]", 
				vel_msg.linear.x, vel_msg.angular.z);

	    // 按照循环频率延时
	    loop_rate.sleep();
	}

	return 0;
}


3、 配置话题发布者代码的编译规则:

  • 其实就是,规定编译可执行文件生成的文件名、链接相关的依赖库;
    在这里插入图片描述

  • 将上述两句指令,拷贝到 CMakeLists.txt 文件中

  • 对于指令的解释:

  • add_executable(velocity_publisher src/velocity_publisher. cpp)

  • 作用:描述将哪一个程序文件(velocity_publisher. cpp),编译成哪一个可执行文件(velocity_publisher src)

  • target_link_libraries(velocity_publisher S(catkin_LIBRARIES])

  • 作用: 帮助将生成的可执行文件与ROS 的一些库建立连接(c++的库)、

  • 在这里插入图片描述
    在这里插入图片描述

4、进行功能包的编译

在这里插入图片描述

在这里插入图片描述

5、设置环境变量:

  • 在工作空间的根目录:
    执行: source devel/setup.bash

  • 注:如果已经将 source devel/setup.bash 命令复制添加到 .bashrc 的配置文件里面,可以 忽略此步骤。

6、终端下运行功能包:


在这里插入图片描述
在这里插入图片描述

订阅者Suberscriber的编程实现(接收 Topic)

逻辑原理图:

在这里插入图片描述

在这里插入图片描述

具体操作:

1、在功能包的 src 中创建 话题订阅者的代码:


/**
 * 该例程将订阅/turtle1/pose话题,消息类型turtlesim::Pose
 */
 
#include <ros/ros.h>
#include "turtlesim/Pose.h"

// 接收到订阅的消息后,会进入消息回调函数
void poseCallback(const turtlesim::Pose::ConstPtr& msg)  // turtlesim::Pose是消息的 结构,与turtle1/pose是一致的, 通过常指针调用
{
    // 将接收到的消息打印出来
    ROS_INFO("Turtle pose: x:%0.6f, y:%0.6f", msg->x, msg->y);
}

int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc, argv, "pose_subscriber");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Subscriber,订阅名为/turtle1/pose的topic,注册回调函数poseCallback
    ros::Subscriber pose_sub = n.subscribe("/turtle1/pose", 10, poseCallback);
//10是队列长度,存储从发布者传输的数据(缓冲区)
// 因为不知道什么时候会有消息传输进来,一旦发现,就

    // 循环等待回调函数(死循环,一旦发现 队列中 有数据进来就 立刻调用personInfoCallback来处理)
    ros::spin();

    return 0;
}

//注意:回调函数非常重要,要完成消息的处理,要高效(不嵌套) ;不能卡住,影响下一个数据的进入



2、配置话题订阅者代码编译规则:

在这里插入图片描述

  • 即是:

将:

在这里插入图片描述
添加到:

在这里插入图片描述

3、 进行编译

  • 在工作空间下执行:
catkin_make

4、配置环境变量:

  • 在工作空间的根目录:
    执行: source devel/setup.bash

  • 注:如果已经将 source devel/setup.bash 命令复制添加到 .bashrc 的配置文件里面,可以 忽略此步骤。

5、终端下运行订阅话题:

  • 终端下分别执行:
    在这里插入图片描述
    在这里插入图片描述

  • 当你不知道某个文件夹的具体某一个文件的名称时候,可以进入该文件夹下 用 tab 键 补全 显示来查看:

  • 如果TAB键不能补全,说明可能环境变量不对、或者程序没有编译成功。

  • 再打开海龟的键盘操纵节点,移动小海龟 :

在这里插入图片描述

  • 海龟对应的位置信息就会实时显示出来。

注:实现语言C++ 和 Python

  • 功能包的实现既可以是c++也可以是 python 语言,区别在于,python脚本语言不用进行编译。

在这里插入图片描述

  • 创建单独的文件夹来存放python代码文件:仅仅是为了区分c++,方便管理
    在这里插入图片描述

  • 同时,由于语言的不同,python 不需要编译,可以直接执行
    在这里插入图片描述

3、话题消息的自定义与使用

  • 现有的 ros 话题消息无法满足需求,可以自己来定义/发布话题

逻辑原理:

在这里插入图片描述

具体操作步骤:

1、自定义话题消息

在这里插入图片描述

  • 其中,注意理解宏定义的用法:

在这里插入图片描述

  • 在功能包的文件夹下创建自定义消息存放的文件夹:msg(方便查找管理)

在这里插入图片描述

  • 然后,创建自定义消息内容的文件:

在这里插入图片描述

  • 内容可以自行发布:

在这里插入图片描述

  • .msg 文件格式既不是c++也不是python文件,它是 ros 在编译过程中,结合具体的定义来变成对应的 c++ 或者 python 程序。

2、 设置编译规则:

  • 即是:添加功能包依赖(编译依赖+执行依赖)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 在添加编译选项

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、在工作空间下进行编译:

在这里插入图片描述
在这里插入图片描述

4、通过程序调用生成的头文件:

  • 创建发布者与订阅者的个自代码:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



/**
 * 该例程将发布/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;   // 通过宏定义调用显示 性别 信息的值male =1 

        // 发布消息
		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;
}


/**
 * 该例程将订阅/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;
}

5、配置topic发布/接收代码编译规则:

在这里插入图片描述

  • 即是:在功能包文件夹下的 CMakeList.txt 中,添加:

在这里插入图片描述
在这里插入图片描述

  • 其中,add_dependencies…
    (有一些代码是动态生成的,需要把生成的可执行文件与动态生成的程序产生依赖关系;用来动态的跟我们生成的头文件产生连接(与自定义的消息产生连接))

6、编译并在终端运行发布者和订阅者:

在这里插入图片描述

  • 编译:

在这里插入图片描述

  • 运行 roscore, 打开节点管理器:

在这里插入图片描述

在这里插入图片描述

  • 实现通讯。

  • 此时,如果关闭 roscore (ROS Master) 发布者 与订阅者仍然可以继续通讯,但是不能 与其他的节点进行 通讯。

  • (这里已经提前设置了环境变量)

  • python版本:

在这里插入图片描述

  • 将代码放在对应的python文件夹中:
    在这里插入图片描述
  • 除去不用编译,其他步骤同c++版本步骤一致。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【一学就会的ROS基础入门教程 】03-1 ROS基础编程:ROS工作空间的创建、话题topic的发布与接收、以及话题消息的自定义使用 的相关文章

  • 函数声明在头文件中的好处,可以利用静态库隐藏算法

    背景 xff1a 现在有个程序员A想实现一个算法 xff0c 这个算法是俩数之和 xff0c 他自己不会于是他去买程序员B的已经做好的算法 xff0c 但是程序员B不想让他看到算法结构应该怎么做 1 首先程序员B需要写程序 xff0c 包括
  • Javaparser使用

    Javaparser使用 什么是Javaparser 分析 转换 生成Java代码 Javaparser库为你提供了一个 Java 代码的抽象语法树 Abstract Syntax Tree AST 结构允许您以一种简单的编程方式使用 Ja
  • YUV和RGB图像格式说明

    对于进行图像处理的程序员来说 xff0c 图像格式是必须了解的问题 本文不涉及压缩图像格式 xff0c 只对YUV和RGB图像进行描述 1 RGB图像和YUV图像区别 RGB和YUV图像的区别在于色彩空间坐标系描述上不同 xff0c 就如同
  • CMake 常用指令

    文章目录 范式环境 amp 工程配置 96 cmake minimum required 96 96 project 96 96 file 96 添加头文件搜索路径 96 link directories 96 96 add compile
  • (JAVA)国际跳棋--棋里乾坤

    导入 因为假期内被朋友带入坑后起了兴趣 xff0c 但发现网上似乎没有什么人写过国际跳棋的相关制作过程 xff0c 于是制作了一个单纯的java的国际跳棋程序 xff0c 虽然没有AI xff0c 但能够实现玩家双方的任务和皮肤 目前只设置
  • 力扣刷题日记 211. 添加与搜索单词

    211 添加与搜索单词 题目描述题解思路代码结语 题目描述 题解思路 首先 xff0c 这道题要求我们给出所有结果 xff0c 那就意味着我们可能只能选择枚举这一条路 xff0c 然后再看到数据范围 xff0c 好家 伙 xff0c 确实挺
  • 力扣刷题日记 798. 得分最高的最小轮调

    798 得分最高的最小轮调 题目描述题解思路代码结语 题目描述 题解思路 数据范围没有截图到 xff0c 这里的数据范围为0 20000 题目的内容还是很好理解的 xff0c 就是给你一个数组 xff0c 你可以将数组内容向左推移若干次 x
  • Java实现简单的计算器

    文章目录 前言一 主界面部分二 监听器部分三 结果计算部分总结 前言 最近在复习着Java Swing的使用 xff0c 在布局这块反复又看了很久 xff0c 然后突然发现GirdLayout机器适合来做一个计算器的简单样子 xff0c 所
  • 多旋翼飞行器设计与控制(一)

    一 基本概念固定翼直升机多旋翼复合飞行器 二 操控和评价四旋翼操控对比评价局限性 三 发展历史休眠期 xff08 1990前 xff09 复苏期 xff08 1990 2005 xff09 产品方面学术方面 发展期 xff08 2005 2
  • 考试中暴露的问题

    1 注意位运算 可以去看看洛谷里如果城堡不用位运算处理的话会怎样233 2 注意数学函数 xff0c 如sqrt为开根号 xff0c abs为绝对值 xff1b 3 最长上升子序列upper bound与lower bound的用法要知道
  • 10月28日考试解题报告

    考试中的心路历程 说实话第一道题和第三道题真的是水题 xff0c 然鹅我只搞到了100分 xff0c 感觉有些亏 xff0c 最后一题看错了题目 xff0c 导致我的思路开始各种螺旋 xff0c 当其他人都为第二题思考的时候 xff0c 我
  • 10月30日解题报告

    做题思路 第一题表示根本没有想到是线段树这种东西 xff0c 结果看到题解的时候 内心是崩溃的 xff0c 看了线段树还是得多练练 xff0c 第二题是dp xff0c 算是简单 xff0c 但是自己没有想到还是很伤 xff0c 也还是要多
  • C++ 获取string字符串长度的三种方法

    1 用string的成员方法length 获取字符串长度 length 比较直观 xff0c 表示的就是该字符串的长度 include lt string gt include lt iostream gt using namespace
  • sublime text3 搭建python环境

    1 python下载 python安装文件下载 2 安装easy install 方法是下载ez setup py后 xff0c 在cmd下执行 pythonez setup py xff0c 即可自动安装setuptools window
  • C++ 字符串指针和字符串指针数组详解

    C 43 43 处理字符串有两种方式 xff0c 即 xff1a 指针方式和数组方式 数组方式 xff1a char a 61 34 HelloWorld 34 指针方式 xff1a const char s 61 34 HelloWorl
  • 【C++笔记】关于push_back(vector<int>());

    vector lt vector lt int gt gt vec vec push back vector lt int gt vec back push back vec n push back 今天在刷leetcode题的时候见到如上
  • C++ const用法总结

    const 是constant的简写 xff0c 是C 43 43 中极为常见且重要的关键字 xff0c 主要功能是设置某些参数不可修改 xff0c 今天对其用法进行总结记录 一 在变量中的用法 对变量进行修饰是const最基本的用法 xf
  • C++ 函数指针以及对void*(* func)(void *)的解读

    1 函数指针 我们知道调用一个函数的时候可以给其传递参数 xff0c 这个参数可以是变量 xff0c 也可以是变量的引用或者指针 那如果想传递另一个函数可以做到吗 xff1f C提供了函数指针这一用法来完成这个需求 函数在内存中是占据一片空
  • 线程同步之互斥锁

    1 问题 单线程执行任务的场景通常是简单不易出错的 xff0c 但是多线程执行任务时 xff0c 由于线程对于内存空间的共享特性 xff0c 在并发执行时却会产生一些意料之外的错误 如下列程序 xff1a include 34 unpthr
  • C++知识点梳理(1)

    C 43 43 程序由一个或者多个被称为函数的模块组成 和函数从main函数 xff08 全部小写 xff09 开始执行 xff0c 所以main函数必不可少 函数头指向函数的返回值 xff08 如果有函数头 xff09 的类型和函数期望通

随机推荐