天天看点

ROS机器人程序设计(原书第2版).

ROS机器人程序设计(原书第2版).

机器人设计与制作系列

ros机器人程序设计

(原书第2版)

learning ros for robotics programming,second edition

恩里克·费尔南德斯(enrique fernández)

路易斯·桑切斯·克雷斯波(luis sánchez crespo)

阿尼尔·马哈塔尼(anil mahtani)

亚伦·马丁内斯(aaron martinez) 著

刘锦涛 张瑞雷 等译

图书在版编目(cip)数据

ros机器人程序设计(原书第2版) / (西)恩里克·费尔南德斯(enrique fernández)等著;刘锦涛等译. —北京:机械工业出版社,2016.9 

(机器人设计与制作系列)

书名原文: learning ros for robotics programming, second edition

isbn 978-7-111-55105-8

i. r… ii. ①恩… ②刘… iii. 机器人-程序设计 iv. tp242

中国版本图书馆cip数据核字(2016)第248166号

本书版权登记号:图字:01-2016-1894

enrique fernández, luis sánchez crespo, anil mahtani, aaron martinez: learning ros for robotics programming, second edition(isbn: 978-1-78398-758-0).

copyright ? 2015 packt publishing. first published in the english language under the title “learning ros for robotics programming, second edition”.

all rights reserved.

chinese simplified language edition published by china machine press.

copyright ? 2016 by china machine press. 

本书中文简体字版由packt publishing授权机械工业出版社独家出版。未经出版者书面许可,不得以任何方式复制或抄袭本书内容。

ros机器人程序设计(原书第2版)

出版发行:机械工业出版社(北京市西城区百万庄大街22号 邮政编码:100037)

责任编辑:刘诗灏 责任校对:董纪丽

印  刷: 版  次:2016年11月第1版第1次印刷

开  本:186mm×240mm 1/16 印  张:20

书  号:isbn 978-7-111-55105-8 定  价:69.00元

凡购本书,如有缺页、倒页、脱页,由本社发行部调换

客服热线:(010)88379426 88361066 投稿热线:(010)88379604

购书热线:(010)68326294 88379649 68995259 读者信箱:[email protected]

版权所有 ? 侵权必究

封底无防伪标均为盗版

本书法律顾问:北京大成律师事务所 韩光/邹晓东

foreword  推荐序一

21世纪是什么样的世纪?是物联网的世纪?是vr的世纪?也许吧,但我更相信21世纪是机器人的世纪。

目前,我国已经步入经济转型的拐点区间,人口红利越来越难以支撑中国经济的发展和进步。在很多行业都已经开始了机器换人、生产工艺升级换代的步伐。工信部、发改委、财政部日前联合印发了《机器人产业发展规划(2016—2020年)》。这份规划指出:“到2020年,我国工业机器人年产量达到10万台,其中六轴及以上机器人达到5万台以上;服务机器人年销售收入超过300亿元,在助老、助残、医疗康复等领域实现小批量生产及应用;要培育3家以上的龙头产业,打造5个以上机器人配套产业集群;工业机器人平均无故障时间要达到8万小时;智能机器人实现创新应用。”从这个规划中可以看出,机器人未来的政策空间和市场发展空间都是非常巨大的。一方面,发展工业机器人在满足我国制造业的转型升级、提质增效,实现“中国制造2025”等方面具有极为重大的意义,是全面推进实施制造强国战略的重要一步。另一方面,从服务机器人来说,也要满足未来市场需求的增长。首先,这包括了基本生活需求,比如说养老、助老、助残等。其次是国家安全需求,比如救灾、抢险、海底勘探、航天、国防。最后还有家庭服务和娱乐机器人,比如娱乐、儿童教育、智能家居应用等。同时,科技部目前也在进行“十三五”科技创新规划战略研究,根据已经披露的内容,其中对机器人(尤其是服务机器人)非常重视,并会在近期遴选并启动一批相应的重大科技项目。

也许看完上面这些,你会觉得这更像是新闻描述,机器人产业真的这么火爆吗?当然。即使刨除工业机器人,只谈其他的智能机器人或服务机器人,这也是一个相当庞大的产业。例如,目前世界上最大的服务机器人公司应该还是美国的直觉外科公司。他们生产的达芬奇机器人系统在全世界已经应用了3000余套,其完成的手术超过千万例。由机器人完成的各类微创手术让无数患者获得新生。这家公司的市值超过300亿美元。中国目前估值最高的机器人公司是大疆创新,其年营收额已经超过10亿美元,估值超过百亿美元。要知道,10年前这家公司刚刚在深圳创立时,还比较弱小。因此,相信机器人产业在未来的前景一定非常广阔。

但是我们也注意到在军用国防、救灾救援、养老、家庭服务、儿童教育等领域,至今没有一个世界级的机器人公司存在。有很多爱好者都希望自己能够制造一个智能轮椅、一个智能儿童教育机器人或是一个家庭服务机器人,也许这样的机器人会像乔布斯和沃兹尼亚克在车库里做出的苹果电脑一样改变世界。但我们看到的很多人,自己只是机械工程师、电气工程师或者自动控制工程师,开发一个控制机器人的软件系统是遥不可及的事情;又或者自己虽然是软件工程师,但是并不知道如何控制和驱动底层设备。这要怎么办呢?没关系, ros机器人操作系统可以帮忙。

ros最初是作为科研辅助工具由斯坦福大学开发的。类似的机器人操作系统在世界各国还有很多。有些操作系统面向实时机器人控制,有些操作系统面向机器人仿真,有些操作系统面向用户交互。这些操作系统大部分都相对封闭,各成体系,没有在学术界和产业界造成影响。而由于ros极大的开放性和包容性,它能够兼容其他机器人开发工具、仿真工具和操作系统,使之融为一体。这使得ros不断发展壮大,并成为应用和影响力最广泛的机器人软件平台。

随着ros 2.0的开发,ros能够兼容除linux之外更多的操作系统,如windows、android;能够支持从工业计算机到adruino开发板等各类型的硬件;能够采集rgb-d摄像头、普通摄像头和各种类型的传感器数据;能够驱动类人形机器人、四轴飞行器等各类型的机器人。而且新版本的ros在采用soa架构的基础上,集成了mvc框架,更加有利于机器人人机交互界面的开发与机器人控制。

学习ros,本身就是掌握一把通往未来的钥匙。自从本人2012年翻译本书第1版之后,关于ros的书籍也渐渐多了起来。但和其他书籍相比,本书经过了时间的检验,第2版从内容到示例对学习ros都更有帮助。希望大家都能够成为机器人软件设计方面的专家。希望在中国的机器人设计领域能够出现新的领军人物,将中国的机器人带入世界一流行列。

刘品杰,本书第1版译者

foreword  推荐序二

记得第一次接触ros的时候我还在学校做研究,当时跟一些海外学者交流时得知有这个专为机器人设计的操作系统。我很是兴奋,一心想把ros用在我们最新研发的机器人上,于是就马上动手玩起来。由于当时ros尚在起步阶段,说明文档不太全面,同时社区支持又很少,不知道经过多少折腾才好不容易把它运行起来。体验后发现它的设计框架确实很适合作为机器人敏捷开发工具——算法及控制等代码很容易被复用,避免了很多重复劳动。但奈何当时的功能包不多,而且系统对运算资源要求高,最终没有用在当时的机器人项目上。

由于其开源性以及对商用友好的版权协议,ros很快得到越来越多的关注及支持。现在ros已有飞快的发展,越来越多机器人相关的软件工具亦加入ros的行列。国外一些商用的机器人也开始支持ros系统,甚至基于ros进行开发。相信这个趋势会一直持续下去并会蔓延到世界各地。而我亦深深体会到国内对ros的关注在近年有显著的上升。

从前在国内学习ros可谓孤军作战,身边没几个人听说过ros,而且只能从国外网站学习ros的相关知识,完全没有中文的资料可以查看。幸好国内有不少有心人积极推动ros的发展,不遗余力地对国外ros相关的文章进行翻译,并且发表一些原创的教学文章,丰富ros的中文资源,这使学习ros变得更方便。

我与本书译者通过共同举办ros国内推广课程而结缘。他对推动ros在国内的发展起到了举足轻重的作用,并运营着国内著名的ros交流社区。本书亦是他贡献ros中文社群的作品之一。而本书的作者同样是ros界的权威,有丰富的ros实战经验,使用ros进行过多种机器人的开发。书中从ros的架构概念到常用的调试工具、功能包及传感器的信息处理都有所涉及,是ros入门必看书之一。希望本书能让你快速进入ros的世界,探索ros的精彩。

林天麟,博士,nxrobo创始人& ceo

译者序  the translators’ words

机器人对于现代人类而言并不陌生和神秘,它在百年前的科幻小说中首次出现,而现在已经逐步进入人类生活的方方面面,机器时代即将到来!

智能机器人的程序究竟是如何设计出来的呢?

智能机器人需要具备强健的“肢”、明亮的“眼”、灵巧的“嘴”以及聪慧的“脑”,这一切的实现实际上涉及诸多技术领域,需要艰辛的设计、开发与调试过程,必然会遇到棘手的问题和挑战。而一个小型的开发团队难以完成机器人各个方面的开发工作,因而需要一套合作开发的框架与模式,以期能够快速集成已有的功能,省却重复劳动的时间。早在2008年,我们在与澳大利亚的布劳恩教授交流时,就得知他们开发了一套商业化的“robios”机器人操作系统,这套系统将一些常用的机器人底层功能进行了封装,可极大简化高级功能的开发。据他们介绍,这是最早的“机器人操作系统”,但由于产品不开源且价格昂贵,我们最终未能一试为快。后来在网络中不断地寻觅,最终发现了ros,由于其开源、开放的特性,一下子就引起了我们极大的兴趣。

我们于2010年建立了易科机器人qq群进行讨论,从而结识了国内最早期的一些机器人研究者和ros探索者。由于早期相关资料非常匮乏,我们于2012年创建了博客(blog.exbot.net)以进行技术分享与交流。易科机器人开发组成员在此期间贡献了大量的教程和开发笔记,在此向他们的无私奉献表示感谢与敬意!近年来,随着机器人的迅猛发展,ros得到了更为广泛的使用,国内也出现了一些优秀的项目,包括“星火计划”ros公开课(blog.exbot.net/spark)、“handsfree”ros机器人开发平台(wiki.exbot.net)等。

出版界近年来也是硕果累累,本书第1版便是国内第一本ros译著,由于实用性强,已经多次重印。第2版针对近年来ros的最新发展,对书中部分内容进行了修订,并增加了第6章和第10章。本书涵盖了使用ros进行机器人编程的最新知识与方法,通过ros编程实践能够帮助你理解机器人系统设计与应用的现实问题。在机器人开发实践中,我们认为除了成功的喜悦外,还看到机器人学目前所处的发展阶段:核心技术尚未成熟、诸多功能尚不完备、bug多……但我们相信,有了ros的开源精神和完备的合作开发框架,很多问题会迎刃而解。唯一迫切需要的就是期待你加入机器的开发和研究中来,一起推动开源机器人技术的发展与普及!

本书第2版与第1版的重叠部分主要沿用了刘品杰在第1版中的翻译,个别词汇根据习惯进行了修改。具体来说,第1至5章和第10章由张瑞雷翻译,第6章由张波翻译,第7至9章由刘锦涛翻译,吴中红和李静老师对全书进行了审阅,最后由刘锦涛对全书进行了修改润色和统稿整理。感谢杨维保、马文科等人对本书提出的修改建议!

我们将会在books.exbot.net发布本书的其他相关资源。

前 言  preface

本书第2版概括性地介绍了ros系统的各种工具。ros是一个先进的机器人操作系统框架,现今已有数百个研究团体和公司将其应用在机器人行业中。对于机器人技术的非专业人士来说,它也相对容易上手。在本书中,你将了解如何安装ros,如何开始使用ros的基本工具,以及最终如何应用先进的计算机视觉和导航工具。

在阅读本书的过程中无需使用任何特殊的设备。书中每一章都附带了一系列的源代码示例和教程,你可以在自己的计算机上运行。这是你唯一需要做的事情。

当然,我们还会告诉你如何使用硬件,这样你可以将你的算法应用到现实环境中。我们在选择设备时特意选择一些业余用户负担得起的设备,同时涵盖了在机器人研究中最典型的传感器或执行器。

最后,由于ros系统的存在使得整个机器人具备在虚拟环境中工作的能力。你将学习如何创建自己的机器人并结合功能强大的导航功能包集。此外如果使用gazebo仿真环境,你将能够在虚拟环境中运行一切。第2版在最后增加了一章,讲如何使用“move it!”包控制机械臂执行抓取任务。读完本书后,你会发现已经可以使用ros机器人进行工作了,并理解其背后的原理。

主要内容

第1章介绍安装ros系统最简单的方法,以及如何在不同平台上安装ros,本书使用的版本是ros hydro。这一章还会说明如何从debian软件包安装或从源代码进行编译安装,以及在虚拟机和arm cpu中安装。

第2章涉及ros框架及相关的概念和工具。该章介绍节点、主题和服务,以及如何使用它们,还将通过一系列示例说明如何调试一个节点或利用可视化方法直观地查看通过主题发布的消息。

第3章进一步展示ros强大的调试工具,以及通过对节点主题的图形化将节点间的通信数据可视化。ros提供了一个日志记录api来轻松地诊断节点的问题。事实上,在使用过程中,我们会看到一些功能强大的图形化工具(如rqt_console和rqt_graph),以及可视化接口(如rqt_plot和rviz)。最后介绍如何使用rosbag和rqt_bag记录并回放消息。

第4章介绍ros系统与真实世界如何连接。这一章介绍在ros下使用的一些常见传感器和执行器,如激光雷达、伺服电动机、摄像头、rgb-d传感器、gps等。此外,还会解释如何使用嵌入式系统与微控制器(例如非常流行的arduino开发板)。

第5章介绍ros对摄像头和计算机视觉任务的支持。首先使用firewire和usb摄像头驱动程序将摄像头连接到计算机并采集图像。然后,你就可以使用ros的标定工具标定你的摄像头。我们会详细介绍和说明什么是图像管道,学习如何使用集成了opencv的多个机器视觉api。最后,安装并使用一个视觉里程计软件。

第6章将展示如何在ros节点中使用点云库。该章从基本功能入手,如读或写pcl数据片段以及发布或订阅这些消息所必需的转换。然后,将在不同节点间创建一个管道来处理3d数据,以及使用pcl进行缩减采样、过滤和搜索特征点。

第7章介绍在ros系统中实现机器人的第一步是创建一个机器人模型,包括在gazebo仿真环境中如何从头开始对一个机器人进行建模和仿真,并使其在仿真环境中运行。你也可以仿真摄像头和激光测距传感器,为后续学习如何使用ros的导航功能包集和其他工具奠定基础。

第8章是两章关于ros导航功能包集中的第1章。该章介绍如何对你的机器人进行使用导航功能包集所需的初始化配置。然后用几个例子对导航功能包集进行说明。

第9章延续第8章的内容,介绍如何使用导航功能包集使机器人有效地自主导航。该章介绍使用ros的gazebo仿真环境和rviz创建一个虚拟环境,在其中构建地图、定位机器人并用障碍回避做路径规划。

第10章讨论ros中移动机器人机械臂的一个工具包。该章包含安装这个包所需要的文档,以及使用moveit!操作机械臂进行抓取、放置,简单的运动规划等任务的演示示例。

预备知识

我们写作本书的目的是让每位读者都可以完成本书的学习并运行示例代码。基本上,你只需要在计算机上安装一个linux发行版。虽然每个linux发行版应该都能使用,但还是建议你使用ubuntu 12.04 lts。这样你可以根据第1章的内容安装ros hydro。

对于ros的这一版本,你将需要ubuntu 14.04之前的版本,因为之后的版本已经不再支持hydro了。

对于硬件要求,一般来说,任何台式计算机或笔记本电脑都满足。但是,最好使用独立显卡来运行gazebo仿真环境。此外,如果有足够的外围接口将会更好,因为这样你可以连接几个传感器和执行器,包括摄像头和arduino开发板。

你还需要git(git-core debian软件包),以便从本书提供的源代码中复制库。同样,你需要具备bash命令行、gnu/linux工具的基本知识和一些c/c++编程技巧。

目标读者

本书的目标读者包括所有机器人开发人员,可以是初学者也可以是专业人员。它涵盖了整个机器人系统的各个方面,展示了ros系统如何帮助完成使机器人真正自主化的任务。对于听说过却从未使用过ros的机器人专业学生或科研人员来说,本书将是非常有益的。ros初学者能从本书中学习ros软件框架的很多先进理念和工具。不仅如此,经常使用ros的用户也可能从某些章节中学习到一些新东西。当然,只有前3章是纯粹为初学者准备的,所以那些已经使用过ros的人可以跳过这部分直接阅读后面的章节。

源代码和彩色图片下载

可以从你在http://www.packtpub.com中的账户下载所有已购买的packt publishing出版的书籍的示例代码文件。如果你在其他地方购买了这本书,可以访问http://www.packtpub.com/support并注册,文件会通过电子邮件直接发送给你。还可以从https://github.com/aaronmr/ros_book_hydro下载源代码文件。

我们同时提供了本书所有彩色的屏幕截图、对话框的pdf文件,这些彩色图片能够更好地帮助你理解输出的变化。可以从http://www.packtpub.com/sites/default/files/downloads/

7580os_colorimages.pdf下载这个文件。

about the authors  作者简介

enrique fernández在拉斯帕尔马斯大学获得计算机工程博士学位,目前是clearpath robotics公司高级机器人工程师。2009年他完成了关于slam的硕士学位论文。2013年他的博士论文解决了自主水下滑翔器(aug)的路径规划问题。那段时间,他还研究了计算机视觉、人工智能以及其他机器人学课题,例如赫罗纳大学的cirs/vicorob研究实验室auv的惯性导航系统和视觉slam。他在2012年参加了欧洲学生自主水下航行器设计挑战赛(student autonomous underwater challenge-europe,sauc-e)并获奖,在2013年作为合作者参与了sauc-e。

