ROS开发日记(1)——ROS基础知识

时间:2024-04-07 12:16:57

ROS,即开源机器人操作系统。

1 官方定义:ROS是面向机器人的开源的元操作系统(meta-operating system) 1 。它能够提供类似传统操作系统的诸多功能,
如硬件抽象、底层设备控制、常用功能实现、进程间消息传递和程序包管理等。此外,它还提供相关工具和库,用于获取、编译、编辑代码以及在多个计算机之间运行程序完成分布式计算。

对比计算机系统:

ROS开发日记(1)——ROS基础知识

如上图所示,计算机的操作系统将计算机硬件封装起来,而应用软件运行在操作系统之上,不用管计算机具体应用的是什么类型的硬件产品。这能大大提高软件开发效率(否则大家只能都写汇编了)。

同理,ROS则是对机器人的硬件进行了封装,不同的机器人、不同的传感器,在ROS里可以用相同的方式表示(topic等),供上层应用程序(运动规划等)调用。

2 ROS用节点(Node)的概念表示一个应用程序,不同node之间通过事先定义好格式的消息(Topic),服务(Service),动作(Action)来实现连接。使用ROS能够解决的机器人软件开发问题:

ROS开发日记(1)——ROS基础知识

分布式计算(进程间的通信问题

软件复用(ROS标准包,ROS通信接口)

快速测试(ROS系统框架将底层硬件控制模块与顶层数据处理与决策模块分离;提供了一种简单的方法可以在调试过程中记录传感器数据以及其他类型的消息数据,并在试验后按时间戳回放)

3 安装ROS-配置账户-使用turtlesim的小例子-功能包/软件包(注意与操作系统软件包的区别)- 节点管理器 - 节点(ROS程序的运行实例)- 话题与消息 (发布与订阅)

ROS节点之间进行通信所利用的最重要的机制就是 消息传递。在ROS中,消息有组织地存放在 话题里。消息传递的理念是:
当一个节点想要分享信息时,它就会 发布(publish)消息到对应的一个或者多个话题;当一个节点想要接收信息时,它就会 订阅
(subscribe)它所需要的一个或者多个话题。ROS节点管理器负责确保发布节点和订阅节点能找到对方;而且消息是直接地从发布节点传递到订阅节点,中间并不经过节点管理器转交。

在 ROS 系统中查看节点之间的发布-订阅关系的最简单方式就是在终端输入如下命令:
rqt_graph

现在,我们对turtlesim遥控系统的工作原理有了一定的理解。当你按下一个键时,/teleop_turtle 节点会以消息的形式将这些运
动控制命令发布到话题/turtle1/cmd_vel;与此同时,因为turtlesim_node 订阅了该话题,因此它会接收到这个些消息,控制
海龟按照该预定的速度移动。

仿真海龟不关心(或者甚至不知道)哪个程序发布了这些cmd_vel 消息。任何向这个话题发布了消息的程序都能控制这个海龟。

远程操作程序不关心(或者甚至不知道)哪个程序订阅了它发布的 cmd_vel 消息。任何订阅了相关话题的程序都能自主选择是否响应这些命令。

ROS开发日记(1)——ROS基础知识

话题列表  为了获取当前活跃的话题,使用如下命令:rostopic list

打印消息内容 为了查看某个话题上发布的消息,可以利用rostopic 命令的如下形式:rostopic echo topic-name,这条命令将会在终端里显示出指定话题

测量发布频率 有两个命令可以用来测量消息发布的频率以及这些消息所占用的带宽:
rostopic hz topic-name
rostopic bw topic-name

查看话题  利用 rostopic info 命令,你可以获取更多关于话题的信息:
rostopic info topic-name

查看消息类型 要想查看某种消息类型的详情,使用类似下面的命令
rosmsg show message-type-name

命令行发布消息 大多数时候,发布消息的工作是由特定的程序完成的。但是,你会发现有时候手动发布消息是很实用的。要实现该功能,利用rostopic命令行工具:
rostopic pub –r rate-in-hz topic-name message-type message-content
这条命令重复地按照指定的频率给指定的话题发布指定的消息。

理解消息类型的命名  和 ROS 里其他的程序一样,每条消息类型都属于一个特定的包。消息类型名总会包含一个斜杠,斜杠前
面的名字是包含它的包:
package-name/type-name
例如,turtlesim/Color 消息类型按如下方式分解:

ROS开发日记(1)——ROS基础知识

话题和消息的通信机制是多对多的,即多个发布者和多个订阅者可以共享同一个话题。

对于绝大多数设计精巧的 ROS 节点——是 松耦合的。每个节点都不需要显式知道其他节点的存在与否;它们的唯一交互方式是间接地发生在基于话题和消息的通信层。这种节点之间的独立性,以及其支持的任务可分解特性(即复杂任务分解成可重用的小模块),是 ROS 最关键的设计特性之一。
 “生产”消息的程序(例如turtle_teleop_key)只管发布该消息,而不用关心该消息是如何被“消费”的。
 “消费”消息的程序(例如 turtlesim_node)只管订阅该话题或者它所需要消息的所有话题,而不用关心这些消息数据是如
何“生产”的。

ROS 为更加直接的一对一通信提供了一种称为 服务(services )的机制。

当ROS没有按你的预期运行时,一种可能有帮助的工具,也是本章要学习的最后一个命令行工具,是roswtf ,该命令可
以不带参数运行:
roswtf
这条命令会进行全面而深入的检测,包括检测你的环境变量、安装的文件以及运行的节点。

3 编写ROS程序

在我们写任何程序之前,第一步是创建一个容纳我们的功能包的工作区,然后再创建功能包本身。

Cmake 是一个符合工业标准的跨平台编译系统。这个文件包含了一系列的编译指令,包括应该生成哪种可执行文件,需
要哪些源文件,以及在哪里可以找到所需的头文件和链接库。
当然,这个文件表明 catkin 在内部使用了 Cmake。

ROS开发日记(1)——ROS基础知识

头文件 ros/ros.h 包含了标准 ROS 类的声明,你将会在每一个你写的 ROS 程序中包含它。

 ros::init函数初始化ROS客户端库。请在你程序的起始处调用一次该函数。函数最后的参数是一个包含节点默认名的字符串。

 ros::NodeHandle(节点句柄)对象是你的程序用于和ROS系统交互的主要机制 。创建此对象会将你的程序注册为ROS节点管理器的节点。最简单的方法就是在整个程序中只创建一个NodeHandle对象。

 ROS_INFO_STREAM 宏将生成一条消息,且这一消息被发送到不同的位置,包括控制台窗口。

编译的四个步骤:声明依赖库(编辑CMakelist文件),声明可执行文件,编译工作区,Sourcing setup.bash

执行hello程序:rosrun agitr hello

不要忘了先启动rescore

发布者程序 步骤:

发布消息  包含消息类型声明 每一个 ROS 话题都与一个消息类型相关联。每一个消息类型都有一个相对应 C++头文件。你需要在你的程序中为每一个用到的消息类型包含这个头文件。当引用 C++代码中的消息类时,你将会使用双分号(::)来区分开包名和类型名,双分号也称为 范围解析运算符

创建发布者对象

发布消息的实际工作是由类名为ros::Publisher的一个对象来完成的。如果你想从同一个节点发布关于多个话题的消息,你需要为
每个话题创建一个独立的 ros::Publisher 对象。

(请注意话题名和消息类型的区别。如果不小心将二者混淆,将会产生很多潜在的令人困惑的编译错误。)

创建并填充消息对象 下一步,我们创建消息对象本身

发布消息 在所有的前期工作完成后,使用 ros::Publisher 对象的publish 方法可以很简单地发布消息

定义输出格式 

我们的pubvel例程在while循环中重复发布消息的步骤,随着时间的推移发布不同的消息。程序在这个循环中使用了两个附加的构造函数。节点 是否 停止工作 的检查 pubvel 的 while 循环的条件是:
ros::ok()

通俗地说,这个函数检查我们的程序作为 ROS 节点是否仍处于运行良好的状态。它会一直返回 true,除非这个节点有某种原因使
其停止工作。

控制消息发布频率 pubvel的最后一个新知识点是它使用了ros::Rate对象
ros::Rate rate;
这个对象控制循环运行速度,其构造函数中的参数以赫兹(Hz)为单位,即每秒钟的循环数

你可能会想到在每一个循环迭代中使用简单的固定延迟(例如 sleep 或者 usleep 命令)来代替 ros::Rate。ros::Rate对象相对于这种方法的优势在于,ros::Rate 可以考虑循环中其他部分消耗的时间。如果每个迭代包含复杂计算(如我们所期待的真正的程序),通过该计算所消耗的时间应该从延迟中减除。在极端情况下,循环所使用的时间比预期的速率还要长,通过 sleep()方法产生的延迟会减少到 0。

编译 pubvel 的过程大部分和 hello 例程的相同,只需要适当修改 CMakeLists.txt 和 package.xml,然后用 catkin_make 来编译你
的工作区。然而,它和 hello 例程有一个很重要的区别:声明消息类型依赖库 因为pubvel使用了来自geometry_msgs包
的消息类型,我们必须声明对这个包的依赖关系

订阅者程序:

编写回调函数 发布和订阅消息的一个重要的区别是订阅者节点无法知道消息什么时候到达。为了应对这一事实,我们必须把响
应收到消息事件的代码放到 回调函数里,ROS 每接收到一个新的消息将调用一次这个函数。

创建订阅者对象 为了订阅一个话题,我们需要创建一个ros::Subscriber对象

给ROS控制权 最后的复杂之处在于只有当我们明确给ROS许可时,它才会执行我们的回调函数

订阅者程序中常见的一个错误是不小心忽略了调用ros::spinOnce 和 ros::spin。在这种情况下,ROS 永远没有机会去执行你的回调函数。忽略 ros::spin 会导致你的程序在开始运行后不久就退出。忽略 ros::spinOnce 使程序表现的好像没有接收到任何消息。

4 日志消息

ROS日志系统的核心思想,就是使程序生成一些简短的文本字符流,这些字符流便是日志消息。ROS中,日志消息分为五个不同的 严重 级别,也可简称为 严重性或者级别。按照严重性程度递增,这些级别有
DEBUG
INFO
WARN
ERROR
FATAL

首先,最明显的是,日志消息可以被送至控制台。具体而言,DEBUG和INFO消息被打印至标准输出(standard output),而WARN、ERROR和FATAL消息将被送至标准错误(standard error) 

格式化控制台消息 可以通过设置 ROSCONSOLE_FORMAT 环境变量来调整日志消息打印到控制台的格式

除了在控制台上显示,每一个日志消息都被发布到话题/rosout 上。该话题的消息类型是 rosgraph_msgs/Log

日志消息的第三个,也是最后一个目的地,是由 rosout 节点
生成的日志文件。作为/rosout 话题回调函数的一部分,该节点可
以将日志消息作为一行写入到一个日志文件

5 计算图源命名

ROS 具有一个能够接受几种不同类型名的灵活的命名系统

节点、话题、服务和参数统称为计算图源,而每个计算图源由一个叫计算图源名称(graph resource name)的短字符串标识。

全局名称的几个组成部分:
 前斜杠“/”表明这个名称为 全局名称。 由斜杠分开的一系列 命名空间(namespace) )每个斜杠代表一级命名空间。你可能已经猜到了,命名空间用于将相关的计算图源归类在一起。 描述资源本身的 基本名称(base name)

 ROS为计算图源提供一个默认的命名空间,具有此特征的名称叫做 相对 计算图源 名称 (ralative graph resource name) ),或简称为 相对名称 (relative name) )。相对名称的典型特征是它缺少全局名称带有的前斜杠“/”。

