1. 程式人生 > >第一個釋出者程式

第一個釋出者程式

1 寫在開頭的話

      首先確保自己已經有工作區間,且已經將該工作區間的setup.bash加入當前使用者的環境變數中,若是則直接看第二章節,否則繼續往下看。

     若沒有工作區間則檢視順序為:1.1——>1.2——>2——>1.3——》3

     若有工作區間但是沒有將setup.bash加入當前使用者的環境變數中,則檢視順序為:1.2——》1.3——》2——》3

    若是已經有工作區間且已經將該工作區間的setup.bash加入當前使用者的環境變數中,則檢視順序1.2—》2—》3

1.1 新建工作區間

  在當前使用者home目錄下呼叫mkdir命令新建資料夾test,cd進入該資料夾,再次呼叫mkdir新建資料夾src,如下

1.2 建立功能包

  在工作區間的src目錄下,呼叫catkin_create_pkg建立功能包pubvel。如下

  呼叫ls檢視是否建立成功,成功會在src下出現pubvel資料夾

  注意:下圖中的amin資料夾和CMakeLists.txt檔案都是由於本人之前已經有工作區才會存在,若初次建立工作區間和功能包則不會出現這兩項,即只有pubvel資料夾;若已經有工作區間則會出現這兩項;

   cd進入pubvel資料夾,同時呼叫ls檢視pubve資料夾,此時可以看到裡面包含2個檔案,如下

  注意:pubvel.cpp檔案是由於本人已經做過所以才會出現,此時應該是沒有的】

   第一個配置檔案,叫做package.xml

   第二個檔案,叫做CMakeLists.txt,是一個Cmake的指令碼檔案,Cmake是一個符合工業標準的跨平臺編譯系統。

1.3  新增環境變數

       執行此部分需要兩個條件(滿足其一即可),條件為:其一,在檢視本文前已經有工作區間但是沒有將該工作區間的setuo.bash配置到當前使用者的環境變數中;其二,已經執行了本文的第二部分

      新增環境變數到當前目錄步驟如下:

      a.在當前使用者目錄的工作區目錄下,即test目錄下【此時的test為本人的工作區名稱,若查閱本文者檢視此文前已經有自己的工作區間,則此步驟的test為查閱者的工作區間名稱】,呼叫ls檢視此目錄下內容,如下:

   b.呼叫cd進入devel目錄,呼叫ls檢視此目錄下內容:

c. 注意:a、b步驟只是為了確保該工作區間中存在該工作區間環境變數的配置檔案setup.bash,沒有做任何實質性的工作

d。再次進入當前使用者的home目錄,呼叫ls -a檢視該目錄下包含隱藏檔案的全部檔案,如下

可以看到,上圖中有隱藏檔案.bashrc

e。呼叫vim編輯此檔案,如下

在最後加入一行:source  ~/test/devel/setup.bash,注意此處的test是工作區間的名字,根據需要修改,如下

按esc退出編輯,繼而輸入:wq儲存退出


2  建立編譯執行釋出者程式

2.1 建立釋出者程式

2.1.1 新增程式碼

 cd進入工作區目錄下的src,再呼叫cd進入pubvel資料夾中,如下

在pubvel資料夾下呼叫vim 建立釋出者程式pubvel.cpp,並新增如下程式碼

2.1.2 關於程式碼內容詳細說明

 2.1.2.1 關於標頭檔案說明

 標頭檔案ros/ros.h包含了標準ROS類的宣告,你將會在每一個你寫的ROS程式中包含它。

 在pubvel程式中,我們想釋出一條型別為geometry_msgs/Twist的訊息(名為geometry_msgs的包所擁有的型別為Twist的消   息),我們應該這樣:#include <geometry_msgs/Twist.h    這個標頭檔案的目的是定義一個C++類,此類和給定的訊息型別含有相同的資料型別成員。這個類定義在以包名命名的域名空間中。這樣命名的實際影響是當引用C++程式碼中的訊息類時,你將會使用  雙分號(::)來區分開包名和型別名,雙分號也稱為範圍解析運算子。在我們的pubvel例程中,標頭檔案定義了一個名為geometry_msgs::Twist的類。

標頭檔案stdlib.h則是因為什麼在main函式中呼叫了srand函式和rand函式

