ros学习记录(1)——ROS概述与环境搭建

本篇重点在于学习过程记录,专业程度不高。

Posted by R on 2023-05-08

前言

目前机械臂开发进度陷入停滞期,很多问题开始暴露出来,这越发的让我感觉学习的不够深入。目前的机械臂通讯都是很浅显的基本应用,真正核心的部分比如运动规划、工作空间、碰撞检测等都没有触及,我顺着开发的方向一路摸索,最终走到了 ros 面前。最近都在捣鼓 ros 和它的环境,可以说进度十分缓慢,先是在公司一台电脑上配置了 Ubuntu 系统,之后经历了几次重装最终确定了ros 的学习方向,跟着教程(古月居入门21篇)学习了以后仍是一头雾水。感觉整个过程中处于一种十分浮躁的状态,总想着实现项目功能,并没有一个清晰的方案路线,于是决定一边学习一边进行记录,尽量把基础概念及工具内化以后再开始结合项目解决问题。

学习 ros 又是一个新的领域,包括 Linux 操作在内,各种指令都是第一次接触,我想尽可能详细的进行学习,文章中更多是对于别的教程的复刻和扩充,希望能够通过这种方式掌握 ros。

基本概念

Ubuntu 系统安装不作过多讲解,这方面的教程十分详细,并且没有太多学习的成分,只需要照搬操作即可。ros 环境的安装非常推荐鱼香的一键安装,简直太省事了,地址以及相关的一些教程资源如下:
鱼香一键安装:https://fishros.org.cn/forum/topic/20/%E5%B0%8F%E9%B1%BC%E7%9A%84%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85%E7%B3%BB%E5%88%97?lang=zh-CN
ROS 中文维基:http://wiki.ros.org/cn/ROS/Tutorials
赵虚左 ROS 教程:http://www.autolabor.com.cn/book/ROSTutorials/
古月居 ROS 教程:https://www.guyuehome.com/
创客智造 ROS 教程:https://www.ncnynl.com/
以上教程中最推荐的是赵虚左的教程,我也是打算跟着 b 站上的视频进行学习。

为了满足效率一些地方可能直接用截图或复制粘贴来说明,以下开始介绍 ros 基本概念。

定义及背景

ros,Robot Operating System,就是适用于机器人的开源元操作系统,ros 集成了大量的工具,库,协议,提供类似 OS(操作系统) 所提供的功能,简化对机器人的控制。要知道一个机器人设计包含了太多东西,从硬件到软件,从通讯到算法,几乎涵盖了工业体系的全部,因此没有任何个人、组织甚至公司能够独立完成系统性的机器人研发工作。一种更合适的策略是:让机器人研发者专注于自己擅长的领域,其他模块则直接复用相关领域更专业研发团队的实现,当然自身的研究也可以被他人继续复用。这样可以大大提高机器人的研发效率,尤其是随着机器人硬件越来越丰富,软件库越来越庞大,这种复用性和模块化开发需求也愈发强烈。

在上述背景下,于 2007 年,一家名为柳树车库(Willow Garage)的机器人公司发布了 ROS(机器人操作系统),ROS 是一套机器人通用软件框架,可以提升功能模块的复用性,并且随着该系统的不断迭代与完善,如今 ROS 已经成为机器人领域的事实标准。ROS 设计者将 ROS 表述为 “ROS = Plumbing + Tools + Capabilities + Ecosystem”,即 ROS 是通讯机制、工具软件包、机器人高层技能以及机器人生态系统的集合体

设计目标及发展例程

机器人开发的分工思想,实现了不同研发团队间的共享和协作,提升了机器人的研发效率,为了服务“ 分工”,ROS 主要设计目标为代码复用、分布式、松耦合等,其中我认为最能体现 ros 特色的就在于代码复用、分布式、松耦合。

ROS的发行版本(ROS distribution)指 ROS 软件包的版本,其与 Linux 的发行版本(如 Ubuntu)的概念类似。推出 ROS 发行版本的目的在于使开发人员可以使用相对稳定的代码库,直到其准备好将所有内容进行版本升级为止。因此,每个发行版本推出后,ROS 开发者通常仅对这一版本的 bug 进行修复,同时提供少量针对核心软件包的改进。
版本特点: 按照英文字母顺序命名,ROS 目前已经发布了 ROS1 的终极版本: noetic,并建议后期过渡至 ROS2 版本。noetic 版本之前默认使用的是 Python2,noetic 支持 Python3。

ros 第一步

ros 的安装前面有提到,这里就不过多讲述,安装完成后可以通过运行小程序进行测试,启动三个命令行窗口:

  • 命令行1键入:roscore(roscore 是节点和程序的集合,这些节点和程序是基于 ROS 的系统所必需的,于是可以称为 ros 核心 core 服务即名字。必须运行 roscore 才能使 ROS 节点进行通信。刚开始可以把它理解为 ros 的后台,有了它才可以使用 ros。)
  • 命令行2键入:rosrun turtlesim turtlesim_node(此时会弹出图形化界面)
  • 命令行3键入:rosrun turtlesim turtle_teleop_key(在3中可以通过上下左右控制2中乌龟的运动,注意必须是在命令行窗口3中进行键入)

接下来进行所有代码的第一步:输出 hello world。ROS 中涉及的编程语言以 C++ 和 Python 为主,ROS 中的大多数程序两者都可以实现,我根据项目需求以 python 为方案进行学习。

ROS中的程序即便使用不同的编程语言,实现流程也大致类似,以当前HelloWorld程序为例,实现流程大致如下:
1.先创建一个工作空间
2.再创建一个功能包
3.编辑源文件
4.编辑配置文件
5.编译并执行
上述流程中,C++和Python只是在步骤3和步骤4的实现细节上存在差异,其他流程基本一致。接下来可以先跟着指令实现功能,之后会回过头来进行详细的讲解各个文件的作用。

1.创建工作空间并初始化

1
2
3
mkdir -p 自定义空间名称/src
cd 自定义空间名称
catkin_make

上述命令,首先会创建一个工作空间以及一个 src 子目录,然后再进入工作空间调用 catkin_make 命令编译。

2.进入 src 创建 ros 包并添加依赖

1
2
cd src
catkin_create_pkg 自定义ROS包名 roscpp rospy std_msgs

上述命令,会在工作空间下生成一个功能包,该功能包依赖于 roscpp、rospy 与 std_msgs,其中 roscpp 是使用 C++ 实现的库,而 rospy 则是使用 python 实现的库,std_msgs 是标准消息库,创建 ROS 功能包时,一般都会依赖这三个库实现。
注意:在 ROS 中,虽然实现同一功能时,C++ 和 Python 可以互换,但是具体选择哪种语言,需要视需求而定,因为两种语言相较而言:C++ 运行效率高但是编码效率低,而 Python 则反之,基于二者互补的特点,ROS 设计者分别设计了 roscpp 与 rospy 库,前者旨在成为 ROS 的高性能库,而后者则一般用于对性能无要求的场景,旨在提高开发效率。

3.进入 ros 包添加 scripts 目录并编辑 python 文件

1
2
cd ros包
mkdir scripts

在 scripts 下新建 python 文件(自定义名字),命令台新建指令为 touch xxx.py

1
2
3
4
5
6
7
8
9
10
11
#! /usr/bin/env python

"""
Python 版 HelloWorld

"""
import rospy

if __name__ == "__main__":
rospy.init_node("Hello")
rospy.loginfo("Hello World!!!!")

4.为 python 文件添加可执行权限

1
chmod +x 自定义文件名.py

5.编辑 ros 包下的 CamkeList.txt 文件