获得博士学位后,enrique作为高级机器人工程师在2013年6月加入pal robotics公司的自主导航部门。在那里,他开发了用于reem、reem-c和移动机器人以及相关项目的软件,如使用ros框架的stockbot。他的研究方向包括运动规划(路径规划和移动机器人控制)、机器人定位和slam。在2015年,他作为高级自主系统开发人员加盟clearpath robotics公司的自主系统部门从事slam相关工作。

在学术方面,enrique发表了多篇会议论文,其中两篇于2011年发表在《international conference of robotics and automation》(icra)上。他是packt publishing出版的第1版《ros机器人程序设计》和其他一些书部分章节的作者。他的硕士学位论文是关于室内机器人的fastslam算法,此机器人装备了sick激光扫描仪以及pioneer差动平台的轮式里程计。他的博士学位论文是关于aug的路径规划算法和工具。他还拥有电子和嵌入式系统(如pc104和arduino)的开发经验。他的研究背景包括slam、计算机视觉、路径规划、优化、机器人学和人工智能。

我要感谢这本书的合著者,感谢他们为完成这本书所付出的努力以及提供了无数示例的代码。我还要感谢博士论文期间大学智能系统和计算工程研究所(university institute of intelligent systems and computational engineering,siani)和水下机器人研究中心(center of underwater robotics research,cirs/vicorob)的研究小组成员。我也要感谢在pal机器人公司的同事,在那里我学到很多关于ros、机器人运动以及仿人双足机器人的知识,不仅有软件,还有电子和硬件设计。最后,我要感谢我的家人和朋友的帮助与支持。

luis sánchez crespo在拉斯帕尔马斯大学获得了电子与电信工程的双硕士学位。他曾在技术开发和创新研究所(idetic)、加那利群岛海洋平台(plocan)和应用微电子研究所(iuma)与不同的研究小组合作,进行超分辨率算法成像研究。

他的专业兴趣包括应用于机器人系统的计算机视觉、信号处理和电子设计。因此,他加入了avora团队,这批年轻的工程师和学生从零开始从事自主水下航行器(auv)的开发工作。在这个项目中,luis开始开发声学和计算机视觉系统,用于提取不同传感器的信息,例如水听器、声呐和摄像头。

依托海洋技术的强大背景,luis与人合作创办了一家新的初创公司subsea mechatronics,致力于为水下环境开发遥控操作和自主航行器。

下面是海洋技术工程师和企业家(lpa fabrika:gran canaria maker space的联合创始人和制造商)dario sosa cabrera对luis的评价:

“他很热情,是一个多学科的工程师。他对工作负责。他可以自我管理,并承担一个团队领导者的责任,如在sauc-e竞赛中领导了avora团队。他在电子和电信领域的背景让其具备从信号处理和软件到电子设计和制造的广泛专业知识。”

luis作为技术审校者参与了packt publishing出版的第1版《ros机器人程序设计》的相关工作。

首先,我要感谢aaron、anil以及enrique邀请我参与编写这本书。和他们一起工作非常快乐。同时,我也要感谢水下机电团队关于重型水下机器人的丰富经验,这些年我们一起成长。我必须提到lpa fabrika:gran canaria maker space,他们备课和讲授教育机器人及技术项目极富热情,与他们共享工作环境也非常令人激动。

最后,我要感谢我的家人和女朋友对我参与的每个项目的大力支持和鼓励。

anil mahtani是一名从事水下机器人工作5年的计算机科学家。他第一次在该领域工作是在完成硕士论文期间为低成本rov开发软件架构。在此期间,他也成为avora的团队领导者和主要开发人员,这个团队的高校学生设计和开发了一个自主水下航行器并参加了2012年的sauc-e。同年,他完成了论文并获得了拉斯帕尔马斯大学的计算机科学硕士学位。此后不久,他成为seebyte公司的软件工程师,这家公司是水下系统智能软件解决方案的全球领导者。

在seebyte公司工作期间,anil参与了军方、石油和天然气公司的一些半自主和自主水下系统的核心开发。在这些项目中,他积极参与自主系统开发、分布式软件体系结构设计和底层软件开发,同时也为前视声呐图像提供计算机视觉解决方案。他还获得了项目经理职位,管理一个开发和维护内核c++库的工程师团队。

他的专业兴趣主要包括软件工程、算法、分布式系统、网络和操作系统。anil在机器人方向主要负责提供高效和健壮的软件解决方案,不仅解决当前存在的问题,还预见未来的问题或可能的改进。鉴于他的经验,他在计算机视觉、机器学习和控制问题上也有独特的见解。anil对diy和电子学有兴趣,并且开发了一些arduino库回馈社区。

首先,我要感谢我的家人和朋友的支持,他们总是在我最需要的时候帮助我。我也要感谢我的同事和朋友david rubio vidal、emilio miguelá?ez martín和john brydon给我最大的支持,他们以专业的方式教我很多知识。我还要感谢我在seebyte和avora团队的同事,这些年从他们那里学习并经历很多。最后,我要特别感谢jorge cabrera gámez,他的指导和建议成就了我自己从未想象到的职业生涯。

aaron martinez是数字化制造领域的电脑工程师、企业家和专家。他于2010年在拉斯帕尔马斯大学的instituto universitario de cienciasy tecnologias ciberneticas(iuctc)完成硕士论文。他在远程监控领域使用沉浸式设备和机器人平台准备硕士论文。得到学位后,他参加了在奥地利林茨开普勒大学研究所的机器人学实习计划。在实习期间,他作为团队的一员使用ros和导航包集进行移动平台开发。之后,他参与了有关机器人的项目,其中一个是拉斯帕尔马斯大学的avora项目。在这个项目中,他参与自主水下航行器制作,并参与意大利的sauc-e。2012年,他负责维护这个项目;2013年,他帮助从ros向机器人平台移植导航包集和其他算法。

最近,aaron与人共同创立了一家名为subseamechatronics sl的公司。这家公司从事与水下机器人和遥控系统相关的项目,还设计和制造水下传感器。公司的主要目标是开发用于研发原型和重型机械手的定制解决方案。

aaron有许多领域的经验,比如编程、机器人、机电一体化、数字化制造以及arduino、beaglebone、服务器和激光雷达等设备。如今,他在subseamechatronics sl公司从事水下和空中环境的机器人平台设计。

我要感谢我的女朋友,她在我写这本书时给我支持以及给我继续成长的动力。我还要感谢donato monopoli(加那利群岛技术研究所(itc)生物医学工程部门的主管),以及itc所有的工作人员,感谢他们使我懂得数字制造、机械以及组织工程,我在此度过了生命中最美好的时光。

感谢我大学的同事,特别是alexis quesada,他给了我在准备硕士论文时创建我第一个机器人的机会。和他们一起工作,使我学习到很多关于机器人的知识。

最后,我要感谢家人和朋友的帮助与支持。

about the reviewers  审校者简介

piotr gródek是一位对计算机视觉和图像处理感兴趣的c++程序员。他曾经是嵌入式程序员,现在工作于银行。他是开源游戏和无人驾驶汽车的开发者。空闲时间他喜欢跑步、打壁球和阅读。

akihiko honda是空间机器人工程师。他于2012年在东京工业大学完成了硕士论文。目前他正在东京工业大学进行博士课程学习。

他的研究兴趣包括与空间机器人的远程操作和自动化相互对应的灵活或可变形的材料。他的一个目标是通过开发更好的自动控制系统提高飞船在太空的性能和稳定性。在早期的研究中,他参与了包含大型太阳能电池阵列和用于捕捉国际空间站的空间机械臂的地球观测卫星的工作。目前,他计划将其研究成果应用于空间太阳能电力系统、行星探测车等。他作为最佳参赛人获奖,并在日本天文学会举办的jsf卫星设计竞赛中因提出使用其研究的一个新型探索宇宙飞船而获奖。

他在大学的研究过程中,还参与了由日本太空发展署指挥的一些项目。在jem(rex-j)项目的机器人实验中,他参与了在轨道上的实验设备支持操作并在研究中获得灵感。他还参加了一个为宇航员开发可穿戴机械臂的项目并开发了手动控制系统。目前他正工作于两个探索机器人项目。其中一个是开发名为“kenage”的可变形的探测车,用于克服月球和火星特殊的崎岖地形。这个探测车正在使用gazebo仿真器进行可行性实验测试。在另一个项目中,他为jumpingscouter开发了一个环境识别系统。

2013年,他参与了萨利大学的smart探测器项目,开发环境保护和识别系统。同时,他也参与了探测车在真实环境中检测实际功能的现场实验。

我要感谢jaxa的hiroki kato给我打开了ros的大门并对我的研究给予宝贵建议。我还要感谢mitsushige oda教授、hiroki nakanishi教授以及东京工业大学空间机器人实验室的同事。他们分享了空间机器人的美好前景,提供了建议,并支持我在研究中使用ros实现它们。我也要感谢萨利大学star实验室的教授和同事给我提供在真实环境中使用ros的重要建议。我特别感谢来自大加那利岛的朋友给我介绍这令人振奋的工作。

最后,我要感谢我的家人yoshihiko、nobuko和ayaka对我的生活和梦想的支持,同时感谢女朋友对我的理解。

matthieu keller是一位热爱技术和计算机科学的法国工程师。他接受的教育涉及计算和机器人学,这使他成为一名爱好者。他审校了本书的第1版。

aridane j. sarrionandia de león研究计算机科学,并对机器人学和自主航行器有非常大的兴趣。他的学位课题是关于使用声呐的水下地图构建,为此他在自主水下航行器中使用ros工作。他有自主系统和ros的经验。他熟悉opencv和pcl,目前正在开发自主水面航行器的控制系统。

我要感谢luis和aaron给我这个机会审校这本书。同时,我要感谢拉斯帕尔马斯大学的avora团队,特别是aaron、luis和enrique,他们给我介绍了ros的神奇之处,并帮助我探索自主航行器世界。感谢我的导师jorge cabrera gámez,他让我有机会成为avora团队的一员。

最后,我要感谢我的家人和朋友在我生活中出现问题时支持我,特别要感谢eva纠正我不清晰的语句。

contents  目 录

推荐序一

推荐序二

译者序

前言

作者简介

审校者简介

第1章 ros hydro系统入门  1

1.1 pc安装教程  3

1.2 使用软件库安装ros hydro  3

1.2.1 配置ubuntu软件库  4

1.2.2 添加软件库到sources.list文件中  4

1.2.3 设置密钥  5

1.2.4 安装ros  5

1.2.5 初始化rosdep  6

1.2.6 配置环境  6

1.2.7 安装rosinstall  7

1.3 如何安装virtualbox和ubuntu  8

1.3.1 下载virtualbox  8

1.3.2 创建虚拟机  8

1.4 在beaglebone black上安装ros hydro  11

1.4.1 准备工作  12

1.4.2 配置主机和source.list文件  13

1.4.3 设置密钥  14

1.4.4 安装ros功能包  14

1.4.5 初始化rosdep  15

1.4.6 在beaglebone black中配置环境  15

1.4.7 在beaglebone black中安装rosinstall  15

1.5 本章小结  15

第2章 ros系统架构及概念  16

2.1 理解ros文件系统级  16

2.1.1 工作空间  17

2.1.2 功能包  18

2.1.3 综合功能包  19

2.1.4 消息  20

2.1.5 服务  21

2.2 理解ros计算图级  22

2.2.1 节点与nodelet  23

2.2.2 主题  24

2.2.3 服务  25

2.2.4 消息  26

2.2.5 消息记录包  26

2.2.6 节点管理器  26

2.2.7 参数服务器  27

2.3 理解ros开源社区级  27

2.4 ros系统试用练习  28

2.4.1 ros文件系统导览  28

2.4.2 创建工作空间  29

2.4.3 创建ros功能包和综合功能包  30

2.4.4 编译ros功能包  30

2.4.5 使用ros节点  31

2.4.6 如何使用主题与节点交互  33

2.4.7 如何使用服务  36

2.4.8 使用参数服务器  38

2.4.9 创建节点  38

2.4.10 编译节点  41

2.4.11 创建msg和srv文件  42

2.4.12 使用新建的srv和msg文件  44

2.4.13 启动文件  48

2.4.14 动态参数  50

2.5 本章小结  54

第3章 可视化和调试工具  55

3.1 调试ros节点  57

3.1.1 使用gdb调试器调试ros节点  57

3.1.2 ros节点启动时调用gdb调试器  58

3.1.3 ros节点启动时调用valgrind分析节点  59

3.1.4 设置ros节点core文件转储  59

3.2 日志信息  59

3.2.1 输出日志信息  59

3.2.2 设置调试信息级别  60

3.2.3 为特定节点配置调试信息级别  61

3.2.4 信息命名  62

3.2.5 按条件显示信息与过滤信息  62

3.2.6 显示信息的方式——单次、可调、组合  63

3.2.7 使用rqt_console和rqt_logger_level在运行时修改调试级别  63

3.3 检测系统状态  66

3.3.1 检测节点、主题、服务和参数  67

3.3.2 使用rqt_graph在线检测节点状态图  70

3.4 设置动态参数  71

3.5 当出现异常状况时使用    roswtf  72

3.6 可视化节点诊断  74

3.7 绘制标量数据图  75

3.8 图像可视化  77

3.9 3d可视化  79

3.9.1 使用rqt_rviz在3d世界中实现数据可视化  79

3.9.2 主题与坐标系的关系  82

3.9.3 可视化坐标变换  82

3.10 保存与回放数据  83

3.10.1 什么是消息记录包文件  84

3.10.2 使用rosbag在消息记录包中记录数据  84

3.10.3 回放消息记录包文件  85

3.10.4 检查消息记录包文件的主题和消息  86

3.11 应用rqt与rqt_gui插件  88

3.12 本章小结  88

第4章 在ros下使用传感器和执行器  90

4.1 使用游戏杆或游戏手柄  90

4.1.1 joy_node如何发送游戏杆动作消息  91

4.1.2 使用游戏杆数据在turtlesim中移动海龟  92

4.2 使用激光雷达——hokuyo urg-04lx  95

4.2.1 了解激光雷达如何在ros中发送数据  96

4.2.2 访问和修改激光雷达数据  98

4.3 使用kinect传感器查看3d环境中的对象  100

4.3.1 如何发送和查看kinect数据  101

4.3.2 创建使用kinect的示例  102

4.4 使用伺服电动机——dynamixel  104

4.5 使用arduino添加更多的传感器和

 执行器  107

4.6 在arduino上使用超声波传感器  111

4.7 距离传感器如何发送消息  113

4.7.1 创建使用超声波的示例  113

4.7.2 xsens如何在ros中发送数据  116

4.7.3 创建使用xsens的示例  116

4.8 使用10自由度低成本惯性测量模组imu  118

4.8.1 下载加速度传感器库  119

4.8.2 arduino nano和10自由度传感器编程  120

4.8.3 创建ros节点以使用10自由度传感器数据  121

4.9 gps的使用  123

4.9.1 gps如何发送信息  125

4.9.2 创建一个使用gps的工程实例  126

4.10 本章小结  127

第5章 计算机视觉  128

5.1 连接和运行摄像头  129

5.1.1 firewire ieee1394摄像头  129

5.1.2 usb摄像头  133

5.2 使用opencv制作usb摄像头 驱动程序  134

5.2.1 通过cv_bridge使用opencv处理ros图像  139

5.2.2 使用image transport发布图像  139

5.2.3 在ros中使用opencv  140

5.2.4 显示摄像头输入的图像  140

5.3 标定摄像头  141

5.4 ros图像管道  148

5.5 计算机视觉任务中有用的ros功能包  152

5.6 使用viso2实现视觉里程计  153

5.6.1 摄像头位姿标定  154

5.6.2 运行viso2在线演示  157

5.6.3 使用低成本双目摄像头运行viso2  159

5.7 使用rgbd深度摄像头实现视觉里程计  160

5.7.1 安装fovis  160

5.7.2 用kinect rgbd深度摄像头运行fovis  160

5.8 计算两幅图像的单应性  161

5.9 本章小结  162

第6章 点云  163

6.1 理解点云库  163

6.1.1 不同的点云类型  164

6.1.2 pcl中的算法  164

6.1.3 ros的pcl接口  165

6.2 我的第一个pcl程序  166

6.2.1 创建点云  167

6.2.2 加载和保存点云到硬盘  170

6.2.3 可视化点云  173

6.2.4 滤波和缩减采样  176

6.2.5 配准与匹配  181

6.2.6 点云分区  184

6.3 分割  187

6.4 本章小结  191

第7章 3d建模与仿真  192

7.1 在ros中自定义机器人的3d模型  192

7.2 创建第一个urdf文件  192

7.2.1 解释文件格式  194

7.2.2 在rviz里查看3d模型  195

7.2.3 加载网格到机器人模型  197

7.2.4 使机器人模型运动  198

7.2.5 物理属性和碰撞属性  198

7.3 xacro——?一个更好的机器人建模方法  199

7.3.1 使用常量  199

7.3.2 使用数学方法  200

7.3.3 使用宏  200

7.3.4 使用代码移动机器人  201

7.3.5 使用sketchup进行3d建模  204

7.4 在ros中仿真  205

7.4.1 在gazebo中使用urdf 3d模型  206

7.4.2 在gazebo中添加传感器  208

7.4.3 在gazebo中加载和使用地图  211

7.4.4 在gazebo中移动机器人  213

7.5 本章小结  215

第8章 导航功能包集入门  216

8.1 ros导航功能包集  216

8.2 创建变换  217

8.2.1 创建广播机构  218

8.2.2 创建侦听器  218

8.2.3 查看坐标变换树  221

8.3 发布传感器信息  221

8.4 发布里程数据信息  224

8.4.1 gazebo如何获取里程数据  225

8.4.2 创建自定义里程数据  228

8.5 创建基础控制器  232

8.5.1 使用gazebo创建里程数据  233

8.5.2 创建自己的基础控制器  235

8.6 使用ros创建地图  237

8.6.1 使用map_server保存地图  238

8.6.2 使用map_server加载地图  239

8.7 本章小结  240

第9章 导航功能包集进阶  241

9.1 创建功能包  241

9.2 创建机器人配置  241

9.3 配置全局和局部代价地图  243

9.3.1 基本参数的配置  244

9.3.2 全局代价地图的配置  245

9.3.3 局部代价地图的配置  245

9.3.4 基本局部规划器配置  246

9.4 为导航功能包集创建启动文件  247

9.5 为导航功能包集设置rviz  248

9.5.1 2d位姿估计  248

9.5.2 2d导航目标  249

9.5.3 静态地图  249

9.5.4 粒子云  251

9.5.5 机器人占地空间  251

9.5.6 局部代价地图  252

9.5.7 全局代价地图  252

9.5.8 全局规划  254

9.5.9 局部规划  254

9.5.10 规划器规划  254

9.5.11 当前目标  255

9.6 自适应蒙特卡罗定位  256

9.7 使用rqt_reconfigure修改参数  258

9.8 机器人避障  259

9.9 发送目标  260

9.10 本章小结  262

第10章 使用moveit!  264

10.1 moveit!体系结构  264

10.1.1 运动规划  265

10.1.2 规划场景  267

10.1.3 运动学  268

10.1.4 碰撞检测  268

10.2 在moveit!中集成一个机械臂  268

10.2.1 工具箱里有什么  268

10.2.2 使用设置助手生成一个moveit!包  269

10.2.3 集成到rviz  273

10.2.4 集成到gazebo或实际机器人的手臂  276

10.3 简单的运动规划  277

10.3.1 规划单个目标  278

10.3.2 规划一个随机目标  278

10.3.3 规划预定义的群组状态  280

10.3.4 显示目标的运动  280

10.4 考虑碰撞的运动规划  280

10.4.1 将对象添加到规划场景中  281

10.4.2 从规划的场景中删除对象  282

10.4.3 应用点云进行运动规划  283

10.5 抓取和放置任务  284

10.5.1 规划的场景  285

10.5.2 感知  288

10.5.3 抓取  288

10.5.4 抓取操作  290

10.5.5 放置操作  292

10.5.6 演示模式  295

10.5.7 在gazebo中仿真  295

10.6 本章小结  296

第1章

ros hydro系统入门

欢迎开始阅读本书第1章。本章将介绍如何安装ros系统,它是一种新的标准化机器人系统软件框架。本书是基于ros fuerte的《ros机器人程序设计》一书的升级版。通过ros,你可以使用大量的示例代码和开源程序轻松地完成机器人编程和控制。同时,你还能够理解如何使用各种传感器与执行器,并为你的机器人增加新的功能,如自动导航和视觉感知等。得益于开源理念,以及持续开发最先进算法并不断提供新功能的开源社区,ros不断进步完善。

通过本书,你将学习到如下内容:

在特定版本的ubuntu系统下安装ros hydro框架

ros的基本操作

调试以及数据可视化

在ros框架下进行机器人编程

连接传感器、执行器和硬件设备以创建机器人

创造三维(3d)模型并进行仿真

使用导航功能包集使机器人实现自主行驶

本章主要介绍怎样在ubuntu系统中安装完整版本的ros hydro。ubuntu不但能够全面支持ros,而且是ros官方推荐的操作系统。当然,你也可以在其他的操作系统中安装ros。这本书使用的ubuntu版本是12.04(precise pangolin),你可以在http://releases.ubuntu.com/12.04/免费下载安装。

在开始安装之前,我们首先了解一下ros的历史。

robot operating system(ros)是一个得到广泛使用的机器人系统的软件框架。ros的基本原理是无需改动就能够在不同的机器人上复用代码。基于这些,我们就可以在不同的机器人上分享和复用已经实现的功能,而不需要做太多的工作,避免了重复劳动。

2007年,斯坦福大学人工智能实验室(stanford artificial intelligence laboratory,sail)在斯坦福ai机器人项目(stanford ai robot project)的支持下开发了ros。2008年之后,其主要在willow garage公司支持下与超过20多家研究机构联合研发ros。

现在已经有很多家研究机构通过增加ros支持的硬件或开放软件源代码的方式加入ros系统的开发中。同样,也有很多家公司将其产品逐步进行软件迁移并在ros系统中应用。一些完全支持ros系统的平台如下图所示。这些平台往往会开放大量的代码、示例和仿真环境,以便开发人员轻松地开展工作。前三个发布代码的机器人例子是人形机器人。最后一个是由拉斯帕尔马斯大学开发的水下机器人,代码尚未公布。你可以在http://wiki.ros.org/robots找到很多这样的例子。

ros系统已经支持这些机器人中的传感器和执行器,同时每天ros软件框架支持的设备也在增加。此外,得益于ros和开放硬件,大量公司正在创建更便宜和更强大的传感器。arduino开发板是一个很好的例子,使用廉价的电路板可以添加很多类型的传感器如编码器、光和温度传感器等。

ros提供了一个标准的操作系统环境,包括硬件抽象、底层设备控制、通用功能的实现、进程间消息转发和功能包管理等。

它基于一个集中式拓扑的图结构,在节点中接收许多传感器、控制、状态、规划、执行器数据进行计算处理,并发送。它的各种库与功能包都是面向类unix系统的。

*-ros-pkg作为一种社区化的软件库使开发高级库更为容易。其中,很多功能是和ros系统绑定的,如导航库和rviz可视化界面都基于这个库。其中的一些库包含很多强大的工具,可以帮助我们方便使用ros并了解机器人当前的实时状态。其中,可视化工具、仿真环境和调试工具是最重要的几个。在下图中你可以看到两个工具,rviz和rqt_plot。中间是rqt_plot的截图,你可以看到由传感器数据绘制的曲线。另外两个截图是rviz;截图中可以看到真实机器人的三维显示。

ros是一个使用bsd(berkeley software distribution)开源协议的开源软件。无论是商业应用还是科学研究它都是免费的。*-ros-pkg包受到了多个开源协议的限制。

用ros你可以做更多工作。你可以使用库中的代码,改进后再次共享。这种观念就是开源软件的本质。

ros已经发布了多个版本,最新的版本是indigo。在本书中,我们使用的版本是hydro,因为这个版本更加稳定,而indigo是实验版本,可能存在错误。

下面会介绍如何安装hydro版本的ros。即使在本书中我们使用hydro,但是在实际工作中,你仍然可能需要安装老版本以便运行一些代码。

如前所述,本书中所使用的操作系统是ubuntu,全书的内容及教程将以该系统为基础。如果你习惯使用其他操作系统又想完成本书的学习,最好的选择就是安装一个带有ubuntu的虚拟机。因此,本章末尾会介绍虚拟机的安装方法。

当然,如果你想在其他系统中安装ros,你可以根据链接http://wiki.ros.org/hydro/installation中的指导来完成。

1.1 pc安装教程

我们假设你已经安装了ubuntu 12.04系统。我们使用这个版本的ubuntu,因为它是一个长期支持版本,配备了long-term support(lts)。这意味着社区在5年内将对这个版本提供维护。

此外,你需要具备一定的linux和命令工具基本知识,例如终端、vim、创建文件夹等。如果需要学习这些工具,你可以在网上找到很多相关的资源,或者你也可以参考这些主题相关的图书。

1.2 使用软件库安装ros hydro

2014年,ros网页更新了设计风格和内容的组织。你可以看到如下的网页截图:

在菜单中,可以找到关于ros的信息以及ros是否适用于你的系统等内容。

ros的安装说明可以在开始(getting started)部分的安装(install)选项卡中找到。

建议你在系统中使用软件库而不是源代码安装ros,除非你是一个专业用户,想进行自定义安装;在这种情况下,你可能更喜欢使用源代码安装ros。

所以我们使用软件库安装ros,下面将开始在我们的系统中配置ubuntu软件库。

1.2.1 配置ubuntu软件库

在本节中,你将学习安装ros hydro的步骤。这个过程基于官方安装页面的内容讲述,链接地址是http://wiki.ros.org/hydro/installation/ubuntu。

我们假设你理解ubuntu软件库(repository)的含义,并且知道如何管理它。如果你有任何疑问,请查询https://help.ubuntu.com/community/repositories/ubuntu。

在开始安装之前,需要首先配置软件库,为此需要先把软件库属性设为restricted、universe、multiverse。为了检查你的ubuntu版本是否支持这些软件库,请单击打开桌面左面的ubuntu软件中心(ubuntu software center),如右图所示。

打开 edit | software sources标签页,你将会看到以下界面,你要保证各个选项与下图中一致。

通常情况下,这些选项都是默认选中的,因此这一步骤你不会遇到什么问题。

1.2.2 添加软件库到sources.list文件中

在这一步中,你应该先选择ubuntu的版本。在多种版本的操作系统中都可以安装ros hydro。虽然你可以使用任何一个版本,但是推荐最新版本,以避免发生问题。请牢记,hydro在precise pangolin(12.04)、quantal quetzal(12.10)和raring ringtail(13.04)下可以正常工作。

在ubuntu 12.04(precise pangolin)下,安装软件库的具体方法如下:

在ubuntu 12.10(quantal quetzal)下安装软件库的具体方法如下:

在ubuntu 13.04(raring ringtail)下安装软件库的具体方法如下:

一旦添加了正确的软件库,操作系统就知道去哪里下载程序,并根据命令自动安装软件。

1.2.3 设置密钥

这一步是为了确认原始的代码是正确的,并且没有人在未经所有者授权的情况下修改任何程序代码。通常情况下,当添加完软件库时,你就已经添加了软件库的密钥,并将其添加到操作系统的可信任列表中。

现在我们能够确定代码来自授权网站并且没有被修改。

1.2.4 安装ros

现在准备开始安装ros。在开始之前最好先升级一下软件,避免错误的库版本或软件版本产生各种问题。输入以下命令升级该软件:

ros非常大,有时候你会安装一些永远也用不到的库和程序。通常情况下,根据用途有四种不同的安装方式。例如,你是一个高级用户,你只需要为你的机器人进行基本安装,而不需要在硬盘上留过多的空间。在本书中,我们推荐完全安装,因为这样能够保证包含本书中所有示例和教程需要的内容。如果你不知道正在安装的rviz、仿真环境或导航程序是什么,不用担心,你将会在后续章节中学习如下内容:

最简单的安装方式(并且是推荐的安装方式,但你需要足够大的硬盘空间)就是桌面完整安装(desktop-full)。这将安装ros、rqt工具箱、rviz可视化环境(3d)、通用机器人库、2d(如stage)和3d(如gazebo)仿真环境、导航工功能包集(移动、定位、地图绘制、机械臂控制),以及其他感知库,如视觉、激光雷达和rgbd摄像头(深度摄像头):

如果你没有足够的硬盘空间,或更喜欢安装特定部分的功能包集,那么第一次安装可以仅安装桌面安装文件,包括ros、rqt工具箱、rviz和其他通用机器人库。之后在需要的时候,再安装其他功能包集(使用apt命令并查找ros-hydro -*功能包集):

如果你只是想尝试一下,请安装ros-base。ros-base通常直接安装在机器人上,尤其是机器人没有屏幕和人机界面,只能tty远程登录的情况下。它只安装ros的编译和通信包,而没有任何的gui工具。在beaglebone black(bbb)中,你将使用下面命令:

最后,无论你选择哪一个选项进行安装,你都可以独立安装特定的ros功能包集(将stack替换成给定功能包集的名称):

1.2.5 初始化rosdep

在使用ros之前,必须先安装和初始化rosdep命令行工具。这可以使你轻松地安装库和编译源代码时的系统依赖,来运行在ros中的一些核心组件。在ros fuerte中,你必须安装完ros后再安装rosdep,因为它是一个独立的工具。现在rosdep默认安装在ros中。你可以使用下面的命令安装和初始化rosdep:

1.2.6 配置环境

恭喜你!能到这一步,说明你已经成功安装了某个版本的ros!为了能够运行它,系统需要知道可执行或二进制文件以及其他命令的位置。为了实现以上目的,你需要执行以下脚本:

如果你还安装了另一个ros发行版,每次你需要通过调用脚本来使用它,这个脚本会直接配置你的环境。在此我们使用的是ros hydro的脚本,如果你想尝试其他发行版,只需要用fuerte或groovy代替hydro即可。

如果你在命令行中输入roscore,那么将看到有程序启动。这是用来测试是否完成ros安装以及是否正确安装最好的方法。

请注意,如果你再次打开一个命令行窗口,并输入roscore或其他ros命令,却无法工作了。这是因为你需要再一次执行脚本来配置全局变量和ros的安装路径。

这个问题很容易解决,你只需要在.bashrc文件最后添加脚本,当你开始新命令行时,该脚本将执行并配置环境。

.bashrc文件在用户的home文件夹下(/home/用户名/.bashrc)。每次用户打开终端,这个文件加载命令行或终端的配置。所以你可以添加命令或配置方便用户使用。出于这个原因,我们将在.bashrc文件结束时添加脚本,以避免我们每次打开一个新终端时都要重复输入命令。我们用下面命令:

如果要使配置生效,你必须使用下面的命令去执行这个文件,或关闭当前终端,打开另一个新终端。

一些用户需要在他们的系统中安装不止一个ros的发行版。由于每次调用脚本都会覆盖系统当前配置,所以~/.bashrc只能设置你正在使用的那一个版本的setup.bash。为了实现在几个发行版之间切换,你需要调用不同的setup.bash脚本。

例如,在.bashrc文件下面可能有这么几行代码:

在这种情况下,ros electric版本将被执行。所以你必须确保将要运行的版本是文件中的最后一个。

如果你想通过终端检查使用的版本,可以非常简单地使用echo $ros_distro命令。

1.2.7 安装rosinstall

现在,下一步工作是安装一个命令工具,以帮助我们使用一条命令安装其他包。这个工具是基于python的,但是别担心,使用它不需要你掌握python。你在接下来的章节中将学习如何使用这个工具:

运行以下命令在ubuntu中安装这个工具:

这就完成了!你已经在你的系统完成了一个完整的ros系统安装。当我完成一个新安装的ros后,我个人喜欢测试两个东西:roscore和turtlesim。

如果你想做相同的事,在不同命令行分别输入以下命令:

如果一切正常,你将看到右边的界面:

1.3 如何安装virtualbox和ubuntu

virtualbox是一个通用、完整的虚拟机,它适用于x86硬件,面向服务器、台式机和嵌入式应用。virtualbox是免费的,支持所有主流的操作系统。几乎每一个linux爱好者都会使用它。

由于我们推荐使用ubuntu,你可能不希望更改计算机现有的操作系统。而如virtualbox之类的工具就可以满足此类需求。它能帮助我们在计算机上虚拟化新的操作系统,而无需对计算机硬件做任何改动。

后面的章节将展示如何安装virtualbox和ubuntu。此外,通过安装虚拟机,你可以在一个干净的操作系统中完成开发。如果你遇到任何问题,能够通过快速重启计算机解决,也可以备份虚拟机及所有必要的机器人安装文件。

1.3.1 下载virtualbox

第一步是下载virtualbox的安装文件。在编写本书时,以下链接能够在windows系统中下载最新的可用版本:http://download.virtualbox.org/virtualbox/4.3.12/virtualbox4.3.12-93733-win.exe。

一旦安装完成,你就需要下载ubuntu的镜像文件。在本教程中,我们使用一个已经安装了ros hydro的ubuntu镜像文件。可以通过以下链接下载它:http://nootrix.com/2014/04/virtualized-ros-hydro/。

对于这个版本,nootrix团队使用torrent下载虚拟机。我尝试了以这种方式下载文件并且效果很好。

你也可以找到预安装了ubuntu和ros的其他虚拟机,但我们还是要使用这个ros官网推荐的版本。

1.3.2 创建虚拟机

通过下载好的文件创建虚拟机非常简单,只需要按照本节的内容一步一步进行即可。打开virtualbox软件并单击file |import appliance,然后点击open appliance并选择之前下载好的roshydro.ova文件,如下图所示。

在下一个窗口中,可以配置新虚拟机的参数。我们保持默认配置并且仅仅改变虚拟机的名称。这个名称帮助我们区分不同的虚拟机。我们推荐给它起一个容易理解的名称,在这里我们使用本书的名称,如下图所示。

点击import按钮,并在下一个窗口中接受软件授权许可。你将看到一个进度条。这表明virtualbox正在复制虚拟机镜像文件,它在以新的名称创建新的副本。

需要说明的是,这个过程并不会影响原有的ros.ova文件,并且你可以通过对原文件进行多次复制创建多个虚拟机。

复制过程所需要的时间取决于计算机的执行速度。当它完成时,可以点击start按钮启动虚拟机。需要注意的是,如果你的机器上有多个虚拟机,在启动前应该选择正确的那一个。当然,在这个例子里只有一个虚拟机。

有时候会出现如下图所示的错误提示。这是因为计算机没有正确的usb 2.0驱动程序。可以通过安装oracle vm virtualbox扩展包(extension pack)来解决问题,当然也可以通过在虚拟机中禁用usb支持来解决。

为了禁用usb支持,在虚拟机上右键单击并选择settings。在工具栏中,选择ports | usb,并取消勾选enable usb 2.0(ehci)controller复选框,如下图所示。重启虚拟机后,就不会再出现任何问题。

