版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
機(jī)器人操作系統(tǒng)(ROS)機(jī)器人操作系統(tǒng)(ROS)編程基礎(chǔ)知識2機(jī)器人操作系統(tǒng)(ROS)2.編程基礎(chǔ)知識在整個(gè)機(jī)器人行業(yè)中,程序是連接機(jī)器人與人的中間橋梁。通過程序,人才能夠讓機(jī)器人從裝飾品變成生產(chǎn)工具。在當(dāng)今機(jī)械控制日漸自動化與智能化的大趨勢下,一段程序的優(yōu)劣對整個(gè)生產(chǎn)過程顯得尤為重要,任何涉及到自動控制或是智能控制的領(lǐng)域都離不開程序的編寫。而編程語言作為編寫程序的工具,是搭建中間橋梁的橋墩。專注于機(jī)器人控制的ROS平臺自然也是離不開編程語言的。相較于其他編程語言,在ROS中使用的編程語言主要是C++和Python,因此我們將通過兩個(gè)章節(jié)的篇幅為讀者簡單介紹這兩種編程語言及其最重要的特點(diǎn)。建議有C++與Python基礎(chǔ)的讀者也仍然閱讀一下這兩部分,熟悉一下這兩種語言在ROS中的運(yùn)用。本章首先簡單介紹C++,主要講解C++最重要的一些基礎(chǔ)概念以及C++基本使用方法,然后介紹Python的相關(guān)知識和使用方法。機(jī)器人操作系統(tǒng)(ROS)2.1面向?qū)ο缶幊蹋╫bject-orientedprogramming)與C++簡介首先我們先來描述一下面向過程編程與面向?qū)ο缶幊痰膮^(qū)別。面向過程程序的控制流程由程序中預(yù)定順序來決定;面向?qū)ο蟪绦虻目刂屏鞒逃蛇\(yùn)行時(shí)各種事件的實(shí)際發(fā)生來觸發(fā),而不再由預(yù)定順序來決定,更符合實(shí)際需要。打個(gè)比方,假如我們要設(shè)計(jì)一款圍棋游戲,如果使用面向過程語言,那么我們的編程思路就應(yīng)當(dāng)是第一步白棋可以下在哪里,結(jié)束以后第二步由黑棋來下,可以下在哪里,每一步下完之后判斷是否有圍殺或是勝敗,以此類推??梢砸姷?,如果將存在棋盤下滿和棋的情況考慮在內(nèi),那么就會需要許多行代碼去完成這個(gè)游戲的開發(fā)。而換成面向?qū)ο缶幊?,我們的編程思路就會轉(zhuǎn)換成,白棋作為一個(gè)模塊,編寫好白棋的使用程序,黑棋作為一個(gè)模塊,由另一個(gè)人完成黑棋的使用程序,兩者再結(jié)合勝敗判定程序即可完成,將一整個(gè)連續(xù)性的程序框架拆解成各個(gè)模塊,這就是面向?qū)ο缶幊?。接下來在介紹C++前,我們先對C++的基礎(chǔ)C語言做一個(gè)簡單概括。C語言是面向過程的結(jié)構(gòu)化和模塊化的語言。在處理較小規(guī)模的程序時(shí),程序員用C語言較為得心應(yīng)手。但是當(dāng)問題比較復(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)該輸出什么等,如上一段所舉的圍棋例子。這對程序員的要求是比較高的,如果面對的是一個(gè)復(fù)雜問題,程序員往往感到力不從心。當(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++簡介而C++正是為了解決這個(gè)問題而從C語言的基礎(chǔ)上改進(jìn)出來的編程語言。在20世紀(jì)80年代提出了面向?qū)ο蟮某绦蛟O(shè)計(jì)(object-orientedprogramming,面向?qū)ο缶幊蹋┧枷?,這就需要設(shè)計(jì)出能支持面向?qū)ο蟮某绦蛟O(shè)計(jì)方法的新語言。Smalltalk就是當(dāng)時(shí)問世的一種面向?qū)ο蟮恼Z言。而在實(shí)踐中,人們發(fā)現(xiàn)由于C語言是如此深入人心,使用如此廣泛,以至最好的辦法不是另外發(fā)明一種新的語言去代替它,而是在它原有的基礎(chǔ)上加以發(fā)展。在這種形勢下,C++應(yīng)運(yùn)而生,并且在C的后面添加自加符號++來表示這是C語言的增強(qiáng)版,我們也可以稱C++為帶類的C語言。由于C++面向?qū)ο缶幊痰谋憬菪愿臃蠙C(jī)器人開發(fā)的要求,因此ROS作為以普適性為目的的機(jī)器人平臺自然也就將C++作為主要的編程語言之一。接下來就將為讀者介紹一些C++編程語言的基礎(chǔ)知識。機(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的編譯器,以及這些語言的庫。GCC是RichardStallman為GNU項(xiàng)目(/gnu/thegnuproject)編寫的。本章代碼需要在電腦中預(yù)裝Linux系統(tǒng)才能運(yùn)行,請讀者參考第五章內(nèi)容,安裝相應(yīng)版本的ubuntu系統(tǒng)或虛擬機(jī)。機(jī)器人操作系統(tǒng)(ROS)2.2.1GCC和G++編譯器介紹讓我們從GCC/G++編譯器開始認(rèn)識C++。最新的UbuntuLinux系統(tǒng)預(yù)裝了C和C++編譯,其中C語言的編譯器是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)識C++。最新的UbuntuLinux系統(tǒng)預(yù)裝了C和C++編譯,其中C語言的編譯器是GCC,C++的編譯器是G++。。在桌面或是文件夾空白處右擊,然后選中在終端中打開,或是使用快捷鍵Ctrl+Alt+t,即可打開一個(gè)終端。終端(Terminal)也是Linux系統(tǒng)操作的重要工具,希望讀者可以牢記該操作,以方便之后的學(xué)習(xí)使用。在打開的終端中先輸入gcc然后回車,接著再輸入g++然后回車,出現(xiàn)的界面如圖所示。如果沒有得到圖2-1中的信息,則代表系統(tǒng)沒有預(yù)裝這些編譯器,可以使用Linux系統(tǒng)中安裝軟件的apt-get命令來安裝這些編譯器,下一小節(jié)我們將進(jìn)行詳細(xì)介紹。機(jī)器人操作系統(tǒng)(ROS)2.2.2安裝C/C++編譯器首先,需要打開終端并使用如下命令從軟件庫中更新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)證安裝安裝完前面的包之后,可以在終端中使用如下指令查看編譯器的安裝路徑、使用說明頁:$whereisgcc$whereisg++使用下面命令可以查看GCC編譯器的版本號:$gcc--version$g++--version下圖顯示了以上命令的輸出。機(jī)器人操作系統(tǒng)(ROS)2.2.4GNU項(xiàng)目調(diào)試器GDB簡介下面我們看一看C/C++的調(diào)試器。什么是調(diào)試器呢?調(diào)試器是一個(gè)可以運(yùn)行和控制另一個(gè)程序的程序,通過檢查每一行代碼來檢查程序的問題或bug。UbuntuLinux自帶一個(gè)名為GNUDebugger的調(diào)試器,簡稱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如果安裝成功,則會顯示圖中的信息。機(jī)器人操作系統(tǒng)(ROS)2.2.6驗(yàn)證安裝圖的界面中,可以發(fā)現(xiàn)最后一行并不是正常終端操作命令執(zhí)行后的初始行,也就是并沒有出現(xiàn)之前操作命令回車執(zhí)行后界面中綠色字體的標(biāo)識符。這是因?yàn)楫?dāng)前操作命令仍然在執(zhí)行,并沒有結(jié)束,此時(shí)讀者輸入quit并敲擊回車結(jié)束gdb命令的執(zhí)行,如圖所示。在下一小節(jié)中,我們將在Ubuntu中編寫我們的第一個(gè)c++代碼,然后編譯并調(diào)試它,以找到代碼中的錯誤。機(jī)器人操作系統(tǒng)(ROS)2.2.7編寫第一行代碼下面我們開始在UbuntuLinux中編寫第一個(gè)程序。用戶可以使用Ubuntu中的gedit,或nano終端文本編輯器來編寫代碼。gedit是ubuntu中一個(gè)常用的GUI文本編輯器,更加符合長期使用Windows系統(tǒng)下的Office操作模式的人的使用習(xí)慣,因此這里我們使用gedit來編寫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,頁面十分簡潔,除了少數(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必須由讀者自己手動輸入,而不是像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ù)來輸出消息,所以有iostream作為頭文件就足夠了。接下來的第二行則是聲明了使用namespacestd即命名空間。命名空間(/namespacc/)是C++中的一個(gè)特性,用于對一組實(shí)體進(jìn)行分組。iostream庫中使用std定義命名空間。當(dāng)我們使用命名空間namespacestd時(shí),我們可以訪問std命名空間中包含的所有函數(shù)或其他實(shí)體,例如cout和cin等函數(shù)。如果我們不使用這行代碼,則必須在函數(shù)前面添加std::用于訪問該名字空間中的函數(shù);例如,std::cout是一個(gè)打印消息的函數(shù)。在討論了頭文件和其他代碼之后,我們可以討論主函數(shù)中包含的內(nèi)容了。我們使用cout<<"Nicetomeetyou,ROS."<<endl打印出一條消息。endl表明在打印消息后換行,消息打印完畢后,函數(shù)返回0并退出程序。在本章稍后的小節(jié)中我們會更加詳細(xì)地分析C++的一些基礎(chǔ)知識在ROS中的使用。機(jī)器人操作系統(tǒng)(ROS)2.2.9編譯代碼保存代碼之后,我們的.cpp文件仍然只是個(gè)文本文檔,并不是可執(zhí)行的程序,因此需要對這個(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í)在文件夾中就會生成hello_ROS.out的可執(zhí)行文件。如圖所示:機(jī)器人操作系統(tǒng)(ROS)2.2.9編譯代碼在終端中輸入以下命令運(yùn)行生成好的可執(zhí)行文件:$./hello_ROS此時(shí)顯示器上會輸出“Nicetomeetyou,ROS”的字符串,表示程序運(yùn)行成果,如圖2-13所示:機(jī)器人操作系統(tǒng)(ROS)2.2.10調(diào)試代碼使用調(diào)試器,可以遍歷每一行代碼并檢查每個(gè)變量的值。將下面的代碼按照之前的方法通過gedit來生成相應(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文件后就要對進(jìn)行編譯了,而為了要調(diào)試/檢查每一行代碼,我們編譯的時(shí)候必須使用調(diào)試符號編譯代碼,并使其能適用于GDB調(diào)試。具體的編譯命令如下:$g++-gSUM.cpp-oSUM編譯后,可以通過運(yùn)行命令$./SUM執(zhí)行它。運(yùn)行結(jié)果如圖所示。機(jī)器人操作系統(tǒng)(ROS)2.2.10調(diào)試代碼可執(zhí)行文件創(chuàng)建成功之后,可以通過以下的命令對其進(jìn)行調(diào)試:$gdbSUM其中,SUM是可執(zhí)行文件的名稱,輸入命令后,需使用GDB的操作指令進(jìn)行代碼調(diào)試。以下是常用的幾個(gè)GDB命令,具體解釋如下:?bline_numer:在給定行號處創(chuàng)建斷點(diǎn)。在調(diào)試時(shí),調(diào)試器會在這個(gè)斷點(diǎn)處停止。?n:運(yùn)行下一行代碼。?r:運(yùn)行程序到斷點(diǎn)位置。?pvariable_name:打印變量的值。?q:退出調(diào)試器。讓我們來嘗試一下這些命令,每個(gè)命令的輸出結(jié)果如圖所示。機(jī)器人操作系統(tǒng)(ROS)2.2.10調(diào)試代碼接下來就要介紹C++最大的特點(diǎn),面向?qū)ο缶幊蹋彩桥cC語言最大的區(qū)別。機(jī)器人操作系統(tǒng)(ROS)2.3從實(shí)例中學(xué)習(xí)C++中OOP的概念如果用戶已經(jīng)知道C的結(jié)構(gòu)體,那么了解OOP概念將不會花費(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í)例都被稱為對象。對象只是實(shí)際類的一個(gè)副本。有幾個(gè)與對象相關(guān)的屬性,稱為面向?qū)ο缶幊谈拍?。接下來我們用C++代碼解釋主要的OOP概念。機(jī)器人操作系統(tǒng)(ROS)2.3.1類和結(jié)構(gòu)體之間的區(qū)別在學(xué)習(xí)OOP概念之前,讓我們先來看看結(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ī)器人的編號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ù),以保證類定義的簡潔性。下面的程序顯示了類中所聲明的函數(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++的類和對象本節(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++的類和對象與結(jié)構(gòu)體實(shí)例類似,我們可以創(chuàng)建一個(gè)類的實(shí)例,稱之為對象。讓我們來看看Robot_Classrobot_2;在這里,robot_2是一個(gè)對象,而robot1是結(jié)構(gòu)體的一個(gè)實(shí)例。使用這個(gè)實(shí)例或?qū)ο?,我們可以訪問每一個(gè)變量和函數(shù)。我們可以使用.操作符去訪問每一個(gè)變量。結(jié)構(gòu)體和類中的變量都可以使用.操作符進(jìn)行訪問。如果是使用結(jié)構(gòu)體或類的指針,則必須使用->操作符來訪問每個(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++的類和對象其中,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++的類和對象我們使用命令$g++class_struct.cpp-oclass_struct和$./class_struct編譯它。圖2-16顯示了這段代碼的輸出??稍L問/cplusplus/cpp_classes_objects.htm,以便進(jìn)一步參考。機(jī)器人操作系統(tǒng)(ROS)2.3.3類訪問修飾符在類中,用戶也許已經(jīng)看到了一個(gè)叫做public:的關(guān)鍵字,它被稱為成員訪問限定符。下面代碼部分是使用訪問修飾符的代碼。classRobot_Class{public:intid;intno_wheels;...};機(jī)器人操作系統(tǒng)(ROS)2.3.3類訪問修飾符這一功能也稱為數(shù)據(jù)隱藏,通過設(shè)置成員訪問修飾符,我們可以限制在類內(nèi)部定義的函數(shù)的使用范圍。類中有三種訪問修飾符:public:一個(gè)public成員可以從類之外的任何地方訪問。我們可以直接訪問公共變量,而不需要編寫其他輔助函數(shù)。private:使用該修飾符號的成員變量或函數(shù),不能從類外部被查看或訪問。只有類和友元函數(shù)可以訪問私有成員。protected:訪問非常類似于private成員,但是不同的是它的子類可以訪問其成員。子類/派生類的概念將在下一節(jié)進(jìn)行討論。訪問修飾符可以幫助你將變量分組,這些變量可以在類中保持可見或隱藏。機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用繼承(Inheritance)是OOP中的另一個(gè)重要概念。如果你有兩個(gè)或多個(gè)類,并且希望在一個(gè)新類中擁有這些類中的函數(shù),那么可以使用繼承屬性。通過使用繼承屬性,你可以在新類中重用現(xiàn)有類中的函數(shù)。我們將要繼承現(xiàn)有類的新類稱為派生類,已有的類稱為基類。類可以通過public、private或protected來繼承。下面將解釋每種繼承類型。publicinheritance:當(dāng)我們派生自public基類時(shí),基類的public成員成為派生類的public成員,并且基類的protected成員成為派生類的protected成員?;惖膒rivate成員不能在派生類中訪問,但可以通過對基類的public和protected成員函數(shù)的調(diào)用來訪問。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繼承的簡單示例代碼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的基類。公共繼承是通過使用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在這種情況下,如果選擇公共繼承,則可以訪問基類的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)在讓我們看看如何訪問派生類中的函數(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”對象。如果用戶仔細(xì)閱讀代碼,便可以理解,在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所示的輸出,沒有顯示任何錯誤。這意味著此公共繼承運(yùn)行良好。機(jī)器人操作系統(tǒng)(ROS)2.3.4C++中繼承的使用根據(jù)輸出可以觀察到,我們從基類和派生類中定義的函數(shù)中獲取了所有消息。此外,我們還可以訪問基類變量并設(shè)置它的值我們已經(jīng)介紹了一些重要的OOP概念。如果需要了解更多的概念,請參考/cplusplus.機(jī)器人操作系統(tǒng)(ROS)2.3.5C++文件和流下面讓我們來一起討論C++中的文件操作以及文件讀寫。我們已經(jīng)討論了用于執(zhí)行文件操作的iostream頭文件,我們還需要另一個(gè)標(biāo)準(zhǔn)的C++庫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類對象,其中包含一個(gè)名為open()的函數(shù),用于打開文件。打開文件后,我們可以使用<<運(yùn)算符對其進(jìn)行寫入。寫完數(shù)據(jù)后,我們關(guān)閉文件為讀取操作做準(zhǔn)備。為了讀入數(shù)據(jù),我們在C++中使用ifstream類對象,并使用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)建了出來。相關(guān)詳細(xì)信息,請?jiān)L問/cplusplus/cpp_files_streams.htm。機(jī)器人操作系統(tǒng)(ROS)2.3.6C++中的命名空間在此之前,HelloWorld代碼中提到了命名空間的概念。在本節(jié)中,你將學(xué)習(xí)如何創(chuàng)建、在何處使用以及如何訪問命名空間。下面代碼提供了一個(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è)命名空間。如果查看代碼,你會發(fā)現(xiàn)在每個(gè)命名空間里都定義了相同的函數(shù)。這些命名空間用來對實(shí)現(xiàn)某一特定操作的一系列函數(shù)或類進(jìn)行分組。通過使用這個(gè)命名空間的名稱,后跟::加函數(shù)名的方式,我們可以訪問命名空間里的成員。在這段代碼中,我們在命名空間里調(diào)用了兩個(gè)函數(shù),分別是robot和machine。圖展示了代碼里代碼的輸出。這段代碼被保存為namespace.cpp。更多的參考,可以訪問/cplusplus/cpp_exceptions_handling.htm。機(jī)器人操作系統(tǒng)(ROS)2.3.7C++的異常處理異常處理Exceptionhandling是C++中的的一種新特性,它可以用來處理當(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++中的的一種新特性,它可以用來處理當(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)鍵詞來處理異常情況。try:在try后面的測試塊中編寫可能會引發(fā)異常的代碼。catch:如果try后的測試塊中出現(xiàn)了異常,則catch后面的代碼塊會捕捉這個(gè)異常。然后我們可以決定如何處理這個(gè)異常情況。throw:當(dāng)開始出現(xiàn)問題時(shí),我們可以從測試塊中拋出一個(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í),就會拋出一個(gè)由throw關(guān)鍵詞num_1引發(fā)的異常,然后catch塊會捕捉該異常并檢查num_1的值。圖展示了代碼編譯和輸出結(jié)果。我們可以在catch塊中打印異常值(也就是num_1的值,也就是1)。異常處理被廣泛地運(yùn)用于簡單的程序調(diào)試。更多的參考,可以訪問/exception-handling-c/。機(jī)器人操作系統(tǒng)(ROS)2.3.8C++的標(biāo)準(zhǔn)模板庫如果你想使用一些數(shù)據(jù)結(jié)構(gòu),比如列表(list)、堆棧(stacks)、數(shù)組(arrays)等等,標(biāo)準(zhǔn)模板庫(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)信息,可以訪問/the-c-standard-template-library-stl/。機(jī)器人操作系統(tǒng)(ROS)2.4建立一個(gè)C++工程現(xiàn)在你已經(jīng)學(xué)習(xí)了一些重要的OOP概念,現(xiàn)在讓我們來看看如何建立C++工程。想象一下,你有成百上千個(gè)源代碼文件,而且你需要編譯、鏈接它們,你要如何處理?這一部分將討論這個(gè)問題。如果你想使用多個(gè)源代碼文件,需要使用下列工具來編譯、鏈接你的工程。Linuxmakefile可以非常方便的用來編譯一個(gè)或多個(gè)源文件,并生成可執(zhí)行文件。讓我們通過一個(gè)簡單的工程來證明makefile的能力。我們將編寫一些代碼來對兩個(gè)數(shù)字求和,為此我們要先建立一個(gè)類。當(dāng)編寫C++類的時(shí)候,我們可以和main函數(shù)一起在源文件中聲明和定義這個(gè)類。另外一種聲明和定義類的方式是使用.h文件和.cpp文件,然后把.h文件包含到main函數(shù)所在的源文件中。這種方法對整個(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中,我們首先通過包含add.h頭文件來訪問add類,然后創(chuàng)建了add類的一個(gè)對象,并將兩個(gè)數(shù)字傳遞給compute函數(shù),最后打印結(jié)果。我們可以使用以下命令編譯并執(zhí)行中的代碼,其輸出結(jié)果如圖所示。對于編譯單個(gè)源代碼,g++命令很容易使用,但是如果我們想要編譯若干個(gè)源代碼,那么g++命令就不那么方便了。Linuxmakefile則提供了一種組織、編譯多個(gè)源代碼文件的方法。下面部分將展示了如何通過編寫makefile文件來編譯代碼。機(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í)行以下命令來執(zhí)行編譯。$make這樣就編譯了源代碼,如圖2-22所示。在使用make命令編譯之后,可以使用以下命令執(zhí)行程序。結(jié)果如圖2-23所示:$./main你可以通過/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)編譯、測試和打包軟件。我們可以使用以下命令安裝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命令的使用說明可以在/documentation/中找到。將上述命令保存為CMakeLists.txt之后,我們還需要創(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文件此命令會解析工程路徑中的CMakeLists.txt,然后將CMakeLists.txt轉(zhuǎn)換為makefile,這樣我們就可以通過makefile進(jìn)行編譯了?;旧峡梢哉f,它使編寫Linuxmakefile的過程變的自動化了。如果在執(zhí)行cmake..命令之后一切都成功,你應(yīng)該得到如圖1所示的消息。在這之后,你可以通過輸入make指令($make)來編譯工程。如果成功的話,項(xiàng)目就可以被執(zhí)行了($./main)。圖2展示了make指令和運(yùn)行可執(zhí)行文件的輸出。機(jī)器人操作系統(tǒng)(ROS)2.5Python簡介Python和C++一樣,也是一門面向?qū)ο蟮慕忉屝陀?jì)算機(jī)程序設(shè)計(jì)語言,由荷蘭人GuidovanRossum于1989年發(fā)明。Python具有豐富和強(qiáng)大的庫,它常被昵稱為膠水語言,能夠把用其他語言制作的各種模塊(尤其是C/C++)很輕松地聯(lián)結(jié)在一起。它是一門跨平臺、開源、免費(fèi)的解釋型高級動態(tài)編程語言,和C++最大的區(qū)別就是,Python是一門解釋型語言,而C++是一門編譯型語言。解釋型語言指的是程序不需要編譯,程序在運(yùn)行時(shí)才翻譯成機(jī)器語言,每執(zhí)行一次都要翻譯一次,因此效率比較低。比如Basic語言,專門有一個(gè)解釋器能夠直接執(zhí)行Basic程序,每個(gè)語句都是執(zhí)行的時(shí)候才翻譯。而編譯型語言程序在執(zhí)行之前需要一個(gè)專門的編譯過程,把程序編譯成為機(jī)器語言的文件,運(yùn)行時(shí)不需要重新翻譯,直接使用編譯的結(jié)果就行了。相比較之下,使用解釋型語言進(jìn)行程序編寫時(shí)更符合人本身的語言習(xí)慣,這也是Python成為ROS程序編寫熱門語言的一大重要原因。機(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命令后通過按兩次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命令用于啟動2.7.12版本,其余的命令則用于啟動3.5.2版本。Python3m和Python3.5m是帶有pymalloc的版本,它比使用malloc的默認(rèn)內(nèi)存分配性能更好。如前所述,Python在Ubuntu中是預(yù)裝的,除此之外,也可以通過下面的命令手動安裝相應(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í)行。首先我們在命令行中用Python解釋器打印“Nicetomeetyou,ROS.”消息,如圖3-5所示。機(jī)器人操作系統(tǒng)(ROS)2.6.3編寫第一條Python程序從圖2-30可以看出,用Python輸出消息非常容易,只需輸入print語句和被打印的消息數(shù)據(jù),然后按回車鍵即可,如下所示:>>>print'Nicetomeetyou,ROS.'如果你在Python3.0以上的版本中執(zhí)行HelloWorld程序,那么需要對Python語句做一些更改。Python3.x和2.x的主要的差別可以在https://wiki.P/moin/Python2orPython3中找到。與Python2.x中使用的print語句不同,在Python3.x中使用下面的語句來打印消息,運(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)方法請參見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í),程序加載器將解析這一行命令并使用該語句指定的執(zhí)行環(huán)境來執(zhí)行代碼。這里我們將Python設(shè)置為執(zhí)行環(huán)境,因此其余代碼將在Python解釋器中執(zhí)行。接下來讓我們看一下如何執(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)義符號“\”。如果你的代碼沒有任何錯誤,它將顯示如圖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展示了如何通過上述方式執(zhí)行Python腳本。接下來我們將討論P(yáng)ython的基礎(chǔ)語法。這一話題涵蓋了很多內(nèi)容,我們將通過具體的例子來討論其中的各個(gè)部分,以增加讀者的理解。機(jī)器人操作系統(tǒng)(ROS)2.7從實(shí)例中學(xué)習(xí)Python簡單易學(xué)是Python語言如此受歡迎的主要原因。因?yàn)镻ython的代碼很短,所以較之別的編程語言Python語言可以更快地幫助建立算法模型。也正是因?yàn)樗绱耸軞g迎,所以網(wǎng)上有海量的Python教程資源和很多活躍的技術(shù)論壇,我們可以很容易的從中獲取到技術(shù)支持。Python還有非常多的庫函數(shù)來幫助你開發(fā)應(yīng)用。Python庫的易獲得性,也是它優(yōu)于別的語言的一個(gè)重要原因。有了Python庫,你就可以利用現(xiàn)有的函數(shù)來大幅的減少開發(fā)時(shí)間。Python還是一個(gè)跨平臺的語言,被廣泛應(yīng)用于搜索、網(wǎng)絡(luò)、圖像、游戲、機(jī)器學(xué)習(xí)、數(shù)據(jù)科學(xué)以及機(jī)器人技術(shù)。很多公司都用這種語言來實(shí)現(xiàn)一些自動化任務(wù),所以靠Python找份工作是比較容易的。那么學(xué)習(xí)這門語言有多難呢?如果你可以完成一項(xiàng)偽代碼的編寫任務(wù),那就可以用Python寫代碼,因?yàn)樗鷤未a非常類似。機(jī)器人操作系統(tǒng)(ROS)2.7.1Python中有哪些新東西如果你學(xué)過C++,那學(xué)Python就比較簡單了,但是你在寫Python代碼時(shí)還得了解一些東西。靜態(tài)語言和動態(tài)語言Python是一個(gè)動態(tài)語言,也就意味著我們不必在編程中提供變量的數(shù)據(jù)類型,它把每個(gè)變量都看作一個(gè)對象。我們可以給一個(gè)名字指定任何數(shù)據(jù)類型。但在C++中,我們需要先給變量制定一個(gè)數(shù)據(jù)類型,然后只能將那一類型的數(shù)據(jù)賦值給這個(gè)變量。C++則是一個(gè)靜態(tài)類型的語言,比如在C++里我們可以這樣賦值:intnumber;number=10;//這個(gè)有效number="10"http://這個(gè)無效但在Python里,我們則可以這樣賦值:#無需考慮數(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)對代碼分塊,但這不是強(qiáng)制性的,即使我們沒有縮進(jìn)也可以編譯。然而在Python里就不一樣了,我們必須保證各代碼塊有一樣的縮進(jìn),否則就會出現(xiàn)縮進(jìn)的錯誤。當(dāng)代碼縮進(jìn)變成強(qiáng)制的之后,代碼看起來就會更整齊,可讀性也更好。分號在C/C++中,每個(gè)語句末尾的分號是強(qiáng)制性的,但是在Python中,它們不是強(qiáng)制性的。你可以在Python中使用分號作為分隔符,但不能作為終止符。例如,如果你想在一行中編寫一組代碼,你可以通過分隔分號來編寫它們。機(jī)器人操作系統(tǒng)(ROS)2.7.2Python變量現(xiàn)在你已經(jīng)了解了Python如何處理變量。圖2-34便展示了如何在Python中給變量賦值并打印不同的原始數(shù)據(jù)類型,如int、float和string。這里我們用到的測試環(huán)境為Python2.7.12版本。機(jī)器人操作系統(tǒng)(ROS)2.7.2Python變量類似于C/C++中的數(shù)組,Python提供列表(lists)和元組(tuples)數(shù)據(jù)類型。列表中的值可以通過使用方括號([])的列表索引進(jìn)行訪問。例如,可以通過[0]訪問列表中的第一個(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字典的工作原理。如果我們在字典中給出鍵(key),它將返回與鍵相關(guān)聯(lián)的值。在下一節(jié)中,我們將學(xué)習(xí)Python條件語句。機(jī)器人操作系統(tǒng)(ROS)2.7.3Python的輸入和條件語句與C++類似,Python也有if/else語句用來檢查條件。在下面的示例中,你將看到Python如何處理用戶輸入,并基于此進(jìn)行決策。程序的邏輯很簡單,僅要求用戶輸入移動機(jī)器人的命令。如果用戶輸入一個(gè)有效的命令,如move_left、move_right、move_forward或move_back,程序?qū)⑤敵鏊谝苿?,否則,它將輸出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的輸入和條件語句在Python中接受用戶的輸入,我們可以使用raw_input()函數(shù)或input()函數(shù)。raw_input()函數(shù)接受任何類型的數(shù)據(jù),但是input()函數(shù)只能接受整數(shù)類型。下面是raw_input()和input()函數(shù)的語法。var=raw_input("Inputmessage")var=input("Inputmessage")raw_input()將變量var中的用戶輸入存儲為字符串。在存儲用戶的輸入之后,我們將輸入與命令列表進(jìn)行比較,然后給出不同的輸出。這里是if/else語句的語法。ifexpression1:statement(s1)elifexpression2:statement(s2)else:statement(s3)在每個(gè)表達(dá)式之后,由一個(gè)冒號來結(jié)束表達(dá)式,然后我們還需要為該語句添加一個(gè)縮進(jìn)。如果不放入縮進(jìn),就會出錯。機(jī)器人操作系統(tǒng)(ROS)2.7.4Python:循環(huán)Python有while和for循環(huán),但默認(rèn)情況下不具有dowhile循環(huán)。下面代碼展示了在Python中while循環(huán)和for循環(huán)的用法。在本例中,機(jī)器人在x和y方向上的位置會增加,如果到達(dá)某個(gè)特定位置,程序?qū)⒃诖蛴∠⒑蠼K止。#!/usr/bin/envpython#-*-coding:utf-8-*-robot_x=0.1robot_y=0.1while(robot_x<2androbot_y<2):robot_x+=0.1robot_y+=0.1print"Currentposition",robot_x,robot_yprint"Reacheddestination."機(jī)器人操作系統(tǒng)(ROS)2.7.4Python:循環(huán)下面顯示了while循環(huán)的語法。whileexpression: statement(s)在前面的示例中,表達(dá)式(expression)為(robot_x<2androbot_y<2)。表達(dá)式中有兩個(gè)條件。我們在兩個(gè)條件之間執(zhí)行AND邏輯。在Python中,'and','or'便是邏輯AND和邏輯OR。如果條件為真,則執(zhí)行內(nèi)部語句。如前所述,我們必須在這個(gè)塊上使用適當(dāng)?shù)目s進(jìn)。當(dāng)表達(dá)式為假時(shí),它退出循環(huán)并輸出消息“reacheddestination”。如果運(yùn)行此代碼,將得到如圖2-38所示的輸出。機(jī)器人操作系統(tǒng)(ROS)2.7.4Python:循環(huán)我們可以在Python中使用for循環(huán)實(shí)現(xiàn)相同的應(yīng)用程序。下面代碼部分顯示了for循環(huán)的工作方式。#!/usr/bin/envpython#-*-coding:utf-8-*-robot_x=0.1robot_y=0.1foriinrange(0,100):robot_x+=0.1robot_y+=0.1print"CurrentPosition",robot_x,robot_yif(robot_x>2androbot_y>2):print"Reacheddestination."break機(jī)器人操作系統(tǒng)(ROS)2.7.4Python:循環(huán)在上述代碼中,for循環(huán)從0執(zhí)行到100,逐漸增加robot_x和robot_y的值,檢查機(jī)器人的位置是否在限制范圍內(nèi)。如果超過了限制,它將打印消息并中斷for循環(huán)。以下展示Python中的for循環(huán)語法:foriterating_varinsequence: statements(s)圖2-39展示了上述代碼的輸出。機(jī)器人操作系統(tǒng)(ROS)2.7.5Python:函數(shù)眾所周知,如果你想復(fù)用某段代碼,可以將它定義為一個(gè)函數(shù)。大多數(shù)編程語言也都具備函數(shù)定義的特性。下面是在Python中定義函數(shù)的格式:deffunction_name(parameter):
"function_docstring"
function_code_block
return[expression]Python中函數(shù)定義的順序非常重要。函數(shù)調(diào)用應(yīng)該在函數(shù)定義之后。Function_docstring函數(shù)是一段帶有函數(shù)描述和函數(shù)用法示例的注釋。在Python中,可以使用#對單行進(jìn)行注釋,但是如果想注釋位于代碼塊或docstring中的內(nèi)容,請使用以下格式。'''
<Blockofcode>
'''機(jī)器人操作系統(tǒng)(ROS)2.7.5Python:函數(shù)下面展示了一個(gè)在Python中使用函數(shù)的示例:#!/usr/bin/envpython#-*-coding:utf-8-*-defforward():
print"Robotmovingforward"
defbackward():
print"Robotmovingbackward"
defleft():
print"Robotmovingleft"
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 電信課程設(shè)計(jì)題目
- 送排風(fēng)機(jī)組課程設(shè)計(jì)
- 二零二五版光伏基站場地租賃與能源合作合同2篇
- 2024版二手房產(chǎn)轉(zhuǎn)讓合同書
- 2024版硅酮密封膠買賣合同書
- 二零二五版360有錢聯(lián)盟會員積分兌換及獎勵機(jī)制合同2篇
- 2025年度鋼筋套筒保險(xiǎn)服務(wù)合同3篇
- 2024年砂石材料行業(yè)投資與并購合作合同范本3篇
- 二零二五版不銹鋼材料加工中心建設(shè)與運(yùn)營合同3篇
- 2025年度環(huán)保設(shè)備采購合同范本及環(huán)境效益評估3篇
- 園區(qū)物業(yè)管理合同協(xié)議書
- 《人體損傷致殘程度分級》
- 港口流體裝卸工職業(yè)技能競賽理論考試題庫500題(含答案)
- QCT1067.5-2023汽車電線束和電器設(shè)備用連接器第5部分:設(shè)備連接器(插座)的型式和尺寸
- 輪式智能移動操作機(jī)器人技術(shù)與應(yīng)用-基于ROS的Python編程 課件 第4章 機(jī)器人運(yùn)動應(yīng)用實(shí)例
- 2024質(zhì)量管理理解、評價(jià)和改進(jìn)組織的質(zhì)量文化指南
- 手指外傷后護(hù)理查房
- 油氣回收相關(guān)理論知識考試試題及答案
- 我能作業(yè)更細(xì)心(課件)-小學(xué)生主題班會二年級
- 2023年湖北省武漢市高考數(shù)學(xué)一模試卷及答案解析
- 英國足球文化課件
評論
0/150
提交評論