机器人操作系统(ROS)课件全套 曾庆喜 1.ROS简介-11ROS-2简介_第1页
机器人操作系统(ROS)课件全套 曾庆喜 1.ROS简介-11ROS-2简介_第2页
机器人操作系统(ROS)课件全套 曾庆喜 1.ROS简介-11ROS-2简介_第3页
机器人操作系统(ROS)课件全套 曾庆喜 1.ROS简介-11ROS-2简介_第4页
机器人操作系统(ROS)课件全套 曾庆喜 1.ROS简介-11ROS-2简介_第5页
已阅读5页,还剩630页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

机器人操作系统(ROS)机器人操作系统(ROS)ROS初识1.1机器人操作系统(ROS)1.1.1ROS是什么ROS是机器人操作系统(RobotOperatingSystem)的英文缩写。ROS起源于2007年斯坦福大学人工智能实验室的STAIR项目与机器人技术公司WillowGarage的个人机器人项目(PR)之间的合作,2008年之后就由WillowGarage来进行推动。最初人们希望设计一个可以像人一样能够感知,并实现自我控制从而完成一些复杂工作的机器人。随着机器人领域的快速发展,代码的复用性和模块化的需求原来越强烈,急需一个能够整合现有资源的框架和接口。2010年WillowGarage公司发布了开源机器人操作系统ROS,很快在机器人研究领域展开了学习和使用ROS的热潮。ROS起源发展机器人操作系统(ROS)1.1.1ROS是什么ROS是用于机器人编程的开放、灵活的软件框架。它提供类似操作系统所提供的功能,包含硬件抽象描述、底层驱动程序管理、共用功能的执行、程序间的消息传递、程序发行包管理等,它也提供一些可视化和调试机器人数据的软件工具。ROS框架的核心是消息传递,即使在不同的机器上运行,进程之间也可以相互通信和交换数据。ROS消息传递可以是同步的,也可以是异步的。事实上,ROS的主要目的就是为机器人研究和开发提供代码复用的支持。ROS是一种分布式处理框架,这使可执行文件能被单独设计,并且在运行时松散耦合。这些过程可以封装到数据包(Packages)和堆栈(Stacks)中,以便于共享和分发。ROS还支持代码库的联合系统,使得协作亦能被分发。上述所有功能都能由ROS的基础工具实现。设计者将ROS表述为“ROS=Plumbing+Tools+Capabilities+Ecosystem”,即ROS是通讯机制、工具软件包、机器人高层技能以及机器人生态系统的集合体。ROS的表述机器人操作系统(ROS)1.1.2ROS的特点点对点的设计:节点是ROS编程基础中一个重要的概念,在ROS中每个进程都以一个节点的形式运行,可以分布于多个不同的主机。节点间的消息通过一个带有发布和订阅功能的传输系统从发布节点传送到接收节点。这种点对点的设计可以分散实现复杂功能时带来的实时计算的压力。多语言支持:为了支持更多应用的移植和开发,ROS通信框架可以轻松地以各种现有的编程语言实现。ROS中使用简洁、中立的定义语言描述模块之间的消息接口,同时也允许消息接口的嵌套使用。目前已经支持Python、C++、Java、Octave和LISP等多种不同的语言。库集成:ROS具有许多第三方机器人库的接口,如开源计算机视觉(Open-CV)、点云库(PCL)、Open-NI、Open-Rave和Orocos。开发人员可以没有顾虑的使用这些库。组件化工具包丰富:ROS可采用组件化方式集成一些工具和软件到系统中并作为一个组件直接使用,如RVIZ(3D可视化工具),开发者根据ROS定义的接口在其中显示机器人模型等,组件还包括仿真环境和消息查看工具等。协作开发:ROS是开源的,遵照的BSD许可给使用者较大的自由,允许修改和重新发布其中的应用代码,开发人员可以通过添加功能包来扩展ROS的功能。几乎所有的ROS包都在硬件抽象层上工作,可以轻松地为其他机器人所用。机器人操作系统(ROS)1.1.3ROS的发行版ROS的发行版本ROS发行版是一组版本化的ROS包,这些类似于Linux发行版(例如Ubuntu)。ROS发行版的目的是让开发人员在相对稳定的代码库上工作,直到他们准备好推进所有事情。因此,一旦发布发行版,我们就会尝试限制对核心包(ros-desktop-full下的所有内容)的错误修复和非破坏性改进的更改。到2022年为止,ROS已经发布了如表1-1所示的多个版本。本书选择的ROS版本是2018年发布的长期支持版本ROSMelodicMorenia,这也是ROS发布的第12个版本,ROS官方称将为该版本提供长达5年的支持与服务,并保证其与Ubuntu18.04长期支持版的生命周期同步。机器人操作系统(ROS)本书的ROS资源1.2机器人操作系统(ROS)1.2本书的ROS资源本书涉及到的代码以及相关资料均放在GitHub中托管,链接:/FieldRoboticsLaboratory/ROS_book可以使用以下命令下载源码以开始后续的学习。$gitclone/FieldRoboticsLaboratory/ROS_book.git机器人操作系统(ROS)本章小结1.3机器人操作系统(ROS)1.3本章小结本章介绍了ROS的起源背景、设计目的和框架特点。本书还提供所有实践的源码,可以帮助读者用ROS搭建丰富的机器人应用功能。机器人操作系统(ROS)机器人操作系统(ROS)编程基础知识2机器人操作系统(ROS)2.编程基础知识在整个机器人行业中,程序是连接机器人与人的中间桥梁。通过程序,人才能够让机器人从装饰品变成生产工具。在当今机械控制日渐自动化与智能化的大趋势下,一段程序的优劣对整个生产过程显得尤为重要,任何涉及到自动控制或是智能控制的领域都离不开程序的编写。而编程语言作为编写程序的工具,是搭建中间桥梁的桥墩。专注于机器人控制的ROS平台自然也是离不开编程语言的。相较于其他编程语言,在ROS中使用的编程语言主要是C++和Python,因此我们将通过两个章节的篇幅为读者简单介绍这两种编程语言及其最重要的特点。建议有C++与Python基础的读者也仍然阅读一下这两部分,熟悉一下这两种语言在ROS中的运用。本章首先简单介绍C++,主要讲解C++最重要的一些基础概念以及C++基本使用方法,然后介绍Python的相关知识和使用方法。机器人操作系统(ROS)2.1面向对象编程(object-orientedprogramming)与C++简介首先我们先来描述一下面向过程编程与面向对象编程的区别。面向过程程序的控制流程由程序中预定顺序来决定;面向对象程序的控制流程由运行时各种事件的实际发生来触发,而不再由预定顺序来决定,更符合实际需要。打个比方,假如我们要设计一款围棋游戏,如果使用面向过程语言,那么我们的编程思路就应当是第一步白棋可以下在哪里,结束以后第二步由黑棋来下,可以下在哪里,每一步下完之后判断是否有围杀或是胜败,以此类推。可以见得,如果将存在棋盘下满和棋的情况考虑在内,那么就会需要许多行代码去完成这个游戏的开发。而换成面向对象编程,我们的编程思路就会转换成,白棋作为一个模块,编写好白棋的使用程序,黑棋作为一个模块,由另一个人完成黑棋的使用程序,两者再结合胜败判定程序即可完成,将一整个连续性的程序框架拆解成各个模块,这就是面向对象编程。接下来在介绍C++前,我们先对C++的基础C语言做一个简单概括。C语言是面向过程的结构化和模块化的语言。在处理较小规模的程序时,程序员用C语言较为得心应手。但是当问题比较复杂、程序的规模比较大时,结构化程序设计方法就显出它的不足。C程序的设计者必须细致地设计程序中的每一个细节,准确地考虑程序运行时每一时刻发生的事情,例如各个变量的值是如何变化的,什么时候应该进行哪些输入,在显示器上应该输出什么等,如上一段所举的围棋例子。这对程序员的要求是比较高的,如果面对的是一个复杂问题,程序员往往感到力不从心。当初提出结构化程序设计方法的目的是解决软件设计危机,但是这个目标并未完全实现。机器人操作系统(ROS)2.1面向对象编程(object-orientedprogramming)与C++简介而C++正是为了解决这个问题而从C语言的基础上改进出来的编程语言。在20世纪80年代提出了面向对象的程序设计(object-orientedprogramming,面向对象编程)思想,这就需要设计出能支持面向对象的程序设计方法的新语言。Smalltalk就是当时问世的一种面向对象的语言。而在实践中,人们发现由于C语言是如此深入人心,使用如此广泛,以至最好的办法不是另外发明一种新的语言去代替它,而是在它原有的基础上加以发展。在这种形势下,C++应运而生,并且在C的后面添加自加符号++来表示这是C语言的增强版,我们也可以称C++为带类的C语言。由于C++面向对象编程的便捷性更加符合机器人开发的要求,因此ROS作为以普适性为目的的机器人平台自然也就将C++作为主要的编程语言之一。接下来就将为读者介绍一些C++编程语言的基础知识。机器人操作系统(ROS)2.2在Linux中使用C++UbuntuLinux系统自带一个内置的C/C++编译器,叫做GCC/G++。GCC即为GNUCompilerCollection,译为GNU编译器套件,它包括C、C++、Objective-C、Fortran、Ada和Go的编译器,以及这些语言的库。GCC是RichardStallman为GNU项目(/gnu/thegnuproject)编写的。本章代码需要在电脑中预装Linux系统才能运行,请读者参考第五章内容,安装相应版本的ubuntu系统或虚拟机。机器人操作系统(ROS)2.2.1GCC和G++编译器介绍让我们从GCC/G++编译器开始认识C++。最新的UbuntuLinux系统预装了C和C++编译,其中C语言的编译器是GCC,C++的编译器是G++。。在桌面或是文件夹空白处右击,然后选中在终端中打开,或是使用快捷键Ctrl+Alt+t,即可打开一个终端。终端(Terminal)也是Linux系统操作的重要工具,希望读者可以牢记该操作,以方便之后的学习使用。在打开的终端中先输入gcc然后回车,接着再输入g++然后回车,出现的界面如图所示。机器人操作系统(ROS)2.2.1GCC和G++编译器介绍让我们从GCC/G++编译器开始认识C++。最新的UbuntuLinux系统预装了C和C++编译,其中C语言的编译器是GCC,C++的编译器是G++。。在桌面或是文件夹空白处右击,然后选中在终端中打开,或是使用快捷键Ctrl+Alt+t,即可打开一个终端。终端(Terminal)也是Linux系统操作的重要工具,希望读者可以牢记该操作,以方便之后的学习使用。在打开的终端中先输入gcc然后回车,接着再输入g++然后回车,出现的界面如图所示。如果没有得到图2-1中的信息,则代表系统没有预装这些编译器,可以使用Linux系统中安装软件的apt-get命令来安装这些编译器,下一小节我们将进行详细介绍。机器人操作系统(ROS)2.2.2安装C/C++编译器首先,需要打开终端并使用如下命令从软件库中更新Ubuntu软件包列表:$sudoapt-getupdate然后安装C/C++编译器需要的两个依赖包:$sudoapt-getinstallbuild-essentialmanpages-devbuild-essential包和许多其他基础包有关,它们共同用于UbuntuLinux中的软件开发。最后安装C/C++编译器,指令如下:$sudoapt-getinstallgccg++机器人操作系统(ROS)2.2.3验证安装安装完前面的包之后,可以在终端中使用如下指令查看编译器的安装路径、使用说明页:$whereisgcc$whereisg++使用下面命令可以查看GCC编译器的版本号:$gcc--version$g++--version下图显示了以上命令的输出。机器人操作系统(ROS)2.2.4GNU项目调试器GDB简介下面我们看一看C/C++的调试器。什么是调试器呢?调试器是一个可以运行和控制另一个程序的程序,通过检查每一行代码来检查程序的问题或bug。UbuntuLinux自带一个名为GNUDebugger的调试器,简称GDB(/software/gdb/),它是Linux系统中最流行的C和C++程序调试器之一。机器人操作系统(ROS)2.2.5在UbuntuLinux中安装GDB最新版本的Ubuntu中已经安装了GDB。如果用户正在使用其他版本,可以使用如下命令安装GDB:$sudoapt-getinstallgdb机器人操作系统(ROS)2.2.6验证安装可以使用如下命令检查GDB是否已经准确安装在计算机中:$gdb如果安装成功,则会显示图中的信息。机器人操作系统(ROS)2.2.6验证安装图的界面中,可以发现最后一行并不是正常终端操作命令执行后的初始行,也就是并没有出现之前操作命令回车执行后界面中绿色字体的标识符。这是因为当前操作命令仍然在执行,并没有结束,此时读者输入quit并敲击回车结束gdb命令的执行,如图所示。在下一小节中,我们将在Ubuntu中编写我们的第一个c++代码,然后编译并调试它,以找到代码中的错误。机器人操作系统(ROS)2.2.7编写第一行代码下面我们开始在UbuntuLinux中编写第一个程序。用户可以使用Ubuntu中的gedit,或nano终端文本编辑器来编写代码。gedit是ubuntu中一个常用的GUI文本编辑器,更加符合长期使用Windows系统下的Office操作模式的人的使用习惯,因此这里我们使用gedit来编写UbuntuLinux中的第一条程序代码。在Ubuntu搜索中查找gedit(见图),然后单击打开该文本编辑器。机器人操作系统(ROS)2.2.7编写第一行代码或者也可以在终端中直接输入gedit然后敲击回车打开gedit,如图所示。可见终端在Linux系统中的重要性,为了养成习惯,建议读者使用终端打开gedit。机器人操作系统(ROS)2.2.7编写第一行代码gedit文本编辑器打开后,可看到如图所示的窗口。机器人操作系统(ROS)2.2.7编写第一行代码这个编辑器非常类似于Windows中的Notepad或者WordPad,页面十分简洁,除了少数几个文件保存打开按钮外就只有书写界面,我们就将在这个文本编辑器中编写第一个C++程序。将下列内容输入到我们打开的gedit界面中:#include<iostream>usingnamespacestd;intmain(){cout<<”Nicetomeetyou,ROS.”<<endl;return0;}机器人操作系统(ROS)2.2.7编写第一行代码在文本编辑器中编写完成后,保存为HelloROS.cpp。需要注意的是,这里的.cpp必须由读者自己手动输入,而不是像Windows中有下拉菜单可以选择文件的保存格式,这也是Linux系统的文件命名特点。机器人操作系统(ROS)2.2.7编写第一行代码保存完毕后,我们可以发现gedit界面中我们刚才输入的程序变成了彩色,如图2-10所示,这就表明该文件已经被成功保存为.cpp格式。机器人操作系统(ROS)2.2.8解释代码HelloROS.cpp里代码的功能是将消息“Nicetomeetyou,ROS.”打印到显示器上。代码中的第一行“#include<iostream>”是一个C++头文件,其中包含的最常用的就是输入/输出函数,例如从键盘输入一段字符或者将指定内容输出到显示器上的cin与cout函数就是最典型的代表。在这个程序中,我们只使用了cout函数来输出消息,所以有iostream作为头文件就足够了。接下来的第二行则是声明了使用namespacestd即命名空间。命名空间(/namespacc/)是C++中的一个特性,用于对一组实体进行分组。iostream库中使用std定义命名空间。当我们使用命名空间namespacestd时,我们可以访问std命名空间中包含的所有函数或其他实体,例如cout和cin等函数。如果我们不使用这行代码,则必须在函数前面添加std::用于访问该名字空间中的函数;例如,std::cout是一个打印消息的函数。在讨论了头文件和其他代码之后,我们可以讨论主函数中包含的内容了。我们使用cout<<"Nicetomeetyou,ROS."<<endl打印出一条消息。endl表明在打印消息后换行,消息打印完毕后,函数返回0并退出程序。在本章稍后的小节中我们会更加详细地分析C++的一些基础知识在ROS中的使用。机器人操作系统(ROS)2.2.9编译代码保存代码之后,我们的.cpp文件仍然只是个文本文档,并不是可执行的程序,因此需要对这个文档进行编译,将里面的代码生成可执行文件。下面的例程将帮助各位读者完成代码编译的步骤。可以重新打开一个新终端,并使用如下命令将终端路径切换到保存代码的文件夹下。在本例中,我们将代码保存到/home/桌面文件夹中。在终端中使用如下命令切换目录和代码编译,编译结果如图所示:$cd桌面$g++HelloROS.cpp机器人操作系统(ROS)2.2.9编译代码在当前文件夹中可以看到生成了一个新的文件a.out,这是编译生成的可执行文件,文件名称由系统默认生成,如需生成特定名称的可执行文件,我们可以使用如下指令:$g++HelloROS.cpp-ohello_ROS此时在文件夹中就会生成hello_ROS.out的可执行文件。如图所示:机器人操作系统(ROS)2.2.9编译代码在终端中输入以下命令运行生成好的可执行文件:$./hello_ROS此时显示器上会输出“Nicetomeetyou,ROS”的字符串,表示程序运行成果,如图2-13所示:机器人操作系统(ROS)2.2.10调试代码使用调试器,可以遍历每一行代码并检查每个变量的值。将下面的代码按照之前的方法通过gedit来生成相应的.cpp文件,输入代码后保存为SUM.cpp文件。#include<iostream>usingnamespacestd;intmain(){intNum1=1;intNum2=2;intSum=Num1+Num2;cout<<”Sum=”<<Sum<<endl;return0;}机器人操作系统(ROS)2.2.10调试代码生成.cpp文件后就要对进行编译了,而为了要调试/检查每一行代码,我们编译的时候必须使用调试符号编译代码,并使其能适用于GDB调试。具体的编译命令如下:$g++-gSUM.cpp-oSUM编译后,可以通过运行命令$./SUM执行它。运行结果如图所示。机器人操作系统(ROS)2.2.10调试代码可执行文件创建成功之后,可以通过以下的命令对其进行调试:$gdbSUM其中,SUM是可执行文件的名称,输入命令后,需使用GDB的操作指令进行代码调试。以下是常用的几个GDB命令,具体解释如下:•bline_numer:在给定行号处创建断点。在调试时,调试器会在这个断点处停止。•n:运行下一行代码。•r:运行程序到断点位置。•pvariable_name:打印变量的值。•q:退出调试器。让我们来尝试一下这些命令,每个命令的输出结果如图所示。机器人操作系统(ROS)2.2.10调试代码接下来就要介绍C++最大的特点,面向对象编程,也是与C语言最大的区别。机器人操作系统(ROS)2.3从实例中学习C++中OOP的概念如果用户已经知道C的结构体,那么了解OOP概念将不会花费太多时间。在C的结构体中,我们可以将不同的数据类型(如整数、浮点数和字符串)封装到一个用户定义的数据类型中。与C的结构体类似,C++有一个增强版的结构体,它增加了定义函数的功能。这个增强版本的结构体称为C++类。C++类的每个实例都被称为对象。对象只是实际类的一个副本。有几个与对象相关的属性,称为面向对象编程概念。接下来我们用C++代码解释主要的OOP概念。机器人操作系统(ROS)2.3.1类和结构体之间的区别在学习OOP概念之前,让我们先来看看结构体和类之间的区别。首先创建名为class_struct.cpp的示例代码文件,将如下内容添加到文件中:#include"iostream"