解析相对名称。设置默认命名空间。乍一看,提出相对名称这个概念似乎只是为了避免每次都用完整的全局名称编程。尽管相对名称提供了这种便捷方式,但是其真正意义在于它使得在小系统基础上实现复杂系统变得更加容易。当一个节点内的计算图源全部使用相对名称时,这本质上给用户提供了一种非常简单的移植手段,即用户能方便地将此节点和话题移植到其他的(比如用户自己程序的)命名空间,而节点的原设计者并不一定参与这个过程。

私有名称,以一个波浪字符(~)开始,是第三类也是最后一类计算图源名称。和相对名称一样,私有名称并不能完全确定它们自身所在的命名空间,而是需要 ROS 客户端库将这个名称解析为一个全局名称。与相对名称的主要差别在于,私有名称不是用
当前默认命名空间,而是用的它们节点名称作为命名空间。

除了以上三种基本的命名类型,ROS 还提供了另一种被称为匿名名称的命名机制,一般用于为节点命名。这里的匿名并不是指没有名字,而是指非用户指定而又没有语义信息的名字。匿名名称的目的是使节点的命名更容易遵守唯一性的规则。其思路是当节点调用 ros::init 方法时可以请求一个自动分配的唯一名称。

6 启动文件

ROS 提供了一个同时启动节点管理器(master)和多个节点的途径,即使用 启动文件 (launch file) 