注意:是编辑 txt 文件,不是写入控制条指令

1
2
3
catkin_install_python(PROGRAMS scripts/自定义文件名.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

6.进入工作空间目录并编译

1
2
cd 自定义空间名称
catkin_make

7.进入工作空间目录并执行

启动命令行窗口 1,执行 roscore 开启节点通信。再启动命令行窗口 2,执行下述指令:

1
2
3
cd 工作空间
source ./devel/setup.bash
rosrun 包名 自定义文件名.py

得到输出结果:hello,world!

架构讲解

到目前为止,我们已经安装了 ROS,运行了 ROS 中内置的小乌龟案例,并且也编写了 ROS 小程序,对 ROS 也有了一个大概的认知,当然这个认知可能还是比较模糊并不清晰的,接下来,我们要从宏观上来介绍一下 ROS 的架构设计。

架构类型

立足不同的角度,对ROS架构的描述也是不同的,一般我们可以从设计者、维护者、系统结构与自身结构4个角度来描述ROS结构(重点放在系统结构和自身结构两方面):

  • 设计者:
    ROS设计者将ROS表述为“ROS = Plumbing + Tools + Capabilities + Ecosystem”
      * Plumbing: 通讯机制(实现ROS不同节点之间的交互)
      * Tools :工具软件包(ROS中的开发和调试工具)
      * Capabilities :机器人高层技能(ROS中某些功能的集合,比如:导航)
      * Ecosystem:机器人生态系统(跨地域、跨软件与硬件的ROS联盟)
    
  • 维护者:
    立足维护者的角度: ROS 架构可划分为两大部分
      * main:核心部分,主要由Willow Garage 和一些开发者设计、提供以及维护。它提供了一些分布式计算的基本工具,以及整个ROS的核心部分的程序编写。
      * universe:全球范围的代码,有不同国家的ROS社区组织开发和维护。一种是库的代码,如OpenCV、PCL等;库的上一层是从功能角度提供的代码,如人脸识别,他们调用下层的库;最上层的代码是应用级的代码,让机器人完成某一确定的功能。
    
  • 系统结构:
    立足系统架构: ROS 可以划分为三层
      * OS 层,也即经典意义的操作系统,ROS 只是元操作系统,需要依托真正意义的操作系统,目前兼容性最好的是 Linux 的 Ubuntu,Mac、Windows 也支持 ROS 的较新版本。
      * 中间层,是 ROS 封装的关于机器人开发的中间件,比如:
          * 基于 TCP/UDP 继续封装的 TCPROS/UDPROS 通信系统
          * 用于进程间通信 Nodelet,为数据的实时性传输提供支持
          * 另外,还提供了大量的机器人开发实现库,如:数据类型定义、坐标变换、运动控制....
      * 应用层,功能包,以及功能包内的节点,比如: master、turtlesim的控制与运动节点...
    
  • 自身结构:
    就 ROS 自身实现而言: 也可以划分为三层
      * 文件系统:ROS文件系统级指的是在硬盘上面查看的ROS源代码的组织形式
      * 计算图:ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程,计算图中的重要概念: 节点(Node)、消息(message)、通信机制_主题(topic)、通信机制_服务(service)
      * 开源社区:ROS的社区级概念是ROS网络上进行代码发布的一种表现形式
    

现在处于学习的初级阶段,只是运行了ROS的内置案例,编写了简单的ROS实现,因此,受限于当前进度,不会详细介绍所有设计架构中的所有模块,当前只介绍文件系统与计算图,下一章会介绍 ROS 的通信机制,这也是ROS的核心实现之一。

ROS文件系统

ROS文件系统级指的是在硬盘上ROS源代码的组织形式,其结构大致可以如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
WorkSpace --- 自定义的工作空间

|--- build:编译空间,用于存放CMake和catkin的缓存信息、配置信息和其他中间文件。

|--- devel:开发空间,用于存放编译后生成的目标文件,包括头文件、动态&静态链接库、可执行文件等。

|--- src: 源码

|-- package:功能包(ROS基本单元)包含多个节点、库与配置文件,包名所有字母小写,只能由字母、数字与下划线组成

|-- CMakeLists.txt 配置编译规则,比如源文件、依赖项、目标文件

|-- package.xml 包信息,比如:包名、版本、作者、依赖项...(以前版本是 manifest.xml)

|-- scripts 存储python文件

|-- src 存储C++源文件

|-- include 头文件

|-- msg 消息通信格式文件

|-- srv 服务通信格式文件

|-- action 动作格式文件

|-- launch 可一次性运行多个节点

|-- config 配置信息

|-- CMakeLists.txt: 编译的基本配置

在刚才的基本实现中,我们定义了工作空间,进行了编译,并且在源码中定义了一个功能包和相应的python文件,通过CMakeLists.txt进行编译配置,最后重新编译实现基本功能。这便是 ros 开发过程中一个最最基本的流程,当然要使用 ros 的特性这还远远不够,随着后面功能的相继展开会再行介绍其他目录下的内容,当前我们主要介绍: package.xml 与 CMakeLists.txt 这两个配置文件。

  • package.xml
    该文件定义有关软件包的属性,例如软件包名称,版本号,作者,维护者以及对其他catkin软件包的依赖性。请注意,该概念类似于旧版 rosbuild 构建系统中使用的 manifest.xml 文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    <?xml version="1.0"?>
    <!-- 格式: 以前是 1,推荐使用格式 2 -->
    <package format="2">
    <!-- 包名 -->
    <name>demo01_hello_vscode</name>
    <!-- 版本 -->
    <version>0.0.0</version>
    <!-- 描述信息 -->
    <description>The demo01_hello_vscode package</description>

    <!-- One maintainer tag required, multiple allowed, one person per tag -->
    <!-- Example: -->
    <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
    <!-- 维护人员 -->
    <maintainer email="xuzuo@todo.todo">xuzuo</maintainer>


    <!-- One license tag required, multiple allowed, one license per tag -->
    <!-- Commonly used license strings: -->
    <!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
    <!-- 许可证信息,ROS核心组件默认 BSD -->
    <license>TODO</license>


    <!-- Url tags are optional, but multiple are allowed, one per tag -->
    <!-- Optional attribute type can be: website, bugtracker, or repository -->
    <!-- Example: -->
    <!-- <url type="website">http://wiki.ros.org/demo01_hello_vscode</url> -->


    <!-- Author tags are optional, multiple are allowed, one per tag -->
    <!-- Authors do not have to be maintainers, but could be -->
    <!-- Example: -->
    <!-- <author email="jane.doe@example.com">Jane Doe</author> -->


    <!-- The *depend tags are used to specify dependencies -->
    <!-- Dependencies can be catkin packages or system dependencies -->
    <!-- Examples: -->
    <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
    <!-- <depend>roscpp</depend> -->
    <!-- Note that this is equivalent to the following: -->
    <!-- <build_depend>roscpp</build_depend> -->
    <!-- <exec_depend>roscpp</exec_depend> -->
    <!-- Use build_depend for packages you need at compile time: -->
    <!-- <build_depend>message_generation</build_depend> -->
    <!-- Use build_export_depend for packages you need in order to build against this package: -->
    <!-- <build_export_depend>message_generation</build_export_depend> -->
    <!-- Use buildtool_depend for build tool packages: -->
    <!-- <buildtool_depend>catkin</buildtool_depend> -->
    <!-- Use exec_depend for packages you need at runtime: -->
    <!-- <exec_depend>message_runtime</exec_depend> -->
    <!-- Use test_depend for packages you need only for testing: -->
    <!-- <test_depend>gtest</test_depend> -->
    <!-- Use doc_depend for packages you need only for building documentation: -->
    <!-- <doc_depend>doxygen</doc_depend> -->
    <!-- 依赖的构建工具,这是必须的 -->
    <buildtool_depend>catkin</buildtool_depend>

    <!-- 指定构建此软件包所需的软件包 -->
    <build_depend>roscpp</build_depend>
    <build_depend>rospy</build_depend>
    <build_depend>std_msgs</build_depend>

    <!-- 指定根据这个包构建库所需要的包 -->
    <build_export_depend>roscpp</build_export_depend>
    <build_export_depend>rospy</build_export_depend>
    <build_export_depend>std_msgs</build_export_depend>

    <!-- 运行该程序包中的代码所需的程序包 -->
    <exec_depend>roscpp</exec_depend>
    <exec_depend>rospy</exec_depend>
    <exec_depend>std_msgs</exec_depend>


    <!-- The export tag contains other, unspecified, tags -->
    <export>
    <!-- Other tools can request additional information be placed here -->

    </export>
    </package>
  • CMakelists.txt
    文件CMakeLists.txt是CMake构建系统的输入,用于构建软件包。刚刚的案例中也对其进行了编辑,编译代码时这个文件时必须要进行相关信息修改的,任何兼容CMake的软件包都包含一个或多个CMakeLists.txt文件,这些文件描述了如何构建代码以及将代码安装到何处。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    ​cmake_minimum_required(VERSION 3.0.2) #所需 cmake 版本
    project(demo01_hello_vscode) #包名称,会被 ${PROJECT_NAME} 的方式调用

    ## Compile as C++11, supported in ROS Kinetic and newer
    # add_compile_options(-std=c++11)

    ## Find catkin macros and libraries
    ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
    ## is used, also find other catkin packages
    #设置构建所需要的软件包
    find_package(catkin REQUIRED COMPONENTS
    roscpp
    rospy
    std_msgs
    )

    ## System dependencies are found with CMake's conventions
    #默认添加系统依赖
    # find_package(Boost REQUIRED COMPONENTS system)


    ## Uncomment this if the package has a setup.py. This macro ensures
    ## modules and global scripts declared therein get installed
    ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
    # 启动 python 模块支持
    # catkin_python_setup()

    ################################################
    ## Declare ROS messages, services and actions ##
    ## 声明 ROS 消息、服务、动作... ##
    ################################################

    ## To declare and build messages, services or actions from within this
    ## package, follow these steps:
    ## * Let MSG_DEP_SET be the set of packages whose message types you use in
    ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
    ## * In the file package.xml:
    ## * add a build_depend tag for "message_generation"
    ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
    ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
    ## but can be declared for certainty nonetheless:
    ## * add a exec_depend tag for "message_runtime"
    ## * In this file (CMakeLists.txt):
    ## * add "message_generation" and every package in MSG_DEP_SET to
    ## find_package(catkin REQUIRED COMPONENTS ...)
    ## * add "message_runtime" and every package in MSG_DEP_SET to
    ## catkin_package(CATKIN_DEPENDS ...)
    ## * uncomment the add_*_files sections below as needed
    ## and list every .msg/.srv/.action file to be processed
    ## * uncomment the generate_messages entry below
    ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)

    ## Generate messages in the 'msg' folder
    # add_message_files(
    # FILES
    # Message1.msg
    # Message2.msg
    # )

    ## Generate services in the 'srv' folder
    # add_service_files(
    # FILES
    # Service1.srv
    # Service2.srv
    # )

    ## Generate actions in the 'action' folder
    # add_action_files(
    # FILES
    # Action1.action
    # Action2.action
    # )

    ## Generate added messages and services with any dependencies listed here
    # 生成消息、服务时的依赖包
    # generate_messages(
    # DEPENDENCIES
    # std_msgs
    # )

    ################################################
    ## Declare ROS dynamic reconfigure parameters ##
    ## 声明 ROS 动态参数配置 ##
    ################################################

    ## To declare and build dynamic reconfigure parameters within this
    ## package, follow these steps:
    ## * In the file package.xml:
    ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
    ## * In this file (CMakeLists.txt):
    ## * add "dynamic_reconfigure" to
    ## find_package(catkin REQUIRED COMPONENTS ...)
    ## * uncomment the "generate_dynamic_reconfigure_options" section below
    ## and list every .cfg file to be processed

    ## Generate dynamic reconfigure parameters in the 'cfg' folder
    # generate_dynamic_reconfigure_options(
    # cfg/DynReconf1.cfg
    # cfg/DynReconf2.cfg
    # )

    ###################################
    ## catkin specific configuration ##
    ## catkin 特定配置##
    ###################################
    ## The catkin_package macro generates cmake config files for your package
    ## Declare things to be passed to dependent projects
    ## INCLUDE_DIRS: uncomment this if your package contains header files
    ## LIBRARIES: libraries you create in this project that dependent projects also need
    ## CATKIN_DEPENDS: catkin_packages dependent projects also need
    ## DEPENDS: system dependencies of this project that dependent projects also need
    # 运行时依赖
    catkin_package(
    # INCLUDE_DIRS include
    # LIBRARIES demo01_hello_vscode
    # CATKIN_DEPENDS roscpp rospy std_msgs
    # DEPENDS system_lib
    )

    ###########
    ## Build ##
    ###########

    ## Specify additional locations of header files
    ## Your package locations should be listed before other locations
    # 添加头文件路径,当前程序包的头文件路径位于其他文件路径之前
    include_directories(
    # include
    ${catkin_INCLUDE_DIRS}
    )

    ## Declare a C++ library
    # 声明 C++ 库
    # add_library(${PROJECT_NAME}
    # src/${PROJECT_NAME}/demo01_hello_vscode.cpp
    # )

    ## Add cmake target dependencies of the library
    ## as an example, code may need to be generated before libraries
    ## either from message generation or dynamic reconfigure
    # 添加库的 cmake 目标依赖
    # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

    ## Declare a C++ executable
    ## With catkin_make all packages are built within a single CMake context
    ## The recommended prefix ensures that target names across packages don't collide
    # 声明 C++ 可执行文件
    add_executable(Hello_VSCode src/Hello_VSCode.cpp)

    ## Rename C++ executable without prefix
    ## The above recommended prefix causes long target names, the following renames the
    ## target back to the shorter version for ease of user use
    ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
    #重命名c++可执行文件
    # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

    ## Add cmake target dependencies of the executable
    ## same as for the library above
    #添加可执行文件的 cmake 目标依赖
    add_dependencies(Hello_VSCode ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

    ## Specify libraries to link a library or executable target against
    #指定库、可执行文件的链接库
    target_link_libraries(Hello_VSCode
    ${catkin_LIBRARIES}
    )

    #############
    ## Install ##
    ## 安装 ##
    #############

    # all install targets should use catkin DESTINATION variables
    # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html

    ## Mark executable scripts (Python etc.) for installation
    ## in contrast to setup.py, you can choose the destination
    #设置用于安装的可执行脚本
    catkin_install_python(PROGRAMS
    scripts/Hi.py
    DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )

    ## Mark executables for installation
    ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
    # install(TARGETS ${PROJECT_NAME}_node
    # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    # )

    ## Mark libraries for installation
    ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
    # install(TARGETS ${PROJECT_NAME}
    # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
    # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
    # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
    # )

    ## Mark cpp header files for installation
    # install(DIRECTORY include/${PROJECT_NAME}/
    # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
    # FILES_MATCHING PATTERN "*.h"
    # PATTERN ".svn" EXCLUDE
    # )

    ## Mark other files for installation (e.g. launch and bag files, etc.)
    # install(FILES
    # # myfile1
    # # myfile2
    # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
    # )

    #############
    ## Testing ##
    #############

    ## Add gtest based cpp test target and link libraries
    # catkin_add_gtest(${PROJECT_NAME}-test test/test_demo01_hello_vscode.cpp)
    # if(TARGET ${PROJECT_NAME}-test)
    # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
    # endif()

    ## Add folders to be run by python nosetests
    # catkin_add_nosetests(test)

ROS文件系统相关命令

ROS 的文件系统本质上都还是操作系统文件,我们可以使用Linux命令来操作这些文件,不过,在ROS中为了更好的用户体验,ROS专门提供了一些类似于Linux的命令,这些命令较之于Linux原生命令,更为简介、高效。文件操作,无外乎就是增删改查与执行等操作,接下来,我们就从这五个维度,来介绍ROS文件系统的一些常用命令。


  • catkin_create_pkg 自定义包名 依赖包 === 创建新的ROS功能包
    sudo apt install xxx === 安装 ROS功能包

  • sudo apt purge xxx ==== 删除某个功能包

  • rospack list === 列出所有功能包
    rospack find 包名 === 查找某个功能包是否存在,如果存在返回安装路径
    roscd 包名 === 进入某个功能包
    rosls 包名 === 列出某个包下的文件
    apt search xxx === 搜索某个功能包

  • rosed 包名 文件名 === 修改功能包文件
    需要安装 vim
    比如:rosed turtlesim Color.msg
  • 执行
    • roscore
      roscore === 是 ROS 的系统先决条件节点和程序的集合, 必须运行 roscore 才能使 ROS 节点进行通信。
      roscore 将启动:ros master、ros 参数服务器、rosout 日志节点
    • rosrun
      rosrun 包名 可执行文件名 === 运行指定的ROS节点
      比如:rosrun turtlesim turtlesim_node
    • roslaunch
      roslaunch 包名 launch文件名 === 执行某个包下的 launch 文件

ROS计算图

前面介绍的是ROS文件结构,是磁盘上 ROS 程序的存储结构,是静态的,而 ros 程序运行之后,不同的节点之间是错综复杂的,ROS 中提供了一个实用的工具:rqt_graph。

rqt_graph能够创建一个显示当前系统运行情况的动态图形。ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程。rqt_graph是rqt程序包中的一部分。

  • 计算图安装
    如果前期把所有的功能包(package)都已经安装完成,则直接在终端窗口中输入 rosrun rqt_graph rqt_graph
    如果未安装则在终端(terminal)中输入:
    1
    2
    $ sudo apt install ros-<distro>-rqt
    $ sudo apt install ros-<distro>-rqt-common-plugins
    请使用你的ROS版本名称(比如:kinetic、melodic、Noetic等)来替换掉
    例如当前版本是 Noetic,就在终端窗口中输入
    1
    2
    $ sudo apt install ros-noetic-rqt
    $ sudo apt install ros-noetic-rqt-common-plugins
  • 计算图演示
    接下来以 ROS 内置的小乌龟案例来演示计算图
    首先,按照前面所示,运行案例
    然后,启动新终端,键入: rqt_graph 或 rosrun rqt_graph rqt_graph,可以看到类似下图的网络拓扑图,该图可以显示不同节点之间的关系。

集成开发环境

  • 安装终端
    在 ROS 中,需要频繁的使用到终端,且可能需要同时开启多个窗口,推荐一款较为好用的终端:Terminator。效果如下:

    运行指令sudo apt install terminator安装
    快捷键如下所示:

  • vscode安装
    具体安装过程不作记录,直接进入官网即可下载安装。此处记录常用于开发ros的插件:
    • 先创建工作空间
      1
      2
      3
      mkdir -p xxx_ws/src(必须得有 src)
      cd xxx_ws
      catkin_make
    • 启动vscode
      1
      2
      cd xxx_ws
      code .
    • vscode 中编译 ros
      快捷键 ctrl + shift + B 调用编译,选择:catkin_make:build
      可以点击配置设置为默认,修改.vscode/tasks.json 文件
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      {
      // 有关 tasks.json 格式的文档,请参见
      // https://go.microsoft.com/fwlink/?LinkId=733558
      "version": "2.0.0",
      "tasks": [
      {
      "label": "catkin_make:debug", //代表提示的描述性信息
      "type": "shell", //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
      "command": "catkin_make",//这个是我们需要运行的命令
      "args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
      "group": {"kind":"build","isDefault":true},
      "presentation": {
      "reveal": "always"//可选always或者silence,代表是否输出信息
      },
      "problemMatcher": "$msCompile"
      }
      ]
      }
    • 创建 ROS 功能包
      选定 src 右击 —-> create catkin package ||设置包名 添加依赖
    • python 实现
      在 功能包 下新建 scripts 文件夹,添加 python 文件,并添加可执行权限
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      #! /usr/bin/env python
      """
      Python 版本的 HelloVScode,执行在控制台输出 HelloVScode
      实现:
      1.导包
      2.初始化 ROS 节点
      3.日志输出 HelloWorld
      """
      import rospy # 1.导包

      if __name__ == "__main__":

      rospy.init_node("Hello_Vscode_p") # 2.初始化 ROS 节点
      rospy.loginfo("Hello VScode, 我是 Python ....") #3.日志输出 HelloWorld
    • 配置 CMakeLists.txt
      1
      2
      3
      catkin_install_python(PROGRAMS scripts/自定义文件名.py
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
      )
    • 编译执行
      编译: ctrl + shift + B
      执行: 和之前一致,只是可以在 VScode 中添加终端,首先执行:source ./devel/setup.bash
      如果不编译直接执行 python 文件,会抛出异常。
      1.第一行解释器声明,可以使用绝对路径定位到 python3 的安装路径 #! /usr/bin/python3,但是不建议
      2.建议使用 #!/usr/bin/env python 但是会抛出异常 : /usr/bin/env: “python”: 没有那个文件或目录
      3.解决1: #!/usr/bin/env python3 直接使用 python3 但存在问题: 不兼容之前的 ROS 相关 python 实现
      4.解决2: 创建一个链接符号到 python 命令:sudo ln -s /usr/bin/python3 /usr/bin/python
  • launch文件
    • 需求
      一个程序中可能需要启动多个节点,比如:ROS 内置的小乌龟案例,如果要控制乌龟运动,要启动多个窗口,分别启动 roscore、乌龟界面节点、键盘控制节点。如果每次都调用 rosrun 逐一启动,显然效率低下,如何优化?
      launch文件就是为解决这个问题产生的,可以一次性生成大量节点。
    • 实现
      • 选定功能包右击 —-> 添加 launch 文件夹
      • 选定 launch 文件夹右击 —-> 添加 launch 文件
      • 编辑 launch 文件内容
        1
        2
        3
        4
        5
        <launch>
        <node pkg="helloworld" type="demo_hello" name="hello" output="screen" />
        <node pkg="turtlesim" type="turtlesim_node" name="t1"/>
        <node pkg="turtlesim" type="turtle_teleop_key" name="key1" />
        </launch>
        其中,node 表示包含的某个节点,pkg 表示功能包,type 表示被运行的节点文件,name 为节点名字,output 为设置日志的输出目标
      • 运行 launch 文件
        roslaunch 包名 launch文件名

结语、补充

文中大量提到的节点便是 ROS 的一大关键所在,相当于一个功能就是一个节点,不同的节点直接会有数据交互,具体的交互方式类似于 mqtt 的订阅发布。上述内容涵盖的点很广,重点需要搞清楚的是基本的架构以及相关命令操作,知道哪个文件夹放着什么文件,怎样操作这些文件即可。而节点等问题后续会开始正式的接触,这里只是相当于一个引子。## 前言

目前机械臂开发进度陷入停滞期,很多问题开始暴露出来,这越发的让我感觉学习的不够深入。目前的机械臂通讯都是很浅显的基本应用,真正核心的部分比如运动规划、工作空间、碰撞检测等都没有触及,我顺着开发的方向一路摸索,最终走到了 ros 面前。最近都在捣鼓 ros 和它的环境,可以说进度十分缓慢,先是在公司一台电脑上配置了 Ubuntu 系统,之后经历了几次重装最终确定了ros 的学习方向,跟着教程(古月居入门21篇)学习了以后仍是一头雾水。感觉整个过程中处于一种十分浮躁的状态,总想着实现项目功能,并没有一个清晰的方案路线,于是决定一边学习一边进行记录,尽量把基础概念及工具内化以后再开始结合项目解决问题。

学习 ros 又是一个新的领域,包括 Linux 操作在内,各种指令都是第一次接触,我想尽可能详细的进行学习,文章中更多是对于别的教程的复刻和扩充,希望能够通过这种方式掌握 ros。

基本概念

Ubuntu 系统安装不作过多讲解,这方面的教程十分详细,并且没有太多学习的成分,只需要照搬操作即可。ros 环境的安装非常推荐鱼香的一键安装,简直太省事了,地址以及相关的一些教程资源如下:
鱼香一键安装:https://fishros.org.cn/forum/topic/20/%E5%B0%8F%E9%B1%BC%E7%9A%84%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85%E7%B3%BB%E5%88%97?lang=zh-CN
ROS 中文维基:http://wiki.ros.org/cn/ROS/Tutorials
赵虚左 ROS 教程:http://www.autolabor.com.cn/book/ROSTutorials/
古月居 ROS 教程:https://www.guyuehome.com/
创客智造 ROS 教程:https://www.ncnynl.com/
以上教程中最推荐的是赵虚左的教程,我也是打算跟着 b 站上的视频进行学习。

为了满足效率一些地方可能直接用截图或复制粘贴来说明,以下开始介绍 ros 基本概念。

定义及背景

ros,Robot Operating System,就是适用于机器人的开源元操作系统,ros 集成了大量的工具,库,协议,提供类似 OS(操作系统) 所提供的功能,简化对机器人的控制。要知道一个机器人设计包含了太多东西,从硬件到软件,从通讯到算法,几乎涵盖了工业体系的全部,因此没有任何个人、组织甚至公司能够独立完成系统性的机器人研发工作。一种更合适的策略是:让机器人研发者专注于自己擅长的领域,其他模块则直接复用相关领域更专业研发团队的实现,当然自身的研究也可以被他人继续复用。这样可以大大提高机器人的研发效率,尤其是随着机器人硬件越来越丰富,软件库越来越庞大,这种复用性和模块化开发需求也愈发强烈。

在上述背景下,于 2007 年,一家名为柳树车库(Willow Garage)的机器人公司发布了 ROS(机器人操作系统),ROS 是一套机器人通用软件框架,可以提升功能模块的复用性,并且随着该系统的不断迭代与完善,如今 ROS 已经成为机器人领域的事实标准。ROS 设计者将 ROS 表述为 “ROS = Plumbing + Tools + Capabilities + Ecosystem”,即 ROS 是通讯机制、工具软件包、机器人高层技能以及机器人生态系统的集合体

设计目标及发展例程

机器人开发的分工思想,实现了不同研发团队间的共享和协作,提升了机器人的研发效率,为了服务“ 分工”,ROS 主要设计目标为代码复用、分布式、松耦合等,其中我认为最能体现 ros 特色的就在于代码复用、分布式、松耦合。

ROS的发行版本(ROS distribution)指 ROS 软件包的版本,其与 Linux 的发行版本(如 Ubuntu)的概念类似。推出 ROS 发行版本的目的在于使开发人员可以使用相对稳定的代码库,直到其准备好将所有内容进行版本升级为止。因此,每个发行版本推出后,ROS 开发者通常仅对这一版本的 bug 进行修复,同时提供少量针对核心软件包的改进。
版本特点: 按照英文字母顺序命名,ROS 目前已经发布了 ROS1 的终极版本: noetic,并建议后期过渡至 ROS2 版本。noetic 版本之前默认使用的是 Python2,noetic 支持 Python3。

ros 第一步

ros 的安装前面有提到,这里就不过多讲述,安装完成后可以通过运行小程序进行测试,启动三个命令行窗口:

  • 命令行1键入:roscore(roscore 是节点和程序的集合,这些节点和程序是基于 ROS 的系统所必需的,于是可以称为 ros 核心 core 服务即名字。必须运行 roscore 才能使 ROS 节点进行通信。刚开始可以把它理解为 ros 的后台,有了它才可以使用 ros。)
  • 命令行2键入:rosrun turtlesim turtlesim_node(此时会弹出图形化界面)
  • 命令行3键入:rosrun turtlesim turtle_teleop_key(在3中可以通过上下左右控制2中乌龟的运动,注意必须是在命令行窗口3中进行键入)

接下来进行所有代码的第一步:输出 hello world。ROS 中涉及的编程语言以 C++ 和 Python 为主,ROS 中的大多数程序两者都可以实现,我根据项目需求以 python 为方案进行学习。

ROS中的程序即便使用不同的编程语言,实现流程也大致类似,以当前HelloWorld程序为例,实现流程大致如下:
1.先创建一个工作空间
2.再创建一个功能包
3.编辑源文件
4.编辑配置文件
5.编译并执行
上述流程中,C++和Python只是在步骤3和步骤4的实现细节上存在差异,其他流程基本一致。接下来可以先跟着指令实现功能,之后会回过头来进行详细的讲解各个文件的作用。

1.创建工作空间并初始化

1
2
3
mkdir -p 自定义空间名称/src
cd 自定义空间名称
catkin_make

上述命令,首先会创建一个工作空间以及一个 src 子目录,然后再进入工作空间调用 catkin_make 命令编译。

2.进入 src 创建 ros 包并添加依赖

1
2
cd src
catkin_create_pkg 自定义ROS包名 roscpp rospy std_msgs

上述命令,会在工作空间下生成一个功能包,该功能包依赖于 roscpp、rospy 与 std_msgs,其中 roscpp 是使用 C++ 实现的库,而 rospy 则是使用 python 实现的库,std_msgs 是标准消息库,创建 ROS 功能包时,一般都会依赖这三个库实现。
注意:在 ROS 中,虽然实现同一功能时,C++ 和 Python 可以互换,但是具体选择哪种语言,需要视需求而定,因为两种语言相较而言:C++ 运行效率高但是编码效率低,而 Python 则反之,基于二者互补的特点,ROS 设计者分别设计了 roscpp 与 rospy 库,前者旨在成为 ROS 的高性能库,而后者则一般用于对性能无要求的场景,旨在提高开发效率。

3.进入 ros 包添加 scripts 目录并编辑 python 文件

1
2
cd ros包
mkdir scripts

在 scripts 下新建 python 文件(自定义名字),命令台新建指令为 touch xxx.py

1
2
3
4
5
6
7
8
9
10
11
#! /usr/bin/env python

"""
Python 版 HelloWorld

"""
import rospy

if __name__ == "__main__":
rospy.init_node("Hello")
rospy.loginfo("Hello World!!!!")

4.为 python 文件添加可执行权限

1
chmod +x 自定义文件名.py

5.编辑 ros 包下的 CamkeList.txt 文件

注意:是编辑 txt 文件,不是写入控制条指令

1
2
3
catkin_install_python(PROGRAMS scripts/自定义文件名.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

6.进入工作空间目录并编译

1
2
cd 自定义空间名称
catkin_make

7.进入工作空间目录并执行

启动命令行窗口 1,执行 roscore 开启节点通信。再启动命令行窗口 2,执行下述指令:

1
2
3
cd 工作空间
source ./devel/setup.bash
rosrun 包名 自定义文件名.py

得到输出结果:hello,world!

架构讲解

到目前为止,我们已经安装了 ROS,运行了 ROS 中内置的小乌龟案例,并且也编写了 ROS 小程序,对 ROS 也有了一个大概的认知,当然这个认知可能还是比较模糊并不清晰的,接下来,我们要从宏观上来介绍一下 ROS 的架构设计。

架构类型

立足不同的角度,对ROS架构的描述也是不同的,一般我们可以从设计者、维护者、系统结构与自身结构4个角度来描述ROS结构(重点放在系统结构和自身结构两方面):

  • 设计者:
    ROS设计者将ROS表述为“ROS = Plumbing + Tools + Capabilities + Ecosystem”
      * Plumbing: 通讯机制(实现ROS不同节点之间的交互)
      * Tools :工具软件包(ROS中的开发和调试工具)
      * Capabilities :机器人高层技能(ROS中某些功能的集合,比如:导航)
      * Ecosystem:机器人生态系统(跨地域、跨软件与硬件的ROS联盟)
    
  • 维护者:
    立足维护者的角度: ROS 架构可划分为两大部分
      * main:核心部分,主要由Willow Garage 和一些开发者设计、提供以及维护。它提供了一些分布式计算的基本工具,以及整个ROS的核心部分的程序编写。
      * universe:全球范围的代码,有不同国家的ROS社区组织开发和维护。一种是库的代码,如OpenCV、PCL等;库的上一层是从功能角度提供的代码,如人脸识别,他们调用下层的库;最上层的代码是应用级的代码,让机器人完成某一确定的功能。
    
  • 系统结构:
    立足系统架构: ROS 可以划分为三层
      * OS 层,也即经典意义的操作系统,ROS 只是元操作系统,需要依托真正意义的操作系统,目前兼容性最好的是 Linux 的 Ubuntu,Mac、Windows 也支持 ROS 的较新版本。
      * 中间层,是 ROS 封装的关于机器人开发的中间件,比如:
          * 基于 TCP/UDP 继续封装的 TCPROS/UDPROS 通信系统
          * 用于进程间通信 Nodelet,为数据的实时性传输提供支持
          * 另外,还提供了大量的机器人开发实现库,如:数据类型定义、坐标变换、运动控制....
      * 应用层,功能包,以及功能包内的节点,比如: master、turtlesim的控制与运动节点...
    
  • 自身结构:
    就 ROS 自身实现而言: 也可以划分为三层
      * 文件系统:ROS文件系统级指的是在硬盘上面查看的ROS源代码的组织形式
      * 计算图:ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程,计算图中的重要概念: 节点(Node)、消息(message)、通信机制_主题(topic)、通信机制_服务(service)
      * 开源社区:ROS的社区级概念是ROS网络上进行代码发布的一种表现形式
    

现在处于学习的初级阶段,只是运行了ROS的内置案例,编写了简单的ROS实现,因此,受限于当前进度,不会详细介绍所有设计架构中的所有模块,当前只介绍文件系统与计算图,下一章会介绍 ROS 的通信机制,这也是ROS的核心实现之一。

ROS文件系统

ROS文件系统级指的是在硬盘上ROS源代码的组织形式,其结构大致可以如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
WorkSpace --- 自定义的工作空间

|--- build:编译空间,用于存放CMake和catkin的缓存信息、配置信息和其他中间文件。

|--- devel:开发空间,用于存放编译后生成的目标文件,包括头文件、动态&静态链接库、可执行文件等。

|--- src: 源码

|-- package:功能包(ROS基本单元)包含多个节点、库与配置文件,包名所有字母小写,只能由字母、数字与下划线组成

|-- CMakeLists.txt 配置编译规则,比如源文件、依赖项、目标文件

|-- package.xml 包信息,比如:包名、版本、作者、依赖项...(以前版本是 manifest.xml)

|-- scripts 存储python文件

|-- src 存储C++源文件

|-- include 头文件

|-- msg 消息通信格式文件

|-- srv 服务通信格式文件

|-- action 动作格式文件

|-- launch 可一次性运行多个节点

|-- config 配置信息

|-- CMakeLists.txt: 编译的基本配置

在刚才的基本实现中,我们定义了工作空间,进行了编译,并且在源码中定义了一个功能包和相应的python文件,通过CMakeLists.txt进行编译配置,最后重新编译实现基本功能。这便是 ros 开发过程中一个最最基本的流程,当然要使用 ros 的特性这还远远不够,随着后面功能的相继展开会再行介绍其他目录下的内容,当前我们主要介绍: package.xml 与 CMakeLists.txt 这两个配置文件。

  • package.xml
    该文件定义有关软件包的属性,例如软件包名称,版本号,作者,维护者以及对其他catkin软件包的依赖性。请注意,该概念类似于旧版 rosbuild 构建系统中使用的 manifest.xml 文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    <?xml version="1.0"?>
    <!-- 格式: 以前是 1,推荐使用格式 2 -->
    <package format="2">
    <!-- 包名 -->
    <name>demo01_hello_vscode</name>
    <!-- 版本 -->
    <version>0.0.0</version>
    <!-- 描述信息 -->
    <description>The demo01_hello_vscode package</description>

    <!-- One maintainer tag required, multiple allowed, one person per tag -->
    <!-- Example: -->
    <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
    <!-- 维护人员 -->
    <maintainer email="xuzuo@todo.todo">xuzuo</maintainer>


    <!-- One license tag required, multiple allowed, one license per tag -->
    <!-- Commonly used license strings: -->
    <!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
    <!-- 许可证信息,ROS核心组件默认 BSD -->
    <license>TODO</license>


    <!-- Url tags are optional, but multiple are allowed, one per tag -->
    <!-- Optional attribute type can be: website, bugtracker, or repository -->
    <!-- Example: -->
    <!-- <url type="website">http://wiki.ros.org/demo01_hello_vscode</url> -->


    <!-- Author tags are optional, multiple are allowed, one per tag -->
    <!-- Authors do not have to be maintainers, but could be -->
    <!-- Example: -->
    <!-- <author email="jane.doe@example.com">Jane Doe</author> -->


    <!-- The *depend tags are used to specify dependencies -->
    <!-- Dependencies can be catkin packages or system dependencies -->
    <!-- Examples: -->
    <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
    <!-- <depend>roscpp</depend> -->
    <!-- Note that this is equivalent to the following: -->
    <!-- <build_depend>roscpp</build_depend> -->
    <!-- <exec_depend>roscpp</exec_depend> -->
    <!-- Use build_depend for packages you need at compile time: -->
    <!-- <build_depend>message_generation</build_depend> -->
    <!-- Use build_export_depend for packages you need in order to build against this package: -->
    <!-- <build_export_depend>message_generation</build_export_depend> -->
    <!-- Use buildtool_depend for build tool packages: -->
    <!-- <buildtool_depend>catkin</buildtool_depend> -->
    <!-- Use exec_depend for packages you need at runtime: -->
    <!-- <exec_depend>message_runtime</exec_depend> -->
    <!-- Use test_depend for packages you need only for testing: -->
    <!-- <test_depend>gtest</test_depend> -->
    <!-- Use doc_depend for packages you need only for building documentation: -->
    <!-- <doc_depend>doxygen</doc_depend> -->
    <!-- 依赖的构建工具,这是必须的 -->
    <buildtool_depend>catkin</buildtool_depend>

    <!-- 指定构建此软件包所需的软件包 -->
    <build_depend>roscpp</build_depend>
    <build_depend>rospy</build_depend>
    <build_depend>std_msgs</build_depend>

    <!-- 指定根据这个包构建库所需要的包 -->
    <build_export_depend>roscpp</build_export_depend>
    <build_export_depend>rospy</build_export_depend>
    <build_export_depend>std_msgs</build_export_depend>

    <!-- 运行该程序包中的代码所需的程序包 -->
    <exec_depend>roscpp</exec_depend>
    <exec_depend>rospy</exec_depend>
    <exec_depend>std_msgs</exec_depend>


    <!-- The export tag contains other, unspecified, tags -->
    <export>
    <!-- Other tools can request additional information be placed here -->

    </export>
    </package>
  • CMakelists.txt
    文件CMakeLists.txt是CMake构建系统的输入,用于构建软件包。刚刚的案例中也对其进行了编辑,编译代码时这个文件时必须要进行相关信息修改的,任何兼容CMake的软件包都包含一个或多个CMakeLists.txt文件,这些文件描述了如何构建代码以及将代码安装到何处。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    ​cmake_minimum_required(VERSION 3.0.2) #所需 cmake 版本
    project(demo01_hello_vscode) #包名称,会被 ${PROJECT_NAME} 的方式调用

    ## Compile as C++11, supported in ROS Kinetic and newer
    # add_compile_options(-std=c++11)

    ## Find catkin macros and libraries
    ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
    ## is used, also find other catkin packages
    #设置构建所需要的软件包
    find_package(catkin REQUIRED COMPONENTS
    roscpp
    rospy
    std_msgs
    )

    ## System dependencies are found with CMake's conventions
    #默认添加系统依赖
    # find_package(Boost REQUIRED COMPONENTS system)


    ## Uncomment this if the package has a setup.py. This macro ensures
    ## modules and global scripts declared therein get installed
    ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
    # 启动 python 模块支持
    # catkin_python_setup()

    ################################################
    ## Declare ROS messages, services and actions ##
    ## 声明 ROS 消息、服务、动作... ##
    ################################################

    ## To declare and build messages, services or actions from within this
    ## package, follow these steps:
    ## * Let MSG_DEP_SET be the set of packages whose message types you use in
    ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
    ## * In the file package.xml:
    ## * add a build_depend tag for "message_generation"
    ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
    ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
    ## but can be declared for certainty nonetheless:
    ## * add a exec_depend tag for "message_runtime"
    ## * In this file (CMakeLists.txt):
    ## * add "message_generation" and every package in MSG_DEP_SET to
    ## find_package(catkin REQUIRED COMPONENTS ...)
    ## * add "message_runtime" and every package in MSG_DEP_SET to
    ## catkin_package(CATKIN_DEPENDS ...)
    ## * uncomment the add_*_files sections below as needed
    ## and list every .msg/.srv/.action file to be processed
    ## * uncomment the generate_messages entry below
    ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)

    ## Generate messages in the 'msg' folder
    # add_message_files(
    # FILES
    # Message1.msg
    # Message2.msg
    # )

    ## Generate services in the 'srv' folder
    # add_service_files(
    # FILES
    # Service1.srv
    # Service2.srv
    # )

    ## Generate actions in the 'action' folder
    # add_action_files(
    # FILES
    # Action1.action
    # Action2.action
    # )

    ## Generate added messages and services with any dependencies listed here
    # 生成消息、服务时的依赖包
    # generate_messages(
    # DEPENDENCIES
    # std_msgs
    # )

    ################################################
    ## Declare ROS dynamic reconfigure parameters ##
    ## 声明 ROS 动态参数配置 ##
    ################################################

    ## To declare and build dynamic reconfigure parameters within this
    ## package, follow these steps:
    ## * In the file package.xml:
    ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
    ## * In this file (CMakeLists.txt):
    ## * add "dynamic_reconfigure" to
    ## find_package(catkin REQUIRED COMPONENTS ...)
    ## * uncomment the "generate_dynamic_reconfigure_options" section below
    ## and list every .cfg file to be processed

    ## Generate dynamic reconfigure parameters in the 'cfg' folder
    # generate_dynamic_reconfigure_options(
    # cfg/DynReconf1.cfg
    # cfg/DynReconf2.cfg
    # )

    ###################################
    ## catkin specific configuration ##
    ## catkin 特定配置##
    ###################################
    ## The catkin_package macro generates cmake config files for your package
    ## Declare things to be passed to dependent projects
    ## INCLUDE_DIRS: uncomment this if your package contains header files
    ## LIBRARIES: libraries you create in this project that dependent projects also need
    ## CATKIN_DEPENDS: catkin_packages dependent projects also need
    ## DEPENDS: system dependencies of this project that dependent projects also need
    # 运行时依赖
    catkin_package(
    # INCLUDE_DIRS include
    # LIBRARIES demo01_hello_vscode
    # CATKIN_DEPENDS roscpp rospy std_msgs
    # DEPENDS system_lib
    )

    ###########
    ## Build ##
    ###########

    ## Specify additional locations of header files
    ## Your package locations should be listed before other locations
    # 添加头文件路径,当前程序包的头文件路径位于其他文件路径之前
    include_directories(
    # include
    ${catkin_INCLUDE_DIRS}
    )

    ## Declare a C++ library
    # 声明 C++ 库
    # add_library(${PROJECT_NAME}
    # src/${PROJECT_NAME}/demo01_hello_vscode.cpp
    # )

    ## Add cmake target dependencies of the library
    ## as an example, code may need to be generated before libraries
    ## either from message generation or dynamic reconfigure
    # 添加库的 cmake 目标依赖
    # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

    ## Declare a C++ executable
    ## With catkin_make all packages are built within a single CMake context
    ## The recommended prefix ensures that target names across packages don't collide
    # 声明 C++ 可执行文件
    add_executable(Hello_VSCode src/Hello_VSCode.cpp)

    ## Rename C++ executable without prefix
    ## The above recommended prefix causes long target names, the following renames the
    ## target back to the shorter version for ease of user use
    ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
    #重命名c++可执行文件
    # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

    ## Add cmake target dependencies of the executable
    ## same as for the library above
    #添加可执行文件的 cmake 目标依赖
    add_dependencies(Hello_VSCode ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

    ## Specify libraries to link a library or executable target against
    #指定库、可执行文件的链接库
    target_link_libraries(Hello_VSCode
    ${catkin_LIBRARIES}
    )

    #############
    ## Install ##
    ## 安装 ##
    #############

    # all install targets should use catkin DESTINATION variables
    # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html

    ## Mark executable scripts (Python etc.) for installation
    ## in contrast to setup.py, you can choose the destination
    #设置用于安装的可执行脚本
    catkin_install_python(PROGRAMS
    scripts/Hi.py
    DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )

    ## Mark executables for installation
    ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
    # install(TARGETS ${PROJECT_NAME}_node
    # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    # )

    ## Mark libraries for installation
    ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
    # install(TARGETS ${PROJECT_NAME}
    # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
    # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
    # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
    # )

    ## Mark cpp header files for installation
    # install(DIRECTORY include/${PROJECT_NAME}/
    # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
    # FILES_MATCHING PATTERN "*.h"
    # PATTERN ".svn" EXCLUDE
    # )

    ## Mark other files for installation (e.g. launch and bag files, etc.)
    # install(FILES
    # # myfile1
    # # myfile2
    # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
    # )

    #############
    ## Testing ##
    #############

    ## Add gtest based cpp test target and link libraries
    # catkin_add_gtest(${PROJECT_NAME}-test test/test_demo01_hello_vscode.cpp)
    # if(TARGET ${PROJECT_NAME}-test)
    # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
    # endif()

    ## Add folders to be run by python nosetests
    # catkin_add_nosetests(test)

ROS文件系统相关命令

ROS 的文件系统本质上都还是操作系统文件,我们可以使用Linux命令来操作这些文件,不过,在ROS中为了更好的用户体验,ROS专门提供了一些类似于Linux的命令,这些命令较之于Linux原生命令,更为简介、高效。文件操作,无外乎就是增删改查与执行等操作,接下来,我们就从这五个维度,来介绍ROS文件系统的一些常用命令。


  • catkin_create_pkg 自定义包名 依赖包 === 创建新的ROS功能包
    sudo apt install xxx === 安装 ROS功能包

  • sudo apt purge xxx ==== 删除某个功能包

  • rospack list === 列出所有功能包
    rospack find 包名 === 查找某个功能包是否存在,如果存在返回安装路径
    roscd 包名 === 进入某个功能包
    rosls 包名 === 列出某个包下的文件
    apt search xxx === 搜索某个功能包

  • rosed 包名 文件名 === 修改功能包文件
    需要安装 vim
    比如:rosed turtlesim Color.msg
  • 执行
    • roscore
      roscore === 是 ROS 的系统先决条件节点和程序的集合, 必须运行 roscore 才能使 ROS 节点进行通信。
      roscore 将启动:ros master、ros 参数服务器、rosout 日志节点
    • rosrun
      rosrun 包名 可执行文件名 === 运行指定的ROS节点
      比如:rosrun turtlesim turtlesim_node
    • roslaunch
      roslaunch 包名 launch文件名 === 执行某个包下的 launch 文件

ROS计算图

前面介绍的是ROS文件结构,是磁盘上 ROS 程序的存储结构,是静态的,而 ros 程序运行之后,不同的节点之间是错综复杂的,ROS 中提供了一个实用的工具:rqt_graph。

rqt_graph能够创建一个显示当前系统运行情况的动态图形。ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程。rqt_graph是rqt程序包中的一部分。

  • 计算图安装
    如果前期把所有的功能包(package)都已经安装完成,则直接在终端窗口中输入 rosrun rqt_graph rqt_graph
    如果未安装则在终端(terminal)中输入:
    1
    2
    $ sudo apt install ros-<distro>-rqt
    $ sudo apt install ros-<distro>-rqt-common-plugins
    请使用你的ROS版本名称(比如:kinetic、melodic、Noetic等)来替换掉
    例如当前版本是 Noetic,就在终端窗口中输入
    1
    2
    $ sudo apt install ros-noetic-rqt
    $ sudo apt install ros-noetic-rqt-common-plugins
  • 计算图演示
    接下来以 ROS 内置的小乌龟案例来演示计算图
    首先,按照前面所示,运行案例
    然后,启动新终端,键入: rqt_graph 或 rosrun rqt_graph rqt_graph,可以看到类似下图的网络拓扑图,该图可以显示不同节点之间的关系。

集成开发环境

  • 安装终端
    在 ROS 中,需要频繁的使用到终端,且可能需要同时开启多个窗口,推荐一款较为好用的终端:Terminator。效果如下:

    运行指令sudo apt install terminator安装
    快捷键如下所示:

  • vscode安装
    具体安装过程不作记录,直接进入官网即可下载安装。此处记录常用于开发ros的插件:
    • 先创建工作空间
      1
      2
      3
      mkdir -p xxx_ws/src(必须得有 src)
      cd xxx_ws
      catkin_make
    • 启动vscode
      1
      2
      cd xxx_ws
      code .
    • vscode 中编译 ros
      快捷键 ctrl + shift + B 调用编译,选择:catkin_make:build
      可以点击配置设置为默认,修改.vscode/tasks.json 文件
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      {
      // 有关 tasks.json 格式的文档,请参见
      // https://go.microsoft.com/fwlink/?LinkId=733558
      "version": "2.0.0",
      "tasks": [
      {
      "label": "catkin_make:debug", //代表提示的描述性信息
      "type": "shell", //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
      "command": "catkin_make",//这个是我们需要运行的命令
      "args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
      "group": {"kind":"build","isDefault":true},
      "presentation": {
      "reveal": "always"//可选always或者silence,代表是否输出信息
      },
      "problemMatcher": "$msCompile"
      }
      ]
      }
    • 创建 ROS 功能包
      选定 src 右击 —-> create catkin package ||设置包名 添加依赖
    • python 实现
      在 功能包 下新建 scripts 文件夹,添加 python 文件,并添加可执行权限
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      #! /usr/bin/env python
      """
      Python 版本的 HelloVScode,执行在控制台输出 HelloVScode
      实现:
      1.导包
      2.初始化 ROS 节点
      3.日志输出 HelloWorld
      """
      import rospy # 1.导包

      if __name__ == "__main__":

      rospy.init_node("Hello_Vscode_p") # 2.初始化 ROS 节点
      rospy.loginfo("Hello VScode, 我是 Python ....") #3.日志输出 HelloWorld
    • 配置 CMakeLists.txt
      1
      2
      3
      catkin_install_python(PROGRAMS scripts/自定义文件名.py
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
      )
    • 编译执行
      编译: ctrl + shift + B
      执行: 和之前一致,只是可以在 VScode 中添加终端,首先执行:source ./devel/setup.bash
      如果不编译直接执行 python 文件,会抛出异常。
      1.第一行解释器声明,可以使用绝对路径定位到 python3 的安装路径 #! /usr/bin/python3,但是不建议
      2.建议使用 #!/usr/bin/env python 但是会抛出异常 : /usr/bin/env: “python”: 没有那个文件或目录
      3.解决1: #!/usr/bin/env python3 直接使用 python3 但存在问题: 不兼容之前的 ROS 相关 python 实现
      4.解决2: 创建一个链接符号到 python 命令:sudo ln -s /usr/bin/python3 /usr/bin/python
  • launch文件

    • 需求
      一个程序中可能需要启动多个节点,比如:ROS 内置的小乌龟案例,如果要控制乌龟运动,要启动多个窗口,分别启动 roscore、乌龟界面节点、键盘控制节点。如果每次都调用 rosrun 逐一启动,显然效率低下,如何优化?
      launch文件就是为解决这个问题产生的,可以一次性生成大量节点。
    • 实现

      • 选定功能包右击 —-> 添加 launch 文件夹
      • 选定 launch 文件夹右击 —-> 添加 launch 文件
      • 编辑 launch 文件内容

        1
        2
        3
        4
        5
        <launch>
        <node pkg="helloworld" type="demo_hello" name="hello" output="screen" />
        <node pkg="turtlesim" type="turtlesim_node" name="t1"/>
        <node pkg="turtlesim" type="turtle_teleop_key" name="key1" />
        </launch>

        其中,node 表示包含的某个节点,pkg 表示功能包,type 表示被运行的节点文件,name 为节点名字,output 为设置日志的输出目标

      • 运行 launch 文件
        roslaunch 包名 launch文件名

结语、补充

文中大量提到的节点便是 ROS 的一大关键所在,相当于一个功能就是一个节点,不同的节点直接会有数据交互,具体的交互方式类似于 mqtt 的订阅发布。上述内容涵盖的点很广,重点需要搞清楚的是基本的架构以及相关命令操作,知道哪个文件夹放着什么文件,怎样操作这些文件即可。而节点等问题后续会开始正式的接触,这里只是相当于一个引子。