ros 机器人程序设计


ROS 机器人程序设计 Learning ROS for Robotics Programming (西班牙) Aaron Martinez Enrique Fernández 著 刘品杰 译 图书在版编目(CIP)数据 ROS 机器人程序设计 /(西)马丁内斯 (Martinez,A.) 等著;刘品杰译 . —北京:机械工业 出版社,2014.8 (电子与嵌入式系统设计丛书) 书名原文: Learning ROS for Robotics Programming ISBN 978-7-111-47396-1 I. R… II. ① 马… ② 刘… III. 机器人-程序设计 IV. TP242 中国版本图书馆 CIP 数据核字(2014)第 161738 号 本书版权登记号:图字:01-2014-1838 Aaron Martinez, Enrique Fernández: Learning ROS for Robotics Programming(ISBN: 978-1-78216- 144-8) Copyright © 2013 Packt Publishing. First published in the English language under the title“Learning ROS for Robotics Programming”. All rights reserved. Chinese simplified language edition published by China Machine Press. Copyright © 2014 by China Machine Press. 本书中文简体字版由 Packt Publishing 授权机械工业出版社独家出版。未经出版者书面许可,不得以任何方式复 制或抄袭本书内容。 ROS 是一个机器人操作系统框架,现今已有数百个研究团体和公司将其应用在机器人技术产业中。本书是一本 ROS 的入门手册,从 ROS 系统的安装到主要功能包里各项工具的使用方法如先进的计算机视觉和导航工具等都进行 细致的介绍和说明,并且提供全面的相关示例代码及详细的解释,读者可以按照本书指导进行相关练习。本书适用于 机械、自动化、计算机等相关专业高年级本科生及研究生学习,也适合于准备学习 ROS 的科研人员及企业研发人员学 习和使用。 ROS 机器人程序设计 [ 西班牙 ] Aaron Martinez 等著 出版发行:机械工业出版社(北京市西城区百万庄大街 22 号 邮政编码:100037) 责任编辑:朱 瑛 责任校对:董纪丽 印  刷: 版  次:2014 年 9 月第 1 版第 1 次印刷 开  本:186mm×240mm 1/16 印  张:15 书  号:ISBN 978-7-111-47396-1 定  价:59.00 元 凡购本书,如有缺页、倒页、脱页,由本社发行部调换 客服热线:(010)88378991 88361066 投稿热线:(010)88379604 购书热线:(010)68326294 88379649 68995259 读者信箱:hzjsj@hzbook.com 版权所有· 侵权必究 封底无防伪标均为盗版 本书法律顾问:北京大成律师事务所 韩光 / 邹晓东 The Translator’s Words  译者序 在过去的几十年里,机器人主要是自动化或机械专业的研究领域,计算机往往作为辅助 仿真的工具,机器人的程序设计也往往仅限于使用诸如 matlab 机器人工具箱之类的仿真工 具。今天很多大型 IT 企业都投入大量资源开发了机器人相关的软件开发工具,例如 Visual Studio 的 Robotics Developer Studio,这些软件工具的目的是颠覆传统的机器人开发和设计模 式。机器人操作系统就是基于这个目的产生的。它们能够帮助开发人员在原有机器人的基础 上不断地进行二次开发,深入拓展机器人技术。而其中最具代表性的正是开源机器人操作系 统 ROS(Robot Operating System)。 与其说 ROS 是一个操作系统,不如说它是一种分布式模块化的开源软件框架。它借用 标准的 TCP(UDP)/IP 协议实现了系统内部各个节点之间的通信,网络化的接口允许将第三 方组件泛化成为其操作系统的一部分。如果你真正使用过 ROS,就会为其无所不包的开放性 而感到惊讶。正因如此, ROS 社区集中了全世界顶尖的机器人研究人员。今天, ROS 能够 无缝集成现在已知的大部分机器人操作系统;能满足最高的实时性与可靠性要求;通过使用 EtherCAT 等高速总线能以每秒 Gb 级的速度传输视频数据;能够通过集成其他开源组件及增 强现实技术提供多种仿真环境;能够通过多种接口与各种硬件设备或传感器进行通信;能够 替你计算繁琐的正逆运动学,通过标定和配置轻松完成视觉伺服等高难度任务;你可以方便 地移植其他机器人上已经测试过的各类算法和代码,或引入其他开源库。 虽然 ROS 大幅度降低了开发和应用机器人的难度,但是考虑到机器人领域无所不包, 想要学习和使用 ROS 还是有几点需要注意的。首先,你应该学习过 C/C++ 程序设计语言, 能够使用 Linux 编译和运行程序,这是阅读本书的基本要求。当然,如果你是一个编程新手, 也可以跟着本书示例在实践中学习 Linux 和编程知识。其次,在学习和使用 ROS 的时候,往 往还需要懂得程序设计之外的很多机器人知识,尤其是数学知识。但由于机器人领域过于宽 泛,因此在学习过程中最好能够专注于某一方面的相关知识,不要贪多求全。再次, ROS 是 一个开源软件,因此我们也要保持一种开放的心态。虽然本书能帮助你入门相对轻松一些, 但这并不会彻底优化你的学习曲线。如果想要学好 ROS,一定要去 www.ros.org 上学习最 IV 新的资料,尤其是 ROS wiki。最顶尖的 ROS 国际会议是 ROSCON,你可以到 Google 或者 YouTube 上搜索相关内容,里面有 ROS 最新的发展与介绍。最后,本书英文版虽然是 2013 年 9 月出版,但 ROS 和 Linux 一样半年出一个新的版本,因此书中并没有介绍最新的 ROS Hydro 和 ROS Groovy。其实这些并不妨碍你对 ROS 的学习,没有谁为了学习 Linux 编程而 非要用最新出版的图书,因为软件的基本框架和组织方式不会发生改变,而且支持 ROS 的 机器人硬件并不一定支持最新的 ROS。ROS Hydro 和 ROS Groovy 主要对 ROS 原有的编译 系统和部分功能包有所升级和替换,如果有兴趣的话,建议在学习完本书之后尚有余力的情 况下,可以通过 wiki 自学 ROS Hydro 或 ROS Groovy。 本书的两位作者并不是以英语为母语的,因此英文原著中存在着较多的语法错误和校对 错误。虽然在翻译过程中参考了原著的勘误和所附代码,考虑到译者的水平亦有限,因此仍 然不免存在错误,还请大家海涵。在本书之前,ROS 的中文译著甚少,因此有些专业名词的 翻译亦有待商榷。为了方便读者学习,译者共享了一个 VMware 9.0 下的虚拟机,里面包含 完整安装的 Vbuntu 12.04 和 ROS Fuerte (下载2018香港马会开奖现场是 http://pan.baidu.com/s/1nt6uH9R)。这样, 使用 VMware 虚拟机的读者可以下载并在 VMware 中运行,然后直接学习第 2 章到第 8 章的 内容。关于本书中的各种问题,欢迎大家与我联系,我的邮箱是 liupinjie@gmail.com。 虽然 ROS 是机器人技术,但是其分布式的节点布置同样满足物联网及很多工业应用的 需求,同时也有很多外国企业利用它进行机床、船舶、汽车或自动化系统的制造。记住, ROS 代表了未来的智能化时代,赋予了我们新的创造与改变世界的能力。 刘品杰 2014 年 4 月于北京 Preface  前 言 本书概括性地介绍了 ROS 系统的各种工具。 ROS 是一个先进的机器人操作系统框架, 现今已有数百个研究团体和公司将其应用在机器人技术产业中。对于机器人技术的非专业人 士来说,它也相对容易上手。在本书中,你将了解如何安装 ROS,如何开始使用 ROS 的基 本工具,以及如何最终应用先进的计算机视觉和导航工具。 在阅读本书的过程中无需使用任何特殊的设备。书中每一章都附带了一系列的源代码 示例和教程,你可以在自己的计算机上运行。这是你唯一需要做的事情。当然,我们还会 告诉你如何使用硬件,这样,你可以将你的算法应用到现实环境中。我们在选择设备时特 意去选择一些业余用户负担得起的设备,并同时涵盖了在机器人研究中最典型的传感器或 执行机构。 最后,由于 ROS 系统的存在使得整个机器人具备在虚拟环境中工作的能力。你将学习 如何创建自己的机器人并结合功能强大的导航功能包集。此外如果使用 Gazebo 仿真环境, 你将能够在虚拟环境中运行一切。我们会在本书的结尾提供一个能够在 ROS 虚拟环境中进 行模拟试验的机器人列表。你将发现你已经可以与机器人一起工作,并理解其背后的原理。 主要内容 第 1 章简单介绍安装 ROS 系统的方法,同时还介绍 ROS 不同版本的安装包的安装,本 书使用的是 ROS Fuerte。这一章还会说明如何从 Debian 软件包安装或从源代码进行编译安 装,以及在虚拟机中安装。 第 2 章涉及 ROS 框架及相关的概念和工具。该章介绍节点、 主题和服务,以及如何使用 它们,还将通过一系列示例来说明如何调试一个节点或通过可视化方法直观地查看通过主题 所发布的消息。 第 3 章进一步展示 ROS 强大的调试工具,以及通过对节点主题的图形化可以将节点间 的通信数据可视化。 ROS 提供一个日志记录 API,允许轻松地诊断节点的问题。事实上在使 用过程中,我们会看到一些功能强大的图形化工具如 rxconsole 和 rxgraph,以及可视化接口 VI 如 rxplot 和 rviz。最后介绍如何使用 rosbag 和 rxbag 记录和回放消息。 第 4 章介绍 ROS 系统与真实世界如何连接。这一章介绍在 ROS 下使用的一些常见传感 器和执行机构,如激光雷达、伺服电动机、摄像头、RGB-D 传感器等设备。此外,还会解释 如何使用嵌入式系统与微控制器,例如非常流行的 Arduino。 第 5 章介绍我们在 ROS 系统中实现机器人的第一步是在 ROS 中创建一个机器人模型, 包括在 Gazebo 仿真环境中如何从头开始对一个机器人进行建模和仿真,并使其在仿真环境 中运行。这是后续学习如何使用 ROS 的导航功能包集和其他工具的前提条件。 第 6 章介绍 ROS 对摄像头和计算机视觉任务的支持。首先使用 FireWire 和 USB 摄像头 驱动程序将摄像头连接到计算机并采集图像。然后,你就可以使用 ROS 的标定工具标定你 的摄像头。我们会详细介绍和说明什么是图像管道,学习如何使用集成了 OpenCV 的多个机 器视觉 API。最后,安装并使用一个视觉测距软件。 第 7 章是本书关于 ROS 导航功能包集的两章中的第 1 章。介绍如何对你的机器人进行 使用导航功能包集所需的初始化配置。然后用几个例子对导航功能包集进行说明。 第 8 章延续第 7 章的内容,介绍如何使用导航功能包集使我们的机器人有效地自主导 航。本章介绍使用 ROS 的 Gazebo 仿真环境和 rviz 创建一个虚拟的环境,并在其中构建地 图、定位我们的机器人并做路径规划与避障。 第 9 章结合前面几章所学的内容,介绍能够支持 ROS 并使用 Gazebo 仿真环境的一些机 器人。在该章中,你将看到如何在仿真环境中运行这些机器人,并执行几项本书中介绍过的 任务,尤其是与导航功能包集相关的。 预备知识 我们写作本书的目的是希望尽可能让每位读者都可以完成本书的学习并运行示例代码。 基本上,你只需要在计算机上安装一个 Linux 发行版。虽然每个 Linux 发行版本应该都能使 用,但还是建议你使用 Ubuntu 的最新版。这样你可以根据第 1 章的内容安装 ROS Fuerte。 对于 ROS 的这一版本,你将需要 Ubuntu 12.10 之前的版本,因为之后的版本已经不再支持 Fuerte 了。 对于硬件要求,一般来说任何台式计算机或笔记本电脑都满足。但是,最好使用独立显 卡来运行 Gazebo 仿真环境。此外,如果能够有足够的外围接口将会更好,因为这样你可以 连接几个传感器和执行机构,包括摄像头和 Arduino。 你还需要 Git (git-core Debian 软件包),以便从本书提供的软件源下载源代码。同样,你 需要具备 Bash 命令行、GNU/Linux 工具的基本知识和一些 C/C++ 编程技巧。 VII 目标读者 本书的目标读者包括所有机器人开发人员,可以是初学者也可以是专业人员。它涵盖了 整个机器人系统的各个方面,展示了 ROS 系统如何帮助完成机器人真正自主化的任务。对 于听说过 ROS 却从未使用过的机器人领域的学生或科研人员来说,本书将是非常有益的。 ROS 初学者能从本书中学习很多 ROS 软件框架的先进理念和工具。不仅如此,经常使用 ROS 的用户也可能从某些章节中学习到一些新东西。当然,只有前 3 章是纯粹为初学者准备 的,所以那些已经使用过 ROS 的人可以跳过这部分直接阅读后面的章节。 排版说明 在本书中,你会发现一些文本的样式与其他正文内容不同。下面是一些样式的示例及含义。 当我们希望能够着重显示示例代码中的某些内容的时候,相关的代码行会如下表示: Preface [ 4 ] Conventions In this book, you will find a number of styles of text that distinguish between different kinds of information. Here are some examples of these styles, and an explanation of their meanings. Code words in text are shown as follows: "The *-ros-pkg contributed packages are licensed under a variety of open source licenses." A block of code is set as follows: long description, Aaron Martinez, Enrique Fernandez BSD http://example.com/ When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold: Any command-line input or output is written as follows: $ rosrun book_tutorials tutorialX _param:=9.0 New terms and important words are shown in bold. Words that you see on the screen, in menus, or dialog boxes for example, appear in the text like this: "We must have clicked on the Play button at least once." Bash 命令行下输入的命令或显示的结果如下表示: Preface [ 4 ] Conventions In this book, you will find a number of styles of text that distinguish between different kinds of information. Here are some examples of these styles, and an explanation of their meanings. Code words in text are shown as follows: "The *-ros-pkg contributed packages are licensed under a variety of open source licenses." A block of code is set as follows: long description, Aaron Martinez, Enrique Fernandez BSD http://example.com/ When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold: Any command-line input or output is written as follows: $ rosrun book_tutorials tutorialX _param:=9.0 New terms and important words are shown in bold. Words that you see on the screen, in menus, or dialog boxes for example, appear in the text like this: "We must have clicked on the Play button at least once." Chapter 7 [ 229 ] Notice that the data is the same as the one you can see on the Gazebo screen. As you can observe, Gazebo is creating the odometry as the robot moves. We are going to see how Gazebo creates it by looking inside the plugin's source code. The plugin file is located in the erratic_gazebo_plugins package, and the file is diffdrive_plugin.cpp. Open the file and you will see the following code inside the file: $ rosed erratic_gazebo_plugins diffdrive_plugin.cpp The file has a lot of code, but the important part for us now is the following function, publish_odometry(): void DiffDrivePlugin::publish_odometry() { ros::Time current_time = ros::Time::now(); std::string odom_frame = tf::resolve(tf_prefix_, "odom"); std::string base_footprint_frame = tf::resolve(tf_prefix_, "base_ footprint"); // getting data for base_footprint to odom transform math::Pose pose = this->parent->GetState().GetPose(); btQuaternion qt(pose.rot.x, pose.rot.y, pose.rot.z, pose.rot.w); btVector3 vt(pose.pos.x, pose.pos.y, pose.pos.z); tf::Transform base_footprint_to_odom(qt, vt); transform_broadcaster_->sendTransform(tf::StampedTransform(base_ footprint_to_odom, current_time, odom_frame, base_footprint_frame)); // publish odom topic odom_.pose.pose.position.x = pose.pos.x; odom_.pose.pose.position.y = pose.pos.y; odom_.pose.pose.orientation.x = pose.rot.x; odom_.pose.pose.orientation.y = pose.rot.y; odom_.pose.pose.orientation.z = pose.rot.z; odom_.pose.pose.orientation.w = pose.rot.w; math::Vector3 linear = this->parent->GetWorldLinearVel(); odom_.twist.twist.linear.x = linear.x; odom_.twist.twist.linear.y = linear.y; odom_.twist.twist.angular.z = this->parent->GetWorldAngularVel().z; 警告或注意事项会这样显示。 Getting Started with ROS [ 16 ] For this book, we are going to install the full version. This version will install all the examples, stacks, and programs. This is a good option for us because in some chapters of this book, we will need to use tools, and if we don't install it now, we will have to do it later: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers, or RGB-D cameras: $ sudo apt-get install ros-fuerte-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-fuerte-desktop • If you only want the bare bones, install ROS-comm, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-fuerte-ros-comm • Finally, along with whatever option you choose from the list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-fuerte-STACK Do not worry if you are installing things that you do not know. In the upcoming chapters, you will learn about everything you are installing and how to use it. When you gain experience with ROS, you can make basic installations in your robots using only the core of ROS, using less resources, and taking only what you need. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. 提示与小窍门会这样显示。 读者反馈 我们非常欢迎读者能够提出意见与建议。让我们知道你关于本书的一些想法,例如:你 喜欢什么,不喜欢什么。读者的反馈对我们是非常重要的,这让我们知道我们最需要做的是 什么。 向我们反馈信息只需发送电子邮件至 feedback@packtpub.com,并在邮件的主题中说明 书籍名称。 如果你在某项上有所专长,或者你有兴趣写一本书或者为书籍的出版做出贡献,你可以 浏览 www.packtpub.com/authors 阅读我们的作者指南。 VIII 读者支持 你现在自豪地拥有了 Packt 出版的书籍,我们会帮助你使你购买的产品物超所值。 源代码下载 可以访问 http://www.packtpub.com/support,完成网站注册并通过 E-mail 接收所有代码 文件。 彩色图片下载 我们同时提供包含了本书所有彩色的屏幕截图、对话框的 PDF 文件,这些彩色图片能 够更好地帮助你理解输出的变化。可以从这里下载这个文件: http://www.packtpub.com/sites/ default/files/ downloads/1448OS_Graphics.pdf。 勘误 虽然我们已尽力确保本书内容的准确性,但错误在所难免。如果你在我们的书中发现 错误,即使是一个错字或一段错误的代码,我们将非常感谢你把错误告知我们。这样可以 避免其他读者发生困扰并帮助我们提高本书后续版本的质量。如果你发现任何错误,请访问 http://www.packtpub.com/ submit-errata 报告这些问题。访问网页,选择你的书,点击勘误提 交表格的链接,并输入你的勘误细节。一旦确认了你的勘误,我们会告知你的提交被接受并 在我们的网站上更新勘误表。你可以在 http://www. packtpub.com/support 根据你选择的标题 查看现有的勘误表。 问题 如果关于本书你有任何疑问,请联系我们 questions@packtpub.com,我们会竭尽所能为 你解答。 译者序 前 言 第 1 章 ROS 系统入门 1 1.1 使用软件源安装 ROS Electric 3 1.1.1  添加软件源到 sources.list 文件中 4 1.1.2  设置密码 4 1.1.3  安装 4 1.1.4  环境配置 5 1.2  使用软件源安装 ROS Fuerte 6 1.2.1  配置 Ubuntu 软件源 6 1.2.2  配置 source.list 文件 6 1.2.3  设置密码 7 1.2.4  安装 7 1.2.5  环境配置 8 1.2.6  独立工具 9 1.3  如何安装 VirtualBox 和 Ubuntu 9 1.3.1  下载 VirtualBox 9 1.3.2  创建虚拟机 10 1.4  本章小结 12 第 2 章 ROS 系统架构及示例 13 2.1  理解 ROS 文件系统级 13 2.1.1  功能包 14 2.1.2  功能包集 16 2.1.3  消息类型 16 2.1.4  服务类型 17 2.2  理解 ROS 计算图级 18 2.2.1  节点 19 2.2.2  主题 20 2.2.3  服务 21 2.2.4  消息 22 2.2.5  消息记录包 22 2.2.6  节点管理器 22 2.2.7  参数服务器 22 2.3  理解 ROS 开源社区级 23 2.4  ROS 系统试用练习 23 2.4.1  ROS 文件系统导览 24 2.4.2  创建工作空间 24 2.4.3  创建 ROS 功能包 25 2.4.4  编译 ROS 功能包 26 2.4.5  使用 ROS 节点 26 2.4.6  使用主题与节点交互 28 2.4.7  学习如何使用服务 31 2.4.8  使用参数服务器 33 2.4.9  创建节点 34 2.4.10  编译节点 36 Contents  目 录 X 2.4.11  创建 msg 和 srv 文件 37 2.4.12  使用新建的 srv 和 msg 文件 38 2.5  本章小结 42 第 3 章 调试和可视化 43 3.1  调试 ROS 节点 44 3.1.1  使用 GDB 调试器调试 ROS 节点 45 3.1.2  ROS 节点启动时调用 GDB 调试器 46 3.1.3  设置 ROS 节点 core 文件 转存 47 3.2  调试信息 47 3.2.1  输出调试信息 47 3.2.2  设置调试信息级别 48 3.2.3  为特定节点配置调试 信息级别 48 3.2.4  信息命名 50 3.2.5  条件显示信息与过滤信息 50 3.2.6  信息的更多功能——单次 显示、可调、组合 51 3.2.7  使用 rosconsole 和 rxconsole 在运行时修改调试级别 52 3.3  监视系统状态 56 3.3.1  节点、主题与服务列表 56 3.3.2  使用 rxgraph 在线监视 节点状态图 56 3.4  当奇怪的事情发生——使用 roswtf 58 3.5  画标量数据图 58 3.5.1  用 rxplot 画出时间趋势 曲线 59 3.5.2  另一个画图工具 rxtools 60 3.6  图像可视化 61 3.6.1  显示单一图片 61 3.6.2  FireWire 接口摄像头 62 3.6.3  使用双目立体视觉 63 3.7  3D 可视化 64 3.7.1  使用 rviz 在 3D 世界中 实现数据可视化 64 3.7.2  主题与坐标系的关系 66 3.7.3  可视化坐标变换 67 3.8  保存与回放数据 68 3.8.1  什么是消息记录包文件 69 3.8.2  使用 rosbag 在包文件中 记录数据 69 3.8.3  回放消息记录文件 70 3.8.4  使用 rxbag 检查消息记录 包的主题和消息 71 3.9  rqt 插件与 rx 应用 72 3.10  本章小结 73 第 4 章  在 ROS 下使用传感器 和执行机构 74 4.1  使用游戏杆或游戏手柄 74 4.1.1  joy_node 如何发送游戏杆 动作消息 75 4.1.2  使用游戏杆数据在 turtlesim 中移动海龟 76 4.2  使用激光雷达——Hokuyo URG-04lx 79 4.2.1  了解激光雷达如何在 ROS 中发送数据 80 4.2.2  访问和修改激光雷达 数据 82 XI 4.3  使用 Kinect 传感器查看 3D 环境 84 4.3.1  如何发送和查看 Kinect 数据 85 4.3.2  创建和使用 Kinect 示例 86 4.4  使用伺服电动机—— Dynamixel 88 4.4.1  Dynamixel 如何发送和 接收运动命令 89 4.4.2  创建和使用伺服电动机 示例 90 4.5  使用 Arduino 添加更多的 传感器和执行机构 91 4.6  使用惯性测量模组—— Xsens MTi 94 4.6.1  Xsens 如何在 ROS 中 发送数据 95 4.6.2  创建和使用 Xsens 示例 96 4.7  使用低成本惯性测量模组 IMU-10 自由度 98 4.7.1  下载加速度传感器库 99 4.7.2  Arduino Nano 和 10 自由度 传感器编程 99 4.7.3  创建 ROS 节点并使用 10 自由度传感器数据 101 4.8  本章小结 103 第 5 章 3D 建模与仿真 104 5.1  自定义机器人在 ROS 中的 3D 模型 104 5.2  创建第一个 URDF 文件 104 5.2.1  解释文件格式 106 5.2.2  在 rviz 里查看 3D 模型 107 5.2.3  加载图形到机器人模型 109 5.2.4  使机器人模型运动 109 5.2.5  物理和碰撞属性 110 5.3  xacro——一个写机器人模型的 更好方法 111 5.3.1  使用常量 111 5.3.2  使用数学方法 112 5.3.3  使用宏 112 5.3.4  使用代码移动机器人 112 5.3.5  使用 SketchUp 进行 3D 建模 116 5.4  在 ROS 中仿真 117 5.4.1  在 Gazebo 中使用 URDF3D 模型 117 5.4.2  在 Gazebo 中添加传感器 120 5.4.3  在 Gazebo 中加载和使用 地图 121 5.4.4  在 Gazebo 中移动机器人 123 5.5  本章小结 125 第 6 章 机器视觉 126 6.1  连接和运行摄像头 128 6.1.1  FireWire IEEE1394 摄像头 128 6.1.2  USB 摄像头 132 6.2  使用 OpenCV 制作 USB 摄像头 驱动程序 133 6.2.1  创建 USB 摄像头驱动 功能包 134 6.2.2  使用 ImageTransport API 发布摄像头帧 135 6.2.3  使用 cv_bridge 进行 OpenCV 和 ROS 图像处理 138 XII 6.2.4  使用 ImageTransport 发布 图像 139 6.2.5  在 ROS 中使用 OpenCV 139 6.2.6  显示摄像头输入的图像 140 6.3  如何标定摄像头 140 6.4  ROS 图像管道 147 6.5  对于计算机视觉任务有用的 ROS 功能包 152 6.6  使用 viso2 执行视觉测距 153 6.6.1  摄像头位姿标定 154 6.6.2  运行 viso2 在线演示 156 6.6.3  使用低成本双目摄像头 运行 viso2 158 6.7  本章小结 159 第 7 章 导航功能包集入门 160 7.1  ROS 导航功能包集 160 7.2  创建转换 161 7.2.1  创建广播机构 162 7.2.2  创建侦听器 162 7.2.3  查看坐标变换树 164 7.3  发布传感器信息 165 7.4  发布里程数据 168 7.4.1  Gazebo 如何获取里程 数据 169 7.4.2  创建自定义里程数据 171 7.5  创建基础控制器 175 7.5.1  使用 Gazebo 创建里程 数据 176 7.5.2  创建基础控制器 178 7.6  使用 ROS 创建地图 180 7.6.1  使用 map_server 保存 地图 181 7.6.2  使用 map_server 加载 地图 182 7.7  本章小结 183 第 8 章 导航功能包集进阶 184 8.1  创建功能包 184 8.2  创建机器人配置 184 8.3  配置全局和局部代价地图 187 8.3.1  基本参数的配置 187 8.3.2  全局代价地图的配置 188 8.3.3  局部代价地图的配置 189 8.4  基本局部规划器配置 189 8.5  为导航功能包集创建启动文件 190 8.6  为导航功能包集设置 rviz 191 8.6.1  2D 位姿估计 191 8.6.2  2D 导航目标 192 8.6.3  静态地图 193 8.6.4  点云 193 8.6.5  机器人立足点 193 8.6.6  障碍 194 8.6.7  膨胀障碍 194 8.6.8  全局规划 195 8.6.9  局部规划 195 8.6.10  规划器规划 196 8.6.11  当前目标 196 8.7  自适应蒙特卡罗定位 197 8.8  避免障碍 199 8.9  发送目标 200 8.10  本章小结 202 XIII 第 9 章 在实践中学习 203 9.1  REEM——类人形 PAL 机器人 204 9.1.1  从官方软件源安装 REEM 205 9.1.2  使用 Gazebo 仿真环境 运行 REEM 208 9.2  PR2——柳树车库机器人 210 9.2.1  安装 PR2 仿真环境 210 9.2.2  在仿真环境中运行 PR2 211 9.2.3  生成地图与定位 214 9.2.4  在仿真环境中运行 PR2 演示程序 216 9.3  Robonaut 2——NASA 的敏捷 型人形机器人 217 9.3.1  从软件源安装 Robonaut 2 217 9.3.2  在国际空间站的固定支座 上运行 Robonaut2 218 9.4  Husky——Clearpath 的轮式 机器人 222 9.4.1  安装 Husky 仿真环境 222 9.4.2  运行 Husky 仿真环境 222 9.5  TurtleBot——低成本移动 机器人 224 9.5.1  安装 TurtleBot 仿真环境 224 9.5.2  运行 TurtleBot 仿真环境 224 9.6  本章小结 225 第 1 章 ROS 系统入门 欢迎来到本书的第 1 章。本章会介绍如何安装 ROS 系统。与其说 ROS 是一个操作系 统,不如说它是一种新的标准化机器人软件框架。通过 ROS,你可以使用大量的示例代码和 开源程序轻松地完成机器人编程和控制。同时,你还能够理解如何使用各种传感器与执行机 构,并为你的机器人增加如自动导航和视觉定位等新的功能。在这里,我们要感谢相关的基 金会及社区对开源软件的贡献,并不断地开发出最新的算法和功能使 ROS 系统不断进步。 本书包含以下知识: ● 在特定版本的 Ubuntu 系统下安装 ROS 框架 ● 学习 ROS 的基本操作 ● 调试数据和数据可视化 ● 在 ROS 框架下对机器人编程 ● 创造 3D 模型并进行仿真 ● 使用导航功能包集使机器人进行自动导航 在本章中,首先要在 Ubuntu 系统中安装完整版本的 ROS。Ubuntu 不仅能够全面支持 ROS,而且它也是 ROS 官方推荐的操作系统。当然,你也可以在其他的操作系统中安装 ROS。但是在其他操作系统中, ROS 大多是实验性质的移植版本,因此容易出现各种安装和 程序执行错误。因此在学习和使用本书的过程中,推荐使用 Ubuntu。 在开始安装之前,首先了解一下 ROS 的历史。 Robot Operating System(ROS)是一种得到广泛使用的机器人操作与控制系统软件框 架。该框架使用了当前最流行的面向服务( SOA)的软件技术,通过网络协议将节点间数据 通信解耦。这样就能够轻松地集成不同语言不同功能的代码。 ROS 的基本原理是无需改动就 能够在不同的机器人上复用代码。基于这些,我们就可以在不同的机器人上分享和复用已经 实现的功能,而不需要做太多的工作,避免了重复劳动。 2007 年,斯坦福大学人工智能实验室 (SAIL) 在斯坦福AI 机器人项目( Stanford AI Robot project)的支持下开发了 ROS。2008 年之后,则主要在 Willow Garage 公司支持下与 其他 20 多家研究机构进行联合研发 ROS。 现在已经有很多家研究机构通过增加 ROS 支持的硬件或开放软件源代码的方式加入 ROS 系统的开发中。同样,也有很多家公司将其产品逐步进行软件迁移并在 ROS 系统中应 2 第 1 章 用。部分 ROS 系统支持的平台如下图所示。这些平台往往会开放大量的代码、示例和仿真 环境,以便开发人员轻松地开展工作。 ROS 系统已经支持这些机器人中的传感器和执行机构,同时每天 ROS 软件框架所支持 的设备也在大量增加。 ROS 提供了一个标准的操作系统环境,包括硬件抽象、底层设备控制、通用功能的实 现、进程间消息转发和功能包管理等。它将多路复用传感器、控制器、运动状态、规划目 标、执行机构及其他设备全部抽象成节点( node),并能对各个节点进程间消息的发生和接 受的处理过程通过节点状态图展示。它的各种库都是面向类 Unix 系统的( ROS 主要支持 Ubuntu Linux,而其他系统如 Fedora 和 Mac OS X 则是实验性质的)。 *-ros-pkg 包主要作为开发高级库的基础软件源。其很多功能是和 ROS 系统绑定的, 如导航库和 rviz 可视化界面都基于这个源。其中的一些库包含很多强大的工具,可以帮助我 们方便使用 ROS 并了解机器人的实时状态。其中,可视化工具、仿真环境和调试工具是最重 要的几个。 ROS 系统入门 3 ROS 是一个使用 BSD(Berkeley Software Distribution)开源协议的开源软件。无论是 商业应用,还是科学研究,它都是免费的。*-ros-pkg 包受到了多个开源协议的限制。 ROS 致力于机器人的代码复用,这样每次研发新的机器人时,开发人员和科学家们再也 不必全部推倒重来。通过 ROS,你可以集中精力做更多的事情,应用不同代码库中的代码, 再完善,并再次分享。 ROS 已经发布了多个版本,最新的版本是Groovy。在本书中,我们使用的版本是 Fuerte,因为这个版本更加稳定。因此需要说明的是,本书中的示例和教程不一定都能够在 Groovy 下使用。 下面我们会介绍如何安装 Electric 版本和 Fuerte 版本的 ROS。不同的 ROS 版本对应 不同的 Ubuntu 版本,所以某些机器人可能仍然使用老版本的 Ubuntu。即使在本书中我 们使用 Fuerte,但是在实际工作中,你仍然可能需要安装 Electric 以便运行一些老版本的 代码。 如前文所述,本书中所使用的操作系统是 Ubuntu,如果你习惯使用其他操作系统又想完 成本书的学习,最好的选择就是安装一个带有 Ubuntu 的虚拟机。因此,我会在最后介绍虚 拟机的安装方法。 当然,如果你想在其他系统中安装 ROS,你可以根据链接 http://wiki.ros.org/fuerte/ Installation 中的指导来完成。 1.1 使用软件源安装 ROS Electric 安装 ROS 有多种方法,你可以按照本书的方法直接使用软件源,也可以使用源文件并 编译后安装。使用软件源的方法相对安全,不容易出现错误。 按照本节介绍的步骤,你可以在自己的电脑上逐步安装 ROS Electric,安装过程详见官 网页面 http://wiki.ros.org/electric/Installation。 我们假设你知道Ubuntu 软件源(repository) 的含义,并且知道如何管理它。如果你有任何 疑问请查询https://help.ubuntu.com/community/ Repositories/Ubuntu 了解相关知识。 在开始安装之前,需要首先配置软件源,为 此需要先把软件源属性设为 restricted、universal、 multiverse,为了检查你的 Ubuntu 版本是否支持这 些软件源,请双击打开你桌面左面的 Ubuntu 软件 中心(Ubuntu Software Center),如右图所示。 打开 Edit | Software Sources 标签页,你能看 到以下界面,你要保证各个选项与下图中一致。 4 第 1 章 通常情况下,这些选项都是选中的,因此这一步骤没有什么问题。 1.1.1 添加软件源到 sources.list 文件中 在这一步中,你应该先选择 Ubuntu 的版本,在多种版本的操作系统中都可以安装 ROS Electric。你可以使用任何一个版本,但是推荐最新版本,以避免发生问题。 ● 基于 Ubuntu 的发行版,如 Ubuntu Lucid Lynx(10.04),安装软件源的具体方法如下: Getting Started with ROS [ 12 ] Adding repositories to your sources.list file In this step, you have to select your Ubuntu version. It is possible to install ROS Electric in various versions of the operating system. You can use any of them, but we recommend you to always use the most updated version to avoid problems: • A specific way to install the repositories for an Ubuntu-based distro such as Ubuntu Lucid Lynx (10.04) is as follows: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu lucid main" > /etc/apt/sources.list.d/ros-latest.list' • A generic way for installing any distro of Ubuntu relies on the lsb_release command that is supported on all Linux Debian-based distro: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu `lsb_ release -cs` main" > /etc/apt/sources.list.d/ros-latest.list' Once you have added the correct repository, your operating system knows where to download the programs that need to be installed on your system. Setting up your keys This step is to confirm that the origin of the code is correct, and nobody has modified the code or programs without the knowledge of the owner. Normally, when you add a new repository, you have to add the keys of that repository so that it is added to your system's trusted list: $ wget http://packages.ros.org/ros.key -O - | sudo apt-key add – We can now be sure that the code came from an authorized site. Installation Now we are ready to start the installation. Before we start, it would be better to update the software to avoid problems with libraries or the wrong software version. We do this with the following command: $ sudo apt-get update ROS is huge; sometimes you will install libraries and programs that you will never use. Normally, it has four different installations depending on the final use; for example, if you are an advanced user, you may only need basic installation for a robot without enough space in the hard disk. For this book, we recommend the use of full installation because it will install everything that's necessary to make the examples and tutorials work. ● 安装任意 Ubuntu 发行版的一种通用方法是使用所有基于 Debian 的 Linux 发行版都支 持的 lsb_release 命令: Getting Started with ROS [ 12 ] Adding repositories to your sources.list file In this step, you have to select your Ubuntu version. It is possible to install ROS Electric in various versions of the operating system. You can use any of them, but we recommend you to always use the most updated version to avoid problems: • A specific way to install the repositories for an Ubuntu-based distro such as Ubuntu Lucid Lynx (10.04) is as follows: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu lucid main" > /etc/apt/sources.list.d/ros-latest.list' • A generic way for installing any distro of Ubuntu relies on the lsb_release command that is supported on all Linux Debian-based distro: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu `lsb_ release -cs` main" > /etc/apt/sources.list.d/ros-latest.list' Once you have added the correct repository, your operating system knows where to download the programs that need to be installed on your system. Setting up your keys This step is to confirm that the origin of the code is correct, and nobody has modified the code or programs without the knowledge of the owner. Normally, when you add a new repository, you have to add the keys of that repository so that it is added to your system's trusted list: $ wget http://packages.ros.org/ros.key -O - | sudo apt-key add – We can now be sure that the code came from an authorized site. Installation Now we are ready to start the installation. Before we start, it would be better to update the software to avoid problems with libraries or the wrong software version. We do this with the following command: $ sudo apt-get update ROS is huge; sometimes you will install libraries and programs that you will never use. Normally, it has four different installations depending on the final use; for example, if you are an advanced user, you may only need basic installation for a robot without enough space in the hard disk. For this book, we recommend the use of full installation because it will install everything that's necessary to make the examples and tutorials work. 一旦添加了正确的软件源,操作系统就知道去哪里下载程序,并根据命令自动安装软件。 1.1.2 设置密码 这一步是为了确认原始的代码是正确的,并且没有人在未经所有者授权的情况下修改任 何程序代码。通常情况下,当添加完软件源,你就已经添加了软件源的密码,并将其添加到 操作系统的可信任列表中。 Getting Started with ROS [ 12 ] Adding repositories to your sources.list file In this step, you have to select your Ubuntu version. It is possible to install ROS Electric in various versions of the operating system. You can use any of them, but we recommend you to always use the most updated version to avoid problems: • A specific way to install the repositories for an Ubuntu-based distro such as Ubuntu Lucid Lynx (10.04) is as follows: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu lucid main" > /etc/apt/sources.list.d/ros-latest.list' • A generic way for installing any distro of Ubuntu relies on the lsb_release command that is supported on all Linux Debian-based distro: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu `lsb_ release -cs` main" > /etc/apt/sources.list.d/ros-latest.list' Once you have added the correct repository, your operating system knows where to download the programs that need to be installed on your system. Setting up your keys This step is to confirm that the origin of the code is correct, and nobody has modified the code or programs without the knowledge of the owner. Normally, when you add a new repository, you have to add the keys of that repository so that it is added to your system's trusted list: $ wget http://packages.ros.org/ros.key -O - | sudo apt-key add – We can now be sure that the code came from an authorized site. Installation Now we are ready to start the installation. Before we start, it would be better to update the software to avoid problems with libraries or the wrong software version. We do this with the following command: $ sudo apt-get update ROS is huge; sometimes you will install libraries and programs that you will never use. Normally, it has four different installations depending on the final use; for example, if you are an advanced user, you may only need basic installation for a robot without enough space in the hard disk. For this book, we recommend the use of full installation because it will install everything that's necessary to make the examples and tutorials work. 现在我们能够确定代码来自授权网站。 1.1.3 安装 现在准备开始安装。在开始之前,最好先升级一下软件,避免错误的库版本或软件版本 产生各种问题,输入以下命令: ROS 系统入门 5 Getting Started with ROS [ 12 ] Adding repositories to your sources.list file In this step, you have to select your Ubuntu version. It is possible to install ROS Electric in various versions of the operating system. You can use any of them, but we recommend you to always use the most updated version to avoid problems: • A specific way to install the repositories for an Ubuntu-based distro such as Ubuntu Lucid Lynx (10.04) is as follows: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu lucid main" > /etc/apt/sources.list.d/ros-latest.list' • A generic way for installing any distro of Ubuntu relies on the lsb_release command that is supported on all Linux Debian-based distro: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu `lsb_ release -cs` main" > /etc/apt/sources.list.d/ros-latest.list' Once you have added the correct repository, your operating system knows where to download the programs that need to be installed on your system. Setting up your keys This step is to confirm that the origin of the code is correct, and nobody has modified the code or programs without the knowledge of the owner. Normally, when you add a new repository, you have to add the keys of that repository so that it is added to your system's trusted list: $ wget http://packages.ros.org/ros.key -O - | sudo apt-key add – We can now be sure that the code came from an authorized site. Installation Now we are ready to start the installation. Before we start, it would be better to update the software to avoid problems with libraries or the wrong software version. We do this with the following command: $ sudo apt-get update ROS is huge; sometimes you will install libraries and programs that you will never use. Normally, it has four different installations depending on the final use; for example, if you are an advanced user, you may only need basic installation for a robot without enough space in the hard disk. For this book, we recommend the use of full installation because it will install everything that's necessary to make the examples and tutorials work. ROS 非常大,有时候你会安装一些永远也用不到的库和程序。通常情况下,根据用途有 四种不同的安装方式。例如,你是一个高级用户,你只需要为你的机器人进行基本安装,而 不需要在硬盘上留过多的空间。在本书中,我们推荐完全安装,因为这样能够保证包含本书 中所有示例和教程需要的库。不用担心,如果你不知道正在安装什么,它可能是 rviz、仿真 环境或导航功能。你将会在后续章节中学习这些内容。 ● 最简单的安装方式(并且是推荐的安装方式,但你需要有足够大的硬盘空间)就是桌 面完整安装(desktop-full)。这将安装 ROS、Rx 工具箱、rviz 可视化环境(3D)、通用 机器人库、2D(如 stage)和 3D(如 Gazebo)仿真环境、导航工功能包集(移动、定位、 地图绘制、机械臂控制)和其他感知库如视觉、激光雷达和 RGB-D 摄像头(深度摄 像 头 ): Chapter 1 [ 13 ] Don't worry if you don't know what you are installing right now, be it rviz, simulators, or navigation. You will learn everything in the upcoming chapters: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers or RGB-D cameras: $ sudo apt-get install ros-electric-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-electric-desktop • If you only want the bare bones, install ROS-base, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-electric-ros-base • Finally, along with whatever option you choose from this list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-electric-STACK The environment setup Congratulations! You are in this step because you have an installed version of ROS on your system. To start using it, the system must know where the executable or binary files as well as other commands are. To do this, you need to execute the next script. If you install another ROS distro in addition to your existing version, you can work with both by calling the script of the one you need every time, since this script simply sets your environment. Here, we will use the one for ROS Electric, but just change electric to fuerte or groovy in the following command if you want to try other distros: $ source /opt/ros/electric/setup.bash ● 如果你没有足够的硬盘空间,或更喜欢安装特定部分功能包集,那么第一次安装可以 仅安装桌面安装文件,包括 ROS、Rx 工具箱、rviz 和其他通用机器人库。之后在需 要的时候,再安装其他功能包集(使用 apt 命令并查找 ros-electric-* 功能包集): Chapter 1 [ 13 ] Don't worry if you don't know what you are installing right now, be it rviz, simulators, or navigation. You will learn everything in the upcoming chapters: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers or RGB-D cameras: $ sudo apt-get install ros-electric-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-electric-desktop • If you only want the bare bones, install ROS-base, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-electric-ros-base • Finally, along with whatever option you choose from this list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-electric-STACK The environment setup Congratulations! You are in this step because you have an installed version of ROS on your system. To start using it, the system must know where the executable or binary files as well as other commands are. To do this, you need to execute the next script. If you install another ROS distro in addition to your existing version, you can work with both by calling the script of the one you need every time, since this script simply sets your environment. Here, we will use the one for ROS Electric, but just change electric to fuerte or groovy in the following command if you want to try other distros: $ source /opt/ros/electric/setup.bash ● 如果你仅想尝试一下,请安装 ROS-base。ROS-base 通常是直接安装在机器人上,尤 其是机器人并没有屏幕和人机界面,只能 TTY 远程登录的情况下。它只安装 ROS 的 编译和通信库,而没有任何的 GUI 工具: Chapter 1 [ 13 ] Don't worry if you don't know what you are installing right now, be it rviz, simulators, or navigation. You will learn everything in the upcoming chapters: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers or RGB-D cameras: $ sudo apt-get install ros-electric-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-electric-desktop • If you only want the bare bones, install ROS-base, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-electric-ros-base • Finally, along with whatever option you choose from this list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-electric-STACK The environment setup Congratulations! You are in this step because you have an installed version of ROS on your system. To start using it, the system must know where the executable or binary files as well as other commands are. To do this, you need to execute the next script. If you install another ROS distro in addition to your existing version, you can work with both by calling the script of the one you need every time, since this script simply sets your environment. Here, we will use the one for ROS Electric, but just change electric to fuerte or groovy in the following command if you want to try other distros: $ source /opt/ros/electric/setup.bash ● 最后,无论你选择哪一个选项进行安装,你都可以独立安装特定的 ROS 功能包集(将 STACK 替换成给定功能包集的名称): Chapter 1 [ 13 ] Don't worry if you don't know what you are installing right now, be it rviz, simulators, or navigation. You will learn everything in the upcoming chapters: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers or RGB-D cameras: $ sudo apt-get install ros-electric-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-electric-desktop • If you only want the bare bones, install ROS-base, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-electric-ros-base • Finally, along with whatever option you choose from this list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-electric-STACK The environment setup Congratulations! You are in this step because you have an installed version of ROS on your system. To start using it, the system must know where the executable or binary files as well as other commands are. To do this, you need to execute the next script. If you install another ROS distro in addition to your existing version, you can work with both by calling the script of the one you need every time, since this script simply sets your environment. Here, we will use the one for ROS Electric, but just change electric to fuerte or groovy in the following command if you want to try other distros: $ source /opt/ros/electric/setup.bash 1.1.4 环境配置 恭喜你!能到这一步,说明你已经安装了某个版本的 ROS。为了使用 ROS,必须让操 作系统知道可执行文件或二进制文件与系统命令的关联,这就需要执行下面的脚本。如果 你已经安装了某一版本的 ROS,并想安装另一个 ROS 发行版,你可以每一次都调用你所需 要的对应脚本。因为这个脚本能够非常方便地设置你的环境变量。在这里,我们将会使用 ROS Electric,但如果你想尝试其他的发行版,只需要把下面的命令中的 electric 替换成 fuerte 或 groovy 即可: Chapter 1 [ 13 ] Don't worry if you don't know what you are installing right now, be it rviz, simulators, or navigation. You will learn everything in the upcoming chapters: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers or RGB-D cameras: $ sudo apt-get install ros-electric-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-electric-desktop • If you only want the bare bones, install ROS-base, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-electric-ros-base • Finally, along with whatever option you choose from this list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-electric-STACK The environment setup Congratulations! You are in this step because you have an installed version of ROS on your system. To start using it, the system must know where the executable or binary files as well as other commands are. To do this, you need to execute the next script. If you install another ROS distro in addition to your existing version, you can work with both by calling the script of the one you need every time, since this script simply sets your environment. Here, we will use the one for ROS Electric, but just change electric to fuerte or groovy in the following command if you want to try other distros: $ source /opt/ros/electric/setup.bash 如果你在 shell 中输入 roscore,那么将会看到有程序启动。这是测试是否完成 ROS 安 6 第 1 章 装和 ROS 安装是否正确的最佳方法。 请注意,如果你再打开一个 shell 窗口,并输入 roscore 或其他 ROS 命令,就行不通 了。这是因为需要你再一次执行脚本来配置全局变量和 ROS 的安装路径。 如何能够让系统记住你的这些配置呢?你只需要在命令行脚本末尾处增加 .bashrc 文 件,这样当你再次启动 shell 的时候,会自动执行这些命令并对环境进行配置。命令脚本如下: Getting Started with ROS [ 14 ] If you type roscore in the shell, you will see that something is starting. This is the best test to find out whether you have ROS and whether it is installed correctly. Note that if you open another shell and type roscore or any other ROS command, it does not work. This is because it is necessary to execute the script again to configure the global variables and path for the location where ROS is installed. It is very easy to solve this. You only need to add the script at the end of your .bashrc file and when you start a new shell, the script will execute and you will have the environment configured. Use the following command to do this: $ echo "source /opt/ros/electric/setup.bash" >> ~/.bashrc $ source ~/.bashrc If it happens that you have more than a single ROS distribution installed on your system, your ~/.bashrc file must source only setup.bash of the version you are currently using. This is because the last call will override the environment set of the others, as we have mentioned previously, to have several distros living in the same system and switch among them. Installing ROS Fuerte – using repositories In this section, we are going to install ROS Fuerte on our computer. You can have different versions installed on the same computer without problems; you only need to select the version that you want to use in the .bashrc file. You will see how to do this in this section. If you want to see the official page where this process is explained, you can visit the following URL: http://wiki.ros.org/fuerte/Installation. You can install ROS using two methods: using repositories and using source code. Normal users will only need to make an installation using repositories to get a functional installation of ROS. You can install ROS using the source code but this process is for advanced users and we don't recommend it. Configuring your Ubuntu repositories First, you must check that your Ubuntu accepts restricted, universal, and multiversal repositories. Refer to the Installing ROS Electric – using repositories section if you want to see how to do it. Normally, Ubuntu is configured to allow these repositories and you won't have problems with this step. 如果安装了多个ROS 的发行版,~/.bashrc 文件必须来自当前正在使用版本的 setup.bash。这是因为最后一次调用将覆盖环境中的其他设置。正如我们前面所提到的, 在同一个系统中安装多个发行版时需要在它们之间进行切换。 1.2 使用软件源安装 ROS Fuerte 在本节中,我们将在计算机上安装 ROS Fuerte。你可以在同一台计算机上安装不同版 本,这都没有问题。只需要在 .bashrc 文件中选择你想要使用的版本。你将在本节学习如 何做到这一点。 如果你想在官方页面查看对这个过程的解释,可以访问http://wiki.ros.org/fuerte/ Installation。 你可以使用两种方法安装 ROS :使用软件源和使用源代码。普通用户可以使用软件源来 完成 ROS 的安装。你也可以使用源代码安装 ROS,但这个方法仅建议高级用户使用,不建 议普通用户这样做。 1.2.1 配置 Ubuntu 软件源 在开始安装之前,首先配置软件源,为此先把软件源属性设为 restricted、universal、 multiverse。具体安装方法请参考 1.1 节的相关内容。 通常情况下,Ubuntu 默认支持这些选项,并不需要进行特殊设置。 1.2.2 配置 source.list 文件 现在我们需要添加下载软件的 URL。由于 ROS Fuerte 并不支持 Ubuntu 10.10 Maverick 和 11.04 Natty,因此我们需要在电脑上安装 Ubuntu 10.04、11.10 或 12.04。 在本书中,我们选择 Ubuntu 12.04。在这个版本下,所有的示例程序都被检查、编译和 执行过。 打开 shell 命令行,输入以下命令: Chapter 1 [ 15 ] Setting up your source.list file Now we are going to add the URLs from where we can download the code. Note that ROS Fuerte doesn't work for Maverick and Natty, so you must have Ubuntu 10.04, 11.10, or 12.04 on your computer. For this book we have used Ubuntu 12.04 and it works fine. All the examples have been checked, compiled, and executed in this version of Ubuntu. Open a new shell and type the following command, as we did before, which should work for any Ubuntu version you have: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list' Setting up your keys It is important to add the key because with it we can be sure that we are downloading the code from the right place and nobody has modified it. If you have followed the steps to install ROS Electric, you don't need to do this again as you have already completed this earlier; if not, add the repository using the following command: $ wget http://packages.ros.org/ros.key -O - | sudo apt-key add – Installation We are ready to install ROS Fuerte at this point. Before doing something, it is necessary to update all the programs used by ROS. We do it to avoid incompatibility problems. Type the following command in a shell and wait: $ sudo apt-get update Depending on whether you had the system updated or not, the command will take more or less time to finish. ROS has a lot of parts and installing the full system can be heavy in robots without enough features. For this reason, you can install various versions depending on what you want to install. 这些命令在任何版本的 Ubuntu 下都应该能够正确运行。 ROS 系统入门 7 1.2.3 设置密码 为软件源增加密码是非常重要的,因为这样能够保证源代码是正确的,并且没有人在未 经所有者知晓的情况下修改代码或程序。 如果你已经按照步骤安装完成 ROS Electric,那么你并不需要重新设置密码;如果你没 有安装过 ROS Electric,那么你需要输入如下命令: Chapter 1 [ 15 ] Setting up your source.list file Now we are going to add the URLs from where we can download the code. Note that ROS Fuerte doesn't work for Maverick and Natty, so you must have Ubuntu 10.04, 11.10, or 12.04 on your computer. For this book we have used Ubuntu 12.04 and it works fine. All the examples have been checked, compiled, and executed in this version of Ubuntu. Open a new shell and type the following command, as we did before, which should work for any Ubuntu version you have: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list' Setting up your keys It is important to add the key because with it we can be sure that we are downloading the code from the right place and nobody has modified it. If you have followed the steps to install ROS Electric, you don't need to do this again as you have already completed this earlier; if not, add the repository using the following command: $ wget http://packages.ros.org/ros.key -O - | sudo apt-key add – Installation We are ready to install ROS Fuerte at this point. Before doing something, it is necessary to update all the programs used by ROS. We do it to avoid incompatibility problems. Type the following command in a shell and wait: $ sudo apt-get update Depending on whether you had the system updated or not, the command will take more or less time to finish. ROS has a lot of parts and installing the full system can be heavy in robots without enough features. For this reason, you can install various versions depending on what you want to install. 1.2.4 安装 我们现在准备安装 ROS Fuerte。在安装之前,需要先升级一下 ROS 可能使用到的程序。 这样可以避免出现兼容性问题。 输入以下命令并等待: Chapter 1 [ 15 ] Setting up your source.list file Now we are going to add the URLs from where we can download the code. Note that ROS Fuerte doesn't work for Maverick and Natty, so you must have Ubuntu 10.04, 11.10, or 12.04 on your computer. For this book we have used Ubuntu 12.04 and it works fine. All the examples have been checked, compiled, and executed in this version of Ubuntu. Open a new shell and type the following command, as we did before, which should work for any Ubuntu version you have: $ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list' Setting up your keys It is important to add the key because with it we can be sure that we are downloading the code from the right place and nobody has modified it. If you have followed the steps to install ROS Electric, you don't need to do this again as you have already completed this earlier; if not, add the repository using the following command: $ wget http://packages.ros.org/ros.key -O - | sudo apt-key add – Installation We are ready to install ROS Fuerte at this point. Before doing something, it is necessary to update all the programs used by ROS. We do it to avoid incompatibility problems. Type the following command in a shell and wait: $ sudo apt-get update Depending on whether you had the system updated or not, the command will take more or less time to finish. ROS has a lot of parts and installing the full system can be heavy in robots without enough features. For this reason, you can install various versions depending on what you want to install. 这个命令会花一定时间才能完成,具体取决于你是否升级过系统。 ROS 同样有很多个组件,在一个机器人上完整安装全部系统会略显笨重而没有一点个 性。基于这个原因,你可以根据需要选择安装。 在本书中,我们还是会安装完整版本。这个版本会安装所有的示例、功能包集和程序。 考虑到我们在本书的后续章节会使用大量的工具,完整安装是一个不错的选择。当然,如果 你并不想现在就完整安装,可以之后再进行。 ● 最简单的安装方式(并且是推荐的安装方式,但你需要有足够大的硬盘空间)就是桌 面完整安装(desktop-full)。这将安装 ROS、Rx 工具箱、rviz 可视化环境(3D)、通用 机器人库、2D(如 stage)和 3D(如 Gazebo)仿真环境、导航功能包集(移动、定位、 地图绘制、路径规划、机械臂控制)和其他感知库如视觉、激光雷达和 RGB-D 摄像 头(深度摄像头): Getting Started with ROS [ 16 ] For this book, we are going to install the full version. This version will install all the examples, stacks, and programs. This is a good option for us because in some chapters of this book, we will need to use tools, and if we don't install it now, we will have to do it later: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers, or RGB-D cameras: $ sudo apt-get install ros-fuerte-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-fuerte-desktop • If you only want the bare bones, install ROS-comm, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-fuerte-ros-comm • Finally, along with whatever option you choose from the list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-fuerte-STACK Do not worry if you are installing things that you do not know. In the upcoming chapters, you will learn about everything you are installing and how to use it. When you gain experience with ROS, you can make basic installations in your robots using only the core of ROS, using less resources, and taking only what you need. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. ● 如果你没有足够的硬盘空间,或更喜欢安装部分功能包集,那么第一次仅安装桌面 安装文件,包括 ROS、Rx 工具箱、rviz 和其他通用机器人库。你可以在需要的时候, 再安装其他的功能包集(使用 apt 命令并查找 ros-fuerte-* 功能包集): Getting Started with ROS [ 16 ] For this book, we are going to install the full version. This version will install all the examples, stacks, and programs. This is a good option for us because in some chapters of this book, we will need to use tools, and if we don't install it now, we will have to do it later: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers, or RGB-D cameras: $ sudo apt-get install ros-fuerte-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-fuerte-desktop • If you only want the bare bones, install ROS-comm, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-fuerte-ros-comm • Finally, along with whatever option you choose from the list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-fuerte-STACK Do not worry if you are installing things that you do not know. In the upcoming chapters, you will learn about everything you are installing and how to use it. When you gain experience with ROS, you can make basic installations in your robots using only the core of ROS, using less resources, and taking only what you need. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. ● 如果你仅想尝试一下,请安装 ROS-base。它通常是直接安装在机器人上,尤其是机器 人并没有屏幕和人机界面,只能 TTY 远程登录的情况下。只安装 ROS 的编译和通信 库,而没有任何的 GUI 工具: Getting Started with ROS [ 16 ] For this book, we are going to install the full version. This version will install all the examples, stacks, and programs. This is a good option for us because in some chapters of this book, we will need to use tools, and if we don't install it now, we will have to do it later: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers, or RGB-D cameras: $ sudo apt-get install ros-fuerte-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-fuerte-desktop • If you only want the bare bones, install ROS-comm, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-fuerte-ros-comm • Finally, along with whatever option you choose from the list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-fuerte-STACK Do not worry if you are installing things that you do not know. In the upcoming chapters, you will learn about everything you are installing and how to use it. When you gain experience with ROS, you can make basic installations in your robots using only the core of ROS, using less resources, and taking only what you need. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. ● 最后,无论选择哪一个选项进行安装,你都可以独立安装特定的 ROS 功能包集(将 8 第 1 章 STACK 替换成给定功能包集的名称): Getting Started with ROS [ 16 ] For this book, we are going to install the full version. This version will install all the examples, stacks, and programs. This is a good option for us because in some chapters of this book, we will need to use tools, and if we don't install it now, we will have to do it later: • The easiest (and recommended if you have enough hard disk space) installation is known as desktop-full. It comes with ROS, the Rx tools, the rviz visualizer (for 3D), many generic robot libraries, the simulator in 2D (such as stage) and 3D (usually Gazebo), the navigation stack (to move, localize, do mapping, and control arms), and also perception libraries using vision, lasers, or RGB-D cameras: $ sudo apt-get install ros-fuerte-desktop-full • If you do not have enough disk space, or you prefer to install only a few stacks, first install only the desktop installation file, which comes only with ROS, the Rx tools, rviz, and generic robot libraries. Later, you can install the rest of the stacks when you need them (using aptitude and looking for the ros-electric-* stacks, for example): $ sudo apt-get install ros-fuerte-desktop • If you only want the bare bones, install ROS-comm, which is usually recommended for the robot itself or computers without a screen or just a TTY. It will install the ROS package with the build and communication libraries and no GUI tools at all: $ sudo apt-get install ros-fuerte-ros-comm • Finally, along with whatever option you choose from the list, you can install individual/specific ROS stacks (for a given stack name): $ sudo apt-get install ros-fuerte-STACK Do not worry if you are installing things that you do not know. In the upcoming chapters, you will learn about everything you are installing and how to use it. When you gain experience with ROS, you can make basic installations in your robots using only the core of ROS, using less resources, and taking only what you need. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. 在安装过程中,请不要担心你对所安装的软件并不了解。在后面的章节,你会学到包括 如何使用在内的所有相关知识。 当你逐渐积累 ROS 系统的经验之后,就能够在机器人上仅安装 ROS 内核,使用更少的 资源,并且逐项添加你所需要的工具。 1.2.5 环境配置 现在 ROS 安装完毕,并准备开始使用。这时你需要向 Ubuntu 提供 ROS 的安装路径。 打开一个新的 shell 并输入以下命令: Chapter 1 [ 17 ] The environment setup Now that you have installed ROS, to start using it, you must provide Ubuntu with the path where ROS is installed. Open a new shell and type the following command: $ roscore roscore: command not found You will see this message because Ubuntu does not know where to search for the commands. To solve it, type the following command in a shell: $ source /opt/ros/fuerte/setup.bash Then, type the roscore command once again, and you will see the following output: ... started roslaunch server http://localhost:45631/ ros_comm version 1.8.11 SUMMARY ======== PARAMETERS * /rosdistro * /rosversion NODES auto-starting new master .... This means that Ubuntu knows where to find the commands to run ROS. Note that if you open another shell and type roscore, it will not work. This is because it is necessary to add this script within the .bashrc file. So, every time you start a new shell, the scripts will run because .bashrc always runs when a shell runs. Use the following commands to add the script: $ echo "source /opt/ros/fuerte/setup.bash" >> ~/.bashrc $ source ~/.bashrc 之所以会看到这样的消息,主要是因为 Ubuntu 并不知道去哪里找这个命令对应的执行 程序。为了解决这个问题,需要在 shell 环境中输入以下命令: Chapter 1 [ 17 ] The environment setup Now that you have installed ROS, to start using it, you must provide Ubuntu with the path where ROS is installed. Open a new shell and type the following command: $ roscore roscore: command not found You will see this message because Ubuntu does not know where to search for the commands. To solve it, type the following command in a shell: $ source /opt/ros/fuerte/setup.bash Then, type the roscore command once again, and you will see the following output: ... started roslaunch server http://localhost:45631/ ros_comm version 1.8.11 SUMMARY ======== PARAMETERS * /rosdistro * /rosversion NODES auto-starting new master .... This means that Ubuntu knows where to find the commands to run ROS. Note that if you open another shell and type roscore, it will not work. This is because it is necessary to add this script within the .bashrc file. So, every time you start a new shell, the scripts will run because .bashrc always runs when a shell runs. Use the following commands to add the script: $ echo "source /opt/ros/fuerte/setup.bash" >> ~/.bashrc $ source ~/.bashrc 然后,再次输入 roscore 命令,你会看到以下输出: Chapter 1 [ 17 ] The environment setup Now that you have installed ROS, to start using it, you must provide Ubuntu with the path where ROS is installed. Open a new shell and type the following command: $ roscore roscore: command not found You will see this message because Ubuntu does not know where to search for the commands. To solve it, type the following command in a shell: $ source /opt/ros/fuerte/setup.bash Then, type the roscore command once again, and you will see the following output: ... started roslaunch server http://localhost:45631/ ros_comm version 1.8.11 SUMMARY ======== PARAMETERS * /rosdistro * /rosversion NODES auto-starting new master .... This means that Ubuntu knows where to find the commands to run ROS. Note that if you open another shell and type roscore, it will not work. This is because it is necessary to add this script within the .bashrc file. So, every time you start a new shell, the scripts will run because .bashrc always runs when a shell runs. Use the following commands to add the script: $ echo "source /opt/ros/fuerte/setup.bash" >> ~/.bashrc $ source ~/.bashrc 这意味着 Ubuntu 已经知道了到哪里去寻找这条命令所对应的执行程序,并启动了 ROS。 而如果你重新打开一个 shell 命令行,并再次输入 roscore,就又不管用了。这是因为你必 须将这个命令行脚本加入 .bashrc 文件中。这样在 shell 打开时 .bashrc 会自动运行,所 以每次你打开一个新的 shell,这个配置环境变量的脚本都会运行。 在命令行中使用以下脚本命令: ROS 系统入门 9 Chapter 1 [ 17 ] The environment setup Now that you have installed ROS, to start using it, you must provide Ubuntu with the path where ROS is installed. Open a new shell and type the following command: $ roscore roscore: command not found You will see this message because Ubuntu does not know where to search for the commands. To solve it, type the following command in a shell: $ source /opt/ros/fuerte/setup.bash Then, type the roscore command once again, and you will see the following output: ... started roslaunch server http://localhost:45631/ ros_comm version 1.8.11 SUMMARY ======== PARAMETERS * /rosdistro * /rosversion NODES auto-starting new master .... This means that Ubuntu knows where to find the commands to run ROS. Note that if you open another shell and type roscore, it will not work. This is because it is necessary to add this script within the .bashrc file. So, every time you start a new shell, the scripts will run because .bashrc always runs when a shell runs. Use the following commands to add the script: $ echo "source /opt/ros/fuerte/setup.bash" >> ~/.bashrc $ source ~/.bashrc 和前面提到的一样,setup.bash 只能为一个 ROS 发行版进行初始化配置。试想一下, 当你同时安装了 ROS Electric 和 Fuerte,而平时需要使用 Fuerte 作为常用的版本。如果你想 在 shell 环境中更改版本,只需要输入以下命令: Getting Started with ROS [ 18 ] As mentioned before, only source setup.bash for one ROS distribution. Imagine that you had Electric and Fuerte installed on your computer, and you are using Fuerte as the normal version. If you want to change the version used in a shell, you only have to type the following command: $ source /opt/ros/electric/setup.bash If you want to use another version on a permanent basis, you must change the .bashrc file and put the correct script for your version. Standalone tools ROS has some tools that need to be installed after the principal installation. These tools will help us install dependencies between programs to compile, download, and install packages from ROS. These tools are rosinstall and rosdep. We recommend installing them because we will use them in the upcoming chapters. To install these tools, type the following command in a shell: $ sudo apt-get install python-rosinstall python-rosdep Now we have a full installation of ROS on our system. As you can see, only a few steps are necessary to do it. It is possible to have two or more versions of ROS installed on our computer. Furthermore, you can install ROS on a virtual machine if you don't have Ubuntu installed on your computer. In the next section, we will explain how to install a virtual machine and use a drive image with ROS. Perhaps this is the best way to get ROS for new users. How to install VirtualBox and Ubuntu VirtualBox is a general-purpose, full virtualizer for x86 hardware, targeted at server, desktop, and embedded use. VirtualBox is free and supports all the major operating systems and pretty much every Linux flavor out there. As we recommend the use of Ubuntu, you perhaps don't want to change the operating system of your computer. Tools such as VirtualBox exist for this purpose and help us virtualize a new operating system on our computer without making any changes to the original. 如果你希望使用其他版本作为常用的版本,只需要修改 .bashrc 文件并将所需版本的 相关脚本加入文件中。 1.2.6 独立工具 ROS 中的很多工具是需要在 ROS 安装之后进行独立安装的。这些工具能够帮助我们对 编程和编译的安装依赖项进行管理、下载和安装 ROS 程序等。这些工具包括 rosinstall 和 rosdep。我们推荐将这两个工具都安装,因为在后续的章节中需要使用它们。我们需要 在 shell 命令行中输入以下命令: Getting Started with ROS [ 18 ] As mentioned before, only source setup.bash for one ROS distribution. Imagine that you had Electric and Fuerte installed on your computer, and you are using Fuerte as the normal version. If you want to change the version used in a shell, you only have to type the following command: $ source /opt/ros/electric/setup.bash If you want to use another version on a permanent basis, you must change the .bashrc file and put the correct script for your version. Standalone tools ROS has some tools that need to be installed after the principal installation. These tools will help us install dependencies between programs to compile, download, and install packages from ROS. These tools are rosinstall and rosdep. We recommend installing them because we will use them in the upcoming chapters. To install these tools, type the following command in a shell: $ sudo apt-get install python-rosinstall python-rosdep Now we have a full installation of ROS on our system. As you can see, only a few steps are necessary to do it. It is possible to have two or more versions of ROS installed on our computer. Furthermore, you can install ROS on a virtual machine if you don't have Ubuntu installed on your computer. In the next section, we will explain how to install a virtual machine and use a drive image with ROS. Perhaps this is the best way to get ROS for new users. How to install VirtualBox and Ubuntu VirtualBox is a general-purpose, full virtualizer for x86 hardware, targeted at server, desktop, and embedded use. VirtualBox is free and supports all the major operating systems and pretty much every Linux flavor out there. As we recommend the use of Ubuntu, you perhaps don't want to change the operating system of your computer. Tools such as VirtualBox exist for this purpose and help us virtualize a new operating system on our computer without making any changes to the original. 现在我们已经在系统中安装了一个完整版本的 ROS。如你所见,只有部分步骤是必须做的。 你可以在机器上安装两个甚至更多的ROS 发行版。另外,如果你的电脑并不使用 Ubuntu 系统,你可以在虚拟机中安装 ROS。下一节我们将介绍如何安装虚拟机和使用镜像 而且这可能是对于初学者来说最好的方法。 1.3 如何安装 VirtualBox 和 Ubuntu VirtualBox 是一个通用的完整的,适用于 x86 硬件,定位于服务器、台式机和嵌入式应 用的虚拟机。 VirtualBox 是免费的,支持所有主流的操作系统。几乎每一个 Linux 爱好者都 使用它。 由于我们推荐使用 Ubuntu,你可能不希望更改计算机现有的操作系统。而如 VirtualBox 之类的工具就可以满足此类需求。它能帮助我们在电脑上建立虚拟的新操作系统,而无需对 电脑硬件做任何改动。 在后面的章节中,我们将展示如何安装 VirtualBox 和 Ubuntu。此外,通过安装虚拟机, 你可以在一个干净的操作系统中完成开发。如果你遇到任何问题,能够快速重启计算机解 决;也可以备份虚拟机及所有必要的机器人安装文件。 1.3.1 下载 VirtualBox 第一步是下载 VirtualBox 的安装文件。在编写本书时,以下链接能够下载最新的可用 版本: 10 第 1 章 ● https://www.virtualbox.org/wiki/Downloads ● http://download.virtualbox.org/virtualbox/4.2.0/VirtualBox- 4.2.1-80871-OSX.dmg 一旦安装完成,你就需要下载 Ubuntu 的镜像文件。在本教程中,我们使用了一个已经 安装了 ROS Ruerte 的 Ubuntu 镜像文件。你可以通过以下链接下载: http://nootrix.com/wp-content/uploads/2012/08/ROS.ova。 你也可以找到带有 Ubuntu 和 ROS 的其他虚拟机,但是我们还是将使用这个 ROS 官网 推荐的版本。 1.3.2 创建虚拟机 通过下载好的文件创建一个虚拟机非常简单,只需要按照本节的内容一步一步进行即 可。打开 VirtualBox 虚拟机软件并打开 File | Import Appliance...,然后点击 Open appliance 并 选择之前下载好的 ROS.ova 文件。 在下一个窗口中,可以配置新虚拟机的参数。我们保持默认配置并且仅仅改变虚拟机的 名称。这个名称帮助我们区分不同的虚拟机。我们推荐给它起一个容易理解的名称,在这里 我们使用本书的名称。 点击 Import 按钮,并在下一个窗口中接受软件授权许可。然后,你将看到一个进度条。 这表明 VirtualBox 正在复制虚拟机镜像文件。 ROS 系统入门 11 需要说明的是,这个过程并不会影响原有的 ROS.ova 文件,并且你可以通过对原文件 进行多次复制创建多个虚拟机。 复制过程所需要的时间取决于你计算机的执行速度。当它完成时,你可以点击 Start 按 钮启动你的虚拟机。需要注意的是,如果你的机器上有多个虚拟机,在启动前应该选择正确 的那一个。当然,在我们这个例子里只有一个虚拟机。 有时候会出现如下图所示的错误提示。这是因为电脑没有正确的 USB 2.0 驱动程序。你 可以通过安装 Oracle VM VirtualBox 扩展包( Extension Pack)来解决问题,当然你也可以通 过在虚拟机中禁用 USB 来解决。 为了禁用 USB,在虚拟机上右键单击并选择 Settings。在工具栏中,选择 Ports | USB, 并取消勾选 Enable USB 2.0 (EHCI) Controller。重启虚拟机,就不会再出现任何问题。 12 第 1 章 虚拟机启动之后,你能看到完成 ROS 安装之后的 Ubuntu 12.04 界面,如下图显示: 当完成这些步骤后,你就有了一个能够在这本书中使用的完整版本的 ROS Fuerte。你可 以运行所有的例子和我们将使用的功能包集。遗憾的是, VirtualBox 在使用部分实际外接设 备的时候会有问题,并且你可能无法使用这个 ROS Fuerte 镜像完成第 4 章中列出的步骤。 1.4 本章小结 本章中,我们已经学会了在 Ubuntu 系统下安装两个不同版本的ROS (Electric 和 Fuerte)。通过这些步骤,你已经在系统中安装了所有必需的软件,这些软件能够支持 ROS 和这本书的所有示例代码。你也可以使用源代码来安装 ROS。但这样做需要编译所有代码, 因此只适用于高级 Linux 用户。而我们一般建议你使用软件源安装,这样做更加通用,且通 常不会发生任何错误或问题。 如果你对 Ubuntu 系统不是很熟悉,那么建立一个虚拟机并在虚拟机上学习使用 ROS, 会更加方便。这样,如果你在安装和使用过程中发生任何问题,都无需重新安装操作系统, 只需要恢复虚拟机镜像文件,然后就可以重新开始。 通常情况下,虚拟机不能访问扩展出的实际硬件,如传感器和执行机构。尽管如此,你 仍可以用它来测试算法。 下一章将学习 ROS 的架构、和一些重要的概念,以及一些能够与 ROS 进行直接交互的 工具。 第 2 章 ROS 系统架构及示例 一旦你完成了 ROS 系统的安装,你肯定会想“好了,我已经安装完成,那么下一步是 什么呢?”本章我们会学习 ROS 系统架构及它都包含哪些部分。然后,我们会开始创建节点 和功能包,并使用 ROS 系统自带的 TurtleSim 示例。 ROS 系统的架构主要被设计和划分成了三部分,每一部分都代表一个层级的概念: ● 文件系统级(Filesystem level) ● 计算图级(Computation Graph level) ● 开源社区级(Community level) 第一级是文件系统级。在这一级,我们将会使用一组概念来解释 ROS 的内部构成、文 件夹结构,以及工作所需的核心文件。 第二级是计算图级,体现的是进程和系统之间的通信。在相关章节中,我们将看到 ROS 的各个概念和功能,包括建立系统、处理各类进程、与多台计算机通信等。 第三级是开源社区级,我们将解释一系列的工具和概念,其中包括在开发人员之间如何 共享知识、算法和代码。这个层级是非常重要的,因为在开源社区的大力支持下 ROS 系统 才得以快速成长。 2.1 理解 ROS 文件系统级 如果你刚接触 ROS,无论是准备使用 ROS 系统还是准备开发 ROS 项目,你都会觉得 ROS 中的各种概念非常奇怪。而一旦你已经驾轻就熟,那么这些概念就会变得亲切了。 文件系统级 功能包集 功能包 其他代码服务消息功能包清单 功能包集清单 14 第 2 章 与其他操作系统相类似,一个 ROS 程序的不同组件要被放在不同的文件夹下。这些文 件夹是根据功能的不同来对文件进行组织的: ● 功能包( Package) 功能包是 ROS 中软件组织的基本形式。一个功能包具有最小的 结构和最少的内容,用于创建 ROS 程序。它可以包含 ROS 运行的进程(节点)、配置 文件等。 ● 功能包清单( Manifest) 功能包清单提供关于功能包、许可信息、依赖关系、编译标 志等的信息。功能包清单是一个 manifests.xml 文件,通过这个文件能够实现对 功能包的管理。 ● 功能包集( Stack) 如果你将几个具有某些功能的功能包组织在一起,那么你将会获 得一个功能包集。在 ROS 系统中,存在大量的不同用途的功能包集,例如导航功能 包集。 ● 功能包集清单( Stack manifest) 功能包集清单 (stack.xml)提供一个关于功能包 集的清单,包括开源代码的许可证信息、与其他功能包集的依赖关系等。 ● 消息类型( Message /msg type) 消息是一个进程发送到其他进程的信息。ROS 系统有很多的标准类型消息。消息类型的说明存储在 my_package/msg/ MyMessageType.msg 中,也就是对应功能包的 msg 文件夹下。 ● 服务类型( Service/srv type) 对服务的类型进 行描述说明的文件在 ROS 系统中定义了服务的请 求和响应的数据结构。这些描述说明存储在 my_ package/srv/ MyServiceType.srv 中,也就 是对应功能包的 srv 文件夹下。 在右面的截屏中,你能看到本书第 3 章文件夹下的 内容。该文件夹就是一个功能包,其中包含了本章示例代 码、功能包清单等多项内容。第 3 章的文件中没有消息和 服务。但如果有,你还可以看到 srv 和 msg 文件夹。 2.1.1 功能包 当每次提到功能包时,指的是一种特定的文件结构和文件夹组合。这种结构如下所示: ● bin/ 这是我们编译和链接程序后,用于存储可执行文件的文件夹。 ● include/package_name/ 此目录包含了你所需要库的头文件。不要忘记导出功 能包清单,因为它们还会被其他功能包所使用。 ● msg/ 如果你要开发非标准消息,请把文件放在这里。 ● scripts/ 其中包括 Bash、Python 或任何其他脚本的可执行脚本文件。 ● src/ 这是存储程序源文件的地方。你可能会为节点创建一个文件夹或按照你希望 的方式去组织它。 ROS 系统架构及示例 15 ● srv/ 这表示的是服务(srv)类型。 ● CMakeLists.txt 这是 CMake 的生成文件。 ● manifest.xml 这是功能包清单文件。 为了创建、 修改或使用功能包,ROS 给我们提供了一些工具: ● rospack 使用此命令来获取信息或在系统中查找功能包。 ● roscreate-pkg 当你想要创建一个新的功能包时,使用此命令。 ● rosmake 使用此命令来编译功能包。 ● rosdep 此命令安装功能包的系统依赖项。 ● rxdeps 如果你想要查看功能包的依赖关系图,使用此命令。 若要在文件夹和功能包之间移动文件,ROS 提供了非常有用的 rosbash 功能包,其中 包含了一些非常类似于 Linux 命令的命令。例如: ● roscd 此命令用于更改目录,类似于 Linux 中的 cd 命令。 ● rosed 此命令用来编辑文件。 ● roscp 此命令用于从一些功能包复制文件。 ● rosd 此命令列出功能包的目录。 ● rosls 此命令列出功能包下的文件,类似于 Linux 中的 ls 命令。 文件 manifest.xml 必须在功能包中,用来说明此功能包相关的各类信息。如果你发 现在某个文件夹内包含有此文件,那么这个文件夹很可能是一个功能包。 打开一个 manifest.xml 文件,可以看到包的名称、依赖关系等信息。功能包清单的 作用就是为了更容易地安装和分发这些功能包。 在功能包清单文件中使用的两个典型标记是 标记 会显示当前功能包安装之前必须先安装哪些功能包。这是因为新的功能包会使用其他包的一 些功能。 标记告诉系统编译该功能包需要使用什么编译标志,引用哪些头文件等。 下面的代码段是此文件的示例: The ROS Architecture with Examples [ 28 ] To create, modify, or work with packages, ROS gives us some tools for assistance: • rospack: This command is used to get information or find packages in the system • roscreate-pkg: When you want to create a new package, use this command • rosmake: This command is used to compile a package • rosdep: This command installs system dependencies of a package • rxdeps: This command is used if you want to see the package dependencies as a graph To move between the packages and their folders and files, ROS gives us a very useful package called rosbash, which provides some commands very similar to the Linux commands. The following are a few examples: • roscd: This command helps to change the directory; this is similar to the cd command in Linux • rosed: This command is used to edit a file • roscp: This command is used to copy a file from some package • rosd: This command lists the directories of a package • rosls: This command lists the files from a package; this is similar to the ls command in Linux The file manifest.xml must be in a package, and it is used to specify information about the package. If you find this file inside a folder, probably this folder is a package. If you open a manifest.xml file, you will see information about the name of the package, dependencies, and so on. All of this is to make the installation and the distribution of these packages easy. Two typical tags that are used in the manifest file are and . The tag shows which packages must be installed before installing the current package. This is because the new package uses some functionality of the other package. The tag tells the system what flags need to be used to compile the package, what headers are to be included, and so on. The following code snippet is an example of this file: long description, Aaron Martinez, Enrique Fernandez BSD http://example.com/ 16 第 2 章 2.1.2 功能包集 ROS 系统中的很多功能包被组织成 ROS 功能包集。如果说功能包的目标是创建易于代 码复用的最小代码集合,那么功能包集的目标则是简化代码共享的过程。 功能包集同样是一个由文件和文件夹构成的基本结构。你可以手动创建它,但 ROS 为 我们提供了 roscreate-stacck 命令行工具来简化这一过程。 功能包集必需的三个文件是:CMakeList.txt、Makefile 和 stack.xml。如果你在 文件夹中见到 stack.xml,那么可以确定这是一个功能包集。 下面的代码段是此文件的示例: Chapter 2 [ 29 ] Stacks Packages in ROS are organized into ROS stacks. While the goal of packages is to create minimal collections of code for easy re-use, the goal of stacks is to simplify the process of code sharing. A stack needs a basic structure of files and folders. You can create it manually, but ROS provides us with the command tool roscreate-stack for this process. The following three files are necessary for a stack: CMakeList.txt, Makefile, and stack.xml. If you see stack.xml in a folder, you can be sure that this is a stack. The following code snippet is an example of this file: Sample_Stack1 Maintained by AaronMR BSD,LGPL,proprietary http://someurl.blablabla Messages ROS uses a simplified message description language for describing the data values that ROS nodes publish. With this description, ROS can generate the right source code for these types of messages in several programming languages. ROS has a lot of messages predefined, but if you develop a new message, it will be in the msg/ folder of your package. Inside that folder, some files with the .msg extension define the messages. 2.1.3 消息类型 ROS 使用了一种简化的消息类型描述语言来描述 ROS 节点发布的数据值。通过这样的 描述语言,ROS 能够使用多种编程语言生成不同类型消息的源代码。 ROS 提供了很多预定义消息类型。如果你创建了一种新的消息类型,那么就要把消息的 类型定义放到功能包的 msg/ 文件夹下。在该文件夹中,有用于定义各种消息的文件。这些 文件都以 .msg 为扩展名。 消息类型必须具有两个主要部分:字段和常量。字段定义了要在消息中传输的数据的类 型,例如 int32、 float32、string 或之前创建的自定义类型,如叫做 type1 和 type2 的新类 型。常量用于定义字段的名称。 一个消息文件的示例如下: The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. 我们能够在下表中找到很多 ROS 消息所使用的标准数据类型: 基本类型 串行化 C++ Python The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Unsigned 8-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Signed 8-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Unsigned 8-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Signed 16-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. ROS 系统架构及示例 17 基本类型 串行化 C++ Python The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Unsigned 16-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Signed 32-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Unsigned 32-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Signed 64-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Unsigned 64-bit int The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. 32-bit IEEE float The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. 64-bit IEEE float The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. ASCII string (4-bit) The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Secs/nsecs signed 32- bit ints The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. Secs/nsecs signed 32- bit ints The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. The ROS Architecture with Examples [ 30 ] A message must have two principal parts: fields and constants. Fields define the type of data to be transmitted in the message, for example, int32, float32, and string, or new types that you have created before, such as type1 and type2. Constants define the name of the fields. An example of an msg file is as follows: int32 id float32 vel string name In ROS, you can find a lot of standard types to use in messages as shown in the following table: Primitive type Serialization C++ Python bool Unsigned 8-bit int uint8_t bool int8 Signed 8-bit int int8_t int uint8 Unsigned 8-bit int uint8_t int int16 Signed 16-bit int int16_t int uint16 Unsigned 16-bit int uint16_t int int32 Signed 32-bit int int32_t int uint32 Unsigned 32-bit int uint32_t int int64 Signed 64-bit int int64_t long uint64 Unsigned 64-bit int uint64_t long float32 32-bit IEEE float float float float64 64-bit IEEE float double float string ASCII string (4-bit) std::string string time Secs/nsecs signed 32- bit ints ros::Time rospy. Time duration Secs/nsecs signed 32- bit ints ros::Duration rospy. Duration Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. ROS 消息中的一种特殊数据类型是报文头,主要用于添加时间戳、 坐标位置等。报文头 还允许对消息进行编号。通过在报文头内部附加信息,我们可以知道是哪个节点发出的消 息,或者可以添加一些能够被 ROS 处理的其他功能。 报文头类型包含以下字段: Chapter 2 [ 31 ] A special type in ROS is Header. This is used to add the timestamp, frame, and so on. This allows messages to be numbered so that we can know who is sending the message. Other functions can be added, which are transparent to the user but are being handled by ROS. The Header type contains the following fields: uint32 seq time stamp string frame_id Thanks to Header, it is possible to record the timestamp and frame of what is happening with the robot, as we will see in the upcoming chapters. In ROS, there exist some tools to work with messages. The tool rosmsg prints out the message definition information and can find the source files that use a message type. In the upcoming sections, we will see how to create messages with the right tools. Services ROS uses a simplified service description language for describing ROS service types. This builds directly upon the ROS msg format to enable request/response communication between nodes. Service descriptions are stored in .srv files in the srv/ subdirectory of a package. To call a service, you need to use the package name along with the service name; for example, for the file sample_package1/srv/sample1.srv, you will refer to it as sample_package1/sample1. There exist some tools that perform some functions with services. The tool rossrv prints out service descriptions, packages that contain the .srv files, and can find source files that use a service type. If you want to create a service, ROS can help you with the services generator. These tools generate code from an initial specification of the service. You only need to add the line gensrv() to your CMakeLists.txt file. In the upcoming sections, we will learn how to create our own services. 我们将在后续的章节中看到,正是通过报文头才能够记录当前机器人运行的时间戳和坐 标位置。 在 ROS 中有一些处理消息的工具。例如:rosmsg 命令行工具能够输出的消息具体信 息,并可以找到使用该消息类型的源文件。 在后面的章节中,我们将会学习如何使用正确的工具创建消息。 2.1.4 服务类型 ROS 使用了一种简化的服务描述语言来描述 ROS 的服务类型。这直接借鉴了 ROS 消息 的数据格式,以实现节点之间的请求 / 响应通信。服务的描述存储在功能包的 srv/ 子目录 下 .srv 文件中。 若要调用服务,你需要使用该功能包的名称及服务名称。例如,对于 sample_ package1/ srv/sample1.srv 文件,可以将它称为 sample_package1/sample1 服务。 ROS 中有一些执行某些功能与服务的工具。rossrv 工具能输出服务说明、.srv 文件 所在的功能包名称,并可以找到使用某一服务类型的源代码文件。 如果你想要在 ROS 中创建一个服务,可以使用服务生成器。这些工具能够从基本的服 务说明中生成代码。你只需要在 CMakeLists.txt 文件中加一行 gensrv() 命令。 (续) 18 第 2 章 在后面的章节中,我们将会学习如何创建服务。 2.2 理解 ROS 计算图级 ROS 会创建一个连接到所有进程的网络。在系统中的任何节点都可以访问此网络,并通 过该网络与其他节点交互,获取其他节点发布的信息,并将自身数据发布到网络上。 节点 主题 服务 消息记录包 节点管理器 消息参数服务器 计算图级 在这一层级中最基本的概念包括节点、节点管理器、参数服务器、消息、服务、主题和 消息记录包,这些概念都以不同的方式向计算图级提供数据: ● 节点(Node) 节点是主要的计算执行进程。如果你想要有一个可以与其他节点进 行交互的进程,那么你需要创建一个节点,并将此节点连接到 ROS 网络。通常情况 下,系统包含能够实现不同功能的多个节点。你最好让每一个节点都具有特定的单一 的功能,而不是在系统中创建一个包罗万象的大节点。节点需要使用如 roscpp 或 rospy 的 ROS 客户端库进行编写。 ● 节点管理器(Master) 节点管理器用于节点的名称注册和查找等。如果在你的整个 ROS 系统中没有节点管理器,就不会有节点、服务、消息之间的通信。需要注意的 是,由于 ROS 本身就是一个分布式网络系统,你可以在某一台计算机上运行节点管 理器,在其他计算机上运行由该管理器管理的节点。 ● 参数服务器(Parameter Server) 参数服务器能够使数据通过关键词存储在一个系统 的核心位置。通过使用参数,就能够在运行时配置节点或改变节点的工作任务。 ● 消息(Message) 节点通过消息完成彼此的沟通。消息包含一个节点发送到其他节点 的数据信息。 ROS 中包含很多种标准类型的消息,同时你也可以基于标准消息开发自 定义类型的消息。 ● 主题(Topic) 主题是由 ROS 网络对消息进行路由和消息管理的数据总线。每一条消 息都要发布到相应的主题。当一个节点发送数据时,我们就说该节点正在向主题发布 消息。节点可以通过订阅某个主题,接收来自其他节点的消息。一个节点可以订阅一 个主题,而并不需要该节点同时发布该主题。这就保证了消息的发布者和订阅者之间 相互解耦,完全无需知晓对方的存在。主题的名称必须是独一无二的,否则在同名主 题之间的消息路由就会发生错误。 ROS 系统架构及示例 19 ● 服务(Service) 在发布主题时,正在发送的数据能够以多对多的方式交互。但当你 需要从某个节点获得一个请求或应答时,就不能通过主题来实现了。在这种情况下, 服务能够允许我们直接与某个节点进行交互。此外,服务必须有一个唯一的名称。当 一个节点提供某个服务时,所有的节点都可以通过使用 ROS 客户端库所编写的代码 与它通信。 ● 消息记录包(Bag) 消息记录包是一种用于保存和回放 ROS 消息数据的文件格式。 消息记录包是一种用于存储数据的重要机制。它能够获取并记录各种难以收集的传感 器数据。我们可以通过消息记录包反复获取实验数据,进行必要的开发和算法测试。 在使用复杂机器人进行实验工作时,需要经常使用消息记录包。 在下图中,你可以看到计算图级的图形化表示(节点状态图)。它表示了一个真实机器人 在真实条件下系统的工作状态。在图中,你可以看到节点和主题,以及哪些节点订阅哪些主 题等。此节点状态图中并没有消息、消息记录包、参数服务器和服务。这些内容需要使用其 他工具进行图形化展示。用于创建该图表的工具是 rxgraph,在后面的章节中将学习到更 多相关知识。 2.2.1 节点 节点都是各自独立的可执行文件,能够通过主题、 服务或参数服务器与其他进程(节点) 通信。ROS 通过使用节点将代码和功能解耦,提高了系统容错能力和可维护性,使系统简化。 同时,节点允许了 ROS 系统能够布置在任意多个机器上并同时运行。 节点在系统中必须有唯一的名称。节点使用特定名称与其他节点进行通信而不产生 20 第 2 章 歧义。节点可以使用不同的库进行编写,如roscpp 和 rospy。roscpp 基于C++,而 rospy 基于 Python。在这本书里,我们将使用 roscpp。 ROS 提供了处理节点的工具,如 rosnode。rosnode 是一个用于显示节点信息的命令 行工具,例如,列出当前正在运行的节点等。支持的命令如下所示: ● rosnode info node 输出当前节点信息。 ● rosnode kill node 结束当前运行节点进程或发送给定信号。 ● rosnode list 列出当前活动节点。 ● rosnode machine hostname 列出某一特定计算机上运行的节点或列出主机名称。 ● rosnode ping node 测试节点间的连通性。 ● rosnode cleanup 将无法访问节点的注册信息清除。 在后面的章节中,我们将通过一些示例学习如何使用这些命令。 ROS 节点的一个强大功能是在启动该节点时更改参数。此功能使我们能够改变节点名 称、主题名称和参数名称。我们无需重新编译代码就能重新配置节点,这样就可以在不同的 场景中使用该节点。 一个改变主题名称的例子如下所示: The ROS Architecture with Examples [ 34 ] Nodes Nodes are executables that can communicate with other processes using topics, services, or the Parameter Server. Using nodes in ROS provides us with fault tolerance and separates the code and functionalities making the system simpler. A node must have a unique name in the system. This name is used to permit the node to communicate with another node using its name without ambiguity. A node can be written using different libraries such as roscpp and rospy; roscpp is for C++ and rospy is for Python. Throughout this book, we will be using roscpp. ROS has tools to handle nodes and give us information about it such as rosnode. The tool rosnode is a command-line tool for displaying information about nodes, such as listing the currently running nodes. The commands supported are as follows: • rosnode info node: This prints information about the node • rosnode kill node: This kills a running node or sends a given signal • rosnode list: This lists the active nodes • rosnode machine hostname: This lists the nodes running on a particular machine or lists the machines • rosnode ping node: This tests the connectivity to the node • rosnode cleanup: This purges registration information from unreachable nodes In the upcoming sections, we will learn how to use these commands with some examples. A powerful feature of ROS nodes is the possibility to change parameters while you are starting the node. This feature gives us the power to change the node name, topic names, and parameter names. We use this to reconfigure the node without recompiling the code so that we can use the node in different scenes. An example for changing a topic name is as follows: $ rosrun book_tutorials tutorialX topic1:=/level1/topic1 This command will change the topic name topic1 to /level1/topic1. I am sure you do not understand this at this moment, but you will find the utility of it in the upcoming chapters. 此命令将主题名称从 topic1 改为 /level1/topic1。我相信你现在还不是很明白, 但在后面的章节中你会发现它的实用性。 更改节点中的参数和更改主题名称很类似。只需要在参数名称前添加一个下划线, 例如: Chapter 2 [ 35 ] To change parameters in the node, you can do something similar to changing the topic name. For this, you only need to add an underscore to the parameter name; for example: $ rosrun book_tutorials tutorialX _param:=9.0 This will set param to the float number 9.0. Keep in mind that you cannot use some names that are reserved by the system. They are: • __name: This is a special reserved keyword for the name of the node • __log: This is a reserved keyword that designates the location where the node's log file should be written • __ip and __hostname: These are substitutes for ROS_IP and ROS_HOSTNAME • __master: This is a substitute for ROS_MASTER_URI • __ns: This is a substitute for ROS_NAMESPACE Topics Topics are buses used by nodes to transmit data. Topics can be transmitted without a direct connection between nodes, meaning the production and consumption of data are decoupled. A topic can have various subscribers. Each topic is strongly typed by the ROS message type used to publish it, and nodes can only receive messages from a matching type. A node can subscribe to a topic only if it has the same message type. The topics in ROS can be transmitted using TCP/IP and UDP. The TCP/IP-based transport is known as TCPROS and uses the persistent TCP/IP connection. This is the default transport used in ROS. The UDP-based transport is known as UDPROS and is a low-latency, lossy transport. So, it is best suited for tasks such as teleoperation. ROS has a tool to work with topics called rostopic. It is a command-line tool that gives us information about the topic or publishes data directly on the network. This tool has the following parameters: • rostopic bw /topic: This displays the bandwidth used by the topic. • rostopic echo /topic: This prints messages to the screen. 这样参数(param)就设置为浮点数 9.0。 请记住,你不能使用系统保留关键字的名称,包括: ● _name 为节点名称保留的一个特殊关键字。 ● _log 为记录节点日志存储2018香港马会开奖现场保留的一个关键字。 ● _ip_hostname 表示 ROS_IP 和 ROS_HOSTNAME 的关键字。 ● _master 表示 ROS_MASTER_URI 的关键字。 ● _ns 表示 ROS_NAMESPACE 的关键字。 2.2.2 主题 主题是节点间用来传输数据的总线。通过主题进行消息路由不需要节点之间直接连接。 这就意味着发布者和订阅者之间不需要知道彼此是否存在。同一个主题也可以有很多个订 阅者。 每个主题都是强类型的,发布到主题上的消息必须与主题的 ROS 消息类型相匹配,并 ROS 系统架构及示例 21 且节点只能接收类型匹配的消息。一个节点要想订阅一个主题,它们就必须具有相同的消息 类型。 ROS 的主题可以使用 TCP/IP 和 UDP 传输。 基于 TCP 传输称为 TCPROS,它使用 TCP/ IP 长连接。这是 ROS 默认的传输方式。 基于 UDP 传输称为 UDPROS,它是一种低延迟高效率的传输方式,但可能产生数据丢 失。所以它最适合于远程操控任务。 ROS 有一个 rostopic 工具用于主题操作。它是一个命令行工具,允许我们获取主题的相 关信息或直接在网络上发布数据。此工具的参数如下: ● rostopic bw /topic 显示主题所使用的带宽。 ● rostopic echo /topic 将消息输出到屏幕。 ● rostopic find message_type 按照类型查找主题。 ● rostopic hz /topic 显示主题的发布率。 ● rostopic info /topic 输出活动主题、发布的主题、主题订阅者和服务的信息。 ● rostopic list 输出活动主题的列表。 ● rostopic pub /topic type args 将数据发布到主题。它允许我们直接从命 令行中对任意主题创建和发布数据。 ● rostopic type /topic 输出主题的类型,或者说主题中发布的消息类型。 我们会在后面的章节中学习如何使用这些命令。 2.2.3 服务 当你需要直接与节点通信并获得应答时,将无法通过主题实现,而需要使用服务。 服务需要由用户开发,节点并不提供标准服务。包含消息源代码的文件存储在 srv 文件 夹中。 像主题一样,服务关联一个以功能包中 .srv 文件名称来命名的服务类型。与其他 基于 ROS 文件系统的类型一样,服务类型是功能包名称和 .srv 文件名称的组合。例如, chapter2_tutorials/srv/chapter2_srv1.srv 文件的服务类型是chapter2_ tutorials/chapter2_srv1。 ROS 关于服务的命令行工具有两个:rossrv 和 rosservice。我们可以通过 rossrv 看到有关服务数据结构的信息,并且与 rosmsg 具有完全一致的用法。通过 rosservice 可以列出服务列表和查询某个服务。支持的命令如下所示: ● rosservice call /service args 根据命令行参数调用服务。 ● rosservice find msg-type 根据服务类型查询服务。 ● rosservice info /service 输出服务信息。 ● rosservice list 输出活动服务清单。 ● rosservice type /service 输出服务类型。 22 第 2 章 ● rosservice uri /service 输出服务的 ROSRPC URI。 2.2.4 消息 一个节点通过向特定主题发布消息,从而将数据发送到另一个节点。消息具有一定的类 型和数据结构,包括 ROS 提供的标准类型和用户自定义类型。 消息的类型在 ROS 中按照以下标准命名方式进行约定:功能包名称 /.msg 文件名称。 例如,std_msgs/msg/String.msg 的消息类型是 std_msgs/String。 ROS 使用命令行工具 rosmsg 来获取有关消息的信息。惯用参数如下所示: ● rosmsg show 显示一条消息的字段。 ● rosmsg list 列出所有消息。 ● rosmsg package 列出功能包的所有消息。 ● rosmsg packages 列出所有具有该消息的功能包。 ● rosmsg users 搜索使用该消息类型的代码文件。 ● rosmsg md5 显示一条消息的 MD5 求和结果。 2.2.5 消息记录包 消息记录包是由 ROS 创建的一组文件。它使用 .bag 格式保存消息、主题、 服务和其他 ROS 数据信息。你可以在事件发生后,通过使用可视化工具调用和回放数据,检查在系统中 到底发生了什么;你可以播放、停止、后退及执行其他操作。 记录包文件可以像实时会话一样在 ROS 中再现情景,在相同时间向主题发送相同的数 据。通常情况下,我们可以使用此功能来调试算法。若要使用记录包文件,我们可以使用以 下 ROS 工具: ● rosbag 用来录制、播放和执行其他操作。 ● rxbag 用于可视化图形环境中的数据。 ● rostopic 帮助我们看到节点发送的主题。 2.2.6 节点管理器 ROS 节点管理器向 ROS 系统中其他节点提供命名和注册服务。它像服务一样跟踪和记 录主题的发布者和订阅者。节点管理器的作用是使 ROS 节点之间能够相互查找。一旦这些 节点找到了彼此,就能建立一种点对点的通信方式。 节点管理器还提供了参数服务器。节点管理器通常使用 roscore 命令运行,它会加载 ROS 节点管理器及其他 ROS 核心组件。 2.2.7 参数服务器 参数服务器是可通过网络访问的共享的多变量字典。节点使用此服务器来存储和检索运 ROS 系统架构及示例 23 行时的参数。 参数服务器使用 XML-RPC 实现并在 ROS 节点管理器下运行。这意味着它的 API 可通 过通用的 XMLRPC 库进行访问。 参数服务器使用 XMLRPC 数据类型为参数赋值,包括以下类型: ● 32 位整数 ● 布尔值 ● 字符串 ● 双精度浮点 ● ISO 8601 日期 ● 列表(List) ● 基于 64 位编码的二进制数据 ROS 中关于参数服务器的工具是 rosparam。其支持的参数如下所示: ● rosparam list 列出了服务器中的所有参数。 ● rosparam get parameter 获取参数值。 ● rosparam set parameter value 设置参数值。 ● rosparam delete parameter 删除参数。 ● rosparam dump file 将参数服务器保存到一个文件。 ● rosparam load file 加载参数文件到参数服务器。 2.3 理解 ROS 开源社区级 ROS 开源社区级的概念主要关于 ROS 资源,能够通过独立的网络社区分享软件和知识。 这些资源包括: ● 发行版( Distribution) ROS 发行版是可以独立安装的、带有版本号的一系列功能包 集。ROS 发行版像 Linux 发行版一样发挥类似的作用。这使得 ROS 软件安装更加容 易,而且能够通过一个软件集合来维持一致的版本。 ● 软件源( Repositorie) ROS 依赖于共享开源代码与软件源的网站或主机服务,在这 里不同的机构能够发布和分享各自的机器人软件与程序。 ● ROS Wiki ROS Wiki 是用于记录有关 ROS 系统信息的主要论坛。任何人都可以注册 账户和贡献自己的文件、提供更正或更新、编写教程以及其他信息。 ● 邮件列表( Mailing list)  ROS 用户邮件列表是关于 ROS 的主要交流渠道,能够交流 从 ROS 软件更新到 ROS 软件使用中的各种疑问或信息。 2.4 ROS 系统试用练习 现在,是时候对之前学习的内容进行一些练习了。在下面的几小节中,你会看到一组试 24 第 2 章 用 TurtleSim 的练习,其中包括如何建立功能包、使用节点、使用参数服务和移动一个虚拟 机器人。通过这些练习,你会明确上面这些概念的具体含义。 2.4.1 ROS 文件系统导览 我们通过命令行工具来浏览一下 ROS 的文件系统。我们将要解释最常用的部分。 为了获得功能包和功能包集的信息,或移动文件,需要使用 rospack、rosstack、 roscd 和 rosls 命令。 我们使用 rospack 和 rosstack 来获取有关功能包、功能包集、路径和依赖性等信 息。例如,如果你想要找 turtlesim 包的路径,可以使用以下命令: Chapter 2 [ 39 ] Understanding the ROS Community level The ROS Community level concepts are ROS resources that enable separate communities to exchange software and knowledge. These resources include: • Distributions: ROS distributions are collections of versioned stacks that you can install. ROS distributions play a similar role to Linux distributions. They make it easier to install a collection of software, and they also maintain consistent versions across a set of software. • Repositories: ROS relies on a federated network of code repositories, where different institutions can develop and release their own robot software components. • The ROS Wiki: The ROS Wiki is the main forum for documenting information about ROS. Anyone can sign up for an account and contribute their own documentation, provide corrections or updates, write tutorials, and more. • Mailing lists: The ROS user-mailing list is the primary communication channel about new updates to ROS as well as a forum to ask questions about the ROS software. Some tutorials to practice with ROS It is time to practice what we have learned until now. In the upcoming sections, you will see examples to practice along with the creation of packages, using nodes, using the Parameter Server, and moving a simulated robot with TurtleSim. Navigating through the ROS filesystem We have some command-line tools to navigate through the filesystem. We are going to explain the most used ones. To get information and move to packages and stacks, we will use rospack, rosstack, roscd, and rosls. We use rospack and rosstack to get information about packages and stacks, the path, the dependencies, and so on. For example, if you want to find the path of the turtlesim package, you will use this: $ rospack find turtlesim 你将获得以下信息: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 同样的,如果你想要找到你已经在系统中安装过的某个功能包集,示例如下: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 想要获得功能包或功能包集下面的文件列表,那么需要使用: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 你将获得以下信息: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 如果你想进入到某个文件夹,可以使用 roscd 命令: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 你将获得以下新路径: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 2.4.2 创建工作空间 在开始具体工作之前,首先创建工作空间。在这个工作空间中,我们将会完成本书中所 使用的所有代码。 若要查看 ROS 正在使用的工作空间,请使用下面的命令: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 你将会看到如下信息: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook ROS 系统架构及示例 25 我们将要创建的文件夹是在 ~/dev/rosbook/ 中。若要新建此文件夹,使用以下命令: The ROS Architecture with Examples [ 40 ] You will then obtain the following: /opt/ros/fuerte/share/turtlesim The same happens with stacks that you have installed in the system. An example of this is as follows: $ rosstack find 'nameofstack' To list the files inside the pack or stack, you will use this: $ rosls turtlesim You will then obtain the following: cmake images mimic srv turtle_teleop_key draw_square manifest.xml msg turtlesim_node If you want to go inside the folder, you will use roscd as follows: $ roscd turtlesim $ pwd You will obtain the following new path: /opt/ros/fuerte/share/turtlesim Creating our own workspace Before doing anything, we are going to create our own workspace. In this workspace, we will have all the code that we will use in this book. To see the workspace that ROS is using, use the following command: $ echo $ROS_PACKAGE_PATH You will see something like this: /opt/ros/fuerte/share:/opt/ros/fuerte/stacks The folder that we are going to create is in ~/dev/rosbook/. To add this folder, we use the following lines: $ cd ~ $ mkdir –p dev/rosbook 一旦我们在目录下建好了文件夹,就有必要将此新路径添加到 ROS_PACKAGE_ PATH。 要做到这一点,只需要在 ~/.bashrc 文件的末尾添加一个新行: $ echo "export ROS_PACKAGE_PATH=~/dev/rosbook:${ROS_PACKAGE_PATH}" >> ~/.bashrc $ . ~/.bashrc 现在我们已经在 ROS 系统中创建和配置完成自己的新文件夹。 2.4.3 创建 ROS 功能包 就像之前所说,你也可以手动创建功能包。但是为了避免那些繁琐的工作,最好使用 roscreate-pkg 命令行工具。 使用以下命令在之前建立的文件夹下创建新的功能包: Chapter 2 [ 41 ] Once we have the folder in place, it is necessary to add this new path to ROS_PACKAGE_ PATH. To do that, we only need to add a new line at the end of the ~/.bashrc file: $ echo "export ROS_PACKAGE_PATH"~/dev/rosbook:${ROS_PACKAGE_PATH}" >> ~/.bashrc $ . ~/.bashrc Now we have our new folder created and configured for use with ROS. Creating an ROS package As said before, you can create a package manually. To avoid tedious work, we will use the roscreate-pkg command-line tool. We will create the new package in the folder created previously using the following lines: $ cd ~/dev/rosbook $ roscreate-pkg chapter2_tutorials std_msgs rospy roscpp The format of this command includes the name of the package and the dependencies that will have the package; in our case, they are std_msgs, rospy, and roscpp. This is shown in the following command line: roscreate-pkg [package_name] [depend1] [depend2] [depend3] The dependencies included are the following: • std_msgs: This contains common message types representing primitive data types and other basic message constructs, such as multiarrays. • rospy: This is a pure Python client library for ROS • roscpp: This is a C++ implementation of ROS. It provides a client library that enables C++ programmers to quickly interface with ROS topics, services, and parameters. If everything is right, you will see the following screenshot: 此命令的格式包括功能包的名称和依赖项;在这个示例中,依赖项包括 std_msgs、 rospy 和 roscpp。如以下命令行所示: Chapter 2 [ 41 ] Once we have the folder in place, it is necessary to add this new path to ROS_PACKAGE_ PATH. To do that, we only need to add a new line at the end of the ~/.bashrc file: $ echo "export ROS_PACKAGE_PATH"~/dev/rosbook:${ROS_PACKAGE_PATH}" >> ~/.bashrc $ . ~/.bashrc Now we have our new folder created and configured for use with ROS. Creating an ROS package As said before, you can create a package manually. To avoid tedious work, we will use the roscreate-pkg command-line tool. We will create the new package in the folder created previously using the following lines: $ cd ~/dev/rosbook $ roscreate-pkg chapter2_tutorials std_msgs rospy roscpp The format of this command includes the name of the package and the dependencies that will have the package; in our case, they are std_msgs, rospy, and roscpp. This is shown in the following command line: roscreate-pkg [package_name] [depend1] [depend2] [depend3] The dependencies included are the following: • std_msgs: This contains common message types representing primitive data types and other basic message constructs, such as multiarrays. • rospy: This is a pure Python client library for ROS • roscpp: This is a C++ implementation of ROS. It provides a client library that enables C++ programmers to quickly interface with ROS topics, services, and parameters. If everything is right, you will see the following screenshot: 这些依赖项包括: ● std_msgs 包含了常见消息类型,表示基本数据类型和其他基本的消息构造,如多 维数组。 ● rospy 一个 ROS 的纯 Python 客户端库。 ● roscpp 使用 C++ 实现 ROS 的各种功能。它提供了一个客户端库。程序员能够调 用这些接口快速完成与 ROS 的主题、服务和参数相关的开发工作。 如果所有步骤都正确执行,结果如下图所示: 正如我们之前看到的,你可以使用 rospack、roscd 和 rosls 命令来获取新的功能包 信息: ● rospack find chapter2_tutorials 此命令用于查找路径。 ● rospack depends chapter2_tutorials 此命令用于查看依赖关系。 26 第 2 章 ● rosls chapter2_tutorials 此命令用于查看内容。 ● roscd chapter2_tutorials 此命令会更改实际路径。 2.4.4 编译 ROS 功能包 一旦你创建了一个功能包,并且编写了一些代码,就需要编译功能包了。当你编译功能 包的时候,主要是代码的编译过程。 为了编译功能包,可以使用 rosmake 命令: The ROS Architecture with Examples [ 42 ] As we saw before, you can use the rospack, roscd, and rosls commands to get information of the new package: • rospack find chapter2_tutorials: This command helps us find the path • rospack depends chapter2_tutorials: This command helps us see the dependencies • rosls chapter2_tutorials: This command helps us see the content • roscd chapter2_tutorials: This command changes the actual path Building an ROS package Once you have your package created, and you have some code, it is necessary to build the package. When you build the package, what really happens is that the code is compiled. To build a package, we will use the rosmake tool as follows: $ rosmake chapter2_tutorials After a few seconds, you will see something like this: If you don't obtain failures, the package is compiled. Playing with ROS nodes As we have explained in the Nodes section, nodes are executable programs and these executables are in the packagename/bin directory. To practice and learn about nodes, we are going to use a typical package called turtlesim. If you have installed the desktop installation file, you have the turtlesim package installed; if not, install it using the following command: $ sudo apt-get install ros-fuerte-ros-tutorials Before starting with anything, you must start roscore as follows: $ roscore 在几秒之后,你会看到: 如果没有看到错误提示信息,说明功能包编译成功。 2.4.5 使用 ROS 节点 正如我们在 2.2.1 章节中解释的,节点都是可执行程序,这些可执行文件位于 packagename/bin 目录中。要学习和了解有关节点的知识,我们要使用一个名为 turtlesim 的功能包进行练习。 如果你进行了 ROS 系统的完整安装,那么你已经有了 turtlesim 功能包。如果还没 有,请使用以下命令安装: The ROS Architecture with Examples [ 42 ] As we saw before, you can use the rospack, roscd, and rosls commands to get information of the new package: • rospack find chapter2_tutorials: This command helps us find the path • rospack depends chapter2_tutorials: This command helps us see the dependencies • rosls chapter2_tutorials: This command helps us see the content • roscd chapter2_tutorials: This command changes the actual path Building an ROS package Once you have your package created, and you have some code, it is necessary to build the package. When you build the package, what really happens is that the code is compiled. To build a package, we will use the rosmake tool as follows: $ rosmake chapter2_tutorials After a few seconds, you will see something like this: If you don't obtain failures, the package is compiled. Playing with ROS nodes As we have explained in the Nodes section, nodes are executable programs and these executables are in the packagename/bin directory. To practice and learn about nodes, we are going to use a typical package called turtlesim. If you have installed the desktop installation file, you have the turtlesim package installed; if not, install it using the following command: $ sudo apt-get install ros-fuerte-ros-tutorials Before starting with anything, you must start roscore as follows: $ roscore 在开始之前,必须使用如下命令启动 roscore: The ROS Architecture with Examples [ 42 ] As we saw before, you can use the rospack, roscd, and rosls commands to get information of the new package: • rospack find chapter2_tutorials: This command helps us find the path • rospack depends chapter2_tutorials: This command helps us see the dependencies • rosls chapter2_tutorials: This command helps us see the content • roscd chapter2_tutorials: This command changes the actual path Building an ROS package Once you have your package created, and you have some code, it is necessary to build the package. When you build the package, what really happens is that the code is compiled. To build a package, we will use the rosmake tool as follows: $ rosmake chapter2_tutorials After a few seconds, you will see something like this: If you don't obtain failures, the package is compiled. Playing with ROS nodes As we have explained in the Nodes section, nodes are executable programs and these executables are in the packagename/bin directory. To practice and learn about nodes, we are going to use a typical package called turtlesim. If you have installed the desktop installation file, you have the turtlesim package installed; if not, install it using the following command: $ sudo apt-get install ros-fuerte-ros-tutorials Before starting with anything, you must start roscore as follows: $ roscore 为了获得节点信息,可以使用 rosnode 命令。为了查看命令接受哪些参数,可以输入 以下命令: Chapter 2 [ 43 ] To get information on nodes, we have the tool rosnode. To see what parameters are accepted, type the following command: $ rosnode You will obtain a list of accepted parameters as shown in the following screenshot: If you want a more detailed explanation on the use of these parameters, use the following line: $ rosnode -h Now that roscore is running, we are going to get information about the nodes that are running: $ rosnode list You see that the only node running is /rosout. It is normal because this node runs whenever roscore is run. We can get all the information of this node using parameters. Try using the following commands for more information: $ rosnode info $ rosnode ping $ rosnode machine $ rosnode kill Now we are going to start a new node with rosrun as follows: $ rosrun turtlesim turtlesim_node 你会获得一个可接受参数的清单,如下图所示: ROS 系统架构及示例 27 如果你想获得关于这些参数更详细的解释,请使用以下命令: Chapter 2 [ 43 ] To get information on nodes, we have the tool rosnode. To see what parameters are accepted, type the following command: $ rosnode You will obtain a list of accepted parameters as shown in the following screenshot: If you want a more detailed explanation on the use of these parameters, use the following line: $ rosnode -h Now that roscore is running, we are going to get information about the nodes that are running: $ rosnode list You see that the only node running is /rosout. It is normal because this node runs whenever roscore is run. We can get all the information of this node using parameters. Try using the following commands for more information: $ rosnode info $ rosnode ping $ rosnode machine $ rosnode kill Now we are going to start a new node with rosrun as follows: $ rosrun turtlesim turtlesim_node 现在 roscore 已经运行,我们想要获取正在运行的节点的相关信息: Chapter 2 [ 43 ] To get information on nodes, we have the tool rosnode. To see what parameters are accepted, type the following command: $ rosnode You will obtain a list of accepted parameters as shown in the following screenshot: If you want a more detailed explanation on the use of these parameters, use the following line: $ rosnode -h Now that roscore is running, we are going to get information about the nodes that are running: $ rosnode list You see that the only node running is /rosout. It is normal because this node runs whenever roscore is run. We can get all the information of this node using parameters. Try using the following commands for more information: $ rosnode info $ rosnode ping $ rosnode machine $ rosnode kill Now we are going to start a new node with rosrun as follows: $ rosrun turtlesim turtlesim_node 你会看到运行的节点仅有 /rosout。这是正常的,因为这个节点总是随着 roscore 的 运行而运行。 通过使用参数我们可以获得此节点的所有信息。也可以使用下列命令获得更详细的 信息: Chapter 2 [ 43 ] To get information on nodes, we have the tool rosnode. To see what parameters are accepted, type the following command: $ rosnode You will obtain a list of accepted parameters as shown in the following screenshot: If you want a more detailed explanation on the use of these parameters, use the following line: $ rosnode -h Now that roscore is running, we are going to get information about the nodes that are running: $ rosnode list You see that the only node running is /rosout. It is normal because this node runs whenever roscore is run. We can get all the information of this node using parameters. Try using the following commands for more information: $ rosnode info $ rosnode ping $ rosnode machine $ rosnode kill Now we are going to start a new node with rosrun as follows: $ rosrun turtlesim turtlesim_node 现在我们要用 rosrun 命令启动一个新的节点,如下所示: Chapter 2 [ 43 ] To get information on nodes, we have the tool rosnode. To see what parameters are accepted, type the following command: $ rosnode You will obtain a list of accepted parameters as shown in the following screenshot: If you want a more detailed explanation on the use of these parameters, use the following line: $ rosnode -h Now that roscore is running, we are going to get information about the nodes that are running: $ rosnode list You see that the only node running is /rosout. It is normal because this node runs whenever roscore is run. We can get all the information of this node using parameters. Try using the following commands for more information: $ rosnode info $ rosnode ping $ rosnode machine $ rosnode kill Now we are going to start a new node with rosrun as follows: $ rosrun turtlesim turtlesim_node 我们看到出现了一个新的窗口,窗口中间有一个小海龟,如下图所示: 如果我们再去查看节点列表,会看到出现了一个新的节点,叫做 /turtlesim。 你可以通过使用 rosnode info Nodename 命令查看节点信息。你可以看到很多可以 用于程序调试的信息: 28 第 2 章 The ROS Architecture with Examples [ 44 ] We will then see a new window appear with a little turtle in the middle, as shown in the following screenshot: If we see the node list now, we will see a new node with the name /turtlesim. You can see the information of the node using rosnode info nameNode. You can see a lot of information that can be used to debug your programs: $ rosnode info /turtlesim Node [/turtlesim] Publications: * /turtle1/color_sensor [turtlesim/Color] * /rosout [rosgraph_msgs/Log] * /turtle1/pose [turtlesim/Pose] Subscriptions: * /turtle1/command_velocity [unknown type] Services: * /turtle1/teleport_absolute * /turtlesim/get_loggers Chapter 2 [ 45 ] * /turtlesim/set_logger_level * /reset * /spawn * /clear * /turtle1/set_pen * /turtle1/teleport_relative * /kill contacting node http://aaronmr-laptop:42791/ ... Pid: 28337 Connections: * topic: /rosout * to: /rosout * direction: outbound * transport: TCPROS In the information, we can see the publications (topics), subscriptions (topics), and the services (srv) that the node has and the unique names of each. Now, let us show you how to interact with the node using topics and services. Learning how to interact with topics To interact and get information of topics, we have the rostopic tool. This tool accepts the following parameters: • rostopic bw: This displays the bandwidth used by topics • rostopic echo: This prints messages to the screen • rostopic find: This finds topics by their type • rostopic hz: This displays the publishing rate of topics • rostopic info: This prints information about active topics • rostopic list: This lists the active topics • rostopic pub: This publishes data to the topic • rostopic type: This prints the topic type If you want to see more information on these parameters, use -h as follows: $ rostopic bw –h 在以上信息中,我们可以看到发布者(及相应主题)、订阅者(及相应主题)和该节点具 有的服务(srv)及它们各自唯一的名称。 接下来介绍如何使用主题和服务与该节点进行交互。 2.4.6 使用主题与节点交互 要进行交互并获取主题的信息,可以使用 rostopic 工具。此工具接受以下参数: ● rostopic bw 显示主题所使用的带宽。 ● rostopic echo 将消息输出到屏幕。 ● rostopic fi nd 按照类型查找主题。 ● rostopic hz 显示主题的发布频率。 ● rostopic info 输出活动主题的 信息。 ● rostopic list 输出活动主题的列表。 ● rostopic pub 将数据发布到主题。 ROS 系统架构及示例 29 ● rostopic type 输出主题的类型。 如果想要查看有关这些参数的详细信息,请使用 -h,如下所示: Chapter 2 [ 45 ] * /turtlesim/set_logger_level * /reset * /spawn * /clear * /turtle1/set_pen * /turtle1/teleport_relative * /kill contacting node http://aaronmr-laptop:42791/ ... Pid: 28337 Connections: * topic: /rosout * to: /rosout * direction: outbound * transport: TCPROS In the information, we can see the publications (topics), subscriptions (topics), and the services (srv) that the node has and the unique names of each. Now, let us show you how to interact with the node using topics and services. Learning how to interact with topics To interact and get information of topics, we have the rostopic tool. This tool accepts the following parameters: • rostopic bw: This displays the bandwidth used by topics • rostopic echo: This prints messages to the screen • rostopic find: This finds topics by their type • rostopic hz: This displays the publishing rate of topics • rostopic info: This prints information about active topics • rostopic list: This lists the active topics • rostopic pub: This publishes data to the topic • rostopic type: This prints the topic type If you want to see more information on these parameters, use -h as follows: $ rostopic bw –h 通过使用 pub 参数,可以发布任何节点都可以订阅的主题。我们只需要用正确的名称将 主题发布出去。我们将会在以后做这个测试,现在要使用一个节点,并让节点做如下工作: The ROS Architecture with Examples [ 46 ] With the pub parameter, we can publish topics that can subscribe to any node. We only need to publish the topic with the correct name. We will do this test later; we are now going to use a node that will do this work for us: $ rosrun turtlesim turtle_teleop_key With this node, we can move the turtle using the arrow keys as you can see in the following screenshot: Why is the turtle moving when turtle_teleop_key is executed? If you want to see the information of the /teleop_turtle and /turtlesim nodes, we can see in the following code that there exists a topic called * /turtle1/ command_velocity [turtlesim/Velocity] in the Publications section of the first node; in the Subscriptions section of the second node, there is * /turtle1/ command_velocity [turtlesim/Velocity]: $ rosnode info /teleop_turtle Node [/teleop_turtle] ... 通过节点订阅的 主题,我们可以使用箭头键移动乌龟,如下图所示: 为什么 turtle_teleop_key 执行时,小海龟会移动呢 ? 如果你想要看到 /teleop_turtle 和 /turtlesim 节点的信息,可以看到在下面的 代码中,在发布者(Publications)部分的第一个节点有一个主题叫 */turtle1/ command_ velocity [turtlesim/Velocity] ;在订阅者(Subscriptions)部分的第二个节点有 */ turtle1/command_ velocity [turtlesim/Velocity]: The ROS Architecture with Examples [ 46 ] With the pub parameter, we can publish topics that can subscribe to any node. We only need to publish the topic with the correct name. We will do this test later; we are now going to use a node that will do this work for us: $ rosrun turtlesim turtle_teleop_key With this node, we can move the turtle using the arrow keys as you can see in the following screenshot: Why is the turtle moving when turtle_teleop_key is executed? If you want to see the information of the /teleop_turtle and /turtlesim nodes, we can see in the following code that there exists a topic called * /turtle1/ command_velocity [turtlesim/Velocity] in the Publications section of the first node; in the Subscriptions section of the second node, there is * /turtle1/ command_velocity [turtlesim/Velocity]: $ rosnode info /teleop_turtle Node [/teleop_turtle] ... Publications: * /turtle1/command_velocity [turtlesim/Velocity] ... $ rosnode info /turtlesim Node [/turtlesim] ... Subscriptions: * /turtle1/command_velocity [turtlesim/Velocity] ... 30 第 2 章 Publications: * /turtle1/command_velocity [turtlesim/Velocity] ... $ rosnode info /turtlesim Node [/turtlesim] ... Subscriptions: * /turtle1/command_velocity [turtlesim/Velocity] ... 这意味着前面的节点发布了一个主题,而后面的节点订阅了这个主题。 你可以使用以下命令查看主题清单: Chapter 2 [ 47 ] Publications: * /turtle1/command_velocity [turtlesim/Velocity] ... $ rosnode info /turtlesim Node [/teleop_turtle] ... Subscriptions: * /turtle1/command_velocity [turtlesim/Velocity] ... This means that the first node is publishing a topic that the second node can subscribe to. You can see the topics' list using the following command lines: $ rostopic list /rosout /rosout_agg /turtle1/color_sensor /turtle1/command_velocity /turtle1/pose With the echo parameter, you can see the information sent by the node. Run the following command line and use the arrow keys to see what data is being sent: $ rostopic echo /turtle1/command_velocity You will see something like this: linear: 2.0 angular: 0.0 --- linear: 0.0 angular: 2.0 --- 通过使用 echo 参数,可以查看节点发出的信息。运行以下命令行并使用箭头键触发消 息,查看消息产生时发送了哪些数据: Chapter 2 [ 47 ] Publications: * /turtle1/command_velocity [turtlesim/Velocity] ... $ rosnode info /turtlesim Node [/teleop_turtle] ... Subscriptions: * /turtle1/command_velocity [turtlesim/Velocity] ... This means that the first node is publishing a topic that the second node can subscribe to. You can see the topics' list using the following command lines: $ rostopic list /rosout /rosout_agg /turtle1/color_sensor /turtle1/command_velocity /turtle1/pose With the echo parameter, you can see the information sent by the node. Run the following command line and use the arrow keys to see what data is being sent: $ rostopic echo /turtle1/command_velocity You will see something like this: linear: 2.0 angular: 0.0 --- linear: 0.0 angular: 2.0 --- 你会看到类似如下显示: Chapter 2 [ 47 ] Publications: * /turtle1/command_velocity [turtlesim/Velocity] ... $ rosnode info /turtlesim Node [/teleop_turtle] ... Subscriptions: * /turtle1/command_velocity [turtlesim/Velocity] ... This means that the first node is publishing a topic that the second node can subscribe to. You can see the topics' list using the following command lines: $ rostopic list /rosout /rosout_agg /turtle1/color_sensor /turtle1/command_velocity /turtle1/pose With the echo parameter, you can see the information sent by the node. Run the following command line and use the arrow keys to see what data is being sent: $ rostopic echo /turtle1/command_velocity You will see something like this: linear: 2.0 angular: 0.0 --- linear: 0.0 angular: 2.0 --- 你可以使用以下命令行查看由主题发送的消息类型: The ROS Architecture with Examples [ 48 ] You can see the type of message sent by the topic using the following command lines: $ rostopic type /turtle1/command_velocity turtlesim/Velocity If you want to see the message fields, you can do it with the following command lines: $ rosmsg show turtlesim/Velocity float32 linear float32 angular These tools are useful because, with this information, we can publish topics using the command, rostopic pub [topic] [msg_type] [args]: $ rostopic pub -1 /turtle1/command_velocity turtlesim/Velocity -- 1 1 You will see the turtle doing a curve. 如果你想要看到消息字段,可以使用以下命令: The ROS Architecture with Examples [ 48 ] You can see the type of message sent by the topic using the following command lines: $ rostopic type /turtle1/command_velocity turtlesim/Velocity If you want to see the message fields, you can do it with the following command lines: $ rosmsg show turtlesim/Velocity float32 linear float32 angular These tools are useful because, with this information, we can publish topics using the command, rostopic pub [topic] [msg_type] [args]: $ rostopic pub -1 /turtle1/command_velocity turtlesim/Velocity -- 1 1 You will see the turtle doing a curve. 这些工具非常有用,因为我们可以通过这些工具使用 rostopic pub [topic] [msg_type] [args] 命令直接发布主题: ROS 系统架构及示例 31 The ROS Architecture with Examples [ 48 ] You can see the type of message sent by the topic using the following command lines: $ rostopic type /turtle1/command_velocity turtlesim/Velocity If you want to see the message fields, you can do it with the following command lines: $ rosmsg show turtlesim/Velocity float32 linear float32 angular These tools are useful because, with this information, we can publish topics using the command, rostopic pub [topic] [msg_type] [args]: $ rostopic pub -1 /turtle1/command_velocity turtlesim/Velocity -- 1 1 You will see the turtle doing a curve.你会看到小海龟做曲线运动,如下图所示。 2.4.7 学习如何使用服务 服务是能够使节点之间相互通信的另一种方法。服务允许节点发送请求和接收响应。 我们要使用 rosservice 工具与服务进行交互。此命令接受的参数如下所示: ● rosservice args /service 输出服务参数。 ● rosservice call /service args 根据命令行参数调用服务。 ● rosservice fi nd msg-type 根据服务类型查询服务。 ● rosservice info /service 输出服务信息。 ● rosservice list 输出活动服务清单。 ● rosservice type /service 输出服务类型。 ● rosservice uri /service 输出服务的 ROSRPC URI。 我们要使用以下命令列出在 turtlesim 节点运行时系统提供的服务。如果你运行了这 个命令,却没有任何反应,那么请记住以后要先运行 roscore 并启动 turtlesim 节点: Chapter 2 [ 49 ] Learning how to use services Services are another way through which nodes can communicate with each other. Services allow nodes to send a request and receive a response. The tool that we are going to use to interact with services is rosservice. The accepted parameters for this command are as follows: • rosservice args /service: This prints service arguments • rosservice call /service: This calls the service with the provided arguments • rosservice find msg-type: This finds services by their service type • rosservice info /service: This prints information about the service • rosservice list: This lists active services • rosservice type /service: This prints the service type • rosservice uri /service: This prints the service ROSRPC URI We are going to list the services available for the turtlesim node by using the following code, so if it is not working, run roscore and run the turtlesim node: $ rosservice list You will obtain the following output: /clear /kill /reset /rosout/get_loggers /rosout/set_logger_level /spawn /teleop_turtle/get_loggers /teleop_turtle/set_logger_level /turtle1/set_pen /turtle1/teleport_absolute /turtle1/teleport_relative /turtle2/set_pen /turtle2/teleport_absolute /turtle2/teleport_relative /turtlesim/get_loggers /turtlesim/set_logger_level 你会获得以下输出: Chapter 2 [ 49 ] Learning how to use services Services are another way through which nodes can communicate with each other. Services allow nodes to send a request and receive a response. The tool that we are going to use to interact with services is rosservice. The accepted parameters for this command are as follows: • rosservice args /service: This prints service arguments • rosservice call /service: This calls the service with the provided arguments • rosservice find msg-type: This finds services by their service type • rosservice info /service: This prints information about the service • rosservice list: This lists active services • rosservice type /service: This prints the service type • rosservice uri /service: This prints the service ROSRPC URI We are going to list the services available for the turtlesim node by using the following code, so if it is not working, run roscore and run the turtlesim node: $ rosservice list You will obtain the following output: /clear /kill /reset /rosout/get_loggers /rosout/set_logger_level /spawn /teleop_turtle/get_loggers /teleop_turtle/set_logger_level /turtle1/set_pen /turtle1/teleport_absolute /turtle1/teleport_relative /turtle2/set_pen /turtle2/teleport_absolute /turtle2/teleport_relative /turtlesim/get_loggers /turtlesim/set_logger_level 32 第 2 章 Chapter 2 [ 49 ] Learning how to use services Services are another way through which nodes can communicate with each other. Services allow nodes to send a request and receive a response. The tool that we are going to use to interact with services is rosservice. The accepted parameters for this command are as follows: • rosservice args /service: This prints service arguments • rosservice call /service: This calls the service with the provided arguments • rosservice find msg-type: This finds services by their service type • rosservice info /service: This prints information about the service • rosservice list: This lists active services • rosservice type /service: This prints the service type • rosservice uri /service: This prints the service ROSRPC URI We are going to list the services available for the turtlesim node by using the following code, so if it is not working, run roscore and run the turtlesim node: $ rosservice list You will obtain the following output: /clear /kill /reset /rosout/get_loggers /rosout/set_logger_level /spawn /teleop_turtle/get_loggers /teleop_turtle/set_logger_level /turtle1/set_pen /turtle1/teleport_absolute /turtle1/teleport_relative /turtle2/set_pen /turtle2/teleport_absolute /turtle2/teleport_relative /turtlesim/get_loggers /turtlesim/set_logger_level 如果你想查看某个服务的类型,例如 /clear 服务,请使用: The ROS Architecture with Examples [ 50 ] If you want to see the type of any service, for example, the /clear service, use: $ rosservice type /clear You will then obtain: std_srvs/Empty To invoke a service, you will use rosservice call [service] [args]. If you want to invoke the /clear service, use: $ rosservice call /clear In the turtlesim window, you will now see that the lines created by the movements of the turtle will be deleted. Now, we are going to try another service, for example, the /spawn service. This service will create another turtle in another location with a different orientation. To start with, we are going to see the following type of message: $ rosservice type /spawn | rossrv show We will then obtain the following: float32 x float32 y float32 theta string name --- string name With these fields, we know how to invoke the service. We need the positions of x and y, the orientation (theta), and the name of the new turtle: $ rosservice call 3 3 0.2 "new_turtle" 你会获得: The ROS Architecture with Examples [ 50 ] If you want to see the type of any service, for example, the /clear service, use: $ rosservice type /clear You will then obtain: std_srvs/Empty To invoke a service, you will use rosservice call [service] [args]. If you want to invoke the /clear service, use: $ rosservice call /clear In the turtlesim window, you will now see that the lines created by the movements of the turtle will be deleted. Now, we are going to try another service, for example, the /spawn service. This service will create another turtle in another location with a different orientation. To start with, we are going to see the following type of message: $ rosservice type /spawn | rossrv show We will then obtain the following: float32 x float32 y float32 theta string name --- string name With these fields, we know how to invoke the service. We need the positions of x and y, the orientation (theta), and the name of the new turtle: $ rosservice call 3 3 0.2 "new_turtle" 若要调用服务,你需要使用 rosservice call [service] [args] 命令。所以如 果想要调用 /clear 服务,请使用: The ROS Architecture with Examples [ 50 ] If you want to see the type of any service, for example, the /clear service, use: $ rosservice type /clear You will then obtain: std_srvs/Empty To invoke a service, you will use rosservice call [service] [args]. If you want to invoke the /clear service, use: $ rosservice call /clear In the turtlesim window, you will now see that the lines created by the movements of the turtle will be deleted. Now, we are going to try another service, for example, the /spawn service. This service will create another turtle in another location with a different orientation. To start with, we are going to see the following type of message: $ rosservice type /spawn | rossrv show We will then obtain the following: float32 x float32 y float32 theta string name --- string name With these fields, we know how to invoke the service. We need the positions of x and y, the orientation (theta), and the name of the new turtle: $ rosservice call 3 3 0.2 "new_turtle" 在 turtlesim 的窗口中,你会看到由于小海龟移动所产生的线条消失了。 现在我们尝试其他的服务,例如 /spawn 服务。这项服务将在不同的方向和不同的位置 创建另一只小海龟。开始之前,我们要去查看以下类型的消息: The ROS Architecture with Examples [ 50 ] If you want to see the type of any service, for example, the /clear service, use: $ rosservice type /clear You will then obtain: std_srvs/Empty To invoke a service, you will use rosservice call [service] [args]. If you want to invoke the /clear service, use: $ rosservice call /clear In the turtlesim window, you will now see that the lines created by the movements of the turtle will be deleted. Now, we are going to try another service, for example, the /spawn service. This service will create another turtle in another location with a different orientation. To start with, we are going to see the following type of message: $ rosservice type /spawn | rossrv show We will then obtain the following: float32 x float32 y float32 theta string name --- string name With these fields, we know how to invoke the service. We need the positions of x and y, the orientation (theta), and the name of the new turtle: $ rosservice call 3 3 0.2 "new_turtle" 我们会获得以下参数: The ROS Architecture with Examples [ 50 ] If you want to see the type of any service, for example, the /clear service, use: $ rosservice type /clear You will then obtain: std_srvs/Empty To invoke a service, you will use rosservice call [service] [args]. If you want to invoke the /clear service, use: $ rosservice call /clear In the turtlesim window, you will now see that the lines created by the movements of the turtle will be deleted. Now, we are going to try another service, for example, the /spawn service. This service will create another turtle in another location with a different orientation. To start with, we are going to see the following type of message: $ rosservice type /spawn | rossrv show We will then obtain the following: float32 x float32 y float32 theta string name --- string name With these fields, we know how to invoke the service. We need the positions of x and y, the orientation (theta), and the name of the new turtle: $ rosservice call 3 3 0.2 "new_turtle" 通过这些字段,可以知道如何来调用服务。我们需要新海龟位置的 x 和 y、方向 theta 和 新海龟的名称: $ rosservice call /spawn 3 3 0.2 "new_turtle" 我们会获得以下结果: ROS 系统架构及示例 33 2.4.8 使用参数服务器 参数服务器用于存储所有节点均可访问的共享数据。 ROS 中用来管理参数服务器的工具 称为 rosparam。接受的参数如下所示: ● rosparam set parameter value 设置参数值。 ● rosparam get parameter 获取参数值。 ● rosparam load fi l e  加载参数文件到参数服务器。 ● rosparam delete parameter 删除参数。 ● rosparam dump fi l e  将参数服务器保存到一个文件。 ● rosparam list 列出了服务器中的所有参数。 例如,查看被所有节点所使用的服务器参数: Chapter 2 [ 51 ] We then obtain the following result: Using the Parameter Server The Parameter Server is used to store data that is accessible by all the nodes. ROS has a tool to manage the Parameter Server called rosparam. The accepted parameters are as follows: • rosparam set parameter value: This sets the parameter • rosparam get parameter: This gets the parameter • rosparam load file: This loads parameters from the file • rosparam dump file: This dumps parameters to the file • rosparam delete parameter: This deletes the parameter • rosparam list: This lists the parameter names For example, we can see the parameters in the server that are used by all the nodes: $ rosparam list 我们会获得以下输出: The ROS Architecture with Examples [ 52 ] We obtain the following output: /background_b /background_g /background_r /rosdistro /roslaunch/uris/host_aaronmr_laptop__60878 /rosversion /run_id The background parameters are of the turtlesim node. These parameters change the color of the windows that are initially blue. If you want to read a value, you will use the get parameter: $ rosparam get /background_b To set a new value, you will use the set parameter: $ rosparam set /background_b 100 Another important feature of rosparam is the dump parameter. With this parameter, you can save or load the content of the Parameter Server. To save the Parameter Server, use rosparam dump [file_name]: $ rosparam dump save.yaml To load a file with new data for the Parameter Server, use rosparam load [file_ name] [namespace]: $ rosparam load load.yaml namespace Creating nodes In this section, we are going to learn how to create two nodes: one to publish some data and the other to receive this data. This is the basic way of communicating between two nodes, that is, to handle data and to do something with that data: $ roscd chapter2_tutorials/src/ Create two files with the names, example1_a.cpp and example1_b.cpp. The example1_a.cpp file will send the data with the node name, and the example2example1_b.cpp file will show the data in the shell. 34 第 2 章 上面的背景(background)参数是 turtlesim 节点的参数。窗口初始化为蓝色,这些参 数可以改变窗口的颜色。如果你想要读取某个值,可以使用 get 参数: The ROS Architecture with Examples [ 52 ] We obtain the following output: /background_b /background_g /background_r /rosdistro /roslaunch/uris/host_aaronmr_laptop__60878 /rosversion /run_id The background parameters are of the turtlesim node. These parameters change the color of the windows that are initially blue. If you want to read a value, you will use the get parameter: $ rosparam get /background_b To set a new value, you will use the set parameter: $ rosparam set /background_b 100 Another important feature of rosparam is the dump parameter. With this parameter, you can save or load the content of the Parameter Server. To save the Parameter Server, use rosparam dump [file_name]: $ rosparam dump save.yaml To load a file with new data for the Parameter Server, use rosparam load [file_ name] [namespace]: $ rosparam load load.yaml namespace Creating nodes In this section, we are going to learn how to create two nodes: one to publish some data and the other to receive this data. This is the basic way of communicating between two nodes, that is, to handle data and to do something with that data: $ roscd chapter2_tutorials/src/ Create two files with the names, example1_a.cpp and example1_b.cpp. The example1_a.cpp file will send the data with the node name, and the example2example1_b.cpp file will show the data in the shell. 为了设定一个新的值,可以使用 set 参数: The ROS Architecture with Examples [ 52 ] We obtain the following output: /background_b /background_g /background_r /rosdistro /roslaunch/uris/host_aaronmr_laptop__60878 /rosversion /run_id The background parameters are of the turtlesim node. These parameters change the color of the windows that are initially blue. If you want to read a value, you will use the get parameter: $ rosparam get /background_b To set a new value, you will use the set parameter: $ rosparam set /background_b 100 Another important feature of rosparam is the dump parameter. With this parameter, you can save or load the content of the Parameter Server. To save the Parameter Server, use rosparam dump [file_name]: $ rosparam dump save.yaml To load a file with new data for the Parameter Server, use rosparam load [file_ name] [namespace]: $ rosparam load load.yaml namespace Creating nodes In this section, we are going to learn how to create two nodes: one to publish some data and the other to receive this data. This is the basic way of communicating between two nodes, that is, to handle data and to do something with that data: $ roscd chapter2_tutorials/src/ Create two files with the names, example1_a.cpp and example1_b.cpp. The example1_a.cpp file will send the data with the node name, and the example2example1_b.cpp file will show the data in the shell. 命令行工具 rosparam 的另外一个重要特性是参数转存。通过该参数,你可以保存或加 载参数服务器的内容。 我们使用 rosparam dump [file_name] 来保存参数服务器: The ROS Architecture with Examples [ 52 ] We obtain the following output: /background_b /background_g /background_r /rosdistro /roslaunch/uris/host_aaronmr_laptop__60878 /rosversion /run_id The background parameters are of the turtlesim node. These parameters change the color of the windows that are initially blue. If you want to read a value, you will use the get parameter: $ rosparam get /background_b To set a new value, you will use the set parameter: $ rosparam set /background_b 100 Another important feature of rosparam is the dump parameter. With this parameter, you can save or load the content of the Parameter Server. To save the Parameter Server, use rosparam dump [file_name]: $ rosparam dump save.yaml To load a file with new data for the Parameter Server, use rosparam load [file_ name] [namespace]: $ rosparam load load.yaml namespace Creating nodes In this section, we are going to learn how to create two nodes: one to publish some data and the other to receive this data. This is the basic way of communicating between two nodes, that is, to handle data and to do something with that data: $ roscd chapter2_tutorials/src/ Create two files with the names, example1_a.cpp and example1_b.cpp. The example1_a.cpp file will send the data with the node name, and the example2example1_b.cpp file will show the data in the shell. 使用 rosparam load [file_name] [namespace] 向参数服务器加载一个新的数据 文件: The ROS Architecture with Examples [ 52 ] We obtain the following output: /background_b /background_g /background_r /rosdistro /roslaunch/uris/host_aaronmr_laptop__60878 /rosversion /run_id The background parameters are of the turtlesim node. These parameters change the color of the windows that are initially blue. If you want to read a value, you will use the get parameter: $ rosparam get /background_b To set a new value, you will use the set parameter: $ rosparam set /background_b 100 Another important feature of rosparam is the dump parameter. With this parameter, you can save or load the content of the Parameter Server. To save the Parameter Server, use rosparam dump [file_name]: $ rosparam dump save.yaml To load a file with new data for the Parameter Server, use rosparam load [file_ name] [namespace]: $ rosparam load load.yaml namespace Creating nodes In this section, we are going to learn how to create two nodes: one to publish some data and the other to receive this data. This is the basic way of communicating between two nodes, that is, to handle data and to do something with that data: $ roscd chapter2_tutorials/src/ Create two files with the names, example1_a.cpp and example1_b.cpp. The example1_a.cpp file will send the data with the node name, and the example2example1_b.cpp file will show the data in the shell. 2.4.9 创建节点 在本节中,我们要学习如何创建两个节点: 一个发布一些数据,另一个接收这些数据。 也就是说,两个节点之间使用最基本的方式进行通信,发送和接收数据并使用这些数据来做 些工作: The ROS Architecture with Examples [ 52 ] We obtain the following output: /background_b /background_g /background_r /rosdistro /roslaunch/uris/host_aaronmr_laptop__60878 /rosversion /run_id The background parameters are of the turtlesim node. These parameters change the color of the windows that are initially blue. If you want to read a value, you will use the get parameter: $ rosparam get /background_b To set a new value, you will use the set parameter: $ rosparam set /background_b 100 Another important feature of rosparam is the dump parameter. With this parameter, you can save or load the content of the Parameter Server. To save the Parameter Server, use rosparam dump [file_name]: $ rosparam dump save.yaml To load a file with new data for the Parameter Server, use rosparam load [file_ name] [namespace]: $ rosparam load load.yaml namespace Creating nodes In this section, we are going to learn how to create two nodes: one to publish some data and the other to receive this data. This is the basic way of communicating between two nodes, that is, to handle data and to do something with that data: $ roscd chapter2_tutorials/src/ Create two files with the names, example1_a.cpp and example1_b.cpp. The example1_a.cpp file will send the data with the node name, and the example2example1_b.cpp file will show the data in the shell. 创建两个文件并分别命名为 example1_a.cpp 和 example1_b.cpp。 example1_a.cpp 文件将会发送带有节点名称的数据,example1_b.cpp 文件会把这 些数据显示在 shell 窗口中。 将下面的代码复制到 example1_a.cpp 文件或者从下载的本书示例代码中找到它: Chapter 2 [ 53 ] Copy the following code into the example1_a.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "example1_a"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise("message", 1000); ros::Rate loop_rate(10); while (ros::ok()) { std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); //ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } Here is some further explanation about the preceding code. The headers to be included are ros/ros.h, std_msgs/String.h, and sstream. Here, ros/ros.h includes all the necessary files for using the node with ROS, and std_msgs/String.h includes the header that denotes the type of message we are going to use: #include "ros/ros.h" #include "std_msgs/String.h" #include Initiate the node and set the name; remember that the name must be unique: ros::init(argc, argv, "example1_a"); The following is the handler of our process: ros::NodeHandle n; ROS 系统架构及示例 35 Chapter 2 [ 53 ] Copy the following code into the example1_a.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "example1_a"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise("message", 1000); ros::Rate loop_rate(10); while (ros::ok()) { std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); //ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } Here is some further explanation about the preceding code. The headers to be included are ros/ros.h, std_msgs/String.h, and sstream. Here, ros/ros.h includes all the necessary files for using the node with ROS, and std_msgs/String.h includes the header that denotes the type of message we are going to use: #include "ros/ros.h" #include "std_msgs/String.h" #include Initiate the node and set the name; remember that the name must be unique: ros::init(argc, argv, "example1_a"); The following is the handler of our process: ros::NodeHandle n; 这里是一些关于上面代码的进一步解释。要包含的头文件是 ros/ros.h、std_msgs/ String.h 和 sstream。其中,ros/ros.h 包含了使用 ROS 节点所有必要的文件,而 std_msgs/String.h 则包含了我们要使用的消息类型: Chapter 2 [ 53 ] Copy the following code into the example1_a.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "example1_a"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise("message", 1000); ros::Rate loop_rate(10); while (ros::ok()) { std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); //ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } Here is some further explanation about the preceding code. The headers to be included are ros/ros.h, std_msgs/String.h, and sstream. Here, ros/ros.h includes all the necessary files for using the node with ROS, and std_msgs/String.h includes the header that denotes the type of message we are going to use: #include "ros/ros.h" #include "std_msgs/String.h" #include Initiate the node and set the name; remember that the name must be unique: ros::init(argc, argv, "example1_a"); The following is the handler of our process: ros::NodeHandle n; 启动该节点并设置其名称,请记住该名称必须是唯一的: Chapter 2 [ 53 ] Copy the following code into the example1_a.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "example1_a"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise("message", 1000); ros::Rate loop_rate(10); while (ros::ok()) { std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); //ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } Here is some further explanation about the preceding code. The headers to be included are ros/ros.h, std_msgs/String.h, and sstream. Here, ros/ros.h includes all the necessary files for using the node with ROS, and std_msgs/String.h includes the header that denotes the type of message we are going to use: #include "ros/ros.h" #include "std_msgs/String.h" #include Initiate the node and set the name; remember that the name must be unique: ros::init(argc, argv, "example1_a"); The following is the handler of our process: ros::NodeHandle n; 下面是设置节点进程的句柄: Chapter 2 [ 53 ] Copy the following code into the example1_a.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "example1_a"); ros::NodeHandle n; ros::Publisher chatter_pub = n.advertise("message", 1000); ros::Rate loop_rate(10); while (ros::ok()) { std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); //ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } Here is some further explanation about the preceding code. The headers to be included are ros/ros.h, std_msgs/String.h, and sstream. Here, ros/ros.h includes all the necessary files for using the node with ROS, and std_msgs/String.h includes the header that denotes the type of message we are going to use: #include "ros/ros.h" #include "std_msgs/String.h" #include Initiate the node and set the name; remember that the name must be unique: ros::init(argc, argv, "example1_a"); The following is the handler of our process: ros::NodeHandle n; 将节点设置成发布者,并将所发布主题的类型和名称告知节点管理器。第一个参数是消 息的名称,设置为 message;第二个参数是缓冲区的大小。如果主题发布数据速度较快,那 么将缓冲区设置为 1000 个消息,如下所示: The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) 在本例中,设置发送数据的频率为 10Hz: The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) 当收到 Ctrl + C 的按键消息或 ROS 停止当前节点运行时,ros ::ok() 库会执行停止 节点运行的命令: The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) 在这里,我们创建一个消息变量,变量的类型必须符合发送数据的要求: The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) 这样,消息被发布: The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) 如果有一个订阅者出现,ROS 就会更新和读取所有主题: 36 第 2 章 The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) 按照 10Hz 的频率将程序挂起: The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) 将下面的代码复制到 example1_b.cpp 文件或者从下载的本书示例代码中找到它: The ROS Architecture with Examples [ 54 ] Set a publisher and tell the Master the name of the topic and the type. The name is message, and the second parameter is the buffer size. If the topic is publishing data quickly, the buffer will keep 1,000 messages as follows: ros::Publisher chatter_pub = n.advertise("message", 1000); Set the frequency to send the data; in this case, it is 10 Hz: ros::Rate loop_rate(10); The ros::ok() library stops the node if it receives a Ctrl + C keypress or if ROS stops all the nodes: while (ros::ok()) { In this part, we create a variable for the message with the correct type to send the data: std_msgs::String msg; std::stringstream ss; ss << " I am the example1_a node "; msg.data = ss.str(); Here, the message is published: chatter_pub.publish(msg); We have a subscriber in this part where ROS updates and reads all the topics: ros::spinOnce(); Sleep the necessary time to get a 10 Hz frequency: loop_rate.sleep(); Copy the following code into the example1_b.cpp file or download it from the repository: #include "ros/ros.h" #include "std_msgs/String.h" void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } int main(int argc, char **argv) Chapter 2 [ 55 ] { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, chatterCallback); ros::spin(); return 0; } Here is some further explanation about the preceding code. Include the headers and the type of message to use for the topic: #include "ros/ros.h" #include "std_msgs/String.h" This function is called every time that node receives a message. This is where we do something with the data; in this case, we show it in the shell: ROS_INFO() is used to print it in the shell. void messageCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } Create a subscriber and start to listen to the topic with the name message. The buffer will be of 1,000, and the function to handle the message will be messageCallback: ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); The ros::spin() library is a loop where the node starts to read the topic, and when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node will exit the loop and the loop ends: ros::spin(); Building the node As we are using the package chapter2_tutorials, we are going to edit the file CMakeLists.txt. You can use your favorite editor or use the rosed tool. This will open the file with the Vim editor: $ rosed chapter2_tutorials CMakeLists.txt At the end of the file, we copy the following command lines: rosbuild_add_executable(example1_a src/example1_a.cpp) rosbuild_add_executable(example1_b src/example1_b.cpp) 这里是一些对上面代码的进一步解释。首先要包含头文件和主题所使用的消息类型: Chapter 2 [ 55 ] { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, chatterCallback); ros::spin(); return 0; } Here is some further explanation about the preceding code. Include the headers and the type of message to use for the topic: #include "ros/ros.h" #include "std_msgs/String.h" This function is called every time that node receives a message. This is where we do something with the data; in this case, we show it in the shell: ROS_INFO() is used to print it in the shell. void messageCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } Create a subscriber and start to listen to the topic with the name message. The buffer will be of 1,000, and the function to handle the message will be messageCallback: ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); The ros::spin() library is a loop where the node starts to read the topic, and when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node will exit the loop and the loop ends: ros::spin(); Building the node As we are using the package chapter2_tutorials, we are going to edit the file CMakeLists.txt. You can use your favorite editor or use the rosed tool. This will open the file with the Vim editor: $ rosed chapter2_tutorials CMakeLists.txt At the end of the file, we copy the following command lines: rosbuild_add_executable(example1_a src/example1_a.cpp) rosbuild_add_executable(example1_b src/example1_b.cpp) 每次该节点收到一条消息时都将调用此函数,我们就可以使用或处理数据。在本示例 中,我们将收到的数据在命令行窗口中输出出来: Chapter 2 [ 55 ] { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, chatterCallback); ros::spin(); return 0; } Here is some further explanation about the preceding code. Include the headers and the type of message to use for the topic: #include "ros/ros.h" #include "std_msgs/String.h" This function is called every time that node receives a message. This is where we do something with the data; in this case, we show it in the shell: ROS_INFO() is used to print it in the shell. void messageCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } Create a subscriber and start to listen to the topic with the name message. The buffer will be of 1,000, and the function to handle the message will be messageCallback: ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); The ros::spin() library is a loop where the node starts to read the topic, and when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node will exit the loop and the loop ends: ros::spin(); Building the node As we are using the package chapter2_tutorials, we are going to edit the file CMakeLists.txt. You can use your favorite editor or use the rosed tool. This will open the file with the Vim editor: $ rosed chapter2_tutorials CMakeLists.txt At the end of the file, we copy the following command lines: rosbuild_add_executable(example1_a src/example1_a.cpp) rosbuild_add_executable(example1_b src/example1_b.cpp) ROS_INFO() 用于在命令行窗口中输出数据。 创建一个订阅者,并从主题获取以 message 为名称的消息数据。设置缓冲区为 1000 个 消息,处理消息句柄的回调函数为 messageCallback: Chapter 2 [ 55 ] { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, chatterCallback); ros::spin(); return 0; } Here is some further explanation about the preceding code. Include the headers and the type of message to use for the topic: #include "ros/ros.h" #include "std_msgs/String.h" This function is called every time that node receives a message. This is where we do something with the data; in this case, we show it in the shell: ROS_INFO() is used to print it in the shell. void messageCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } Create a subscriber and start to listen to the topic with the name message. The buffer will be of 1,000, and the function to handle the message will be messageCallback: ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); The ros::spin() library is a loop where the node starts to read the topic, and when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node will exit the loop and the loop ends: ros::spin(); Building the node As we are using the package chapter2_tutorials, we are going to edit the file CMakeLists.txt. You can use your favorite editor or use the rosed tool. This will open the file with the Vim editor: $ rosed chapter2_tutorials CMakeLists.txt At the end of the file, we copy the following command lines: rosbuild_add_executable(example1_a src/example1_a.cpp) rosbuild_add_executable(example1_b src/example1_b.cpp) ros ::spin() 库是节点读取数据的消息响应循环,当消息到达的时候,回调函数 messageCallback 就会被调用。当用户按下 Ctrl + C 时,节点会退出消息循环,于是循环 结束: Chapter 2 [ 55 ] { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, chatterCallback); ros::spin(); return 0; } Here is some further explanation about the preceding code. Include the headers and the type of message to use for the topic: #include "ros/ros.h" #include "std_msgs/String.h" This function is called every time that node receives a message. This is where we do something with the data; in this case, we show it in the shell: ROS_INFO() is used to print it in the shell. void messageCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } Create a subscriber and start to listen to the topic with the name message. The buffer will be of 1,000, and the function to handle the message will be messageCallback: ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); The ros::spin() library is a loop where the node starts to read the topic, and when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node will exit the loop and the loop ends: ros::spin(); Building the node As we are using the package chapter2_tutorials, we are going to edit the file CMakeLists.txt. You can use your favorite editor or use the rosed tool. This will open the file with the Vim editor: $ rosed chapter2_tutorials CMakeLists.txt At the end of the file, we copy the following command lines: rosbuild_add_executable(example1_a src/example1_a.cpp) rosbuild_add_executable(example1_b src/example1_b.cpp) 2.4.10 编译节点 当使用 chapter2_tutorials 功能包时,需要自行编辑 CMakeLists.txt 文件。你 ROS 系统架构及示例 37 可以使用你喜欢的编辑器或直接使用 rosed 工具。这里我们将会在 VIM 编辑器下打开这个 文件: Chapter 2 [ 55 ] { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, chatterCallback); ros::spin(); return 0; } Here is some further explanation about the preceding code. Include the headers and the type of message to use for the topic: #include "ros/ros.h" #include "std_msgs/String.h" This function is called every time that node receives a message. This is where we do something with the data; in this case, we show it in the shell: ROS_INFO() is used to print it in the shell. void messageCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } Create a subscriber and start to listen to the topic with the name message. The buffer will be of 1,000, and the function to handle the message will be messageCallback: ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); The ros::spin() library is a loop where the node starts to read the topic, and when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node will exit the loop and the loop ends: ros::spin(); Building the node As we are using the package chapter2_tutorials, we are going to edit the file CMakeLists.txt. You can use your favorite editor or use the rosed tool. This will open the file with the Vim editor: $ rosed chapter2_tutorials CMakeLists.txt At the end of the file, we copy the following command lines: rosbuild_add_executable(example1_a src/example1_a.cpp) rosbuild_add_executable(example1_b src/example1_b.cpp) 将以下命令行复制到文件的末尾处: Chapter 2 [ 55 ] { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, chatterCallback); ros::spin(); return 0; } Here is some further explanation about the preceding code. Include the headers and the type of message to use for the topic: #include "ros/ros.h" #include "std_msgs/String.h" This function is called every time that node receives a message. This is where we do something with the data; in this case, we show it in the shell: ROS_INFO() is used to print it in the shell. void messageCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]", msg->data.c_str()); } Create a subscriber and start to listen to the topic with the name message. The buffer will be of 1,000, and the function to handle the message will be messageCallback: ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); The ros::spin() library is a loop where the node starts to read the topic, and when a message arrives, messageCallback is called. When the user presses Ctrl + C, the node will exit the loop and the loop ends: ros::spin(); Building the node As we are using the package chapter2_tutorials, we are going to edit the file CMakeLists.txt. You can use your favorite editor or use the rosed tool. This will open the file with the Vim editor: $ rosed chapter2_tutorials CMakeLists.txt At the end of the file, we copy the following command lines: rosbuild_add_executable(example1_a src/example1_a.cpp) rosbuild_add_executable(example1_b src/example1_b.cpp) 这些命令行会在 /bin 文件夹下创建两个可执行文件。 现在我们使用 rosmake 工具编译功能包就会编译全部的节点: The ROS Architecture with Examples [ 56 ] These lines will create two executables in the /bin folder. Now to build the package and compile all the nodes, use the rosmake tool: $ rosmake chapter2_tutorials If ROS is not running on your computer, you will have to use: $ roscore You can check whether ROS is running using the rosnode list command as follows: $ rosnode list Now, run both the nodes in different shells: $ rosrun chapter2_tutorials example1_a $ rosrun chapter2_tutorials example1_b If you check the shell where the node example1_b is running, you will see something like this: ... [ INFO] [1355228542.283236850]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.383221843]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.483249861]: I heard: [ I am the example1_a node ] ... Everything that is happening can be viewed in the following figure. You can see that the example1_a node is publishing the topic message, and the example2_b node is subscribing to the topic. You can use rosnode and rostopic to debug and see what the nodes are doing. Try the following commands: $ rosnode list $ rosnode info /example1_a 如果在你的电脑上还没有启动 ROS,需要首先调用: The ROS Architecture with Examples [ 56 ] These lines will create two executables in the /bin folder. Now to build the package and compile all the nodes, use the rosmake tool: $ rosmake chapter2_tutorials If ROS is not running on your computer, you will have to use: $ roscore You can check whether ROS is running using the rosnode list command as follows: $ rosnode list Now, run both the nodes in different shells: $ rosrun chapter2_tutorials example1_a $ rosrun chapter2_tutorials example1_b If you check the shell where the node example1_b is running, you will see something like this: ... [ INFO] [1355228542.283236850]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.383221843]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.483249861]: I heard: [ I am the example1_a node ] ... Everything that is happening can be viewed in the following figure. You can see that the example1_a node is publishing the topic message, and the example2_b node is subscribing to the topic. You can use rosnode and rostopic to debug and see what the nodes are doing. Try the following commands: $ rosnode list $ rosnode info /example1_a 你可以使用 rosnode list 命令检查 ROS 是否运行: The ROS Architecture with Examples [ 56 ] These lines will create two executables in the /bin folder. Now to build the package and compile all the nodes, use the rosmake tool: $ rosmake chapter2_tutorials If ROS is not running on your computer, you will have to use: $ roscore You can check whether ROS is running using the rosnode list command as follows: $ rosnode list Now, run both the nodes in different shells: $ rosrun chapter2_tutorials example1_a $ rosrun chapter2_tutorials example1_b If you check the shell where the node example1_b is running, you will see something like this: ... [ INFO] [1355228542.283236850]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.383221843]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.483249861]: I heard: [ I am the example1_a node ] ... Everything that is happening can be viewed in the following figure. You can see that the example1_a node is publishing the topic message, and the example2_b node is subscribing to the topic. You can use rosnode and rostopic to debug and see what the nodes are doing. Try the following commands: $ rosnode list $ rosnode info /example1_a 然后,在不同的 shell 窗口下分别运行以下命令: The ROS Architecture with Examples [ 56 ] These lines will create two executables in the /bin folder. Now to build the package and compile all the nodes, use the rosmake tool: $ rosmake chapter2_tutorials If ROS is not running on your computer, you will have to use: $ roscore You can check whether ROS is running using the rosnode list command as follows: $ rosnode list Now, run both the nodes in different shells: $ rosrun chapter2_tutorials example1_a $ rosrun chapter2_tutorials example1_b If you check the shell where the node example1_b is running, you will see something like this: ... [ INFO] [1355228542.283236850]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.383221843]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.483249861]: I heard: [ I am the example1_a node ] ... Everything that is happening can be viewed in the following figure. You can see that the example1_a node is publishing the topic message, and the example2_b node is subscribing to the topic. You can use rosnode and rostopic to debug and see what the nodes are doing. Try the following commands: $ rosnode list $ rosnode info /example1_a 如果你检查一下 example1_b 正在运行的 shell 窗口,你就会看到以下信息: The ROS Architecture with Examples [ 56 ] These lines will create two executables in the /bin folder. Now to build the package and compile all the nodes, use the rosmake tool: $ rosmake chapter2_tutorials If ROS is not running on your computer, you will have to use: $ roscore You can check whether ROS is running using the rosnode list command as follows: $ rosnode list Now, run both the nodes in different shells: $ rosrun chapter2_tutorials example1_a $ rosrun chapter2_tutorials example1_b If you check the shell where the node example1_b is running, you will see something like this: ... [ INFO] [1355228542.283236850]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.383221843]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.483249861]: I heard: [ I am the example1_a node ] ... Everything that is happening can be viewed in the following figure. You can see that the example1_a node is publishing the topic message, and the example2_b node is subscribing to the topic. You can use rosnode and rostopic to debug and see what the nodes are doing. Try the following commands: $ rosnode list $ rosnode info /example1_a 我们可以在下图中看到正在发生的消息传递。 example1_a 节点发布消息到 message 主题,同时节点 example2_b 订阅了这个主题。 /example1_a /example1_b/message 你可以使用 rosnode 和 rostopic 命令来调试和查看当前节点的运行状况。尝试使用 以下命令: The ROS Architecture with Examples [ 56 ] These lines will create two executables in the /bin folder. Now to build the package and compile all the nodes, use the rosmake tool: $ rosmake chapter2_tutorials If ROS is not running on your computer, you will have to use: $ roscore You can check whether ROS is running using the rosnode list command as follows: $ rosnode list Now, run both the nodes in different shells: $ rosrun chapter2_tutorials example1_a $ rosrun chapter2_tutorials example1_b If you check the shell where the node example1_b is running, you will see something like this: ... [ INFO] [1355228542.283236850]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.383221843]: I heard: [ I am the example1_a node ] [ INFO] [1355228542.483249861]: I heard: [ I am the example1_a node ] ... Everything that is happening can be viewed in the following figure. You can see that the example1_a node is publishing the topic message, and the example2_b node is subscribing to the topic. You can use rosnode and rostopic to debug and see what the nodes are doing. Try the following commands: $ rosnode list $ rosnode info /example1_a Chapter 2 [ 57 ] $ rosnode info /example1_b $ rostopic list $ rostopic info /message $ rostopic type /message $ rostopic bw /message Creating msg and srv files In this section, we are going to learn how to create msg and srv files for using them in our nodes. They are files where we put a specification about the type of data to be transmitted and the values of these data. ROS will use these files to create the necessary code for us to implement the msg and srv files to be used in our nodes. Let's start with the msg file first. In the example used in the Building the node section, we have created two nodes with a standard type message. Now, we are going to learn how to create custom messages with the tools that ROS has. First, create a new folder msg in our package chapter2_tutorials, and create a new file chapter2_msg1 adding the following lines: int32 A int32 B int32 C Now edit CMakeList.txt, remove # from the line # rosbuild_genmsg(), and build the package with rosmake as follows: $ rosmake chapter2_tutorials To check whether all is OK, you can use the rosmsg command: $ rosmsg show chapter2_tutorials/chapter2_msg1 If you see the same content of the file chapter2_msg1.msg, all is OK. Now we are going to create an srv file. Create a new folder in the chapter2_ tutorials folder with the name srv and create a new file chapter2_srv1.srv adding the following lines: int32 A int32 B int32 C --- int32 sum 2.4.11 创建 msg 和 srv 文件 在这一节中,我们将会学习如何在节点中创建 msg 和 srv 文件。它们是用于定义传输 38 第 2 章 数据的类型和数据值的文件。 ROS 会根据这些文件内容自动地为我们创建所需的代码,以便 msg 和 srv 文件能够被节点所使用。第一步,我们先学习 msg 文件。 在上一节所使用的示例中,我们已经创建了两个具有标准类型 massage 的节点。现在, 我们要学习如何使用 ROS 工具创建自定义消息。 首先,在 chapter2_tutorials 功能包下创建 msg 文件夹,并在其中创建一个新的 文件 chapter2_msg1.msg。在文件中增加以下行: Chapter 2 [ 57 ] $ rosnode info /example1_b $ rostopic list $ rostopic info /message $ rostopic type /message $ rostopic bw /message Creating msg and srv files In this section, we are going to learn how to create msg and srv files for using them in our nodes. They are files where we put a specification about the type of data to be transmitted and the values of these data. ROS will use these files to create the necessary code for us to implement the msg and srv files to be used in our nodes. Let's start with the msg file first. In the example used in the Building the node section, we have created two nodes with a standard type message. Now, we are going to learn how to create custom messages with the tools that ROS has. First, create a new folder msg in our package chapter2_tutorials, and create a new file chapter2_msg1 adding the following lines: int32 A int32 B int32 C Now edit CMakeList.txt, remove # from the line # rosbuild_genmsg(), and build the package with rosmake as follows: $ rosmake chapter2_tutorials To check whether all is OK, you can use the rosmsg command: $ rosmsg show chapter2_tutorials/chapter2_msg1 If you see the same content of the file chapter2_msg1.msg, all is OK. Now we are going to create an srv file. Create a new folder in the chapter2_ tutorials folder with the name srv and create a new file chapter2_srv1.srv adding the following lines: int32 A int32 B int32 C --- int32 sum 现在编辑 CMakeList.txt,从 # rosbuild_genmsg() 这一行中删除 #,然后使用 rosmake 命令编译功能包: Chapter 2 [ 57 ] $ rosnode info /example1_b $ rostopic list $ rostopic info /message $ rostopic type /message $ rostopic bw /message Creating msg and srv files In this section, we are going to learn how to create msg and srv files for using them in our nodes. They are files where we put a specification about the type of data to be transmitted and the values of these data. ROS will use these files to create the necessary code for us to implement the msg and srv files to be used in our nodes. Let's start with the msg file first. In the example used in the Building the node section, we have created two nodes with a standard type message. Now, we are going to learn how to create custom messages with the tools that ROS has. First, create a new folder msg in our package chapter2_tutorials, and create a new file chapter2_msg1 adding the following lines: int32 A int32 B int32 C Now edit CMakeList.txt, remove # from the line # rosbuild_genmsg(), and build the package with rosmake as follows: $ rosmake chapter2_tutorials To check whether all is OK, you can use the rosmsg command: $ rosmsg show chapter2_tutorials/chapter2_msg1 If you see the same content of the file chapter2_msg1.msg, all is OK. Now we are going to create an srv file. Create a new folder in the chapter2_ tutorials folder with the name srv and create a new file chapter2_srv1.srv adding the following lines: int32 A int32 B int32 C --- int32 sum 为了检查编译是否正确,可以使用 rosmsg 命令: Chapter 2 [ 57 ] $ rosnode info /example1_b $ rostopic list $ rostopic info /message $ rostopic type /message $ rostopic bw /message Creating msg and srv files In this section, we are going to learn how to create msg and srv files for using them in our nodes. They are files where we put a specification about the type of data to be transmitted and the values of these data. ROS will use these files to create the necessary code for us to implement the msg and srv files to be used in our nodes. Let's start with the msg file first. In the example used in the Building the node section, we have created two nodes with a standard type message. Now, we are going to learn how to create custom messages with the tools that ROS has. First, create a new folder msg in our package chapter2_tutorials, and create a new file chapter2_msg1 adding the following lines: int32 A int32 B int32 C Now edit CMakeList.txt, remove # from the line # rosbuild_genmsg(), and build the package with rosmake as follows: $ rosmake chapter2_tutorials To check whether all is OK, you can use the rosmsg command: $ rosmsg show chapter2_tutorials/chapter2_msg1 If you see the same content of the file chapter2_msg1.msg, all is OK. Now we are going to create an srv file. Create a new folder in the chapter2_ tutorials folder with the name srv and create a new file chapter2_srv1.srv adding the following lines: int32 A int32 B int32 C --- int32 sum 如果你在 chapter2_msg1.msg 文件中看到一样的内容,说明编译正确。 现在创建一个 srv 文件。在 chapter2_tutorials 文件夹下创建一个名为 srv 的文 件夹,并新建文件 chapter2_srv1.srv,在文件中增加以下行: Chapter 2 [ 57 ] $ rosnode info /example1_b $ rostopic list $ rostopic info /message $ rostopic type /message $ rostopic bw /message Creating msg and srv files In this section, we are going to learn how to create msg and srv files for using them in our nodes. They are files where we put a specification about the type of data to be transmitted and the values of these data. ROS will use these files to create the necessary code for us to implement the msg and srv files to be used in our nodes. Let's start with the msg file first. In the example used in the Building the node section, we have created two nodes with a standard type message. Now, we are going to learn how to create custom messages with the tools that ROS has. First, create a new folder msg in our package chapter2_tutorials, and create a new file chapter2_msg1 adding the following lines: int32 A int32 B int32 C Now edit CMakeList.txt, remove # from the line # rosbuild_genmsg(), and build the package with rosmake as follows: $ rosmake chapter2_tutorials To check whether all is OK, you can use the rosmsg command: $ rosmsg show chapter2_tutorials/chapter2_msg1 If you see the same content of the file chapter2_msg1.msg, all is OK. Now we are going to create an srv file. Create a new folder in the chapter2_ tutorials folder with the name srv and create a new file chapter2_srv1.srv adding the following lines: int32 A int32 B int32 C --- int32 sum 编辑 CMakeList.txt 文件,从 #rosbuild_gensrv() 这一行中删除 #,并且使用 rosmake chapter2_tutorials 命令编译功能包。 你可以通过 rossrv 工具来检查编译是否正确: The ROS Architecture with Examples [ 58 ] Edit CMakeList.txt, and remove # from the line # rosbuild_gensrv(), and build the package with rosmake chapter2_tutorials. You can test whether all is OK using the rossrv tool as follows: $ rossrv show chapter2_tutorials/chapter2_srv1 If you see the same content of the file chapter2_srv1.srv, all is OK. Using the new srv and msg files First, we are going to learn how to create a service and how to use it in ROS. Our service will calculate the sum of three numbers. We need two nodes, a server and a client. In the package chapter2_tutorials, create two new nodes with names: example2_a.cpp and example2_b.cpp. Remember to put the files in the src folder. In the first file, example2_a.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) { res.sum = req.A + req.B + req.C; ROS_INFO("request: A=%ld, B=%ld C=%ld", (int)req.A, (int)req.B, (int)req.C); ROS_INFO("sending back response: [%ld]", (int)res.sum); return true; } int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_server"); ros::NodeHandle n; ros::ServiceServer service = n.advertiseService("add_3_ints", add); ROS_INFO("Ready to add 3 ints."); ros::spin(); return 0; } 如果你在 chapter2_srv1.srv 文件中看到相同的内容,说明编译正确。 2.4.12 使用新建的 srv 和 msg 文件 首先,我们将会学习如何创建一个服务并且在 ROS 中使用它。该服务将会对三个整数 求和。我们需要两个节点,一个服务器一个客户端。 在 chapter2_tutorials 功能包中,新建两个节点并使用 example2_a.cpp 和 example2_b.cpp 为名称。别忘了要在 src 文件夹下创建这两个文件。 在第一个文件 example2_a.cpp 中,添加以下代码: The ROS Architecture with Examples [ 58 ] Edit CMakeList.txt, and remove # from the line # rosbuild_gensrv(), and build the package with rosmake chapter2_tutorials. You can test whether all is OK using the rossrv tool as follows: $ rossrv show chapter2_tutorials/chapter2_srv1 If you see the same content of the file chapter2_srv1.srv, all is OK. Using the new srv and msg files First, we are going to learn how to create a service and how to use it in ROS. Our service will calculate the sum of three numbers. We need two nodes, a server and a client. In the package chapter2_tutorials, create two new nodes with names: example2_a.cpp and example2_b.cpp. Remember to put the files in the src folder. In the first file, example2_a.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) { res.sum = req.A + req.B + req.C; ROS_INFO("request: A=%ld, B=%ld C=%ld", (int)req.A, (int)req.B, (int)req.C); ROS_INFO("sending back response: [%ld]", (int)res.sum); return true; } int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_server"); ros::NodeHandle n; ros::ServiceServer service = n.advertiseService("add_3_ints", add); ROS_INFO("Ready to add 3 ints."); ros::spin(); return 0; } ROS 系统架构及示例 39 The ROS Architecture with Examples [ 58 ] Edit CMakeList.txt, and remove # from the line # rosbuild_gensrv(), and build the package with rosmake chapter2_tutorials. You can test whether all is OK using the rossrv tool as follows: $ rossrv show chapter2_tutorials/chapter2_srv1 If you see the same content of the file chapter2_srv1.srv, all is OK. Using the new srv and msg files First, we are going to learn how to create a service and how to use it in ROS. Our service will calculate the sum of three numbers. We need two nodes, a server and a client. In the package chapter2_tutorials, create two new nodes with names: example2_a.cpp and example2_b.cpp. Remember to put the files in the src folder. In the first file, example2_a.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) { res.sum = req.A + req.B + req.C; ROS_INFO("request: A=%ld, B=%ld C=%ld", (int)req.A, (int)req.B, (int)req.C); ROS_INFO("sending back response: [%ld]", (int)res.sum); return true; } int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_server"); ros::NodeHandle n; ros::ServiceServer service = n.advertiseService("add_3_ints", add); ROS_INFO("Ready to add 3 ints."); ros::spin(); return 0; } 还需要包含必要的头文件和我们创建的 srv 文件: Chapter 2 [ 59 ] Include the necessary headers and srv that we created: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" This function will add three variables and send the result to the other node: bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) Here, the service is created and advertised over ROS as follows: ros::ServiceServer service = n.advertiseService("add_3_ints", add); In the second file, example2_b.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_client"); if (argc != 4) { ROS_INFO("usage: add_3_ints_client A B C "); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient("add_3_ints"); chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_3_ints"); return 1; } return 0; } 这个函数会对 3 个变量求和,并将计算结果发送给其他节点: Chapter 2 [ 59 ] Include the necessary headers and srv that we created: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" This function will add three variables and send the result to the other node: bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) Here, the service is created and advertised over ROS as follows: ros::ServiceServer service = n.advertiseService("add_3_ints", add); In the second file, example2_b.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_client"); if (argc != 4) { ROS_INFO("usage: add_3_ints_client A B C "); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient("add_3_ints"); chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_3_ints"); return 1; } return 0; } 在这里,创建服务并在 ROS 中发布广播,如下: Chapter 2 [ 59 ] Include the necessary headers and srv that we created: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" This function will add three variables and send the result to the other node: bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) Here, the service is created and advertised over ROS as follows: ros::ServiceServer service = n.advertiseService("add_3_ints", add); In the second file, example2_b.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_client"); if (argc != 4) { ROS_INFO("usage: add_3_ints_client A B C "); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient("add_3_ints"); chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_3_ints"); return 1; } return 0; } 在第 2 个文件 example2_b.cpp 中,增加以下代码: Chapter 2 [ 59 ] Include the necessary headers and srv that we created: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" This function will add three variables and send the result to the other node: bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) Here, the service is created and advertised over ROS as follows: ros::ServiceServer service = n.advertiseService("add_3_ints", add); In the second file, example2_b.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_client"); if (argc != 4) { ROS_INFO("usage: add_3_ints_client A B C "); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient("add_3_ints"); chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_3_ints"); return 1; } return 0; } 40 第 2 章 Chapter 2 [ 59 ] Include the necessary headers and srv that we created: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" This function will add three variables and send the result to the other node: bool add(chapter2_tutorials::chapter2_srv1::Request &req, chapter2_tutorials::chapter2_srv1::Response &res) Here, the service is created and advertised over ROS as follows: ros::ServiceServer service = n.advertiseService("add_3_ints", add); In the second file, example2_b.cpp, add this code: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_srv1.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "add_3_ints_client"); if (argc != 4) { ROS_INFO("usage: add_3_ints_client A B C "); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient("add_3_ints"); chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_3_ints"); return 1; } return 0; } 使用 add_3_ints 为名称创建一个服务的客户端: The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. 下面创建 srv 文件的一个实例,并且加入需要发送的数据值。如果你还记得,这个消息 需要 3 个字段: The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. 这些代码会调用服务并发送数据。如果调用成功, call() 函数会返回 true;如果没成 功,call() 函数会返回 false: The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. 为了编译节点,在 CMakeList.txt 文件中增加以下行: The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. 现在执行以下命令: The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. 为了启动节点,需要执行以下命令行: The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. 并且你会看到如下显示: The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. ROS 系统架构及示例 41 The ROS Architecture with Examples [ 60 ] Create a client for the service with the name add_3_ints: ros::ServiceClient client = n.serviceClient("add_3_ints"); Here we create an instance of our srv file and fill all the values to be sent. If you remember, the message has three fields: chapter2_tutorials::chapter2_srv1 srv; srv.request.A = atoll(argv[1]); srv.request.B = atoll(argv[2]); srv.request.C = atoll(argv[3]); With these lines, the service is called and the data is sent. If the call succeeds, call() will return true; if not, call() will return false: if (client.call(srv)) To build new nodes, edit CMakeList.txt and add the following lines: rosbuild_add_executable(example2_a src/example2_a.cpp) rosbuild_add_executable(example2_b src/example2_b.cpp) Now execute the following command: $ rosmake chapter2_tutorials To start the nodes, execute the following command lines: $rosrun chapter2_tutorials example2_a $rosrun chapter2_tutorials example2_b 1 2 3 And you should see something like this: Node example2_a [ INFO] [1355256113.014539262]: Ready to add 3 ints. [ INFO] [1355256115.792442091]: request: A=1, B=2 C=3 [ INFO] [1355256115.792607196]: sending back response: [6] Node example2_b [ INFO] [1355256115.794134975]: Sum: 6 Now we are going to create nodes with our custom msg file. The example is the same, that is, example1_a.cpp and example1_a.cpp but with the new message chapter2_msg1.msg. 现在将要用自定义的 msg 文件来创建节点。这个例子也一样,创建 example3_a.cpp 和 example3_b.cpp 文件,同时调用 chapter2_msg1.msg。 将下面的代码放在 example3_a.cpp 文件中: Chapter 2 [ 61 ] The following code snippet is present in the example3_a.cpp file: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_msg1.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "example1_a"); ros::NodeHandle n; ros::Publisher pub = n.advertise("message", 1000); ros::Rate loop_rate(10); while (ros::ok()) { chapter2_tutorials::chapter2_msg1 msg; msg.A = 1; msg.B = 2; msg.C = 3; pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } The following code snippet is present in the example3_b.cpp file: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_msg1.h" void messageCallback(const chapter2_tutorials::chapter2_ msg1::ConstPtr& msg) { ROS_INFO("I heard: [%d] [%d] [%d]", msg->A, msg->B, msg->C); } int main(int argc, char **argv) { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); ros::spin(); return 0; } 将下面的代码放在 example3_b.cpp 文件中: Chapter 2 [ 61 ] The following code snippet is present in the example3_a.cpp file: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_msg1.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "example1_a"); ros::NodeHandle n; ros::Publisher pub = n.advertise("message", 1000); ros::Rate loop_rate(10); while (ros::ok()) { chapter2_tutorials::chapter2_msg1 msg; msg.A = 1; msg.B = 2; msg.C = 3; pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; } The following code snippet is present in the example3_b.cpp file: #include "ros/ros.h" #include "chapter2_tutorials/chapter2_msg1.h" void messageCallback(const chapter2_tutorials::chapter2_ msg1::ConstPtr& msg) { ROS_INFO("I heard: [%d] [%d] [%d]", msg->A, msg->B, msg->C); } int main(int argc, char **argv) { ros::init(argc, argv, "example1_b"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("message", 1000, messageCallback); ros::spin(); return 0; } 如果现在运行这两个节点,将会看到如下信息: 42 第 2 章The ROS Architecture with Examples [ 62 ] If we run both the nodes now, we will see something like this: … [ INFO] [1355270835.920368620]: I heard: [1] [2] [3] [ INFO] [1355270836.020326372]: I heard: [1] [2] [3] [ INFO] [1355270836.120367449]: I heard: [1] [2] [3] [ INFO] [1355270836.220266466]: I heard: [1] [2] [3] … Summary This chapter provides you with general knowledge of the ROS architecture and how it works. You saw some concepts, tools, and samples of how to interact with nodes, topics, and services. In the beginning, all these concepts could look complicated and without use, but in the upcoming chapters, you will start to understand the applications of these. It is useful to practice with these terms and tutorials before continuing because, in the upcoming chapters, we will suppose that you know all the concepts and uses. Remember that if you have queries regarding something, and you cannot find the solution in this book, you can use the official resources of ROS from the URL http://www.ros.org. Additionally, you can ask questions to the ROS community at http://answers.ros.org. In the next chapter, you will learn how to debug and visualize data using ROS tools. These will help you find problems and to know whether what ROS is doing is correct, and what you expect it to do. 2.5 本章小结 本章介绍了 ROS 系统的基本架构及其典型的工作方式。学习了一些基本概念、工具及 如何同节点、主题和服务进行交互的示例。一开始,所有这些概念可能看起来有些复杂且不 太实用,但在后面的章节中,你会逐渐理解如何使用这些概念所代表的对象。 各位读者最好在继续后续章节的学习之前,对这些概念及示例进行练习,因为在后面的 章节里,我们将假定你已经熟悉所有的概念及其用途。 请注意如果想查询某个名词或功能的解释,且无法在这本书中找到相关内容或答案,那 么可以通过以下链接访问 ROS 官方资源 http://www.ros.org。而且,你还可以通过访问 ROS 社区 http://answers.ros.org 提出自己的问题。 在下一章中,将学习如何使用 ROS 工具查询调试信息和实现数据的可视化。这些将帮 助你理解 ROS 的运行状态,发现软件运行的问题,并且指导你对它的运行进行调整。 第 3 章 调试和可视化 ROS 软件框架附带了大量功能强大的工具,帮助用户和开发人员检测软硬件问题并完成 代码调试。这包括了调试工具(如日志消息记录与展示工具)、数据可视化工具和系统监测组 件。这些工具使得用户轻松地以自己喜欢的方式查看系统运行状态。 在这里,我们还会以 GDB 调试器为例解释调试 ROS 节点的工作流程。虽然这和调试一 般的 C/C++ 程序没有什么不同,但还是需要说明几个必须要考虑到的地方。我们将只着重说 明这几个特殊点,因为解释如何使用调试器已经超出了本章的范围。相对而言,我们希望你 能够去阅读 GDB 的参考文档和用户手册。 ROS 提供用于日志记录的 API。在输出信息时,它允许根据信息的重要性来选择不同的日 志记录级别。这样做的目的在于在发生故障时,能够提供更丰富内容帮助开发人员进行调试, 并最终提供具有更高鲁棒性的程序。正如后面会看到的,我们可以通过高级通知消息告知用户 算法运行信息,或警告用户出现了遗漏的值和参数,或记录无法恢复的故障和致命的错误。 然而,在程序编译和运行时仍然可能会失败。这时,可能发生两个关键的问题:首先, 一个问题与节点、主题、服务或任何其他 ROS 组件有关;第二,我们的算法本身也可能导致 问题。ROS 提供了一组功能强大的工具来监视系统状态。例如下面截屏中所示的节点状态图, 在图中能够显示主题间(发布者和订阅者)的所有连接。无论是本地节点还是远程节点都被 无缝部署,以便用户能够轻松、迅速地检测如节点未运行或主题连接缺失等问题。 44 第 3 章 在某种程度上,ROS 提供了一系列通用绘图工具以分析自定义算法的输出或结果,以 便更容易地检测 bug。首先,有针对标量值的时序绘图工具,这常用于节点间传递的消息字 段的图形化展示;其次,有支持双目立体视觉的图像展示工具;再次,有如 rviz 等 3D 可视 化工具(如下面截屏所示,图中为 PR2 机器人),这些工具能够呈现点云、激光扫描等 3D 数 据。这些是很特殊的数据格式,数据相关于特定的传感器坐标空间,并通过坐标来呈现数 据。一个机器人一般由多个坐标空间组成,坐标空间之间能够进行变换。为了帮助用户查看 它们之间的关系,也有查看坐标空间层次结构的工具。 在本章中,将介绍以下内容: ● 创建 ROS 节点时,调试和优化代码。 ● 为代码添加消息日志并设置不同的级别,包括调试消息、错误、致命错误。 ● 日志命名、应用特定条件、消息日志条件显示,这些在大型项目中非常有用。 ● 介绍一个管理所有消息的图形化工具。 ● 通过列出节点运行状态和可用的主题与服务来监视 ROS 系统的状态。 ● 节点状态图形以图形形式展示,以主题连接发布者和订阅者。 ● 绘制特定消息的标量数据。 ● 复杂类型的标量数据可视化。特别是将介绍图像显示、FireWire 接口摄像头的实例和 多种消息类型的 3D 可视化。这些都在 ROS 中实现了无缝支持。 ● 解释坐标空间以及它们与特定主题的消息之间的关系。同样将会看到在坐标变换树中 的空间坐标变换。 ● 保存主题发送的消息和如何为了仿真或测试重播已发的消息。 3.1 调试 ROS 节点 为了检测 ROS 节点内部算法执行的问题,可以从不同层面面对问题,使软件调试更加 调试和可视化 45 容易。首先,必须针对算法、驱动或其他软件代码提供一些可读的关于计算进度和状态的信 息。为达到这个目的, ROS 提供了一套覆盖整个系统的日志记录宏。其次,可以根据需要 配置不同的日志级别,这需要使用日志工具来确定将哪个节点的相关日志配置成哪个具体级 别。在 ROS 的示例中,还将看到如何针对特定消息的条件和名称设置调试 / 日志记录级别。 再次,必须能够使用调试器单步执行源代码。我们将看到广为人知的 GDB 调试器与 ROS 节 点无缝集成。最后,通过查看 ROS 节点和主题的抽象语义,有效地监视整个系统的当前状 态。这种 ROS 系统的内部检查通过绘制主题间的节点连接图工具实现。用户或开发人员可 以一目了然地发现某个连接断开,这些会在后续章节中介绍。 3.1.1 使用 GDB 调试器调试 ROS 节点 从调试任意 C/C++ 可执行文件的标准方法开始。 ROS 的灵活性允许使用众所周知的 GDB 调试器对常规的 C/C++ 程序进行调试,唯一要知道的是可执行文件的路径,这在 ROS 系统里通常是用 C++ 程序编写的某个节点的位置。因此,我们只需要将当前路径移动到包含 二进制文件的节点目录下并在 GDB 中运行这些代码。实际上,还可以直接运行节点而无需 使用标准的 rosrun 的语法。 简单地说,我们将向你展示如何在 GDB 中运行 chapter3_tutorials 功能包中的 example1 节点。首先,使用 roscd 命令移动到功能包路径下: Debugging and Visualization [ 66 ] Debugging ROS nodes In order to detect problems in the algorithms implemented inside ROS nodes, we can face the problem at different levels to make the debugging of the software easier. First, we must provide some readable information about the progress of the algorithm, driver, or another piece of software. In ROS, we have a set of logging macros for this particular purpose, which are completely integrated with the whole system. Second, we need tools to determine which verbosity level is desired for a given node; this is related to the ability to configure different logging levels. In the case of ROS, we will see how it is possible to set debugging/logging levels even on the fly as well as conditions and names for particular messages. Third, we must be able to use a debugger to step over the source code. We will see that the widely known GDB debugger integrates seamlessly with ROS nodes. Finally, at the abstraction (or semantic) level of ROS nodes and topics, it is useful to inspect the current state of the whole system. Such introspection capabilities in ROS are supported by means of tools that draw the nodes graph with connections among topics. The user or developer can easily detect a broken connection at a glance, as we will explain later in another section. Using the GDB debugger with ROS nodes We will start with the standard way of debugging C/C++ executables of any kind. The flexibility of ROS allows using the well-known GDB debugger with a regular C/C++ program. All we have to know is the location of our executable, which in the case of ROS would be a node implemented in C++. Therefore, we only have to move to the path that contains the node binary and run it within GDB. Indeed, we could also run our node directly without the typical rosrun syntax. To make it simple, we will show you how to run a node in GDB for the example1 node in the chapter3_tutorials package. First, move to the package with roscd as follows: roscd chapter3_tutorials Then, we only have to recall that C++ binaries are created inside the bin folder of the package folder's structure. Hence, we simply run it inside GDB using the following command: gdb bin/example1 Remember that you must have a roscore command running before you start your node because it will need the master/server running. 然后,要记得在功能包文件夹下的 bin 文件夹中创建 C++ 程序文件。因此,只需在 GDB 里面运行以下命令: Debugging and Visualization [ 66 ] Debugging ROS nodes In order to detect problems in the algorithms implemented inside ROS nodes, we can face the problem at different levels to make the debugging of the software easier. First, we must provide some readable information about the progress of the algorithm, driver, or another piece of software. In ROS, we have a set of logging macros for this particular purpose, which are completely integrated with the whole system. Second, we need tools to determine which verbosity level is desired for a given node; this is related to the ability to configure different logging levels. In the case of ROS, we will see how it is possible to set debugging/logging levels even on the fly as well as conditions and names for particular messages. Third, we must be able to use a debugger to step over the source code. We will see that the widely known GDB debugger integrates seamlessly with ROS nodes. Finally, at the abstraction (or semantic) level of ROS nodes and topics, it is useful to inspect the current state of the whole system. Such introspection capabilities in ROS are supported by means of tools that draw the nodes graph with connections among topics. The user or developer can easily detect a broken connection at a glance, as we will explain later in another section. Using the GDB debugger with ROS nodes We will start with the standard way of debugging C/C++ executables of any kind. The flexibility of ROS allows using the well-known GDB debugger with a regular C/C++ program. All we have to know is the location of our executable, which in the case of ROS would be a node implemented in C++. Therefore, we only have to move to the path that contains the node binary and run it within GDB. Indeed, we could also run our node directly without the typical rosrun syntax. To make it simple, we will show you how to run a node in GDB for the example1 node in the chapter3_tutorials package. First, move to the package with roscd as follows: roscd chapter3_tutorials Then, we only have to recall that C++ binaries are created inside the bin folder of the package folder's structure. Hence, we simply run it inside GDB using the following command: gdb bin/example1 Remember that you must have a roscore command running before you start your node because it will need the master/server running. Chapter 7 [ 229 ] Notice that the data is the same as the one you can see on the Gazebo screen. As you can observe, Gazebo is creating the odometry as the robot moves. We are going to see how Gazebo creates it by looking inside the plugin's source code. The plugin file is located in the erratic_gazebo_plugins package, and the file is diffdrive_plugin.cpp. Open the file and you will see the following code inside the file: $ rosed erratic_gazebo_plugins diffdrive_plugin.cpp The file has a lot of code, but the important part for us now is the following function, publish_odometry(): void DiffDrivePlugin::publish_odometry() { ros::Time current_time = ros::Time::now(); std::string odom_frame = tf::resolve(tf_prefix_, "odom"); std::string base_footprint_frame = tf::resolve(tf_prefix_, "base_ footprint"); // getting data for base_footprint to odom transform math::Pose pose = this->parent->GetState().GetPose(); btQuaternion qt(pose.rot.x, pose.rot.y, pose.rot.z, pose.rot.w); btVector3 vt(pose.pos.x, pose.pos.y, pose.pos.z); tf::Transform base_footprint_to_odom(qt, vt); transform_broadcaster_->sendTransform(tf::StampedTransform(base_ footprint_to_odom, current_time, odom_frame, base_footprint_frame)); // publish odom topic odom_.pose.pose.position.x = pose.pos.x; odom_.pose.pose.position.y = pose.pos.y; odom_.pose.pose.orientation.x = pose.rot.x; odom_.pose.pose.orientation.y = pose.rot.y; odom_.pose.pose.orientation.z = pose.rot.z; odom_.pose.pose.orientation.w = pose.rot.w; math::Vector3 linear = this->parent->GetWorldLinearVel(); odom_.twist.twist.linear.x = linear.x; odom_.twist.twist.linear.y = linear.y; odom_.twist.twist.angular.z = this->parent->GetWorldAngularVel().z; 请记住在启动节点之前请务必调用 roscore 命令,因为 ROS 需要启动节点管理 器及其他核心服务进程。 一旦 roscore 已经运行,你就可以通过点击 R 键和 Enter 键从 GDB 中启动节点;也可 以用 L 键列出相关源代码,以及设置断点或使用任何 GDB 附带的功能。如果一切工作正常, 在调试器内运行节点后就能在 GDB 终端看到下面的输出: Chapter 3 [ 67 ] Once roscore is running, you can start your node in GDB by pressing the R key and Enter. You can also list the associated source code with the L key as well as set breakpoints or any of the functionalities that GDB comes with. If everything works correctly, you should see the following output in the GDB terminal after you have run the node inside the debugger: (gdb) r Starting program: /home/enrique/dev/rosbook/chapter3_tutorials/bin/ example1 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_ db.so.1". [New Thread 0x7ffff2664700 (LWP 3204)] ... ... [Thread 0x7ffff1e63700 (LWP 3205) exited] [Inferior 1 (process 3200) exited normally] Attaching a node to GDB while launching ROS If we have a launch file to start our node, we have some attribute in the XML syntax that allows us to attach the node to a GDB session. For the previous node, example1, in the package chapter3_tutorials, we will add the following node element to the launch file: Note that the package is passed to the pkg attribute and the node to the type attribute. We also have to give this instance of the node a name since we can run more than one instance of the same node. In this case, we gave the same name as the node type, that is, the name attribute, which has the value example1. It is also a good practice to set the attribute output to screen, so the debugging messages, which we will see in the following code snippet, appear on the same terminal where we launched the node: 46 第 3 章 Chapter 3 [ 67 ] Once roscore is running, you can start your node in GDB by pressing the R key and Enter. You can also list the associated source code with the L key as well as set breakpoints or any of the functionalities that GDB comes with. If everything works correctly, you should see the following output in the GDB terminal after you have run the node inside the debugger: (gdb) r Starting program: /home/enrique/dev/rosbook/chapter3_tutorials/bin/ example1 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_ db.so.1". [New Thread 0x7ffff2664700 (LWP 3204)] ... ... [Thread 0x7ffff1e63700 (LWP 3205) exited] [Inferior 1 (process 3200) exited normally] Attaching a node to GDB while launching ROS If we have a launch file to start our node, we have some attribute in the XML syntax that allows us to attach the node to a GDB session. For the previous node, example1, in the package chapter3_tutorials, we will add the following node element to the launch file: Note that the package is passed to the pkg attribute and the node to the type attribute. We also have to give this instance of the node a name since we can run more than one instance of the same node. In this case, we gave the same name as the node type, that is, the name attribute, which has the value example1. It is also a good practice to set the attribute output to screen, so the debugging messages, which we will see in the following code snippet, appear on the same terminal where we launched the node: 3.1.2 ROS 节点启动时调用 GDB 调试器 如果在启动节点时使用启动文件来完成的话,就可以通过使用 XML 语法修改启动文件 中的节点属性,在节点启动时调用 GDB 调试器。以前文示例中的节点为例,即 chapter3_ tutorials 功能包中的 example1,添加以下节点信息到 launch 文件: Chapter 3 [ 67 ] Once roscore is running, you can start your node in GDB by pressing the R key and Enter. You can also list the associated source code with the L key as well as set breakpoints or any of the functionalities that GDB comes with. If everything works correctly, you should see the following output in the GDB terminal after you have run the node inside the debugger: (gdb) r Starting program: /home/enrique/dev/rosbook/chapter3_tutorials/bin/ example1 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_ db.so.1". [New Thread 0x7ffff2664700 (LWP 3204)] ... ... [Thread 0x7ffff1e63700 (LWP 3205) exited] [Inferior 1 (process 3200) exited normally] Attaching a node to GDB while launching ROS If we have a launch file to start our node, we have some attribute in the XML syntax that allows us to attach the node to a GDB session. For the previous node, example1, in the package chapter3_tutorials, we will add the following node element to the launch file: Note that the package is passed to the pkg attribute and the node to the type attribute. We also have to give this instance of the node a name since we can run more than one instance of the same node. In this case, we gave the same name as the node type, that is, the name attribute, which has the value example1. It is also a good practice to set the attribute output to screen, so the debugging messages, which we will see in the following code snippet, appear on the same terminal where we launched the node: 请注意在上面的配置中,功能包名传递给 pkg 属性,节点名传递给 type 属性。由于同 一节点可以运行多个实例,因此需要给这个节点的实例起一个名称。在这种情况下,我们给 出了与节点类型相同的名称,也就是把 name 属性赋值为 example1。同时,最好将这些属 性配置输出到屏幕,这样就会在与启动节点相同的 shell 窗口中出现相应调试信息,正如下面 的代码所示: Chapter 3 [ 67 ] Once roscore is running, you can start your node in GDB by pressing the R key and Enter. You can also list the associated source code with the L key as well as set breakpoints or any of the functionalities that GDB comes with. If everything works correctly, you should see the following output in the GDB terminal after you have run the node inside the debugger: (gdb) r Starting program: /home/enrique/dev/rosbook/chapter3_tutorials/bin/ example1 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_ db.so.1". [New Thread 0x7ffff2664700 (LWP 3204)] ... ... [Thread 0x7ffff1e63700 (LWP 3205) exited] [Inferior 1 (process 3200) exited normally] Attaching a node to GDB while launching ROS If we have a launch file to start our node, we have some attribute in the XML syntax that allows us to attach the node to a GDB session. For the previous node, example1, in the package chapter3_tutorials, we will add the following node element to the launch file: Note that the package is passed to the pkg attribute and the node to the type attribute. We also have to give this instance of the node a name since we can run more than one instance of the same node. In this case, we gave the same name as the node type, that is, the name attribute, which has the value example1. It is also a good practice to set the attribute output to screen, so the debugging messages, which we will see in the following code snippet, appear on the same terminal where we launched the node: 想要在节点启动时调用GDB 调试器,需要添加launch-prefix="xterm-egdb-- args": Debugging and Visualization [ 68 ] To attach it to GDB, we must add launch-prefix="xterm -e gdb --args": What this prefix does is very simple. It starts GDB, loads our node, and waits until the user presses the C or R key; that is, the node is loaded but waiting to run. This way the user can set breakpoints before the node runs and interact as a regular GDB session. Also, note that a new window opens up. This is because we create the GDB session in xterm, so we have a debugging window separated from the program output window. Additionally, we can use the same attribute to attach the node to other diagnostic tools; for example, we can run valgrind on our program to detect memory leaks and perform some profiling analysis. For further information on valgrind, you can check out http://valgrind.org. To attach our node to it, we proceed in a similar way as we did with GDB. In this case, we do not need an additional window, so that we do not start xterm, and simply set valgrind as the launch prefix: Enabling core dumps for ROS nodes Although ROS nodes are actually regular executables, there are some tricky points to note to enable core dumps that can be used later in a GDB session. First of all, we have to set an unlimited core size. Note that this is required for any executable, not just ROS nodes: ulimit -c unlimited Then, to allow core dumps to be created, we must set the core filename to use the process pid by default; otherwise, they will not be created because at $ROS_HOME, there is already a core directory to prevent core dumps. Therefore, in order to create core dumps with the name and path $ROS_HOME/core.PID, we must do the following: echo 1 > /proc/sys/kernel/core_uses_pid 这个语句的功能很好理解。它会在加载节点的同时启动 GDB 调试器,一直等待用户按 C 键或 R 键,也就是说加载节点并等待运行。这种方式,用户可以在节点运行之前设置断 点或与一般 GDB 会话一样执行各种功能。此外,请注意这时会打开一个新窗口。因为是在 xterm 上创建 GDB 会话,所以区别于程序输出窗口,还会有一个调试窗口。 此外,我们可以使用相同的属性在节点启动时调用其他诊断工具。例如,可以在程序上 启动 valgrind 来检测内存泄漏,并执行性能分析。你可以访问 http://valgrind.org 获取有关 valgrind 的详细信息。我们可以使用和 GDB 类似的方式把节点附加上去。这时不需要额 外的窗口,所以不启动 xterm,只需设置 valgrind 为启动前缀: Debugging and Visualization [ 68 ] To attach it to GDB, we must add launch-prefix="xterm -e gdb --args": What this prefix does is very simple. It starts GDB, loads our node, and waits until the user presses the C or R key; that is, the node is loaded but waiting to run. This way the user can set breakpoints before the node runs and interact as a regular GDB session. Also, note that a new window opens up. This is because we create the GDB session in xterm, so we have a debugging window separated from the program output window. Additionally, we can use the same attribute to attach the node to other diagnostic tools; for example, we can run valgrind on our program to detect memory leaks and perform some profiling analysis. For further information on valgrind, you can check out http://valgrind.org. To attach our node to it, we proceed in a similar way as we did with GDB. In this case, we do not need an additional window, so that we do not start xterm, and simply set valgrind as the launch prefix: Enabling core dumps for ROS nodes Although ROS nodes are actually regular executables, there are some tricky points to note to enable core dumps that can be used later in a GDB session. First of all, we have to set an unlimited core size. Note that this is required for any executable, not just ROS nodes: ulimit -c unlimited Then, to allow core dumps to be created, we must set the core filename to use the process pid by default; otherwise, they will not be created because at $ROS_HOME, there is already a core directory to prevent core dumps. Therefore, in order to create core dumps with the name and path $ROS_HOME/core.PID, we must do the following: echo 1 > /proc/sys/kernel/core_uses_pid 调试和可视化 47 3.1.3 设置 ROS 节点 core 文件转存 虽然 ROS 节点实际上就是一般的可执行文件,但在设置 GDB 的 core 内存文件转存 (core dump)时仍有一些棘手的问题需要注意。首先,要取消 core 文件大小限制。请注意这 适用于任何可执行文件,不只是 ROS 节点: Debugging and Visualization [ 68 ] To attach it to GDB, we must add launch-prefix="xterm -e gdb --args": What this prefix does is very simple. It starts GDB, loads our node, and waits until the user presses the C or R key; that is, the node is loaded but waiting to run. This way the user can set breakpoints before the node runs and interact as a regular GDB session. Also, note that a new window opens up. This is because we create the GDB session in xterm, so we have a debugging window separated from the program output window. Additionally, we can use the same attribute to attach the node to other diagnostic tools; for example, we can run valgrind on our program to detect memory leaks and perform some profiling analysis. For further information on valgrind, you can check out http://valgrind.org. To attach our node to it, we proceed in a similar way as we did with GDB. In this case, we do not need an additional window, so that we do not start xterm, and simply set valgrind as the launch prefix: Enabling core dumps for ROS nodes Although ROS nodes are actually regular executables, there are some tricky points to note to enable core dumps that can be used later in a GDB session. First of all, we have to set an unlimited core size. Note that this is required for any executable, not just ROS nodes: ulimit -c unlimited Then, to allow core dumps to be created, we must set the core filename to use the process pid by default; otherwise, they will not be created because at $ROS_HOME, there is already a core directory to prevent core dumps. Therefore, in order to create core dumps with the name and path $ROS_HOME/core.PID, we must do the following: echo 1 > /proc/sys/kernel/core_uses_pid 然后,为了能够创建 core 文件转存,必须将 core 文件名设置为默认使用的进程 pid, 否则,它们会无法创建,因为在 $ ROS_HOME 已有一个 core 目录会防止 core 文件转存。因 此,为了创建 core 文件转存的名称和路径 $ ROS_ HOME/core.PID,必须按照如下命令: Debugging and Visualization [ 68 ] To attach it to GDB, we must add launch-prefix="xterm -e gdb --args": What this prefix does is very simple. It starts GDB, loads our node, and waits until the user presses the C or R key; that is, the node is loaded but waiting to run. This way the user can set breakpoints before the node runs and interact as a regular GDB session. Also, note that a new window opens up. This is because we create the GDB session in xterm, so we have a debugging window separated from the program output window. Additionally, we can use the same attribute to attach the node to other diagnostic tools; for example, we can run valgrind on our program to detect memory leaks and perform some profiling analysis. For further information on valgrind, you can check out http://valgrind.org. To attach our node to it, we proceed in a similar way as we did with GDB. In this case, we do not need an additional window, so that we do not start xterm, and simply set valgrind as the launch prefix: Enabling core dumps for ROS nodes Although ROS nodes are actually regular executables, there are some tricky points to note to enable core dumps that can be used later in a GDB session. First of all, we have to set an unlimited core size. Note that this is required for any executable, not just ROS nodes: ulimit -c unlimited Then, to allow core dumps to be created, we must set the core filename to use the process pid by default; otherwise, they will not be created because at $ROS_HOME, there is already a core directory to prevent core dumps. Therefore, in order to create core dumps with the name and path $ROS_HOME/core.PID, we must do the following: echo 1 > /proc/sys/kernel/core_uses_pid 3.2 调试信息 在调试时,通过信息记录显示程序的运行状态是非常重要的,但需要确定这样做不会 影响软件的运行效率,不会和正常输出混淆。在 ROS 中有满足以上要求并且内置于 log4cxx (众所周知的 log4j 记录库的一个端口)之上的 API。简单地说,我们有不同层级的调试信息 输出,每条信息都有自己的名称,并根据相应条件输出消息,它们对性能没有任何影响并与 ROS 框架中的其他工具完全集成。此外,它们无缝集成在并发执行的节点上,也就是说信息 没有被打散,而是完全可以根据它们的时间戳进行交叉展示。在下面的小节中,我们将进行 详细的解释以及如何充分使用它们。 3.2.1 输出调试信息 ROS 自带了大量的能够输出调试信息的函数和宏。这些信息包括错误、警告或简单 的提示信息。它提供了如信息(或日志)级别、条件触发消息和 STL 的流接口等诸多方 式。更加直截了当地说,如果想要输出任何提示信息,你只需要在代码中的任意位置插入 以下代码: Chapter 3 [ 69 ] Debugging messages It is good practice to include messages that indicate what the program is doing. However, we must do it without compromising the efficiency of our software and the clearance of its output. In ROS, we have an API that covers both features and is built on top of log4cxx (a port of the well-known log4j logger library). In brief, we have several levels of messages, which might have a name depending on a condition or even throttle, with a null footprint on the performance and full integration with other tools in the ROS framework. Also, they are integrated seamlessly with the concurrent execution of nodes, that is, the messages do not get split, but they can be interleaved according to their timestamps. In the following sections, we will explain the details and how to use them adequately. Outputting a debug message ROS comes with a great number of functions or macros that allow us to output a debugging message as well as errors, warnings, or simply informative messages. It offers a great functionality by means of message (or logging) levels, conditional messages, interfaces for STL streams, and much more. To put things in a simple and straightforward fashion, in order to print an informative message (or information), we can do the following at any point in the code: ROS_INFO( "My INFO message." ); Note that we do not have to include any particular library in our source code as long as the main ROS header is included. However, we can add the ros/console.h header as shown in the following code snippet: #include #include As a result of running a program with the preceding message, we will have the following output: [ INFO] [1356440230.837067170]: My INFO message. All messages are printed with its level and the current timestamp (your output might differ for this reason) before the actual message and both these values are between square brackets. The timestamp is the epoch time, that is, the seconds and nanoseconds since 1970 followed by our message. 注意,只要主要的 ROS 头文件被包括在内,那么在源代码中就不需要包括任何特定的 库。但我们可以添加 ros/console.h 头文件,如下面的代码所示: Chapter 3 [ 69 ] Debugging messages It is good practice to include messages that indicate what the program is doing. However, we must do it without compromising the efficiency of our software and the clearance of its output. In ROS, we have an API that covers both features and is built on top of log4cxx (a port of the well-known log4j logger library). In brief, we have several levels of messages, which might have a name depending on a condition or even throttle, with a null footprint on the performance and full integration with other tools in the ROS framework. Also, they are integrated seamlessly with the concurrent execution of nodes, that is, the messages do not get split, but they can be interleaved according to their timestamps. In the following sections, we will explain the details and how to use them adequately. Outputting a debug message ROS comes with a great number of functions or macros that allow us to output a debugging message as well as errors, warnings, or simply informative messages. It offers a great functionality by means of message (or logging) levels, conditional messages, interfaces for STL streams, and much more. To put things in a simple and straightforward fashion, in order to print an informative message (or information), we can do the following at any point in the code: ROS_INFO( "My INFO message." ); Note that we do not have to include any particular library in our source code as long as the main ROS header is included. However, we can add the ros/console.h header as shown in the following code snippet: #include #include As a result of running a program with the preceding message, we will have the following output: [ INFO] [1356440230.837067170]: My INFO message. All messages are printed with its level and the current timestamp (your output might differ for this reason) before the actual message and both these values are between square brackets. The timestamp is the epoch time, that is, the seconds and nanoseconds since 1970 followed by our message. 作为前面的消息处理程序运行的结果,将得到如下输出: Chapter 3 [ 69 ] Debugging messages It is good practice to include messages that indicate what the program is doing. However, we must do it without compromising the efficiency of our software and the clearance of its output. In ROS, we have an API that covers both features and is built on top of log4cxx (a port of the well-known log4j logger library). In brief, we have several levels of messages, which might have a name depending on a condition or even throttle, with a null footprint on the performance and full integration with other tools in the ROS framework. Also, they are integrated seamlessly with the concurrent execution of nodes, that is, the messages do not get split, but they can be interleaved according to their timestamps. In the following sections, we will explain the details and how to use them adequately. Outputting a debug message ROS comes with a great number of functions or macros that allow us to output a debugging message as well as errors, warnings, or simply informative messages. It offers a great functionality by means of message (or logging) levels, conditional messages, interfaces for STL streams, and much more. To put things in a simple and straightforward fashion, in order to print an informative message (or information), we can do the following at any point in the code: ROS_INFO( "My INFO message." ); Note that we do not have to include any particular library in our source code as long as the main ROS header is included. However, we can add the ros/console.h header as shown in the following code snippet: #include #include As a result of running a program with the preceding message, we will have the following output: [ INFO] [1356440230.837067170]: My INFO message. All messages are printed with its level and the current timestamp (your output might differ for this reason) before the actual message and both these values are between square brackets. The timestamp is the epoch time, that is, the seconds and nanoseconds since 1970 followed by our message. 所有输出的调试信息都附带其级别和当前时间戳(因为这个原因你的输出可能有所不 48 第 3 章 同),这两个值放在实际计算值之前的方括号中。时间戳以公历时间计时,代表着自 1970 年 以来的秒和纳秒计数,时间戳之后是具体的信息。 此函数允许以 C 语言中的 printf 函数的方式增加参数,这意味着可以用 printf 格式 为特殊字符传递数值。例如,可以按照下面代码输出变量 val 对应的浮点数值: Debugging and Visualization [ 70 ] This function allows parameters in the same way as the printf function in C. This means that we can pass values using all special characters that we can use with printf; for example, we can print the value of a floating point number in the variable val with this code: const double val = 3.14; ROS_INFO( "My INFO message with argument: %f", val ); Also, C++ STL streams are supported with *_STREAM functions. Therefore, the previous instruction is equivalent to the following using streams: ROS_INFO_STREAM( "My INFO stream message with argument: " << val ); Please note that we did not specify any stream because it is implicit that we refer to cout or cerr, depending on the message level, as we will see in the next section. Setting the debug message level ROS comes with five classic logging levels, which are in the order of relevance. They are DEBUG, INFO, WARN, ERROR, and FATAL. These names are part of the function or macro used to output messages that follows this syntax: ROS_[_] Both DEBUG and INFO messages go to cout (or stdout). Meanwhile, WARN, ERROR, and FATAL go to cerr (or stderr). Also, each message is printed with a particular color as long as the terminal has this capability. The colors are DEBUG in green, INFO in white, WARN in yellow, ERROR in red, and FATAL in purple. The names of these messages clearly say the typology of the message given. The user must use them accordingly. As we will see in the following sections, this allows us to output only messages starting at a user-defined minimum level so that debugging messages can be omitted when our code is stable. Additionally, we have OTHER variants that are explained in the sequel. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. 此外,C++STL 流支持 *_STREAM 函数。因此,前面的指令相当于下面使用流: Debugging and Visualization [ 70 ] This function allows parameters in the same way as the printf function in C. This means that we can pass values using all special characters that we can use with printf; for example, we can print the value of a floating point number in the variable val with this code: const double val = 3.14; ROS_INFO( "My INFO message with argument: %f", val ); Also, C++ STL streams are supported with *_STREAM functions. Therefore, the previous instruction is equivalent to the following using streams: ROS_INFO_STREAM( "My INFO stream message with argument: " << val ); Please note that we did not specify any stream because it is implicit that we refer to cout or cerr, depending on the message level, as we will see in the next section. Setting the debug message level ROS comes with five classic logging levels, which are in the order of relevance. They are DEBUG, INFO, WARN, ERROR, and FATAL. These names are part of the function or macro used to output messages that follows this syntax: ROS_[_] Both DEBUG and INFO messages go to cout (or stdout). Meanwhile, WARN, ERROR, and FATAL go to cerr (or stderr). Also, each message is printed with a particular color as long as the terminal has this capability. The colors are DEBUG in green, INFO in white, WARN in yellow, ERROR in red, and FATAL in purple. The names of these messages clearly say the typology of the message given. The user must use them accordingly. As we will see in the following sections, this allows us to output only messages starting at a user-defined minimum level so that debugging messages can be omitted when our code is stable. Additionally, we have OTHER variants that are explained in the sequel. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. 请注意,我们没有指定任何流,因为它一般默认为 cout 或 cerr。调试信息级别会决 定具体是哪一个。我们将在下一节中做详细介绍。 3.2.2 设置调试信息级别 ROS 有五个标准级别,按照顺序排列分别是 DEBUG、INFO、WARN、ERROR 和 FATAL。 这些名称是输出信息的函数或宏的一部分,它们遵循以下语法: Debugging and Visualization [ 70 ] This function allows parameters in the same way as the printf function in C. This means that we can pass values using all special characters that we can use with printf; for example, we can print the value of a floating point number in the variable val with this code: const double val = 3.14; ROS_INFO( "My INFO message with argument: %f", val ); Also, C++ STL streams are supported with *_STREAM functions. Therefore, the previous instruction is equivalent to the following using streams: ROS_INFO_STREAM( "My INFO stream message with argument: " << val ); Please note that we did not specify any stream because it is implicit that we refer to cout or cerr, depending on the message level, as we will see in the next section. Setting the debug message level ROS comes with five classic logging levels, which are in the order of relevance. They are DEBUG, INFO, WARN, ERROR, and FATAL. These names are part of the function or macro used to output messages that follows this syntax: ROS_[_] Both DEBUG and INFO messages go to cout (or stdout). Meanwhile, WARN, ERROR, and FATAL go to cerr (or stderr). Also, each message is printed with a particular color as long as the terminal has this capability. The colors are DEBUG in green, INFO in white, WARN in yellow, ERROR in red, and FATAL in purple. The names of these messages clearly say the typology of the message given. The user must use them accordingly. As we will see in the following sections, this allows us to output only messages starting at a user-defined minimum level so that debugging messages can be omitted when our code is stable. Additionally, we have OTHER variants that are explained in the sequel. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. You can also download these code files from https://github.com/ AaronMR/Learning_ROS_for_Robotics_Programming. DEBUG 和 INFO 信息是输出到标准输出cout(或 stdout); 而 WARN、ERROR 和 FATAL 会输出到错误信息输出 cerr(或 stderr)。同时,只要显示终端能够支持,那么每 一种信息都会以特定的颜色输出在屏幕上。这些颜色分别是:DEBUG 为绿色, INFO 为白色, WARN 为黄色, ERROR 为红色,以及 FATAL 为紫色。 这些信息的名称清楚地代表了信息的类型。因此,用户只需要相应地使用它们。正如我 们将在后续章节看到的,我们只在用户需要的最小范围内输出消息。在代码稳定之后,就能 够按条件显示调试信息。此外,我们会在后续章节中解释 OTHER 变量。 3.2.3 为特定节点配置调试信息级别 默认情况下,系统会显示 INFO 及更高级别的调试信息,并使用 ROS 默认级别来过滤 特定节点所需输出的信息。要实现这一功能有很多方法。其中有些是在编译时设定,而其他 的则可以在执行前使用配置文件进行更改。另外,也可以动态地改变级别。下面将介绍使用 rosconsole 和 rxconsole 来实现这一功能。 首先,将看到在编译时如何设置源代码的调试级别。只需要找到 main 函数,在 ros:: init 代码之后,插入以下代码: Chapter 3 [ 71 ] Configuring the debugging level of a particular node By default, only messages of INFO or a higher level are shown. ROS uses the levels to filter the messages printed by a particular node. There are many ways to do so. Some of them are set at the compile time, while others can be changed before execution using a configuration file. It is also possible to change this level dynamically, as we will see later in the following sections, using rosconsole and rxconsole. First, we will see how to set the debugging level at compile time in our source code. Just go to the main function, and after the ros::init call, insert the following code: // Set the logging level manually to DEBUG ROSCONSOLE_AUTOINIT; log4cxx::LoggerPtr my_logger = log4cxx::Logger::getLogger( ROSCONSOLE_DEFAULT_NAME ); my_logger->setLevel( ros::console::g_level_lookup[ros::console::levels::Debug] ); You do not need to include any particular header, but in the CMakeLists.txt file, we must link the header to the log4cxx library. To do so, we must put: find_library(LOG4CXX_LIBRARY log4cxx) And our node must link to it: rosbuild_add_executable(example1 src/example1.cpp) target_link_libraries(example1 ${LOG4CXX_LIBRARY}) Now, DEBUG (and higher) messages are shown when our node runs since we set ros::console::levels::Debug in the preceding example. You can run the example1 node to check it and even change the level. An alternative to the preceding method consists of using the compile-time-logger- removal macros. Note that this will remove all the messages below a given level at compilation time, so later we will not have them; this is typically useful for the release build of our programs. To do so, we must set ROSCONSOLE_MIN_SEVERITY to the minimum severity level or even none, in order to avoid any message (even FATAL); this macro can be set in the source code or even in the CMakeLists.txt file. The macros are ROSCONSOLE_SEVERITY_DEBUG, ROSCONSOLE_SEVERITY_INFO, ROSCONSOLE_SEVERITY_WARN, ROSCONSOLE_SEVERITY_ERROR, ROSCONSOLE_ SEVERITY_FATAL, and ROSCONSOLE_SEVERITY_NONE. 调试和可视化 49 Chapter 3 [ 71 ] Configuring the debugging level of a particular node By default, only messages of INFO or a higher level are shown. ROS uses the levels to filter the messages printed by a particular node. There are many ways to do so. Some of them are set at the compile time, while others can be changed before execution using a configuration file. It is also possible to change this level dynamically, as we will see later in the following sections, using rosconsole and rxconsole. First, we will see how to set the debugging level at compile time in our source code. Just go to the main function, and after the ros::init call, insert the following code: // Set the logging level manually to DEBUG ROSCONSOLE_AUTOINIT; log4cxx::LoggerPtr my_logger = log4cxx::Logger::getLogger( ROSCONSOLE_DEFAULT_NAME ); my_logger->setLevel( ros::console::g_level_lookup[ros::console::levels::Debug] ); You do not need to include any particular header, but in the CMakeLists.txt file, we must link the header to the log4cxx library. To do so, we must put: find_library(LOG4CXX_LIBRARY log4cxx) And our node must link to it: rosbuild_add_executable(example1 src/example1.cpp) target_link_libraries(example1 ${LOG4CXX_LIBRARY}) Now, DEBUG (and higher) messages are shown when our node runs since we set ros::console::levels::Debug in the preceding example. You can run the example1 node to check it and even change the level. An alternative to the preceding method consists of using the compile-time-logger- removal macros. Note that this will remove all the messages below a given level at compilation time, so later we will not have them; this is typically useful for the release build of our programs. To do so, we must set ROSCONSOLE_MIN_SEVERITY to the minimum severity level or even none, in order to avoid any message (even FATAL); this macro can be set in the source code or even in the CMakeLists.txt file. The macros are ROSCONSOLE_SEVERITY_DEBUG, ROSCONSOLE_SEVERITY_INFO, ROSCONSOLE_SEVERITY_WARN, ROSCONSOLE_SEVERITY_ERROR, ROSCONSOLE_ SEVERITY_FATAL, and ROSCONSOLE_SEVERITY_NONE. 你不需要包含任何特殊的头文件,但在 CMakeLists.txt 文件中必须将头文件链接到 log4cxx 库。要做到这一点,必须输入: Chapter 3 [ 71 ] Configuring the debugging level of a particular node By default, only messages of INFO or a higher level are shown. ROS uses the levels to filter the messages printed by a particular node. There are many ways to do so. Some of them are set at the compile time, while others can be changed before execution using a configuration file. It is also possible to change this level dynamically, as we will see later in the following sections, using rosconsole and rxconsole. First, we will see how to set the debugging level at compile time in our source code. Just go to the main function, and after the ros::init call, insert the following code: // Set the logging level manually to DEBUG ROSCONSOLE_AUTOINIT; log4cxx::LoggerPtr my_logger = log4cxx::Logger::getLogger( ROSCONSOLE_DEFAULT_NAME ); my_logger->setLevel( ros::console::g_level_lookup[ros::console::levels::Debug] ); You do not need to include any particular header, but in the CMakeLists.txt file, we must link the header to the log4cxx library. To do so, we must put: find_library(LOG4CXX_LIBRARY log4cxx) And our node must link to it: rosbuild_add_executable(example1 src/example1.cpp) target_link_libraries(example1 ${LOG4CXX_LIBRARY}) Now, DEBUG (and higher) messages are shown when our node runs since we set ros::console::levels::Debug in the preceding example. You can run the example1 node to check it and even change the level. An alternative to the preceding method consists of using the compile-time-logger- removal macros. Note that this will remove all the messages below a given level at compilation time, so later we will not have them; this is typically useful for the release build of our programs. To do so, we must set ROSCONSOLE_MIN_SEVERITY to the minimum severity level or even none, in order to avoid any message (even FATAL); this macro can be set in the source code or even in the CMakeLists.txt file. The macros are ROSCONSOLE_SEVERITY_DEBUG, ROSCONSOLE_SEVERITY_INFO, ROSCONSOLE_SEVERITY_WARN, ROSCONSOLE_SEVERITY_ERROR, ROSCONSOLE_ SEVERITY_FATAL, and ROSCONSOLE_SEVERITY_NONE. 同时也要把我们的节点链接过去: Chapter 3 [ 71 ] Configuring the debugging level of a particular node By default, only messages of INFO or a higher level are shown. ROS uses the levels to filter the messages printed by a particular node. There are many ways to do so. Some of them are set at the compile time, while others can be changed before execution using a configuration file. It is also possible to change this level dynamically, as we will see later in the following sections, using rosconsole and rxconsole. First, we will see how to set the debugging level at compile time in our source code. Just go to the main function, and after the ros::init call, insert the following code: // Set the logging level manually to DEBUG ROSCONSOLE_AUTOINIT; log4cxx::LoggerPtr my_logger = log4cxx::Logger::getLogger( ROSCONSOLE_DEFAULT_NAME ); my_logger->setLevel( ros::console::g_level_lookup[ros::console::levels::Debug] ); You do not need to include any particular header, but in the CMakeLists.txt file, we must link the header to the log4cxx library. To do so, we must put: find_library(LOG4CXX_LIBRARY log4cxx) And our node must link to it: rosbuild_add_executable(example1 src/example1.cpp) target_link_libraries(example1 ${LOG4CXX_LIBRARY}) Now, DEBUG (and higher) messages are shown when our node runs since we set ros::console::levels::Debug in the preceding example. You can run the example1 node to check it and even change the level. An alternative to the preceding method consists of using the compile-time-logger- removal macros. Note that this will remove all the messages below a given level at compilation time, so later we will not have them; this is typically useful for the release build of our programs. To do so, we must set ROSCONSOLE_MIN_SEVERITY to the minimum severity level or even none, in order to avoid any message (even FATAL); this macro can be set in the source code or even in the CMakeLists.txt file. The macros are ROSCONSOLE_SEVERITY_DEBUG, ROSCONSOLE_SEVERITY_INFO, ROSCONSOLE_SEVERITY_WARN, ROSCONSOLE_SEVERITY_ERROR, ROSCONSOLE_ SEVERITY_FATAL, and ROSCONSOLE_SEVERITY_NONE. 现在,当节点运行时, DEBUG 及更高级别的信息才会显示,因为在前面的示例中设置了 ros::console::levels::Debug。你可以运行 example1 节点来检查它是否改变 了级别。 另一种替代前面的方法包括使用编译时宏记录去除器。请注意,这种方法会在编译时 移除低于特定级别的所有调试信息,而在此之后再也无法恢复这些信息。这是我们在发布 程序时经常使用的。我们必须设置 ROSCONSOLE_MIN_SEVERITY 宏来实现,可以将其设 为最低严重性级别才显示或者设置不显示,这样任何调试信息(包括 FATAL 级别)都会被 抑制输出。这个宏可以在源代码中或者在 CMakeLists.txt 文件中进行设置。这种方法 可能用到的宏包括ROSCONSOLE_SEVERITY_DEBUG、ROSCONSOLE_SEVERITY_INFO、 ROSCONSOLE_SEVERITY_WARN、ROSCONSOLE_SEVERITY_ERROR、ROSCONSOLE_ SEVERITY_FATAL 和 ROSCONSOLE_SEVERITY_NONE。 ROSCONSOLE_MIN_SEVERITY 宏在 ros/console.h 中默认定义为DEBUG 调 试。于是可将它作为一个编译参数(使用 -D) 传递或把它放在头文件前。例如,若要仅显示 ERROR 或更高级别的调试信息,在 example2 这个节点中将执行以下操作: Debugging and Visualization [ 72 ] The ROSCONSOLE_MIN_SEVERITY macro is defined in ros/console.h as DEBUG if not given. Therefore, we can pass it as a built argument (with -D) or put it before all the headers; for example, to show only ERROR (or higher) messages we will execute the following code as we did in the example2 node: #define ROSCONSOLE_MIN_SEVERITY ROSCONSOLE_SEVERITY_DEBUG On the other hand, we have a more flexible solution of setting the minimum debugging level in a configuration file. We will create a folder, just for convenience, named config with the file chapter3_tutorials.config and this content: log4j.logger.ros.chapter3_tutorials=DEBUG We can put any of the levels supported in ROS. Then, we must set the ROSCONSOLE_ CONFIG_FILE environment variable to point our file. However, there is a better option. It consists of using a launch file that does this and also runs our node directly. Therefore, we can extend the launch files shown before to do so with an env element as shown in the following code snippet: The environment variable takes the config file, described previously, that contains the logging level specification for each named logger. Then, in the launch file, our node is simply run. Giving names to messages Since we can put messages in many places inside the same node, ROS allows us to give a name to each node in our program. This way, later on, it will be easier to detect from which part of the code is such a message coming. To do so, we use the ROS_[_STREAM]_NAMED function as shown in the following code snippet (taken from the example2 node): ROS_INFO_STREAM_NAMED( "named_msg", "My named INFO stream message; val = " << val ); 除此之外,还有一个更灵活的方法就是在配置文件中设置到最低调试级别。为了方便, 创建一个名为的 config 文件夹和名为 chapter3_tutorials.config 的文件,文件内容 如下: Debugging and Visualization [ 72 ] The ROSCONSOLE_MIN_SEVERITY macro is defined in ros/console.h as DEBUG if not given. Therefore, we can pass it as a built argument (with -D) or put it before all the headers; for example, to show only ERROR (or higher) messages we will execute the following code as we did in the example2 node: #define ROSCONSOLE_MIN_SEVERITY ROSCONSOLE_SEVERITY_DEBUG On the other hand, we have a more flexible solution of setting the minimum debugging level in a configuration file. We will create a folder, just for convenience, named config with the file chapter3_tutorials.config and this content: log4j.logger.ros.chapter3_tutorials=DEBUG We can put any of the levels supported in ROS. Then, we must set the ROSCONSOLE_ CONFIG_FILE environment variable to point our file. However, there is a better option. It consists of using a launch file that does this and also runs our node directly. Therefore, we can extend the launch files shown before to do so with an env element as shown in the following code snippet: The environment variable takes the config file, described previously, that contains the logging level specification for each named logger. Then, in the launch file, our node is simply run. Giving names to messages Since we can put messages in many places inside the same node, ROS allows us to give a name to each node in our program. This way, later on, it will be easier to detect from which part of the code is such a message coming. To do so, we use the ROS_[_STREAM]_NAMED function as shown in the following code snippet (taken from the example2 node): ROS_INFO_STREAM_NAMED( "named_msg", "My named INFO stream message; val = " << val ); 我们可以设置成 ROS 所支持的任何级别。然后,必须设置 ROSCONSOLE_CONFIG_ FILE 环境变量指向我们的文件。由于环境变量在指向某个特定文件后,如果我们需要使其 他文件也支持这个功能,就要不断修改环境变量。因此,还有更好的选择。我们可以使用一 个 launch 文件来代替配置环境变量,这样做还会直接运行我们的节点。因此,我们可以通 过 env 字段扩展 launch 文件,如下面的代码所示: 50 第 3 章 Debugging and Visualization [ 72 ] The ROSCONSOLE_MIN_SEVERITY macro is defined in ros/console.h as DEBUG if not given. Therefore, we can pass it as a built argument (with -D) or put it before all the headers; for example, to show only ERROR (or higher) messages we will execute the following code as we did in the example2 node: #define ROSCONSOLE_MIN_SEVERITY ROSCONSOLE_SEVERITY_DEBUG On the other hand, we have a more flexible solution of setting the minimum debugging level in a configuration file. We will create a folder, just for convenience, named config with the file chapter3_tutorials.config and this content: log4j.logger.ros.chapter3_tutorials=DEBUG We can put any of the levels supported in ROS. Then, we must set the ROSCONSOLE_ CONFIG_FILE environment variable to point our file. However, there is a better option. It consists of using a launch file that does this and also runs our node directly. Therefore, we can extend the launch files shown before to do so with an env element as shown in the following code snippet: The environment variable takes the config file, described previously, that contains the logging level specification for each named logger. Then, in the launch file, our node is simply run. Giving names to messages Since we can put messages in many places inside the same node, ROS allows us to give a name to each node in our program. This way, later on, it will be easier to detect from which part of the code is such a message coming. To do so, we use the ROS_[_STREAM]_NAMED function as shown in the following code snippet (taken from the example2 node): ROS_INFO_STREAM_NAMED( "named_msg", "My named INFO stream message; val = " << val ); 如前面所述,环境变量会找到 config 文件,其中包含每个已命名日志的级别说明。然 后我们的节点就可以通过 launch 文件运行。 3.2.4 信息命名 因为可以在同一节点的很多位置放置信息,ROS 允许为程序中的每一条信息取名。这样 的话我们就会更加容易地知道每一条信息是来自于哪一段代码。为了实现这个功能,我们使 用 [_STREAM]_NAMED 函数,如以下代码所示 ( 以 example2 节点为例 ): Debugging and Visualization [ 72 ] The ROSCONSOLE_MIN_SEVERITY macro is defined in ros/console.h as DEBUG if not given. Therefore, we can pass it as a built argument (with -D) or put it before all the headers; for example, to show only ERROR (or higher) messages we will execute the following code as we did in the example2 node: #define ROSCONSOLE_MIN_SEVERITY ROSCONSOLE_SEVERITY_DEBUG On the other hand, we have a more flexible solution of setting the minimum debugging level in a configuration file. We will create a folder, just for convenience, named config with the file chapter3_tutorials.config and this content: log4j.logger.ros.chapter3_tutorials=DEBUG We can put any of the levels supported in ROS. Then, we must set the ROSCONSOLE_ CONFIG_FILE environment variable to point our file. However, there is a better option. It consists of using a launch file that does this and also runs our node directly. Therefore, we can extend the launch files shown before to do so with an env element as shown in the following code snippet: The environment variable takes the config file, described previously, that contains the logging level specification for each named logger. Then, in the launch file, our node is simply run. Giving names to messages Since we can put messages in many places inside the same node, ROS allows us to give a name to each node in our program. This way, later on, it will be easier to detect from which part of the code is such a message coming. To do so, we use the ROS_[_STREAM]_NAMED function as shown in the following code snippet (taken from the example2 node): ROS_INFO_STREAM_NAMED( "named_msg", "My named INFO stream message; val = " << val ); 这样,我们就可以在 config 文件中为每个带有名称的信息设置不同调试级别。这允许 在节点定义文件中使用信息的名称对信息进行配置。例如可以设定 named_msg 的信息只在 ERROR 及更高级别中显示,(请注意尽管 ROS 使用 log4cxx,但其配置文件使用 log4j 根目录 名称)如下列代码所示: Chapter 3 [ 73 ] With named messages, we can go back to the config file and set different debugging levels for each named message. This allows for fine tuning using the name of the messages as the children of the node in the specification; for example, we can set the named_msg messages that are shown only for the ERROR (or higher) level with (note that although ROS uses log4cxx, the configuration files use the log4j root name) the following command line: log4j.logger.ros.chapter3_tutorials.named_msg=ERROR Conditional and filtered messages Conditional messages are printed only when a given condition is satisfied. In some way, they are like conditional breakpoints using debugging messages. To use them, we have the ROS_[_STREAM]_COND[_NAMED] functions; note that they can be named messages as well. The following are the examples of the example2 node: // Conditional messages: ROS_INFO_STREAM_COND( val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); // Conditional Named messages: ROS_INFO_STREAM_COND_NAMED( "cond_named_msg", val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( "cond_named_msg", val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); Filtered messages are similar to conditional messages in essence, but they allow us to specify a user-defined filter that extends ros::console::FilterBase. We must pass a pointer to such a filter in the first argument of a macro with the format ROS_[_STREAM]_FILTER[_NAMED]. The following example is taken from the example2 node: struct MyLowerFilter : public ros::console::FilterBase { MyLowerFilter( const double& val ) : value( val ) {} 3.2.5 条件显示信息与过滤信息 条件显示(conditional)信息是指仅当满足给定的条件时才输出的信息。在某些情况下, 这就像是调试信息的条件断点。 我们需要使用 ROS_[_STREAM]_COND[_NAMED] 函数来调用它们,请注意 它们也可以是命名的信息。以下是以 example2 节点为例的代码: Chapter 3 [ 73 ] With named messages, we can go back to the config file and set different debugging levels for each named message. This allows for fine tuning using the name of the messages as the children of the node in the specification; for example, we can set the named_msg messages that are shown only for the ERROR (or higher) level with (note that although ROS uses log4cxx, the configuration files use the log4j root name) the following command line: log4j.logger.ros.chapter3_tutorials.named_msg=ERROR Conditional and filtered messages Conditional messages are printed only when a given condition is satisfied. In some way, they are like conditional breakpoints using debugging messages. To use them, we have the ROS_[_STREAM]_COND[_NAMED] functions; note that they can be named messages as well. The following are the examples of the example2 node: // Conditional messages: ROS_INFO_STREAM_COND( val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); // Conditional Named messages: ROS_INFO_STREAM_COND_NAMED( "cond_named_msg", val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( "cond_named_msg", val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); Filtered messages are similar to conditional messages in essence, but they allow us to specify a user-defined filter that extends ros::console::FilterBase. We must pass a pointer to such a filter in the first argument of a macro with the format ROS_[_STREAM]_FILTER[_NAMED]. The following example is taken from the example2 node: struct MyLowerFilter : public ros::console::FilterBase { MyLowerFilter( const double& val ) : value( val ) {} 调试和可视化 51 Chapter 3 [ 73 ] With named messages, we can go back to the config file and set different debugging levels for each named message. This allows for fine tuning using the name of the messages as the children of the node in the specification; for example, we can set the named_msg messages that are shown only for the ERROR (or higher) level with (note that although ROS uses log4cxx, the configuration files use the log4j root name) the following command line: log4j.logger.ros.chapter3_tutorials.named_msg=ERROR Conditional and filtered messages Conditional messages are printed only when a given condition is satisfied. In some way, they are like conditional breakpoints using debugging messages. To use them, we have the ROS_[_STREAM]_COND[_NAMED] functions; note that they can be named messages as well. The following are the examples of the example2 node: // Conditional messages: ROS_INFO_STREAM_COND( val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); // Conditional Named messages: ROS_INFO_STREAM_COND_NAMED( "cond_named_msg", val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( "cond_named_msg", val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); Filtered messages are similar to conditional messages in essence, but they allow us to specify a user-defined filter that extends ros::console::FilterBase. We must pass a pointer to such a filter in the first argument of a macro with the format ROS_[_STREAM]_FILTER[_NAMED]. The following example is taken from the example2 node: struct MyLowerFilter : public ros::console::FilterBase { MyLowerFilter( const double& val ) : value( val ) {} 过滤(Filtered)信息在本质上与条件显示信息类似,但它允许我们指定一个用户自定义 的过滤器。这个自定义过滤器继承自 ros::console::FilterBase 结构体。 我们必须将过滤器作为指针传递给以 ROS_[_STREAM]_FILTER [_NAMED] 为格式的宏的第一个参数。下面的示例来自于 example2 节点: Chapter 3 [ 73 ] With named messages, we can go back to the config file and set different debugging levels for each named message. This allows for fine tuning using the name of the messages as the children of the node in the specification; for example, we can set the named_msg messages that are shown only for the ERROR (or higher) level with (note that although ROS uses log4cxx, the configuration files use the log4j root name) the following command line: log4j.logger.ros.chapter3_tutorials.named_msg=ERROR Conditional and filtered messages Conditional messages are printed only when a given condition is satisfied. In some way, they are like conditional breakpoints using debugging messages. To use them, we have the ROS_[_STREAM]_COND[_NAMED] functions; note that they can be named messages as well. The following are the examples of the example2 node: // Conditional messages: ROS_INFO_STREAM_COND( val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); // Conditional Named messages: ROS_INFO_STREAM_COND_NAMED( "cond_named_msg", val < 0., "My conditional INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_COND( "cond_named_msg", val >= 0., "My conditional INFO stream message; val (" << val << ") >= 0" ); Filtered messages are similar to conditional messages in essence, but they allow us to specify a user-defined filter that extends ros::console::FilterBase. We must pass a pointer to such a filter in the first argument of a macro with the format ROS_[_STREAM]_FILTER[_NAMED]. The following example is taken from the example2 node: struct MyLowerFilter : public ros::console::FilterBase { MyLowerFilter( const double& val ) : value( val ) {}Debugging and Visualization [ 74 ] inline virtual bool isEnabled() { return value < 0.; } double value; }; struct MyGreaterEqualFilter : public ros::console::FilterBase { MyGreaterEqualFilter( const double& val ) : value( val ) {} inline virtual bool isEnabled() { return value >= 0.; } double value; }; MyLowerFilter filter_lower( val ); MyGreaterEqualFilter filter_greater_equal( val ); ROS_INFO_STREAM_FILTER( &filter_lower, "My filter INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_FILTER( &filter_greater_equal, "My filter INFO stream message; val (" << val << ") >= 0" ); More messages – once, throttle, and combinations It is also possible to control how many times a given message is shown. We can print it only once with ROS_[_STREAM]_ONCE[_NAMED]. This kind of message is useful in loops where we do not want to output so many messages for efficiency reasons, and it is enough to know that we entered. for( int i = 0; i < 10; ++i ) { ROS_INFO_STREAM_ONCE( "My once INFO stream message; i = " << i ); } Debugging and Visualization [ 74 ] inline virtual bool isEnabled() { return value < 0.; } double value; }; struct MyGreaterEqualFilter : public ros::console::FilterBase { MyGreaterEqualFilter( const double& val ) : value( val ) {} inline virtual bool isEnabled() { return value >= 0.; } double value; }; MyLowerFilter filter_lower( val ); MyGreaterEqualFilter filter_greater_equal( val ); ROS_INFO_STREAM_FILTER( &filter_lower, "My filter INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_FILTER( &filter_greater_equal, "My filter INFO stream message; val (" << val << ") >= 0" ); More messages – once, throttle, and combinations It is also possible to control how many times a given message is shown. We can print it only once with ROS_[_STREAM]_ONCE[_NAMED]. This kind of message is useful in loops where we do not want to output so many messages for efficiency reasons, and it is enough to know that we entered. for( int i = 0; i < 10; ++i ) { ROS_INFO_STREAM_ONCE( "My once INFO stream message; i = " << i ); } 3.2.6 信息的更多功能——单次显示、可调、组合 你可以控制信息的显示次数。通过使用 ROS_[_STREAM]_ONCE[_NAMED], 可以让信息只输出一次。这个功能在循环中非常有用,因为考虑到效率的关系我们不希望有 过多输出,但同时又能知道程序进入了该循环运算。 52 第 3 章 Debugging and Visualization [ 74 ] inline virtual bool isEnabled() { return value < 0.; } double value; }; struct MyGreaterEqualFilter : public ros::console::FilterBase { MyGreaterEqualFilter( const double& val ) : value( val ) {} inline virtual bool isEnabled() { return value >= 0.; } double value; }; MyLowerFilter filter_lower( val ); MyGreaterEqualFilter filter_greater_equal( val ); ROS_INFO_STREAM_FILTER( &filter_lower, "My filter INFO stream message; val (" << val << ") < 0" ); ROS_INFO_STREAM_FILTER( &filter_greater_equal, "My filter INFO stream message; val (" << val << ") >= 0" ); More messages – once, throttle, and combinations It is also possible to control how many times a given message is shown. We can print it only once with ROS_[_STREAM]_ONCE[_NAMED]. This kind of message is useful in loops where we do not want to output so many messages for efficiency reasons, and it is enough to know that we entered. for( int i = 0; i < 10; ++i ) { ROS_INFO_STREAM_ONCE( "My once INFO stream message; i = " << i ); } 这段代码也是来自 example2 节点,信息只会在 i==0 时显示 1 次。 然而,有时候在迭代中每次都显示信息也是有必要的。这就需要可调信息。它们和前面 单次显示的消息格式是一样的,但是你需要将函数名中的 ONCE 替换成 THROTTLE,函数会 将可调时间(Duration)作为第一个参数,也就是说,它将会只在特殊的时间间隔后输出: Chapter 3 [ 75 ] This code from the example2 node will show the message only once for i == 0. However, it is usually better to show the message at every iteration. This is where we can use throttle messages. They have the same format as that of the ONCE message, but if you replace ONCE with THROTTLE they will have Duration as the first argument; that is, it is printed only at the specified time interval: for( int i = 0; i < 10; ++i ) { ROS_INFO_STREAM_ONCE( 2, "My once INFO stream message; i = " << i ); ros::Duration( 1 ).sleep(); } Finally, note that named, conditional, and once/throttle messages can be combined together for all the available levels. Nodelets also have some support in terms of logging and debugging messages. Since they have their own namespace, they have a specific name to differentiate the messages of one nodelet from another. Simply, all the macros shown so far are valid, but instead of ROS_* we have NODELET_*. These macros will only compile inside nodelets. Also, they operate by setting up a named logger, with the name of the nodelet running, so that you can differentiate between the output of two nodelets of the same type running in the same nodelet manager. Another advantage of nodelets is that they will help you turn one specific nodelet to the DEBUG level, instead of all the nodelets of a specific type. Using rosconsole and rxconsole to modify the debugging level on the fly A logging message integrates with a series of tools to visualize and configure them. The ROS framework comes with an API known as rosconsole that was used to some extent in the previous sections. We advised you to consult the API for more advanced features, but we believe that this book covers everything a regular robotics user or developer might need. Apart from the API to configure the logging message in your nodes, ROS provides a graphical tool, which is part of the rxtools package. This tool is rxconsole, and you only have to type it in the command line to see the graphical interface that allows seeing, inspecting, and configuring the logging subsystem of all running nodes. 最后要说明的是,无论对于哪个级别的信息,命名信息、条件显示信息、单次 / 可调信 息等都能够组合起来使用。 动态加载节点(Nodelet)对于日志和调试信息也提供了一定的支持。因为它们有自己的 命名空间,而且有各自唯一的名称,这样才能够让一个动态加载节点的提示信息与其他节点 的区别开。简单地说,前面提到的所有宏对于动态加载节点都是可用的,只是宏的名称上, 需要将 ROS_* 开头替换成 NODELET_*。这些宏将只能够在动态加载节点内部编译。同时, 它们会使用动态加载节点运行时的名称设置一个命名的日志。这样你就能够区分同一个动态 加载节点管理器下运行的两个相同类型动态加载节点的输出。动态加载节点的另外一个优势 是它们能够帮助你将某个动态加载节点转换到 DEBUG 级别,而不是把整个特定类型的动态 加载节点都转换过去。 3.2.7 使用 rosconsole 和 rxconsole 在运行时修改调试级别 日志信息集成了一系列的窗口化显示及配置工具。ROS 框架附带了名为 rosconsole 的 API。其实,在某种程度上我们已经在前面的章节中使用了该 API。如果你想使用该 API 的 高级特性,那么你可能需要通过其他途径查询相关资料,但我们认为本书已经涵盖了机器人 应用及开发人员必须要了解的基本知识。 除了能在你的节点中配置日志记录信息的 API 之外,ROS 还在 rxtools 功能包下提供 一种图形化工具。这个工具是 rxconsole,你只需要将其敲入命令行,然后就会看到一个 图形界面,允许你查看、监视和配置所有正在运行的节点日志记录子系统。 为了测试这个功能,将使用代码示例 example3,在一个命令行窗口中运行 roscore, 在另一个终端窗口中运行节点: 调试和可视化 53Debugging and Visualization [ 76 ] In order to test this, we are going to use example3, so we will run roscore in one terminal and the node in another using the following command line: rosrun chapter3_tutorials example3 Now, with the node running, we will open another terminal and run rxconsole. The following window will open; note that you can also run rxconsole first. So the logging message will now appear immediately as shown in the following screenshot: Once we have our example3 node running, we will start to see messages as shown in the following screenshot: 在运行这个节点的同时,在另外一个终端窗口中运行 rxconsole。这时会打开下面的窗 口。请注意,你也可以先运行 rxconsole,然后再运行节点。这样就会有日志信息出现如以下 截屏所示: 一旦 example3 节点开始运行,就会看到如下图所显示的信息: 在上表中,是关于给定信息的几列内容(如图所示顺序排列)。这些列包括信息本身、严 重级别、产生该信息的节点、时间戳、主题(通常是 /rosout 聚合器聚合了来自 ROS 服务 器的各类信息)以及产生日志的宏所在的节点代码位置。 我们可以通过点击 Pause 按钮来停止接收新信息,再次点击就可恢复监听。对于这个表 中的每一条信息,我们都可以通过点击 Pau se 来查看它的细节,如下图所示,正是上一个截 屏的最后一条信息。 54 第 3 章 还有一个非常好的特性,就是 rxconsole 能够过滤信息。最直接的过滤方法是设定严 重级别。如果你只想看 FATAL 和 ERROR 级别的信息,必须取消勾选其他级别,如下截屏 所示: 你立刻就能看到只剩下FATAL 和 ERROR 级别的信息了。另外,我们可以按照信息 内容、节点名称、位置、主题名称及查询关键词等方式进行过滤(选择 include 方式或 exclude 方式)。下图显示了我们选择在信息( Message)一栏内筛选包含关键词 named 的所 有信息: 调试和可视化 55 请注意,我们可以添加足够多的过滤器,也可以直接移除或取消消息。 我们同样可以通过 rxconsole 移除所有捕捉的信息,只需要点击 Clear 按钮。Setup 按钮 允许我们配置诊断信息聚合器(diagnostic_aggregator)主题。聚合器主题主要是 rosout_ agg,还有一定数量由 GUI 保存的滚屏前屏幕内的历史数据(如下图所示)。请注意,诊断信 息聚合器仅仅是 ROS 服务器中接收所有日志信息的一个接收器。只有这样,我们才能够监 视哪个设备失效了或者设备如何工作。高级的开发者会发现这些工具对于了解诊断 API 是很 有用的。这不仅能够支持在更高层级上建立继承关系,而且对于复杂系统或机器人来说非常 有帮助。 最后,我们可以根据日志的名称设定日志的严重级别。默认情况下,每个节点都有一个 使用功能包名称的日志,但我们还可以使用前面章节介绍过的 NAMED 宏,来定义日志信息 的名称。对于 example3 节点来说,有 ros.chapter3_tutorials 和 ros.chapter3_ tutorials.named_msg 日志。如果你点击 Levels... 按钮,就会看到如下截屏所示: 56 第 3 章 这里我们选择使用 example3 节点,然后选择相应的日志信息 ,并设定其级别。请注 意,这里还有一些内部日志,你需要把这些日志和前面提到的日志区分开。在前面的截屏 中,我们为 ros.chapter3_tutorials.named_msg 日志选择了 DEBUG 级别,这样只有 该级别或更高级别的信息才能被显示。也就是说,所有的信息都符合这一设定。 3.3 监视系统状态 当系统运行时,可能有数个节点和数十个主题在发布消息,通过订阅与其他节点连接。 同时,有些节点可能也会提供服务。对于大型系统来说,通过提供一些工具让我们看到系统 在给定时间的运行状态是非常重要的。 ROS 提供了一些基本而又非常强大的工具,它们不仅 能实现状态监视,还能探测节点状态图中任何节点发生的功能失效。简而言之,使用主题来 连接节点展现系统架构的状态。 3.3.1 节点、主题与服务列表 坦白地讲,我们应该先从基本的内容回顾一下我们的学习。我们将学习如何获得正在运 行节点、主题、当前所有可用服务的清单。尽管这非常简单,却是最有效和最常用的。 ● 获得运行中节点的清单: Debugging and Visualization [ 80 ] Inspecting what is going on When our system is running, we might have several nodes and even more topics publishing messages and connected by subscription among nodes. Also, we might have some nodes providing services as well. For large systems, it is important to have some tools that let us see what is running at a given time. ROS provides us with some basic but powerful tools to do so, and also to detect a failure in any part of the nodes graph; that is, the architecture that emerges from the connection of ROS nodes using topics. Listing nodes, topics, and services In our honest opinion, we should start with the most basic level of introspection. We are going to see how to obtain the list of nodes running, and topics and services available at a given time. Although extremely simple, this is very useful and robust. • To obtain the list of nodes running use: rosnode list • The topics of all nodes are listed using: rostopic list • And, similarly, all services are shown by: rosservice list We recommend you to go back to Chapter 2, The ROS Architecture with Examples to see how these commands also allow you to obtain the message type sent by a particular topic, as well as its fields, using rosmsg show. Inspecting the node's graph online with rxgraph The simplest way to illustrate the current state of an ROS session is with a directed graph that shows the nodes running on the system and the publisher-subscriber connections among these nodes through the topics. The ROS framework provides some tools to generate such a node's graph. The main tool is rxgraph, which shows the node's graph during the system execution and allows us to see how a node appears or disappears dynamically. ● 所有节点的主题请使用: Debugging and Visualization [ 80 ] Inspecting what is going on When our system is running, we might have several nodes and even more topics publishing messages and connected by subscription among nodes. Also, we might have some nodes providing services as well. For large systems, it is important to have some tools that let us see what is running at a given time. ROS provides us with some basic but powerful tools to do so, and also to detect a failure in any part of the nodes graph; that is, the architecture that emerges from the connection of ROS nodes using topics. Listing nodes, topics, and services In our honest opinion, we should start with the most basic level of introspection. We are going to see how to obtain the list of nodes running, and topics and services available at a given time. Although extremely simple, this is very useful and robust. • To obtain the list of nodes running use: rosnode list • The topics of all nodes are listed using: rostopic list • And, similarly, all services are shown by: rosservice list We recommend you to go back to Chapter 2, The ROS Architecture with Examples to see how these commands also allow you to obtain the message type sent by a particular topic, as well as its fields, using rosmsg show. Inspecting the node's graph online with rxgraph The simplest way to illustrate the current state of an ROS session is with a directed graph that shows the nodes running on the system and the publisher-subscriber connections among these nodes through the topics. The ROS framework provides some tools to generate such a node's graph. The main tool is rxgraph, which shows the node's graph during the system execution and allows us to see how a node appears or disappears dynamically. ● 类似地,显示所有服务使用: Debugging and Visualization [ 80 ] Inspecting what is going on When our system is running, we might have several nodes and even more topics publishing messages and connected by subscription among nodes. Also, we might have some nodes providing services as well. For large systems, it is important to have some tools that let us see what is running at a given time. ROS provides us with some basic but powerful tools to do so, and also to detect a failure in any part of the nodes graph; that is, the architecture that emerges from the connection of ROS nodes using topics. Listing nodes, topics, and services In our honest opinion, we should start with the most basic level of introspection. We are going to see how to obtain the list of nodes running, and topics and services available at a given time. Although extremely simple, this is very useful and robust. • To obtain the list of nodes running use: rosnode list • The topics of all nodes are listed using: rostopic list • And, similarly, all services are shown by: rosservice list We recommend you to go back to Chapter 2, The ROS Architecture with Examples to see how these commands also allow you to obtain the message type sent by a particular topic, as well as its fields, using rosmsg show. Inspecting the node's graph online with rxgraph The simplest way to illustrate the current state of an ROS session is with a directed graph that shows the nodes running on the system and the publisher-subscriber connections among these nodes through the topics. The ROS framework provides some tools to generate such a node's graph. The main tool is rxgraph, which shows the node's graph during the system execution and allows us to see how a node appears or disappears dynamically. 我们推荐你回到第 2 章,熟悉如何使用这些命令,同时看一下如何使用 rosmsg show 获取特定主题所发出的消息类型。 3.3.2 使用 rxgraph 在线监视节点状态图 能够说明 R OS 会话当前状态的最简单方法是用一个有向图,它显示在系统中运行的节 点和这些节点通过主题实现的发布者到订阅者的连接。 ROS 框架提供了一些工具来生成此类 节点状态图。其最主要工具是 rxgraph,可以在系统执行过程中显示该节点状态图,并使我们 看到一个节点是如何动态地出现或消失。 为了说明如何监视节点、主题和 rxgraph 的服务,我们将使用以下文件同时运行 example4 和 example5 节点: Chapter 3 [ 81 ] To illustrate how to inspect the nodes, topics, and services with rxgraph, we are going to run the example4 and example5 nodes simultaneously with the following file: roslaunch chapter3_tutorials example4_5.launch The example4 node publishes in two different topics and calls a service. Meanwhile, example5 subscribes to those topics and also has the service server attend the request queries and provide the response. Once the nodes are running, we have the node's topology as shown in the following screenshot: In the preceding screenshot, we have nodes connected by topics. We also have the ROS server node as rosout, as well as the rosout topics that publish the log message for the diagnostic aggregator in the server as we have seen previously. There is also a panel to the right with information regarding the node selected. In the preceding screenshot, we have information regarding the server; that is, its IP and port for the remote nodes, topics, and connections. example4 节点在两个不同的主题中发布并调用了一个服务。同时, example5 节点订 阅了这些主题,并提供了一个服务来响应服务器的查询请求和提供反馈数据。一旦这些节点 开始运行,我们就能够查询到如下截屏所示的节点状态图: 调试和可视化 57 在上面的截屏中,我们看到节点通过主题相连, rosout 节点可以理解为 ROS 服务器。还 有如我们之前所学的, rosout 主题会向服务器中的诊断聚合器发布日志信息。在右侧的面板 上有选定节点相关的信息。我们还能看到服务器相关的信息,包括其 IP 2018香港马会开奖现场、远程节点连接 端口、主题和连接。 我们可以启用简洁( quiet)视图,这就会省略 ROS 服务器。这对于大型的系统是非 常有用的,因为 ROS 服务器总是存在,却在我们的系统拓扑图上不会提供任何有用的信 息。要查看节点的服务,我们先打开节点再查看右侧面板。在下面的截屏中,我们选中了 example5 节点的 speed 服务: 58 第 3 章 当系统发生问题时,节点会一直显示为红色(而不仅仅在我们鼠标悬停在其上时)。在这 种情况下,最好是选择 All topics 来查看未连接的主题。有些时候,问题可能仅仅是一个主 题名称的拼写错误造成的。 当节点在不同的机器上运行时,rxgraph 会展示其高级别调试能力,因为它能够显示不同 机器的两个节点间是否连接。 3.4 当奇怪的事情发生——使用 roswtf ROS 还提供了另外一个工具来检测给定功能包中所有组件的潜在问题。使用 roscd 移 动到你想要分析的功能包路径下,然后运行 roswtf。在 chapter3_tutorials 示例中, 我们可以获得以下输出: 通常情况下,我们所希望获得的结果是没有任何的错误和警告,但是很多错误和警告 在系统正常运行时是没有影响的。在上面的截屏中,我们看到 roswtf 已经检测到无法和 example4 节点相连接。之所以会这样是因为这个节点已经收到了挂起(sleep)指令,而当 你在它挂起时进行分析的时候,总是会出现这样的提示。而后面的错误都是这个错误造成 的。roswtf 的作用是检测信号的潜在问题,然后就像上面示例一样,我们再来检查这些提 示是否有意义。 3.5 画标量数据图 我们可以使用 ROS 中现有的一些通用工具,轻松地绘制标量数据图。它要求对每一个 调试和可视化 59 标量字段数据分别绘制成二维曲线。这就是我们在这里讨论标量数据的原因,大部分非标量 数据结构更适合于使用专用的可视化工具,我们会在后面进行部分介绍,例如,图形、位 姿、方向和角度。 3.5.1 用 rxplot 画出时间趋势曲线 在 ROS 系统中,标量数据可以根据消息中提供的时间戳作为时间序列绘制图形。然后, 我们就能够在 y 轴上使用 rxplot 工具绘制标量数据。 rxplot 工具有一套功能强大的参数 语法,允许我们在结构化消息中指定多个字段(当然使用了相当简明的方式)。 为了能够实际展示 rxplot 工具,我们使用 example4 节点,它在两个不同的主题中 分别发布一个标量和一个矢量(非标量),这两个主题分别是温度( temp)和加速度( accel)。 在这些消息中的值是随机生成的,所以它们没有实际意义,仅用于示范曲线绘制。那么首先 运行节点: Debugging and Visualization [ 84 ] Creating a time series plot with rxplot In ROS, scalar data can be plotted as a time series over the time provided by the timestamps of the messages. Then, we will plot our scalar data in the y axis. The tool to do so is rxplot. It has a powerful argument syntax that allows us to specify several fields of a structured message (in a concise manner as well). To show rxplot in action, we are going to use the example4 node since it publishes a scalar and a vector (nonscalar) in two different topics, which are temp and accel respectively. The values put in these messages are synthetically generated, so they have no actual meaning but are useful for plotting demonstration purposes. So, start by running the node with: rosrun chapter3_tutorials example4 With rostopic list, you will see the topics temp and accel available. Now, instead of the typical rostopic echo , we will use rxplot so that we can see the values graphically over time. To plot a message, we must know its format; use rosmg show if you do not know it. In the case of scalar data, we always have a field called data that has the actual value. Hence, for the temp topic, which is of the type Int32, we will use: rxplot /temp/data With the node running, we will see a plot that changes over time with incoming messages as shown in the following screenshot: 通过 rostopic list,你能看到两个活动主题 temp 和 accel。现在,我们不再去使 用 rostopic echo ,而是通过 rxplot 命令就能够看到随时间变化的值的曲线。 为了能够画出消息,我们必须知道具体的格式;如果你不知道具体格式则使用 rosmg show 获取。对于标量数据,我们通常使用 data 作为字段名来表示实际的 值。因此,对于 temp 主题,以 Int32 为数据格式,我们就用: Debugging and Visualization [ 84 ] Creating a time series plot with rxplot In ROS, scalar data can be plotted as a time series over the time provided by the timestamps of the messages. Then, we will plot our scalar data in the y axis. The tool to do so is rxplot. It has a powerful argument syntax that allows us to specify several fields of a structured message (in a concise manner as well). To show rxplot in action, we are going to use the example4 node since it publishes a scalar and a vector (nonscalar) in two different topics, which are temp and accel respectively. The values put in these messages are synthetically generated, so they have no actual meaning but are useful for plotting demonstration purposes. So, start by running the node with: rosrun chapter3_tutorials example4 With rostopic list, you will see the topics temp and accel available. Now, instead of the typical rostopic echo , we will use rxplot so that we can see the values graphically over time. To plot a message, we must know its format; use rosmg show if you do not know it. In the case of scalar data, we always have a field called data that has the actual value. Hence, for the temp topic, which is of the type Int32, we will use: rxplot /temp/data With the node running, we will see a plot that changes over time with incoming messages as shown in the following screenshot: 只要节点正常运行,我们就能看到消息中的数值随时间变化的图形。如下截屏中显示: 在示例节点提供的accel 主题里,我们看到一个 Vector3 的消息 ( 你可以通过 rostopic type /accel 来查看 ),我们可以在一个 plot 图中分别绘制三个字段的曲线, 这是 rxplot 工具的一大优势。 Vector3 消息包含三个字段 x、y 和 z。我们可以使用逗号 来区分字段或者像下面一样使用更加简洁的方式: Chapter 3 [ 85 ] For the accel topic provided by the example node, in which we have a Vector3 message (as you can check with rostopic type /accel), we can plot three fields of the vector in a single plot, which is a great feature of rxplot. The Vector3 message has the fields x, y, and z. We can specify the fields separated by commas (,) or in a more concise manner as follows: rxplot /accel/x:y:z The plot will look like this: 60 第 3 章 绘制的曲线图如下: 我们还可以将每个字段分开绘制,如下图所示。我们需要在命令中增加空格间隔字段 名才能够实现这个功能。记住如果你使用逗号,则不允许加入任何空格。因此,如果你运行 rxplot /accel/x /accel/y /accel/z,就会出现: 3.5.2 另一个画图工具 rxtools 在 rxtools 功能包内除了 rxplot 工具之外还有其他很多工具。你可以到这个功能包 的路径下去查看更多的 GUI 或批处理工具,这些工具都可以帮助更加快捷地开发机器人应 用程序、进行调试、查看数据和检查内部信息。这些工具还能够作为功能包内的一个节点运 行,这是非常重要的功能,它允许通过 launch 文件启动这些工具。 以 rxplot 为例,为了能够通过 launch 文件运行它,需要插入以下代码: 调试和可视化 61 Debugging and Visualization [ 86 ] We can also plot each field in separate axes as shown in the next screenshot. To do so, we separate each field by a blank space; remember that when you use commas, you must not insert any spaces. Therefore, if we run rxplot /accel/x /accel/y / accel/z, the plot will show like this: Other plotting utilities – rxtools The rxplot tool is part of the rxtools package along with other tools. You might go to this package to see more GUI or batch tools that can help in the development of robotic applications and the process of debugging, monitoring, and introspecting. It is also important to know that being a node (inside this package), these tools can also be run from a launch file. In the case of rxplot, in order to run it from a launch file, we must put the following code inside it: 需要注意的是在 launch 文件中我们通过 node 的 args 字段向 rxplot 传递相关参数。 3.6 图像可视化 在 ROS 系统中,我们可以创建一个节点,在节点中展示来自即插即用摄像头的图像。 我们需要系统连接一个摄像头来完成这项工作。在 ROS 中也能够在某个节点上复现一段视 频,但是在示例里我们会直接使用笔记本上的 webcam 摄像头。 在 example6 节点中,通过调用 OpenCV 库插入一段基本的摄像头捕捉程序,然后在 ROS 中将采集到的 cv ::Mat 图像转换到 ROS 图像,这样就可以在主题中发布了。这个节 点会在 /camera 主题里发布图像帧。 我们将会使用 launch 文件运行节点并进行图像捕捉和发布工作。节点中的代码对于读 者来说可能很陌生,但是在下面的章节中,我们将会介绍如何在 ROS 中使用摄像头和图像, 到时候再回来看这些代码,你就会完全理解节点的工作原理和每行代码的含义: Chapter 3 [ 87 ] Note that we use the args argument of the node element in the launch file to pass rxplot the arguments. Visualization of images In ROS, we have a node that allows us to show images coming from a camera on the fly. You only need a camera to do this. It is also possible to reproduce a video with a simple node in ROS but here we are going to use your laptop's webcam. The example6 node implements a basic camera capture program using OpenCV and ROS bindings to convert cv::Mat images into ROS image messages that can be published in a topic. This node publishes the camera frames in the /camera topic. We are only going to run the node with a launch file created to do so. The code inside the node is still new for the reader, but in the upcoming chapters, we will cover how to work with cameras and images in ROS so that we can come back to this node and understand every bit of the code: roslaunch chapter3_tutorials example6.launch Once the node is running, we can list the topics (rostopic list) and see that the /camera topic is there. A straightforward way to see that we are actually capturing images is to see at which frequency we are receiving images in the topic with rostopic hz /camera. It should be something like 30 Hz usually, but at least some value must be seen: subscribed to [/camera] average rate: 30.131 min: 0.025s max: 0.045s std dev: 0.00529s window: 30 Visualizing a single image Being an image, we cannot use rostopic echo /camera because the amount of information in plain text would be very huge and also difficult to analyze. Hence, we are going to use the following code: rosrun image_view image_view image:=/camera 一旦节点运行起来,我们就能够列出主题列表 (rostopic list),查看是否包含 / camera 主题。想要查看我们是否正确捕捉到图像有一个简单直接的方法,使用 rostopic hz /camera 语句查看我们在主题中收到的图像是在哪个频率下。频率通常是 30Hz,但是 我们至少看到了图像的一些参数: Chapter 3 [ 87 ] Note that we use the args argument of the node element in the launch file to pass rxplot the arguments. Visualization of images In ROS, we have a node that allows us to show images coming from a camera on the fly. You only need a camera to do this. It is also possible to reproduce a video with a simple node in ROS but here we are going to use your laptop's webcam. The example6 node implements a basic camera capture program using OpenCV and ROS bindings to convert cv::Mat images into ROS image messages that can be published in a topic. This node publishes the camera frames in the /camera topic. We are only going to run the node with a launch file created to do so. The code inside the node is still new for the reader, but in the upcoming chapters, we will cover how to work with cameras and images in ROS so that we can come back to this node and understand every bit of the code: roslaunch chapter3_tutorials example6.launch Once the node is running, we can list the topics (rostopic list) and see that the /camera topic is there. A straightforward way to see that we are actually capturing images is to see at which frequency we are receiving images in the topic with rostopic hz /camera. It should be something like 30 Hz usually, but at least some value must be seen: subscribed to [/camera] average rate: 30.131 min: 0.025s max: 0.045s std dev: 0.00529s window: 30 Visualizing a single image Being an image, we cannot use rostopic echo /camera because the amount of information in plain text would be very huge and also difficult to analyze. Hence, we are going to use the following code: rosrun image_view image_view image:=/camera 3.6.1 显示单一图片 想要查看一张图像,我们不能直接使用 rostopic echo /camera 命令,因为这会使 用文本格式输出图片的信息,这些数据量会非常巨大,不可能进行任何有效的分析。因此, 我们会调用下面的命令: Chapter 3 [ 87 ] Note that we use the args argument of the node element in the launch file to pass rxplot the arguments. Visualization of images In ROS, we have a node that allows us to show images coming from a camera on the fly. You only need a camera to do this. It is also possible to reproduce a video with a simple node in ROS but here we are going to use your laptop's webcam. The example6 node implements a basic camera capture program using OpenCV and ROS bindings to convert cv::Mat images into ROS image messages that can be published in a topic. This node publishes the camera frames in the /camera topic. We are only going to run the node with a launch file created to do so. The code inside the node is still new for the reader, but in the upcoming chapters, we will cover how to work with cameras and images in ROS so that we can come back to this node and understand every bit of the code: roslaunch chapter3_tutorials example6.launch Once the node is running, we can list the topics (rostopic list) and see that the /camera topic is there. A straightforward way to see that we are actually capturing images is to see at which frequency we are receiving images in the topic with rostopic hz /camera. It should be something like 30 Hz usually, but at least some value must be seen: subscribed to [/camera] average rate: 30.131 min: 0.025s max: 0.045s std dev: 0.00529s window: 30 Visualizing a single image Being an image, we cannot use rostopic echo /camera because the amount of information in plain text would be very huge and also difficult to analyze. Hence, we are going to use the following code: rosrun image_view image_view image:=/camera 这里使用了 image_view 节点,在窗口中展示了给定 主题(使用 image 参数)的图像,如右图所示。 这样我们就能简单直接地显示在主题内发布的图像的 每一帧,即使数据来自网络也可以实现。你可以将当前帧 保存在硬盘里,通常会存在 home 目录下或者 ~/.ros 目 录下。 62 第 3 章 3.6.2 FireWire 接口摄像头 在使用 FireWire 接口的摄像头时,ROS 会提供大量的工具来支持摄像头标定,无论是单 目视觉还是双目视觉都支持,还可以通过 reconfi gure_gui 节点动态调整摄像头的参数。 通常情况下, FireWire 摄像头允许改变传感器的配置参数,例如帧分辨率、快门速度和亮度。 ROS 直接带有 FireWire(IEEE1394,a 和 b) 摄像头的驱动,我们可以使用以下命令来调用: Debugging and Visualization [ 88 ] This is the image_view node, which shows the images in the given topic (the image argument) in a window, as shown in the following screenshot: This way we can visualize every image or frame published in a topic in a very simple and flexible manner, even over a network. If you right-click on the window, you can save the current frame in the disk, usually in your home directory or ~/.ros. FireWire cameras In the case of FireWire cameras, ROS also provides a larger set of tools that support calibration, both mono and stereo, as well as a way to change the camera parameters dynamically with the reconfigure_gui node. Usually, FireWire cameras allow changing some configuration parameters of the sensor, such as the frame rate, shutter speed, and brightness. ROS already comes with a driver for FireWire (IEEE 1394, a and b) cameras that can be run using the following command: rosrun camera1394 camera1394_node Once the camera is running, we can configure its parameters with the reconfigure_ gui node, in which the first thing we do is the selection of the node we want to configure. We only have to run this: rosrun dynamic_reconfigure reconfigure_gui We will see an interface with all the configuration parameters and a series of slider or comboboxes, depending on the data type, to set its value within the valid limits. The following screenshot illustrates this for a particular FireWire camera: 一旦摄像头启动,我们能通过 reconfi gure_gui 节点配置这些参数,我们只需要选择 要配置的节点,然后运行以下命令: Debugging and Visualization [ 88 ] This is the image_view node, which shows the images in the given topic (the image argument) in a window, as shown in the following screenshot: This way we can visualize every image or frame published in a topic in a very simple and flexible manner, even over a network. If you right-click on the window, you can save the current frame in the disk, usually in your home directory or ~/.ros. FireWire cameras In the case of FireWire cameras, ROS also provides a larger set of tools that support calibration, both mono and stereo, as well as a way to change the camera parameters dynamically with the reconfigure_gui node. Usually, FireWire cameras allow changing some configuration parameters of the sensor, such as the frame rate, shutter speed, and brightness. ROS already comes with a driver for FireWire (IEEE 1394, a and b) cameras that can be run using the following command: rosrun camera1394 camera1394_node Once the camera is running, we can configure its parameters with the reconfigure_ gui node, in which the first thing we do is the selection of the node we want to configure. We only have to run this: rosrun dynamic_reconfigure reconfigure_gui We will see an interface with all the configuration parameters and a series of slider or comboboxes, depending on the data type, to set its value within the valid limits. The following screenshot illustrates this for a particular FireWire camera: 这时将会看到带有所有配置参数和一系列下拉框的界面,界面具体的内容取决于摄像头 数据的类型和各个数值的限值。下图就是某种 FireWire 摄像头的参数配置截图: 请注意我们将会以开发者的角度在后面的章节专门介绍如何使用摄像头,以及如何配置 这些参数。这些内容都会在第 6 章中介绍。 另一个要说明的是 ROS 系统能够帮助开发者标定摄像头,这些标定接口都是通过 OpenCV 和其他 API 实现的。 我们同样会在第 6 章介绍如何使用这些接口。这些工具使用起来非常简单,摄像头一运 行起来,我们只需要使用下面代码调用一些常用标定图案(通常使用棋盘): Chapter 3 [ 89 ] Note that we will cover how to work with cameras in later chapters. Also, note that the parameters reconfiguration, from the developer point of view, will be explained in detail in Chapter 6, Computer Vision. Another important utility that ROS gives to the user is the possibility to calibrate the camera. It has a calibration interface built on top of the OpenCV calibration API. We will also cover this in Chapter 6, Computer Vision, when we see how to work with cameras. This tool is very simple to use; so, once the camera is running, we only have to show some views of a calibration pattern (usually a checkerboard) using this: rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.108 image:=/camera/image_raw camera:=/camera You can see the checkerboard pattern in the following screenshot:我们可以在下图中看到棋盘图案。 标定之后,标定结果会保存为摄像头信息和失真矩阵参数,以及计算这些参数的视图。 我们在后面会经常看到这样的图像。在使用 FireWire 摄像头的情况下,会将所有的标定信息 存储在一个能够说明摄像头配置的文件中。 ROS 系统无缝集成了 image_ proc 工具实现 调试和可视化 63 图像的修正,也就是修正失真或者说对拜耳(Bayer)模式的源图像进行恢复和去拜耳化(de- Bayer)。 3.6.3 使用双目立体视觉 在某种程度上,ROS 系统同时支持双目立体视觉。如果你有双目摄像头,就能够同时标 定两个摄像头和调整它们的基线。我们可以调用以下代码来实现: Debugging and Visualization [ 90 ] After the calibration, the result will be the so-called camera matrix and distortion coefficients along with the views used to compute it. Although we will see this later in the book, it is important to say that in the case of the FireWire camera, all the calibration information is saved in a file that is pointed by the camera configuration. Hence, the ROS system allows seamless integration so that we can use the image_ proc tool to rectify the images; that is, to correct the distortion as well as to de-Bayer the raw images if they were in Bayer. Working with stereo vision To some extent, ROS also supports stereo vision. If you have a stereo pair, you can calibrate both cameras simultaneously as well as the baseline between them. For this, we will use: rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.108 right:=/my_stereo/right/image_raw left:=/my_stereo/left/image_raw right_ camera:=/my_stereo/right left_camera:=/my_stereo/left This command runs the Python camera calibrator node and receives two initial parameters that indicate the type of calibration pattern. In particular, the size specified is the number of inner corners (8 x 6 in the example) and the dimensions of the square cells. Then, the topics that publish the right and left raw images and the respective camera information topics are given. In this case, the interface will show the images from the left and right cameras and the results will be for each as well. They will include the baseline as well that is useful for some stereo tools. 这些命令能在 Python 摄像头标定节点中运行,并会收到两种表明标定模式的初始化参 数。特别地,指定的大小是内角的数目(示例中是 8×6)和单元格的尺寸。然后,会给出发 布左右两个源图像的主题和各种摄像头信息的主题。在示例中,接口会显示左右摄像头的图 像,结果也是分别展示的。其中也会包含摄像头的基线,这对很多双目视觉工具非常重要的。 64 第 3 章 双目视觉专用工具会允许你计算视差图像,如下图所示。这实际上是一种获取 3D 点云 的方法( 3D 点云能够显示每个像素点在实际物理世界中的深度)。因此,摄像头标定和基线 会提供给 3D 点云,处理图像错误和噪声分布,从而能够表征每个像素在真实世界中的真实 3D 位置及其颜色和纹理。 对于单目摄像头来说也是一样的,我们能够通过拍摄类似于双目视觉的左右图像,生成 视差图像。在这样的情况下,需要使用 stereo_image_proc。 3.7 3D 可视化 正如我们在前面章节中所见,有很多设备(例如双目摄像头、 3D 激光雷达和 Kinect 传 感器)能够提供 3D 数据。它们通常使用点云格式(组织好的或未组织的)。基于上述原因, 能够使用工具实现 3D 数据可视化就非常有用了。本节我们将介绍 ROS 系统中的 rviz 工具。 它集成了能够完成 3D 数据处理的 OpenGL 接口,能够将传感器数据在模型化世界( world) 中展示。因此,我们将会看到在复杂系统中至关重要的传感器的坐标系建立和坐标变换。 3.7.1 使用 rviz 在 3D 世界中实现数据可视化 首先,使用 roscore 命令启动 ROS,然后我们仅需要使用以下命令来启动 rviz: Debugging and Visualization [ 92 ] Visualizing data on a 3D world using rviz With roscore running, we only have to execute the following code to start rviz: rosrun rviz rviz We will see the graphical interface in the following screenshot: To the left, we have the Displays pane, in which we have a tree list of the different elements in the world, which appears in the middle. In this case, we have some elements that are already loaded. Indeed, this configuration or layout is saved in the config/example7.cvg file, which can be loaded by navigating to File | Open Config. Below the Displays area, we have the Add button that allows the addition of more elements. Also, note that there are some global options, which are basically tools to set the fixed frame in the world with respect to which others might move. Then, we have Axes (Axes) and Grid (Grid) as a reference for the rest of the elements. In this case, for the example7 node, we are going to see Markers (Markers) and PointCloud2 (PointCloud2). Finally, at the status bar, we have information regarding time, and to the right are the menus for the way to navigate in the world and select and manipulate elements. Now we are going to run the example7 node: roslaunch chapter3_tutorials example7.launch 我们将会看到如下图的图形化工作界面: 调试和可视化 65 在左边,有一个 Displays 面板,在面板的中间有一个包含了模拟环境下不同参数项的树 形列表。在示例中,我们已经加载了部分参数项。实例中的配置和布局都存储在了 confi g/ example7.cvg 文件中,可以通过点击 File|OpenConfi g 加载配置。 在 Displays 区域之下,我们有一个 Add 按钮,允许添加更多的参数项。同时,注意到这 里还有一些全局选项,基本上是用于设定固定坐标系的工具,因为坐标系是可以移动的。其 次,还有轴( Axes)和网格( Grid)作为各个参数项的参照物。在示例中,对于 example7 节点,我们将会看到标记(M arkers)和点云(PointCloud2)。 最后,在状态栏上,有时间相关的信息提示,以及在右侧,有用于在虚拟环境中导航、 选择和操纵参数项的菜单。 现在运行 example7 节点: Debugging and Visualization [ 92 ] Visualizing data on a 3D world using rviz With roscore running, we only have to execute the following code to start rviz: rosrun rviz rviz We will see the graphical interface in the following screenshot: To the left, we have the Displays pane, in which we have a tree list of the different elements in the world, which appears in the middle. In this case, we have some elements that are already loaded. Indeed, this configuration or layout is saved in the config/example7.cvg file, which can be loaded by navigating to File | Open Config. Below the Displays area, we have the Add button that allows the addition of more elements. Also, note that there are some global options, which are basically tools to set the fixed frame in the world with respect to which others might move. Then, we have Axes (Axes) and Grid (Grid) as a reference for the rest of the elements. In this case, for the example7 node, we are going to see Markers (Markers) and PointCloud2 (PointCloud2). Finally, at the status bar, we have information regarding time, and to the right are the menus for the way to navigate in the world and select and manipulate elements. Now we are going to run the example7 node: roslaunch chapter3_tutorials example7.launch 在 rviz 中,我们将会把 frame _id 设置为标记,这个标记是固定坐标系的坐标标记 (frame_marker)。我们将会看到如下图所示的红色方块标记在移动: 类似地,如果设置固定坐标系为 frame_pc,我们将看到一个 200×100 像素点平面所 组成的点云,如下图所示: 66 第 3 章 它支持的 rviz 内置类型的参数列表也包括影像和图像。它们会在一个类似于 image_view 的窗口中进行展示。在使用摄像头的时候,需要对它先进行标定;在使用双目视觉图像的时 候,它允许我们覆盖点云。我们同样也可以看到激光雷达的激光扫描数据,以及 IR/SONAR (红外 / 声呐)传感器的锥状距离数据( range cone)。 它能够表现机器人相关的各种基本元素,例如多边形、各种不同的标记、地图(通常是 2D 网格地图),甚至是交互式标记对象。交互式标记对象允许用户设定标记对象在 3D 环境 中的位姿(位置和方向)。 对于导航功能包集,将会在下一章进行详细的介绍。我们会使用 rviz 支持的多种数据 类型,例如里程(画出机器人的里程位姿)、路径(画出机器人所走过的路径),这些包括了 机器人的多个连续位姿对象。在这些类型中,需要说明的是机器人的模型,它能够展示机器 人组件的 CAD 模型,并将每个组件的坐标系之间的转换考虑进去,甚至还能画出坐标变换 (Transform Frame,TF)树,并且在仿真环境中为坐标系调试提供非常大的帮助。我们会在下 一小节看到示例。 这个 3D 图形化接口还能够嵌入新的 rqt_gui 的 GUI 中,我们也能够为新的类型开发 插件等。我们相信在本书中提供的信息已经足够了。如果你有兴趣学习更多的技术细节和高 级技巧,我们推荐你查看 rviz 官方文档。 3.7.2 主题与坐标系的关系 如果主题发布的特定传感器数据在真实世界里具有一个物理位置的话,那么这样的主题 就需要有一个坐标系。例如,相对于机器人质心有一段距离的某个位置上有一个加速度计。 如果我们要集成加速度数据来估计机器人的速度和位姿,那么必须对机器人质心和加速度计 所在位置的坐标系之间进行转换。在 ROS 系统中,带有报文头的消息除了具有时间戳(在不 同的消息进行数据同步时也非常重要)之外,还要附上 frame_id(坐标系标签)。坐标系标 签用于区分消息所属的坐标系。 但当机器人具有多个设备,且每个设备都有不同的坐标系或位姿时,坐标系本身并没有 调试和可视化 67 更多的用处。我们仅利用其进行坐标变换而已。实际上,机器人的坐标变换树都会有一个根 坐标系(root)作为参照。这样,我们就能够在 rviz 中通过对比根坐标系和其他坐标系查看机 器人相对于真实世界坐标系的运动。 3.7.3 可视化坐标变换 为了解释如何进行坐标变换的可视化,我们将会再次使用 turtlesim 的示例。运行以下 launch 文件: Debugging and Visualization [ 94 ] For the navigation stack that we will cover in the next chapters, we have several data types that are also supported such as odometry (plots the robot odometry poses), and path (draws the path followed by the robot), which is a succession of pose objects. Among other types, it is also worth mentioning the robot model, which shows the CAD model of all the robot parts, taking into account the transformation among the frame of each element. Indeed, TF (transform frame) elements can also be drawn, which is very useful for debugging the frames in the system; we will see an example in the next section. This 3D graphical interface can also be embedded in the new rqt_gui GUI. We can also develop plugins for new types, and much more. However, we believe that the information given here is usually enough, and we recommend you consult the rviz documentation for further details and advanced topics. The relationship between topics and frames All topics must have a frame if they are publishing data from a particular sensor that have a physical location in the real world; for example, an accelerometer that is located in some position with respect to the mass center of the robot. If we integrate the accelerations to estimate the robot's velocities or its pose, we must take the transformation between the base (mass center) and the accelerometer frames. In ROS, the messages with a header, apart from the timestamp (also extremely important to put or synchronize different messages), can be assigned frame_id, which gives a name to the frame it belongs to. But the frames itself are not very useful when we have more than a single device in our robot, each in a different frame/pose. We need the transformation among them. Actually, we have a frame transformation tree that usually has the base frame as its root. Then, we can see in rviz how this and other frames move with respect to the world frame. Visualizing frame transformations To illustrate how to visualize the frame transformations, we are going to use the turtlesim example. Run the following launch file then: roslaunch turtle_tf turtle_tf_demo.launch This is a very basic example with the purpose of illustrating the TF visualization in rviz. Note that for the different possibilities offered by the TF API, you should refer to later chapters of this book, in particular Chapter 7, Navigation Stack – Robot Setups and Chapter 8, Navigation Stack – Beyond Setups. For now, it is enough to know that they allow making the computations in one frame and then transforming them to another, including time delays. 这是一个在 rviz 里能够用于解释坐标变换可视化的最基本的示例。需要注意的是 TF API 提供了很多不同的可能性,你可以参考本书的后续章节,特别是第 7 章和第 8 章。而对于现 在的示例,我们只需要知道它们能够在某个坐标系内进行计算并进行坐标变换到另外一个坐 标系,而且包含时间延迟即可。 我们还需要了解在系统中坐标变换会以某个特定的频率进行发布,这样它就会像子系统 一样允许我们遍历坐标变换树以获取其中任意两个坐标系之间的转换,并且可以在系统的任 意节点中通过调用 TF API 进行变换。 如果你收到一个错误,这很可能是因为在 launch 文件启动时侦听器(l istener)失效了。 侦听器是一个必备的节点,必须准备好才能进行坐标变换。因此,请在另外一个命令行窗口 下运行以下命令: Chapter 3 [ 95 ] It is also important to know that TFs are published at a certain frequency in the system, so it is like a subsystem where we can traverse the TF tree to obtain the transformation between any frames in it, and we can do it in any node of our system just by consulting TF. If you receive an error, it is probably because the listener died on the launch startup, as another node that was required was not yet ready; so, please run the following on another terminal to start it again: rosrun turtle_tf turtle_tf_listener Now you should see a window with two turtles (the icon might differ) where one follows the other. You can control one of the turtles with the arrow keys but with the focus on the terminal for which the launch file is run. The following screenshot shows how one turtle has been following the other, after moving the one we can control for some time: Each turtle has its own frame. We can see them in rviz: rosrun rviz rviz 现在你应该会看到一个带有两只小海龟的 窗口(小海龟的图标不同),一只小海龟跟着 另一只。你可以使用键盘上的上下左右四个箭 头按键控制小海龟。要注意要让操作系统的焦 点停留在运行 launch 文件的那个命令行窗口 上,而不是在 TurtleSim 窗口上,这样才能让 小海龟移动。右图显示了在我们控制一只小海 龟移动了一段距离之后,另一个小海龟是如何 跟随着这只小海龟的。 每一只小海龟都有自己的坐标系,可以在 rviz 中查看它们: Chapter 3 [ 95 ] It is also important to know that TFs are published at a certain frequency in the system, so it is like a subsystem where we can traverse the TF tree to obtain the transformation between any frames in it, and we can do it in any node of our system just by consulting TF. If you receive an error, it is probably because the listener died on the launch startup, as another node that was required was not yet ready; so, please run the following on another terminal to start it again: rosrun turtle_tf turtle_tf_listener Now you should see a window with two turtles (the icon might differ) where one follows the other. You can control one of the turtles with the arrow keys but with the focus on the terminal for which the launch file is run. The following screenshot shows how one turtle has been following the other, after moving the one we can control for some time: Each turtle has its own frame. We can see them in rviz: rosrun rviz rviz 现在,先放下 TurtleSim,我们先来看当 使用箭头键移动小海龟时 rviz 里小海龟的坐标系是如何移动的。先设定固定坐标为 68 第 3 章 /world,然后将坐标转换树添加到左边的区域。我们会看到 /turtle1 和 /turtle2 两 个坐标系,它们同为 /world 坐标系的子坐标系。在 world 展现的环境中,坐标系由轴组 成。/world 坐标系是固定的,因为我们在 rviz 中将其配置成这样。它同时是根坐标系和小 海龟所在坐标系的父坐标系,由一个带有粉红色尾巴的黄色箭头所表示。同时,设定 world 的视图(view)为 TopDownOrtho,因为这会使示例中检查坐标系的移动更容易,它们仅在 2D 平面中移动。你还会发现通过鼠标操作转换 world 视图显示的中心非常有用,只需要你 按下 shift 按键同时转动鼠标。 在下图中,你能看到不同海龟所在的两个坐标系如何转换到 /world 坐标系中并进行 显示。我们建议读者针对示例加以练习,并观察实时的现象。同时,你也可以更改固定坐标 系。请注意 config/example_tf.vcg 是用来作本示例的基本 rviz 配置的。 3.8 保存与回放数据 通常情况下,当我们使用机器人系统时,资源都是共享的,并不一定总能提供给你一个 人使用,或者因为种种原因实验不能顺利完成,如准备和实施实验就消耗了大量的时间。基 于以上原因,将实验会话数据记录下来用于未来的分析、处理、开发和算法验证,就是一个 学习者必修的课程。然而要保证存储数据正确并能够用于离线回放并不是容易的事情,因为 很多实验并不一定能反复进行。幸运的是,我们拥有 ROS 中的强大工具能够完成这个功能。 ROS 能够存储所有节点通过主题发布的消息。它能够创建一个消息记录包文件来保存消 息,并包含消息的所有字段参数和时间戳。这允许离线回放实验并模拟真实的状态,包括消 息的时间延迟。甚至 ROS 工具能够非常有效地在处理高速数据流时进行高效的数据组织的 方式来实现这一切。 在下面的小节中,我们会解释 ROS 中提供的这些用于存储和回放数据的工具,以及由 调试和可视化 69 ROS 开发者设计的使用二进制格式存储数据的消息记录包文件。我们还将看到如何管理这些 文件,也就是说,检查文件内容(消息的数量、主题等)、文件压缩、分割和合并多个记录包 文件。 3.8.1 什么是消息记录包文件 消息记录包是一个包含各个主题所发消息的容器,用于记录机器人各个节点间的会话过 程。简而言之,它们是系统运行期间消息传送的记录文件,并能允许我们回放所有一切,甚 至包括时间延迟。因此所有消息在记录时都会打上时间戳,不仅是报文头里的时间戳,还包 括使用消息的功能包。用于记录的时间戳和报文头内的时间戳之间的区别在于前者是消息被 记录时的时间,而后者是消息产生和发布时的时间。 消息记录包中存储的数据使用二进制格式。这个容器使用的数据结构非常特殊,能够支 持对超高速数据流的处理和记录。这是记录数据最关键的能力。当然,这和记录包文件的 大小也是相关的。随着文件的增大会牺牲数据的记录速度。我们能选择 bz2 算法进行数据 压缩,只需要在你使用 rosbag record 命令记录时使用 -j 参数,你会在下一节看到具体 示例。 每个消息与发布它的主题都被记录下来。因此,我们可以区分某个主题进行记录,或者 直接选择全部(使用 -a)。然后等你回放记录包的时候,同样可以通过指明特定主题的名称 来选择记录包中全部主题的某个特定子集进行回放。 3.8.2 使用 rosbag 在包文件中记录数据 我们首先要做的事情是简单地记录数据。使用一个非常简单的系统,以 example4 节点 为例。因此,先运行节点: Debugging and Visualization [ 98 ] Recording data in a bag file with rosbag The first thing we have to do to start is simply record the data. We are going to use a very simple system, our example4 node, as an example. Hence, we first run the node: rosrun chapter3_tutorials example4 Now we have two options. First, we can record all the topics: rosbag record -a Or, second, record only some specific (user-defined) topics. In this case, it will make sense to record only the example4 topics, so we will use the following: rosbag record /temp /accel By default, when we run the preceding command, the rosbag program subscribes to the node and starts recording the message in a bag file in the current directory with data as the name. Once you have finished the experiment or you want to stop recording, you only have to hit Ctrl + C. The following is an example of recording the data and the resulting bag file: [ INFO] [1357815371.768263730]: Subscribing to /temp [ INFO] [1357815371.771339658]: Subscribing to /accel [ INFO] [1357815371.774950563]: Recording to 2013-01-10-10-56-11.bag. You can see more options with rosbag help record that includes things such as the bag file size, the duration of the recording, and options to split the files into several ones of a given size. As we have mentioned before, the file can be compressed on the fly (using the -j option). In our honest opinion, this is only useful for small bandwidths because it also consumes some CPU time and might produce some message dropping. Also, we can increase the buffer (-b) size for the recorder in MB, which defaults to 256 MB, but it can be increased to some GB if the bandwidth is very high (especially with images). It is also possible to include the call to rosbag record into a launch file. To do so, we must add a node like this: Note that the topics and other arguments to the command are passed using the args argument. Also, it is important to say that when running from the launch file, the bag file is created by default in ~/.ros, unless we give the name of the file with -o (prefix) or -O (full name). 现在我们有两个选择。第一个是记录所有的主题: Debugging and Visualization [ 98 ] Recording data in a bag file with rosbag The first thing we have to do to start is simply record the data. We are going to use a very simple system, our example4 node, as an example. Hence, we first run the node: rosrun chapter3_tutorials example4 Now we have two options. First, we can record all the topics: rosbag record -a Or, second, record only some specific (user-defined) topics. In this case, it will make sense to record only the example4 topics, so we will use the following: rosbag record /temp /accel By default, when we run the preceding command, the rosbag program subscribes to the node and starts recording the message in a bag file in the current directory with data as the name. Once you have finished the experiment or you want to stop recording, you only have to hit Ctrl + C. The following is an example of recording the data and the resulting bag file: [ INFO] [1357815371.768263730]: Subscribing to /temp [ INFO] [1357815371.771339658]: Subscribing to /accel [ INFO] [1357815371.774950563]: Recording to 2013-01-10-10-56-11.bag. You can see more options with rosbag help record that includes things such as the bag file size, the duration of the recording, and options to split the files into several ones of a given size. As we have mentioned before, the file can be compressed on the fly (using the -j option). In our honest opinion, this is only useful for small bandwidths because it also consumes some CPU time and might produce some message dropping. Also, we can increase the buffer (-b) size for the recorder in MB, which defaults to 256 MB, but it can be increased to some GB if the bandwidth is very high (especially with images). It is also possible to include the call to rosbag record into a launch file. To do so, we must add a node like this: Note that the topics and other arguments to the command are passed using the args argument. Also, it is important to say that when running from the launch file, the bag file is created by default in ~/.ros, unless we give the name of the file with -o (prefix) or -O (full name). 或者,选择第二个,仅记录一些特定(用户自定义)的主题。在这个示例中, 仅记录 example4 的主题是合理的选择,我们可以使用以下指令: Debugging and Visualization [ 98 ] Recording data in a bag file with rosbag The first thing we have to do to start is simply record the data. We are going to use a very simple system, our example4 node, as an example. Hence, we first run the node: rosrun chapter3_tutorials example4 Now we have two options. First, we can record all the topics: rosbag record -a Or, second, record only some specific (user-defined) topics. In this case, it will make sense to record only the example4 topics, so we will use the following: rosbag record /temp /accel By default, when we run the preceding command, the rosbag program subscribes to the node and starts recording the message in a bag file in the current directory with data as the name. Once you have finished the experiment or you want to stop recording, you only have to hit Ctrl + C. The following is an example of recording the data and the resulting bag file: [ INFO] [1357815371.768263730]: Subscribing to /temp [ INFO] [1357815371.771339658]: Subscribing to /accel [ INFO] [1357815371.774950563]: Recording to 2013-01-10-10-56-11.bag. You can see more options with rosbag help record that includes things such as the bag file size, the duration of the recording, and options to split the files into several ones of a given size. As we have mentioned before, the file can be compressed on the fly (using the -j option). In our honest opinion, this is only useful for small bandwidths because it also consumes some CPU time and might produce some message dropping. Also, we can increase the buffer (-b) size for the recorder in MB, which defaults to 256 MB, but it can be increased to some GB if the bandwidth is very high (especially with images). It is also possible to include the call to rosbag record into a launch file. To do so, we must add a node like this: Note that the topics and other arguments to the command are passed using the args argument. Also, it is important to say that when running from the launch file, the bag file is created by default in ~/.ros, unless we give the name of the file with -o (prefix) or -O (full name). 默认情况下,当运行前面的命令, rosbag 程序会订阅相关节点并开始记录消息,将数 据存储在当前目录下以数据内容作为文件名的消息记录包文件中。一旦你完成实验或者想结 束记录,只需要点击 Ctrl + C。下面就是一个记录数据和包文件结果的示例: Debugging and Visualization [ 98 ] Recording data in a bag file with rosbag The first thing we have to do to start is simply record the data. We are going to use a very simple system, our example4 node, as an example. Hence, we first run the node: rosrun chapter3_tutorials example4 Now we have two options. First, we can record all the topics: rosbag record -a Or, second, record only some specific (user-defined) topics. In this case, it will make sense to record only the example4 topics, so we will use the following: rosbag record /temp /accel By default, when we run the preceding command, the rosbag program subscribes to the node and starts recording the message in a bag file in the current directory with data as the name. Once you have finished the experiment or you want to stop recording, you only have to hit Ctrl + C. The following is an example of recording the data and the resulting bag file: [ INFO] [1357815371.768263730]: Subscribing to /temp [ INFO] [1357815371.771339658]: Subscribing to /accel [ INFO] [1357815371.774950563]: Recording to 2013-01-10-10-56-11.bag. You can see more options with rosbag help record that includes things such as the bag file size, the duration of the recording, and options to split the files into several ones of a given size. As we have mentioned before, the file can be compressed on the fly (using the -j option). In our honest opinion, this is only useful for small bandwidths because it also consumes some CPU time and might produce some message dropping. Also, we can increase the buffer (-b) size for the recorder in MB, which defaults to 256 MB, but it can be increased to some GB if the bandwidth is very high (especially with images). It is also possible to include the call to rosbag record into a launch file. To do so, we must add a node like this: Note that the topics and other arguments to the command are passed using the args argument. Also, it is important to say that when running from the launch file, the bag file is created by default in ~/.ros, unless we give the name of the file with -o (prefix) or -O (full name). 70 第 3 章 使用 rosbag help record 可以看到更多的选项,其中包括记录包文件的大小、记 录的持续时间、分割文件到某个给定大小的选项。或者像前文所提到的那样,使用文件压缩 (使用 -j 参数)。坦率地讲,这只在数据存储速率较低时有用,因为这同时还会消耗大量的 CPU 时间并可能丢失部分消息。或者,我们可以以 MB 为单位增加记录缓存( -b)大小。缓 存大小默认值是 256MB,但在某些数据存储速率特别高的情况下也可能需要 GB 级的缓存 (特别是处理图像时)。 将对 rosbag record 的调用直接包含到 launch 文件中去也是可以的。我们需要在 launch 文件中增加一个节点如下所示: Debugging and Visualization [ 98 ] Recording data in a bag file with rosbag The first thing we have to do to start is simply record the data. We are going to use a very simple system, our example4 node, as an example. Hence, we first run the node: rosrun chapter3_tutorials example4 Now we have two options. First, we can record all the topics: rosbag record -a Or, second, record only some specific (user-defined) topics. In this case, it will make sense to record only the example4 topics, so we will use the following: rosbag record /temp /accel By default, when we run the preceding command, the rosbag program subscribes to the node and starts recording the message in a bag file in the current directory with data as the name. Once you have finished the experiment or you want to stop recording, you only have to hit Ctrl + C. The following is an example of recording the data and the resulting bag file: [ INFO] [1357815371.768263730]: Subscribing to /temp [ INFO] [1357815371.771339658]: Subscribing to /accel [ INFO] [1357815371.774950563]: Recording to 2013-01-10-10-56-11.bag. You can see more options with rosbag help record that includes things such as the bag file size, the duration of the recording, and options to split the files into several ones of a given size. As we have mentioned before, the file can be compressed on the fly (using the -j option). In our honest opinion, this is only useful for small bandwidths because it also consumes some CPU time and might produce some message dropping. Also, we can increase the buffer (-b) size for the recorder in MB, which defaults to 256 MB, but it can be increased to some GB if the bandwidth is very high (especially with images). It is also possible to include the call to rosbag record into a launch file. To do so, we must add a node like this: Note that the topics and other arguments to the command are passed using the args argument. Also, it is important to say that when running from the launch file, the bag file is created by default in ~/.ros, unless we give the name of the file with -o (prefix) or -O (full name). 需要注意的是主题和其他命令传递的参数会使用 args 参数。同时,在使用 launch 文 件直接启动记录的时候,记录包文件会默认创建在 ~/.ros 路径下,除非使用 -o(前 缀) 或 -O(全名)给文件命名。 3.8.3 回放消息记录文件 现在我们有了一个消息记录包文件,可以使用它回放所记录主题发布的所有消息数据。 只需要运行 roscore,而不需要再运行其他任何节点。然后,移动到想要回放的消息记录 包文件所在的文件夹下(在本章的示例中 bag 文件夹下提供了两个记录包示例),并且输入以 下命令: Chapter 3 [ 99 ] Playing back a bag file Now that we have a bag file recorded, we can use it to play back all the messages of the topics inside it. We need roscore running and nothing else. Then, we move to the folder with the bag file we want to play (there are two examples in the bag folder of this chapter's tutorials) and do this: rosbag play 2013-01-10-10-56-11.bag We will see the following output: [ INFO] [1357820252.241049890]: Opening bag/2013-01-10-10-56-11.bag Waiting 0.2 seconds after advertising topics... done. Hit space to toggle paused, or 's' to step. [RUNNING] Bag Time: 1357815375.147705 Duration: 2.300787 / 39.999868 In the terminal where we are playing the bag file, we can pause (hit Space bar) or move step by step (hit S), and, as usual, use Ctrl + C to finish it immediately. Once we reach the end of the file, it will close, but there is an option to loop (-l) that sometimes might be useful. Automatically, we will see the topics with rostopic list: /accel /clock /rosout /rosout_agg /temp The /clock topic is part of the fact that we can instruct the system clock to simulate a faster playback. This can be configured using the -r option. In the /clock topic, the time for simulation at a configurable frequency with the --hz argument (it defaults to 100 Hz) is published. Also, we could specify a subset of the topics in the file to be published. This is done with the --topics option. In order to see what we have inside the file, we would use rosbag info , which we will explain in the next section. 我们会看到如下输出: Chapter 3 [ 99 ] Playing back a bag file Now that we have a bag file recorded, we can use it to play back all the messages of the topics inside it. We need roscore running and nothing else. Then, we move to the folder with the bag file we want to play (there are two examples in the bag folder of this chapter's tutorials) and do this: rosbag play 2013-01-10-10-56-11.bag We will see the following output: [ INFO] [1357820252.241049890]: Opening bag/2013-01-10-10-56-11.bag Waiting 0.2 seconds after advertising topics... done. Hit space to toggle paused, or 's' to step. [RUNNING] Bag Time: 1357815375.147705 Duration: 2.300787 / 39.999868 In the terminal where we are playing the bag file, we can pause (hit Space bar) or move step by step (hit S), and, as usual, use Ctrl + C to finish it immediately. Once we reach the end of the file, it will close, but there is an option to loop (-l) that sometimes might be useful. Automatically, we will see the topics with rostopic list: /accel /clock /rosout /rosout_agg /temp The /clock topic is part of the fact that we can instruct the system clock to simulate a faster playback. This can be configured using the -r option. In the /clock topic, the time for simulation at a configurable frequency with the --hz argument (it defaults to 100 Hz) is published. Also, we could specify a subset of the topics in the file to be published. This is done with the --topics option. In order to see what we have inside the file, we would use rosbag info , which we will explain in the next section. 在回放消息记录包的命令行窗口内,可以暂停(点击空格键)或一步一步前进(点击 S 键),或者使用 Ctrl + C 来马上停止回复。一旦回放完毕,窗口就会关闭,但是有一个选项 (-l)允许循环播放,这在有些时候也很有用。 我们可以通过 rostopic list 命令查看主题列表: Chapter 3 [ 99 ] Playing back a bag file Now that we have a bag file recorded, we can use it to play back all the messages of the topics inside it. We need roscore running and nothing else. Then, we move to the folder with the bag file we want to play (there are two examples in the bag folder of this chapter's tutorials) and do this: rosbag play 2013-01-10-10-56-11.bag We will see the following output: [ INFO] [1357820252.241049890]: Opening bag/2013-01-10-10-56-11.bag Waiting 0.2 seconds after advertising topics... done. Hit space to toggle paused, or 's' to step. [RUNNING] Bag Time: 1357815375.147705 Duration: 2.300787 / 39.999868 In the terminal where we are playing the bag file, we can pause (hit Space bar) or move step by step (hit S), and, as usual, use Ctrl + C to finish it immediately. Once we reach the end of the file, it will close, but there is an option to loop (-l) that sometimes might be useful. Automatically, we will see the topics with rostopic list: /accel /clock /rosout /rosout_agg /temp The /clock topic is part of the fact that we can instruct the system clock to simulate a faster playback. This can be configured using the -r option. In the /clock topic, the time for simulation at a configurable frequency with the --hz argument (it defaults to 100 Hz) is published. Also, we could specify a subset of the topics in the file to be published. This is done with the --topics option. In order to see what we have inside the file, we would use rosbag info , which we will explain in the next section. 调试和可视化 71 Chapter 3 [ 99 ] Playing back a bag file Now that we have a bag file recorded, we can use it to play back all the messages of the topics inside it. We need roscore running and nothing else. Then, we move to the folder with the bag file we want to play (there are two examples in the bag folder of this chapter's tutorials) and do this: rosbag play 2013-01-10-10-56-11.bag We will see the following output: [ INFO] [1357820252.241049890]: Opening bag/2013-01-10-10-56-11.bag Waiting 0.2 seconds after advertising topics... done. Hit space to toggle paused, or 's' to step. [RUNNING] Bag Time: 1357815375.147705 Duration: 2.300787 / 39.999868 In the terminal where we are playing the bag file, we can pause (hit Space bar) or move step by step (hit S), and, as usual, use Ctrl + C to finish it immediately. Once we reach the end of the file, it will close, but there is an option to loop (-l) that sometimes might be useful. Automatically, we will see the topics with rostopic list: /accel /clock /rosout /rosout_agg /temp The /clock topic is part of the fact that we can instruct the system clock to simulate a faster playback. This can be configured using the -r option. In the /clock topic, the time for simulation at a configurable frequency with the --hz argument (it defaults to 100 Hz) is published. Also, we could specify a subset of the topics in the file to be published. This is done with the --topics option. In order to see what we have inside the file, we would use rosbag info , which we will explain in the next section. /clock 主题是用于指定调整系统时钟以便加快仿真的回放速度。它能够通过 -r 选项进 行配置。在 /clock 主题中能够发布仿真时间,并以 --hz 为配置频率(默认是 100Hz)。 同时,我们可以指定文件中将要发布主题的一个子集。这可以通过 --topics 选项来完 成配置。为了查看文件中包含哪些内容,可以使用 rosbag info 命令。我们 会在下一小节具体解释这个命令。 3.8.4 使用 rxbag 检查消息记录包的主题和消息 有两个主要的方法来查看消息记录包内部的数据。第一个非常简单。我们只需要输入 rosbag info ,然后结果会如下显示: 我们有消息记录包文件本身的信息,例如创建的日期、持续时间、文件大小,以及内部 消息的数量和文件的压缩格式(如果有压缩)。然后,我们还会有文件内部数据类型的列表。 最后,有主题的列表,并对应它们的名称、消息数量和消息类型。 第二种检查包文件的方法则非常强大。这个工具叫做 rxbag。它不仅具有图形界面,还 允许我们回放消息记录包、查看图像(如果有)、绘制标量数据图和消息的数据原结构。我们 只需要传递包文件的名称,就会看到如下图所示的界面(使用之前的包文件): 我们有一个能用于所有主题的时间条。对于每一个消息都会带有这个标记。在本示例图 中,能够在时间条中使用缩略图查看消息(通过鼠标指针来选择)。 在下图中,我们能够看到如何调用 Raw、Plot 和 Image 指令(如果是图像类型的主题), 来查看包文件中的主题。在时间条上单击右键就会弹出这个菜单。 72 第 3 章 对于 /accel 主题,我们可以使用一个轴绘出所有的字段。为了实现这个功能,先要进 入绘画( Plot)的视图中,点击齿轮状的按钮 / 图标,然后选择所有字段。请注意,我们可以 随后再删除它们或者新建一个轴(在右下角的窗口中)。这个绘图可以用于文件中所有数值, 其纵轴表示在回放中的当前位置。 需要注意的是至少要点击一次 Play 按钮才能够对数据进行绘制。我们还能够播放、暂 停、停止和移动到文件头或者文件结尾。 这里图像都很简单,而且会出现一个带有当前坐标系和配置选项的窗口,能够将这些内 容作为图像文件存储在硬盘上。 3.9 rqt 插件与 rx 应用 从 ROS Fuerte 发布以来, rx 应用或工具已经被弃用了,而我们需要使用 rqt 节点。它 们基本上是一样的,只有其中一小部分进行了小的升级、 bug 修正和加入了新功能。同时, 调试和可视化 73 它们能在 rqt_gui 的窗口和其他应用中当做插件加载。 我们使用以下列表对本章中介绍的 工具所对应的节点进行说明: ● rxconsole 被替代为 rosrun rqt_console rqt_console ● rxgraph 被替代为 rosrun rqt_graph rqt_graph ● rxplot 被替代为 rosrun rqt_plot rqt_plot ● rxbag 被替代为 rosrun rqt_bag rqt_bag 更多要说明的是,这些可被单独运行的插件能够更广泛地应用,能够作为命令行 (shell)、主题的发布者、消息类型的检查者。甚至 rviz 都有一个名为 rqt_rviz 的插件, 还能够被集成在最新的 rqt_gui 界面中。上面的这一切都被集成在 ROS Groovy 和 Hydro 中。在这两版 ROS 中,虽然 rx 工具已经被弃用了,但是仍然保留在软件包中。在 ROS Fuerte 中也是一样的,这个版本是第一个弃用 rqt 工具的版本。 3.10 本章小结 在阅读了本章并运行了示例代码之后,你就能够掌握加快机器人系统建造速度、错误调 试、结果可视化的大量实用工具。你可以通过这些工具评估或验证设计质量。作为机器人开 发人员,你会在开发过程中逐渐深入体验这些特殊的概念和工具: ● 现在你知道了如何在代码中包含不同级别不同详细程度的日志信息。这能够帮助你调 试节点错误。为了实现这个目的,你还需要使用其他一些 ROS 中包含的工具,例如 rxconsole 界面。另外,你也可以检查和列出运行中的节点、发布的主题和系统运行时 所提供的服务。这包含了使用 rxgraph 工具检查节点状态图。 ● 对于可视化工具,已经能够使用 rxplot 绘制标量数据曲线。它能够以更加直观的方 式分析你的节点所发布的特定变量。类似地,你能够查看更加复杂的数据类型(非标 量数据)。这包括使用 rviz 查看图像和 3D 数据。 ● 最后,你已经通过学习 rosbag 工具学会了记录和回放主题中的消息,还知道了如何 使用 rxbag 查看消息回放包文件的内容,这就允许你基于以往的经验去记录数据和 使用 AI 算法或机器人算法处理数据。
还剩85页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

huangz

贡献于2017-04-10

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf