版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
機(jī)器人操作系統(tǒng)(ROS)機(jī)器人操作系統(tǒng)(ROS)ROS初識(shí)1.1機(jī)器人操作系統(tǒng)(ROS)1.1.1ROS是什么ROS是機(jī)器人操作系統(tǒng)(RobotOperatingSystem)的英文縮寫。ROS起源于2007年斯坦福大學(xué)人工智能實(shí)驗(yàn)室的STAIR項(xiàng)目與機(jī)器人技術(shù)公司W(wǎng)illowGarage的個(gè)人機(jī)器人項(xiàng)目(PR)之間的合作,2008年之后就由WillowGarage來(lái)進(jìn)行推動(dòng)。最初人們希望設(shè)計(jì)一個(gè)可以像人一樣能夠感知,并實(shí)現(xiàn)自我控制從而完成一些復(fù)雜工作的機(jī)器人。隨著機(jī)器人領(lǐng)域的快速發(fā)展,代碼的復(fù)用性和模塊化的需求原來(lái)越強(qiáng)烈,急需一個(gè)能夠整合現(xiàn)有資源的框架和接口。2010年WillowGarage公司發(fā)布了開源機(jī)器人操作系統(tǒng)ROS,很快在機(jī)器人研究領(lǐng)域展開了學(xué)習(xí)和使用ROS的熱潮。ROS起源發(fā)展機(jī)器人操作系統(tǒng)(ROS)1.1.1ROS是什么ROS是用于機(jī)器人編程的開放、靈活的軟件框架。它提供類似操作系統(tǒng)所提供的功能,包含硬件抽象描述、底層驅(qū)動(dòng)程序管理、共用功能的執(zhí)行、程序間的消息傳遞、程序發(fā)行包管理等,它也提供一些可視化和調(diào)試機(jī)器人數(shù)據(jù)的軟件工具。ROS框架的核心是消息傳遞,即使在不同的機(jī)器上運(yùn)行,進(jìn)程之間也可以相互通信和交換數(shù)據(jù)。ROS消息傳遞可以是同步的,也可以是異步的。事實(shí)上,ROS的主要目的就是為機(jī)器人研究和開發(fā)提供代碼復(fù)用的支持。ROS是一種分布式處理框架,這使可執(zhí)行文件能被單獨(dú)設(shè)計(jì),并且在運(yùn)行時(shí)松散耦合。這些過(guò)程可以封裝到數(shù)據(jù)包(Packages)和堆棧(Stacks)中,以便于共享和分發(fā)。ROS還支持代碼庫(kù)的聯(lián)合系統(tǒng),使得協(xié)作亦能被分發(fā)。上述所有功能都能由ROS的基礎(chǔ)工具實(shí)現(xiàn)。設(shè)計(jì)者將ROS表述為“ROS=Plumbing+Tools+Capabilities+Ecosystem”,即ROS是通訊機(jī)制、工具軟件包、機(jī)器人高層技能以及機(jī)器人生態(tài)系統(tǒng)的集合體。ROS的表述機(jī)器人操作系統(tǒng)(ROS)1.1.2ROS的特點(diǎn)點(diǎn)對(duì)點(diǎn)的設(shè)計(jì):節(jié)點(diǎn)是ROS編程基礎(chǔ)中一個(gè)重要的概念,在ROS中每個(gè)進(jìn)程都以一個(gè)節(jié)點(diǎn)的形式運(yùn)行,可以分布于多個(gè)不同的主機(jī)。節(jié)點(diǎn)間的消息通過(guò)一個(gè)帶有發(fā)布和訂閱功能的傳輸系統(tǒng)從發(fā)布節(jié)點(diǎn)傳送到接收節(jié)點(diǎn)。這種點(diǎn)對(duì)點(diǎn)的設(shè)計(jì)可以分散實(shí)現(xiàn)復(fù)雜功能時(shí)帶來(lái)的實(shí)時(shí)計(jì)算的壓力。多語(yǔ)言支持:為了支持更多應(yīng)用的移植和開發(fā),ROS通信框架可以輕松地以各種現(xiàn)有的編程語(yǔ)言實(shí)現(xiàn)。ROS中使用簡(jiǎn)潔、中立的定義語(yǔ)言描述模塊之間的消息接口,同時(shí)也允許消息接口的嵌套使用。目前已經(jīng)支持Python、C++、Java、Octave和LISP等多種不同的語(yǔ)言。庫(kù)集成:ROS具有許多第三方機(jī)器人庫(kù)的接口,如開源計(jì)算機(jī)視覺(Open-CV)、點(diǎn)云庫(kù)(PCL)、Open-NI、Open-Rave和Orocos。開發(fā)人員可以沒(méi)有顧慮的使用這些庫(kù)。組件化工具包豐富:ROS可采用組件化方式集成一些工具和軟件到系統(tǒng)中并作為一個(gè)組件直接使用,如RVIZ(3D可視化工具),開發(fā)者根據(jù)ROS定義的接口在其中顯示機(jī)器人模型等,組件還包括仿真環(huán)境和消息查看工具等。協(xié)作開發(fā):ROS是開源的,遵照的BSD許可給使用者較大的自由,允許修改和重新發(fā)布其中的應(yīng)用代碼,開發(fā)人員可以通過(guò)添加功能包來(lái)擴(kuò)展ROS的功能。幾乎所有的ROS包都在硬件抽象層上工作,可以輕松地為其他機(jī)器人所用。機(jī)器人操作系統(tǒng)(ROS)1.1.3ROS的發(fā)行版ROS的發(fā)行版本ROS發(fā)行版是一組版本化的ROS包,這些類似于Linux發(fā)行版(例如Ubuntu)。ROS發(fā)行版的目的是讓開發(fā)人員在相對(duì)穩(wěn)定的代碼庫(kù)上工作,直到他們準(zhǔn)備好推進(jìn)所有事情。因此,一旦發(fā)布發(fā)行版,我們就會(huì)嘗試限制對(duì)核心包(ros-desktop-full下的所有內(nèi)容)的錯(cuò)誤修復(fù)和非破壞性改進(jìn)的更改。到2022年為止,ROS已經(jīng)發(fā)布了如表1-1所示的多個(gè)版本。本書選擇的ROS版本是2018年發(fā)布的長(zhǎng)期支持版本ROSMelodicMorenia,這也是ROS發(fā)布的第12個(gè)版本,ROS官方稱將為該版本提供長(zhǎng)達(dá)5年的支持與服務(wù),并保證其與Ubuntu18.04長(zhǎng)期支持版的生命周期同步。機(jī)器人操作系統(tǒng)(ROS)本書的ROS資源1.2機(jī)器人操作系統(tǒng)(ROS)1.2本書的ROS資源本書涉及到的代碼以及相關(guān)資料均放在GitHub中托管,鏈接:/FieldRoboticsLaboratory/ROS_book可以使用以下命令下載源碼以開始后續(xù)的學(xué)習(xí)。$gitclone/FieldRoboticsLaboratory/ROS_book.git機(jī)器人操作系統(tǒng)(ROS)本章小結(jié)1.3機(jī)器人操作系統(tǒng)(ROS)1.3本章小結(jié)本章介紹了ROS的起源背景、設(shè)計(jì)目的和框架特點(diǎn)。本書還提供所有實(shí)踐的源碼,可以幫助讀者用ROS搭建豐富的機(jī)器人應(yīng)用功能。機(jī)器人操作系統(tǒng)(ROS)機(jī)器人操作系統(tǒng)(ROS)編程基礎(chǔ)知識(shí)2機(jī)器人操作系統(tǒng)(ROS)2.編程基礎(chǔ)知識(shí)在整個(gè)機(jī)器人行業(yè)中,程序是連接機(jī)器人與人的中間橋梁。通過(guò)程序,人才能夠讓機(jī)器人從裝飾品變成生產(chǎn)工具。在當(dāng)今機(jī)械控制日漸自動(dòng)化與智能化的大趨勢(shì)下,一段程序的優(yōu)劣對(duì)整個(gè)生產(chǎn)過(guò)程顯得尤為重要,任何涉及到自動(dòng)控制或是智能控制的領(lǐng)域都離不開程序的編寫。而編程語(yǔ)言作為編寫程序的工具,是搭建中間橋梁的橋墩。專注于機(jī)器人控制的ROS平臺(tái)自然也是離不開編程語(yǔ)言的。相較于其他編程語(yǔ)言,在ROS中使用的編程語(yǔ)言主要是C++和Python,因此我們將通過(guò)兩個(gè)章節(jié)的篇幅為讀者簡(jiǎn)單介紹這兩種編程語(yǔ)言及其最重要的特點(diǎn)。建議有C++與Python基礎(chǔ)的讀者也仍然閱讀一下這兩部分,熟悉一下這兩種語(yǔ)言在ROS中的運(yùn)用。本章首先簡(jiǎn)單介紹C++,主要講解C++最重要的一些基礎(chǔ)概念以及C++基本使用方法,然后介紹Python的相關(guān)知識(shí)和使用方法。機(jī)器人操作系統(tǒng)(ROS)2.1面向?qū)ο缶幊蹋╫bject-orientedprogramming)與C++簡(jiǎn)介首先我們先來(lái)描述一下面向過(guò)程編程與面向?qū)ο缶幊痰膮^(qū)別。面向過(guò)程程序的控制流程由程序中預(yù)定順序來(lái)決定;面向?qū)ο蟪绦虻目刂屏鞒逃蛇\(yùn)行時(shí)各種事件的實(shí)際發(fā)生來(lái)觸發(fā),而不再由預(yù)定順序來(lái)決定,更符合實(shí)際需要。打個(gè)比方,假如我們要設(shè)計(jì)一款圍棋游戲,如果使用面向過(guò)程語(yǔ)言,那么我們的編程思路就應(yīng)當(dāng)是第一步白棋可以下在哪里,結(jié)束以后第二步由黑棋來(lái)下,可以下在哪里,每一步下完之后判斷是否有圍殺或是勝敗,以此類推??梢砸姷?,如果將存在棋盤下滿和棋的情況考慮在內(nèi),那么就會(huì)需要許多行代碼去完成這個(gè)游戲的開發(fā)。而換成面向?qū)ο缶幊?,我們的編程思路就?huì)轉(zhuǎn)換成,白棋作為一個(gè)模塊,編寫好白棋的使用程序,黑棋作為一個(gè)模塊,由另一個(gè)人完成黑棋的使用程序,兩者再結(jié)合勝敗判定程序即可完成,將一整個(gè)連續(xù)性的程序框架拆解成各個(gè)模塊,這就是面向?qū)ο缶幊獭=酉聛?lái)在介紹C++前,我們先對(duì)C++的基礎(chǔ)C語(yǔ)言做一個(gè)簡(jiǎn)單概括。C語(yǔ)言是面向過(guò)程的結(jié)構(gòu)化和模塊化的語(yǔ)言。在處理較小規(guī)模的程序時(shí),程序員用C語(yǔ)言較為得心應(yīng)手。但是當(dāng)問(wèn)題比較復(fù)雜、程序的規(guī)模比較大時(shí),結(jié)構(gòu)化程序設(shè)計(jì)方法就顯出它的不足。C程序的設(shè)計(jì)者必須細(xì)致地設(shè)計(jì)程序中的每一個(gè)細(xì)節(jié),準(zhǔn)確地考慮程序運(yùn)行時(shí)每一時(shí)刻發(fā)生的事情,例如各個(gè)變量的值是如何變化的,什么時(shí)候應(yīng)該進(jìn)行哪些輸入,在顯示器上應(yīng)該輸出什么等,如上一段所舉的圍棋例子。這對(duì)程序員的要求是比較高的,如果面對(duì)的是一個(gè)復(fù)雜問(wèn)題,程序員往往感到力不從心。當(dāng)初提出結(jié)構(gòu)化程序設(shè)計(jì)方法的目的是解決軟件設(shè)計(jì)危機(jī),但是這個(gè)目標(biāo)并未完全實(shí)現(xiàn)。機(jī)器人操作系統(tǒng)(ROS)2.1面向?qū)ο缶幊蹋╫bject-orientedprogramming)與C++簡(jiǎn)介而C++正是為了解決這個(gè)問(wèn)題而從C語(yǔ)言的基礎(chǔ)上改進(jìn)出來(lái)的編程語(yǔ)言。在20世紀(jì)80年代提出了面向?qū)ο蟮某绦蛟O(shè)計(jì)(object-orientedprogramming,面向?qū)ο缶幊蹋┧枷耄@就需要設(shè)計(jì)出能支持面向?qū)ο蟮某绦蛟O(shè)計(jì)方法的新語(yǔ)言。Smalltalk就是當(dāng)時(shí)問(wèn)世的一種面向?qū)ο蟮恼Z(yǔ)言。而在實(shí)踐中,人們發(fā)現(xiàn)由于C語(yǔ)言是如此深入人心,使用如此廣泛,以至最好的辦法不是另外發(fā)明一種新的語(yǔ)言去代替它,而是在它原有的基礎(chǔ)上加以發(fā)展。在這種形勢(shì)下,C++應(yīng)運(yùn)而生,并且在C的后面添加自加符號(hào)++來(lái)表示這是C語(yǔ)言的增強(qiáng)版,我們也可以稱C++為帶類的C語(yǔ)言。由于C++面向?qū)ο缶幊痰谋憬菪愿臃蠙C(jī)器人開發(fā)的要求,因此ROS作為以普適性為目的的機(jī)器人平臺(tái)自然也就將C++作為主要的編程語(yǔ)言之一。接下來(lái)就將為讀者介紹一些C++編程語(yǔ)言的基礎(chǔ)知識(shí)。機(jī)器人操作系統(tǒng)(ROS)2.2在Linux中使用C++UbuntuLinux系統(tǒng)自帶一個(gè)內(nèi)置的C/C++編譯器,叫做GCC/G++。GCC即為GNUCompilerCollection,譯為GNU編譯器套件,它包括C、C++、Objective-C、Fortran、Ada和Go的編譯器,以及這些語(yǔ)言的庫(kù)。GCC是RichardStallman為GNU項(xiàng)目(/gnu/thegnuproject)編寫的。本章代碼需要在電腦中預(yù)裝Linux系統(tǒng)才能運(yùn)行,請(qǐng)讀者參考第五章內(nèi)容,安裝相應(yīng)版本的ubuntu系統(tǒng)或虛擬機(jī)。機(jī)器人操作系統(tǒng)(ROS)2.2.1GCC和G++編譯器介紹讓我們從GCC/G++編譯器開始認(rèn)識(shí)C++。最新的UbuntuLinux系統(tǒng)預(yù)裝了C和C++編譯,其中C語(yǔ)言的編譯器是GCC,C++的編譯器是G++。。在桌面或是文件夾空白處右擊,然后選中在終端中打開,或是使用快捷鍵Ctrl+Alt+t,即可打開一個(gè)終端。終端(Terminal)也是Linux系統(tǒng)操作的重要工具,希望讀者可以牢記該操作,以方便之后的學(xué)習(xí)使用。在打開的終端中先輸入gcc然后回車,接著再輸入g++然后回車,出現(xiàn)的界面如圖所示。機(jī)器人操作系統(tǒng)(ROS)2.2.1GCC和G++編譯器介紹讓我們從GCC/G++編譯器開始認(rèn)識(shí)C++。最新的UbuntuLinux系統(tǒng)預(yù)裝了C和C++編譯,其中C語(yǔ)言的編譯器是GCC,C++的編譯器是G++。。在桌面或是文件夾空白處右擊,然后選中在終端中打開,或是使用快捷鍵Ctrl+Alt+t,即可打開一個(gè)終端。終端(Terminal)也是Linux系統(tǒng)操作的重要工具,希望讀者可以牢記該操作,以方便之后的學(xué)習(xí)使用。在打開的終端中先輸入gcc然后回車,接著再輸入g++然后回車,出現(xiàn)的界面如圖所示。如果沒(méi)有得到圖2-1中的信息,則代表系統(tǒng)沒(méi)有預(yù)裝這些編譯器,可以使用Linux系統(tǒng)中安裝軟件的apt-get命令來(lái)安裝這些編譯器,下一小節(jié)我們將進(jìn)行詳細(xì)介紹。機(jī)器人操作系統(tǒng)(ROS)2.2.2安裝C/C++編譯器首先,需要打開終端并使用如下命令從軟件庫(kù)中更新Ubuntu軟件包列表:$sudoapt-getupdate然后安裝C/C++編譯器需要的兩個(gè)依賴包:$sudoapt-getinstallbuild-essentialmanpages-devbuild-essential包和許多其他基礎(chǔ)包有關(guān),它們共同用于UbuntuLinux中的軟件開發(fā)。最后安裝C/C++編譯器,指令如下:$sudoapt-getinstallgccg++機(jī)器人操作系統(tǒng)(ROS)2.2.3驗(yàn)證安裝安裝完前面的包之后,可以在終端中使用如下指令查看編譯器的安裝路徑、使用說(shuō)明頁(yè):$whereisgcc$whereisg++使用下面命令可以查看GCC編譯器的版本號(hào):$gcc--version$g++--version下圖顯示了以上命令的輸出。機(jī)器人操作系統(tǒng)(ROS)2.2.4GNU項(xiàng)目調(diào)試器GDB簡(jiǎn)介下面我們看一看C/C++的調(diào)試器。什么是調(diào)試器呢?調(diào)試器是一個(gè)可以運(yùn)行和控制另一個(gè)程序的程序,通過(guò)檢查每一行代碼來(lái)檢查程序的問(wèn)題或bug。UbuntuLinux自帶一個(gè)名為GNUDebugger的調(diào)試器,簡(jiǎn)稱GDB(/software/gdb/),它是Linux系統(tǒng)中最流行的C和C++程序調(diào)試器之一。機(jī)器人操作系統(tǒng)(ROS)2.2.5在UbuntuLinux中安裝GDB最新版本的Ubuntu中已經(jīng)安裝了GDB。如果用戶正在使用其他版本,可以使用如下命令安裝GDB:$sudoapt-getinstallgdb機(jī)器人操作系統(tǒng)(ROS)2.2.6驗(yàn)證安裝可以使用如下命令檢查GDB是否已經(jīng)準(zhǔn)確安裝在計(jì)算機(jī)中:$gdb如果安裝成功,則會(huì)顯示圖中的信息。機(jī)器人操作系統(tǒng)(ROS)2.2.6驗(yàn)證安裝圖的界面中,可以發(fā)現(xiàn)最后一行并不是正常終端操作命令執(zhí)行后的初始行,也就是并沒(méi)有出現(xiàn)之前操作命令回車執(zhí)行后界面中綠色字體的標(biāo)識(shí)符。這是因?yàn)楫?dāng)前操作命令仍然在執(zhí)行,并沒(méi)有結(jié)束,此時(shí)讀者輸入quit并敲擊回車結(jié)束gdb命令的執(zhí)行,如圖所示。在下一小節(jié)中,我們將在Ubuntu中編寫我們的第一個(gè)c++代碼,然后編譯并調(diào)試它,以找到代碼中的錯(cuò)誤。機(jī)器人操作系統(tǒng)(ROS)2.2.7編寫第一行代碼下面我們開始在UbuntuLinux中編寫第一個(gè)程序。用戶可以使用Ubuntu中的gedit,或nano終端文本編輯器來(lái)編寫代碼。gedit是ubuntu中一個(gè)常用的GUI文本編輯器,更加符合長(zhǎng)期使用Windows系統(tǒng)下的Office操作模式的人的使用習(xí)慣,因此這里我們使用gedit來(lái)編寫UbuntuLinux中的第一條程序代碼。在Ubuntu搜索中查找gedit(見圖),然后單擊打開該文本編輯器。機(jī)器人操作系統(tǒng)(ROS)2.2.7編寫第一行代碼或者也可以在終端中直接輸入gedit然后敲擊回車打開gedit,如圖所示??梢娊K端在Linux系統(tǒng)中的重要性,為了養(yǎng)成習(xí)慣,建議讀者使用終端打開gedit。機(jī)器人操作系統(tǒng)(ROS)2.2.7編寫第一行代碼gedit文本編輯器打開后,可看到如圖所示的窗口。機(jī)器人操作系統(tǒng)(ROS)2.2.7編寫第一行代碼這個(gè)編輯器非常類似于Windows中的Notepad或者WordPad,頁(yè)面十分簡(jiǎn)潔,除了少數(shù)幾個(gè)文件保存打開按鈕外就只有書寫界面,我們就將在這個(gè)文本編輯器中編寫第一個(gè)C++程序。將下列內(nèi)容輸入到我們打開的gedit界面中:#include<iostream>usingnamespacestd;intmain(){cout<<”Nicetomeetyou,ROS.”<<endl;return0;}機(jī)器人操作系統(tǒng)(ROS)2.2.7編寫第一行代碼在文本編輯器中編寫完成后,保存為HelloROS.cpp。需要注意的是,這里的.cpp必須由讀者自己手動(dòng)輸入,而不是像Windows中有下拉菜單可以選擇文件的保存格式,這也是Linux系統(tǒng)的文件命名特點(diǎn)。機(jī)器人操作系統(tǒng)(ROS)2.2.7編寫第一行代碼保存完畢后,我們可以發(fā)現(xiàn)gedit界面中我們剛才輸入的程序變成了彩色,如圖2-10所示,這就表明該文件已經(jīng)被成功保存為.cpp格式。機(jī)器人操作系統(tǒng)(ROS)2.2.8解釋代碼HelloROS.cpp里代碼的功能是將消息“Nicetomeetyou,ROS.”打印到顯示器上。代碼中的第一行“#include<iostream>”是一個(gè)C++頭文件,其中包含的最常用的就是輸入/輸出函數(shù),例如從鍵盤輸入一段字符或者將指定內(nèi)容輸出到顯示器上的cin與cout函數(shù)就是最典型的代表。在這個(gè)程序中,我們只使用了cout函數(shù)來(lái)輸出消息,所以有iostream作為頭文件就足夠了。接下來(lái)的第二行則是聲明了使用namespacestd即命名空間。命名空間(/namespacc/)是C++中的一個(gè)特性,用于對(duì)一組實(shí)體進(jìn)行分組。iostream庫(kù)中使用std定義命名空間。當(dāng)我們使用命名空間namespacestd時(shí),我們可以訪問(wèn)std命名空間中包含的所有函數(shù)或其他實(shí)體,例如cout和cin等函數(shù)。如果我們不使用這行代碼,則必須在函數(shù)前面添加std::用于訪問(wèn)該名字空間中的函數(shù);例如,std::cout是一個(gè)打印消息的函數(shù)。在討論了頭文件和其他代碼之后,我們可以討論主函數(shù)中包含的內(nèi)容了。我們使用cout<<"Nicetomeetyou,ROS."<<endl打印出一條消息。endl表明在打印消息后換行,消息打印完畢后,函數(shù)返回0并退出程序。在本章稍后的小節(jié)中我們會(huì)更加詳細(xì)地分析C++的一些基礎(chǔ)知識(shí)在ROS中的使用。機(jī)器人操作系統(tǒng)(ROS)2.2.9編譯代碼保存代碼之后,我們的.cpp文件仍然只是個(gè)文本文檔,并不是可執(zhí)行的程序,因此需要對(duì)這個(gè)文檔進(jìn)行編譯,將里面的代碼生成可執(zhí)行文件。下面的例程將幫助各位讀者完成代碼編譯的步驟??梢灾匦麓蜷_一個(gè)新終端,并使用如下命令將終端路徑切換到保存代碼的文件夾下。在本例中,我們將代碼保存到/home/桌面文件夾中。在終端中使用如下命令切換目錄和代碼編譯,編譯結(jié)果如圖所示:$cd桌面$g++HelloROS.cpp機(jī)器人操作系統(tǒng)(ROS)2.2.9編譯代碼在當(dāng)前文件夾中可以看到生成了一個(gè)新的文件a.out,這是編譯生成的可執(zhí)行文件,文件名稱由系統(tǒng)默認(rèn)生成,如需生成特定名稱的可執(zhí)行文件,我們可以使用如下指令:$g++HelloROS.cpp-ohello_ROS此時(shí)在文件夾中就會(huì)生成hello_ROS.out的可執(zhí)行文件。如圖所示:機(jī)器人操作系統(tǒng)(ROS)2.2.9編譯代碼在終端中輸入以下命令運(yùn)行生成好的可執(zhí)行文件:$./hello_ROS此時(shí)顯示器上會(huì)輸出“Nicetomeetyou,ROS”的字符串,表示程序運(yùn)行成果,如圖2-13所示:機(jī)器人操作系統(tǒng)(ROS)2.2.10調(diào)試代碼使用調(diào)試器,可以遍歷每一行代碼并檢查每個(gè)變量的值。將下面的代碼按照之前的方法通過(guò)gedit來(lái)生成相應(yīng)的.cpp文件,輸入代碼后保存為SUM.cpp文件。#include<iostream>usingnamespacestd;intmain(){intNum1=1;intNum2=2;intSum=Num1+Num2;cout<<”Sum=”<<Sum<<endl;return0;}機(jī)器人操作系統(tǒng)(ROS)2.2.10調(diào)試代碼生成.cpp文件后就要對(duì)進(jìn)行編譯了,而為了要調(diào)試/檢查每一行代碼,我們編譯的時(shí)候必須使用調(diào)試符號(hào)編譯代碼,并使其能適用于GDB調(diào)試。具體的編譯命令如下:$g++-gSUM.cpp-oSUM編譯后,可以通過(guò)運(yùn)行命令$./SUM執(zhí)行它。運(yùn)行結(jié)果如圖所示。機(jī)器人操作系統(tǒng)(ROS)2.2.10調(diào)試代碼可執(zhí)行文件創(chuàng)建成功之后,可以通過(guò)以下的命令對(duì)其進(jìn)行調(diào)試:$gdbSUM其中,SUM是可執(zhí)行文件的名稱,輸入命令后,需使用GDB的操作指令進(jìn)行代碼調(diào)試。以下是常用的幾個(gè)GDB命令,具體解釋如下:?bline_numer:在給定行號(hào)處創(chuàng)建斷點(diǎn)。在調(diào)試時(shí),調(diào)試器會(huì)在這個(gè)斷點(diǎn)處停止。?n:運(yùn)行下一行代碼。?r:運(yùn)行程序到斷點(diǎn)位置。?pvariable_name:打印變量的值。?q:退出調(diào)試器。讓我們來(lái)嘗試一下這些命令,每個(gè)命令的輸出結(jié)果如圖所示。機(jī)器人操作系統(tǒng)(ROS)2.2.10調(diào)試代碼接下來(lái)就要介紹C++最大的特點(diǎn),面向?qū)ο缶幊?,也是與C語(yǔ)言最大的區(qū)別。機(jī)器人操作系統(tǒng)(ROS)2.3從實(shí)例中學(xué)習(xí)C++中OOP的概念如果用戶已經(jīng)知道C的結(jié)構(gòu)體,那么了解OOP概念將不會(huì)花費(fèi)太多時(shí)間。在C的結(jié)構(gòu)體中,我們可以將不同的數(shù)據(jù)類型(如整數(shù)、浮點(diǎn)數(shù)和字符串)封裝到一個(gè)用戶定義的數(shù)據(jù)類型中。與C的結(jié)構(gòu)體類似,C++有一個(gè)增強(qiáng)版的結(jié)構(gòu)體,它增加了定義函數(shù)的功能。這個(gè)增強(qiáng)版本的結(jié)構(gòu)體稱為C++類。C++類的每個(gè)實(shí)例都被稱為對(duì)象。對(duì)象只是實(shí)際類的一個(gè)副本。有幾個(gè)與對(duì)象相關(guān)的屬性,稱為面向?qū)ο缶幊谈拍?。接下?lái)我們用C++代碼解釋主要的OOP概念。機(jī)器人操作系統(tǒng)(ROS)2.3.1類和結(jié)構(gòu)體之間的區(qū)別在學(xué)習(xí)OOP概念之前,讓我們先來(lái)看看結(jié)構(gòu)體和類之間的區(qū)別。首先創(chuàng)建名為class_struct.cpp的示例代碼文件,將如下內(nèi)容添加到文件中:#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;
}機(jī)器人操作系統(tǒng)(ROS)2.3.1類和結(jié)構(gòu)體之間的區(qū)別這段代碼定義了一個(gè)類和結(jié)構(gòu)體。結(jié)構(gòu)體名稱是Robot_struct,類名是Robot_Class。下面部分展示了如何定義一個(gè)結(jié)構(gòu)體。該結(jié)構(gòu)體定義了若干變量,比如機(jī)器人的編號(hào)id、名稱robot_name和輪子的數(shù)量no_wheels。structRobot_Struct
{
intid;
intno_wheels;
stringrobot_name;
};機(jī)器人操作系統(tǒng)(ROS)2.3.1類和結(jié)構(gòu)體之間的區(qū)別如大家所知,每個(gè)結(jié)構(gòu)體都有一個(gè)名字,所有變量的聲明都在里面。下面部分是類的定義:classRobot_Class{public:intid;intno_wheels;stringrobot_name;voidmove_robot();voidstop_robot();};機(jī)器人操作系統(tǒng)(ROS)2.3.1類和結(jié)構(gòu)體之間的區(qū)別所以,這兩者之間到底有什么區(qū)別呢?結(jié)構(gòu)體只能定義不同的成員變量,但是類除了可以定義多個(gè)成員變量之外還可以聲明不同成員函數(shù)。那么每個(gè)函數(shù)定義在哪里呢?我們可以在類的內(nèi)部或外部定義函數(shù)。標(biāo)準(zhǔn)的做法是在類的外部定義函數(shù),以保證類定義的簡(jiǎn)潔性。下面的程序顯示了類中所聲明的函數(shù)在類外部的定義。voidRobot_Class::move_robot(){cout<<"MovingRobot!"<<endl;}voidRobot_Class::stop_robot(){cout<<"StoppingRobot!"<<endl;}機(jī)器人操作系統(tǒng)(ROS)2.3.1類和結(jié)構(gòu)體之間的區(qū)別在函數(shù)定義中,第一項(xiàng)是返回?cái)?shù)據(jù)的類型,然后是類名,再然后是用::連接的函數(shù)名。表明函數(shù)是包含在類中的。在函數(shù)定義中,我們可以輸入我們的代碼,函數(shù)中這段特定的代碼打印了一條信息。你已經(jīng)看到類的函數(shù)定義。下一步是學(xué)習(xí)如何讀/寫變量和使用函數(shù)。機(jī)器人操作系統(tǒng)(ROS)2.3.2C++的類和對(duì)象本節(jié)將解釋如何讀/寫結(jié)構(gòu)體和類中的變量。下面程序是創(chuàng)建結(jié)構(gòu)體和類的代碼:Robot_Structrobot_1;Robot_Classrobot_2;robot_1.id=2;robot_1.robot_name="Mobilerobot";robot_2.id=3;robot_2.robot_name="NoWheelsrobot";機(jī)器人操作系統(tǒng)(ROS)2.3.2C++的類和對(duì)象與結(jié)構(gòu)體實(shí)例類似,我們可以創(chuàng)建一個(gè)類的實(shí)例,稱之為對(duì)象。讓我們來(lái)看看Robot_Classrobot_2;在這里,robot_2是一個(gè)對(duì)象,而robot1是結(jié)構(gòu)體的一個(gè)實(shí)例。使用這個(gè)實(shí)例或?qū)ο螅覀兛梢栽L問(wèn)每一個(gè)變量和函數(shù)。我們可以使用.操作符去訪問(wèn)每一個(gè)變量。結(jié)構(gòu)體和類中的變量都可以使用.操作符進(jìn)行訪問(wèn)。如果是使用結(jié)構(gòu)體或類的指針,則必須使用->操作符來(lái)訪問(wèn)每個(gè)變量。如下所示:Robot_Class*robot_3;robot_3=newRobot_Class;robot_3->id=4;robot_3->robot_name="Rosrobot";機(jī)器人操作系統(tǒng)(ROS)2.3.2C++的類和對(duì)象其中,new操作符為C++變量分配內(nèi)存。我們可以使用操作符調(diào)用類中的函數(shù)和打印變量,程序如下所示: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();機(jī)器人操作系統(tǒng)(ROS)2.3.2C++的類和對(duì)象我們使用命令$g++class_struct.cpp-oclass_struct和$./class_struct編譯它。圖2-16顯示了這段代碼的輸出??稍L問(wèn)/cplusplus/cpp_classes_objects.htm,以便進(jìn)一步參考。機(jī)器人操作系統(tǒng)(ROS)2.3.3類訪問(wèn)修飾符在類中,用戶也許已經(jīng)看到了一個(gè)叫做public:的關(guān)鍵字,它被稱為成員訪問(wèn)限定符。下面代碼部分是使用訪問(wèn)修飾符的代碼。classRobot_Class{public:intid;intno_wheels;...};機(jī)器人操作系統(tǒng)(ROS)2.3.3類訪問(wèn)修飾符這一功能也稱為數(shù)據(jù)隱藏,通過(guò)設(shè)置成員訪問(wèn)修飾符,我們可以限制在類內(nèi)部定義的函數(shù)的使用范圍。類中有三種訪問(wèn)修飾符:public:一個(gè)public成員可以從類之外的任何地方訪問(wèn)。我們可以直接訪問(wèn)公共變量,而不需要編寫其他輔助函數(shù)。private:使用該修飾符號(hào)的成員變量或函數(shù),不能從類外部被查看或訪問(wèn)。只有類和友元函數(shù)可以訪問(wèn)私有成員。protected:訪問(wèn)非常類似于private成員,但是不同的是它的子類可以訪問(wèn)其成員。子類/派生類的概念將在下一節(jié)進(jìn)行討論。訪問(wèn)修飾符可以幫助你將變量分組,這些變量可以在類中保持可見或隱藏。機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用繼承(Inheritance)是OOP中的另一個(gè)重要概念。如果你有兩個(gè)或多個(gè)類,并且希望在一個(gè)新類中擁有這些類中的函數(shù),那么可以使用繼承屬性。通過(guò)使用繼承屬性,你可以在新類中重用現(xiàn)有類中的函數(shù)。我們將要繼承現(xiàn)有類的新類稱為派生類,已有的類稱為基類。類可以通過(guò)public、private或protected來(lái)繼承。下面將解釋每種繼承類型。publicinheritance:當(dāng)我們派生自public基類時(shí),基類的public成員成為派生類的public成員,并且基類的protected成員成為派生類的protected成員。基類的private成員不能在派生類中訪問(wèn),但可以通過(guò)對(duì)基類的public和protected成員函數(shù)的調(diào)用來(lái)訪問(wèn)。protectedinheritance:當(dāng)我們使用protected基類繼承時(shí),基類的public和protected成員成為派生類的protected成員。privateinheritance:當(dāng)我們派生自private基類時(shí),基類的public和protected成員成為派生類的private成員。機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用我們創(chuàng)建一個(gè)public繼承的簡(jiǎn)單示例代碼class_inheritance.cpp,并填入如下內(nèi)容:#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;}機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用在本例中,我們創(chuàng)建了一個(gè)名為Robot_Class_Derived的新類,它派生自一個(gè)名為Robot_Class的基類。公共繼承是通過(guò)使用public關(guān)鍵字加后邊的基類名實(shí)現(xiàn)的,即在派生類名之后緊接著是一個(gè)public關(guān)鍵字和一個(gè)基類名。classRobot_Class_Derived:publicRobot_Class{public: voidturn_left(); voidturn_right();};機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用Robot_Class在這種情況下,如果選擇公共繼承,則可以訪問(wèn)基類的public和protected修飾的變量和函數(shù)。我們使用的類與第一個(gè)示例中使用的類相同。派生類中每個(gè)函數(shù)的定義如下所示:voidRobot_Class_Derived::turn_left(){ cout<<"RobotTurnleft"<<endl;}voidRobot_Class_Derived::turn_right(){ cout<<"RobotTurnRight"<<endl;}機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用現(xiàn)在讓我們看看如何訪問(wèn)派生類中的函數(shù):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();機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用在這里,我們創(chuàng)建了一個(gè)名為“robot”的“Robo_Class_Derived”對(duì)象。如果用戶仔細(xì)閱讀代碼,便可以理解,在Robo_Class_Derived中,我們沒(méi)有聲明id和robot_name變量,它是在Robo_Class中定義的。通過(guò)使用inheritance屬性,我們可以在派生類Robo_Class_Derived中訪問(wèn)Robo_Class的變量。下面讓我們看一下代碼的輸出,通過(guò)使用下面的命令來(lái)編譯class_inheritance.cpp文件:$g++class_inherit.cpp-oclass_inherit$./class_inherit這將得到如圖2-17所示的輸出,沒(méi)有顯示任何錯(cuò)誤。這意味著此公共繼承運(yùn)行良好。機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用根據(jù)輸出可以觀察到,我們從基類和派生類中定義的函數(shù)中獲取了所有消息。此外,我們還可以訪問(wèn)基類變量并設(shè)置它的值我們已經(jīng)介紹了一些重要的OOP概念。如果需要了解更多的概念,請(qǐng)參考/cplusplus.機(jī)器人操作系統(tǒng)(ROS)2.3.5C++文件和流下面讓我們來(lái)一起討論C++中的文件操作以及文件讀寫。我們已經(jīng)討論了用于執(zhí)行文件操作的iostream頭文件,我們還需要另一個(gè)標(biāo)準(zhǔn)的C++庫(kù)fstream。在fstream中有以下三種數(shù)據(jù)類型。ofstream:表示輸出文件流。它用于創(chuàng)建文件并將數(shù)據(jù)寫入其中。ifstream:表示輸入文件流。它用于從文件中讀取數(shù)據(jù)。fstream:同時(shí)具有讀/寫能力。機(jī)器人操作系統(tǒng)(ROS)2.3.5C++文件和流下面代碼展示了如何使用C++函數(shù)讀/寫文件:#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;}機(jī)器人操作系統(tǒng)(ROS)2.3.5C++文件和流代碼必須包含fstream頭,以獲得C++中的讀/寫數(shù)據(jù)類型。我們已經(jīng)創(chuàng)建了一個(gè)ofstream類對(duì)象,其中包含一個(gè)名為open()的函數(shù),用于打開文件。打開文件后,我們可以使用<<運(yùn)算符對(duì)其進(jìn)行寫入。寫完數(shù)據(jù)后,我們關(guān)閉文件為讀取操作做準(zhǔn)備。為了讀入數(shù)據(jù),我們?cè)贑++中使用ifstream類對(duì)象,并使用ifstream類中的open(“file_name”)函數(shù)打開文件。打開文件后,我們可以使用>>操作符從文件中讀取數(shù)據(jù)。讀取完畢后,在終端中打印。我們要寫的文件名是Config.txt并且數(shù)據(jù)是一個(gè)機(jī)器人相關(guān)的參數(shù)。圖2-18顯示了編譯并運(yùn)行代碼后的輸出結(jié)果。你可以看到Config.txt已經(jīng)在桌面文件夾中被創(chuàng)建了出來(lái)。相關(guān)詳細(xì)信息,請(qǐng)?jiān)L問(wèn)/cplusplus/cpp_files_streams.htm。機(jī)器人操作系統(tǒng)(ROS)2.3.6C++中的命名空間在此之前,HelloWorld代碼中提到了命名空間的概念。在本節(jié)中,你將學(xué)習(xí)如何創(chuàng)建、在何處使用以及如何訪問(wèn)命名空間。下面代碼提供了一個(gè)創(chuàng)建和使用兩個(gè)命名空間的示例:#include<iostream>usingnamespacestd;namespacerobot{ voidprocess(void) { cout<<"ProcessingbyRobot"<<endl; }}namespacemachine{ voidprocess(void) { cout<<"ProcessingbyMachine"<<endl; }}intmain(){ robot::process(); machine::process();}機(jī)器人操作系統(tǒng)(ROS)2.3.6C++中的命名空間創(chuàng)建命名空間時(shí),要使用關(guān)鍵詞namespace,后面緊跟這個(gè)命名空間的名字。其中我們定義了兩個(gè)命名空間。如果查看代碼,你會(huì)發(fā)現(xiàn)在每個(gè)命名空間里都定義了相同的函數(shù)。這些命名空間用來(lái)對(duì)實(shí)現(xiàn)某一特定操作的一系列函數(shù)或類進(jìn)行分組。通過(guò)使用這個(gè)命名空間的名稱,后跟::加函數(shù)名的方式,我們可以訪問(wèn)命名空間里的成員。在這段代碼中,我們?cè)诿臻g里調(diào)用了兩個(gè)函數(shù),分別是robot和machine。圖展示了代碼里代碼的輸出。這段代碼被保存為namespace.cpp。更多的參考,可以訪問(wèn)/cplusplus/cpp_exceptions_handling.htm。機(jī)器人操作系統(tǒng)(ROS)2.3.7C++的異常處理異常處理Exceptionhandling是C++中的的一種新特性,它可以用來(lái)處理當(dāng)用戶輸入后產(chǎn)生非預(yù)期的輸出響應(yīng)的情況。下面是C++異常處理特性的一個(gè)例子:#include<iostream>usingnamespacestd;intmain(){ try { intno_1=1; intno_2=0; if(no_2==0) { throwno_1; } }
catch(inte) { cout<<"Exceptionfound:"<<e<<endl; }}機(jī)器人操作系統(tǒng)(ROS)2.3.7C++的異常處理異常處理Exceptionhandling是C++中的的一種新特性,它可以用來(lái)處理當(dāng)用戶輸入后產(chǎn)生非預(yù)期的輸出響應(yīng)的情況。下面是C++異常處理特性的一個(gè)例子:#include<iostream>usingnamespacestd;intmain(){try{intno_1=1;intno_2=0;if(no_2==0) { throwno_1; }}
catch(inte){ cout<<"Exceptionfound:"<<e<<endl;}}機(jī)器人操作系統(tǒng)(ROS)2.3.7C++的異常處理我們主要用三個(gè)關(guān)鍵詞來(lái)處理異常情況。try:在try后面的測(cè)試塊中編寫可能會(huì)引發(fā)異常的代碼。catch:如果try后的測(cè)試塊中出現(xiàn)了異常,則catch后面的代碼塊會(huì)捕捉這個(gè)異常。然后我們可以決定如何處理這個(gè)異常情況。throw:當(dāng)開始出現(xiàn)問(wèn)題時(shí),我們可以從測(cè)試塊中拋出一個(gè)異常。該異??梢员缓筮叺腸atch塊捕捉到。機(jī)器人操作系統(tǒng)(ROS)2.3.7C++的異常處理下面代碼展示了異常處理的基本結(jié)構(gòu):try{ //Ourcodesnippets}catch(Exceptionname){ //Exceptionhandlingblock}機(jī)器人操作系統(tǒng)(ROS)2.3.7C++的異常處理這個(gè)代碼是在查詢num_2是否為0。當(dāng)num_2為0時(shí),就會(huì)拋出一個(gè)由throw關(guān)鍵詞num_1引發(fā)的異常,然后catch塊會(huì)捕捉該異常并檢查num_1的值。圖展示了代碼編譯和輸出結(jié)果。我們可以在catch塊中打印異常值(也就是num_1的值,也就是1)。異常處理被廣泛地運(yùn)用于簡(jiǎn)單的程序調(diào)試。更多的參考,可以訪問(wèn)/exception-handling-c/。機(jī)器人操作系統(tǒng)(ROS)2.3.8C++的標(biāo)準(zhǔn)模板庫(kù)如果你想使用一些數(shù)據(jù)結(jié)構(gòu),比如列表(list)、堆棧(stacks)、數(shù)組(arrays)等等,標(biāo)準(zhǔn)模板庫(kù)(StandardTemplateLibrary,STL)是最好的選擇。STL為計(jì)算機(jī)科學(xué)提供了多樣的標(biāo)準(zhǔn)算法的實(shí)現(xiàn),比如排序和搜索,以及類似于向量、列表、隊(duì)列等數(shù)據(jù)結(jié)構(gòu)。這是一個(gè)先進(jìn)的C++概念,如果想瀏覽一下相關(guān)信息,可以訪問(wèn)/the-c-standard-template-library-stl/。機(jī)器人操作系統(tǒng)(ROS)2.4建立一個(gè)C++工程現(xiàn)在你已經(jīng)學(xué)習(xí)了一些重要的OOP概念,現(xiàn)在讓我們來(lái)看看如何建立C++工程。想象一下,你有成百上千個(gè)源代碼文件,而且你需要編譯、鏈接它們,你要如何處理?這一部分將討論這個(gè)問(wèn)題。如果你想使用多個(gè)源代碼文件,需要使用下列工具來(lái)編譯、鏈接你的工程。Linuxmakefile可以非常方便的用來(lái)編譯一個(gè)或多個(gè)源文件,并生成可執(zhí)行文件。讓我們通過(guò)一個(gè)簡(jiǎn)單的工程來(lái)證明makefile的能力。我們將編寫一些代碼來(lái)對(duì)兩個(gè)數(shù)字求和,為此我們要先建立一個(gè)類。當(dāng)編寫C++類的時(shí)候,我們可以和main函數(shù)一起在源文件中聲明和定義這個(gè)類。另外一種聲明和定義類的方式是使用.h文件和.cpp文件,然后把.h文件包含到main函數(shù)所在的源文件中。這種方法對(duì)整個(gè)項(xiàng)目的模塊化很有幫助。我們的工程包含三個(gè)文件。main.cpp:是我們將要構(gòu)建的主要代碼。add.h:add類的頭文件,包含一個(gè)類的聲明。add.cpp:這個(gè)文件里含有類add的全部定義。最好將類、頭文件、.cpp文件用同一個(gè)名字命名。這里我們建立類add,所以頭文件名是add.h和add.cpp。機(jī)器人操作系統(tǒng)(ROS)2.4建立一個(gè)C++工程以下是add.h代碼:#include<iostream>classadd{public: intcompute(intno_1,intno_2);};以下是add.cpp代碼:#include"add.h"intadd::compute(inta,intb){ return(a+b);}機(jī)器人操作系統(tǒng)(ROS)2.4建立一個(gè)C++工程以下是main.cpp代碼:#include"add.h"usingnamespacestd;intmain(){ addobj; intresult=pute(43,34); cout<<"TheResult:="<<result<<endl; return0;}機(jī)器人操作系統(tǒng)(ROS)2.4建立一個(gè)C++工程在main.cpp中,我們首先通過(guò)包含add.h頭文件來(lái)訪問(wèn)add類,然后創(chuàng)建了add類的一個(gè)對(duì)象,并將兩個(gè)數(shù)字傳遞給compute函數(shù),最后打印結(jié)果。我們可以使用以下命令編譯并執(zhí)行中的代碼,其輸出結(jié)果如圖所示。對(duì)于編譯單個(gè)源代碼,g++命令很容易使用,但是如果我們想要編譯若干個(gè)源代碼,那么g++命令就不那么方便了。Linuxmakefile則提供了一種組織、編譯多個(gè)源代碼文件的方法。下面部分將展示了如何通過(guò)編寫makefile文件來(lái)編譯代碼。機(jī)器人操作系統(tǒng)(ROS)2.4建立一個(gè)C++工程這部分是LinuxMakefile文件內(nèi)容: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機(jī)器人操作系統(tǒng)(ROS)2.4建立一個(gè)C++工程上面代碼保存為makefile之后,我們必須執(zhí)行以下命令來(lái)執(zhí)行編譯。$make這樣就編譯了源代碼,如圖2-22所示。在使用make命令編譯之后,可以使用以下命令執(zhí)行程序。結(jié)果如圖2-23所示:$./main你可以通過(guò)/cplusplus/gnumake.php了解更多關(guān)于makefile的信息機(jī)器人操作系統(tǒng)(ROS)2.4.2創(chuàng)建一個(gè)CMake文件CMake()是構(gòu)建C++工程的另一種方法。CMake代表cross-platformmakefile。它是一個(gè)開源工具,可以跨操作系統(tǒng)編譯、測(cè)試和打包軟件。我們可以使用以下命令安裝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)機(jī)器人操作系統(tǒng)(ROS)2.4.2創(chuàng)建一個(gè)CMake文件這段代碼的意思一目了然,它僅僅設(shè)置了C++標(biāo)志,并從源代碼add.cpp和main.cpp中創(chuàng)建了一個(gè)名為main的可執(zhí)行文件。CMake命令的使用說(shuō)明可以在/documentation/中找到。將上述命令保存為CMakeLists.txt之后,我們還需要?jiǎng)?chuàng)建一個(gè)用于構(gòu)建工程的文件夾。你可以為文件夾選擇任何名稱。在這里,我們使用build作為該文件夾的名稱。$mkdirbuild在創(chuàng)建文件夾之后,切換到build文件夾并在當(dāng)前文件夾中打開終端,并在該路徑下執(zhí)行以下命令。$cmake..機(jī)器人操作系統(tǒng)(ROS)2.4.2創(chuàng)建一個(gè)CMake文件此命令會(huì)解析工程路徑中的CMakeLists.txt,然后將CMakeLists.txt轉(zhuǎn)換為makefile,這樣我們就可以通過(guò)makefile進(jìn)行編譯了。基本上可以說(shuō),它使編寫Linuxmakefile的過(guò)程變的自動(dòng)化了。如果在執(zhí)行cmake..命令之后一切都成功,你應(yīng)該得到如圖1所示的消息。在這之后,你可以通過(guò)輸入make指令($make)來(lái)編譯工程。如果成功的話,項(xiàng)目就可以被執(zhí)行了($./main)。圖2展示了make指令和運(yùn)行可執(zhí)行文件的輸出。機(jī)器人操作系統(tǒng)(ROS)2.5Python簡(jiǎn)介Python和C++一樣,也是一門面向?qū)ο蟮慕忉屝陀?jì)算機(jī)程序設(shè)計(jì)語(yǔ)言,由荷蘭人GuidovanRossum于1989年發(fā)明。Python具有豐富和強(qiáng)大的庫(kù),它常被昵稱為膠水語(yǔ)言,能夠把用其他語(yǔ)言制作的各種模塊(尤其是C/C++)很輕松地聯(lián)結(jié)在一起。它是一門跨平臺(tái)、開源、免費(fèi)的解釋型高級(jí)動(dòng)態(tài)編程語(yǔ)言,和C++最大的區(qū)別就是,Python是一門解釋型語(yǔ)言,而C++是一門編譯型語(yǔ)言。解釋型語(yǔ)言指的是程序不需要編譯,程序在運(yùn)行時(shí)才翻譯成機(jī)器語(yǔ)言,每執(zhí)行一次都要翻譯一次,因此效率比較低。比如Basic語(yǔ)言,專門有一個(gè)解釋器能夠直接執(zhí)行Basic程序,每個(gè)語(yǔ)句都是執(zhí)行的時(shí)候才翻譯。而編譯型語(yǔ)言程序在執(zhí)行之前需要一個(gè)專門的編譯過(guò)程,把程序編譯成為機(jī)器語(yǔ)言的文件,運(yùn)行時(shí)不需要重新翻譯,直接使用編譯的結(jié)果就行了。相比較之下,使用解釋型語(yǔ)言進(jìn)行程序編寫時(shí)更符合人本身的語(yǔ)言習(xí)慣,這也是Python成為ROS程序編寫熱門語(yǔ)言的一大重要原因。機(jī)器人操作系統(tǒng)(ROS)2.6.1Linux中的Python解釋器與GNUC/C++編譯器一樣,Python解釋器也預(yù)裝在Ubuntu中。使用所示的命令$python可以查看系統(tǒng)默認(rèn)的Python解釋器版本。圖2-26展示了系統(tǒng)默認(rèn)的Python解釋器的版本。機(jī)器人操作系統(tǒng)(ROS)2.6.1Linux中的Python解釋器可以看到,當(dāng)前默認(rèn)的Python版本是2.7.12。在輸入Python命令后通過(guò)按兩次Tab鍵,還可以獲得已安裝的Python版本的列表。圖2-27顯示了Ubuntu中可用的Python版本列表。機(jī)器人操作系統(tǒng)(ROS)2.6.1Linux中的Python解釋器在這里,你可以看到若干個(gè)Python命令,它們分別服務(wù)于兩個(gè)不同的版本2.7.12和3.5.2。Python、Python2和Python2.7命令用于啟動(dòng)2.7.12版本,其余的命令則用于啟動(dòng)3.5.2版本。Python3m和Python3.5m是帶有pymalloc的版本,它比使用malloc的默認(rèn)內(nèi)存分配性能更好。如前所述,Python在Ubuntu中是預(yù)裝的,除此之外,也可以通過(guò)下面的命令手動(dòng)安裝相應(yīng)版本的Python解釋器:$sudoapt-getinstallPythonPython3機(jī)器人操作系統(tǒng)(ROS)2.6.2驗(yàn)證Python的安裝本節(jié)展示如何查看Python可執(zhí)行路徑和版本。下面是查看Python和Python3命令的當(dāng)前路徑的兩條命令。$whichPython$whichPython3顯示結(jié)果如圖所示。機(jī)器人操作系統(tǒng)(ROS)2.6.2驗(yàn)證Python的安裝如果讀者想查看Python二進(jìn)制文件、源文件和文檔的位置,則可以使用以下兩條命令。$whereisPython$whereisPython3.5顯示結(jié)果如圖2-29所示。機(jī)器人操作系統(tǒng)(ROS)2.6.3編寫第一條Python程序我們的第一個(gè)程序同樣將打印一個(gè)“Nicetomeetyou,ROS.”消息,讓我們看看如何使用Python實(shí)現(xiàn)它。在開始編程之前,我們需要首先了解一下Python編程的兩種方式。(1)在Python解釋器中直接編程;(2)編寫Python腳本并使用解釋器運(yùn)行;這兩種方法以相同的方式工作。第一個(gè)方法中的代碼在解釋器中逐行執(zhí)行。編寫腳本的方法則要求在文件中寫入所有代碼,然后再使用解釋器執(zhí)行。首先我們?cè)诿钚兄杏肞ython解釋器打印“Nicetomeetyou,ROS.”消息,如圖3-5所示。機(jī)器人操作系統(tǒng)(ROS)2.6.3編寫第一條Python程序從圖2-30可以看出,用Python輸出消息非常容易,只需輸入print語(yǔ)句和被打印的消息數(shù)據(jù),然后按回車鍵即可,如下所示:>>>print'Nicetomeetyou,ROS.'如果你在Python3.0以上的版本中執(zhí)行HelloWorld程序,那么需要對(duì)Python語(yǔ)句做一些更改。Python3.x和2.x的主要的差別可以在https://wiki.P/moin/Python2orPython3中找到。與Python2.x中使用的print語(yǔ)句不同,在Python3.x中使用下面的語(yǔ)句來(lái)打印消息,運(yùn)行結(jié)果如圖2-31所示:>>>print('Nicetomeetyou,ROS.')機(jī)器人操作系統(tǒng)(ROS)2.6.3編寫第一條Python程序下面介紹在腳本中編寫Python程序。使用腳本時(shí),我們將代碼寫入擴(kuò)展名為.py的文件中。編寫Python代碼的標(biāo)準(zhǔn)方法請(qǐng)參見www.P/dev/peps/pep-0008/。與創(chuàng)建C++可執(zhí)行文件類似,我們將先創(chuàng)建一個(gè)名為HelloROS.py的文件,并在文件中編寫代碼,具體內(nèi)容如下:#!/usr/bin/envpython#-*-coding:utf-8-*-print‘Nicetomeetyou,ROS.’其中的第一行“#!/usr/bin/envPython”稱為Shebang。當(dāng)我們執(zhí)行Python代碼時(shí),程序加載器將解析這一行命令并使用該語(yǔ)句指定的執(zhí)行環(huán)境來(lái)執(zhí)行代碼。這里我們將Python設(shè)置為執(zhí)行環(huán)境,因此其余代碼將在Python解釋器中執(zhí)行。接下來(lái)讓我們看一下如何執(zhí)行上述代碼。機(jī)器人操作系統(tǒng)(ROS)2.6.4運(yùn)行Python代碼將hello_world.py保存到home文件夾或其他文件夾下。本書代碼的保存路徑是桌面文件夾,因此我們需把路徑切換到桌面文件夾下并用如下命令執(zhí)行Python代碼。$pythonHello\ROS.py這里的腳本名稱因?yàn)楹锌崭袼孕枰由限D(zhuǎn)義符號(hào)“\”。如果你的代碼沒(méi)有任何錯(cuò)誤,它將顯示如圖2-32所示的輸出。機(jī)器人操作系統(tǒng)(ROS)2.6.4運(yùn)行Python代碼還有另外一種方法可以執(zhí)行Python文件。首先使用下面的命令向給定的Python代碼提供可執(zhí)行權(quán)限。$chmoda+xHello\ROS.py然后使用以下命令執(zhí)行Python代碼。$./Hello\ROS.py圖2-33展示了如何通過(guò)上述方式執(zhí)行Python腳本。接下來(lái)我們將討論P(yáng)ython的基礎(chǔ)語(yǔ)法。這一話題涵蓋了很多內(nèi)容,我們將通過(guò)具體的例子來(lái)討論其中的各個(gè)部分,以增加讀者的理解。機(jī)器人操作系統(tǒng)(ROS)2.7從實(shí)例中學(xué)習(xí)Python簡(jiǎn)單易學(xué)是Python語(yǔ)言如此受歡迎的主要原因。因?yàn)镻ython的代碼很短,所以較之別的編程語(yǔ)言Python語(yǔ)言可以更快地幫助建立算法模型。也正是因?yàn)樗绱耸軞g迎,所以網(wǎng)上有海量的Python教程資源和很多活躍的技術(shù)論壇,我們可以很容易的從中獲取到技術(shù)支持。Python還有非常多的庫(kù)函數(shù)來(lái)幫助你開發(fā)應(yīng)用。Python庫(kù)的易獲得性,也是它優(yōu)于別的語(yǔ)言的一個(gè)重要原因。有了Python庫(kù),你就可以利用現(xiàn)有的函數(shù)來(lái)大幅的減少開發(fā)時(shí)間。Python還是一個(gè)跨平臺(tái)的語(yǔ)言,被廣泛應(yīng)用于搜索、網(wǎng)絡(luò)、圖像、游戲、機(jī)器學(xué)習(xí)、數(shù)據(jù)科學(xué)以及機(jī)器人技術(shù)。很多公司都用這種語(yǔ)言來(lái)實(shí)現(xiàn)一些自動(dòng)化任務(wù),所以靠Python找份工作是比較容易的。那么學(xué)習(xí)這門語(yǔ)言有多難呢?如果你可以完成一項(xiàng)偽代碼的編寫任務(wù),那就可以用Python寫代碼,因?yàn)樗鷤未a非常類似。機(jī)器人操作系統(tǒng)(ROS)2.7.1Python中有哪些新東西如果你學(xué)過(guò)C++,那學(xué)Python就比較簡(jiǎn)單了,但是你在寫Python代碼時(shí)還得了解一些東西。靜態(tài)語(yǔ)言和動(dòng)態(tài)語(yǔ)言Python是一個(gè)動(dòng)態(tài)語(yǔ)言,也就意味著我們不必在編程中提供變量的數(shù)據(jù)類型,它把每個(gè)變量都看作一個(gè)對(duì)象。我們可以給一個(gè)名字指定任何數(shù)據(jù)類型。但在C++中,我們需要先給變量制定一個(gè)數(shù)據(jù)類型,然后只能將那一類型的數(shù)據(jù)賦值給這個(gè)變量。C++則是一個(gè)靜態(tài)類型的語(yǔ)言,比如在C++里我們可以這樣賦值:intnumber;number=10;//這個(gè)有效number="10"http://這個(gè)無(wú)效但在Python里,我們則可以這樣賦值:#無(wú)需考慮數(shù)據(jù)類型number=10#有效number="10"#也有效所以現(xiàn)在number的值是10。機(jī)器人操作系統(tǒng)(ROS)2.7.1Python中有哪些新東西代碼縮進(jìn)縮進(jìn),就是在一行的開頭敲一個(gè)tab或是幾個(gè)空格。在C++里,我們可以使用縮進(jìn)對(duì)代碼分塊,但這不是強(qiáng)制性的,即使我們沒(méi)有縮進(jìn)也可以編譯。然而在Python里就不一樣了,我們必須保證各代碼塊有一樣的縮進(jìn),否則就會(huì)出現(xiàn)縮進(jìn)的錯(cuò)誤。當(dāng)代碼縮進(jìn)變成強(qiáng)制的之后,代碼看起來(lái)就會(huì)更整齊,可讀性也更好。分號(hào)在C/C++中,每個(gè)語(yǔ)句末尾的分號(hào)是強(qiáng)制性的,但是在Python中,它們不是強(qiáng)制性的。你可以在Python中使用分號(hào)作為分隔符,但不能作為終止符。例如,如果你想在一行中編寫一組代碼,你可以通過(guò)分隔分號(hào)來(lái)編寫它們。機(jī)器人操作系統(tǒng)(ROS)2.7.2Python變量現(xiàn)在你已經(jīng)了解了Python如何處理變量。圖2-34便展示了如何在Python中給變量賦值并打印不同的原始數(shù)據(jù)類型,如int、float和string。這里我們用到的測(cè)試環(huán)境為Python2.7.12版本。機(jī)器人操作系統(tǒng)(ROS)2.7.2Python變量類似于C/C++中的數(shù)組,Python提供列表(lists)和元組(tuples)數(shù)據(jù)類型。列表中的值可以通過(guò)使用方括號(hào)([])的列表索引進(jìn)行訪問(wèn)。例如,可以通過(guò)[0]訪問(wèn)列表中的第一個(gè)元素,它類似于C/C++中的數(shù)組。圖展示了Python列表和元組的示例。圖3-11展示了如何使用Python元組。機(jī)器人操作系統(tǒng)(ROS)2.7.2Python變量元組的工作方式與列表類似,但元組包含在()中,而列表則包含在[]中。元組是只讀列表,因?yàn)樗闹翟诔跏蓟蟛荒鼙桓?,但是在列表中我們可以修改其元素的值。Python提供的另一個(gè)內(nèi)置數(shù)據(jù)類型是字典(dictionary)。與實(shí)際的字典類似,它有一個(gè)鍵(key)和一個(gè)與之關(guān)聯(lián)的值(value)。例如,在我們的字典里,有一個(gè)詞和它相應(yīng)的釋義。這里的詞便是key,value就是該詞的釋義。圖顯示了Python字典的工作原理。如果我們?cè)谧值渲薪o出鍵(key),它將返回與鍵相關(guān)聯(lián)的值。在下一節(jié)中,我們將學(xué)習(xí)Python條件語(yǔ)句。機(jī)器人操作系統(tǒng)(ROS)2.7.3Python的輸入和條件語(yǔ)句與C++類似,Python也有if/else語(yǔ)句用來(lái)檢查條件。在下面的示例中,你將看到Python如何處理用戶輸入,并基于此進(jìn)行決策。程序的邏輯很簡(jiǎn)單,僅要求用戶輸入移動(dòng)機(jī)器人的命令。如果用戶輸入一個(gè)有效的命令,如move_left、move_right、move_forward或move_back,程序?qū)⑤敵鏊谝苿?dòng),否則,它將輸出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.”機(jī)器人操作系統(tǒng)(ROS)2.7.3Python的輸入和條件語(yǔ)句在Python中接受用戶的輸入,我們可以使用raw_input()函數(shù)或input()函數(shù)。raw_input()函數(shù)接受任何類型的數(shù)據(jù),但是input()函數(shù)只能接受整數(shù)類型。下面是ra
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 酒店改造合同范例范例
- 戶外汽燈租賃合同范例
- 鋪位 租賃合同范例
- 快遞員合作合同范例
- 家具買賣貸款合同范例
- 市政材料供應(yīng)合同范例
- 含司機(jī)租車合同范例
- 鞋面批發(fā)采購(gòu)合同范例
- 藥品合同范例格式
- 裝修固定總價(jià)合同范例
- 2024-2025學(xué)年高二上學(xué)期期末數(shù)學(xué)試卷(提高篇)(含答案)
- 2025年安全生產(chǎn)目標(biāo)實(shí)施計(jì)劃
- 福建百校2025屆高三12月聯(lián)考?xì)v史試卷(含答案解析)
- 2024年山西省建筑安全員《B證》考試題庫(kù)及答案
- 2023年益陽(yáng)市安化縣招聘鄉(xiāng)鎮(zhèn)衛(wèi)生院護(hù)理人員筆試真題
- 《基于PLC的智能交通燈控制系統(tǒng)設(shè)計(jì)》10000字(論文)
- 首都經(jīng)濟(jì)貿(mào)易大學(xué)《微積分》2021-2022學(xué)年第一學(xué)期期末試卷
- 人音版音樂(lè)七年級(jí)上冊(cè)《父親的草原母親的河》課件
- 2024年度短視頻內(nèi)容創(chuàng)作服務(wù)合同3篇
- 介入治療并發(fā)癥
- 鑄牢中華民族共同體意識(shí)-形考任務(wù)1-國(guó)開(NMG)-參考資料
評(píng)論
0/150
提交評(píng)論