其基本思想是在一个XML格式的文件内将需要同时启动的一组节点罗列出来

执行启动文件 想要运行一个启动文件,可以像下面这样使用roslaunch命令:roslaunch package-name launch-file-name

不要将 rosrun 和 roslaunch 混为一谈,rosrun 一次只能启动一个节点,而 roslaunch 可以同时启动多个节点。设计良好的 ROS 节点,是不关心各个节点的启动顺序的

创建启动文件:启动文件的存储位置常的命名方案是以.launch 作为启动文件的后缀   启动文件的基本元素,插入根元素,插入根元素 ,请求复位 ,必要节点 ,为节点维护独立的窗口

在命名空间内启动节点

名称重映射-关于重映射的使用,有一点需要牢记:在 ROS 应用任何重映射之前,所有的名称都要先解析为全局名称,包括重映射中的原始名称和新名称。

例子:反向海龟

ROS开发日记(1)——ROS基础知识

重映射后

ROS开发日记(1)——ROS基础知识

7 参数 

除了前面介绍过的消息传递,ROS还提供另一种参数( parameters )机制用于获取节点的信息。其主要思想是使用集中
参数服务器 ( parameter server )维护一个变量集的值,包括整数、浮点数、字符串以及其他数据类型,每一个变量用一个较短的字符串标识 。由于允许节点主动查询其感兴趣的参数的值,它们适用于配置那些不会随时间频繁变更的信息。