#include"string"

usingnamespacestd;

structRobot_Struct

{

intid;

intno_wheels;

stringrobot_name;

};

classRobot_Class

{

public:

intid;

intno_wheels;

stringrobot_name;

voidmove_robot();

voidstop_robot();

};

voidRobot_Class::move_robot()

{

cout<<"MovingRobot!"<<endl;

}

voidRobot_Class::stop_robot()

{

cout<<"StoppingRobot!"<<endl;

}

intmain()

{

Robot_Structrobot_1;

Robot_Classrobot_2;

robot_1.id=2;

robot_1.robot_name="Mobilerobot";

robot_2.id=3;

robot_2.robot_name="NoWheelsrobot";

cout<<"ID="<<robot_1.id<<"\t"<<"RobotName="<<robot_1.robot_name<<endl;

cout<<"ID="<<robot_2.id<<"\t"<<"RobotName="<<robot_2.robot_name<<endl;

robot_2.move_robot();

robot_2.stop_robot();

return0;

}机器人操作系统(ROS)2.3.1类和结构体之间的区别这段代码定义了一个类和结构体。结构体名称是Robot_struct,类名是Robot_Class。下面部分展示了如何定义一个结构体。该结构体定义了若干变量,比如机器人的编号id、名称robot_name和轮子的数量no_wheels。structRobot_Struct

