《Kinect应用开发实战:用最自然的方式与机器对话》一2.2 Kinect传感器的硬件组成
2.2 Kinect传感器的硬件组成
如果打开Kinect传感器的外壳(通常建议不这么做),你会发现一个结构复杂的设备,其中包含很多的感应器元件和处理芯片。事实上,内部传感器栏上甚至有一个小风扇,用于冷却所有的电子器件。相对而言,Kinect是比较容易拆卸的,如图2-4所示。Kinect的电子芯片很多都采用非焊组装的方式,如果你能得到备换的零件,修复率应该会很高。
如图2-5所示,除了语音指令和体感操作指令外,Kinect没有其他形式的用户输入,其输入系统的关键是由麦克风和摄像头组成的感应器系统。如图2-6所示,Kinect内部的确比想象中要复杂得多,其主板并非标准的单板压模工艺,而是分拆为成三个独立的部分,并且配有专用冷却风扇。
PrimeSense技术是微软Kinect传感器系统的基础。最初,该传感器被设计为与微软Xbox 360控制台游戏系统的自然人机交互输入。它的工作原理容易理解,但执行过程相当复杂。PS1080系统级芯片(SoC)则是一款完美支持PrimeSense技术的产品,可以将其理解为Kinect的“心脏”。从外观上看,Kinect也有三只“眼睛”,它们自左向右分别是红外投影机、彩色摄像头、红外深度投影头。此外,Kinect还暗藏着四只“耳朵”—L形布局的麦克风阵列。PS1080这款芯片独立地管理音频和视频信息,这些信息都可以通过USB接口进行访问。USB仅为PrimeSense单元提供电源,Kinect还需要额外的电源供给它的伺服系统。以下是Kinect的组件的完整列表: 外壳、底座及4个不同类型的螺钉; Moving Touch传动马达电动机(用于仰角控制); 散热风扇; 彩色摄像头; 红外摄像头; 红外投影机; 麦克风阵列(4个); 3部分主板; 14种关键芯片。注意 核心的Primesense芯片来自以色列、存储芯片来自韩国三星,部分零配件来自中国台湾。Kinect和Xbox 360一样,都是在中国广东组装制造。对Kinect的核心芯片描述的摘要如下: Wolfson Stereo ADC with microphone preamp(立体声ADC与麦克风前置放大器); Fairchild N-Channel PowerTrench MOSFET; NEC USB 2.0 hub controller(USB 2.0集线器控制器); Unidentified SAP package chip; Camera interface controller(摄像头控制芯片); Hynix 512Mb DDR2 SDRAM; Analog Devices CMOS Rail-to-Rail Output Operational Amplifier(CMOS运算放大器); TI 8-bit, 8-channel Sampling A/D converter; Allegro low voltage stepper and single/dual motor driver(低功率步进器和单/双直流电动机驱动器); ST 8Mbit NV flash memory(8MB闪存); Marvell SoC camera interface controllerAP102(附带摄像头接口控制器的SoC); PrimeSense PS1080 image sensor processor(SoC成像传感器处理器,PrimeSense的核心芯片); TI USB audio controller (音频控制器); KionixKXSD9 accelerometer (三轴加速度,测量是否水平,计算偏移用于补偿)。你可以从网络上搜索到关于Kinect硬件拆解的相关文章。Kinect的关键部件如图2-7所示。
图2-7所示Kinect关键部件及说明如下:1)麦克风阵列:声音从4个麦克风采集,同时过滤背景噪声,可定位声源。2)红外投影机:主动投射近红外光谱,照射到粗糙物体、或是穿透毛玻璃后,光谱发生扭曲,会形成随机的反射斑点(称为散斑),进而能被红外摄像头读取。3)红外摄像头:分析红外光谱,创建可视范围内的人体、物体的深度图像。4)仰角控制马达:可编程控制仰角的马达,用于获取最佳视角。5)USB线缆:支持USB 2.0接口,用于传输彩色视频流、深度流、音频流等。必须使用外部电源,传感器才能充分发挥其功能。(Kinect的功率达到了12W,而普通USB一般是2.5W。)6)彩色摄像头:用于拍摄视角范围内的彩色视频图像。接下来,分别从控制芯片、红外投影、视频输入、音频输入、姿态控制调整等方面来分析Kinect硬件的内部结构。
2.2.1 Kinect的“心脏”—PS1080 SoC
Kinect的“心脏”是PrimeSense的PS1080 系统级芯片(SoC)。PS1080 SoC拥有超强的并行计算逻辑,可控制近红外光源,进行图像编码并主动投射近红外光谱。同时,通过一个标准的CMOS图像传感器接收投影的Light Coding 红外光谱并且将编码后的反射斑点图像传输给PS1080,PS1080对此进行处理并生成深度图像。图2-8所示为PrimeSense的推荐设计。
PrimeSense是一家以色列公司,它赋予电视、机顶盒、客厅计算机等消费电子产品自然交互技术,招牌就两个字—深度。PS1080 SoC芯片是一个多感应系统,能提供同步深度图像、彩色图像和音频流,如图2-9所示。PS1080通过USB 2.0物理层协议将所有数据传送到主机。PS1080适用于各种主机CPU—所有深度获取算法均在PS1080上运行,主机只需运行最低限度的USB通信层。通过这种设计,即使是计算能力有限的主机设备也能具备“深度图像获取能力”。
深入理解 关于PrimeSense的推荐设计及专利信息,可通过在Micorosoft学术搜索或Google专利搜索中搜索。关键字“INTEGRATED PROCESSOR FOR 3D MAPPING”或其专利号“Pub.No.:US 2010/0007717 A1”进一步了解。此外,Kinect使用NEC uPD720114的USB 2.0集线器控制器作为数据集成接口,主要控制芯片包括Allegro Microsystems A3906(低电压步进器和单/双路直流电动机驱动器)、Marvell AP102(带摄像机接口控制器的SoC)/PrimeSense PS1080-A2(成像处理器SoC)、TI TAS1020B(USB音频控制器)和其他辅助计算/存储设备。Kinect在设计时由于平衡Xbox 360商业和技术上的诸多考虑,以150美金的定位包含如此众多的功能,让Xbox 360如虎添翼。Kinect的芯片造型上,要求最大限度分担Xbox 360的处理压力,尽量使Kinect硬件层分担一些预处理的工作。在Kinect早先原型设计的一个版本里,包含一个额外的硬件传感器用于加速“骨骼跟踪”任务,但最终版本还是基于主机软件来实现的。从商业角度而言,这可以降低20至30美元,并保持更小的体型。
2.2.2 Kinect的“三只眼”—投影机和两个摄像头
你可能已经注意到Kinect有三只不对称的“眼睛”,从左向右分别是红外投影机和一组光学部件—彩色摄像头和红外摄像头,如图2-10所示。在图2-10所示中,从左向右,分别是OG12/0956/D306/JG05A红外投影机、VNA38209015CMOS彩色摄像头,以及Microsoft/X853750001/VCA379C7130CMOS红外摄像头。中间的摄像头提供了彩色图像;剩余的两个元件通过发射/接收红外线,来提供深度数据,如图2-11所示。尺寸上它们接近于网络摄像头,其镜头大,具备自动对焦功能。
Kinect获得深度数据的原理如下:红外投影机的普通激光源投射出一道“一类普通激光”(Class1 Lasor),这道激光经过磨砂玻璃和红外滤光片,覆盖Kinect的可视范围,红外摄像头接收反射光线,识别目标物体的“深度场”(Depth Field)。后面的章节会进一步介绍相关内容。
红外投影机红外投影机是位于Kinect最左侧的那只“眼睛”,它与最右侧的红外摄像头配合使用。拆解后的红外投影机如图2-12所示。
PS1080 SoC(系统级芯片)对红外光源进行控制,以便通过红外光编码影像放映场景。红外投影机的光源是一类普通激光光源,经过磨砂玻璃和红外滤光片,投射出近红外光,该光波长为830nm,可持续输出,符合IEC 60825-1标准中的一级安全要求。红外摄像头是一个标准CMOS影像传感器,负责接收放出的红外光,并将红外光编码影像传给PS1080。PS1080负责处理红外影像,然后逐帧生成准确的场景深度影像,如图2-13所示。
看到“激光”,你可能心存疑虑:Kinect发射的是红外线还是激光,会不会对人体有害?英文资料里有提到“Laser projector:near infraredlight,830nm,cons-tantoutput, class1 laser”。上述也提到过,事实上,Kinect的光源符合IEC 60825-1标准中的一级安全要求,大家大可放心。扩展阅读 激光辐射的电磁波波长范围包括长波长的红外的(CO2激光)范围,到近红外(Nd激光:Yag,Nd:YVO4),可见光(Ne或者氩)和不可见的紫外光(受激准分子激光)。在光谱中波长自0.76至400微米的一段称为红外线,红外线是不可见光线。所有高于绝对零度(–273.15℃)的物质都可以产生红外线。有体温的生命体(如人类)发出的光谱属于“远红外线”;Kinect发射的光谱属于“近红外线”,波长更小。关于激光辐射的规章制度已经建立,它是根据伤害人的程度来定义激光危险不同的等级,从激光一级(在各种情况下,一级激光基本安全)到激光四级(任何情况下,四级激光是危险的)。
彩色摄像头和红外摄像头Kinect是通过彩色摄像头和红外摄像头来观察这个世界的,拆解后的硬件如图2-14所示。
Kinect这两只不同的“眼睛”所看到的世界是如何同步和互相补充的呢?视力又是如何?为了生成更准确的传感器信息,PS1080系统级芯片(SoC)会执行“PrimeSense注册过程”。什么是PrimeSense注册过程?为了让深度影像和二维标准色彩影像相互对应,必须进行注册。注册就是将色彩影像和深度影像进行对应,产生像素相互对应的影像,即色彩影像中的每个像素分别与深度影像中的一个像素对应。这能让应用程序准确了解收到的色彩影像中每个像素的深度。所有传感器信息(深度影像、色彩影像和音频)通过一个USB 2.0接口传送给主机,且时序一丝不差。通过Kinect SDK可以获得同步的深度图像和彩色图像数据流。
2.2.3 Kinect的“四只耳朵”—麦克风阵列
由于Kinect的“三只眼”的不对称分布,Kinect麦克风阵列也是左右不对称,从而保持质量分布的均衡。Kinect的“四只耳朵”分布如图2-15所示。
Kinect的音频系统采用了四元线性麦克风阵列技术。一般而言,麦克风阵列中包含四个相互独立的小型麦克风,每个设备之间相距数厘米,其排列可呈线形,捕捉多声道立体声,通过数字信号处理(DSP)等组件,根据麦克风阵列接听声音的时间差来判断声源方向,如图2-16所示。
从元件上看,除了Kinect所有的四元麦克风阵列以外,还配置了Wolfson Microelectronics WM8737G(配置了前置放大器的24bit立体声ADC)用于进行本地的音频信号处理。Kinect的“四只耳朵”具有以下特点: 音频格式:16kHz, 16bit单声道(PCM)。 音频输入特性:4个带有24bit的数字模拟信号(ADC),用于消除和处理噪声的麦克风阵列。 Kinect共有4个向下的麦克风:右侧3个,左侧1个。微软认为最佳的声音搜集方向应该是朝下的。这种麦克风阵列的设计是为了尽可能获得优质的声音信号以及判断不同方向的声源,尤其适用于在室内的走动,并识别语音命令。比如玩Kinect Xbox 360游戏前,为了正确识别语音指令,系统会建议用户对房间中的语音进行校准。不过,如果你改变了房间内的家具摆放,就必须要重新校准。在进行设置时,语音识别功能会根据房间的反射性创制一幅音频分布图。音频处理器则利用这幅图来执行多通道上的回声消除,以提高对声音命令的解读能力。与一般的单麦克风数据相比,Kinect阵列技术包含有效的噪声消除和回波抑制(Acoustic Echo Cancellation,AEC)算法,同时采用波束成形(Beamforming)技术,通过每个独立设备的响应时间确定音源位置,并尽可能避免环境噪声的影响。此外,Kinect还被设计为可以在发言者超过一人时辨别出相应的语音指令。波束形成技术已广泛应用于雷达、声纳和通信等领域。扩展阅读 上述波束成形技术的细节来源于微软研究院,有兴趣的读者可以参考A New Beamformer Design Algorithmfor Microphone Arrays,原文发表于IEEE-Proceedings of ICASSP 2005 USA。
2.2.4 会摇摆的“相控雷达”—传动马达
Moving Touch传动马达让Kinect感觉像是个“相控雷达”,能根据它与用户之间的相对位置/距离来调整姿态,从而更有效地与用户进行交互,这种机制被命名为Tilt机制(垂直倾斜机制),如图2-17所示。
传达马达可以控制Kinect仰角,调整最佳姿态来适应玩家的位置,确保玩家全身肢体被覆盖。Kinect for Xbox 360视野范围如图2-18所示。Kinect配备了追焦系统—Tilt仰角控制。如果玩家超出影像范围,底座马达可驱动Kinect垂直调整±28°。而Kinect成像系统自身的视角大小为垂直43°,水平57°。
注意,目前Kinect的传动马达还比较简陋,将其拆开可以发现其中的电动机和塑料齿轮看起来工艺有些粗糙,抗疲劳能力有限,如图2-19所示。当然,从商业成本压缩的角度来说,这也是可以理解的。另外要注意的是:Moving Touch的传动马达不适用于重复性运动,并应避免人为手工的转动。Kinect SDK建议避免频繁调用Tilt功能,其最低标准是每秒不超过1次(或每20秒不超过15次)调用。
2.2.5 姿态控制—三轴加速度计
考虑到Kinect的放置平面未必绝对水平,或者有不固定运动的应用场景,Kinect的硬件设计包含了Kionix KXSD9三轴加速度计。自iPhone问世,三轴加速度计已在智能手机中得到广泛应用。三轴加速度计除了自动切换水平、垂直显示视角外,还可在GPS信号不好时,用作运动偏移补偿计算。日常生活中的一些计步器也是采用三轴加速度计的。Kionix KXSD9 三轴加速度计用于倾斜补偿,保证Kinect深度数据的准确性。后面会谈到人体骨骼识别,其中很重要的一点就是判断Kinect是否水平放置,每个骨骼帧都包括一个描述重力的值。该值是由内部的三轴加速度计配合传感器图像测量来计算得到的。如果你在玩Kinect for Xbox 360游戏时移动了Kinect,界面会跳出一个提示窗口,暂停游戏。系统就是通过三轴加速度计捕捉到这一事件的。后面章节会谈到利用Kinect Services for RDS 2008 R3进行机器人运动开发,通过Kinect技术充当机器人“眼睛”,对周围3D环境进行实时重建;还会提到“Kinect牌导盲犬”,为盲人指路。因为Kinect处于运动状态,硬件设计上包含三轴加速度计,以用于倾斜补偿。
2.2.6 USB接口及电源
在Primesense的推荐设计中,采用了标准的USB 2.0接口。在Kinect的设计中,USB仅为PrimeSense PS1080 系统级芯片(SoC)单元提供电源。Kinect还需要额外的电源,如用以驱动传动马达、投射红外,这样传感器才能充分发挥其功能。
连接Kinect十分容易,只需插上电源,并将Kinect通过USB接口连接到计算机上。盒装版本的Kinect,都有独立的电源。如果你买的是新版Kinect Xbox 360套装,是不附带电源的,而且不是标准的USB接口。如果想在PC上用Kinect,必须购买独立的电源供应器和一根AUX转USB的接线,如图2-20所示。
Kinect接口支持USB 2.0,用于传输视频流、深度流、音频流等。Kinect LED指示灯位置如图2-21所示,其状态指示如下: 对于Kinect for Xbox 360,仅连接PC后Kinect的LED会点亮,但还不能执行主要功能;连接电源后正常工作,LED绿灯会持续闪亮。 对于Kinect for Windows,只有连接并且加点后,绿色LED才会常亮。Windows版Kinect的USB线被缩短,并可兼容各种型号的计算机,内置的软件可以确保USB和计算机其他USB设备的兼容性。Kinect的电源和USB是同一个接口,如图2-22所示。Kinect必须使用外部电源,传感器才能充分发挥其功能。Kinect的功率达到了12W,而普通USB一般是2.5W。
小插曲 微软没有对USB传输的信息进行加密,因此这给黑客最初破解Kinect提供了非常有利的条件。New Scientist网站在Inside the race to hack the Kinect一文中讲述了Kinect被破解的全过程。黑客们通过USB记录仪截获了Kinect与主机之间通信的所有数据,整个破解过程就是一个逆向工程,类似于密码破译,未加密的数据给黑客带来了极大的便利,这可能也是Kinect设计上基于性能的一些考虑。
2.2.7 Kinect风扇控制
为了抑制温度过高导致激光振荡波长变化影响激光散斑,Kinect在近红外激光器上颇费了些心思,实施周密的温度控制。在导热性高的金属部件上安装激光器,在金属部件和激光器之间还配置了冷却用热电效应器件(Peltier Effect Device,TE),旁边还备有冷却风扇。具体如下: 风扇从一端进气、一端出气。 Kinect从自身设计上已考虑如何避免风扇过热。这由传感器硬件控制,当温度过热(超过90℃)时会关闭摄像头。 Kinect For Windows SDK本身没有提供接口来控制风扇。
文章
传感器 · 安全 · 语音技术 · 芯片 · SoC
2017-08-01
《Kinect应用开发实战:用最自然的方式与机器对话》一3.2 基于“管道”的系统架构
3.2 基于“管道”的系统架构
Kinect for Xbox 360是一个基于“管道”的体系架构,如图3-3所示。Kinect传感器设备提供三大类的原始数据信息,包括深度数据流(depth stream)、彩色视频流(color stream)、原始音频数据(raw audio stream),同时分别对应骨骼跟踪(Skeletal Tracking)、身份识别(Identify)、语音识别(Speech Pipeline)三个处理过程。
1)骨骼跟踪具有以下特点: 从Kinect Primesense芯片组获取深度数据流,通过USB 2.0端口传输。 设定人体“分类”(Classification)的特征阈值,通过约定的字节编码,为每个被追踪的玩家在深度图像中创建“分割遮罩”(Segmentation)。 将深度数据中出现的游戏玩家(用户)与背景图像分割,发现玩家。 通过机器学习的结果,快速对人体部位进行分类。 通过机器学习的结果,从人体部位进一步识别关节点三维坐标,从而进行人体骨骼三维建模。 根据Xbox 360游戏场景需要进行后续的游戏渲染工作。2)身份识别包括动作识别和人脸识别两部分,其具有以下特点: 从Kinect彩色摄像头获得视频流信息,通过USB 2.0端口传输。 玩家面部器官被分解成几个关键性的面部标志,通过彩色视频信息的特征采样进行人脸匹配。 为了提高识别精度和效率,同时结合人的着装信息、身高等因素来进行匹配。 玩家用户信息被识别,并从关联数据库中被检索。 根据玩家的个性化信息,Xbox 360游戏进行后续的游戏渲染工作。3)语音识别处理具有以下特点: 从Kinect麦克风阵列中获取原始音频信息,通过USB 2.0端口传输。 根据特定算法进行多通道回声消除、回声抑制,适应玩家与Kinect麦克风一定距离及室内空旷回声等情况。 通过波束成形等机制,进行声源定位。 通过噪声抑制等机制,自动过滤环境噪声。 语音命令识别。 根据Xbox 360游戏场景需要进行后续的处理工作。Kinect“体感操作”带来了全新的用户体验和交互设计,可以说用户体验、交互设计、创新技术正是Kinect成功的“三板斧”。Kinect for Xbox 360的关键技术特性归纳为如下四点:骨骼跟踪、动作识别、人脸识别、语音识别。下面,我们逐一分析这些关键特性。
3.2.1 骨骼跟踪
骨骼跟踪是Kinect“体感操作”的基础,同时系统根据这一特性创建你的数字Avatar。当你玩Xbox游戏时,根据Kinect传输过来的深度数据,系统将创建一个你的“数字骨架”。因此,无论当你向左或向右移动甚至跳跃时,你的Avatar都会保持一致的动作,就像照镜子一般,如图3-4所示。
为什么Kinect的骨骼跟踪意义非凡?从用户交互设计的角度来看,之前游戏控制器的自由度都是预先设定好的,比如键盘、鼠标、更多自由度的遥杆、带重力感应的手柄及更为先进的数字手套。骨骼跟踪的设计目标是和玩家的运动保持一致,无论他是在跳华尔兹还是在打太极拳。这其中的自由度和变换是无法穷举的,这也给Kinect For Xbox体感游戏创造了无限遐想的空间。微软在2010年的E3上展示了Kinect Avatar,如图3-5所示。
Avatar可以将玩家的虚拟形象带入全新的世界中。除了步态一致的肢体控制外,系统甚至可以惟妙惟肖地克隆玩家的表情,当他笑、皱眉、点头或者说话时,虚拟形象也会做同样的动作。通过Avatar,玩家可以邀请好友加入各种虚拟环境,比如车尾野餐会场景。骨骼跟踪要求系统在允许的延时范围内,快速构建玩家的躯干、肢体、头部甚至手指。目前这一代的Kinect技术有其自身的限制,比如视场角(FoV)有限,低于手指的分辨率,但这些限制本身应该也是更多因为相关芯片及工艺的成本,其中涉及以下三个关键点:
压缩感知前面在剖析Kinect硬件架构时,已经谈到黑客是利用USB记录仪截获数据进行分析的,当时令黑客大吃一惊的就是“数据洪水”(data flood)。如何从深度图像中抛弃背景图像信息,把人体骨骼抽象出来,这将是一件关键的工作。后面的原理分析会谈到,那将是“一个像素一个像素”地识别的工作,系统会通过机器学习和模式识别来压缩感知,处理这些原始数据(raw data)。
骨骼关节游戏中的Avatar人物与真实人体的匹配度的高低是“骨骼识别”的关键。匹配度的高低决定于能实时抽象出多少个关节点。关节点连线在一起就是一个“火柴人”,如图3-6所示。应该说关节点越多,骨骼就越真实。当然,游戏中的人物还会通过表面渲染来构建一个3D人物。
关节点的精度问题另外一个关键点是骨骼关节点精度问题,这同时涉及几个层次:
激光散斑测距采样的精度(后面会具体谈到)。 红外摄像头的采样分辨率和频率(比如Kinect深度图像默认为每秒30帧,320×240的分辨率)。 通过深度图构建骨骼数据的延时。传输延时基本可以忽略不计(正如图像显示器的刷新率一样,延时的控制应该在人的生物识别范围内,人类对事物的反应速度几乎都超过100ms)。国外调查发现Kinect的空间判断精准度为4mm, PlayStation Move则是1mm。对于运动类的游戏而言,不用携带额外控制器的好处完全可以弥补这点精度的下降。通过Kinect,玩家可以身体自如地加入运动或比赛:用脚射门、用手挥动打乒乓、身体倾斜控制皮划艇的漂流等。关于这一话题后面会具体分析,值得注意的是,Kinect深度图像采样频率并不是产生延迟进而使空间精度下降的主因,延迟的主因是芯片处理速度和软件识别处理速度不够。我们相信,随着硬件发展和软件升级,Kinect的空间精度会不断提高。如果你希望通过Kinect做运动竞技分析,或是用于低成本电影的动作捕捉,空间精度和响应速度将是关键的技术评估点。
3.2.2 动作识别
动作识别的基础是骨骼跟踪,广义上识别的内容包含肢体运动、手势以及静态姿势。美国著名心理学家艾伯特赫拉伯恩曾提出过一个公式:信息交流的结果=7%的语言+38%的语调语速+55%的表情和动作人们在人际交往中,多达93%的信息是通过非语言方式传递,其中又以肢体语言为主。比如在美剧《Lie to me》中,卡尔莱特曼博士无需测谎仪,无需确凿证据,即使嫌疑人保持沉默,也从其最终细微的表情变化和身体语言中洞察出端倪。因此,动作识别是“体感操作”的前提,引领着新一代的自然人机交互技术,也是Kinect for Xbox 360游戏的最大卖点,如图3-7所示。我们可以把动作抽象为骨骼关节点的状态或运动序列。手语是一种较为复杂的手势,它的表达涉及动作的连续性和持续性,不同的组合可以表达丰富的词组或短句。如何进行动作识别呢?最为朴素的算法是基于动作序列的算法分析。正如词组匹配算法那样,你会考虑准备一个足够长的队列,然后根据预设的算法不断地扫描,中间可以用一些决策树进行有效的删减;或者,你实现一个“有限状态机”,去触发你预先定义的动作事件。
我们这里谈的动作识别包含两个层次的概念:1)骨骼在某一时间点的状态,是为静态的姿势。比如图3-8所示是Kinect的“通用暂停或退出”姿势,玩家的左手倾斜举起,并与脊柱保持45度。2)骨骼中的某一关节或是多个关节点在空间的运动序列,是为动态的行为。比如人挥动左手,或是用手在空气中划一个圈,或者双脚离地跳起,如图3-9所示。
显然,动态的行为分析要比静态的姿势识别要复杂得多。这其中的区别,正如语音识别中“命令词识别”和“自然语义理解”一样。Kinect游戏中的动作表达有大致可分为两类: 大开大合的肢体运动,比如运动、舞蹈或者武术。 手的运动,包括手指运动。人体的各个关节从运动动力学的角度来看,有着不同的自由度。其中手是人体自由度最大的部位,它包含十根手指,除拇指外每根手指又有三个关节。通过手可以完成许多动作,简单的如挥手以引起别人的注意或表示再见,复杂点的如用手来控制镜像的机械手臂。翻译聋哑人的手语无疑是最具挑战的。Kinect手语识别示意图如图3-10所示。
第6章会具体谈Xbox Kinect Hub的一些设计,其理念就是通过简单的手势来浏览信息、翻阅信息、暂停播放、返回主界面或是确定下一步的操作。目前,Kinect for Window SDK v1.0中并不包含手势识别的部分,整个手在骨骼建模中只有一个点。但这并不意味着当前的Kinect版本不能进行相应的手势识别,你可以从最为原始的深度数据做起。这其中会有很多挑战,比如手指深度图像的精度不够,手指间的交替或是手指与身体的重叠都会产生很多噪声数据等。微笑、害羞的表情、唇语,属于人脸识别的命题,虽不属于动作的范围,但又有共同之处。相信随着技术和硬件的提升,Kinect除了可以理解人类的行为外,也可以洞察人类的内在情感。
3.2.3 人脸识别
人脸识别是整个身份识别中最重要的一个组成部分,你的身份证、驾照或是毕业证上无一不记录了你的脸部照片。作为传奇人物,拿破仑在指挥作战中,不仅能准确地记住他的各个部队的具体战斗位置,而且能记住许多士兵的姓名和面容。Kinect也将拥有如此博闻强识的本领,它能区分不同玩家、快速识别玩家的身份,从而提供更为个性化的体验,比如记住你上次听过的歌曲,或者最近玩过的游戏。通过人脸识别实现的个性化体验已经成为游戏体验的一部分,神奇之处恰恰在于你并没有做任何事情,你只是站在那里,Kinect通过人脸识别就知道你是谁,如图3-11所示。“人脸识别”与“骨骼跟踪”类似,第一步首先定位人脸的存在,其次基于人的脸部特征,对输入的人脸图像或者视频流进行进一步的分析,包括脸的位置、大小和各个主要面部器官的位置信息,并依据这些信息,进一步提取每个人脸中所蕴涵的身份特征,并将其与已知的人脸进行对比,从而识别每个人的身份。由于Kinect摄像头分辨率仅为640×480,在1.8m及以上距离的情况下,摄像头所能提供的面部的像素数据十分有限,并不适用于进行高维计算。另外,房间内光线会变,玩家时而接近时而远离Kinect,而且当玩家投入游戏时他们的面部表情也会改变,这些都会给人脸识别带来影响。还有,由于环境光照、色温和人表情的这种差异,会给人脸识别带来噪声。目前,Kinect for Xbox的人脸识别采用了抽取人脸中层结构特征的折中方式,但这种方法无法提供100%的准确识别率(大约为85%)。前面我们提到过,这种纯二维的图片识别算法也被应用在Windows Live Photo Gallery中。同时,人脸识别还综合了着装的色彩以及玩家身高的分析,以帮助提高识别准确率。抽象脸部特征作为Kinect的人脸识别的关键步骤。如果说Kinect骨骼跟踪是给每个玩家穿上动作捕捉“Marker”点,那么人脸识别中的脸部特征分解这一环节,恰恰就类似好莱坞电影面部捕捉的做法,如图3-12所示。
人脸识别另外一个需要攻克的难点在于同一个人的变化。人的面部在不同照明、表情或姿势等因素的影响下产生的差异有时让对同一个人的识别产生不同的结果。为了识别不同表情、不同光照条件下的人脸,联想推测模型的第一步是构建一个“通用”的人脸数据库。面部器官被分解成几个关键性的标志,如眼睛中心、嘴角和其他12个面部特征。这些信息作为识别引擎搜索到的不同条件下或以不同姿势呈现的人脸的基本“记忆”元素。下一步,将特定对象的面孔,如Kinect玩家的面孔与28种不同的“记忆”图像进行对比,也就是7种姿态乘以4种光照条件。识别引擎将对目标对象面部与记忆库存储的人脸展开“关联”,对一个或多个关键的面部特征进行匹配,如处于脸部阴影一侧并且正在向左看的眼睛等。然后,系统使用这些信息就对象脸部在不同姿势和不同光照条件下的样子做出科学的猜测。
关于人脸识别的技术和算法有很多种,包括几何特征识别、神经网络、弹性图匹配、线段Hausdorff距离等,本书就不再展开,读者如有兴趣可参考相关资料。Kinect for Xbox 360的人脸识别是基于彩色摄像头的信息,同时结合人的着装信息、身高来匹配的,属于纯二维的图片识别算法,并没有用到深度数据。你可以尝试基于Kinect提供的深度数据进行特征采集,提高人脸识别的精度。提示 Kinect for Windwos SDK v1.5中增加了人脸跟踪的开发包。读者还可以访问face.com,它提供开发的API接口,方便你构造自己的人脸识别应用程序。
3.2.4 语音识别
语音识别的技术大家一点也不陌生,从前面影片中提到的HAL9000、IBM尝试过的ViaVoice,到现今苹果iPhone 4S Siri以及微软的TellMe服务,都是语音识别的产品。从技术应用的深度及广度而言,语音识别丝毫不逊色动作识别、人脸识别。语音识别包括很多层次的技术,如最为简单的“语音命令”、声音特征识别、语种识别、分词、语气语调情感探测等多个方面。Kinect麦克风阵列捕获的音频数据流通过音频增强效果算法处理来屏蔽环境噪声。即使在一个大的空间,即使人离麦克风一定的距离,也能够进行语音命令的识别。Kinect阵列技术包含有效的噪声消除和回波抑制(Acoustic Echo Cancellation,AEC)算法,同时采用波束成形(Beamforming)技术通过每个独立设备的响应时间确定音源位置,并尽可能避免环境噪声的影响。从前面的产品设计分析中我们可以了解到,Kinect for Xbox 360的语音识别也仅仅定位在简单的“语音命令”的层次。比如说“Xbox, Let抯 Play”,这里Xbox就相当于是一个命令提示符,后面的话对应着一些常用操作命令,如图3-13所示。
提示 Kinect for Windows SDK v1.5是基于Microsoft Speech SDK v11.0来实现的。后面开发章节,我们会有具体的例子。目前,Kinect SDK v1.5尚不支持中文语音命令支持。在Kinect for Xbox 360中,语音识别通常用于Xbox控制中心的导航、菜单控制,以及多媒体的播放。你可以对着Kinect说“Xbox Kinect”,进入Kinect控制中心,如图3-14所示。对着Kinect说出“Xbox”,系统就会提示“if you see it, just say it”。比如打开光驱就说“Xbox Open Tray”,如果想去下一页就说“Xbox Next”,如果想退出Kinect控制中心就说“Xbox Dashboard”。想用Xbox 360看电影,那就吩咐Kinect吧:Xbox Play(播放)、Xbox Pause(暂停)、Xbox Next(下一页)…
文章
算法 · 语音技术 · 开发工具 · 计算机视觉 · UED
2017-08-01
《Arduino计算机视觉编程》一第3章 用OpenCV和Arduino进行数据采集3.1 图像和视频采集
本节书摘来自华章出版社《Arduino计算机视觉编程》一书中的第3章,第3.1节,作者[土耳其] 欧森·奥兹卡亚(zen zkaya),吉拉伊·伊利茨(Giray Yilliki),更多章节内容可以访问云栖社区“华章计算机”公众号查看。
第3章
用OpenCV和Arduino进行数据采集
在本章中,你将了解计算机视觉系统的数据采集部分。相机和传感器的数据都会被处理。本章将讲授如何给视觉系统选择相机和传感器以及如何正确使用它们。因此,本章有两个主要部分:一个部分是关于用OpenCV进行图像和视频采集,另外一个部分是用Arduino进行传感器数据采集。
3.1 图像和视频采集
人们通过眼睛来获取周围环境的视觉信息。当涉及机器如何获取视觉数据时,各种各样的相机被用于这个目的。因为视觉数据会用数字来表示,有效的相机处理会得到一个更好的表示。这是你可以从本章中学到的知识。在第2章中,你已经安装了OpenCV并且运行了一个典型的hello world应用。在此基础上,我们通过手头实际案例的讲解来学习OpenCV的数据采集功能。OpenCV支持各种各样的相机,这样开发者有很大的选择范围。学习如何针对你的应用选择一个合适的相机也是本章的一个主题。你会在本章的相机选择部分找到答案。选择相机之后,我们将研究如何使用OpenCV进行图像和视频的采集。在此过程中,我们将会学习如何读写图像、捕捉视频等。现在让我们开始吧!3.1.1 相机选择相机的选择是和需求紧密相关的。所以,在开始的时候多花点时间仔细考虑你需要的系统。这个简单的步骤会在后面的开发过程中帮你节省时间和金钱。除了需求以外,相机本身的性能也是需要考虑的。所以应该联系项目需求和相机性能来做出最佳选择。这正是本节要讲的内容!3.1.1.1 分辨率为了给应用程序选择合适的相机,分辨率和相关的相机传感器属性非常重要,先解释一下分辨率这个术语代表的意思。当我们谈论一台200万像素相机的时候,这是什么意思?这是指图像(或者一个视频帧)上像素的数目。如果相机产生的图片有1200像素高、1800像素宽,那么图像包括1200×1800 = 2?160?000个像素大概是两百万像素。尽管这个属性被称为相机的分辨率,但是现实中的视觉应用程序往往需要不同的信息比如物体的分辨率,它与相机分辨率紧密相关但是需要更多的细节。在实际使用中,分辨率意味着可用来区分两点的最小距离。因为照相的目的是获取一个物体或者事件的细节,能够获取的最小细节就显得非常重要。对于视频也是一样的,它不过是一系列连续的图像。物体分辨率这个重要术语意味着可以通过相机察觉的物体最小粒度。因此物体和最小粒度都是非常重要的。下式展示了一个特定物体的大小和可以获取的最小粒度之间的关系:
让我们举个现实生活中的例子。想象一下你正在看一辆车的车牌。假设你的相机能看到车的全景。车在全视图里面的高度和宽度都是2m。假设为了能看到车牌,你需要的最小粒度是高0.2cm、宽0.2cm。为了理解所需的物体分辨率,我们把值代入上面的公式可以得到:
所以针对这个情况我们需要的分辨率为100万像素。但是需要注意的是这个计算依赖于物体和相机之间的距离。如果我们是从比较远的地方照相,图像中的物体会更小,因此为了识别车牌需要一个更高的分辨率。反之亦然,如果车离相机更近,那么车牌在图像中就会更大,因此一个更低分辨率的相机就能满足需求。距离和分辨率之间的关系有一点复杂,但是可以用一种实用的方法来简化它。下图很好地展示了相机到物体的距离的重要性。
在这种情况下,我们可以很容易看出图片的宽度是车宽度的三倍,高度是车高度的两倍,所以总的分辨率是最初计算的6倍,就是600万像素,见以下计算:
你越是经常在实际例子中实践,就能越准确地猜出特定应用所需相机的分辨率。3.1.1.2 颜色从颜色的角度区分,相机有两种类型:单色或者彩色。选择单色相机还是彩色相机仅仅取决于应用的要求。如果应用需要彩色信息,那么必须用彩色相机。如果颜色不重要,重要的是形状,最好选择一个单色(灰度)相机。单色相机通常比彩色相机更敏感并能提供更清晰的图片。在某些情况下将这两种相机一起使用也是有可能并且是必要的。大部分网络摄像头是彩色的。此外你可以用OpenCV从彩色相机里面捕获一个灰度图像。一般来说,考虑未来的扩展性,彩色相机是首选。通过这种方式,你可以同时获取颜色和形状信息。3.1.1.3 帧率帧率是用每秒的帧数(FPS)来衡量的。帧率这个术语描述了相机每秒能够捕获和传输的图像的数量。一般来说,网络摄像头最高可以达到30FPS。有一些相机允许你动态调整帧率。帧率越高,传感器运行得更快。此外,更高的帧率也会导致更多数据的存储。需要注意的是,如果你的应用程序不够快,也许无法充分利用相机的最高FPS。如果要在工厂每分钟生产6000个产品的生产线上找到产品缺陷,你可能需要一个高FPS相机。每分钟6000个产品意味着每秒100个,假设你需要为每个产品花10帧来找到缺陷,那么在这个应用中你需要一个10×100 = 1000FPS的相机。FPS越高的相机,价格也越高。针对工厂这个例子做一个启发性计算并用帧速率来定义平均速度。比如一个普通的网络摄像机的FPS可能是50,而上文讨论的工厂的例子至少需要一个1000FPS的相机来检测缺陷,如果做一个粗略估计,1000FPS相机的价格可能是普通相机的20倍。3.1.1.4 2D还是3D从原理上来说,相机获取的图像是对场景的2D投影。如果你熟悉网络摄像头,它们都是2D网络摄像头。3D相机加了第三个维度——到数据的距离。3D相机这个词指的是广角相机或者立体相机。广角相机会生成一个每个像素带着到特定点距离信息的图像。立体相机是用2个平行相机模仿人类的视觉来捕获三维图像。通过两张图片对应点的偏移量,可以计算出图像中任意点的深度。如果你的应用需要3D功能,那么你需要一个3D相机比如Kinect或者Asus Xtion Pro Live。当然,还有很多其他3D相机!再次提醒,3D相机需要更多的存储空间。所以如果你不需要3D信息,请使用2D相机。3.1.1.5 通信接口通信接口影响相机系统的很多属性。流行的接口有USB、FireWire、GigE和CameraLink。有很多变量可以进行比较,见下表:通信接口 最大距离 最大带宽 支持多相机 实时性 即插即用USB 2.0 5m 40MB/s 中等 低 高USB 3.0 8m 350MB/s 中等 高 高FireWire 4.5m 65MB/s 中等 高 高CameraLink 10m 850MB/s 低 高 低GigE 100m 100MB/s 高 中等 中等
从表中可以看到,通信接口对控制器到相机的距离、带宽、FPS甚至可用性会产生巨大影响!所以,请评估你的需求并且给应用选择合适的接口。网络摄像头有一个USB接口。所以它们有不错的控制器到相机距离、带宽、FPS和可用性。这使得绝大多数计算机视觉应用可以使用网络摄像头。3.1.2 图像采集到现在为止,我们已经对如何选择相机有了一个比较清楚的认识。现在是时候更进一步了,让我们从相机中读取数据。大道至简,最好让一切事情保持简单并且易于使用。正因如此,我们的例子将使用一个标准的网络摄像头。这个例子将选用罗技C120作为网络摄像头。请注意安装网络摄像头的驱动以便可以与OpenCV一起工作。我们使用了OpenCV C++ API来从相机中读取数据,此外,OpenCV提供了很棒的文档,可以用C、Python和Java API轻松实现这个例子。如果需要更多信息,可以访问opencv.org。3.1.2.1 读取静态图片在设计的概念验证阶段,使用静态图片进行工作是有好处的。例如,假设你想开发一个人脸识别的应用程序。首先,你应该在一组人脸图像的样本上工作,所以,从数据存储中读取静态数据将是这个过程的第一步。OpenCV使计算机视觉系统的开发变得简单!让我们用OpenCV从存储中读取静态数据。现在编写代码来读取静态图片并将它展现在窗口中。请把下面的代码输入到OpenCV开发环境中并将其保存为read_static_image.cpp:
当你编译这段代码时,它将生成一个可执行文件。在Windows环境下,我们姑且认为它是read_static_image.exe。你可以把计算机视觉里面著名的lena.jpg图片作为输入。在Windows环境下,把这个图片复制到C:/cv_book/目录下。在cmd.exe窗口中,导航到包含read_static_image.exe的目录下。该指令如下:
在其他平台上,指令也类似。比如你的可执行文件是read_static_image.exe并且与lena.jpg在同一个目录下,你可以执行下面的指令来运行程序:
现在让我们解释这段代码。引入头文件这样的基础部分已经在前面讲过。让我们从新的部分开始,如下代码片段所示:
首先检查参数的数目是否正确。在前面的命令行中看到应该有两个参数:第一个参数是程序本身,第二个参数是图片路径。如果参数的数量不是两个,那么程序将打印一行帮助信息然后报错退出。下一步创建了一个Mat对象用来存储图像数据。图片数据以RGB格式读取,如下代码所示:
然后判断是否成功读取图片,并确认图片数据不为空。创建一个名为Read Static Image的窗口,图片会显示在该窗口中。
我们想要图片持续显示直到用户按键退出,所以我们使用waitKey函数,它只有一个用来表示等待用户输入多久(单位是毫秒)的参数。零意味着永远等待:
程序的输出如下:
你可以使用CV_LOAD_IMAGE_GRAYSCALE属性来以灰度图的格式加载图片!3.1.2.2 在网络摄像头里面做快照有时候需要用相机做快照并且保存下来以便进一步分析。这个过程通常通过一个触发器启动。回想一下基于人脸识别的门锁例子。当访客按门铃时,系统需要对脸部做一个快照并且对它进行人脸识别。这个应用是快照的一个很好的例子,我们还能找到其他需要做快照的相似情形。使用以下代码创建一个项目并且保存为take_snapshot.cpp。
前面的代码和read_static_image.cpp的代码相似。但它只是从相机中读取一帧的图像并用命令行传进来的名字对这一帧进行保存。命令行如下所示:
如果应用的名字不是take_snapshot,那么想要运行这段命令应把take_snapshot替换成应用的名字。现在让我们来解释代码!首先,我们创建了一个视频捕捉对象用来从连接的相机中捕获数据。通常情况下CV_CAP_ANY的值是0。如果你使用多台相机,需要手动增加索引,比如cap(1):
下一步创建了一个用来保存帧的矩阵对象,并把帧数据从相机对象读到矩阵对象中:
在检查帧不为空之后,就开始读取数据,然后用imwrite函数来保存图片。图片的名字是命令行的第一个参数。
3.1.2.3 从网络摄像头获取视频流视频处理应用程序通常需要一个视频流作为输入数据。通过分析帧间数据,就可以完成一些更高级的任务,比如运动识别等。视频流的FPS值和分辨率在这一过程中就变得非常重要,因为它们直接影响实时行为。越高的FPS意味着用来进行处理的时间越少。同样,越高的分辨率也让计算变得更加复杂和耗时。基于手势的运动识别是一个非常好的视频流应用例子。同样,寻线机器人也需要捕获一个实时视频流来持续地沿线行走。所以我们要理解这一部分的重要性,让我们用下述代码来捕获实时视频流:
这段代码和快照代码非常相似,除了帧数据的读取过程是在一个无限while循环中。有一个可选的ProcessFrame函数来把视频帧转成灰度帧。如果你想要一个彩色的帧,那么注释掉ProcessFrame函数。在运行这段代码时,你能看到相机里面的实时视频流!如果要改变视频流的FPS,你可以使用函数bool VideoCapture::set(int propId, double value),propId的值为CV_CAP_PROP_FPS。如果你要把FPS设为10,你可以输入:
别忘了先检查你的相机是否支持不同的帧率。3.1.2.4 与Kinect交互Kinect是一个革命性的3D图像设备,由微软研发并被广泛应用于计算机视觉应用中。Kinect的第一个版本是与大受欢迎的游戏主机Xbox 360一起发布的,Xbox的新版本名为Xbox One。尽管它最初是为游戏创造的,但是Kinect对计算机视觉应用产生了巨大的促进作用。Kinect的默认连接器是为Xbox专门设计的,电源线和数据线是一根线。如果电脑或者微机要使用Kinect,你需要一根USB转换线(见下图)。现在让我们开始与Kinect进行交互并通过OpenCV来访问它。然后你将开始学习3D视觉应用程序!
3.1.2.5 将OpenCV与Kinect集成安装点云库(Point Clond Library,PCL)将安装所有Kinect需要的软件和驱动。PCL是一个多平台库。你可以从http://pointclouds.org/得到PCL的安装包。在Mac上你无需安装PCL来使用Kinect。只要执行这一章的步骤就可以让Kinect工作起来。你需要安装libfreenect驱动来让Kinect与OpenCV通信。现在我们进入主题!我们将在Mac示范这个例子,在其他平台上也同样有效。在Mac上安装最好安装一个诸如Homebrew、Macports或者Fink这样的包管理器。正如我们之前的选择,我们将用Homebrew进行安装。让我们按照以下步骤安装libfreenect:1.?如果你还没有安装Homebrew,你可以看下2.2.2节中的指令。不管你是否安装了Homebrew,运行下列程序来更新Homebrew:
2.?要安装libfreenect,请在终端输入如下指令:
3.?这就完成了,现在你可以把Kinect插到电脑上并执行下面的命令来体验下带深度信息的图像:
Xcode集成与OpenCV和Xcode的集成一样,我们将使用相同的步骤来集成libfreenect以便在OpenCV中使用Kinect的功能。1.按照之前创建OpenCV_Template项目的步骤来创建一个新的项目。命名为OpeCV_Kinect。2.在OpeCV_Kinect项目上依次单击Build Settings | Search Paths | Header Search Paths并单击加号来添加如下的两个路径:
3.然后,依次单击Build Phases | Link Binary with Libraries并单击加号来添加两个需要的框架:
4.加完框架以后,需要添加libfreenect库和libusb库。然后,再次单击加号,再单击Add Other…。5.按cmd+Shift+g组合键然后在弹出窗口中输入/usr/local/lib。之后选择ibfreenect_*.dylibs。在选择的同时持续按下cmd键。6.现在让我们执行相同的步骤来加入libusb库。按cmd+Shift+g组合键然后在弹出窗口输入/usr/local。之后选择libusb*.dylibs。这样就集成好了!现在按照以下步骤开始编码。1.?下载libfreenect-master得到我们需要的源代码。你可以从https://github.com/OpenKinect/libfreenect下载。2.?复制粘贴libfreenect-master/wrappers/opencv/cvdemo.c到OpenCV_Kinect项目的main.cpp文件里。3.?最后,我们需要把libfreenect_cv.h和libfreenect_cv.c拖到OpenCV_Kinect项目的文件夹中(与main.cpp在一个文件夹中)并构建!以下是main.cpp的代码:
现在,让我们通过代码来解释它是如何工作的,以及如何从Kinect中获取带深度信息的图像:
来自Kinect的数据需要转换成合适的格式以便存储深度信息。在IplImage *GlViewColor(IplImage *depth)函数的for循环里,深度信息被转换成颜色。这个函数返回了一个缩放过的图像来进行表示。这是main函数里面的代码部分:
在main函数中,有一个while循环会一直循环直到有按键输入。While循环会每10ms检测一次,这是因为调用了cvWaitKey(10),所以会等待10ms就检测一次:
代码中使用Libfreenect库的freenect_sync_get_rgb_cv函数接收RGB相机的图像并把其加载到IplImage*这个图像指针指向的内存地址,如上述代码所示。代码段中的if语句会检测图像是否正确加载,如果没有正确加载会返回-1来中止程序。在cvCvtColor函数的帮助下,图像会从RGB格式转换为BGR格式。
对于图像的深度信息会执行一个类似的过程。freenect_sync_get_depth_cv函数会去获取带深度信息的原始图像并把它放到IplImage *depth指针指向的内存地址。然后,会检测深度图像是否正确加载。下面是if循环之后的代码:
现在是时候用RGB信息和深度信息把图像展示出来了。如果仔细看前面代码片段的第二行,会注意到原始的深度图像使用了GlViewColor函数进行缩放。运行代码后,你会看到下图:
在深度信息图中,可以看到靠近摄像机的物体会更红一点,而远离摄像机的物体会更绿一点。
文章
数据采集 · 存储 · 传感器 · 编解码 · 计算机视觉
2017-05-02
《Kinect应用开发实战:用最自然的方式与机器对话》一第1章 自然人机交互技术漫谈1.1 自然人机交互技术的发展
第1章 自然人机交互技术漫谈
自然用户界面(Natural User Interface, NUI)是指一类无形的用户界面。“自然”一词是相对图形用户界面(GUI)而言的,GUI要求用户必须先学习软件开发者预先设置好的操作,而NUI则只需要人们以最自然的交流方式(如语言和文字)与机器互动。直观地说,就是使用NUI的计算机不需要键盘或鼠标。—维基百科这些自然的、有响应的交互,向我们展示了如何让机器的智能与协作力自然地发挥出来,营造出真正的“机器+人”的共生系统,也就是最佳的人机交互。设计是有意识对环境的塑造,从而满足个人和社会的需求。—Donald A. Norman,《未来产品的设计》
1.1 自然人机交互技术的发展
2008年,比尔盖茨提出“自然用户界面”(Natural User Interface)的概念,并预言人机交互在未来几年内会有很大的改观,键盘和鼠标将会逐步被更为自然的触摸式、视觉型以及语音控制界面所代替。与此同时,另外一种提法— “有机用户界面”(Organic User Interface)也开始悄然兴起,其包括生物识别传感器、皮肤显示器,乃至大脑与计算机的直接对接,这些技术无疑都将给人类的生活带来重大影响。随着计算机技术和传感器的普遍应用,现实世界也逐步出现其“数字版”的一面,而自然人机交互技术正是现实与虚拟世界之间的桥梁。本章将结合一些生动例子来说明这些自然人机交互技术的最新发展,同时希望你在阅读中获得新的创作灵感。
1.1.1 第六感设备:技术的组合创新
有这样一期TED,麻省理工学院的Pranav Mistry极富想象力地将手势识别、摄像头、投影和云计算结合在一起,并命名为“第六感设备”。这种设备不用携带任何大尺寸的东西,所有的终端都浓缩在胸口的挂饰和贴在手指的“色环”中:当你想要拍照时,只需要用四根手指摆出一个框的形状;当你想要玩赛车游戏时,只需用手抓住一张白纸,通过投影仪它会“摇身一变”成为显示屏,你可通过改变纸张的倾斜角度来控制方向,如图1-1所示。
“第六感设备”通过普通摄像头对四根不同色环的手指进行手势识别,这四根手指即为关键点。这种方法有效且价格低廉。一方面,微型投影仪实现了一个“信息输出”的功能,它可以把手机键盘界面投影到掌心,另外一只手指通过“色环”捕捉“点击”操作,如图1-2所示。另外一方面,投影仪也是“增强现实”表演的道具。图1-3所示是用户展开一张报纸,大标题下的静态图片突然“栩栩如生”起来,变成了一段动态的新闻视频。这其中的奥秘是:首先通过摄像头“OCR”技术识别报纸的标题,然后智能手机访问“云端”的在线视频,最后投影到报纸上。
“第六感设备”中的任何一项技术都为众人熟知,属于一种“组合创新”,它用简单、廉价的方式创造了令人耳目一新的用户体验。关于“第六感设备”的更多信息,读者可访问Parnav Mistry的个人页面,地址为:http://www.pranavmistry.com/。“第六感设备”通过捕捉手指色环来控制方向。Kinect有些则更进一步,你不用戴色环,只需用手在空气中把握“虚拟”的方向盘即可,如图1-4所示。
关键字:第六感设备、组合创新、手势识别、增强现实
1.1.2 追影技术:摄像头也疯狂
再看一款iPhone/iPad上的创意游戏—“稻草人大战乌鸦”(Crows Coming)。这款游戏是由清华大学的学生创作的,其玩法很简单:通过人体左右晃动控制稻草人,驱赶偷南瓜的乌鸦。这是一款入门级的“体感游戏”,比用手操作的传统游戏更有趣。其原理是通过前置摄像头,结合“人脸跟踪”的计算机视觉算法来识别出玩家的动作,如图1-5所示。原来普通摄像头也能进行简单的体感操作。
微软硬件曾推出一项技术,打破摄像头产品多年以来功能单一不变的格局,这就是在微软旗下多款产品上所采用的“追影”(CamBot)技术。通过该技术,可以让用户通过手势来对PowerPoint 、Windows Photo Viewer及Windows Media Center等软件进行操作。此外,Flutter是一个Mac上的应用,通过摄像头你可以用手势控制Spotify和iTunes的播放。Google也做了类似的尝试,推出了Gmail Motion。你需要一台内置摄像头的笔记本电脑来体验这项技术,目前只支持Google Chrome或在3.5版本以上的Firefox浏览器。在Gmail设置页面中启用“Gmail Motion”后,Gmail将在你登录时启用内置摄像头,通过空间跟踪算法识别侦测到的动作,用来浏览、阅读、回复、转发邮件,如图1-6所示。长期保持坐姿的办公人员,可以在处理工作邮件的同时伸展下筋骨,这会不会也是Gmail Motion的设计初衷呢?而我们又何乐而不为呢?
摄像头及视频监控在现实中被广泛应用。结合计算机视觉技术、运动目标图形识别算法,可以通过固定道口的摄像头来监控车辆流量,如图1-7所示。
另外,这项技术也可用来统计大型场馆会议通道出入口的人流情况和人群密度,统计医院大厅目前候诊挂号人流以及火车站售票大厅的排队情况。基于普通摄像头的图形识别,会受到环境光照的制约。但Gmail Motion从体验的角度而言,一定程度上是接近Kinect的体感操作。后面我们在介绍Kinect时,也会举一些类似的例子,但实现的方式不一样,比如用手在空气中翻页操纵PPT、对老年人的监护等。关键字:计算机视觉运动目标跟踪、CamBot、Flutter、Gmail Motion
1.1.3 虚拟现实:真实的体验场景
谈到虚拟现实,这不是一个新鲜的概念,i-Max电影也可以理解为这一范畴。通过这项技术,你可以更为真实地沉浸在虚拟的现实中,比如漫步故宫、海底珊瑚礁探秘、飞行训练等。Google的《街景计划》的Google Earth可以延伸到海底;微软的Virtual Earth、WorldWide Telescope,甚至让你能用虚拟的天文望远镜观测太空。微软的经典模拟飞行游戏,后期甚至去掉了模拟(Simulator)的字样,如图1-8所示。
目前飞行舱模拟器被广泛地应用在军事训练和民航飞行培训中,它采用虚拟现实技术,通过创建和模拟呈现真实飞行过程中飞机的状态、飞行环境等。结合视景系统以及音响系统,用户可以通过视觉、听觉及触觉等多种传感途径与设备进行交互,从而更逼真地观测以及达到犹如真实操纵飞机的训练目的。对于含3D物体或数据的相关应用而言,像CAD/CAM设计创作工具、GIS绘图、石油勘探、矿区规划、3D电影制作等,3D显示为其使用性能的提升带来了极大希望。而显示器仅仅是输出设备,位于平面上的鼠标作为输入设备却无法很好地转化进3D空间。是否可以用手和身体来与虚拟的场景进行互动呢?Kinect为这种虚拟现实的体验提供了可能,如图1-9所示。
关键字:虚拟现实、飞行舱模拟器、空间体感操作
1.1.4 增强现实:真实与虚拟的叠加
增强现实(Augmented Reality,AR)又称混合现实,它通过信息技术,在同一时空,将真实的环境和虚拟的物体实时地叠加。举个例子,有款Augmented Outdoors的手机应用软件。当用户眺望远处的雪山时,使用手机摄像头取景,屏幕的雪山旁边叠加了雪山的名称、高度和距离用户的距离信息。这项技术通常结合GPS空间地理位置信息、陀螺仪方位信息和图像识别技术一同完成混合现实,如图1-10所示。类似的例子还有iPhone/iPad上的StarWalk软件。你可以在抬头观察星空的同时,了解那片天空的星座信息。这种增强现实只是结合了GPS和陀螺仪方位信息,如图1-11所示。
如果你看过《碟中谍4》,就会对影片中的“间谍眼镜”印象深刻—它就像是个隐形眼镜一样,外观看出不来,眨眼即可拍照。通过隐形眼镜可以了解周边环境信息,甚至知道前方的美女是一个冷血杀手。Google也在开发一款增强现实的眼镜Project Glass,其集智能手机、导航、相机为一体,并结合了其强大的搜索引擎。它会告诉你眼前建筑物的名称、天气和交通运输路线等实时信息。这意味着你也可以拥有《碟中谍4》中阿汤哥那样的眼镜了。增强现实在自然人机交互领域也是逐渐升温的,后面我们会举一个有趣的增强现实的开发案例,即通过Kinect摄像头来创造《星球大战》中的“光剑”效果,如图1-12所示。此外,随着裸眼3D技术的不断成熟和市场化,未来的Kinect体感游戏和增强现实眼镜或头盔会结合起来,进而给玩家身临其境的体验。另外,随着电子商务的日益普及,虚拟试衣镜的需求逐渐升温,Kinect的3D人体测量使其成为可能,并已有实际的案例应用,如图1-13所示(在后面的Kinect企业应用展望章节会进行介绍)。关键字:增强现实、Google Project Glass 、Kinect虚拟试衣镜
1.1.5 多点触摸:信息就在指尖
iPhone、iPad的多点触摸已普遍渗入到人的日常生活中,几乎将现在所有的智能手机的交互方式都更新了一遍。事实上,微软才是多点触控技术的先行者,Microsoft Surface比iPad更早提供了多点触控(Multi-Touch)的功能,可以让多人同时使用Surface多点触控,而iPad只支持一个人的操作。比如把信用卡放在Surface上,用户则可以选择付账等下一步操作。Surface甚至可以识别一瓶可乐或识别你的智能手机,来交互音乐或照片(见图1-14),这有些类似于NFC(近场数据通信)。Surface这类交互设备应属于机器视觉交互的范畴,和iPhone、iPad的原理不同,它是由位于底部的多个摄像机实时获取人手指的位置和运动信息的,然后进行分割识别处理而得到交互语义,如图1-15所示。
电影《007:大破量子危机》也出现过Surface的场景:在007总部中情六局的办公室里,数名特工围着一个可触摸的“办公桌”(就是Microsoft Surface)进行讨论。此外,微软研究团队正在开发一种名为OmniTouch的新技术,通过“3D动作感应”技术和一个投影仪可以让日常物体的表面变成一个触控屏。该项技术与Kinect的体感技术非常相似。关键字:多点触摸、iPhone、iPad、Microsoft Surface
1.1.6 语音识别:从ViaVoice到Siri
大约在计算机芯片还是MMX166的奔腾时代时,IBM就推出过一款ViaVoice的语音识别软件,提起它多少有点技术考古的意味。比它更早的就是电影《2001太空漫游》中的片段。下面的对话会不会让你出一身冷汗?也许若干年后真正的HAL9000出现的时候,Siri会被追认为前身,如图1-16所示。Dave Bowman: Open the pod bay doors, HAL.(打开求生舱门,HAL)HAL9000: I'm sorry Dave, I'm afraid I can't do that. Are you happy now? (抱歉,我恐怕不能这么做。你现在开心吗?)
HAL9000通过“唇语”读懂玻璃舱后宇航员的对话,也是影片中精彩的一段。研究表明,基于视觉识别的唇语有助于提高语音识别的命中率和性能。Siri的出现,再次唤起用户对自然语音交互的渴望。目前,语音识别的发展在呼叫中心也得到了长足的应用,将原有烦琐的按键式提示改成更具人性化的交谈式语音交互。比如,你可以拿起电话直接说:“我要挂失信用卡”,而不用枯燥地按照话音数字提示去操作按键。你也许有过这样的体验,听到一首动听的歌,迫切想知道它的名称。现在微软最新的Windows Phone 7.5手机里就集成了这一功能(Bing Audio),你让手机也听上一小段,它就会告诉你音乐的演唱者等相关信息,如图1-17所示。这是一种声纹特征分析的技术,很酷,不是吗?类似的软件还有Shazam。后面在介绍Kinect for Windows SDK开发时,会介绍如何结合Microsoft Speech API进行语音控制开发。此外,语音识别还可以利用到微软的Tellme语音识别云服务。
关键字:语音识别、Siri、Bing Audio、Tellme
1.1.7 眼球跟踪:从霍金的座椅谈起
霍金有一个神奇的座椅,上面安装有一个眼球跟踪红外感应器,他通过眨眼来和外界交流,用眼球控制计算机造句,然后语音合成后发音,如图1-18所示。
眼球跟踪技术也被用在了其他方面,比如日本佳能公司生产的高端相机可以用眼球来控制相机的对焦点。眼球跟踪技术也可以让屏幕理解我们的阅读意图。例如,到了文章的末尾时自动翻页;凝视某一个单词时,会显示该单词的含义。目前,眼动跟踪技术可以帮助残障人士操作计算机、帮助眼科医生进行眼部疾病诊断、检测婴幼儿的认知能力。在医院的重症监护室,一些无法用语言表达意愿的危重病人,也可以通过该项技术和医护人员交流。眼球追踪技术极具潜力,在个人设备领域能够带来附加价值。目前,瑞典Tobii眼球追踪技术公司有相关技术和成熟产品。此外,微软的产品在开发中有一个交互体验测试的环节,也采用了眼球跟踪技术来分析软件操作的热点,归纳出用户特别关注的信息和功能按钮,从而进一步改进用户体验。一些大型社交网站如Facebook也利用眼球跟踪技术进行信息热点分析。如图1-19所示,个人头像和顶端第一条更新的信息获得了最大的关注度。为了捕捉眼睛的注视点,眼动跟踪仪发射出不可见的红外线,然后通过传感器采集并分析从眼球反射回来的信号,一般还分虹膜、瞳孔两个不同的层次。综合眼睛颜色和周围环境光,眼动跟踪仪区分“亮瞳”和“暗瞳”并进行亮、暗瞳图像差分和滤波,从而精确跟踪瞳孔的位置、捕捉视线的方向。笔者体验过一款名为《行星乱舞》(Asteroids)的游戏,可以用“目光”击落飞舞的小行星,由此看来“目光”也是一种“光”啊。另外,生活中你一定听说过“激光治疗近视”,该项手术需要精湛的医术,一般手术设备都具备优良的眼球运动跟踪系统,保障激光在眼球光学中心的精准切削。
从原理上来看,眼球跟踪和Kinect还真的非常相似。为了宣传Kinect的潜能,微软曾在E3上公布过一个人工智能小孩—米罗(Milo),如图1-20所示。他通过Kinect理解你的动作和行为,他可以记住你的脸,理解你脸上的表情,他会很有感情地注视着你的眼睛说话。如果他看到你有黑眼圈,甚至会问你是不是熬夜了。他能从你的语气中猜测你的情绪,并做出回应。最惊讶的一幕是,你拿一张纸条递到他面前,米罗会和你交换个眼神,并从游戏里伸手接过你的字条,看你写了什么。这就是Kinect的“眼球跟踪”技术,尽管没有在Xbox游戏中体现。你是不是跃跃欲试呢?
关键字:眼球跟踪、霍金座椅、热点分析、激光治疗近视
1.1.8 人脸识别:Photo DNA
人脸识别是个非常有趣的话题。《碟中谍4》影片一开场就有位特工挂掉,留给同伴的线索是他的iPhone手机。该手机的自动人脸识别系统识别出了偷袭者的杀手身份。前面,我们在谈论增强显示时也提到这样的片段:阿汤哥的“间谍眼镜”提醒前方的美女是一个冷血杀手。背后的技术就是“人脸识别”技术,如图1-21所示。
在日常生活中,人脸识别技术也被广泛应用,如在公安、机场、边防口岸、安防、智能门禁、考勤等领域。识别人脸绝非易事。举个例子,在公共安全领域应用,希望通过“人脸识别”来甄别嫌疑犯,这需要在全国流窜犯的数据库中进行实时匹配。大人群中甄别的挑战,一方面在于人脸原始特征采集的质量,以及识别搜索的准确度和效率;另一方面在于同一个人的变化,这是更大的难点。同一个人的面部在不同照明、表情或姿势等因素影响下的变化,有时会致使出现“判若两人”的识别结果。除了传统的身份识别应用外,比较简单的应用还包括Google Android 4.0系统的面部识别解锁等功能,比如三星的Galaxy Nexus就支持这项功能。人脸识别还可以用作社交网络的相册聚合服务。它可从你好友相册中自动去识别和你相册中出现的人脸有关的照片,比如Facebook等社交网络在照片标签服务中引入面部识别技术,自动事件(活动、聚会)匹配,综合拍摄日期、照片内的人脸、照片颜色识别出同一事件的照片。同样,Windows Live Photo Gallery能够识别区分照片中的人物,并据此实现照片自动分组。谷歌Picasa和苹果iPhoto等照片软件和在线服务也同样支持这项功能。受此启发,如果我们的手机相册也内嵌该功能,同时还可以点击相册的人脸拨打电话,也不失是个好主意哦。似乎以色列的很多公司在计算机视觉领域有着相当高的水准,这里不得不提到face.com。Facebook应用的人脸识别技术就是来自这家以色列公司。face.com算是术业有专攻,其产品除了基本的人脸识别外,还可以分析人脸上的表情等信息,甚至也可以分析出相片中主角的年龄、情绪以及戴没戴眼镜。贩卖儿童应该是这个世界最邪恶的事情之一。2012年3月19日,微软给警方提供了一套智能图像匹配软件,帮助警方解救这些儿童。这项技术称为Photo DNA。通过这项技术,也许有一天,你在街头看见一流浪儿,你可以用手机给他拍摄一张照片然后上传,同时包含Where(GPS采集)、When(拍摄时间)、Who(照片)、What(事件:发现流浪小孩)。后台经过智能匹配,会给警方和丢失孩子的父母提供有价值的线索。通过以上介绍可以看出,人脸识别意义重大。尽管Kinect for Xbox 360只是一款电子消费产品,但其可以通过“人脸识别”记住不同的玩家,从而提供更为个性化的体验,比如记录最近玩过的游戏,当你中途退出游戏又再次回来时,立刻认出“你是谁”。它已经成为Xbox游戏体验的一部分,你只是站在那里,Kinect就会知道你是谁。关键字:人脸识别、相册聚合、Photo DNA、face.com
1.1.9 体感操作:达芬奇手术机器人
达芬奇机器人手术系统是由美国Intuitive Surgical公司研制的机器人辅助微创外科手术系统。它主要由一个手术机械手控制台、一个装有四支7自由度交互手臂的手术台和一个高精度的3D高清视觉系统构成,如图1-22所示。
以文艺复兴时期三杰之一“达芬奇”的名字命名,是因为它被公认为是第一台类人机器人。机器人手术不仅使外科医生受益,也是患者的福音。机器人手术可以将复杂的手术过程简化,减少病人手术过程中的疼痛和失血量,并可以缩短术后恢复时间。这里,机器成为人体自然的延伸部分。或许在不远的未来,我们可以在地面用体感操作远在火星的探测车采集大气和岩石标本。关键字:达芬奇手术机器人、机器成为人体自然的延伸部分、体感操作
1.1.10 脑机界面:霍金座椅的升级版
我们谈论科幻电影《阿凡达》时提到过“脑机接口”:在潘多拉星上,下身瘫痪的前海军战士杰克萨利躺在密封舱中,通过头上戴着的复杂设备,利用意念操控人造的混血阿凡达。“脑机接口”目前还处于相当前沿的阶段。其核心原理是捕捉“脑电波”的变化,进而与外界系统进行交互。比如思考问题时大脑会产生0.2~1mV的电压。美国科学家通过功能性核磁共振(fMRI),探测大脑周围的血液流动,能够准确猜测出参与者脑中所想的事物,并还原为灰阶的图像,准确率高达80%左右,为FBI提供了“读心术”的新式武器。前面在介绍“眼球跟踪”时提到过霍金的座椅。霍金患的是卢伽雷氏症,他现在连手指都不能活动,眼球活动也很困难,以前一分钟能说15个单词,现在1分钟说1个单词,思维表达几乎快被封冻住了。他以前的座椅显得有些无能为力,还好现在有了新的转机,这位天才物理学家的座椅有了升级版—iBrain。由NeuroVigil公司研制的iBrain,能捕获人类思维并将其转化为相应的计算机指令。《生活大爆炸》(The Big Bang Theory)第5季第21集中,霍金客串出演,据说就使用了这套装备。关键字:脑机界面、iBrain
文章
机器人 · 人机交互 · vr&ar · 计算机视觉 · iOS开发
2017-08-01
计算机视觉技术在物联网中的发展与应用
计算机视觉的发展演进我们可以轻松地在日常产品中找到计算机视觉技术的应用,从可以识别手势的游戏机到可以自动聚焦于人脸的智能手机摄像头。如今,计算机视觉正在影响我们生活的许多领域。
实际上,计算机视觉在商业和政府使用中已有悠久的历史。可以感测各种光谱范围内的光波的光学传感器已在许多应用中部署:像制造中的产品质量检测,用于环境管理的遥感或在战场上收集情报的高分辨率相机。这些传感器中的一些是固定的,而另一些则附着在移动的物体上,例如卫星、无人机和车辆。
过去,这些计算机视觉应用中有许多都限于某些封闭的平台。但是,当与IP连接技术结合使用时,它们会创建一套以前无法实现的新应用。计算机视觉,再加上IP连接性、高级数据分析和人工智能,将成为彼此的催化剂,从而引发物联网(IoT)创新和应用的革命性飞跃。
推动计算机视觉的多个领域的进步
专为视觉设计的环境视力或视觉是人类五种感官中最发达的。我们每天都使用它来认识我们的朋友、发现前进道路上的障碍、完成任务并学习新事物。我们设计视觉环境的物理环境,有路标和信号灯可以帮助我们从一个地方到达另一个地方;商店有标牌来帮助我们找到它们;电脑和电视屏幕显示我们消费的信息和娱乐。考虑到视觉的重要性,将其扩展到计算机和自动化领域并不是一个大飞跃。
什么是计算机视觉?计算机视觉始于捕获和存储图像或一组图像的技术,然后将这些图像转换为可以进一步作用的信息。它由多种技术共同组成(图1)。计算机视觉工程是一个跨学科领域,需要许多这些技术的跨功能和系统专业知识。
例如,Microsoft Kinect使用3D计算机图形算法来使计算机视觉能够分析和理解三维场景。它允许游戏开发人员将实时的全身运动捕捉与人工3D环境合并。除了游戏以外,这还在机器人技术、虚拟现实(VR)和增强现实(AR)应用等领域开辟了新的可能性。
传感器技术的进步也在许多方面超越了传统的相机传感器而迅速发展。最近的一些例子包括:
红外传感器和激光结合起来可感应深度和距离,这是自动驾驶汽车和3D映射应用的关键推动力之一非侵入式传感器,无需物理接触即可跟踪医疗患者的生命体征高频摄像头可以捕捉人眼无法察觉的细微动作,帮助运动员分析步态超低功耗和低成本视觉传感器,可以长时间部署在任何地方
图1.由多个领域的进步推动的计算机视觉。图片来源:IFA
计算机视觉变得智能
早期应用监控行业是图像处理技术和视频分析的较早采用者之一。视频分析是计算机视觉的一种特殊用例,其重点是从数小时的录像中查找模式。在现实世界中自动检测和识别预定义模式的能力代表着数百个用例的巨大市场机会。
首批视频分析工具使用手工算法来识别图像和视频中的特定功能。它们在实验室设置和模拟环境中都是准确的。但是,当输入数据(例如光照条件和摄像机视图)偏离设计假设时,性能会迅速下降。
研究人员和工程师花了很多年时间开发和调整算法,或者提出新的算法来应对不同的条件。但是,使用这些算法的摄像机或录像机仍然不够坚固。尽管这些年来取得了一些渐进的进步,但现实世界的糟糕表现限制了该技术的实用性和采用性。
深度学习突破近年来,深度学习算法的出现重新激发了计算机视觉。深度学习使用模仿人类大脑神经元的人工神经网络(ANN)算法。
从2010年代初开始,通过图形处理单元(GPU)加速的计算机性能已经变得足够强大,足以让研究人员实现复杂的人工神经网络的功能。此外,部分地受视频站点和流行的IoT设备驱动,研究人员拥有庞大的视频和图像数据库来训练他们的神经网络。
2012年,一种称为卷积神经网络(CNN)的深度神经网络(DNN)版本在准确性上实现了巨大飞跃。这一发展带动了人们对计算机视觉工程领域的兴趣和兴奋。现在,在需要图像分类和面部识别的应用中,深度学习算法甚至超过了人类。更重要的是,就像人类一样,这些算法具有学习和适应不同条件的能力。
图2.场景的语义表示
随着深度学习的发展,我们正在进入认知技术的时代,其中计算机视觉和深度学习融合在一起,以解决人脑领域中的高级复杂问题(图2)。我们只是在探索一切可能的事物。随着更快的处理器,更先进的机器学习算法以及与边缘设备的更深入集成,这些系统将继续得到改善。计算机视觉将彻底改变物联网。用例增加其他有趣的用例包括:监控作物健康的农业无人机(http://www.slantrange.com/)(图3)运输基础设施管理(http://www.vivacitylabs.com/)无人机检查(http://industrialskyworks.com/drone-inspections-services/)下一代家庭安全摄像头(https://buddyguard.io/)
图3.从无人机收集的图像中的植被指数(来源:Emmetts,www.emmetts.com.au)
这些只是计算机视觉如何在许多领域极大地提高生产力的一些小例子。我们正在进入物联网发展的下一阶段。在第一阶段,我们专注于连接设备,聚合数据和构建大数据平台。在第二阶段,重点将转移到通过计算机视觉和深度学习等技术使“事物”更加智能,生成更多可操作的数据。
挑战在让计算机视觉技术对大众更实用和更经济时,有许多问题需要克服:嵌入式平台需要集成深度神经设计。由于功耗、成本、准确性和灵活性,很难做出设计决定。业界需要标准化,以允许智能设备和系统相互通信并共享元数据。系统不再是数据的被动收集器。他们需要以最少的人工干预就数据采取行动。他们需要自己学习和即兴创作。整个软件/固件更新过程在机器学习时代具有新的意义。黑客可以利用计算机视觉和AI中的新安全漏洞。设计师需要考虑到这一点。
原文链接:http://ai.qianjia.com/html/2020-09/04_370313.html本文转载自千家网,本文一切观点和机器智能技术圈子无关
文章
机器学习/深度学习 · 传感器 · 人工智能 · 监控 · 算法 · 安全 · 物联网 · 测试技术 · vr&ar · 计算机视觉
2020-09-09
擂台:灵异视频辨真伪
“大数据”和传统的数据最本真的区别就是:数据的形态变了,比以前更加多样,携带的信息更加丰富,因而对数据分析的要求更高了。西方有句话叫“Rubbish in rubbish out”。从数据处理的角度看,就是要保证数据的真实性,否则后续的分析意义不大。那么“视频”作为一种信息丰富的数据源,它的真实性如何保证?怎样验证呢?让我们以这个视频为例,诚邀您进行分析。
奖励
(1)如果您的方案足够好,我们会在文摘上发布,为您和您的公司做广告
(2)如果您来北京或在北京,大数据文摘创办人愿意请您吃饭,也许还有文摘团队的美女哦:)
投稿请发邮件 wangdc@bigdatadigest.cn
邮件标题:打擂:灵异视频识别(XXX公司or个人)
今日奉上干货文章
当机器学习遇上计算机视觉
作者:Jamie Shotton,Antonio Criminisi,Sebastian Nowozin
机构:微软剑桥研究院
译者:andydoo,kbyran
摘自:译言(www.yeeyan.org)
计算机视觉在上一个世纪60年代脱胎于人工智能与认知神经科学,旨在通过设计算法来让计算机自动理解图像的内容。为了“解决”机器视觉的问题,1966年,在麻省理工学院,这个问题作为一个夏季项目被提出,但是人们很快发现要解决这个问题可能还需要更长时间。在50年后的今天,一般的图像理解任务仍旧是不能得到完美解决。但是也已取得显著进展,并且随着机器视觉算法商业化的成功,机器视觉产品已经开始拥有广泛的用户,包括图像分割(例如微软office中去除图片背景的功能)、图像检索、人脸检测对焦和Kinect的人体运动捕捉等。几乎可以确定的是机器视觉最近的突飞猛进主要得益于最近15到20年机器学习领域的快速发展。
本主题的第一篇文章主要是探索一下机器视觉所面临的挑战和介绍一个非常重要的机器学习技术——像素级分类决策树算法。
图像分类
想像一下并试着回答下面这个有关图像分类的问题:“在这张图片中有一辆汽车吗”。对于计算机来说,一张图片仅仅是由三原色(红、绿、蓝)构成的像素组成的格子,三原色中每一个颜色通道的值的范围都是0到255。这些值的改变不仅依赖于事物对象是否在图片中呈现,也依赖于一些干扰事件,比如摄像机的视角、灯光条件、背景和对象的形态。另外,一个必须处理的问题是不同类别的汽车呈现不同的形状。例如,这辆汽车可能是辆旅行车、或者小卡车、或者是辆跑车,这些都会对图片像素造成很大影响。
幸运的是监督机器学习算法提供了替代原本需要人工编码解决这些多可能性的问题的方式。通过收集图片的训练集和适当的人工标记每一张训练图片,我们能够使用最好的机器学习算法找到哪些像素模式是同要识别的对象相关的以及哪些是干扰因素产生的。我们希望我们的算法最终能够适用于识别以前没有经过训练的新的样本,并且对于噪声保持不变性。在新的机器视觉算法的发展和数据集的收集标注两个方面我们都取得了长足的进步。
像素级分类决策树算法
图片在很多层面上包含细节。就像前面我们提到的,我们可以问一个问题——在整张图片中是否有一个特定的对象类别(比如汽车)。现在我们可以问一个更难点的问题——这张图里都包含了什么,这就变成了一个著名的问题“图像语义分割”:提取图片场景中所有的对象。例如下面街道场景的图片
你可以想象一下,这可以用于帮助你有选择的编辑一些照片,或者用于拼接一张全新的照片;我们还能马上想出更多的应用场景。
解决语义分割问题可以有很多方法,但是一个最有效的算法是像素级分类:训练一个分类器在像素级别预测每一个对象(如汽车、街道、树、墙等)分布情况。这个任务带给机器学习一些计算问题,特别是图片包括很多的像素的时候(例如,诺基亚1020智能手机拍照的像素是4100万像素)。这就意味着整个运算时间是我们分类任务全部训练和测试样本图片乘以几百万的倍数。
这个问题的规模促使我们寻找一个更有效的分类模型——决策树(也称为随机树或随机决策树)。一个决策树是一个分离训练后的决策树的集合,如下图所示。
每一决策树都有一个根节点,多个内部“分支”节点,和多个叶子节点。测试分类时,从根节点开始,并且计算二叉“分支函数”,这个函数可能就像“这个像素是否比它的邻域像素更红”一样简单。根据该二元决策,它将沿分支向左或向右,接下来查看下一个“分支函数”,一直重复这样的操作。当最终达到叶子节点,一个存储的预测——通常是一个包含类别标签的直方图——就是输出(你也可以去看一下ChrisBurges最近的一篇非常出色的论文,是关于提升变种决策树在搜索排名中的应用)。
决策树的美在于他的执行效率:虽然从根节点到叶子节点包含指数级可能的路径,但是任意一个独立的测试像素仅仅通过一个路经。此外,分支函数的计算是以此前的事件为条件的:例如,分类器只需要依赖此前分支决策的答案提出正确的问题就行了。这很像“20问”游戏:当你仅被允许去问少量问题时,你可以很快学会根据你以前问题的答案来调整自己要提出的下一个问题。
有了这项技术,我们已经能够成功处理这些不同的问题,如照片的语义分割,街头的场景分割,人体解剖学的3D医学扫描图像分割,摄像头的重定位和使用Kinect深度摄像头对人体身体部位的划分。对于Kinect来讲,决策树测试时间效率是关键:我们有一个非常严格的计算预算,但是这样的计算要求搭配XboxGPU并行处理像素的能力,意味着我们能够适应这种应用场景。
深层神经网络
在过去的几年里,我们视觉研究者所使用的测试数据集无论在质量上,还是数量上都有了快速的提高。这些进步在很大程度归因于吸收了众包的成果。众包项目允许我们把数百万张已标记图像加入测试数据集。其中一个最具挑战性的测试数据集ImageNet,就包含了数万个种类、超过百万张已标注层次的图像。
然而多年来,对ImageNet测试数据集的识别工作进展较缓慢,直到2012年,Krizhevsky等人的成果震惊了业界。他们使用通用GPU配合一些看似细微的算法改进,从而更深层次地训练卷积神经网络。最终,他们在ImageNet的1000个分类测试中显著提升了图像分类的准确性。这项成果还赢得了大众媒体的关注,甚至导致相关的初创公司被大笔收购。自从那以后,“深度学习”开始成为计算机视觉领域的热门话题,而最近发表的文章也开始涵盖到物体定位、脸部识别和人体姿势识别等与“深度学习”息息相关的内容。
展望未来
深度卷积网络毫无疑问是相当强大的,然而它真的能解决计算机视觉领域的一切问题吗?可以肯定的是,它还会继续火热下去并且推动业界未来几年的发展,同时我们也相信未来还会有新的突破性进展。谁也说不准会有哪些突破,但我们会为你预测一些我们认为很有可能实现的突破点:
语义分析:以上的网络模型只能学会理解图像内容的表意,而不能深入理解图像中各个物体、物体之间如何相互联系以及特定物体在生活情景中的作用,例如我们不能轻率地根据头发看起来会有点光泽,和他们拿着电吹风这一事实,很有把握地推断他们的头发是湿的。像微软CoCo这样的新型测试数据集就可以帮助增强语义分析。该数据集对抽象图像提供非常详尽的分类标注,例如包含多个主体的图像会被标记出不重要的部分。
运行效率:虽然对测试图片的深度网络评估过程可以通过并行计算来加速,但是神经网络的构造并没有在上一篇中提及的逻辑运算概念:每一个训练样例必须通过遍历网络中的所有节点来输出结果。再者,即使配备高速的GPU,训练网络也要花费数天甚至数周,这使得深度网络不能快速投入试用。
结构学习:经过多年的研究发展,深度卷积网络现在拥有一个设计完善、相对死板的结构。也就是说,改变某一层大小或层级的数量会对模型做出预测的能力产生不良影响。除了简单粗暴地输入特定参数来最优化网络的形态,我们希望可以真正地直接从数据中学习出更加灵活的网络结构。
近年来,我们已经开始寻找突破这些瓶颈的方案。现在,我们很高兴能向你推荐我们最新的成果,决策丛林模型:根部相连接的决策有向无环图。你可以认为决策有向无环图是子节点相通的决策树,因此一个子节点可以存在多个父节点。我们不但证明了这种模型在内存消耗上比决策树降低了一个数量级,同时还能大大提高模型的泛化能力。有向无环图起初看起来很像神经网络,但是有两个重要的不同点:第一,其结构和模型参数都是从数据中学习而来的;第二,有向无环图保留了决策树中高效的逻辑运算:一个测试样例只沿着有向无环图的一条路径传递,而不是像神经网络一样遍历所有节点。我们正在积极尝试结合其他深度学习的形态,譬如结果的复用和树节点的纠缠,使得决策丛林能够真正有效地替代深度神经网络。
如果你对运用决策丛林模型解决问题感兴趣,Azure机器学习云平台中的Gemini模块将能带你探索得更深入。
总的来说,计算机视觉的前途一片光明,其中很大程度归功于机器学习。即便近年来视觉领域的快速发展已经让人难以置信了,但我们认为计算机视觉的研究未来还会震惊世界。
原文发布时间为:2015-07-12
本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
文章
机器学习/深度学习 · 算法 · 大数据 · 测试技术 · 计算机视觉
2017-05-02
计算机视觉技术在物联网中的发展与应用
计算机视觉的发展演进我们可以轻松地在日常产品中找到计算机视觉技术的应用,从可以识别手势的游戏机到可以自动聚焦于人脸的智能手机摄像头。如今,计算机视觉正在影响我们生活的许多领域。
实际上,计算机视觉在商业和政府使用中已有悠久的历史。可以感测各种光谱范围内的光波的光学传感器已在许多应用中部署:像制造中的产品质量检测,用于环境管理的遥感或在战场上收集情报的高分辨率相机。这些传感器中的一些是固定的,而另一些则附着在移动的物体上,例如卫星、无人机和车辆。
过去,这些计算机视觉应用中有许多都限于某些封闭的平台。但是,当与IP连接技术结合使用时,它们会创建一套以前无法实现的新应用。计算机视觉,再加上IP连接性、高级数据分析和人工智能,将成为彼此的催化剂,从而引发物联网(IoT)创新和应用的革命性飞跃。
推动计算机视觉的多个领域的进步
专为视觉设计的环境视力或视觉是人类五种感官中最发达的。我们每天都使用它来认识我们的朋友、发现前进道路上的障碍、完成任务并学习新事物。我们设计视觉环境的物理环境,有路标和信号灯可以帮助我们从一个地方到达另一个地方;商店有标牌来帮助我们找到它们;电脑和电视屏幕显示我们消费的信息和娱乐。考虑到视觉的重要性,将其扩展到计算机和自动化领域并不是一个大飞跃。
什么是计算机视觉?计算机视觉始于捕获和存储图像或一组图像的技术,然后将这些图像转换为可以进一步作用的信息。它由多种技术共同组成(图1)。计算机视觉工程是一个跨学科领域,需要许多这些技术的跨功能和系统专业知识。
例如,Microsoft Kinect使用3D计算机图形算法来使计算机视觉能够分析和理解三维场景。它允许游戏开发人员将实时的全身运动捕捉与人工3D环境合并。除了游戏以外,这还在机器人技术、虚拟现实(VR)和增强现实(AR)应用等领域开辟了新的可能性。
传感器技术的进步也在许多方面超越了传统的相机传感器而迅速发展。最近的一些例子包括:
红外传感器和激光结合起来可感应深度和距离,这是自动驾驶汽车和3D映射应用的关键推动力之一非侵入式传感器,无需物理接触即可跟踪医疗患者的生命体征高频摄像头可以捕捉人眼无法察觉的细微动作,帮助运动员分析步态超低功耗和低成本视觉传感器,可以长时间部署在任何地方
图1.由多个领域的进步推动的计算机视觉。图片来源:IFA
计算机视觉变得智能
早期应用监控行业是图像处理技术和视频分析的较早采用者之一。视频分析是计算机视觉的一种特殊用例,其重点是从数小时的录像中查找模式。在现实世界中自动检测和识别预定义模式的能力代表着数百个用例的巨大市场机会。
首批视频分析工具使用手工算法来识别图像和视频中的特定功能。它们在实验室设置和模拟环境中都是准确的。但是,当输入数据(例如光照条件和摄像机视图)偏离设计假设时,性能会迅速下降。
研究人员和工程师花了很多年时间开发和调整算法,或者提出新的算法来应对不同的条件。但是,使用这些算法的摄像机或录像机仍然不够坚固。尽管这些年来取得了一些渐进的进步,但现实世界的糟糕表现限制了该技术的实用性和采用性。
深度学习突破近年来,深度学习算法的出现重新激发了计算机视觉。深度学习使用模仿人类大脑神经元的人工神经网络(ANN)算法。
从2010年代初开始,通过图形处理单元(GPU)加速的计算机性能已经变得足够强大,足以让研究人员实现复杂的人工神经网络的功能。此外,部分地受视频站点和流行的IoT设备驱动,研究人员拥有庞大的视频和图像数据库来训练他们的神经网络。
2012年,一种称为卷积神经网络(CNN)的深度神经网络(DNN)版本在准确性上实现了巨大飞跃。这一发展带动了人们对计算机视觉工程领域的兴趣和兴奋。现在,在需要图像分类和面部识别的应用中,深度学习算法甚至超过了人类。更重要的是,就像人类一样,这些算法具有学习和适应不同条件的能力。
图2.场景的语义表示
随着深度学习的发展,我们正在进入认知技术的时代,其中计算机视觉和深度学习融合在一起,以解决人脑领域中的高级复杂问题(图2)。我们只是在探索一切可能的事物。随着更快的处理器,更先进的机器学习算法以及与边缘设备的更深入集成,这些系统将继续得到改善。计算机视觉将彻底改变物联网。用例增加其他有趣的用例包括:监控作物健康的农业无人机(http://www.slantrange.com/)(图3)运输基础设施管理(http://www.vivacitylabs.com/)无人机检查(http://industrialskyworks.com/drone-inspections-services/)下一代家庭安全摄像头(https://buddyguard.io/)
图3.从无人机收集的图像中的植被指数(来源:Emmetts,www.emmetts.com.au)
这些只是计算机视觉如何在许多领域极大地提高生产力的一些小例子。我们正在进入物联网发展的下一阶段。在第一阶段,我们专注于连接设备,聚合数据和构建大数据平台。在第二阶段,重点将转移到通过计算机视觉和深度学习等技术使“事物”更加智能,生成更多可操作的数据。
挑战在让计算机视觉技术对大众更实用和更经济时,有许多问题需要克服:嵌入式平台需要集成深度神经设计。由于功耗、成本、准确性和灵活性,很难做出设计决定。业界需要标准化,以允许智能设备和系统相互通信并共享元数据。系统不再是数据的被动收集器。他们需要以最少的人工干预就数据采取行动。他们需要自己学习和即兴创作。整个软件/固件更新过程在机器学习时代具有新的意义。黑客可以利用计算机视觉和AI中的新安全漏洞。设计师需要考虑到这一点。
总结在这篇文章中,我们简要介绍了计算机视觉以及它如何成为许多连接的设备和应用的关键组成部分。最重要的是,我们预测了该技术的爆炸式增长,并列举了实际应用中的一些障碍。在下一系列文章中,我们将探索新的框架,最佳实践和设计方法,以克服一些挑战。原文链接:http://ai.qianjia.com/html/2020-09/04_370313.html本文转载自千家网,本文一切观点和阿里云视觉智能开放平台无关
如果大家对视觉AI能力感兴趣,欢迎访问视觉智能开放平台进行AI能力的开通及调试。【点我一键开通】阿里云视觉智能开放平台(vision.aliyun.com)是基于阿里巴巴视觉智能技术实践经验,面向视觉智能技术的开发与应用用户,为其提供好用、易用、普惠的视觉智能API服务,帮助企业和开发者快速建立视觉智能技术的应用能力的综合性视觉AI算法平台,目前已开放9大类目,120+种AI能力,平台95%以上的能力限时免费调用,别犹豫啦,快来体验吧!【0代码在线体验百种AI能力】
文章
机器学习/深度学习 · 传感器 · 人工智能 · 监控 · 算法 · 安全 · 物联网 · 测试技术 · vr&ar · 计算机视觉
2020-09-08
详述机器人的5种定位技术
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
随着传感技术、智能技术和计算技术等的不断提高,智能移动机器人一定能够在生产和生活中扮演人的角色。那么移动机器人定位技术主要涉及到哪些呢?经总结目前移动机器人主要有这5大定位技术。
移动机器人超声波导航定位技术
超声波导航定位的工作原理也与激光和红外类似,通常是由超声波传感器的发射探头发射出超声波,超声波在介质中遇到障碍物而返回到接收装置。
通过接收自身发射的超声波反射信号,根据超声波发出及回波接收时间差及传播速度,计算出传播距离S,就能得到障碍物到机器人的距离,即有公式:S=Tv/2式中,T—超声波发射和接收的时间差;v—超声波在介质中传播的波速。
当然,也有不少移动机器人导航定位技术中用到的是分开的发射和接收装置,在环境地图中布置多个接收装置,而在移动机器人上安装发射探头。
在移动机器人的导航定位中,因为超声波传感器自身的缺陷,如:镜面反射、有限的波束角等,给充分获得周边环境信息造成了困难,因此,通常采用多传感器组成的超声波传感系统,建立相应的环境模型,通过串行通信把传感器采集到的信息传递给移动机器人的控制系统,控制系统再根据采集的信号和建立的数学模型采取一定的算法进行对应数据处理便可以得到机器人的位置环境信息。
由于超声波传感器具有成本低廉、采集信息速率快、距离分辨率高等优点,长期以来被广泛地应用到移动机器人的导航定位中。而且它采集环境信息时不需要复杂的图像配备技术,因此测距速度快、实时性好。
同时,超声波传感器也不易受到如天气条件、环境光照及障碍物阴影、表面粗糙度等外界环境条件的影响。超声波进行导航定位已经被广泛应用到各种移动机器人的感知系统中。
移动机器人视觉导航定位技术
在视觉导航定位系统中,目前国内外应用较多的是基于局部视觉的在机器人中安装车载摄像机的导航方式。在这种导航方式中,控制设备和传感装置装载在机器人车体上,图像识别、路径规划等高层决策都由车载控制计算机完成。
视觉导航定位系统主要包括:摄像机(或CCD图像传感器)、视频信号数字化设备、基于DSP的快速信号处理器、计算机及其外设等。现在有很多机器人系统采用CCD图像传感器,其基本元件是一行硅成像元素,在一个衬底上配置光敏元件和电荷转移器件,通过电荷的依次转移,将多个像素的视频信号分时、顺序地取出来,如面阵CCD传感器采集的图像的分辨率可以从32×32到1024×1024像素等。
视觉导航定位系统的工作原理简单说来就是对机器人周边的环境进行光学处理,先用摄像头进行图像信息采集,将采集的信息进行压缩,然后将它反馈到一个由神经网络和统计学方法构成的学习子系统,再由学习子系统将采集到的图像信息和机器人的实际位置联系起来,完成机器人的自主导航定位功能。
GPS全球定位系统
如今,在智能机器人的导航定位技术应用中,一般采用伪距差分动态定位法,用基准接收机和动态接收机共同观测4颗GPS卫星,按照一定的算法即可求出某时某刻机器人的三维位置坐标。差分动态定位消除了星钟误差,对于在距离基准站1000km的用户,可以消除星钟误差和对流层引起的误差,因而可以显着提高动态定位精度。
但是因为在移动导航中,移动GPS接收机定位精度受到卫星信号状况和道路环境的影响,同时还受到时钟误差、传播误差、接收机噪声等诸多因素的影响,因此,单纯利用GPS导航存在定位精度比较低、可靠性不高的问题,所以在机器人的导航应用中通常还辅以磁罗盘、光码盘和GPS的数据进行导航。另外,GPS导航系统也不适应用在室内或者水下机器人的导航中以及对于位置精度要求较高的机器人系统。
移动机器人光反射导航定位技术
典型的光反射导航定位方法主要是利用激光或红外传感器来测距。激光和红外都是利用光反射技术来进行导航定位的。
激光全局定位系统一般由激光器旋转机构、反射镜、光电接收装置和数据采集与传输装置等部分组成。
工作时,激光经过旋转镜面机构向外发射,当扫描到由后向反射器构成的合作路标时,反射光经光电接收器件处理作为检测信号,启动数据采集程序读取旋转机构的码盘数据(目标的测量角度值),然后通过通讯传递到上位机进行数据处理,根据已知路标的位置和检测到的信息,就可以计算出传感器当前在路标坐标系下的位置和方向,从而达到进一步导航定位的目的。
激光测距具有光束窄、平行性好、散射小、测距方向分辨率高等优点,但同时它也受环境因素干扰比较大,因此采用激光测距时怎样对采集的信号进行去噪等也是一个比较大的难题,另外激光测距也存在盲区,所以光靠激光进行导航定位实现起来比较困难,在工业应用中,一般还是在特定范围内的工业现场检测,如检测管道裂缝等场合应用较多。
红外传感技术经常被用在多关节机器人避障系统中,用来构成大面积机器人“敏感皮肤”,覆盖在机器人手臂表面,可以检测机器人手臂运行过程中遇到的各种物体。
典型的红外传感器包括一个可以发射红外光的固态发光二极管和一个用作接收器的固态光敏二极管。由红外发光管发射经过调制的信号,红外光敏管接收目标物反射的红外调制信号,环境红外光干扰的消除由信号调制和专用红外滤光片保证。设输出信号Vo代表反射光强度的电压输出,则Vo是探头至工件间距离的函数:Vo=f(x,p)式中,p—工件反射系数。p与目标物表面颜色、粗糙度有关。x—探头至工件间距离。
当工件为p值一致的同类目标物时,x和Vo一一对应。x可通过对各种目标物的接近测量实验数据进行插值得到。这样通过红外传感器就可以测出机器人距离目标物体的位置,进而通过其他的信息处理方法也就可以对移动机器人进行导航定位。
虽然红外传感定位同样具有灵敏度高、结构简单、成本低等优点,但因为它们角度分辨率高,而距离分辨率低,因此在移动机器人中,常用作接近觉传感器,探测临近或突发运动障碍,便于机器人紧急停障。
SLAM技术
行业领先的服务机器人企业,大多都采用了SLAM技术。唯有(SLAMTEC)思岚科技在SLAM技术上独占优势,到底什么是SLAM技术呢?简单来说,SLAM技术是指机器人在未知环境中,完成定位、建图、路径规划的整套流程。
SLAM(Simultaneous Localization and Mapping,即时定位与地图构建),自1988年被提出以来,主要用于研究机器人移动的智能化。对于完全未知的室内环境,配备激光雷达等核心传感器后,SLAM技术可以帮助机器人构建室内环境地图,助力机器人的自主行走。
SLAM问题可以描述为:机器人在未知环境中从一个未知位置开始移动,在移动过程中根据位置估计和传感器数据进行自身定位,同时建造增量式地图。
SLAM技术的实现途径主要包括VSLAM、Wifi-SLAM与Lidar SLAM。
1.VSLAM(视觉SLAM)
指在室内环境下,用摄像机、Kinect等深度相机来做导航和探索。其工作原 理简单来说就是对机器人周边的环境进行光学处理,先用摄像头进行图像信息采集,将采集的信息进行压缩,然后将它反馈到一个由神经网络和统计学方法构成的学习子系统,再由学习子系统将采集到的图像信息和机器人的实际位置联系起来,完成机器人的自主导航定位功能。
但是,室内的VSLAM仍处于研究阶段,远未到实际应用的程度。一方面,计算量太大,对机器人系统的性能要求较高;另一方面,VSLAM生成的地图(多数是点云)还不能用来做机器人的路径规划,需要进一步探索和研究。
2.Wifi-SLAM
指利用智能手机中的多种传感设备进行定位,包括Wifi、GPS、陀螺仪、加 速计和磁力计,并通过机器学习和模式识别等算法将获得的数据绘制出准确的室内地图。该技术的提供商已于2013年被苹果公司收购,苹果公司是否已经把 Wifi-SLAM 的科技用到iPhone上,使所有 iPhone 用户相当于携带了一个绘图小机器人,这一切暂未可知。毋庸置疑的是,更精准的定位不仅有利于地图,它会让所有依赖地理位置的应用(LBS) 更加精准。
3.Lidar SLAM
指利用激光雷达作为传感器,获取地图数据,使机器人实现同步定位与地图构建。就技术本身而言,经过多年验证,已相当成熟,但Lidar成本昂贵这一瓶颈问题亟待解决。
Google无人驾驶汽车正是采用该项技术,车顶安装的激光雷达来自美国 Velodyne公司,售价高达7万美元以上。这款激光雷达可以在高速旋转时向周围发射64束激光,激光碰到周围物体并返回,便可计算出车体与周边物体的距离。计算机系统再根据这些数据描绘出精细的3D地形图,然后与高分辨率地图相结合,生成不同的数据模型供车载计算机系统使用。激光雷达占去了整车成本的一半,这可能也是 Google 无人车迟迟无法量产的原因之一。
激光雷达具有指向性强的特点,使得导航的精度得到有效保障,能很好地适应室内环境。但是,Lidar SLAM却并未在机器人室内导航领域有出色表现,原因就在于激光雷达的价格过于昂贵。
【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/zhibo
立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-04-01本文作者:人工智能产业链联盟本文来自:“人工智能产业链联盟公众号”,了解相关信息可以关注“人工智能产业链联盟”
文章
传感器 · 机器学习/深度学习 · 数据采集 · 编解码 · 人工智能 · 算法 · 机器人 · 定位技术 · 数据处理 · iOS开发
2020-04-02
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 读者信箱:hzit@hzbook.com
版权所有 ? 侵权必究
封底无防伪标均为盗版
本书法律顾问:北京大成律师事务所 韩光/邹晓东
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 find msg-type 根据服务类型查询服务。
rosservice info /service 输出服务信息。
rosservice list 列出活动服务清单。
rosservice type/service 输出服务类型。
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 set parameter value 设置参数值。
rosparam get parameter 获取参数值。
rosparam load file 从文件加载参数。
rosparam dump file 将参数保存到一个文件。
rosparam delete parameter 删除参数。
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中的使用说明和它们输出数据的可视化等。
文章
传感器 · 数据可视化 · 机器人 · 定位技术 · 计算机视觉
2017-05-02
《Arduino计算机视觉编程》一1.2 解决计算机视觉问题
####本节书摘来自华章出版社《Arduino计算机视觉编程》一书中的第1章,第1.2节,作者[土耳其] 欧森·奥兹卡亚(zen zkaya),吉拉伊·伊利茨(Giray Yilliki),更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1.2 解决计算机视觉问题
解决任何复杂的问题,比如计算机视觉问题,非常重要的一点就是通过理解每一步的目的来把问题分解成简单和可实现的子步骤。本章的目的是向你展示如何解决计算机视觉问题,以及如何用一个通用模型来对问题建模。本书讲解的实用计算机视觉系统的架构,由Arduino系统和OpenCV系统组合而成,如下图所示:
Arduino只负责从环境中收集感官信息,比如温度、湿度,然后把这些信息发给视觉系统控制器的OpenCV系统。视觉系统控制器和Arduino之间的通信可以是有线的,也可以是无线的,Arduino对于这两种方式处理起来都很容易。视觉系统处理完从Arduino和网络摄像头传过来的数据后,会检测或者识别出一个结论。比如,它设置可以识别出你的脸。下一步是根据这个结论来给Arduino系统发送指令,让Arduino采取合适的动作。这些动作可能是开风扇来让环境冷却,移动机械臂来给你递咖啡等。视觉控制器可以是台式电脑、笔记本电脑、手机,甚至是树莓派或者Beaglebone这样的迷你电脑!OpenCV可以在所有这些平台上运营,所以基本原则在这些平台上都是有效的。迷你电脑也可以做部分Arduino的工作。任何计算机视觉系统都由一系列边界清晰的设计模块组成,它们依次是数据采集、预处理、图像处理、后置过滤、识别(检测)和驱动。本书将针对这些步骤介绍一些详细实用的方案。我们把这些步骤对应到平台上具体实现,就可以得到一个计算机视觉系统的通用流程图。在下图中,你可以看到计算机视觉系统的通用处理流程:
1.2.1 数据采集
可以看到,视觉系统处理的第一步是数据采集,通常是收集来自环境的感官信息。从视觉控制器的角度来看,主要有两个数据源:相机和Arduino系统。相机是模仿人类视觉系统的终极传感器并与体系中的视觉控制器直接相连。通过使用OpenCV的数据采集功能,视觉控制器可以从相机中读取视觉数据。数据可以是快照图片或者由一帧帧数据按时间组成的视频。相机的种类并没有什么限制。最根本区分相机类型的方法是根据输出信号是模拟信号还是数字信号进行区分。本书例子中所采用的相机都是数码相机,因为处理环境和处理操作本身都是数字的。图片的基本组成元素被称为像素。在一张数码图片中,一个像素或者说图片元素是光栅化图片上的一个物理点,或者是全屏光点式显示设备上的最小寻址单位。所以它是屏幕上图片的最小控制单位。相机还可以按颜色感应能力进行分类。RGB相机既能感觉主要颜色成分也能感应这些主要颜色的混合。灰度相机能感应到的场景都是灰色的。因此,这种相机提供的不是颜色信息,而是场景的形状信息。最后,二进制摄像机识别的场景只有黑色和白色。顺便说一下,二进制相机的一个像素只有2个值,即黑色和白色。相机的另外一种分类方法是基于它们的通信接口。比如USB相机、IP相机、无线相机,等等。相机的通信接口也直接影响相机的可用性和功能。在家里我们一般用带USB接口的网络摄像头。在使用时通常不需要外部电源或者其他外部设备,所以它很适合用于图像处理。相机也有分辨率等属性,我们会在后面的章节处理相机属性。最常部署为网络摄像头的USB相机提供的是2D图片。除了2D相机系统,我们现在有可以检测场景中每个元素深度的3D相机系统。三维摄像机系统中最著名的可能是Kinect,如下图所示:
OpenCV支持各种类型的相机,并且可以通过非常简单的接口从这些相机中读取视觉信息。在随后的章节我们将介绍相关的例子。请记住,图像采集是视觉处理流程最基本的步骤,我们有很多选择。一般来说,我们还需要获取相机以外的信息来分析我们周围的环境。其中一些信息是和其余四个感官相关的。此外,有时我们需要超出人体感知能力的额外信息。我们可以通过Arduino传感器来获得这些信息。想象下你要构建一个面部识别自动开关门的项目。系统可能会由敲门声或者门铃触发。你需要一个声音传感器来对敲门声或者门铃声做反应。这些信息很容易由Arduino收集到。让我们添加一个指纹传感器,使其更加安全!通过这种方式,视觉系统可以结合Arduino和相机的数据来得出关于场景的结论。总之,视觉系统控制器可以通过相机和Arduino(使用传感器)来获取详细的环境信息。1.2.2 预处理
预处理的意思是把东西准备好以便进行处理。它可以包含各种各样的子步骤,但是基本原理是一样的。我们现在开始解释什么是预处理以及它的重要性。首先,让我们明确一件事。这一步的目的是把收集到的视觉数据整理好准备进行处理。计算机视觉系统需要预处理的原因是,原始的数据一般会有很多噪音。图片数据是从相机得到的,里面有很多区域是不需要的,有时候由于振动、运动等因素会得到一个模糊的图像。在任何情况下,最好都过滤一下图片来让它对我们的系统更加有用。比如,如果你想检测图像中的一个大红球,你就可以删除那些小点,你甚至可以移除那些不是红色的部分。所有这些过滤操作都会让后续操作更简单。一般来说,相机都在数据获取的时候做了过滤,但是每一个相机都有不同的预处理功能,甚至有一些相机做了防振动处理。但要注意的是内置功能的增加也会带来成本的增加。所以最好在内部通过OpenCV进行这些过滤处理。顺便说一句,即使使用的是廉价的设备比如网络摄像头,也能设计出一个鲁棒的视觉系统。同样的处理也适用于传感器数据。在真实环境中我们得到的总是有噪音的数据,所以噪音应该从传感器的真实数据中移除。这些噪音部分是由环境引起的,部分是由传感器的内部结构引起的。在任何情况下,数据应该被准备好以便进行处理。本书将给出实际可行的方法来达到这一目标。图像数据的复杂性远远超过任何常规的传感器,比如温度传感器、湿度传感器,这很好理解。用来表征信息的数据维度也是不同的。RGB图片的每个像素包含三个颜色组件:红色、绿色和蓝色。为了用分辨率640×480来表征一个场景,一个RGB相机需要640×480×3 = 921?600字节。乘以3的原因是每个像素有三个维度。每个像素对应3个字节的数据,1个字节代表一个颜色。为了表征房间的温度,我们一般需要4个字节的数据。这也解释了为什么我们需要更强的设备来处理图像。此外,图像过滤的复杂性也和简单的传感器过滤不同。但这并不意味着不可以用一个简单的方法来进行复杂的过滤。如果我们知道过滤的目的和过滤参数的含义,就可以更加容易地使用它们。这本书的目的是让你了解过滤的过程和如何更轻松地使用先进的过滤技术。所以过滤的目的是为了从数据中获取真实的数据信息,这是计算机视觉计算过程中不可或缺的一步。许多计算机视觉项目在开发阶段失败了,就是因为缺少过滤这一层。即使是最好的识别算法,遇到充满噪音和不准确的数据也会失败。所以,请重视数据过滤和预处理。
1.2.3 图像处理的特征提取
计算机视觉项目最让人激动的部分大概就是对场景的自动化解释。为了从图像中提取含义,我们应用了各种各样的图像处理技术。有时候一张图片的信息并不够。在这种情况下,图像帧之间的关系就非常重要。如果这种帧与帧之间的信息会被提取出来,这种处理通常被称为视频处理。许多视频处理应用也包括了对声音信号的处理。因为采用相同的基本原则,视频处理和图像处理区别不大。理解本章的重点在于逻辑地去看待真实生活中的应用。想象一下你在建一个沿着线行走的视觉机器人。机器人中间上方会有一个相机,它会在白色地板上沿着黑线行走。为了实现这个目标,你需要检测黑线,并找出黑线现在是在机器人的左边还是右边。如果黑线出现在图片的左边部分,你应该让机器人往左走让黑线在中间。同样,如果黑线出现在图片的右边部分,你应该让机器人往右走。如果黑线差不多在图片的中间,你就该让机器人往前走。你也可以检测黑线的方向来提前规划机器人的行进,以便让它的移动更加聪明合理。在这个例子中,你应该使用图像处理技术来检测图像中的线。你将在本书中看到一系列技术方案,在你解决问题时,这些技术方案将为你指引方向。使用这些技术方案,可以在图像中得到一些可能是线的候选区域。为了有效找到线的候选,你需要在这些候选区域上使用特征提取。通过对特征(属性)的对比,你就可以把真正的线从诸如阴影等噪音中分离出来。特征提取是一个模式识别和分类的术语,它意味着提取一些可以代表更大数据集的小数据。通过处理图像,我们提取了长度、位置、图像区域等特征。在后面的章节里,我们将用这些特征来检测和识别物体。从图像中提取有用的小集合数据有一些主要的方法。分割就是针对这种操作的一个术语。图像分割是把一个数码图像分成多个点集的过程。分割的目的是为了简化问题以及改变图像的表示方式,以一种更容易处理也更有意义的方式表示出来。更多信息可以在http://en.wikipedia.org/wiki/Image_segmentation找到。在我们的例子中,线段的候选就是这些图像的分割。blob分析是对图像分割进行标记的好方法。它对于找到图像中的闭环非常有用。闭环一般对应着图像中的物体。blob分析也是一种图像处理技术,我们会在后面讲到。现在最重要的是理解特征拾取的目的。从图像提取的信息将会用于计算机视觉系统的下一步流程中。因为这一步将对图像进行抽象概括,所以它对整个计算机视觉系统是否能正确工作非常重要。再一次强调,你不需要了解底层所涉及的复杂计算。相反,你要了解的是何时以及如何使用图像处理技术从场景中得到有价值的小信息块。这正是本书后面章节的专注点。
1.2.4 后处理和后置滤波
在从图像提取出一些有用的信息以后,有时需要做一些更高层次的滤波。从属性的角度出发去除不必要的部分就是一种更高层次的滤波。通常情况下,如果你了解相关项目的需求,这种滤波很容易。因为这一部分非常简单,通常我们会把它视为图像处理的一部分。因为图像处理的目的是给识别或者检测模块提供一些清晰小块的数据,所以这种处理比较合适。OpenCV有一个非常好的后处理机制,理解了它的意义我们可以很容易地将其应用在实际场景的例子中。理解后处理的目的更重要。
1.2.5 识别或检测
计算机视觉系统的主要目的是通过解释图像或者图像序列来得到结论。得到结论所使用的方法是识别或者检测。检测可以被看作识别的一种基本形式。它的目的是检测一个对象或者物体。会有两种类型的结论。一个物体或者时间存在或者不存在。因为结论的二进制本质,使得检测是一个只有两类的特殊分类过程。第一个类别是存在,第二个类别是不存在。“生存还是毁灭,这是个问题。”识别是一个更复杂的术语,也被称为分类,它的目的是在一个识别过程里将物体分成几个预先分好的类,或者通过学习将物体分类。人脸识别是这方面很好的一个例子。计算机视觉系统通过识别你的脸来确认是不是你。这是一个有多个类别的复杂分类过程。在这个例子中,每张脸是一个类别,所以它非常复杂。但是,感谢OpenCV,我们有很多简单易用的识别机制,即使是处理复杂问题也很方便。有时执行复杂的算法需要花费大量的时间。但有些时候,需要快速完成,特别是在有实时要求的情况下。在这些情况下,我们会采用一些简单但是有效的决策算法。正如列奥纳多•达•芬奇说,“大道至简,至繁归于至简”。本书还将讲述如何用简单的设计模块设计出健壮的识别系统。再次重申,你应该牢记识别或者分类的目的,这方面的意识将导引你走向成功。
1.2.6 在现实世界中行动
每个计算机视觉系统都有它的目的。有一些场景是“如果你发现了这个事件(或者物体),那么就执行这个动作”。计算机视觉系统在结束了长而有趣的决策过程后,下一步就是根据结论执行一个动作。这就是计算机视觉系统存在的目的。到目前为止所做的一切都是为了让我们能执行正确的动作。让我们回忆下寻线行走机器人的例子。机器人检测到线以及线在它的视野中的位置。它还需要判断线的方向。如果机器人仅仅是知道该往哪个方向走但是根本不动,那有什么意义呢?这个例子还展示了决策以后行动的重要性。视觉控制器管理的物理行动用物理的方式来影响真实世界。这样的例子包括:驱动汽车移动、加热环境、打开一扇门、触发一个设备,等等。要做这些需要依赖Arduino。它有庞大的社区支持,许多设备上开发了很多库并且它真得非常简单易用。也许对于工业设计,你有更好的选择,但是对于概念设计,Arduino非常适合用来执行最后的物理行动。Arduino是一个嵌入式系统,能让困难的工业内容简单易用。我们应该喜欢它!嵌入式系统最激动人心的是可以用相同的软件开发出不同的物理效果。嵌入式系统会在多个不同的目的中使用矩形波信号。你会在后面的章节里具体了解矩形波信号,现在先认为它是一种调光功能。当你用50%的占空比产生了矩形波信号,这意味着产生了有限时间t以内为逻辑高然后在有限时间t以内为逻辑低的脉冲。该软件将应用相同的调光原理到完全不同的设备上。如果你把这个矩形波信号应用到电动机上,它会以自身一半的最大速度运转。同样,如果你把这个矩形波信号应用到LED上,它的亮度会是最大亮度的一半。即使是在完全不同的物理设备上,我们用相同的软件能够得到相同的行为。所以我们看到了这些用来与世界交互的设备让人激动的特质。如果我们知道如何将它们连接到我们的系统上,一切都没问题了。本书提出了一种与硬件无关的用软件与世界交互的方法。所以,即使我们遇到的情况是与设备有关的,你也可以在任意的嵌入式设备上应用相同的原则。本书中也有一些非常先进的用Arduino与世界交互的技巧。
1.2.7 连接子模块
在我们提出的方法中,视觉处理过程被划分为一系列独立易实现的子模块。因为每一小块在整个系统的性能表现中都扮演了一个关键角色,每个子模块都应该基于一些简单的规则进行设计开发,这样整个系统才能坚如磐石。解决任何视觉问题的时候,首先要对问题有个全局的考虑,然后把问题分解成一系列有意义、内部独立的子模块。这种解决方法能让你考虑到问题的细节,并能不受干扰地解决一些子问题。对于建立未来的可视化视觉系统,这是最关键的第一步。下一步就只是把这些子模块连接起来享受你的成果。本章给出的方法适用于任何类型的计算机视觉系统。但是你应该去不停地实践以便让解决方案落地。让我们来对一个现实生活的例子做一个头脑风暴,这个例子是手势控制的门禁系统。入口的地方应该有个相机,在门上,这样可以看到任何客人的动作。为了更实用,只有按门铃才会触发运动检测系统。游客按下门铃,展示一个正确的手势,视觉控制器将自动打开门。如果手势错误,则门不会打开。第一步是数据采集,因为我们需要看到手势,用一个每秒30帧分辨率为1024×768的网络相机就可以实现。我们把图像转化为二进制格式,然后把图像中比较小的物体都过滤掉。手势会以二进制表示。这样过滤就完成了。然后我们将执行特征提取来找到图像中手的可能位置。这个问题可以用凸包方法或blob分析来解决,我们稍后来解释这些算法。最后,我们得到了一个带手势候选的图像,如下图所示:
下一步需要一个手势检测器。我们可以对手指进行骨骼分析比较手指的位置,这样可以对手势分类。如果是正确的手势,我们会给Arduino门禁控制器发信息,然后它就按限定的时间打开门以便欢迎授权游客!你可以将这些原则应用到任何问题上以便来熟悉它们。现在不要去关注算法的细节。仅仅是把问题分块然后决定哪些属性可以用来解决问题。只要你熟悉这套解决方法,本书将告诉你如何实现每一步以及如何找到合适的算法来解决问题。所以,继续用这套方法来解决一个可以识别你的汽车牌号的车库门禁系统。
文章
传感器 · 数据采集 · 算法 · 机器人 · 计算机视觉
2017-05-02