2.1.2.2 關於main函式內程式碼說明

 A.ros::init函式初始化ROS客戶端庫。請在你程式的起始處呼叫一次該函式3。函式最後的引數是一個包含節點預設名的字串。

 B.ros::NodeHandle(節點控制代碼)物件是你的程式用於和ROS系統互動的主要機制4。建立此物件會將你的程式註冊為ROS節點管    理器的節點。最簡單的方法就是在整個程式中只建立一個NodeHandle物件。

C..建立釋出者物件:釋出訊息的實際工作是由類名為ros::Publisher的一個物件來完成的。建立格式如下:                                                     ros::Publisher pub = node_handle.advertise<message_type>(topic_name, queue_size);                                                  上述格式中引數說明如下:                                                                                                                                                                      node_handle是ros::NodeHandle類的一個物件,是你在程式的開始處建立的,即ng。我們將呼叫這個物件的advertise方法;                                                                                                                               

          在尖括號中的message_type部分,其正式名稱為模板引數,是我們要釋出的訊息的資料型別。這個應該是上面討論過的標頭檔案中定義的類名。在例程中,我們使用geometry_msgs::Twist類。

           topic_name是一個字串,它包含了我們想釋出的話題的名稱。 

           advertise函式最後的引數是一個整數,表示這個釋出者釋出的訊息序列的大小。在大多數情況下,一個相對比較大的值,比方說1000,是合適的。如果你的程式迅速釋出比佇列可以容納的更多的訊息,最早進入佇列的未傳送的訊息將被丟棄。如果你想從同一個節點發布關於多個話題的訊息,你需要為每個話題建立一個獨立的ros::Publisher物件。

D.srand(time(0)):計算機沒有辦法產生真正的隨機數的,是用演算法模擬,所以你只調用rand,每次出來的東西是一樣的。設定一個種子後,根據種子的不同,就可以產生不同的數了。而怎麼保證種子的不同呢?最簡單的辦法當然是用永遠在向前的時間。srand(time(0)) ;//先設定種子rand();//然後產生隨機數。Srand是種下隨機種子數,你每回種下的種子不一樣,用Rand得到的隨機數就不一樣。為了每回種下一個不一樣的種子,所以就選用Time(0),Time(0)是得到當前時時間值(因為每時每刻時間是不一樣的了)。

E.建立並填充訊息物件,geometry_msgs::Twist msg;                                                                                                                                                               msg.linear.x = double(rand())/double(RAND_MAX);                                                                                                                         msg.angular.z = 2*double(rand())/double(RAND_MAX) - 1;

F.釋出訊息 。使用ros::Publisher物件的publish方法可以很簡單地釋出訊息。例如下面所示:pub.publish(msg);這個方法將所給的訊息新增到釋出者的輸出訊息佇列中,從這裡,它會盡快被髮送到相同話題的訂閱者那裡。

G.訊息釋出迴圈。                                                                                                                                                                                     我們的pubvel例程在while迴圈中重複釋出訊息的步驟,隨著時間的推移釋出不同的訊息。程式在這個迴圈中使用了兩個附加的建構函式。                                                                                                                                                                                             其一為節點是否停止工作的檢查 pubvel的while迴圈的條件是:ros::ok()  通俗地說,這個函式檢查我們的程式作為ROS節點是否仍處於執行良好的狀態。它會一直返回true,除非這個節點有某種原因使其停止工作。                                                                  有如下幾個原因會使ros::ok()返回false:你可能對節點使用了rosnode kill命令;你可能給程式傳送了一個終止訊號(Ctrl-C);你可能在程式的某個位置呼叫了ros::shutdown()這個函式是在你的程式碼中傳送節點工作已經完成訊號的一個很有用的方法;你可能以相同的名字啟動了其他節點,經常是因為你啟動了一個相同程式的新例項。                                                                     其二為控制訊息釋出頻率。pubvel的最後一個新知識點是它使用了ros::Rate物件ros::Rate rate(2);這個物件控制迴圈執行速度,其建構函式中的引數以赫茲(Hz)為單位,即每秒鐘的迴圈數。                                                                                                     這個例子建立了旨在規範每秒鐘執行兩個迭代迴圈的速率物件。鄰近每次迴圈迭代的結尾,我們呼叫此物件的sleep方法:
rate.sleep();每次呼叫此方法時就會在程式中產生延遲。延遲的持續時間被用來阻止迴圈的迭代速率超過指定的速率。沒有這種控制,程式會以計算機允許的最快速度釋出訊息,這樣會佔滿釋出和訂閱的序列,並且浪費計算和網路資源(在作者的電腦上,一個不加控制的程式會每秒釋出大約6300條訊息。)。