{

intid;

intno_wheels;

stringrobot_name;

};机器人操作系统(ROS)2.3.1类和结构体之间的区别如大家所知,每个结构体都有一个名字,所有变量的声明都在里面。下面部分是类的定义:classRobot_Class{public:intid;intno_wheels;stringrobot_name;voidmove_robot();voidstop_robot();};机器人操作系统(ROS)2.3.1类和结构体之间的区别所以,这两者之间到底有什么区别呢?结构体只能定义不同的成员变量,但是类除了可以定义多个成员变量之外还可以声明不同成员函数。那么每个函数定义在哪里呢?我们可以在类的内部或外部定义函数。标准的做法是在类的外部定义函数,以保证类定义的简洁性。下面的程序显示了类中所声明的函数在类外部的定义。voidRobot_Class::move_robot(){cout<<"MovingRobot!"<<endl;}voidRobot_Class::stop_robot(){cout<<"StoppingRobot!"<<endl;}机器人操作系统(ROS)2.3.1类和结构体之间的区别在函数定义中,第一项是返回数据的类型,然后是类名,再然后是用::连接的函数名。表明函数是包含在类中的。在函数定义中,我们可以输入我们的代码,函数中这段特定的代码打印了一条信息。你已经看到类的函数定义。下一步是学习如何读/写变量和使用函数。机器人操作系统(ROS)2.3.2C++的类和对象本节将解释如何读/写结构体和类中的变量。下面程序是创建结构体和类的代码:Robot_Structrobot_1;Robot_Classrobot_2;robot_1.id=2;robot_1.robot_name="Mobilerobot";robot_2.id=3;robot_2.robot_name="NoWheelsrobot";机器人操作系统(ROS)2.3.2C++的类和对象与结构体实例类似,我们可以创建一个类的实例,称之为对象。让我们来看看Robot_Classrobot_2;在这里,robot_2是一个对象,而robot1是结构体的一个实例。使用这个实例或对象,我们可以访问每一个变量和函数。我们可以使用.操作符去访问每一个变量。结构体和类中的变量都可以使用.操作符进行访问。如果是使用结构体或类的指针,则必须使用->操作符来访问每个变量。如下所示:Robot_Class*robot_3;robot_3=newRobot_Class;robot_3->id=4;robot_3->robot_name="Rosrobot";机器人操作系统(ROS)2.3.2C++的类和对象其中,new操作符为C++变量分配内存。我们可以使用操作符调用类中的函数和打印变量,程序如下所示:cout<<"ID="<<robot_1.id<<"\t"<<"RobotName="<<robot_1.robot_name<<endl;cout<<"ID="<<robot_2.id<<"\t"<<"RobotName="<<robot_2.robot_name<<endl;robot_2.move_robot();robot_2.stop_robot();机器人操作系统(ROS)2.3.2C++的类和对象我们使用命令$g++class_struct.cpp-oclass_struct和$./class_struct编译它。图2-16显示了这段代码的输出。可访问/cplusplus/cpp_classes_objects.htm,以便进一步参考。机器人操作系统(ROS)2.3.3类访问修饰符在类中,用户也许已经看到了一个叫做public:的关键字,它被称为成员访问限定符。下面代码部分是使用访问修饰符的代码。classRobot_Class{public:intid;intno_wheels;...};机器人操作系统(ROS)2.3.3类访问修饰符这一功能也称为数据隐藏,通过设置成员访问修饰符,我们可以限制在类内部定义的函数的使用范围。类中有三种访问修饰符:public:一个public成员可以从类之外的任何地方访问。我们可以直接访问公共变量,而不需要编写其他辅助函数。private:使用该修饰符号的成员变量或函数,不能从类外部被查看或访问。只有类和友元函数可以访问私有成员。protected:访问非常类似于private成员,但是不同的是它的子类可以访问其成员。子类/派生类的概念将在下一节进行讨论。访问修饰符可以帮助你将变量分组,这些变量可以在类中保持可见或隐藏。机器人操作系统(ROS)2.3.4C++中继承的使用继承(Inheritance)是OOP中的另一个重要概念。如果你有两个或多个类,并且希望在一个新类中拥有这些类中的函数,那么可以使用继承属性。通过使用继承属性,你可以在新类中重用现有类中的函数。我们将要继承现有类的新类称为派生类,已有的类称为基类。类可以通过public、private或protected来继承。下面将解释每种继承类型。publicinheritance:当我们派生自public基类时,基类的public成员成为派生类的public成员,并且基类的protected成员成为派生类的protected成员。基类的private成员不能在派生类中访问,但可以通过对基类的public和protected成员函数的调用来访问。protectedinheritance:当我们使用protected基类继承时,基类的public和protected成员成为派生类的protected成员。privateinheritance:当我们派生自private基类时,基类的public和protected成员成为派生类的private成员。机器人操作系统(ROS)2.3.4C++中继承的使用我们创建一个public继承的简单示例代码class_inheritance.cpp,并填入如下内容:#include<iostream>#include<string>usingnamespacestd;classRobot_Class{public: intid; intno_wheels; stringrobot_name; voidmove_robot(); voidstop_robot();};classRobot_Class_Derived:publicRobot_Class{public: voidturn_left(); voidturn_right();};voidRobot_Class::move_robot(){ cout<<"MovingRobot"<<endl;}voidRobot_Class::stop_robot(){ cout<<"StoppingRobot"<<endl;}voidRobot_Class_Derived::turn_left(){ cout<<"RobotTurnleft"<<endl;}voidRobot_Class_Derived::turn_right(){ cout<<"RobotTurnRight"<<endl;}intmain(){ Robot_Class_Derivedrobot; robot.id=2; robot.robot_name="Mobilerobot"; cout<<"RobotID="<<robot.id<<endl; cout<<"RobotName="<<robot.robot_name<<endl; robot.move_robot(); robot.stop_robot(); robot.turn_left(); robot.turn_right(); return0;}机器人操作系统(ROS)2.3.4C++中继承的使用在本例中,我们创建了一个名为Robot_Class_Derived的新类,它派生自一个名为Robot_Class的基类。公共继承是通过使用public关键字加后边的基类名实现的,即在派生类名之后紧接着是一个public关键字和一个基类名。classRobot_Class_Derived:publicRobot_Class{public: voidturn_left(); voidturn_right();};机器人操作系统(ROS)2.3.4C++中继承的使用Robot_Class在这种情况下,如果选择公共继承,则可以访问基类的public和protected修饰的变量和函数。我们使用的类与第一个示例中使用的类相同。派生类中每个函数的定义如下所示:voidRobot_Class_Derived::turn_left(){ cout<<"RobotTurnleft"<<endl;}voidRobot_Class_Derived::turn_right(){ cout<<"RobotTurnRight"<<endl;}机器人操作系统(ROS)2.3.4C++中继承的使用现在让我们看看如何访问派生类中的函数:Robot_Class_Derivedrobot; robot.id=2; robot.robot_name="Mobilerobot"; cout<<"RobotID="<<robot.id<<endl; cout<<"RobotName="<<robot.robot_name<<endl; robot.move_robot(); robot.stop_robot(); robot.turn_left(); robot.turn_right();机器人操作系统(ROS)2.3.4C++中继承的使用在这里,我们创建了一个名为“robot”的“Robo_Class_Derived”对象。如果用户仔细阅读代码,便可以理解,在Robo_Class_Derived中,我们没有声明id和robot_name变量,它是在Robo_Class中定义的。通过使用inheritance属性,我们可以在派生类Robo_Class_Derived中访问Robo_Class的变量。下面让我们看一下代码的输出,通过使用下面的命令来编译class_inheritance.cpp文件:$g++class_inherit.cpp-oclass_inherit$./class_inherit这将得到如图2-17所示的输出,没有显示任何错误。这意味着此公共继承运行良好。机器人操作系统(ROS)2.3.4C++中继承的使用根据输出可以观察到,我们从基类和派生类中定义的函数中获取了所有消息。此外,我们还可以访问基类变量并设置它的值我们已经介绍了一些重要的OOP概念。如果需要了解更多的概念,请参考/cplusplus.机器人操作系统(ROS)2.3.5C++文件和流下面让我们来一起讨论C++中的文件操作以及文件读写。我们已经讨论了用于执行文件操作的iostream头文件,我们还需要另一个标准的C++库fstream。在fstream中有以下三种数据类型。ofstream:表示输出文件流。它用于创建文件并将数据写入其中。ifstream:表示输入文件流。它用于从文件中读取数据。fstream:同时具有读/写能力。机器人操作系统(ROS)2.3.5C++文件和流下面代码展示了如何使用C++函数读/写文件:#include<iostream>#include<fstream>#include<string>usingnamespacestd;intmain(){ ofstreamout_file; stringdata="Robot_ID=0"; cout<<"Writedata:"<<data<<endl; out_file.open("Config.txt"); out_file<<data<<endl; out_file.close(); ifstreamin_file; in_file.open("Config.txt"); in_file>>data; cout<<"Readdata:"<<data<<endl; in_file.close(); return0;}机器人操作系统(ROS)2.3.5C++文件和流代码必须包含fstream头,以获得C++中的读/写数据类型。我们已经创建了一个ofstream类对象,其中包含一个名为open()的函数,用于打开文件。打开文件后,我们可以使用<<运算符对其进行写入。写完数据后,我们关闭文件为读取操作做准备。为了读入数据,我们在C++中使用ifstream类对象,并使用ifstream类中的open(“file_name”)函数打开文件。打开文件后,我们可以使用>>操作符从文件中读取数据。读取完毕后,在终端中打印。我们要写的文件名是Config.txt并且数据是一个机器人相关的参数。图2-18显示了编译并运行代码后的输出结果。你可以看到Config.txt已经在桌面文件夹中被创建了出来。相关详细信息,请访问/cplusplus/cpp_files_streams.htm。机器人操作系统(ROS)2.3.6C++中的命名空间在此之前,HelloWorld代码中提到了命名空间的概念。在本节中,你将学习如何创建、在何处使用以及如何访问命名空间。下面代码提供了一个创建和使用两个命名空间的示例:#include<iostream>usingnamespacestd;namespacerobot{ voidprocess(void) { cout<<"ProcessingbyRobot"<<endl; }}namespacemachine{ voidprocess(void) { cout<<"ProcessingbyMachine"<<endl; }}intmain(){ robot::process(); machine::process();}机器人操作系统(ROS)2.3.6C++中的命名空间创建命名空间时,要使用关键词namespace,后面紧跟这个命名空间的名字。其中我们定义了两个命名空间。如果查看代码,你会发现在每个命名空间里都定义了相同的函数。这些命名空间用来对实现某一特定操作的一系列函数或类进行分组。通过使用这个命名空间的名称,后跟::加函数名的方式,我们可以访问命名空间里的成员。在这段代码中,我们在命名空间里调用了两个函数,分别是robot和machine。图展示了代码里代码的输出。这段代码被保存为namespace.cpp。更多的参考,可以访问/cplusplus/cpp_exceptions_handling.htm。机器人操作系统(ROS)2.3.7C++的异常处理异常处理Exceptionhandling是C++中的的一种新特性,它可以用来处理当用户输入后产生非预期的输出响应的情况。下面是C++异常处理特性的一个例子:#include<iostream>usingnamespacestd;intmain(){ try { intno_1=1; intno_2=0; if(no_2==0) { throwno_1; } }