虚拟机启动之后,你能看到完成ros安装之后的ubuntu 12.04界面,如下图显示:

当完成这些步骤后,你就有了一个能够在这本书中使用的完整版本的ros hydro。你可以运行所有的例子和我们将使用的功能包集。遗憾的是,virtualbox在使用部分实际外接设备的时候会有问题,并且你可能无法使用这个ros hydro镜像完成第4章中给出的例子。

1.4 在beaglebone black上安装ros hydro

beaglebone black(bbb)是一种基于arm cortex a8处理器的低成本开发平台。此开发板是基于?ngstr?m linux发行版制作的。?ngstr?m由一支希望统一嵌入式系统linux发行版的小型团队开发,他们希望操作系统是稳定且用户友好的。

考虑到社区的开发人员需要一个具有一些通用输入/输出(gpio)引脚的机载计算机设备,德州仪器设计了beaglebone black。beaglebone black平台是beaglebone的改进版。开发板的主要特性包括arm cortex a8处理器(时钟频率为1ghz,内存为512mb),具有以太网、usb接口、hdmi、46引脚gpio接口。这些gpio可以设置为数字i/o、adc、脉宽调制,以及i2c、spi或者uart等通信协议接口。gpio是一种直接将传感器和执行器与beaglebone连接的简单方法。beaglebone如下图所示:

在beaglebone开发板刚推出时,无法直接在?ngstr?m发行版上安装ros。由于这个原因,通常在beaglebone上安装基于ubuntu的操作系统。有不同版本的ubuntu arm兼容beaglebone black和ros,推荐在运行ros的平台上使用ubuntu 13.04 arm raring armhf的镜像。

目前已有了?ngstr?m发行版的ros版本安装文件。安装步骤可以参考网址http://wiki.ros.org/hydro/installation/angstrom。除此之外,我们选择在ubuntu arm上安装ros还因为这个发行版更常用,此外它还可以用于其他基于arm的开发板,如udoo odroid u3、odroid x2或gumstick。

arm技术在智能手机和平板计算机等移动设备领域蓬勃发展。除了增加的arm cortex运算性能,高集成度和低功耗也使这项技术更适合于自主机器人系统开发。在过去的几年里,开发人员已经在市场上推出多款arm平台。其中一些特性类似于beaglebone black、raspberry pi或gumstick overo。此外,更强大的开发板(如具备双核arm cortex a9的gumstick duovero或四核版odroid u3、odroid x2或udoo)也已经上市。

1.4.1 准备工作

在安装ros到beaglebone black之前,我们需要做一些准备工作。本书的重点是介绍ros,我们将列出这些准备工作但不详细介绍。很多关于beaglebone black和ubuntu arm的信息可以在网站、论坛和书中找到。

首先,我们必须安装一个与ros兼容的ubuntu arm发行版。所以需要ubuntu arm的安装镜像。可以通过下面的命令使用wget获得ubuntu 13.04 raring armhf:

下载ubuntu 13.04 armhf镜像,将其安装到sd卡上。可以在elinux网址上得到关于如何安装ubuntu到bealgebone black的更多细节:http://elinux.org/beagleboard:ubuntu_on_beaglebone_black # ubuntu_ raring_on_micro_sd。

在之前的网页上描述的过程工作良好,但是我们必须注意所使用的ubuntu版本。由于网站会定期更新,因此它们现在使用的是ubuntu 14.04,但这可能与我们所使用的ros不兼容。我们将使用之前提及的ubuntu 13.04 raring armhf。

一旦在开发平台中安装好ubuntu arm,就需要配置beaglebone black的网络接口以实现网络访问。所以,必须配置如ip、dns和网关等网络配置。

记住,在另一个计算机上挂载sd卡并编辑/etc/network/interfaces可能是最简单的方式。

设置好网络后,为了安装ros中如cmake、python或vim等可能需要的功能包、程序和库,使用以下命令:

用于beaglebone black的操作系统在微型sd卡上配置的空间为1至4gb。这个存储空间是非常有限的,如果我们想要使用一个大的ros hydro功能包,它可能就不够用了。为了解决这个问题,我们可以使用空间更大的sd卡,重新分区,扩大文件系统占可用空间的比例。

如果需要使用更大的存储空间,建议扩大beaglebone black内存文件系统。在网址http://elinux.org/beagleboard:expanding_file_system_partition_on_a_microsd可以得到相关内容的进一步介绍。

通过下列命令可以实现上述目的:

1.需要切换到超级用户模式,输入下面的命令并输入密码:

2.查看sd卡的分区信息:

3.输入p,可见sd卡的两个分区:

4.之后,输入'd'删除分区,然后输入2指定要删除的分区/dev/mmcblk0p2:

5.输入n,创建一个新分区;如果输入p将创建一个主分区。我们输入2指定第二个分区的编号。

6.如果没有问题,输入w保存这些操作,或按ctrl + z组合键取消更改:

7.完成后重启开发板:

8.完成重启后,再次切换到超级用户模式:

9.最后,运行下面的命令执行操作系统内存文件系统的扩容。

现在我们准备好安装ros了。安装的过程非常类似于在本章之前介绍过的安装,主要区别是我们不能安装ros full-desktop,必须单独安装每一个功能包。

1.4.2 配置主机和source.list文件

现在开始配置主机:

在这之后,我们将配置源列表,这基于我们安装在beaglebone black中的ubuntu版本。兼容beaglebone black的ubuntu版本数量有限,目前活跃的发行版是ubuntu 13.04 raring armhf,它也是ubuntu arm最受欢迎的版本。

ubuntu 13.04 raring armhf:

ubuntu 12.10 quantal armhf:

ubuntu 12.04 precise armhf:

1.4.3 设置密钥

正如前面所解释的,这一步需要确认源代码是正确的,并且没有人在未经所有者授权的情况下修改过代码或程序:

1.4.4 安装ros功能包

在安装ros功能包之前,我们必须更新系统以避免出现库依赖的问题。

这部分安装与beaglebone black略有不同。ros中有很多库和功能包,并不是全部都能在arm上完整编译。所以不可能实现一个完整的桌面版安装。建议独立安装各功能包,以确保它们能在arm平台上运行。

你可以尝试安装ros-base,称为ros bare bones。ros-base会安装包括编译和通信库以及ros功能包,但不包括gui工具:

我们可以使用下面的命令来安装指定的ros功能包:

如果我们需要查找在beaglebone black中可用的ros功能包,运行下面的命令:

例如,下面的包为ros正常工作的基础,可以使用apt-get单独安装:

虽然从理论上讲,beaglebone black并不支持所有的ros功能包,但实际上我们已经能够将在pc上开发的整个项目移植到beaglebone black。我们成功尝试了很多功能包,只有安装rviz没有实现。

1.4.5 初始化rosdep

在使用ros之前,必须首先安装并初始化rosdep命令行工具,可使你轻松地安装库并解决你准备编译源代码的系统依赖问题,以及提供ros运行需要的一些核心组件。可以使用下面的命令安装并初始化rosdep:

1.4.6 在beaglebone black中配置环境

如果你已经到达这一步,恭喜你,因为你已经在beaglebone black中成功地安装了ros。添加下面的ros环境变量到bash中,这样它们就会在每次命令行启动时自动加载:

如果在系统中有多个版本的ros我们必须注意。bashrc的变量必须设置为我们正在使用的版本。

如果我们想要在当前命令行中配置环境,运行命令如下:

1.4.7 在beaglebone black中安装rosinstall

rosinstall是ros中一个常见的命令行工具,使安装功能包更方便。如果你要安装它,可以在ubuntu中使用下面的命令行:

1.5 本章小结

在这一章,我们学习了如何在不同ubuntu设备上(计算机、virtualbox、beaglebone black)安装ros hydro。通过这些步骤,你已经在系统上安装了一切必要的软件,可以使用ros开始工作,也可以练习本书中的示例。你也可以使用源代码来安装ros。但这样做需要编译所有代码,因此只适用于高级linux用户。而我们一般建议你使用软件库安装,这样做更通用,且一般不会出现任何错误或问题。

如果你对ubuntu系统不是很熟悉,那么建立一个虚拟机并在虚拟机上学习使用ros会更加方便。这样,如果你在安装和使用过程中发生任何问题,都无需重新安装操作系统,只需要恢复虚拟机镜像文件,然后就可以重新开始。

通常情况下,虚拟机不能访问扩展出的实际硬件,如传感器和执行器。尽管如此,你仍可以用它来测试算法。

下一章将学习ros的架构、一些重要的概念,以及一些能够与ros进行直接交互的工具。

第2章

ros系统架构及概念

一旦你完成了ros系统的安装,你肯定会想“好了,我已经安装完成,那么下一步要做什么呢?”在本章我们将学习ros系统架构及它的组成。然后,我们会开始创建节点和功能包,并使用ros系统自带的turtlesim示例。

ros系统的架构主要被设计和划分成了三部分,每一部分都代表一个层级的概念:

文件系统级(the filesystem level)

计算图级(the computation graph level )

开源社区级(the community level)

第一级是文件系统级。在这一级,我们会使用一组概念来解释ros的内部构成、文件夹结构,以及工作所需的核心文件。

第二级是计算图级,体现的是进程和系统之间的通信。在相关小节中,我们将学习ros的各个概念和功能,包括建立系统、处理各类进程、与多台计算机通信等。

第三级是开源社区级,我们将解释一系列的工具和概念,其中包括在开发人员之间如何共享知识、算法和代码。这个层级非常重要,正是由于开源社区的大力支持,ros系统才得以快速成长。

2.1 理解ros文件系统级

如果你刚接触ros,无论是准备使用ros系统还是准备开发ros项目,你都会觉得ros中的各种概念非常奇怪。而一旦你驾轻就熟,那么这些概念就会变得熟悉了。

与其他操作系统类似,一个ros程序的不同组件要被放在不同的文件夹下。这些文件夹是根据功能的不同来对文件进行组织的:

功能包(package):功能包是ros中软件组织的基本形式。一个功能包具有用于创建ros程序的最小结构和最少内容。它可以包含ros运行的进程(节点)、配置文

件等。

功能包清单(package manifest):功能包清单提供关于功能包、许可信息、依赖关系、编译标志等的信息。一个包的清单由一个名为package.xml的文件管理。

综合功能包(metapackage):如果你将几个具有某些功能的功能包组织在一起,那么你将会获得一个综合功能包。在ros fuerte中,这种包的组织形式被称为功能包集(stack)。为了保持ros简洁,功能包集被移除,现在使用综合功能包实现这个功能。在ros系统中,存在大量不同用途的综合功能包,例如导航功能包集。

综合功能包清单(metapackage manifest):综合功能包清单(package.xml)类似普通功能包但有一个xml格式的导出标记。它在结构上也有一定的限制。

消息类型(message(msg)type):消息是一个进程发送到其他进程的信息。ros系统有很多的标准类型消息。消息类型的说明存储在my_package/msg/mymessagetype.msg中,也就是对应功能包的msg文件夹下。

服务类型(service(srv)type):服务描述说明存储在my_package/srv/myservicetype.srv中,定义了在ros中由每个进程提供的关于服务请求和响应的数据结构。

在右侧的截图中,可以看到turtlesim功能包的内容。你看到的是一系列文件和文件夹,包含代码、图片、启动文件、服务和消息。记住,截图显示文件的一个简短列表,真正的功能包会更多。

2.1.1 工作空间

概言之,工作空间就是一个包含功能包、可编辑源文件或编译包的文件夹。当你想同时编译不同的功能包时非常有用,并且可以用来保存本地开发包。

下图所示的是一个典型的工作空间。每个文件夹都是一个具有不同功能的空间:

源文件空间(the source space):在源空间(src文件夹)放置了功能包、项目、克隆包等。在这个空间最重要的一个文件是cmakelists.txt。当你在工作空间中配置功能包时,src文件夹cmakelists.txt调用cmake。这个文件是通过catkin_init_workspace命令创建的。

编译空间(the build space):在build文件夹里,cmake和catkin为功能包和项目保存缓存信息、配置和其他中间文件。

开发空间(the development(devel)space):devel文件夹用来保存编译后的程序,这些是无需安装就能用来测试的程序。一旦项目通过测试,你可以安装或导出功能包与其他开发人员分享。

catkin编译包有两个选项。第一个是使用标准cmake工作流程,通过此方式可以一次编译一个包,见以下命令:

如果你想编译所有的包,可以使用catkin_make命令行,见以下命令:

在ros配置的编译空间目录中,这两个命令编译可执行文件。

ros的另一个有趣的特性是它的覆盖。当你正在使用ros功能包,例如turtlesim,你可以使用安装版本,也可以下载源文件并编译它来使用你的修改版本。

ros允许使用你自己版本的功能包以替代安装版本。如果你正在安装升级包,这是非常有用的。或许此时你并不理解它的作用,但无需担心,在下一章我们将使用这个功能来创建自己的插件。

2.1.2 功能包

功能包指的是一种特定的文件结构和文件夹组合。这种结构如下所示:

include/package_name/:此目录包含了你需要的库的头文件。

msg/:如果你要开发非标准消息,请把文件放在这里。

scripts/:其中包括bash、python或任何其他脚本的可执行脚本文件。

src/:这是存储程序源文件的地方。你可能会为节点创建一个文件夹或按照你希望的方式去组织它。

srv/:这表示服务(srv)类型。

cmakelists.txt:这是cmake的生成文件。

package.xml:这是功能包清单文件。

为了创建、修改或使用功能包,ros给我们提供了一些工具:

rospack使用此命令来获取信息或在系统中查找工作空间。

catkin_create_pkg 当你想要创建一个新的功能包时,使用此命令。

catkin_make 使用此命令来编译工作空间。

rosdep 此命令安装功能包的系统依赖项。

rqt_dep:这个命令用来查看包的依赖关系图。如果你想看包的依赖关系图,你会在rqt发现一个称为包图(package graph)插件。选择一个包并查看依赖关系。

若要在文件夹和功能包之间移动文件,ros提供了非常有用的rosbash功能包,其中包含了一些非常类似于linux命令的命令。例如:

roscd 此命令用于更改目录,类似于linux中的cd命令。

rosed 此命令用来编辑文件。

roscp 此命令用于从一些功能包复制文件。

rosd 此命令列出功能包的目录。

rosls 此命令列出功能包下的文件,类似于linux中的ls命令。

文件package.xml必须在功能包中,用来说明此功能包相关的各类信息。如果你发现在某个文件夹内包含此文件,那么这个文件夹很可能是一个功能包或综合功能包。

打开一个package.xml文件,可以看到包的名称、依赖关系等信息。功能包清单的作用就是为了更容易地安装和分发这些功能包。

在package.xml文件中使用的两个典型标记是<build_depend>和<run_depend>。

<build_depend>标记会显示当前功能包安装之前必须先安装哪些功能包。这是因为新的功能包会使用其他包的一些功能。

<run_depend>标记显示运行功能包代码所需要的包。右面截图是package.xml文件的示例。

2.1.3 综合功能包

如前所述,综合功能包是一些只有一个文件的特定包,它是package.xml。它不包含其他文件,如代码等。

综合功能包用于引用其他功能特性类似的功能包,例如导航包、ros_tutorials等。

你可以将ros fuerte的功能包和功能包集转为hydro和catkin。具体参考http://wiki.ros. org/catkin/migrating_from_rosbuild。

在右面截图中,你可以看到在ros_tutorials综合功能包中package.xml的内容。你可以看到<export>标记和<run_depend>标记,这些是功能包清单中必不可少的。

如果你想定位ros_tutorials综合功能包,可以使用下面的命令:

显示路径为:/opt/ros/hydro/share/ros_tutorials。

查看里面的代码,通过下面命令:

记住hydro使用综合功能包,不是功能包集,但还是用rosstack命令用于寻找综合功能包。

2.1.4 消息

ros使用了一种简化的消息类型描述语言来描述ros节点发布的数据值。通过这样的描述语言,ros能够使用多种编程语言生成不同类型消息的源代码。

ros提供了很多预定义消息类型。如果你创建了一种新的消息类型,那么就要把消息的类型定义放到功能包的msg/文件夹下。在该文件夹中,有用于定义各种消息的文件。这些文件都以.msg为扩展名。

消息类型必须具有两个主要部分:字段和常量。字段定义了要在消息中传输的数据类型,例如int32、float32、string或之前创建的新类型,如叫做type1和type2的新类型。常量用于定义字段的名称。

一个msg文件的示例如下:

我们能够在下表中找到很多ros消息所使用的标准数据类型:

基本类型 序列化 c++ python

bool(1) unsigned 8-bit int uint8_t(2) bool

int8 signed 8-bit int int8_t int

uint8 unsigned 8-bit int uint8_t int(3)

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) 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

ros消息中的一种特殊数据类型是报文头,主要用于添加时间戳、坐标位置等。报文头还允许对消息进行编号。通过在报文头内部附加信息,我们可以知道是哪个节点发出的消息,或者可以添加一些能够被ros处理的其他功能。

报文头类型包含以下字段:

可以通过下面命令查看消息的结构:

我们将在后续的章节中看到,正是通过报文头才能够记录当前机器人运行的时间戳和坐标位置。

在ros中有一些处理消息的工具。例如rosmsg命令行工具能够输出消息定义信息,并可以找到使用该消息类型的源文件。

在后面的章节中,我们将会学习如何使用正确的工具创建消息。

2.1.5 服务

ros使用了一种简化的服务描述语言来描述ros的服务类型。这直接借鉴了ros msg消息的数据格式,以实现节点之间的请求/响应通信。服务的描述存储在功能包的srv/子目录下.srv文件中。

若要调用服务,你需要使用该功能包的名称及服务名称。例如,对于sample_package1/srv/sample1.srv文件,可以将它称为sample_package1/sample1服务。