H.定義輸出格式:ROS_INFO_STREAM行儘管和釋出速度命令不是直接相關的,但還是值得一看的。這是關於巨集ROS_INFO_STREAM可以做什麼的一個更加完整的例證,因為它演示了在輸出中除了插入字串還可以插入其他資料的能力

2,2 編譯pubvel

2.2.1 在CMakeLists.txt檔案中宣告訊息型別依賴庫

      因為pubvel使用了來自geometry_msgs包的訊息型別和roscpp中的ros.h標頭檔案,我們必須宣告對這兩個包的依賴關係

     進入工作區間目錄下的src目錄,cd再次進入pubvel功能包,vim開啟該目錄下的CMakeLists.txt

    

     CMakeLists.txt檔案的預設版本含有如下行:find_package(catkin REQUIRED)

   

    所依賴的其他catkin包可以新增到這一行的COMPONENTS關鍵字後面,如下所示:

                     find_package(catkin REQUIRED COMPONENTS package-names)

     對於pubvel例程,我們需要新增名為roscpp和geometry_msgs的依賴庫。因此,修改後的find_package行如下所示:                           

 2.2.2 在package.xml檔案中宣告訊息型別依賴庫

         我們同樣需要在包的清單檔案中列出依賴庫,通過使用build_depend (編譯依賴)和run_depend(執行依賴)兩個關鍵字實現【注意:格式有2種,具體見https://blog.csdn.net/guosuling/article/details/83214460中的3.2】:
                                             <build_export_depend>package-name</build_export_depend>
                                             <exec_depend>package-name</run_depend>

       開啟package.xml檔案後,找到檔案偏下方的綠色字型<buildtool_depend>catkin</buildtoo;_depend>,在其後新增我們的依賴庫,新增後效果如下

         

      在清單檔案中宣告的依賴庫並沒有在編譯過程中用到;如果你在此處忽略它們,你可能不會看到任何錯誤訊息,直到釋出你的包給其他人,他們可能在沒有安裝所需包的情況下編譯你釋出的包而導致報錯。

2.3  宣告可執行檔案

       在功能包的CMakeLists.txt中新增兩行,來宣告我們需要建立的可執行檔案。其一般形式是:
                                         add_executable(executable-name source-files)
                                          target_link_libraries(executable-name ${catkin_LIBRARIES})

       第一行聲明瞭我們想要的可執行檔案的檔名,以及生成此可執行檔案所需的原始檔列表。如果你有多個原始檔,把它們列在此處,並用空格將其區分開

        第二行告訴Cmake當連結此可執行檔案時需要連結哪些庫(在上面的find_package中定義)。如果你的包中包括多個可執行檔案,為每一個可執行檔案複製和修改上述兩行程式碼。

      在我們的例程中,我們需要一個名為pubvel的可執行檔案,它通過名為pubvel.cpp的原始檔編譯而來。所以我們需要新增如下幾行程式碼到CMakeLists.txt中。注意:在CMakeLists.txt檔案中有很多註釋和例句,找到對應的例句,在其下方輸入我們要求的命令,儲存退出

2.4. 編譯工作區

   使用下列命令在工作區目錄下編譯包中所有的可執行檔案 :catkin_make

  

   執行結果如下表示成功

若出現找不到標頭檔案等錯誤,首先詳細檢查自己程式碼中相關標頭檔案和函式是否書寫出錯,若已經確保直接書寫正確則見另外一篇文章https://mp.csdn.net/postedit/83214460的2.4.3


3 執行pubvel

      執行完第2部分後要記得執行1.3 ,即新增環境變數到此使用者的啟動檔案.bashrc中,然後再往下執行

     當所有這些編譯步驟完成後,新的ROS程式就可以使用rosrun來執行,就像任何其他ROS程式一樣。

      但是注意:任何ros程式在執行前都要保證roscore在執行

    

       此例程是釋出者傳送型別為為geometry_msgs/Twist的訊息給話題向話題/turtle1/cmd_vel,此話題已經被節點/turtlesim節點訂閱,所以執行本例程的pubvel程式時可以開啟一個/turtlesim節點來顯式的看我們程式的效果

      開啟節點/turtlesim節點的方式為:新開啟一個shell來執行如下程式碼

此時再開一個shell來執行我們自己的程式,如下