catch(inte) { cout<<"Exceptionfound:"<<e<<endl; }}机器人操作系统(ROS)2.3.7C++的异常处理异常处理Exceptionhandling是C++中的的一种新特性,它可以用来处理当用户输入后产生非预期的输出响应的情况。下面是C++异常处理特性的一个例子:#include<iostream>usingnamespacestd;intmain(){try{intno_1=1;intno_2=0;if(no_2==0) { throwno_1; }}

catch(inte){ cout<<"Exceptionfound:"<<e<<endl;}}机器人操作系统(ROS)2.3.7C++的异常处理我们主要用三个关键词来处理异常情况。try:在try后面的测试块中编写可能会引发异常的代码。catch:如果try后的测试块中出现了异常,则catch后面的代码块会捕捉这个异常。然后我们可以决定如何处理这个异常情况。throw:当开始出现问题时,我们可以从测试块中抛出一个异常。该异常可以被后边的catch块捕捉到。机器人操作系统(ROS)2.3.7C++的异常处理下面代码展示了异常处理的基本结构:try{ //Ourcodesnippets}catch(Exceptionname){ //Exceptionhandlingblock}机器人操作系统(ROS)2.3.7C++的异常处理这个代码是在查询num_2是否为0。当num_2为0时,就会抛出一个由throw关键词num_1引发的异常,然后catch块会捕捉该异常并检查num_1的值。图展示了代码编译和输出结果。我们可以在catch块中打印异常值(也就是num_1的值,也就是1)。异常处理被广泛地运用于简单的程序调试。更多的参考,可以访问/exception-handling-c/。机器人操作系统(ROS)2.3.8C++的标准模板库如果你想使用一些数据结构,比如列表(list)、堆栈(stacks)、数组(arrays)等等,标准模板库(StandardTemplateLibrary,STL)是最好的选择。STL为计算机科学提供了多样的标准算法的实现,比如排序和搜索,以及类似于向量、列表、队列等数据结构。这是一个先进的C++概念,如果想浏览一下相关信息,可以访问/the-c-standard-template-library-stl/。机器人操作系统(ROS)2.4建立一个C++工程现在你已经学习了一些重要的OOP概念,现在让我们来看看如何建立C++工程。想象一下,你有成百上千个源代码文件,而且你需要编译、链接它们,你要如何处理?这一部分将讨论这个问题。如果你想使用多个源代码文件,需要使用下列工具来编译、链接你的工程。Linuxmakefile可以非常方便的用来编译一个或多个源文件,并生成可执行文件。让我们通过一个简单的工程来证明makefile的能力。我们将编写一些代码来对两个数字求和,为此我们要先建立一个类。当编写C++类的时候,我们可以和main函数一起在源文件中声明和定义这个类。另外一种声明和定义类的方式是使用.h文件和.cpp文件,然后把.h文件包含到main函数所在的源文件中。这种方法对整个项目的模块化很有帮助。我们的工程包含三个文件。main.cpp:是我们将要构建的主要代码。add.h:add类的头文件,包含一个类的声明。add.cpp:这个文件里含有类add的全部定义。最好将类、头文件、.cpp文件用同一个名字命名。这里我们建立类add,所以头文件名是add.h和add.cpp。机器人操作系统(ROS)2.4建立一个C++工程以下是add.h代码:#include<iostream>classadd{public: intcompute(intno_1,intno_2);};以下是add.cpp代码:#include"add.h"intadd::compute(inta,intb){ return(a+b);}机器人操作系统(ROS)2.4建立一个C++工程以下是main.cpp代码:#include"add.h"usingnamespacestd;intmain(){ addobj; intresult=pute(43,34); cout<<"TheResult:="<<result<<endl; return0;}机器人操作系统(ROS)2.4建立一个C++工程在main.cpp中,我们首先通过包含add.h头文件来访问add类,然后创建了add类的一个对象,并将两个数字传递给compute函数,最后打印结果。我们可以使用以下命令编译并执行中的代码,其输出结果如图所示。对于编译单个源代码,g++命令很容易使用,但是如果我们想要编译若干个源代码,那么g++命令就不那么方便了。Linuxmakefile则提供了一种组织、编译多个源代码文件的方法。下面部分将展示了如何通过编写makefile文件来编译代码。机器人操作系统(ROS)2.4建立一个C++工程这部分是LinuxMakefile文件内容:CC=g++CFLAGS=-cSOURCES=main.cppadd.cppOBJECTS=$(SOURCES:.cpp=.o)EXECUTABLE=mainall:$(OBJECTS)$(EXECUTABLE)$(EXECUTABLE):$(OBJECTS) $(CC)$(OBJECTS)-o$@.cpp.o:*.h $(CC)$(CFLAGS)$<-o$@clean: -rm-f$(OBJECTS)$(EXECUTABLE).PHONY:allclean机器人操作系统(ROS)2.4建立一个C++工程上面代码保存为makefile之后,我们必须执行以下命令来执行编译。$make这样就编译了源代码,如图2-22所示。在使用make命令编译之后,可以使用以下命令执行程序。结果如图2-23所示:$./main你可以通过/cplusplus/gnumake.php了解更多关于makefile的信息机器人操作系统(ROS)2.4.2创建一个CMake文件CMake()是构建C++工程的另一种方法。CMake代表cross-platformmakefile。它是一个开源工具,可以跨操作系统编译、测试和打包软件。我们可以使用以下命令安装CMake。$sudoapt-getinstallcmake安装之后,需要将下面代码保存为CMakeLists.txt:cmake_minimum_required(VERSION3.0)set(CMAKE_BUILD_TYPERelease)set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS}-std=c++14")project(main)add_executable( main add.cpp main.cpp)机器人操作系统(ROS)2.4.2创建一个CMake文件这段代码的意思一目了然,它仅仅设置了C++标志,并从源代码add.cpp和main.cpp中创建了一个名为main的可执行文件。CMake命令的使用说明可以在/documentation/中找到。将上述命令保存为CMakeLists.txt之后,我们还需要创建一个用于构建工程的文件夹。你可以为文件夹选择任何名称。在这里,我们使用build作为该文件夹的名称。$mkdirbuild在创建文件夹之后,切换到build文件夹并在当前文件夹中打开终端,并在该路径下执行以下命令。$cmake..机器人操作系统(ROS)2.4.2创建一个CMake文件此命令会解析工程路径中的CMakeLists.txt,然后将CMakeLists.txt转换为makefile,这样我们就可以通过makefile进行编译了。基本上可以说,它使编写Linuxmakefile的过程变的自动化了。如果在执行cmake..命令之后一切都成功,你应该得到如图1所示的消息。在这之后,你可以通过输入make指令($make)来编译工程。如果成功的话,项目就可以被执行了($./main)。图2展示了make指令和运行可执行文件的输出。机器人操作系统(ROS)2.5Python简介Python和C++一样,也是一门面向对象的解释型计算机程序设计语言,由荷兰人GuidovanRossum于1989年发明。Python具有丰富和强大的库,它常被昵称为胶水语言,能够把用其他语言制作的各种模块(尤其是C/C++)很轻松地联结在一起。它是一门跨平台、开源、免费的解释型高级动态编程语言,和C++最大的区别就是,Python是一门解释型语言,而C++是一门编译型语言。解释型语言指的是程序不需要编译,程序在运行时才翻译成机器语言,每执行一次都要翻译一次,因此效率比较低。比如Basic语言,专门有一个解释器能够直接执行Basic程序,每个语句都是执行的时候才翻译。而编译型语言程序在执行之前需要一个专门的编译过程,把程序编译成为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。相比较之下,使用解释型语言进行程序编写时更符合人本身的语言习惯,这也是Python成为ROS程序编写热门语言的一大重要原因。机器人操作系统(ROS)2.6.1Linux中的Python解释器与GNUC/C++编译器一样,Python解释器也预装在Ubuntu中。使用所示的命令$python可以查看系统默认的Python解释器版本。图2-26展示了系统默认的Python解释器的版本。机器人操作系统(ROS)2.6.1Linux中的Python解释器可以看到,当前默认的Python版本是2.7.12。在输入Python命令后通过按两次Tab键,还可以获得已安装的Python版本的列表。图2-27显示了Ubuntu中可用的Python版本列表。机器人操作系统(ROS)2.6.1Linux中的Python解释器在这里,你可以看到若干个Python命令,它们分别服务于两个不同的版本2.7.12和3.5.2。Python、Python2和Python2.7命令用于启动2.7.12版本,其余的命令则用于启动3.5.2版本。Python3m和Python3.5m是带有pymalloc的版本,它比使用malloc的默认内存分配性能更好。如前所述,Python在Ubuntu中是预装的,除此之外,也可以通过下面的命令手动安装相应版本的Python解释器:$sudoapt-getinstallPythonPython3机器人操作系统(ROS)2.6.2验证Python的安装本节展示如何查看Python可执行路径和版本。下面是查看Python和Python3命令的当前路径的两条命令。$whichPython$whichPython3显示结果如图所示。机器人操作系统(ROS)2.6.2验证Python的安装如果读者想查看Python二进制文件、源文件和文档的位置,则可以使用以下两条命令。$whereisPython$whereisPython3.5显示结果如图2-29所示。机器人操作系统(ROS)2.6.3编写第一条Python程序我们的第一个程序同样将打印一个“Nicetomeetyou,ROS.”消息,让我们看看如何使用Python实现它。在开始编程之前,我们需要首先了解一下Python编程的两种方式。(1)在Python解释器中直接编程;(2)编写Python脚本并使用解释器运行;这两种方法以相同的方式工作。第一个方法中的代码在解释器中逐行执行。编写脚本的方法则要求在文件中写入所有代码,然后再使用解释器执行。首先我们在命令行中用Python解释器打印“Nicetomeetyou,ROS.”消息,如图3-5所示。机器人操作系统(ROS)2.6.3编写第一条Python程序从图2-30可以看出,用Python输出消息非常容易,只需输入print语句和被打印的消息数据,然后按回车键即可,如下所示:>>>print'Nicetomeetyou,ROS.'如果你在Python3.0以上的版本中执行HelloWorld程序,那么需要对Python语句做一些更改。Python3.x和2.x的主要的差别可以在https://wiki.P/moin/Python2orPython3中找到。与Python2.x中使用的print语句不同,在Python3.x中使用下面的语句来打印消息,运行结果如图2-31所示:>>>print('Nicetomeetyou,ROS.')机器人操作系统(ROS)2.6.3编写第一条Python程序下面介绍在脚本中编写Python程序。使用脚本时,我们将代码写入扩展名为.py的文件中。编写Python代码的标准方法请参见www.P/dev/peps/pep-0008/。与创建C++可执行文件类似,我们将先创建一个名为HelloROS.py的文件,并在文件中编写代码,具体内容如下:#!/usr/bin/envpython#-*-coding:utf-8-*-print‘Nicetomeetyou,ROS.’其中的第一行“#!/usr/bin/envPython”称为Shebang。当我们执行Python代码时,程序加载器将解析这一行命令并使用该语句指定的执行环境来执行代码。这里我们将Python设置为执行环境,因此其余代码将在Python解释器中执行。接下来让我们看一下如何执行上述代码。机器人操作系统(ROS)2.6.4运行Python代码将hello_world.py保存到home文件夹或其他文件夹下。本书代码的保存路径是桌面文件夹,因此我们需把路径切换到桌面文件夹下并用如下命令执行Python代码。$pythonHello\ROS.py这里的脚本名称因为含有空格所以需要加上转义符号“\”。如果你的代码没有任何错误,它将显示如图2-32所示的输出。机器人操作系统(ROS)2.6.4运行Python代码还有另外一种方法可以执行Python文件。首先使用下面的命令向给定的Python代码提供可执行权限。$chmoda+xHello\ROS.py然后使用以下命令执行Python代码。$./Hello\ROS.py图2-33展示了如何通过上述方式执行Python脚本。接下来我们将讨论Python的基础语法。这一话题涵盖了很多内容,我们将通过具体的例子来讨论其中的各个部分,以增加读者的理解。机器人操作系统(ROS)2.7从实例中学习Python简单易学是Python语言如此受欢迎的主要原因。因为Python的代码很短,所以较之别的编程语言Python语言可以更快地帮助建立算法模型。也正是因为它如此受欢迎,所以网上有海量的Python教程资源和很多活跃的技术论坛,我们可以很容易的从中获取到技术支持。Python还有非常多的库函数来帮助你开发应用。Python库的易获得性,也是它优于别的语言的一个重要原因。有了Python库,你就可以利用现有的函数来大幅的减少开发时间。Python还是一个跨平台的语言,被广泛应用于搜索、网络、图像、游戏、机器学习、数据科学以及机器人技术。很多公司都用这种语言来实现一些自动化任务,所以靠Python找份工作是比较容易的。那么学习这门语言有多难呢?如果你可以完成一项伪代码的编写任务,那就可以用Python写代码,因为它跟伪代码非常类似。机器人操作系统(ROS)2.7.1Python中有哪些新东西如果你学过C++,那学Python就比较简单了,但是你在写Python代码时还得了解一些东西。静态语言和动态语言Python是一个动态语言,也就意味着我们不必在编程中提供变量的数据类型,它把每个变量都看作一个对象。我们可以给一个名字指定任何数据类型。但在C++中,我们需要先给变量制定一个数据类型,然后只能将那一类型的数据赋值给这个变量。C++则是一个静态类型的语言,比如在C++里我们可以这样赋值:intnumber;number=10;//这个有效number="10"//这个无效但在Python里,我们则可以这样赋值:#无需考虑数据类型number=10#有效number="10"#也有效所以现在number的值是10。机器人操作系统(ROS)2.7.1Python中有哪些新东西代码缩进缩进,就是在一行的开头敲一个tab或是几个空格。在C++里,我们可以使用缩进对代码分块,但这不是强制性的,即使我们没有缩进也可以编译。然而在Python里就不一样了,我们必须保证各代码块有一样的缩进,否则就会出现缩进的错误。当代码缩进变成强制的之后,代码看起来就会更整齐,可读性也更好。分号在C/C++中,每个语句末尾的分号是强制性的,但是在Python中,它们不是强制性的。你可以在Python中使用分号作为分隔符,但不能作为终止符。例如,如果你想在一行中编写一组代码,你可以通过分隔分号来编写它们。机器人操作系统(ROS)2.7.2Python变量现在你已经了解了Python如何处理变量。图2-34便展示了如何在Python中给变量赋值并打印不同的原始数据类型,如int、float和string。这里我们用到的测试环境为Python2.7.12版本。机器人操作系统(ROS)2.7.2Python变量类似于C/C++中的数组,Python提供列表(lists)和元组(tuples)数据类型。列表中的值可以通过使用方括号([])的列表索引进行访问。例如,可以通过[0]访问列表中的第一个元素,它类似于C/C++中的数组。图展示了Python列表和元组的示例。图3-11展示了如何使用Python元组。机器人操作系统(ROS)2.7.2Python变量元组的工作方式与列表类似,但元组包含在()中,而列表则包含在[]中。元组是只读列表,因为它的值在初始化后不能被更改,但是在列表中我们可以修改其元素的值。Python提供的另一个内置数据类型是字典(dictionary)。与实际的字典类似,它有一个键(key)和一个与之关联的值(value)。例如,在我们的字典里,有一个词和它相应的释义。这里的词便是key,value就是该词的释义。图显示了Python字典的工作原理。如果我们在字典中给出键(key),它将返回与键相关联的值。在下一节中,我们将学习Python条件语句。机器人操作系统(ROS)2.7.3Python的输入和条件语句与C++类似,Python也有if/else语句用来检查条件。在下面的示例中,你将看到Python如何处理用户输入,并基于此进行决策。程序的逻辑很简单,仅要求用户输入移动机器人的命令。如果用户输入一个有效的命令,如move_left、move_right、move_forward或move_back,程序将输出它正在移动,否则,它将输出Invalidcommand,程序如下:#!/usr/bin/envpython#-*-coding:utf-8-*-Robot_command=raw_input(“Enterthecommand:>”)if(robot_command==“move_forward”):print“Robotismovingforward.”elif(robot_command==“move_backward”):print“Robotismovingbackward.”elif(robot_command==“move_left”):print“Robotismovingleft.”elif(robot_command==“move_right”):print“Robotismovingright.”else:print“Invalidcommand.”机器人操作系统(ROS)2.7.3Python的输入和条件语句在Python中接受用户的输入,我们可以使用raw_input()函数或input()函数。raw_input()函数接受任何类型的数据,但是input()函数只能接受整数类型。下面是ra

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论