ros中有一些执行某些功能与服务的工具。rossrv工具能输出服务说明、.srv文件所在的功能包名称,并可以找到使用某一服务类型的源代码文件。

如果你想要在ros中创建一个服务,可以使用服务生成器。这些工具能够从基本的服务说明中生成代码。你只需要在cmakelists.txt文件中加一行gensrv()命令。

在后面的章节中,我们将会学习如何创建服务。

2.2 理解ros计算图级

ros会创建一个连接到所有进程的网络。在系统中的任何节点都可以访问此网络,并通过该网络与其他节点交互,获取其他节点发布的信息,并将自身数据发布到网络上。

在这一层级中最基本的概念包括节点、节点管理器、参数服务器、消息、服务、主题和消息记录包,这些概念都以不同的方式向计算图级提供数据:

节点(node) 节点是主要的计算执行进程。如果你想要有一个可以与其他节点进行交互的进程,那么你需要创建一个节点,并将此节点连接到ros网络。通常情况下,系统包含能够实现不同功能的多个节点。你最好让每一个节点都具有特定的单一的功能,而不是在系统中创建一个包罗万象的大节点。节点需要使用如roscpp或rospy的ros客户端库进行编写。

节点管理器(master) 节点管理器用于节点的名称注册和查找等。它也设置节点间的通信。如果在你的整个ros系统中没有节点管理器,就不会有节点、服务、消息之间的通信。需要注意的是,由于ros本身就是一个分布式网络系统,你可以在某一台计算机上运行节点管理器,在该管理器或其他计算机上运行节点。

参数服务器(parameter server) 参数服务器能够使数据通过关键词存储在一个系统的核心位置。通过使用参数,就能够在运行时配置节点或改变节点的工作任务。

消息(message) 节点通过消息完成彼此的沟通。消息包含一个节点发送到其他节点的信息数据。ros中包含很多种标准类型的消息,同时你也可以基于标准消息开发自定义类型的消息。

主题(topic) 每个消息都必须有一个名称来被ros网络路由。每一条消息都要发布到相应的主题。当一个节点发送数据时,我们就说该节点正在向主题发布消息。节点可以通过订阅某个主题,接收来自其他节点的消息。一个节点可以订阅一个主题,而不需要该节点同时发布该主题。这就保证了消息的发布者和订阅者之间相互解耦,完全无需知晓对方的存在。主题的名称必须是独一无二的,否则在同名主题之间的消息路由就会发生错误。

服务(service) 在发布主题时,正在发送的数据能够以多对多的方式交互。但当你需要从某个节点获得一个请求或应答时,就不能通过主题来实现了。在这种情况下,服务能够允许我们直接与某个节点进行交互。此外,服务必须有唯一的名称。当一个节点提供某个服务时,所有的节点都可以通过使用ros客户端库编写的代码与它通信。

消息记录包(bag) 消息记录包是一种用于保存和回放ros消息数据的文件格式。消息记录包是一种用于存储数据的重要机制。它能够获取并记录各种难以收集的传感器数据。我们可以通过消息记录包反复获取实验数据,进行必要的开发和算法测试。在使用复杂机器人进行实验工作时,需要经常使用消息记录包。

在下图中你可以看到计算图级的图形化表示(节点状态图)。它表示了真实机器人在真实条件下系统的工作状态。在图中,你可以看到节点和主题,以及哪些节点订阅哪些主题等。此节点状态图中并没有消息、消息记录包、参数服务器和服务。这些内容需要使用其他工具进行图形化展示。用于创建该图表的工具是rqt_graph,在第3章中将学习到更多相关知识。这些概念在ros-comm库中实现。

2.2.1 节点与nodelet

节点都是各自独立的可执行文件,能够通过主题、服务或参数服务器与其他进程(节点)通信。ros通过使用节点将代码和功能解耦,提高了系统容错能力和可维护性,使系统简化。

ros有另一种类型的节点,称为nodelet。这类特殊节点可以在单个进程中运行多个节点,其中每个nodelet为一个线程(轻量级进程)。这样,可以在不使用ros网络的情况下与其他节点通信,节点通信效率更高,并避免网络拥塞。nodelet对于摄像头和3d传感器这类数据传输量非常大的设备特别有用。

节点在系统中必须有唯一的名称。节点使用特定名称与其他节点进行通信而不产生歧义。节点可以使用不同的库进行编写,如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节点的一个强大功能是可以在启动该节点时更改参数。此功能使我们能够改变节点名称、主题名称和参数名称。我们无需重新编译代码就能重新配置节点,这样就可以在不同的场景中使用该节点。

一个改变主题名称的例子如下所示:

此命令将主题名称从topic1改为/level1/topic1。相信你现在还不甚明了,但在后面的章节中你会发现它的实用性。

更改节点中的参数和更改主题名称很类似。只需要在参数名称前添加一个下划线,例如:

这样参数(param)就设置为浮点数9.0。

请记住,不能使用系统保留的关键字名称,包括:

_name 为节点名称保留的一个特殊关键字。

_log 为记录节点日志存储地址保留的一个关键字。

_ip和_hostname 表示ros_ip和ros_hostname的关键字。

_master 表示ros_master_uri的关键字。

_ns 表示ros_namespace的关键字。

2.2.2 主题

主题是节点间用来传输数据的总线。通过主题进行消息路由不需要节点之间直接连接。这就意味着发布者和订阅者之间不需要知道彼此是否存在。同一个主题也可以有很多个订阅者。一个主题可以有多个订阅者也可以有多个发布者,但是你需要注意用不同的节点发布同样的主题,否则会产生冲突。

每个主题都是强类型的,发布到主题上的消息必须与主题的ros消息类型相匹配,并且节点只能接收类型匹配的消息。节点要想订阅主题,就必须具有相同的消息类型。

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 输出服务类型。

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 用来录制、播放和执行其他操作。

rqt_bag 用于可视化图形环境中的数据。

rostopic 帮助我们看到节点发送的主题。

2.2.6 节点管理器

ros节点管理器向ros系统中其他节点提供命名和注册服务。它像服务一样跟踪主题的发布者和订阅者。节点管理器的作用是使ros节点之间能够相互查找。一旦这些节点找到了彼此,就能建立点对点的通信。你可以看到以图例显示的ros执行步骤,包括广播一个主题,订阅一个主题,发布一个消息,如下图所示:

节点管理器还提供了参数服务器。节点管理器通常使用roscore命令运行,它会加载ros节点管理器及其他ros核心组件。

2.2.7 参数服务器

参数服务器是可通过网络访问的共享的多变量字典。节点使用此服务器来存储和检索运行时的参数。

参数服务器使用xmlrpc实现并在ros节点管理器下运行,这意味着它的api可以通过通用的xmlrpc库进行访问。xmlrpc是一个使用xml编码并以http作为传输机制的远程调用(remote procedure call,rpc)协议。

参数服务器使用xmlrpc数据类型为参数赋值,包括以下类型:

32位整数(32-bit integer)

布尔值(boolean)

字符串(string)

双精度浮点(double)

iso 8601日期(iso8601 date)

列表(list)

基于64位编码的二进制数据(base64-encoded binary data)

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软件安装更加容易,而且能够通过一个软件集合维持一致的版本。

软件库(repository) ros依赖于共享开源代码与软件库的网站或主机服务,在这里不同的机构能够发布和分享各自的机器人软件与程序。

ros维基(ros wiki) ros wiki是用于记录有关ros系统信息的主要论坛。任何人都可以注册账户、贡献自己的文件、提供更正或更新、编写教程以及其他行为。

bug提交系统(bug ticket system)如果你发现问题或者想提出一个新功能,ros提供这个资源去做这些。

邮件列表(mailing list) ros用户邮件列表是关于ros的主要交流渠道,能够像论坛一样交流从ros软件更新到ros软件使用中的各种疑问或信息。

ros问答(ros answer)用户可以使用这个资源去提问题。

博客(blog)你可以看到定期更新、照片和新闻,网址是http://www.ros.org/news。

2.4 ros系统试用练习

现在是时候对之前学习的内容进行一些练习了。在下面的几小节中,你将看到练习包的创建,使用节点、参数服务器以及通过turtlesim移动仿真机器人。

2.4.1 ros文件系统导览

我们通过命令行工具来浏览一下ros的文件系统。我们将要解释最常用的部分。

为了获得功能包和功能包集的信息,我们将使用rospack、rosstack、roscd和rosls命令。

我们使用rospack和rosstack来获取有关功能包、功能包集、路径和依赖性等信息。例如,如果你想要找turtlesim包的路径,可以使用以下命令:

你将获得以下信息:

同样,如果你想要找到你已经在系统中安装过的某个综合功能包,示例如下:

你将获得到ros-comm综合功能包的路径,如下:

想要获得功能包或功能包集下面的文件列表,那么需要使用:

之前命令的输出如下所示:

如果你想进入某个文件夹,可以使用roscd命令:

你将获得以下新路径:

2.4.2 创建工作空间

在开始具体工作之前,首先创建工作空间。在这个工作空间中,我们将会完成本书中使用的所有代码。

若要查看ros正在使用的工作空间,请使用下面的命令:

你将会看到如下类似信息:

我们将要创建的文件夹是在~/dev/catkin_ws/src/中。若要新建此文件夹,使用以下命令:

当我们创建工作空间文件夹后,里面并没有功能包,只有cmakelist.txt。下一步是编译工作空间,使用下面命令:

现在,如果你输入ls命令,可以看到上面命令创建的新文件夹,分别是build和devel文件夹。

完成配置,使用下面命令:

这一步只是重新加载了setup.bash文件。如果你关闭并打开一个新的终端,也将得到同样的效果。你应该已经在你的~/.bashrc文件中加入了该命令行,因为我们在第1章用过。如果没有,你可以使用下面命令添加它:

2.4.3 创建ros功能包和综合功能包

就像之前所说,你也可以手动创建功能包。但是为了避免那些繁琐的工作,最好使用catkin_create_pkg命令行工具。

使用以下命令在之前建立的工作空间创建新的功能包:

此命令的格式包括功能包的名称和依赖项。在这个示例中,依赖项包括std_msgs和roscpp。如以下命令行所示:

这些依赖项包括:

std_msgs 包含了常见消息类型,表示基本数据类型和其他基本的消息构造,如多维数组。

roscpp 使用c++实现ros的各种功能。它提供了一个客户端库,让c++程序员能够调用这些接口快速完成与ros的主题、服务和参数相关的开发工作。

如果所有步骤都正确执行,结果如下图所示:

正如我们之前看到的,你可以使用rospack、roscd和rosls命令来获取新的功能包信息。下面所示是独立使用的:

rospack profile 此命令用于通知新添加的内容

rospack find chapter2_tutorials 此命令用于查找路径。

rospack depends chapter2_tutorials 此命令用于查看依赖关系。

rosls chapter2_tutorials 此命令用于查看内容。

roscd chapter2_tutorials 此命令会更改实际路径。

2.4.4 编译ros功能包

一旦你创建了一个功能包,并且编写了一些代码,就需要编译功能包了。当你编译功能包的时候,主要是代码的编译过程。

为了编译功能包,可以使用catkin_make工具:

在几秒之后,你会看到:

如果没有看到错误提示信息,说明功能包编译成功。

记住你必须在工作空间文件夹运行catkin_make命令。如果你在其他文件夹这样做,命令无法执行,下面是一个例子:

当你在chapter2_tutorials文件夹试图用catkin_make编译功能包,你会看到如下错误:

当你在catkin_ws文件夹执行catkin_make命令,则会编译成功。

2.4.5 使用ros节点

正如我们在2.2.1节中解释的,节点都是可执行程序,这些可执行文件位于开发空间中。要学习和了解有关节点的知识,我们要使用一个名为turtlesim的功能包进行练习。

如果你进行了ros系统的完整安装,那么你已经有了turtlesim功能包。如果还没有,请使用以下命令安装:

在开始之前,必须使用如下命令启动roscore:

为了获得节点信息,可以使用rosnode工具。为了查看命令接受哪些参数,可以输入以下命令:

你会获得一个可接受参数的清单,如下图所示:

如果你想获得关于这些参数更详细的解释,请使用以下命令:

现在roscore正在运行,我们想要获取正在运行节点的相关信息:

你会看到运行的节点仅有/rosout。这是正常的,因为这个节点总是随着roscore的运行而运行。

通过使用参数我们可以获得此节点的所有信息。也可以使用下列命令获得更详细的

信息:

现在我们要用rosrun命令启动一个新的节点,如下所示:

我们看到出现了一个新的窗口,窗口中间有一个小海龟,如右图所示:

如果我们再去查看节点列表,会看到出现了一个新的节点,叫做/turtlesim。你可以通过使用rosnode info namenode命令查看节点信息。可以看到很多能用于程序调试的信息:

上一个命令输出如下信息:

在以上信息中,我们可以看到publications(及相应主题)、subscriptions(及相应主题)、该节点具有的services(srv)及它们各自唯一的名称。

接下来介绍如何使用主题和服务与该节点进行交互。

2.4.6 如何使用主题与节点交互

要进行交互并获取主题的信息,可以使用rostopic工具。此工具接受以下参数:

rostopic bw topic 显示主题所使用的带宽。

rostopic echo topic 将消息输出到屏幕。

rostopic find topic 按照类型查找主题。

rostopic hz topic 显示主题的发布频率。

rostopic info topic 输出活动主题的信息。

rostopic list topic 列出活动主题。

rostopic pubs topic 将数据发布到主题。

rostopic type topic 输出主题的类型。

如果想要查看有关这些参数的详细信息,请使用-h,如下所示:

通过使用pub参数,可以发布任何节点都可以订阅的主题。我们只需要用正确的名称将主题发布出去。我们将会在以后做这个测试,现在要使用一个节点,并让节点做如下工作:

通过节点订阅的主题,我们可以使用箭头键移动海龟,如右图所示:

为什么turtle_teleop_key执行时,小海龟会移动呢?

如果你想要看到/teleop_turtle和/turtlesim节点的信息,可以看到在下面的代码中,在第一个节点的发布者(publications)部分有一个主题叫/turtle1/cmd_vel 

[geometry_msgs/twist];在第二个节点的订阅者(subscriptions)部分有/turtle1/cmd_vel [geometry_ msgs/twist]:

这意味着前面的节点发布了一个主题,而后面的节点可以订阅。你可以使用以下命令查看主题清单:

输出如下:

通过使用echo参数,可以查看节点发出的信息。运行以下命令行并使用箭头键查看消息产生时发送了哪些数据:

你会看到类似下面的显示:

你可以使用以下命令行查看由主题发送的消息类型:

你会看到类似如下的显示:

如果你想要看到消息字段,可以使用以下命令:

这些工具非常有用,因为我们可以通过这些工具使用rostopic pub [topic] [msg_type] [args]命令直接发布主题:

你会看到小海龟做曲线运动,如右图所示。

2.4.7 如何使用服务

服务是能够使节点之间相互通信的另一种方法。服务允许节点发送请求和接收响应。

可以使用rosservice工具与服务进行交互。此命令接受的参数如下所示:

rosservice args/service 输出服务参数。

rosservice call/service 根据命令行参数调用服务。

rosservice info /service 输出服务信息。

rosservice list 列出活动服务清单。

rosservice uri/service 输出rosrpc uri服务。

我们要使用以下命令列出在turtlesim节点运行时系统提供的服务。如果你运行了这个命令,却没有任何反应,那么请记住要先运行roscore并启动turtlesim节点:

你会获得以下输出:

如果你想查看某个服务的类型,例如/clear服务,请使用:

你会获得类似下面的输出:

若要调用服务,你需要使用rosservice call [service] [args]命令。所以如果想要调用/clear服务,请使用:

在turtlesim的窗口中,你会看到由小海龟移动产生的线条消失了。

现在我们尝试其他的服务,例如/spawn服务。这项服务将以不同的方向在另一个位置创建另一只小海龟。开始之前,我们要去查看以下类型的消息:

我们会获得以下参数:

前面的命令和下面的命令是相同的。如果你想知道为什么这些命令相同,可以在搜索引擎里搜索piping linux:

你会看到如下类似的结果:

输入下面命令:

通过这些字段,可以知道如何调用服务。我们需要新海龟位置的x和y、方向(theta)和新海龟的名称:

我们会获得右侧的结果:

2.4.8 使用参数服务器

参数服务器用于存储所有节点均可访问的共享数据。ros中用来管理参数服务器的工具称为rosparam。接受的参数如下所示:

rosparam load file 从文件加载参数。

rosparam dump file 将参数保存到一个文件。

rosparam list 列出了所有参数名。

例如,查看被所有节点使用的服务器参数:

我们会获得以下输出:

上面的背景(background)是turtlesim节点的参数。这些参数可以改变窗口的颜色,窗口初始化为蓝色。如果你想要读取某个值,可以使用get参数:

为了设定一个新的值,可以使用set参数:

命令行工具rosparam的另外一个重要特性是dump参数。通过该参数,你可以保存或加载参数服务器的内容。

我们使用rosparam dump [file_name]来保存参数服务器:

使用rosparam load [file_name] [namespace]向参数服务器加载新的数据文件:

2.4.9 创建节点

在本节中,我们要学习如何创建两个节点:一个发布数据,另一个接收这些数据。这是两个节点之间最基本的通信方式,也就是操作数据并使用这些数据来做些工作。

使用以下命令返回chapter2_tutorials/src/文件夹:

创建两个文件并分别命名为example1_a.cpp和example1_b.cpp。example1_a.cpp文件将会发送带有节点名称的数据,example1_b.cpp文件会把这些数据显示在命令行窗口中。将下面的代码复制到example1_a.cpp文件或者从库中下载它:

就以上代码做进一步解释。

要包含的头文件是ros/ros.h、std_msgs/string.h和sstream。其中,ros/ros.h包含了使用ros节点所有必要的文件,而std_msgs/string.h包含了我们要使用的消息类型:

启动该节点并设置其名称,请记住该名称必须是唯一的:

下面是设置节点进程的句柄:

将节点设置成发布者,并将所发布主题和类型的名称告知节点管理器。第一个参数是缓冲区的大小,名为message。如果主题发布数据速度较快,那么将缓冲区设置为1000个消息,如下所示:

在本例中,设置发送数据的频率为10hz:

当收到ctrl + c的按键消息或ros停止当前节点运行时,ros::ok()行会执行停止节点运行的命令:

在这里,我们创建一个消息变量,变量的类型必须符合发送数据的要求:

这样,消息被发布:

如果有一个订阅者出现,ros就会更新并读取所有主题:

按照10hz的频率将程序挂起。

现在我们创建另一个节点。将下面的代码复制到example1_b.cpp文件或者从库中下载它:

这里是一些对上面代码的解释。

首先要包含头文件和主题所使用的消息类型:

每次该节点收到一条消息时都将调用此函数,我们就可以使用或处理数据。在本示例中,我们将收到的数据在命令行窗口中输出:

创建一个订阅者,并从主题获取以message为名称的消息数据。设置缓冲区为1000个消息,处理消息的回调函数为messagecallback:

ros::spin()行是节点开始读取主题和在消息到达时,回调函数messagecallback被调用的循环。当用户按下ctrl + c,节点会退出消息循环,于是循环结束。

2.4.10 编译节点

当使用chapter2_tutorials功能包时,需要自行编辑cmakelists.txt文件。你可以使用你喜欢的编辑器或直接使用rosed工具。这里我们将会在vim编辑器下打开这个文件:

将以下命令行复制到文件的末尾处:

现在我们使用catkin_make工具来编译功能包和全部的节点:

如果在你的电脑上还没有启动ros,需要首先调用:

你可以使用rosnode list命令检查ros是否运行:

然后,在不同的命令行窗口下分别运行两个节点:

如果你检查一下example1_b节点正在运行的命令行窗口,你就会看到以下信息:

我们可以在下图中看到正在发生的消息传递。example1_a节点发布message主题,同时节点example2_b节点订阅了这个主题。

你可以使用rosnode和rostopic命令来调试和查看当前节点的运行状况。尝试使用以下命令:

2.4.11 创建msg和srv文件

在这一节中,我们将会学习如何在节点中创建msg和srv文件。它们是用于说明传输数据的类型和数据值的文件。ros会根据这些文件内容自动地为我们创建所需的代码,以便msg和srv文件能够被节点使用。第一步,我们先学习msg文件。

在上一节使用的示例中,我们已经创建了两个具有标准类型message的节点。现在,我们要学习如何使用ros工具创建自定义消息。

首先,在chapter2_tutorials功能包下创建msg文件夹,并在其中创建一个新的文件chapter2_msg1.msg。在文件中增加以下行:

现在编辑package.xml,从<build_depend>message_generation</build_depend>和<run_depend>message_runtime</run_depend>行删除<!-- -->,然后编辑cmakelist.txt,按下面所示加入message_generation:

找到如下行,取消注释,并加入新消息名称:

现在,用下面命令进行编译:

检查编译是否成功,使用下面rosmsg命令:

如果你在chapter2_msg1.msg文件中看到一样的内容,说明编译正确。

现在创建一个srv文件。在chapter2_tutorials文件夹下创建一个名为srv的文件夹,并新建文件chapter2_srv1.srv,在文件中增加以下行:

为了编译新的msg和srv文件,必须取消在package.xml和cmakelists.txt中的如下行的注释。这些包含消息和服务的配置信息,并告诉ros如何编译。

首先,按下面方式从chapter2_tutorials功能包中打开package.xml文件:

找到下面行并取消注释:

使用下面命令打开cmakelists.txt:

找到下面行,取消注释,并改为正确数据:

为了生成消息,你需要在find_ package部分添加message_generation行:

在add_message_files如下位置添加消息和服务文件的名字:

取消generate_messages部分的注释,使得消息和服务可以顺利生成:

测试编译是否成功,使用如下rossrv命令:

如果你在chapter2_srv1.srv文件中看到相同的内容,说明编译正确。

2.4.12 使用新建的srv和msg文件

首先,我们将会学习如何创建一个服务并且在ros中使用。该服务将会对三个整数求和。我们需要两个节点,一个服务器一个客户端。

在chapter2_tutorials功能包中,新建两个节点并以example2_a.cpp和example2_b.cpp为名称。别忘了要在src文件夹下创建这两个文件。

在第一个文件example2_a.cpp中,添加以下代码:

解释一下这些代码:

这些行包含必要的头文件和我们创建的srv文件:

这个函数会对3个变量求和,并将计算结果发送给其他节点:

在这里,创建服务并在ros中发布广播。

在第2个文件example2_b.cpp中,增加以下代码:

代码解释:

以add_3_ints为名称创建一个服务的客户端。

下面创建srv文件的一个实例,并且加入需要发送的数据值。如果你还记得,这个消息需要3个字段。

这行代码会调用服务并发送数据。如果调用成功,call()函数会返回true;如果没成功,call()函数会返回false。

为了编译节点,在cmakelist.txt文件中增加以下行:

现在执行以下命令:

为了启动节点,需要执行以下命令行:

并且你会看到如下显示:

现在将要用自定义的msg文件来创建节点。这个例子也一样,创建example1_a.cpp和example1_b.cpp文件,同时调用chapter2_msg1.msg。

将下面的代码放在example3_a.cpp文件中:

将下面的代码放在example3_b.cpp文件中:

如果现在运行这两个节点,将会看到如下信息:

2.4.13 启动文件

启动(launch)文件是ros中一个非常有用的功能,可以启动多个节点。在之前的小节中,我们已经学习了创建了节点,并且在不同的命令行窗口执行,想象一下,如果在每一个命令行窗口启动20个节点会是多么恐怖的一件事情!

通过启动文件我们可以在命令行窗口方便地实现以上任务,只需要运行后缀名为.launch的配置文件来启动多个节点。

为了练习这个例子,我们在功能包中创建一个新文件夹:

现在,在chapter2.launch文件中输入下面的代码:

这是个简单的例子,如果需要的话,也可以编写非常复杂的文件。例如,控制一个完整机器人,如pr2或robonaut,包括真实的机器人和在ros中仿真的机器人。

这个文件包括launch启动标签,在标签内部可以看到node节点标签。这个节点标签用于从功能包中启动节点,例如从chapter2_tutorials包中启动example1_a节点。

这个启动文件将执行两个节点,即这章最前的两个例子。如果你还记得,就是节点example1_a发送消息到节点example1_b。你可以通过如下命令启动这个文件:

你可以看到类似下图的显示:

运行的节点在上面的截图中列出,你可以通过下面命令查看运行的节点信息:

可以看到如右图所示的三个节点:

当执行启动文件时,并不需要在roscore命令前启动,roslaunch会启动它。

还记得节点example1_b会在屏幕输出从其他节点收到的消息,现在却看不到了,这是因为example1_b使用了ros_info输出消息。当你在命令行只运行一个节点时,可以看到。但是当你运行启动文件时,则看不到。

现在,如果想看到信息,你可以运行rqt_console应用。在接下来的章节中,会做详细介绍。运行以下命令:

你从下面的截图中可以看到example1_b发送的消息:

在框中,你可以看到节点发送的消息以及来源文件。

2.4.14 动态参数

ros的另一个功能是动态重配置应用。通常情况下,当你正在编写一个新节点,你只能以数据初始化节点内的变量。如果你想从外部节点动态地改变这些值,你可以使用参数服务器、服务或主题。如果你使用一个pid节点来控制一个电动机,则应该使用动态重配置

应用。

在本节中,你将学习如何配置一个包含此功能的基本节点。添加必要的内容到cmakelists.txt和package.xml文件。

为了使用动态重配置,你需要写一个配置文件并保存在你功能包的cfg文件夹中,创建一个文件夹和新文件如下:

在chapter2.cfg文件中添加如下代码:

以上代码初始化ros并导入参数生成器:

以上代码初始化参数生成器,通过它我们可以开始用下面的代码行添加参数:

以上代码加入不同的参数类型并设置默认值、描述、范围等,参数有如下内容:

name 参数的名称

type 参数值的类型

level 一个传递给回调的位掩码

description 一个描述参数

default 节点启动的初始值

min 参数最小值

max 参数最大值

参数的名称必须唯一,参数值必须在最小和最大的范围内:

最后一行生成必要的文件并退出程序。注意.cfg文件是用python写的。本书的实例代码主要使用c++编写,但有时会使用python代码片段。

因为文件将由ros执行,所以需要改变文件的权限,我们将使用chmod a + x使文件可由任何用户执行和运行,如下所示:

打开cmakelist.txt,加入下面代码:

现在,我们要写具有动态重配置支持的新节点。在src文件夹中创建一个新文件如下:

在文件中写入如下代码段:

这里进行代码解释,注意一些重要的行:

这些行包括ros头文件、参数服务器以及我们先前创建的config文件。

回调函数将输出参数的新值。这是参数访问的方式,例如config.int_param。参数的名称必须与example2.cfg配置文件相同:

初始化服务器,忽略chapter2_config配置文件:

现在,我们向服务器发送回调函数。当服务器得到重新配置请求,它会调用回调函数。

一旦我们完成以上讲解的步骤,我们需要在cmakelists.txt文件中添加如下代码:

现在,你必须编译并运行节点和动态重配置界面(dynamic reconfigure gui),如下:

在你执行最后一行命令后,你会看到一个新窗口,通过它你可以动态重配置节点的参数,如下图所示:

每当你通过滑块、文本框等调整参数时,你可以在命令行看到正在运行的节点的这些改变,如下图所示:

通过动态重配置,你可以更高效地开发和测试节点。与硬件一起配合使用这个程序是不错的选择。你将在接下来的章节中学习到更多内容。

2.5 本章小结

本章介绍了ros系统的架构及其工作方式的基本信息。学习了一些基本概念、工具及如何同节点、主题和服务进行交互的示例。一开始,所有这些概念可能看起来有些复杂且不太实用,但在后面的章节中,你会逐渐理解这样的应用。

各位读者最好在继续后续章节的学习之前,对这些概念及示例进行练习,因为在后面的章节里,我们将假定你已经熟悉所有的概念及其用途。

请注意如果想查询某个名词或功能的解释,且无法在这本书中找到相关内容或答案,那么可以通过以下链接访问ros官方资源http://www.ros.org。而且你还可以通过访问ros社区http://answers.ros.org提出自己的问题。

在下一章中,将学习如何使用ros工具调试和可视化数据。这些将帮助你发现软件运行的问题,并且指导你对它的运行进行调整。

第3章

可视化和调试工具

ros附带了大量功能强大的工具,帮助用户和开发人员可视化和调试代码,以便检测并解决软硬件问题。其中包括消息日志系统(类似log4cxx)、诊断消息、可视化以及检测工具。这些工具展示了哪些节点正在运行和它们是如何连接的。

本章我们还会展示如何用gdb调试器调试ros节点,介绍用于日志记录的api,以及如何设置日志记录级别。接着,我们将解释如何用ros工具集检测哪些进程正在运行以及它们之间通信的内容。例如,在下图所示的系统可视化图中可以看到正在运行的节点以及用连线表示的数据流。这个工具是rqt_graph,这里显示的是reem机器人在gazebo仿真中运行的节点和主题。

从图中我们可以看到多个关于机械臂、肢体和头部的控制器、moveit!的move_group节点、抓取和放置操作服务以及play_motion节点的预存储动作。其他节点发布joint_states、大量机器人控制器以及移动底盘的手柄控制等信息。

同样,本章会介绍标量数据的时序绘图工具,视频流数据的可视化图,以及用于不同类型数据的3d可视化工具rviz(或rqt_rviz)等,如下图所示:

可以使用下面命令运行上图的reem机器人仿真:

注意,在开始安装此仿真前,请认真阅读下面网页的使用说明:http://wiki.ros.org/robots/reem。

在本节中,将介绍以下内容:

如何在ros中调试和优化代码。

介绍在代码中添加消息日志并设置不同的级别、命名、特定条件和流选项。这里我们将解释rqt_logger_level和rqt_console接口,它们可以分别设置节点错误级别和消息可视化。

介绍如何通过列表来检测ros系统状态,包括运行的节点、主题、服务和它们之间传递信息的行为以及ros节点管理器中声明的参数等。我们将介绍以有向图形式显示主题和节点的rqt_graph,和可以用来修改动态参数的rqt_reconfigure。

讲解如何使用runtime_monitor和robot_monitor接口可视化诊断信息。

讲解如何使用rqt_plot绘制特定消息的标量数据。对于非标量数据,我们将讲解ros中的其他rqt工具,例如用rqt_image_view显示图像以及用rqt_rviz以3d形式显示多维数据。还包括如何可视化标记和交互式标记。

介绍坐标系以及如何将它们集成到ros消息和可视化工具之中。以及如何使用rqt_tf_tree来可视化转换坐标系树transform frame(tf)。

讲解如何保存主题发送的消息,以及如何重播它们用于仿真或测试目的,并介绍rqt_bag接口。

最后,将介绍rqt_gui接口,以及如何在一个gui窗口中排列显示它们。

大部分rqt工具可以在终端输入名称运行,例如rqt_console,但有时不行,必须使用rosrun rqt_reconfigure rqt_reconfigure,注意名字虽然是重复的,但其实前一个是功能包的名称,后一个是节点名称。

3.1 调试ros节点

ros节点可以像正常程序一样调试。调试程序在系统中运行时有一个进程号(pid)。你可以用任何标准工具(如gdb)进行调试。同样可以用valgrind检查内存泄漏,或者用callgrind分析算法性能。请记住使用下面的命令运行一个节点:

很遗憾,你不能通过下面的方式启动命令:

在接下来的部分中,我们将解释如何调用这些工具调试ros节点,以及如何在代码中添加日志消息,让问题诊断更简单。这样即使没有二进制调试文件,也可以诊断基本问题。然后,我们将讨论ros自检工具,测试节点间损坏的连接。因此,这章的概述是自下而上,实际的问题诊断方式是自上向下。

3.1.1 使用gdb调试器调试ros节点

为了使用gdb调试器调试一个c/c++节点,唯一要知道的是可执行节点的路径。在ros hydro和catkin功能包中,节点的可执行文件在工作空间的devel/lib/<package>文件下。例如,为了在gdb中运行chapter3_tutorials功能包中的example1节点,我们需要按如下步骤进行,首先到工作空间文件夹下(~/dev/catkin_ws):

如果已经运行过catkin_make install,你也使用下面命令导航到install/lib/chapter3_tutorials文件夹下:

现在可以使用gdb命令运行节点:

记住,必须在启动节点之前保证roscore运行,因为节点需要管理器/服务器运行。

一旦roscore在运行,你就可以通过点击r键和enter键从gdb中启动节点。也可以用l键列出相关源代码,以及设置断点或使用任何gdb附带的功能。如果一切工作正常,在运行节点后就能在gdb终端看到下面的输出:

3.1.2 ros节点启动时调用gdb调试器

我们需要一个启动文件(launch)去启动节点,如下:

想要在节点启动时调用gdb调试器,需要添加launch-prefix="xterm -e gdb --args",如下:

类似地,也可以添加output="screen",使节点在终端显示。这个启动前缀会创建一个调用gdb节点的新xterm终端。依据需要设置断点,按c键或r键启动节点并调试。这在节点崩溃时,可以得到回溯(backtrace,bt)。

3.1.3 ros节点启动时调用valgrind分析节点

此外,我们可以使用相同的属性把节点附加到诊断工具上。例如,可以启动valgrind来检测我们程序的内存泄漏情况,并执行性能分析。你可以访问http://valgrind.org获取详细信息。与调用gdb的方式相反,现在我们无需重新启动xterm,只需如下设置:

3.1.4 设置ros节点core文件转储

虽然ros节点实际上就是一般的可执行文件,但在设置gdb的core文件转储(core dump)时仍有一些棘手的问题需要注意。首先要取消core文件大小限制,当前值可以通过ulimit -a查看。请注意这适用于任何可执行文件,不只是ros节点:

然后,为了能够创建core文件转储,必须将core文件名设置为默认使用的进程pid,否则无法创建,因为在$ros_home已有一个core目录会防止core文件转储。因此,为了创建core文件转存的名称和路径为$ros_home/core.pid,必须运行如下命令:

3.2 日志信息

通过信息记录显示程序的运行状态是好的习惯,但需要确定这样做不会影响软件的运行效率和输出的清晰度。在ros中有满足以上要求并且内置于log4cxx(众所周知的log4j记录库的一个端口)之上的api。简单地说,我们有不同层级的调试信息输出,每条信息都有自己的名称,并根据相应条件输出消息。如果它们被当前冗长级别掩盖(甚至在编译时),它们对性能没有影响。它们与ros其他工具完全集成来可视化或过滤来自所有运行节点的

消息。

3.2.1 输出日志信息

ros自带了大量的能够输出日志信息的函数和宏。它提供了如信息(或日志)级别、条件触发消息和stl的流接口等诸多方式。从简单的开始,用c++代码输出一个消息信息:

为了获取日志记录的函数和宏,这个头文件足够了:

这包括了以下头文件:

前面的消息处理程序运行的结果如下所示:

所有输出的信息都附带其级别和当前时间戳(因为这个原因你的输出可能有所不同),这两个值放在实际信息之前的方括号中。时间戳以公历时间计时,代表着自1970年1月1日以来的秒和纳秒计数。于是我们在新一行输出了信息。

此函数允许以和c语言中的printf函数相同的方式增加参数。例如,可以按照下面代码输出变量val对应的浮点数值:

此外,c++stl流被*_stream函数支持。因此,前面的指令相当于使用流:

请注意,我们没有指定任何流,因为api负责这些,通过重定向到cout/cerr、一个文件或两者。

3.2.2 设置调试信息级别

ros有五个日志记录标准级别,按照顺序排列分别是:

debug调试

info信息

warn警告

error错误

fatal致命

这些名称是输出信息的函数的一部分,它们遵循以下语法:

每一种信息都会以特定的颜色在屏幕上输出。这些颜色分别是:

每个消息级别用于不同的目的。在这里,我们建议:

debug:只有调试时有用

info:说明重要步骤或节点在执行操作

warn:提醒你一些错误、缺失或者不正常

error:提示错误,尽管节点仍然可以运行

fatal:通常防止节点继续运行

3.2.3 为特定节点配置调试信息级别

默认情况下,系统会显示info及更高级别的调试信息,并使用ros默认级别来过滤特定节点输出的信息。要实现这一功能有很多方法。其中有些是在编译时设定,而其他的可以在执行前使用配置文件进行更改。另外,也可以动态地改变级别。下面将介绍使用rqt_console和rqt_logger_level来实现这一功能。

在编译源代码时可以设置日志级别,但不推荐这么做,这需要我们修改源代码定制日志级别,如果你想这样做,请参考《ros机器人程序设计》(第1版)。

然而,在一些时候,我们需要删除低于设定级别的日志。这时,我们希望看到那些消息后,将它们删除而不是禁用。为此需要将rosconsole_min_severity设置为期望的最低严重级别或者避免任何消息(甚至是fatal)。宏如下:

rosconsole_min_severity宏在<ros/console.h>中默认定义为debug级别。于是可将它作为一个编译参数(使用-d)传递或把它放在头文件前。例如,若想仅显示error或更高级别的调试信息,在源代码中加入下面代码:

或者,在cmakelists.txt中使用下面代码设置包中所有节点的宏:

除此之外,还有一个更灵活的方法就是在配置文件中设置最低日志级别。用文件创建一个名为的config文件夹和名为chapter3_tutorials.config的文件,文件内容如下(从它设置为debug级别开始编辑给定文件):

然后,我们设置rosconsole_config_file环境变量指向我们的文件。我们可以使用一个启动(launch)文件来替代配置环境变量,但这样做会直接运行节点。因此,我们可以通过env(环境变量)字段扩展launch文件,如下所示:

如上所述,环境变量会找到之前显示的配置文件,其中包含每个已命名日志的日志级别说明。在这个例子中是功能包名称。

3.2.4 信息命名

默认情况,ros分配一些名字给节点记录器。目前讨论过的消息在节点名字后命名。对于复杂的节点,我们可以为一个给定的模块或功能的消息提供一个名字。ros_<level>[?_stream]_named函数,如下面代码所示(以example2节点为例):

通过命名的消息,我们可以使用配置文件为每个命名的消息设置不同的初始日志级别,之后可以单独修改它们。在命名规范上我们必须使用消息的名称作为功能包的子包。例如可以设定named_msg的信息,如下列代码所示:

3.2.5 按条件显示信息与过滤信息

按条件显示(conditional)信息是指仅当满足给定的条件时才输出的信息。我们需要使用ros_<level>[_stream]_cond[_named]函数来调用它们,请注意它们也可以是命名的信息。下面是以example2节点为例的代码:

过滤(filtered)信息在本质上与按条件显示信息类似,但它允许我们指定一个用户自定义的过滤器。这个自定义过滤器继承自ros::console::filterbase结构体。我们必须将过滤器作为指针传递给以ros_<level>[_stream]_filter [_named]为格式的宏的第一个参数。下例来自于example2节点:

3.2.6 显示信息的方式——单次、可调、组合

你可以控制信息的显示次数。通过使用ros_<level>[_stream]_once[_named]可以让信息只输出一次。

这段代码也是来自example2节点,只会显示信息1次。

然而,有时候在迭代中以一定频率显示信息更好。这就需要可调信息。它们和前面单次显示的消息格式是一样的,但是需要将函数名中的once替换成throttle,函数会将period作为第一个参数,也就是说,它将会间隔每个period秒后输出:

最后要说明的是,无论对于哪个级别的信息,命名信息、条件显示信息、单次/可调信息等都能够组合起来使用。

动态加载节点(nodelet)对于日志信息也提供了一定的支持。因为它们有自己的命名空间,而且有各自唯一的名称,这样才能够让一个动态加载节点的提示信息与其他节点的提示信息区别开。简单地说,前面提到的所有宏对于动态加载节点都是可用的,只是宏的名称需要将ros_*开头替换成nodelet_*。这些宏将只能够在动态加载节点内部编译。同时,它们会使用动态加载节点运行时的名称设置一个命名的日志记录器。这样你就能够区分同一个动态加载节点管理器下运行的两个相同类型动态加载节点的输出。动态加载节点的另外一个优势是它们能够帮助你将某个动态加载节点转换到调试级别,而不是把整个特定类型的动态加载节点都转换过去。

3.2.7 使用rqt_console和rqt_logger_level在运行时修改调试级别

ros中提供了一系列工具去管理日志信息。在ros hydro中,我们有两个独立的gui:rqt_logger_level设置节点或者指定日志记录器的日志记录级别;rqt_console对日志信息进行可视化、过滤和分析。

使用代码示例example3测试这个功能。运行roscore和rqt_console来看日志信息:

将看到如下窗口:

运行下面节点:

一旦example3节点开始运行,就会看到如下图所示的信息。注意roscore必须已经启动,也必须点击在rqt_console窗口上的记录(recording)按钮。

在rqt_console下,消息按类别进行收集和显示,如通过时间戳、信息类型、严重级别以及产生这些信息的节点等。你可以通过点击resize columns自动调整格式。双击一个消息,你可以看到所有信息,包括生成它的那行代码,如下图所示:

交互窗口可以实现暂停、保存、读取和载入保存的日志信息。我们可以清理信息列表并过滤它们。在ros hydro下,除了过滤掉的信息外,信息依赖于过滤条件的特定接口,例如,节点可以通过一条规则进行过滤,将我们选择的节点排除。另外,通过相同的方式,我们可以设置高亮显示过滤器。如下图所示:

举一个例子,上图所示信息想过滤除fatal和error外其他级别的信息。

为了设置日志记录器的严重级别,必须运行以下命令:

在这里,我们可以选择节点,然后指定日志记录器,最后是严重级别。一旦我们修改它,就会收到带有严重级别的新消息,低于预定严重级别的消息不会在rqt_console中出现:

在下图中,我们将命名为ros.chapter3_tutorials.named_msg的example3节点的日志记录器的严重级别设置为最低(debug)。记住,所命名的日志记录器是通过*_named日志函数创建的:

如上图所示,在默认情况下每个节点都有多个内部日志记录器,与ros通信api相关,一般不要降低它们的严重级别。

3.3 检测系统状态

当系统运行时,可能有数个节点和数十个主题在节点中发布消息。同时,有些节点可能也会提供行为或服务。对于大型系统来说,通过提供一些工具让我们看到系统在给定时间的运行状态是非常重要的。ros对此提供了一些基本但非常强大的工具,包括从cli到gui应用。

3.3.1 检测节点、主题、服务和参数

坦白地讲,我们应该先回顾一下学习过的基本内容。如何获得正在运行的节点、主题、给定时间可用服务的清单,如下表所示。

获取所有列表 命令

运行的节点 rosnode list

所有节点运行的主题 rostopic list

所有节点运行的服务 rosservice list

服务器中的参数 rosparam list

我们建议你回顾第2章,熟悉如何使用这些命令,同时看一下如何使用rosmsg show获取特定主题和字段发出的消息类型。

所有这些命令可以结合bash命令,如grep,寻找所需的节点、主题、服务或参数。例如,启动目标主题可以使用以下命令:

bash命令grep在文件列表或标准输出中查找文本或模式,如本例所示。

此外,ros提供几个gui检测主题和服务。首先,在一个类似于进程表(top)窗口rqt_top中显示运行的节点,可以快速查看正在使用的所有节点和资源。以reem导航栈运行仿真为例,如下图所示:

另一方面,rqt_topic显示主题调试信息,包括发布者、接收者、发布速率和发布的消息。可以查看消息字段的主题并选择你想要订阅的主题,分析带宽和速率(hz)以及查看最新消息发布。注意锁定的主题通常不会持续发布,所以不会看到任何关于它们的信息。如下图

所示。

同样,rqt_publisher允许我们在一个接口管理rostopic pub命令的多个实例。它还支持python发布消息和固定值的表达式。在下图中,我们看到发布了两个示例主题(我们将在两个不同的终端看到使用rostopic echo <topic>发布消息)。

另一种更灵活的gui是rqt_ez_publisher。对ros hydro而言,必须使用下面的代码从一个空的工作空间手动安装:

对ros indigo而言,它将会作为一个debian功能包,所以只需要运行下面命令:

然后,运行:

在example5节点运行时,你可以发布将被该节点读取的消息。在下图中,我们将选择accel和temp主题(删除accel/y和accel/z字段):

注意,当启用重复(repeat)后,消息会不断发布。否则,gui只在你改变值时发布消息。

rqt_service_caller和rosservice call命令的多个实例一样。在下图中,我们将调用/move_base/navfnros/make_plan服务,我们必须为空服务设置请求。这对于来自/amcl节点的

/global_localization服务而言是不需要的。点击call按钮之后,我们将获得响应消息。对于本例,我们运行导航栈的reem仿真,如下图所示:

3.3.2 使用rqt_graph在线检测节点状态图

可以用有向图来显示ros会话的当前状态,其中运行的节点是图中的节点,边为发布者-订阅者在这些节点与主题间的连接。此图形由rqt_graph动态绘制。

为了说明如何使用rqt_graph检测节点、主题和服务,使用以下launch文件同时运行example4和example5节点:

example4节点在两个不同的主题中发布并调用了一个服务。同时,example5节点订阅了这些主题,并提供了一个服务器来响应查询请求并提供反馈数据。一旦这些节点开始运行,我们就能够查询到如下图所示的节点拓扑图:

在上图中,我们看到节点通过主题相连。由于选择hide debug,我们不会看到ros服务器节点rosout以及rosout主题发布到诊断聚合器(diagnostic aggregator)上的日志信息,如我们之前做的那样。取消这个选项就可以显示该节点和主题的调试信息,以便显示ros服务器和rqt_graph节点本身(如下图所示)。这对于调试大型系统非常有用,因为图可以使其简化。同时,ros hydro中相同命名空间的节点被分组,例如图像管道的节点:

当系统出现问题时,会一直(而不只是当我们移动鼠标掠过它们时)以红色显示。在这种情况下,选择all topics查看没有连接的主题非常有用,这通常显示由于主题名称拼写错误导致节点之间连接的中断。

当节点在不同的机器上运行时,rqt_graph会显示其强大的高级调试功能,包括节点能否从各自的机器看到对方、列举连接等。

最后,我们可以启用统计查看在主题边上显示的信息速率、带宽,以及写入速率和行速率,如下一个图所示。我们必须在运行rqt_graph之前设置参数来使信息有效:

不幸的是,这些参数ros hydro目前不可用。它会在ros indigo中(下一个发行版)出现,也有可能移植回hydro中。

3.4 设置动态参数

如果一个节点配置了一个动态重配置参数服务器,在工作中就可以使用rqt_reconfigure进行修改。运行下面的代码启动一个带有几个参数动态重配置的服务器(见功能包cfg文件夹中的cfg文件):

使用下面命令启动动态重配置服务器,打开gui:

在左边的列表中选择example6服务器,然后就能看到它的参数,并可以直接修改。运行源代码中一个回调方法的代码会对值的有效性进行检查。也就是当回调方法执行时,在示例中这些参数的更改将立即生效。所述内容如下图所示:

动态参数原本是为驱动程序设计的,这使参数修改变得简单。因此动态参数已经在一些驱动上得以应用。尽管如此,它们也可以用于任何其他节点。驱动程序实现的示例,如hokuyo激光测距仪的hokuyo_node驱动或firewire camera1394驱动。firewire摄像头采用通用的驱动程序以支持传感器一些配置参数的改变,如帧速率、快门速度和亮度等。可以运行下面的命令启动firewire ros摄像头驱动(ieee 1394,a和b):

当摄像头运行时,我们可以用rqt_reconfigure配置参数,将会看到类似下图的界面:

请注意,我们将在第5章介绍如何使用摄像头,我们还将从开发人员的角度解释这些参数。

3.5 当出现异常状况时使用roswtf

ros还提供了另外一些工具来检测给定功能包中所有组件的潜在问题。使用roscd移动到你想要分析的功能包路径下,然后运行roswtf。对于chapter3_tutorials,我们可以获得以下输出。请注意,如果你运行了一些代码,就可以用ros图进行分析。运行roslaunch chapter3_tutorials example6.launch命令,输出如图所示。

通常情况下,我们希望获得的结果没有任何错误和警告,但是很多错误和警告在系统正常运行时是没有影响的。在上图中,roswtf没有检测到任何错误,只有一个关于pip的警告,这有时可能是由系统安装的python代码产生的问题。请注意,roswtf的作用是检测信号的潜在问题,然后就像上面示例一样,我们再来检查这些提示是否有意义。

另一个有用的工具是catkin_lint,可以帮助catkin诊断错误,通常在cmakelists.txt和package.xml文件中。在chapter3_tutorials中,得到如下输出:

使用参数-w2,就看到通常会被忽略的警告,如下图所示:

3.6 可视化节点诊断

ros节点可以使用diagnostics(诊断)主题提供诊断信息,并为此提供了一个api用于以标准方式发布诊断信息。信息遵循diagnostic_msgs/diagnositcstatus的消息类型,它允许我们指定一个级别(警告、错误)、名称、消息和硬件id以及diagnostic_msgs /keyvalue列表,对应键(key)和值(value)字符串。

有趣的部分是收集诊断信息并将其可视化的工具。在最基本的层面上,rqt_runtime_monitor通过diagnostics主题直接发布可视化信息。运行example7节点,它通过诊断主题发布信息并可以通过可视化工具查看诊断信息:

前面的命令输出如下所示:

当系统很大时,我们可以使用diagnostic_aggregator汇总诊断信息。在diagnostics_agg里处理和归类diagnostics主题的消息并重新发布。这些汇总诊断消息通过rqt_robot_monitor实现可视化。诊断汇总器通过一个配置文件进行配置,例如下面的这一个(参看chapter3_tutorials中的config/diagnostic_aggregator.yaml文件),并使用analyzergroup定义不同的analyzers(分析器):

launch文件已经在之前的代码中使用,并以之前的配置运行诊断节点aggregator_node,如下:

现在,我们可以比较rqt_runtime_monitor与rqt_robot_monitor的可视化,如下图所示。

3.7 绘制标量数据图

我们可以使用ros中现有的一些通用工具轻松地绘制标量数据图。当然非标量数据也可以绘制,但是要分别在不同的标量域里进行。我们之所以在此仅讨论标量数据,是因为对于大多数非标量数据,有专门的工具能够更好地对其进行表示,我们会在后面进行部分介绍,例如图形、位姿、方向和角度等。

用rqt_plot画出时间趋势曲线

在ros系统中,标量数据可以根据消息中提供的时间戳作为时间序列绘制。然后,我们就能够在y轴上使用rqt_plot工具绘制标量数据。rqt_plot工具有一套功能强大的参数语法,允许我们在结构化消息中指定多个字段(当然使用了相当简明的方式),也可以在gui中手动添加或删除主题和字段。

为了能够实际展示rqt_plot工具,我们使用example4节点,它在两个不同的主题中分别发布一个标量和一个矢量(非标量),这两个主题分别是温度(temp)和加速度(accel)。在这些消息中的值是随机生成的,所以它们没有实际意义,仅用于示范曲线绘制。那么首先以下面的命令运行节点:

为了能够画出消息,我们必须知道具体的格式;如果你不知道具体格式则使用rosmg show?<msg type>获取。对于标量数据,我们通常使用data作为字段名来表示实际的值。因此,对于temp主题,数据格式为int32,运行下面命令:

只要节点正常运行,我们就能看到曲线图随输入消息一直变化。如下图显示。

在示例节点提供的accel主题里,我们看到一个vector3的消息(你可以通过rostopic type/accel来查看),我们可以在一个plot图中分别绘制三个字段的曲线。vector3消息包含三个字段x、y和z。我们可以使用逗号(,)来区分字段或者像下面一样使用更加简洁的方式:

绘制的曲线图如下:

我们还可以将每个字段分开绘制。由于rqt_plot不直接支持这个功能,因此我们需要使用rqt_gui将三个图表手动分开,如下图所示:

rqt_plot的gui支持三种绘图前端。在ros hydro之前,只有matplotlib支持。现在,我们可以使用更快的qt前端,同时它支持更多的时间序列。可以点击配置(configuration)按钮选择(如右图所示):

3.8 图像可视化

在ros系统中,我们可以创建一个节点,在节点中展示来自即插即用摄像头的图像。这是一个复杂数据主题的例子,这些数据可以使用特殊工具更好地可视化或分析。你只需要一个摄像头来完成这些,例如你笔记本上的webcam。在example8节点中,通过调用opencv库实现一段基本的摄像头捕捉程序,然后在ros中将采集到的cv::mat图像转换到ros图像,这样就可以在主题中发布了。这个节点会在/camera主题里发布图像帧。

我们仅会使用launch文件运行节点并进行图像捕捉和发布工作。节点中的代码对于读者来说可能很陌生,但是在下面的章节中,我们将会介绍如何在ros中使用摄像头和图像,到时候再回来看这些代码,你就会完全理解节点的工作原理和每行代码的含义:

一旦节点运行起来,我们就能够列出主题列表(rostopic list),并查看是否包含/camera 主题。查看是否正确捕捉到图像有一个简单直接的方法,使用rostopic hz /camera语句查看在主题中收到的图像更新频率是多少。频率通常是30hz,如下图所示:

显示单一图片

想要查看一张图像,我们不能直接使用rostopic echo /camera命令,因为这会使用文本格式输出图片的信息,数据量会非常巨大,不可能进行任何有效的分析。因此,我们会调用下面的命令:

这里使用了image_view节点,在窗口中展示了给定主题(使用image参数)的图像,如下图所示。这样我们就能简单直接地显示在主题内发布的每一幅图像或帧,即使数据来自网络也可以实现。你可以通过在窗口中点击右边的按钮将当前帧保存在硬盘里,通常会存在home目录下或者~/.ros目录下。

ros hydro还有rqt_image_view,支持在一个窗口查看多个图像,但不允许点击右边按钮保存图像。我们可以在gui上手动选择图像主题或使用image_view:

前面命令结果如右图所示:

ros提供了一个基于opencv校准api的摄像头校准界面。我们将在第5章介绍如何使用摄像头,包括单目和双目摄像头以及ros图像管道(image_proc和stereo_image_proc)相关内容,这些能修正摄像头图像失真、计算双目摄像头深度差异,并得到一个点云。

3.9 3d可视化

正如我们在前面章节中所见,有很多设备(例如双目摄像头、3d激光和kinect传感器等)能够提供3d数据。它们通常使用点云格式(组织好或未组织的)。基于上述原因,能够使用工具实现3d数据可视化就非常有用了。本节我们将介绍ros系统中的rviz或rqt_rviz工具。它集成了能够完成3d数据处理的opengl接口,能够将传感器数据在模型化世界(world)中展示,过程是先使用传感器坐标系读取测量值,再将这些读数按照之间的相对位置在正确的位置绘制。

3.9.1 使用rqt_rviz在3d世界中实现数据可视化

在roscore运行时,启动rqt_rviz(请注意rviz在ros hydro中依然有效):

我们将会看到如下图所示的图形化工作界面:

在左边有一个displays面板,在面板的中间有一个包含了模拟环境下不同参数项的树形列表。在示例中,已经加载了部分参数项。实例中的配置和布局都存储在了config/example9.rviz文件中,可以通过点击file | open config加载。

在displays区域之下有一个add按钮,允许通过主题或类型添加更多的参数项。同时,注意到这里还有一些全局选项,基本上是用于设定固定坐标系的工具,因为坐标系是可以移动的。其次,还有轴(axes)和网格(grid)作为各个参数项的参照物。在示例中,对于example9节点,我们将会看到标记(marker)和点云(pointcloud2)。

最后,在状态栏上有时间相关的信息提示,以及在右侧有一些菜单。tools用于配置一些插件参数,如2d nav goal和2d pose estimate主题名等。在views目录提供了不同查看类型,一般而言有orbit和topdownortho就足够了,一个用于3d查看,另一个用于2d俯视查看,其他目录显示了环境中一些可以选择的元素。在顶部,有一个当前操作模式的菜单栏,包括交互(interact)、移动(move)、测量(measure)等,以及一些插件。

现在运行example9节点:

在rqt_rviz中,我们将会把frame_id设置为标记,这个标记是固定坐标系的坐标标记(frame_marker)。我们将会看到红色方块标记在移动,如下图所示:

类似地,如果设置固定坐标系为frame_pc,我们将看到一个200×100像素点平面所组成的点云,如下图所示:

支持的rqt_rviz内置类型的参数列表包括camera和image。它们会在一个类似于image_view的窗口中显示。选择camera的时候,需要对它先进行校准,在使用双目视觉图像的时候,它允许我们覆盖点云。我们同样也可以看到激光雷达的laserscan数据,红外/声呐(ir/sonar)传感器的锥状距离数据range,以及3d传感器例如kinect的pointcloud2。

对于导航功能包集,将会在下一章进行详细介绍。我们会使用多种数据类型,例如里程odometry(画出机器人的里程位姿),路径path(画出机器人所走过的路径),物体位姿pose,带有机器人位姿估计的粒子云posearray,使用occupancy grid map(ogm)的地图map,以及costmaps(这是ros hydro的map类型,之前是gridcell)。

在这些类型中,需要说明的是机器人的模型robotmodel,它能够展示机器人组件的cad模型,并将每个组件的坐标系之间的转换考虑进去,甚至还能画出坐标变换(tf)树,并且在仿真环境中为坐标系调试提供非常大的帮助。我们会在下一节展示示例。在robotmodel中,我们用机器人urdf描述中的关节绘制一条轨迹,看它们如何随时间变化移动。

基本元素也可以被表示,例如机器人足迹的polygon、各种不同的标记markers通常支持基本几何元素,如立方体、球体、线条等,甚至是交互式标记对象interactivemarker。交互式标记对象允许用户设定标记对象在3d环境中的位姿(位置和方向)。使用下面命令,运行example8节点查看简单交互式标记:

你将看到一个标记,可以在rqt_rviz交互模式中移动它。它的位姿可以用于修改系统中另一个参数的位姿,例如机器人关节:

3.9.2 主题与坐标系的关系

如果数据从真实世界中一个物理位置的特定传感器数据发布,主题必须有一个坐标系。例如,相对于机器人底盘的位置上有一个激光传感器(通常在轮式机器人两个轮子的轮轴中间)。如果我们需要用激光扫描数据去检测环境中障碍物或者构建地图,就必须对激光传感器和底盘所在的位置进行坐标转换。在ros系统中,带有报文头的消息除了具有时间戳(在不同的消息间进行数据同步非常重要)之外,还要附上frame_id(坐标系标签)。坐标系标签用于区分消息所属的坐标系。

坐标系自身并没有意义,我们需要的是它们之间的坐标变换。实际上,机器人的tf坐标变换树都会有一个base_link作为根坐标系(或是地图,如果运行导航包的话)。这样,我们就能够在rqt_rviz中通过对比根坐标系和其他坐标系查看机器人相对于真实世界坐标系的运动。

3.9.3 可视化坐标变换

为了解释如何进行坐标变换的可视化,我们将会再次使用turtlesim的示例。运行以下launch文件:

这是一个在rqt_rviz里能够用于展示tf可视化的最基本示例。需要注意的是tf api提供了很多不同的可能性,可以参考本书的后续章节。而对于现在的示例,我们只需要知道它们能够在某个坐标系内进行计算和从一个坐标系变换到另外一个坐标系,而且包含时间延迟即可。我们还需要了解tf在系统中会以某个特定的频率进行发布,这样它就会像子系统一样允许我们遍历坐标变换树以获取其中任意两个坐标系之间的转换,并且可以在系统的任意节点中通过调用tf进行变换。

如果你收到一个错误,这很可能是因为在launch文件启动时监听器(listener)失效了。监听器是一个必备的节点,必须准备好才能进行坐标变换。因此,请在另外一个命令行窗口下运行以下命令:

现在你应该会看到一个带有两只小海龟的窗口(小海龟的图标不同),一只小海龟跟着另一只。你可以使用键盘上的上下左右四个箭头按键控制小海龟。需要注意的是要停留在运行launch文件的那个命令行窗口上,而不是在turtlesim窗口上,这样才能让小海龟移动。右图显示了在我们控制一只小海龟移动了一段距离之后,另一个小海龟是如何跟随着它的。

每一只小海龟都有自己的坐标系,可以在rqt_rviz中查看它们:

现在,先放下turtlesim,我们先来看当使用箭头键移动小海龟时rqt_rviz里小海龟的坐标系是如何移动的。首先设定固定坐标为/world,然后将坐标转换tf树添加到左边的区域。我们会看到/turtle1和/turtle2两个坐标系,它们同为/world坐标系的子坐标系。在world的显示中,坐标系由坐标轴组成,父-子之间的连接是一个带有粉红色尾巴的黄色箭头。同时,设定world的视图(view)为topdownortho,这会使示例中查看坐标系的移动更容易,因为它们仅在2d平面中移动。你还会发现通过鼠标操作转换world视图显示的中心非常有用,只需要你按下shift按键同时转动鼠标。

在下图中,你能看到不同海龟所在的两个坐标系如何转换到/world坐标系中并进行显示。同时,你也可以用这个示例和tf更改固定坐标系。请注意config/example_tf.rviz用作本示例的基本rviz配置:

3.10 保存与回放数据

通常情况下,当我们使用机器人系统时,资源通常是共享的,并不一定总能给你一个人使用。或者由于准备和实施实验消耗了大量的时间,或是实验难以重现等诸如此类的原因导致实验不能顺利完成。基于以上原因,将实验数据记录下来用于未来的分析、处理、开发和算法验证就是一个很好的实践方法。然而要保证存储数据正确并能够用于离线回放却不是容易的事情,因为很多实验并不一定能反复进行。幸运的是,ros中的强大工具使我们能够完成这项任务。

ros能够存储所有节点通过主题发布的消息。它能够创建一个消息记录包文件(bag)来保存消息,并包含消息的所有字段参数和时间戳。这允许离线回放实验并模拟真实的状态,包括消息的时间延迟。甚至ros工具能够非常有效地在处理高速数据流时以充足的数据组织方式来实现这一切。

在下面的小节中,我们会解释ros中提供的这些用于存储和回放消息记录包文件的工具,消息记录包文件由ros开发者设计,使用二进制格式存储数据。我们还将看到如何管理这些文件,即检查文件内容(消息的数量、主题等)、文件压缩、分割和合并多个记录包文件。

3.10.1 什么是消息记录包文件

消息记录包(bag)是一个包含各个主题所发消息的容器,用于记录机器人各个节点间的会话过程。简而言之,它们是系统运行期间消息传送的记录文件,并能允许我们回放所有一切,甚至包括时间延迟。因此所有消息在记录时都会打上时间戳,不仅是报文头里的时间戳,还包括使用消息的数据包。用于记录的时间戳和报文头内的时间戳之间的区别在于前者是消息被记录时的时间,而后者是消息产生和发布时的时间。

消息记录包中存储的数据使用二进制格式。这个容器使用的数据结构非常特殊,能够支持超高速数据流的处理和记录。这是记录数据最关键的功能。当然,这和消息记录包文件的大小也是相关的。但随着文件的增大会牺牲数据的记录速度。我们能选择bz2算法进行实时数据压缩,只需要在你使用rosbag record命令记录时使用-j参数,你会在下一节看到具体示例。

每个消息与发布它的主题都被记录下来。因此,我们可以区分某个主题进行记录,或者直接选择全部(使用-a参数)。然后等你回放记录包的时候,同样可以通过指明特定主题的名称来选择消息记录包中全部主题的某个特定子集进行回放。

3.10.2 使用rosbag在消息记录包中记录数据

首先要做的事情是简单地记录数据。使用一个非常简单的系统,以example4节点为例。因此,先运行节点:

现在我们有两个选择。第一个是记录所有的主题:

或者选择第二个,仅记录一些特定(用户自定义)的主题。在这个示例中,仅记录example4的主题是合理的选择,可以使用以下指令:

默认情况下,当运行前面的命令,rosbag程序会订阅相关节点并开始记录消息,将数据存储在当前目录下以数据内容作为文件名的消息记录包文件中。一旦你完成实验或者想结束记录,只需要点击ctrl + c。下面就是一个记录数据和消息记录包结果的示例:

使用rosbag help record可以看到更多的选项,其中包括记录包文件的大小、记录的持续时间、分割文件到某个给定大小的选项等。或者像前文提到的那样,文件可以实时压缩(使用-j参数)。坦率地讲,这只在数据存储速率较低时有用,因为这同时还会消耗大量的cpu时间并可能丢失部分消息。或者,我们能以mb为单位增加记录缓存(-b)大小。缓存大小默认值是256mb,但在某些数据存储速率特别高的情况下也可能需要gb级的缓存(特别是处理图像时)。

在launch文件中可以直接调用rosbag record,这在我们需要为一些主题设置记录器时非常有用。为此,我们需要在launch文件中增加一个如下所示的节点:

需要注意的是主题和传递给其他命令的参数会使用args参数。同时,在使用launch文件直接启动记录的时候,记录包文件会默认创建在~/.ros路径下,除非使用-o(前缀)或-o(全名)给文件命名。

3.10.3 回放消息记录包文件

现在我们有了一个消息记录包文件(bag),可以使用它回放主题发布的所有消息数据。只需要运行roscore,而不需要再运行其他任何节点。然后,移动到想要回放的消息记录包文件所在的文件夹下(在本章的示例中bag文件夹下提供了两个记录包示例),并且输入以下命令:

我们会看到如下输出:

在回放消息记录包的命令行窗口内,可以暂停(点击空格键)或一步一步前进(点击s键),或者使用ctrl + c来马上停止回放。一旦回放完毕,窗口就会关闭,但是有一个选项(-l)允许循环播放,这在有些时候也很有用。

通过rostopic list命令查看主题列表,如下所示:

/clock主题用于指定系统时钟以便加快仿真的回放速度。它能够通过-r选项进行配置。在/clock主题中能够发布仿真时间,并以--hz为参数配置频率(默认是100hz)。

同时,我们可以指定文件中将要发布主题的一个子集。这可以通过--topics选项来完成配置。

3.10.4 检查消息记录包文件的主题和消息

这里有两个主要的方法来查看消息记录包内部的数据。第一个非常简单。我们只需要输入rosbag info <bag_file>,然后结果如下图所示:

我们有消息记录包文件本身的信息,例如创建的日期、持续时间、文件大小,以及内部消息的数量和文件的压缩格式(如果有压缩)。然后,我们还会有文件内部数据类型的列表。最后有主题的列表,并对应它们的名称、消息数量和类型。

第二种检查包文件的方法则非常强大。这个gui工具叫做rqt_bag。它不仅具有图形界面,还允许我们回放消息记录包、查看图像(如果有)、绘制标量数据图和消息的数据原结构(raw)。我们只需要传递记录包文件的名称,就会看到如下图所示的界面(使用之前的记录包文件):

我们有一个能用于所有主题的时间条。对于每一个消息都会带有这个标记。在本例中,能够在时间条中使用缩略图查看消息。

在下图中,我们能够看到如何调用raw、plot和image指令(如果是图像类型的主题),来查看记录包文件中的主题。在时间条上单击右键就会弹出这个菜单。下图对应老rxbag,这个功能已经被添加到rqt_bag,但目前在debian库中可能还不可用:

作为补充,我们使用rqt_gui将rqt_bag和rqt_plot插件放到同一窗口中。通过config/bag_plot.perspective文件夹导入下图所示的布局。不同于rxbag,我们使用pubulish all和播放查看绘图。对于/accel主题,我们可以使用一个坐标轴绘出所有的字段。为了实现这个功能,先要进入绘图(plot)的视图中,点击+按钮/图标选择所有字段。请注意,我们可以随后再删除它们或者新建一个轴。如之前提及的,绘图工具不生成文件中所有数值,它只是简单显示数据的回放和发布:

需要注意的是由于rxbag的特点,至少要点击一次play按钮才能够对数据进行绘制。我们还能够播放、暂停、停止和移动到文件头或者文件结尾。

这里图像都很简单,而且会出现一个带有当前坐标系和配置选项的窗口,能够将这些内容作为图像文件存储在硬盘上。

由于rqt_bag的第一版还没有前面提到的预览和可视化功能,你将需要为ros hydro编译rxbag或升级最新的rqt_bag(或者从github库中克隆hydro-devel分支并编译)。

3.11 应用rqt与rqt_gui插件

从ros fuerte发布以来,rx应用或工具已经被rqt节点替代。它们基本上是一样的,只有一小部分的升级、bug修正和新功能。我们使用下面列表对本章中介绍的工具进行说明(ros hydro的rqt工具以及对应被替代的之前的ros发布版本):

ros hydro rqt工具 替代(ros fuerte或之前版本)

rqt_console和rqt_logger_level rxconsole

rqt_graph rxgraph

rqt_reconfigure rqt_reconfigure dynamic_reconfigure reconfigure_gui

rqt_plot rxplot

rqt_image_view image_view

rqt_bag rxbag

在ros hydro中,这些可以单独运行的插件甚至更多,能够作为命令行(rqt_shell)、主题的发布者(rqt_publisher)、消息类型的检查者(rqt_msg)等,本章内容涵盖了这些重要的插件。甚至rviz都有一个名为rqt_rviz的插件,还能够集成在最新的rqt_gui界面中。我们可以运行这个gui并在窗口上手动添加和排列一些插件,如本章之前给出的一些示例:

3.12 本章小结

在阅读了本章并运行了示例代码之后,你就掌握了加快机器人系统构建速度、错误调试、结果可视化等大量实用工具。可以通过这些工具评估或验证设计质量。作为机器人开发人员,你将在开发过程中逐渐深入体验这些特殊的概念和工具。

现在你知道了如何在代码中包含不同级别不同详细程度的日志信息。这能够帮助你调试节点错误。为了实现这个目的,你还需要使用其他一些ros中包含的强大工具,例如rqt_console界面。另外,你也可以检查或列出运行中的节点、发布的主题和系统运行时提供的服务。这包含了使用rqt_graph工具检测节点状态图。

对于可视化工具,你已学习了使用rqt_plot绘制标量数据曲线。它能够以更加直观的特定变量分析方式发布你的节点。类似地,你能够查看更加复杂的数据类型(非标量数据)。这包括使用rqt_image_view和rqt_rviz查看图像和3d数据,也可以使用这些工具校正和调整摄像头图像。

最后,你已经通过学习rosbag工具学会了记录和回放主题中的消息,还知道了如何使用rqt_bag查看消息记录包文件的内容,这就允许你基于以往的经验去记录数据和使用ai算法或机器人算法处理数据。

在接下来一章中,你将会使用本章讲过的这些工具可视化不同类型的数据,以及一些传感器在ros中的使用说明和它们输出数据的可视化等。

继续阅读