需要引起高度注意的是,更新的参数值不会自动“推送”到节点。恰恰相反,如果节点关心它的一些或者所有参数是否改变,必须明确向参数服务器请求这些参数的值。

8 服务

服务调用与消息的区别主要体现在两个方面。
 服务调用是双向的,一个节点给另一个节点发送信息并等待响应,因此信息流是双向的。作为对比,当消息发布后,并没有响应的概念,甚至不能保证系统内有节点订阅了这些消息。
 服务调用实现的是一对一通信。每一个服务由一个节点发起,对这个服务的响应返回同一个节点。另一方面,每一个消息
都和一个话题相关,这个话题可能有很多的发布者和订阅者。

ROS开发日记(1)——ROS基础知识

其过程是一个 客户端(client)节点发送一些称为 请求(request )的数据到一个 服务器(server )节点,并且等待回应。服务器节点接收到请求后,采取一些行动(计算、配置软件或硬件、改变自身行为等),然后发送一些称为响应 (response )的数据给客户端节点。
请求和响应数据携带的特定内容由 服务数据类型(service data type )来决定,它与决定消息内容的消息类型是类似的(。同消息类型一样,服务数据类型也是由一系列域构成的。唯一的区别就在于服务数据类型分为两部分,分别表示请求(客户端节点提供给服务器节点)和响应(服务其节点反馈给客户端节点)。

9 消息录制与重放

设计精良的ROS系统的一个重要特征便是系统中信息的消费者不应该关心信息的生产者。这种体系架构最明显的体现是 ROS
主要使用的消息发布 - 订阅通信模型。在这个模型下,不论什么时刻,只要有消息被发布,其订阅节点就应该正常工作,而不管
是哪个或是哪些节点正在发布这些消息。本章将介绍一个体现这种灵活性的具体例子,即一种被称为rosbag 的工具。通过rosbag,我们能够将发布在一个或者多个话题上的消息录制到一个包文件中,然后可以回放这些消息,重现相似的运行过程。将这两种能力结合,便形成了测试某些机器人软件的有效方式:我们可以偶尔运行机器人,运行过程中录制关注的话题,然后多次回放与这些话题相关的消息,同时使用处理这些数据的软件进行实验。

10 总结

这一节扼要介绍前面章节没有覆盖但在实际ROS系统中又经常碰到的几个问题,并给出它们在 ROS 官网的链接地址。
在网络环境中运行 ROS 从用户的角度看,在不同计算机上运行的节点之间的通信和同一台计算机上运行的节点间通信没任何区别。
编写更规范的程序
使用rviz使数据可视化 运行turtlesim的例程时,几乎所有的消息数据都很简单,包括二维空间中的位置、朝向角度和速度等。与
之相反,真实的机器人系统往往十分复杂,机器人传感器获得的据不仅复杂而且通常带有噪声,本书中提到的方法不能用于查看这些数据。为了填补这个空白,ROS提供了一个叫做rviz的非常强大的图形界面工具,它可以通过订阅用户选择的话题来显示机
器人内部的各种信息,便于机器人的开发和调试。
创建消息和服务类型 本书中的所有例程涉及到的消息和服务均采用ROS系统已有的基本数据类型。当然,我么也可以根据自身
需要创建新的消息和服务类型,这并不复杂 。
用使用tf工具来管理多个坐标系 由于机器人运行在真实的物理环境中,通常的做法是用不同的坐标描述机器人不同部件的位置,包括机器人想要避开或者交互的目标。因此,如何正确描述这些坐标所在的坐标系成为了关键问题。在 ROS 中,很多消息类型均包含一个 frame_id 域来标识消息中数据所在的坐标系。为了更好的地用这些不同的坐标系,我们需要知道它们的相对位置关系。具体来说,我们需要知道将某个坐标从一个坐标系到另一个坐标系的 变换矩阵(Transformation) )。ROS提供了一个标准功能包tftf(transformation的缩写),其功能就是帮助节点来完成坐标转换
使用Gazebo 仿真 ROS系统最大的优势之一就是能够实现软件的模块化设计,基于这个框架可以轻易地替换系统中的各种软件模块,从而节约系统的开发时间,也使得测试变得简单方便

