- ROS介绍
什么是ROS?
ROS 运行时的“蓝图”是一种基于ROS通信基础结构的松耦合点对点进程网络。ROS实现了几种不同的通信方式,包括基于同步RPC样式通信的服务(services)机制,基于异步流媒体数据的话题(topics)机制以及用于数据存储的参数服务器(Parameter Server)。想更加深入的解释这些概念,请参见概念综述。
ROS并不是一个实时的框架,但ROS可以嵌入实时程序。Willow Garage的PR2机器人使用了一种叫做pr2_etherCAT的系统来实时发送或接收ROS消息。ROS也可以与Orocos实时工具包无缝集成。
目的
很多人都在问“ROS与其它机器人软件平台有什么不同?”这是一个很难解答的问题。因为ROS不是一个集成了大多数功能或特征的框架。事实上,ROS 的主要目标是为机器人研究和开发提供代码复用的支持。ROS是一个分布式的进程(也就是节点)框架,这些进程被封装在易于被分享和发布的程序包和功能包集中。ROS也支持一种类似于代码储存库的联合系统,这个系统也可以实现工程的协作及发布。这个设计可以使一个工程的开发和实现从文件系统到用户接口完全独立决策(不受ROS限制)。同时,所有的工程都可以被ROS的基础工具整合在一起。
为了支持分享和协作的主要目的,ROS框架也有其它几个目标:
- 小型化:ROS尽可能设计的很小 -- 我们不封装您的 main() 函数 -- 所以为ROS编写的代码可以轻松的在其它机器人软件平台上使用。 由此得出的必然结论是ROS可以轻松集成在其它机器人软件平台:ROS已经可以与OpenRAVE,Orocos和Player集成。
- ROS不敏感库:ROS的首选开发模型都是用不依赖ROS的干净的库函数编写而成。
- 语言独立:ROS框架可以简单地使用任何的现代编程语言实现。我们已经实现了Python版本,C++版本和 Lisp版本。同时,我们也拥有Java 和 Lua版本的实验库。
- 方便测试:ROS内建一个了叫做rostest的单元/集成测试框架,可以轻松安装或卸载测试模块。
- 可扩展:ROS可以适用于大型运行时系统和大型开发进程。
所以,“ROS与其它机器人软件平台有什么不同?”很难得到一个适用于所有情况的答案,但是,如果你选择使用其它机器人软件平台,我们希望你仍然可以使用到很多基于ROS发布的库函数。至于更多细节,这封Brian Gerkey(同时涉猎 Player 和 ROS)向ROS用户所写的关于ROS和Player区别的电子邮件(包括OpenCV 的集成)可以为我们提供一些比较:
这个问题的答案,和许多问题一样,视情况而定。特别是取悦于你想要干什么。Player非常适合简洁的非铰接的移动平台。它的设计为那些激光雷达的先锋提供了简单的传感器和电机操作方法。
然而,ROS是围绕着基于驱动传感器(倾斜式激光,盘式/斜试头部传感器,机械臂传感器)的复杂移动处理平台设计的。与Player相比,ROS可以更方便的借助分布式计算设备,而且我可以肯定,越高级的应用越适用于ROS而不是Player。换句话说,Player提供了更多的硬件驱动,而ROS提供了更多算法。
我认为,说ROS比Player更加灵活强大是公平的。但是,现实情况是,更加灵活强大意味着更加复杂。尽管我们很努力的使ROS更加简单易用,ROS仍然需要一个很长的学习过程。当然,熟悉Player会对学习ROS有很大帮助,因为它们很多基本的方面都是相似的。
关于你们针对OpenCV集成提出的问题,我想你们会发现ROS集成OpenCV的代码要比Player多一点。未来,当ROS和OpenCV团队明显重叠时,你们会发现这种差异将变得更大。
我发现ROS利用了大量的来自于Player工程的代码。ROS节点的代码重用了许多Player的驱动,而且Stage和Gazebo可在ROS社区中得到广泛的支持和良好的应用。
操作系统
ROS目前只能在基于Unix的平台上运行。ROS的软件主要在Ubuntu和Mac OS X 系统上测试,同时ROS社区仍持续支持Fedora,Gentoo,Arch Linux和其它Linux平台。
与此同时,Microsoft Windows端口的ROS已经实现,但并未完全开发完成。
发布
ROS核心系统及各种工具和库函数通常在ROS 发行版本中发布。ROS发行版本类似于Linux发行版本,并提供了一系列兼容此版本的可被使用或开发的软件。
- ROS安装
我们同时对数个ROS发行版提供支持服务。一些是较旧的发行版,它们有长期支持(LTS)且更加稳定,而另一些则是新版,支持周期较短,但具有针对新平台的二进制文件且由新版本的ROS软件包组成。我们建议使用下列版本的ROS:
ROS虽然支持windows平台,但是笔者还是建议使用Ubuntu系统
我的是ubuntu20.4系统因此首先选择NOTEIC,然后选择Ubuntu
安装
配置Ubuntu软件仓库
配置你的Ubuntu软件仓库(repositories)以允许使用“restricted”“universe”和“multiverse”存储库。你可以根据Ubuntu软件仓库指南来完成这项工作。
注意:Ubuntu本身的源经常会下载失败,可以将/etc/apt/sources.list备份后,更改为国内源,但是更改国内源需要注意,我们用的Ubuntu系统为Arm64系统,因此需要使用Ubuntu Ports镜像,如果使用错误的镜像源会经常报错。
设置sources.list
设置电脑以安装来自packages.ros.org的软件。
- sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
若下载速度缓慢,推荐就近选择一个镜像源替换上面的命令。例如,Tsinghua University为:
- sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'
如果依旧遇到连接问题,请尝试为Ubuntu apt换源(非ROS网站)。
设置密钥
- sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
若无法连接到密钥服务器,可以尝试替换上面命令中的 hkp://keyserver.ubuntu.com:80 为 hkp://pgp.mit.edu:80 。
你也可以使用curl命令替换apt-key命令,这在使用代理服务器的情况下比较有用:
- curl -sSL 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xC1CF6E31E6BADE8868B172B4F42ED6FBAB17C654' | sudo apt-key add -
开始安装
首先,确保你的Debian软件包索引是最新的:
- sudo apt update
然后选择你想安装“多少部分”的ROS:
- 完整桌面版安装(Desktop-Full,推荐):除了桌面版的全部组件外,还包括2D/3D模拟器(simulator)和2D/3D 感知包(perception package)。
-
- sudo apt install ros-noetic-desktop-full
或 点这里
-
- sudo apt install ros-noetic-desktop
或 点这里
- ROS-Base(仅含骨架):ROS packaging,build,和communication库。没有图形界面(GUI)工具。
-
- sudo apt install ros-noetic-ros-base
或 点这里
在ROS中还有更多可用的软件包。你可以直接安装一个特定的软件包。
- sudo apt install ros-noetic-PACKAGE
例如,
sudo apt install ros-noetic-slam-gmapping
要查看或搜索所有可用的软件包,请参见ROS Index或使用:
apt search ros-noetic
注意:此处还需要安装rosdep,命令如下:
sudo apt install python3-rosdep
sudo rosdep init
rosdep update
设置环境
你需要在使用ROS的每个bash终端中source这个脚本。
source /opt/ros/noetic/setup.bash
而下面这些命令可以在每次启动新的shell窗口时很方便地为你自动source一下这个脚本:
Bash
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc
如果同时安装了好几个ROS发行版,~/.bashrc只会生效你当前使用的这个版本的setup.bash。
zsh
echo "source /opt/ros/noetic/setup.zsh" >> ~/.zshrc
source ~/.zshrc
三.开始使用
管理环境
在安装ROS期间,你会看到提示说需要source多个setup.*sh文件中的某一个,或者添加这条命令到你的shell启动脚本里面。这些操作是必须的,因为ROS依赖于使用shell环境组合空间的概念,这使得针对不同版本的ROS或不同的软件包集开发变得更加容易。
如果你在查找和使用ROS软件包方面遇到了问题,请确保已经正确配置了环境。有个好办法可以检查,确保ROS_ROOT和ROS_PACKAGE_PATH这两个环境变量正确设置:
$ printenv | grep ROS
如果没有的话,这个时候你就需要重新source一下了。
环境变量设置文件是为你生成的,但可能来自不同的地方:
- 用软件包管理器安装的ROS软件包已经提供了setup.*sh文件
- 在rosbuild workspaces中使用类似rosws的工具生成
- 编译或安装catkin软件包时自动生成
注意: 在整个教程中你将会经常看到分别针对rosbuild和catkin的不同操作说明,这是组织和构建ROS代码的两种可用方法。rosbuild不再维护且不推荐了,而是作为传统保留。catkin现在是组织代码的推荐方式,它使用更标准的CMake约定,并具有更大的灵活性,特别是对于希望集成外部代码库或希望发布其软件的用户。如需了解详细信息,请访问catkin or rosbuild。
如果你是通过Ubuntu上的apt工具来安装ROS的,那么你将会在/opt/ros/<distro>/目录中看到setup.*sh文件,以执行下面的source命令:
$ source /opt/ros/<distro>/setup.bash
请使用具体的ROS发行版简称代替<distro>。比如你安装的是ROS Noetic Ninjemys,则上述命令改为:
$ source /opt/ros/noetic/setup.bash
在每次打开终端时你都需要先运行上面这条后才能访问ROS相关的命令,为了避免这一繁琐过程,你可以事先在.bashrc文件中添加这条命令。这样做也可以方便你在同一台计算机上安装并随时切换到不同版本的ROS(比如kinetic和noetic)。
对于其他平台,无论你把ROS安装在哪里,都应该能找到这些setup.*sh文件。
创建ROS工作空间
catkin rosbuild
这些操作方法只适用于ROS Groovy及更新版本。如果你是新用户,请选择catkin。对于ROS Fuerte及早期版本,请选择rosbuild。
下面我们开始创建和构建一个catkin工作空间:
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/
$ catkin_make
catkin_make命令在catkin工作空间中是一个非常方便的工具。在你的工作空间中第一次运行它时,它会在src目录下创建一个CMakeLists.txt的链接。
对于ROS Melodic和早期版本的Python 3用户:注意,如果你从源代码构建ROS来实现Python 3的兼容性,并适当地设置您的系统(即:安装所有必需的ROS Python包的Python 3版本,例如catkin),那么在干净的catkin工作区中的第一个catkin_make命令必须是:
$ catkin_make -DPYTHON_EXECUTABLE=/usr/bin/python3
这将会配置catkin_make使用Python 3,在以后的构建中可以只使用catkin_make。
另外,如果你查看一下当前目录应该能看到build和devel这两个目录。在devel文件夹里面你可以看到几个setup.*sh文件。source这些文件中的任何一个都可以将当前工作空间设置在环境的最顶层。想要了解更多,请参考catkin文档。接下来首先source一下新生成的setup.*sh文件:
$ source devel/setup.bash
要保证工作区被安装脚本正确覆盖,需确定ROS_PACKAGE_PATH环境变量包含你当前的工作空间目录:
$ echo $ROS_PACKAGE_PATH
/home/<username>/catkin_ws/src:/opt/ros/<distro>/share
ROS文件系统导览
预备工作
本教程中我们将会用到ros-tutorials程序包。如果你之前安装的ROS不是完整桌面版(Desktop-Full),请先:
$ sudo apt-get install ros-<distro>-ros-tutorials
将<distro>替换成你安装的ROS发行版简称(比如kinetic或noetic等)。
文件系统概念简介
- 软件包(Packages):包是ROS代码的软件组织单元,每个软件包都可以包含程序库、可执行文件、脚本或其他构件。
- Manifests (package.xml): 清单(Manifest)是对软件包的描述。它用于定义软件包之间的依赖关系,并记录有关软件包的元信息,如版本、维护者、许可证等。
文件系统工具
程序代码散落在许多ROS包中。使用Linux内置命令行工具(如ls和cd)来进行查找和导航可能非常繁琐,因此ROS提供了专门的命令工具来简化这些操作。
使用rospack
rospack允许你获取软件包的有关信息。在本教程中,我们只涉及到find参数选项,该选项可以返回软件包的所在路径。
用法:
$ rospack find [package_name]
比如:
$ rospack find roscpp
将会输出:
- YOUR_INSTALL_PATH/share/roscpp
如果你是在Ubuntu操作系统上通过apt安装的ROS,你看到的应该是:
- /opt/ros/<distro>/share/roscpp
使用roscd
roscd是rosbash命令集的一部分,它允许你直接切换目录(cd)到某个软件包或者软件包集当中。
用法:
$ roscd [locationname[/subdir]]
要想验证是否能切换到roscpp包的位置,请运行以下示例:
$ roscd roscpp
现在让我们使用Unix命令pwd输出工作目录:
$ pwd
你应该会看到:
- YOUR_INSTALL_PATH/share/roscpp
你可以看到YOUR_INSTALL_PATH/share/roscpp和之前使用rospack find输出的路径是一样的。
注意,就像ROS中的其它工具一样,roscd只能切换到那些路径已经包含在ROS_PACKAGE_PATH环境变量中的软件包。要查看 ROS_PACKAGE_PATH中包含的路径,可以输入:
$ echo $ROS_PACKAGE_PATH
你的ROS_PACKAGE_PATH环境变量应该包含那些保存有ROS软件包的路径,并且每个路径之间用冒号(:)分隔开来。一个典型的ROS_PACKAGE_PATH环境变量如下:
- /opt/ros/<distro>/base/install/share
跟其他环境变量路径类似,你可以在ROS_PACKAGE_PATH中添加更多的目录,每条路径使用冒号(:)分隔。
子目录
roscd也可以切换到一个软件包或软件包集的子目录中。
执行:
$ roscd roscpp/cmake
$ pwd
应该会看到:
- YOUR_INSTALL_PATH/share/roscpp/cmake
roscd log
roscd log将带您进入存储ROS日志文件的目录。需要注意的是,如果你没有执行过任何ROS程序,系统会报错说该目录不存在。
如果你已经运行过ROS程序,那么可以尝试:
$ roscd log
使用 rosls
rosls 是rosbash命令集的一部分,它允许你直接按软件包的名称执行 ls 命令(而不必输入绝对路径)。
用法:
$ rosls [locationname[/subdir]]
示例:
$ rosls roscpp_tutorials
应输出:
- cmake launch package.xml srv
Tab补全
总是输入完整的软件包名称感觉比较繁琐。在之前的例子中,roscpp tutorials是个相当长的名称。幸运的是,一些ROS工具支持TAB补全的功能。
试着开始输入:
$ roscd roscpp_tut<<<按TAB键>>>
当按TAB键后,命令行应该会自动补充剩余部分:
$ roscd roscpp_tutorials/
这是因为roscpp_tutorials是目前唯一一个名称以roscpp_tut开头的ROS软件包。
现在试着输入:
$ roscd tur<<<按TAB键>>>
当按TAB键后,命令应该会尽可能地自动补充完整:
$ roscd turtle
然而,在这种情况下有许多软件包都以turtle开头。当再次按TAB键后会列出所有以turtle开头的ROS软件包:
- turtle_actionlib/ turtlesim/ turtle_tf/
这时在命令行中你仍然只输入了:
$ roscd turtle
现在在turtle后面输入s然后按TAB键:
$ roscd turtles<<<按TAB键>>>
因为只有一个软件包的名称以turtles开头,所以你应该会看到:
$ roscd turtlesim/
如果要查看当前安装的所有软件包的列表,你也可以利用TAB补全:
$ rosls <<<双击TAB键>>>
复习
你也许已经注意到了ROS命令工具的的命名方式:
- rospack = ros + pack(age)
- roscd = ros + cd
- rosls = ros + ls
这种命名模式在许多ROS命令工具中都会用到。
创建ROS软件包
一个catkin软件包由什么组成?
一个包要想称为catkin软件包,必须符合以下要求:
- 这个包必须有一个符合catkin规范的package.xml文件
- 这个package.xml文件提供有关该软件包的元信息
- 这个包必须有一个catkin版本的CMakeLists.txt文件
- 如果它是个Catkin元包的话,则需要有一个CMakeList.txt文件的相关样板
- 每个包必须有自己的目录
- 这意味着在同一个目录下不能有嵌套的或者多个软件包存在
最简单的软件包看起来就像这样:
- my_package/
- CMakeLists.txt
- package.xml
catkin工作空间中的软件包
开发catkin软件包的推荐方法是使用catkin工作空间,但是你也可以单独开发catkin软件包。一个简单的工作空间如下所示:
- workspace_folder/ -- WORKSPACE
- src/ -- SOURCE SPACE
- CMakeLists.txt -- 'Toplevel' CMake file, provided by catkin
- package_1/
- CMakeLists.txt -- CMakeLists.txt file for package_1
- package.xml -- Package manifest for package_1
- ...
- package_n/
- CMakeLists.txt -- CMakeLists.txt file for package_n
- package.xml -- Package manifest for package_n
在继续本教程之前请先按照创建catkin工作空间教程创建一个空白的catkin工作空间。
创建catkin软件包
本部分教程将演示如何使用catkin_create_pkg脚本来创建一个新的catkin软件包,以及创建之后都能做些什么。
首先切换到刚才创建的空白catkin工作空间中的源文件空间目录:
# You should have created this in the Creating a Workspace Tutorial
$ cd ~/catkin_ws/src
现在使用catkin_create_pkg命令创建一个名为beginner_tutorials的新软件包,这个软件包依赖于std_msgs、roscpp和rospy:
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
这将会创建一个名为beginner_tutorials的文件夹,这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件,这两个文件都已经部分填写了你在执行catkin_create_pkg命令时提供的信息。
catkin_create_pkg命令会要求你输入package_name,如有需要还可以在后面添加一些需要依赖的其它软件包:
# This is an example, do not try to run this
# catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
catkin_create_pkg命令也有更多的高级功能,这些功能在catkin/commands/catkin_create_pkg中有描述。
构建一个catkin工作区并生效配置文件
现在你需要在catkin工作区中构建软件包:
$ cd ~/catkin_ws
$ catkin_make
工作空间构建完成后,在devel子目录下创建了一个与你通常在/opt/ros/$ROSDISTRO_NAME下看到的目录结构类似的结构。
要将这个工作空间添加到ROS环境中,你需要source一下生成的配置文件:
$ . ~/catkin_ws/devel/setup.bash
软件包依赖关系
一级依赖
之前在使用catkin_create_pkg命令时提供了几个软件包作为依赖关系,现在我们可以使用rospack命令工具来查看这些一级依赖包。
$ rospack depends1 beginner_tutorials
- std_msgs
- rospy
- roscpp
如你所见,rospack列出了在运行catkin_create_pkg命令时作为参数的依赖包,这些依赖关系存储在package.xml文件中。
$ roscd beginner_tutorials
$ cat package.xml
- <package>
- ...
- <buildtool_depend>catkin</buildtool_depend>
- <build_depend>roscpp</build_depend>
- <build_depend>rospy</build_depend>
- <build_depend>std_msgs</build_depend>
- ...
- </package>
间接依赖
在很多情况下,一个依赖包还会有它自己的依赖关系,比如,rospy就有其它依赖包。
$ rospack depends1 rospy
- genpy
- roscpp
- rosgraph
- rosgraph_msgs
- roslib
- std_msgs
一个软件包可以有相当多间接的依赖关系,好在使用rospack可以递归检测出所有嵌套的依赖包。
$ rospack depends beginner_tutorials
cpp_common
rostime
roscpp_traits
roscpp_serialization
catkin
genmsg
genpy
message_runtime
gencpp
geneus
gennodejs
genlisp
message_generation
rosbuild
rosconsole
std_msgs
rosgraph_msgs
xmlrpcpp
roscpp
rosgraph
ros_environment
rospack
roslib
rospy
自定义你的软件包
本部分教程将剖析catkin_create_pkg命令生成的每个文件,并详细描述这些文件的组成部分,以及如何自定义这些文件。
自定义package.xml
自动生成的package.xml文件应该在你的新软件包中。现在让我们一起来看看新生成的package.xml文件以及每一个需要你关注的元素。
描述标签
首先关注description标签:
5 <description>The beginner_tutorials package</description>
将描述信息修改为任何你喜欢的内容,但是按照惯例,第一句话应该简短一些,因为它包括了软件包的范围。如果用一句话难以描述完全那就需要换行了。
维护者标签
接下来是maintainer标签:
7 <!-- One maintainer tag required, multiple allowed, one person per tag -->
8 <!-- Example: -->
9 <!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
10 <maintainer email="[email protected]">user</maintainer>
这是package.xml中要求填写的一个重要标签,因为它能够让其他人联系到软件包的相关人员。至少需要填写一个维护者,但如果你想的话可以添加多个。除了在标签里面填写维护者的名字外,还应该在标签的email属性中填写电子邮件地址:
7 <maintainer email="[email protected]">Your Name</maintainer>
许可证标签
再接下来是license标签,同样地也需要:
12 <!-- One license tag required, multiple allowed, one license per tag -->
13 <!-- Commonly used license strings: -->
14 <!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
15 <license>TODO</license>
你应该选择一种许可证并将它填写到这里。一些常见的开源许可协议有BSD、MIT、Boost Software License、GPLv2、GPLv3、LGPLv2.1和LGPLv3。你可以在Open Source Initiative中阅读其中的若干个许可协议的相关信息。对于本教程,我们使用BSD许可证,因为其他核心ROS组件已经在使用它:
8 <license>BSD</license>
依赖项标签
接下来的标签描述了软件包的依赖关系,这些依赖项分为build_depend、buildtool_depend、run_depend、test_depend。有关这些标记的详细说明,请参考Catkin Dependencies相关的文档。在之前的操作中,因为我们将roscpp、rospy和std_msgs作为catkin_create_pkg命令的参数,因此依赖关系如下所示:
27 <!-- The *_depend tags are used to specify dependencies -->
28 <!-- Dependencies can be catkin packages or system dependencies -->
29 <!-- Examples: -->
30 <!-- Use build_depend for packages you need at compile time: -->
31 <!-- <build_depend>genmsg</build_depend> -->
32 <!-- Use buildtool_depend for build tool packages: -->
33 <!-- <buildtool_depend>catkin</buildtool_depend> -->
34 <!-- Use exec_depend for packages you need at runtime: -->
35 <!-- <exec_depend>python-yaml</exec_depend> -->
36 <!-- Use test_depend for packages you need only for testing: -->
37 <!-- <test_depend>gtest</test_depend> -->
38 <buildtool_depend>catkin</buildtool_depend>
39 <build_depend>roscpp</build_depend>
40 <build_depend>rospy</build_depend>
41 <build_depend>std_msgs</build_depend>
除了catkin中默认提供的buildtool_depend,所有我们列出的依赖包都已经被添加到build_depend标签中。在本例中,因为在编译和运行时都需要用到所有指定的依赖包,因此还要将每一个依赖包分别添加到run_depend标签中:
12 <buildtool_depend>catkin</buildtool_depend>
13
14 <build_depend>roscpp</build_depend>
15 <build_depend>rospy</build_depend>
16 <build_depend>std_msgs</build_depend>
17
18 <exec_depend>roscpp</exec_depend>
19 <exec_depend>rospy</exec_depend>
20 <exec_depend>std_msgs</exec_depend>
最终的package.xml
现在看下面最后去掉了注释和未使用标签后的package.xml文件就显得更加简洁了:
1 <?xml version="1.0"?>
2 <package format="2">
3 <name>beginner_tutorials</name>
4 <version>0.1.0</version>
5 <description>The beginner_tutorials package</description>
6
7 <maintainer email="[email protected]">Your Name</maintainer>
8 <license>BSD</license>
9 <url type="website">http://wiki.ros.org/beginner_tutorials</url>
10 <author email="[email protected]">Jane Doe</author>
11
12 <buildtool_depend>catkin</buildtool_depend>
13
14 <build_depend>roscpp</build_depend>
15 <build_depend>rospy</build_depend>
16 <build_depend>std_msgs</build_depend>
17
18 <exec_depend>roscpp</exec_depend>
19 <exec_depend>rospy</exec_depend>
20 <exec_depend>std_msgs</exec_depend>
21
22 </package>
自定义CMakeLists.txt
到此,这个包含软件包元信息的package.xml文件已经按照需要完成了裁剪整理,现在你可以继续下面的教程了。catkin_create_pkg命令生成的CMakeLists.txt文件将在后续关于构建ROS程序代码的教程中讲述。
构建ROS软件包
构建软件包
只要安装了这个包的所有系统依赖项,就可以开始编译软件包了。
注意:如果你是通过apt或者其它软件包管理器来安装ROS的,那么系统已经安装好了所有的依赖项。
如果你还没设置环境的话,记得先soucre一下。在Ubuntu中的操作如下:
$ source /opt/ros/<distro>/setup.bash
使用catkin_make
catkin_make 是一个命令行工具,它简化了标准catkin工作流程。你可以认为catkin_make是在标准CMake工作流程中依次调用了cmake和make。
用法:
# 在catkin工作空间下
$ catkin_make [make_targets] [-DCMAKE_VARIABLES=...]
如果你不熟悉什么是标准CMake工作流程,可以认为是以下几个步骤:
注意:直接运行以下命令是无效的,因为它只是一个演示CMake工作流程的例子。
# 在CMake工作空间下
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install # (可选)
每个CMake项目都要单独进行这样的步骤。相反,多个catkin项目可以放在工作空间中一起构建,在工作空间中构建零到多个catkin软件包为以下工作流程:
# 在catkin工作空间下
$ catkin_make
$ catkin_make install # (可选)
上述命令会构建src目录下的所有catkin项目。该过程遵循REP128的建议。如果你的源代码不在默认位置(catkin_ws/src),比如说存放在了my_src中,那可以这样来使用catkin_make:
注意:直接运行以下命令是无效的,因为my_src可能不存在。
# 在catkin工作空间下
$ catkin_make --source my_src
$ catkin_make install --source my_src # (可选)
对于catkin_make的高级用法,请参考catkin/commands/catkin_make。
开始构建你的软件包
如果现在就要构建自己的代码,请同时看一下后面的(C++)/(Python)教程,因为你可能需要修改CMakeLists.txt文件。
按照之前的创建ROS软件包教程,你应该已经创建好了一个catkin工作空间和一个名为beginner_tutorials的catkin软件包。现在切换到catkin工作空间并查看src目录:
$ cd ~/catkin_ws/
$ ls src
- beginner_tutorials/ CMakeLists.txt@
你可以看到一个名为beginner_tutorials的目录,这就是你之前用catkin_create_pkg命令创建的。现在我们可以使用catkin_make来构建它了:
$ catkin_make
你可以看到很多cmake和make的输出信息:
- Base path: /home/user/catkin_ws
- Source space: /home/user/catkin_ws/src
- Build space: /home/user/catkin_ws/build
- Devel space: /home/user/catkin_ws/devel
- Install space: /home/user/catkin_ws/install
- ####
- #### Running command: "cmake /home/user/catkin_ws/src
- -DCATKIN_DEVEL_PREFIX=/home/user/catkin_ws/devel
- -DCMAKE_INSTALL_PREFIX=/home/user/catkin_ws/install" in "/home/user/catkin_ws/build"
- ####
- -- The C compiler identification is GNU 4.2.1
- -- The CXX compiler identification is Clang 4.0.0
- -- Checking whether C compiler has -isysroot
- -- Checking whether C compiler has -isysroot - yes
- -- Checking whether C compiler supports OSX deployment target flag
- -- Checking whether C compiler supports OSX deployment target flag - yes
- -- Check for working C compiler: /usr/bin/gcc
- -- Check for working C compiler: /usr/bin/gcc -- works
- -- Detecting C compiler ABI info
- -- Detecting C compiler ABI info - done
- -- Check for working CXX compiler: /usr/bin/c++
- -- Check for working CXX compiler: /usr/bin/c++ -- works
- -- Detecting CXX compiler ABI info
- -- Detecting CXX compiler ABI info - done
- -- Using CATKIN_DEVEL_PREFIX: /tmp/catkin_ws/devel
- -- Using CMAKE_PREFIX_PATH: /opt/ros/kinetic
- -- This workspace overlays: /opt/ros/kinetic
- -- Found PythonInterp: /usr/bin/python (found version "2.7.1")
- -- Found PY_em: /usr/lib/python2.7/dist-packages/em.pyc
- -- Found gtest: gtests will be built
- -- catkin 0.5.51
- -- BUILD_SHARED_LIBS is on
- -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- -- ~~ traversing packages in topological order:
- -- ~~ - beginner_tutorials
- -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- -- +++ add_subdirectory(beginner_tutorials)
- -- Configuring done
- -- Generating done
- -- Build files have been written to: /home/user/catkin_ws/build
- ####
- #### Running command: "make -j4" in "/home/user/catkin_ws/build"
- ####
请注意,catkin_make首先输出它所使用到的每个空间所在的路径。更多关于空间的信息,请参考REP128和catkin/workspaces。需要注意的是,根据这些变量的默认值,有几个目录已经在catkin工作空间中自动生成了,用ls看看:
$ ls
- build
- devel
- src
build 目录是构建空间的默认位置,同时cmake和make也是在这里被调用来配置和构建你的软件包。而devel目录是开发空间的默认位置, 在安装软件包之前,这里可以存放可执行文件和库。
理解ROS节点
预备工作
本教程中我们将会用到一个轻量级模拟器。如果你之前安装的ROS不是完整桌面版(Desktop-Full),请先:
$ sudo apt-get install ros-<distro>-ros-tutorials
将<distro>替换成你安装的ROS发行版简称(比如kinetic或noetic等)。
图概念速览
计算图(Computation Graph)是一个由ROS进程组成的点对点网络,它们能够共同处理数据。ROS的基本计算图概念有节点(Nodes)、主节点(Master)、参数服务器(Parameter Server)、消息(Messages)、服务(Services)、话题(Topics)和袋(Bags),它们都以不同的方式向图(Graph)提供数据。
- 节点(Nodes):节点是一个可执行文件,它可以通过ROS来与其他节点进行通信。
- 消息(Messages):订阅或发布话题时所使用的ROS数据类型。
- 话题(Topics):节点可以将消息发布到话题,或通过订阅话题来接收消息。
- 主节点(Master):ROS的命名服务,例如帮助节点发现彼此。
- rosout:在ROS中相当于stdout/stderr(标准输出/标准错误)。
- roscore:主节点 + rosout + 参数服务器(会在以后介绍)。
节点
节点实际上只不过是ROS软件包中的一个可执行文件。ROS节点使用ROS客户端库与其他节点通信。节点可以发布或订阅话题,也可以提供或使用服务。
注:节点是ROS中非常重要的一个概念,为了帮助初学者理解这个概念,这里举一个通俗的例子:
例如,咱们有一个机器人,和一个遥控器,那么这个机器人和遥控器开始工作后,就是两个节点。遥控器起到了下达指 令的作用;机器人负责监听遥控器下达的指令,完成相应动作。从这里我们可以看出,节点是一个能执行特定工作任 务的工作单元,并且能够相互通信,从而实现一个机器人系统整体的功能。在这里我们把遥控器和机器人简单定义为两个节点,实际上在机器人中根据控制器、传感器、执行机构等不同组成模块,还可以将其进一步细分为更多的节点,这个是根据用户编写的程序来定义的。)
客户端库
ROS客户端库可以让用不同编程语言编写的节点进行相互通信:
- rospy = Python客户端库
- roscpp = C++客户端库
roscore
roscore是你在运行所有ROS程序前首先要运行的命令。
请运行:
$ roscore
然后你会看到类似下面的输出信息:
- ... logging to ~/.ros/log/9cf88ce4-b14d-11df-8a75-00251148e8cf/roslaunch-machine_name-13039.log
- Checking log directory for disk usage. This may take awhile.
- Press Ctrl-C to interrupt
- Done checking log file disk usage. Usage is <1GB.
- started roslaunch server http://machine_name:33919/
- ros_comm version 1.4.7
- SUMMARY
- ========
- PARAMETERS
- * /rosversion
- * /rosdistro
- NODES
- auto-starting new master
- process[master]: started with pid [13054]
- ROS_MASTER_URI=http://machine_name:11311/
- setting /run_id to 9cf88ce4-b14d-11df-8a75-00251148e8cf
- process[rosout-1]: started with pid [13067]
- started core service [/rosout]
如果roscore运行后没有初始化,很有可能是网络配置的问题。参见网络配置 - 单机器配置。
如果roscore不能初始化并提示缺少权限,可能是因为~/.ros目录属于root用户(只有root用户才能访问),可以用以下命令递归地更改该目录的所有权:
$ sudo chown -R <your_username> ~/.ros
使用rosnode
打开一个新终端,可以使用rosnode看看roscore运行时干了些什么…… 记得要保持以前的终端开着,比如打开一个新的标签页,或者最小化之前的窗口。
注意: 当打开一个新的终端时,环境将会重置,~/.bashrc文件将会生效。如果你在运行rosnode等命令时出现一些问题,那么可能需要将一些环境设置文件添加到~/.bashrc或手动source一下。
rosnode显示当前正在运行的ROS节点信息。rosnode list命令会列出这些活动的节点:
$ rosnode list
- 你会看到:
- /rosout
这表示当前只有一个节点在运行: rosout。因为这个节点用于收集和记录节点的调试输出,所以它总是在运行的。
而rosnode info命令返回的是某个指定节点的信息。
$ rosnode info /rosout
这给了我们更多关于rosout的信息, 比如说实际上它是发布了一个/rosout_agg话题。
- ------------------------------------------------------------------------
- Node [/rosout]
- Publications:
- * /rosout_agg [rosgraph_msgs/Log]
- Subscriptions:
- * /rosout [unknown type]
- Services:
- * /rosout/get_loggers
- * /rosout/set_logger_level
- contacting node http://machine_name:54614/ ...
- Pid: 5092
现在,让我们看看其他节点。为此,我们将使用rosrun调出另一个节点。
使用rosrun
rosrun可以让你用包名直接运行软件包内的节点(而不需要知道包的路径)。
用法:
$ rosrun [package_name] [node_name]
所以现在我们试着运行turtlesim包中的turtlesim_node。
在一个新终端中:
$ rosrun turtlesim turtlesim_node
你会看到turtlesim窗口:
注意:此处的乌龟可能和你turtlesim窗口上的不同。别担心,实际上有许多版本的turtle ,而你的是个惊喜!(一个可爱的小彩蛋~)
在一个新终端中:
$ rosnode list
你会看到类似下面的输出信息:
- /rosout
- /turtlesim
ROS有一个强大的功能,就是你可以通过命令行重新分配名称。
关闭turtlesim窗口以停止节点(或回到rosrun turtlesim的终端并按Ctrl+C)。现在让我们重新运行它,但是这一次使用重映射参数来改变节点名称:
$ rosrun turtlesim turtlesim_node __name:=my_turtle
现在,如果我们回去使用rosnode list:
$ rosnode list
- 你会看到类似下面的输出信息:
- /rosout
- /my_turtle
注意:如果你仍看到/turtlesim在列表中,这可能因为你是在终端中使用Ctrl+C停止的节点而不是关闭窗口,或者你没有按网络配置 - 单机器配置中的描述定义$ROS_HOSTNAME环境变量。可以尝试清除下rosnode列表: $ rosnode cleanup
我们可以看到新的/my_turtle节点。使用另外一个rosnode指令,ping,来测试它是否正常:
$ rosnode ping my_turtle
- rosnode: node is [/my_turtle]
- pinging /my_turtle with a timeout of 3.0s
- xmlrpc reply from http://aqy:42235/ time=1.152992ms
- xmlrpc reply from http://aqy:42235/ time=1.120090ms
- xmlrpc reply from http://aqy:42235/ time=1.700878ms
- xmlrpc reply from http://aqy:42235/ time=1.127958ms
复习
本节所涉及的内容:
- roscore = ros+core:主节点(为ROS提供命名服务) + rosout (stdout/stderr) + 参数服务器(会在以后介绍)
- rosnode = ros+node:获取节点信息的ROS工具
- rosrun = ros+run:运行给定的软件包中的节点
到这里,您已经了解ROS节点是如何工作的