另:

好文转载:https://blog.csdn.net/jimson_zhu/article/details/81227495 重要概念

在开始进一步ROS的学习和使用之前,ROS的三层架构需要了解,而且对一些概念的理解是无法绕开的。

ROS有三个层级的概念,分别是:文件系统级、计算图级和开源社区级。

文件系统级:ROS的内部结构、文件结构和所需的核心文件都在这一层里,理解ROS文件系统是入门ROS的基础。一个ROS程序的结构,是一些按不同功能进行区分的文件夹。一般的文件夹结构是:

工作空间文件夹(workspace)->源文件空间文件夹(src)、编译空间文件夹(build)和开发空间文件夹(devel);

源文件空间文件夹再进一步放置功能包。

计算图级:主要是指进程之间(节点之间)的通信。ROS创建了一个连接所有进程的网络,通过这个网络节点之间完成交互,获取其他节点发布的信息。围绕计算图级和节点,一些重要的概念也随即产生:节点,节点管理器,参数服务器,消息,服务,主题(或称话题)和消息记录包,这些概念后面会逐一说明。

开源社区级:主要是指ROS资源的获取和分享。通过独立的网络社区,我们可以共享和获取知识、算法和代码,开源社区的大力支持使得ROS系统得以快速成长。


计算图级下的几个重要概念

节点:作为ROS系统的核心,节点是用C++或Python(ROS客户端库roscpp、rospy)编写的程序,用来执行任务或进程。

消息:节点之间通过消息进行通信,这些消息包含一个节点发送给其他节点的信息数据,消息类型有ROS标准类型和基于标准消息开发的自定义类型两种。

主题:有些书籍翻译为话题,指节点发布的消息的去处。节点每一条消息都要发布到主题,一个节点a发布信息数据,就说该节点a向主题发布消息。其他节点可以订阅这个节点a发布的主题,以此来接收a的消息。所以归根结底节点之间的通信,是主题之间的发布和订阅实现的,所以如果你在ROS下打开rqt_graph(一个ROS应用工具),会看到节点之间的通信机制是这样的:节点(主题)节点。蓝色和绿色为节点,中间横线上的/turtle1/cmd_vel是主题。

ROS开发日记(1)——ROS基础知识

当然,如果我们想查看主题的消息类型,可以使用命令行工具:rostopic type topicname;如果想看这个消息类型的内部结构,则可以使用:rosmsg show typename。节点通过主题与另一个节点通信是间接实现的,然而直接与节点通信不能使用主题实现,需要使用服务。

服务:名称唯一,由用户开发,节点不提供标准服务(因为你的节点本身是用客户端库编写的),如果你想获得某个节点的请求和应答,即直接与某个节点交互,只能使用服务。当然,这些服务是节点提供的服务,如果节点没有提供服务,我们就无法请求和获取应答。一个节点提供某个服务时,通过使用ROS客户端库编写的代码(节点)就可以与它通信。查看一个节点提供的服务可使用命令工具:rosnode info nodename,例如:rosnode info /turtlesim,输出的信息中,Services部分就是该节点具有的服务。

ROS开发日记(1)——ROS基础知识

直接与服务交互,可使用命令行工具:rosservice call servicename,例如:rosservice call /clear,此时小海龟的运动轨迹会被清除,当然前提是小海龟节点已经启动,并且小海龟已经有移动痕迹。

ROS开发日记(1)——ROS基础知识

ROS开发日记(1)——ROS基础知识

至此,几个基本的ROS概念我们已经有所了解。

参考:

https://mp.weixin.qq.com/s?__biz=MzA5MDE2MjQ0OQ==&mid=2652786427&idx=1&sn=ac4b9a890fec3d68773c6cb65ed86946&mpshare=1&scene=1&srcid=0326mGy0nXBqFqBWxQCeNv6B&pass_ticket=1eHBdZLk6YjR3YAN0wCTt5ZXh4HtyqvVaLglwMh4ZRmOyALdqcjLhuOqe%2BBWkmJm#rd 入门

https://blog.csdn.net/hcx25909/article/details/8811313 ROS新手教程