機器人作業系統(ROS)淺析-學習筆記
機器人作業系統(ROS)淺析
學習筆記
至 2018-2-8 已將此教程過了一遍此文件中為摘抄的筆記,若有不明白的地方,請檢視原文件
2018-2-2
關於節點nodes 的操作
1、啟動節點master $ roscore
這個定義中的“執行例項”(runninginstance)很重要。如果我們同時執行相同程式的多個副本——注意確保每個副本使用不同的節點名——則每個副本都被當做一個單獨的節點。
2、啟動節點$ rosrun
rosrun命令有兩個引數,其中第一個引數是功能包的名稱;第二個引數是該軟體包中的可執行檔案的名稱。
ROS中要求每個節點有不同的名稱
可以使用rosrun命令顯式設定節點的名稱,語法如下:
rosrun package-name executable-name__name:=node-name
rosrun是一個shell指令碼,能夠理解ROS的檔案組織結構,知道到哪裡能找到與給定包名稱對應的可執行檔案。
一旦它找到你要的程式,rosrun就會正常啟動節點。
例如,如果你真的想要,你可以像執行任何其他程式一樣直接執行turtlesim_node:
/opt/ros/indigo/lib/turtlesim/turtlesim_node
這裡還要強調一點,通過節點管理器註冊成為ROS節點發生在程式的內部,而不是通過rosrun命令。
3、檢視節點要獲得特定節點的資訊,使用如下命令:
rosnode info node-name
4、終止節點要終止節點,使用如下命令:
rosnode kill node-name
topic
ROS節點之間進行通訊所利用的最重要的機制就是訊息傳遞。在ROS中,訊息有組織地存放在話題topic裡19。
訊息傳遞的理念是:
當一個節點node想要分享資訊時,它就會發布(publish)訊息到對應的一個或者多個話題;
當一個節點想要接收資訊時,它就會訂閱(subscribe)它所需要的一個或者多個話題。
ROS節點管理器負責確保釋出節點和訂閱節點能找到對方;而且訊息是直接地從釋出節點傳遞到訂閱節點,中間並不經過節點管理器轉交。
檢視節點構成的計算圖
要檢視節點之間的連線關係,恐怕將其表示為圖形是最便於檢視的。
在ROS系統中檢視節點之間的釋出-訂閱關係的最簡單方式就是在終端輸入如下命令:
rqt_graph
在這個命令中,r代表ROS,qt指的是用來實現這個視覺化程式的Qt圖形介面(GUI)工具包。輸入該命令之後,你將會看到一個圖形介面,其中大部分割槽域用於展示當前系統中的節點。通常情況下,你將會看到如圖2.2類似的圖形介面。在該圖中,
橢圓形表示節點node ,有向邊表示其兩端節點間的釋出-訂閱關係。該計算圖告訴我們,
/teleop_turtle節點向話題/turtle1/cmd_vel釋出訊息,而/turtlesim節點訂閱了這些訊息(“cmd_vel”是“commandvelocity”的縮寫。)。
rostopic pub
rostopic pub可以把資料釋出到當前某個正在廣播的話題上。
節點node 可以釋出話題topic,其他的節點node 可以訂閱某個topic,當節點訂閱某個topic 的時候,可以不用關心整個topic 是由誰發出
turtlesim遙控系統的工作原理有了一定的理解。當你按下一個鍵時,/teleop_turtle節點會以訊息的形式將這些運動控制命令釋出到話題/turtle1/cmd_vel;與此同時,因為turtlesim_node訂閱了該話題,因此它會接收到這個些訊息,控制海龜按照該預定的速度移動。其中的關鍵點在於:
模擬海龜不關心(或者甚至不知道)哪個程式釋出了這些cmd_vel訊息。任何向這個話題釋出了訊息的程式都能控制這個海龜。
遠端操作程式不關心(或者甚至不知道)哪個程式訂閱了它釋出的cmd_vel訊息。任何訂閱了相關話題的程式都能自主選擇是否響應這些命令。
測量釋出頻率有兩個命令可以用來測量訊息釋出的頻率以及這些訊息所佔用的頻寬:
rostopic hz topic-name
rostopic bw topic-name
檢視訊息型別
要想檢視某種訊息型別的詳情,使用類似下面的命令21,22:
rosmsg show message-type-name
用命令列釋出訊息
大多數時候,釋出訊息的工作是由特定的程式完成的*。但是,你會發現有時候手動釋出訊息是很實用的。要實現該功能,利用rostopic命令列工具23:
rostopicpub –r rate-in-hz topic-name message-type message-content
這條命令重複地按照指定的頻率給指定的話題釋出指定的訊息。
該命令最後的引數message-content應該按順序提供訊息型別中所有域的引數值。
例如:
rostopicpub –r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[2,0,0]’ ’[0,0,0]’
前面三個數字表示期望的位移線速度,後面三個數字表示期望的角速度。用單引號(’…’)和中括號([…])組織這些數值賦給它們對應的兩個頂層複合域變數
同樣的,類似的命令將會控制小海龜沿著它的z軸(垂直於
電腦螢幕)旋轉。
rostopicpub –r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[0,0,0]’ ’[0,0,1]’
注意:如何去確定message-type
上述語法有一個明顯的缺點,那就是你必須記住訊息型別裡所有的域以及這些域出現的順序
此處展示的命令利用了-r來指定話題以頻率模式釋出訊息,即以一定的時間週期釋出訊息。這條命令同樣支援一次性發布的模式(-1“虛線後為數字1”)和特別的鎖存模式(-l“虛線後為字母L的小寫”),鎖存模式雖然也只是釋出一次訊息,但是會確保該話題的新訂閱者也會收到訊息。實際上,鎖存模式是預設的模式。
理解訊息型別的命名
和ROS裡其他的程式一樣,每條訊息型別都屬於一個特定的包。訊息型別名總會包含一個斜槓,斜槓前面的名字是包含它的包:
package-name/type-name
例如,turtlesim/Color訊息型別按如下方式分解:
turtlesim (包名)+color (型別名稱) --》訊息型別 turtlesim/Color
這種分解訊息型別名的方法有如下幾個目的:
最直接地,把包的名字包含在訊息型別名裡能避免命名衝突。例如,geometry_msgs/Pose和turtlesim/Pose是有區別的訊息型別,它們包含了不同的(但概念上是類似的)資料。
正如我們將在第3章看到的那樣,當我們編寫ROS程式的時候,如果也用到了其他包的訊息型別,那麼我們需要宣告對它們的依賴關係。把功能包的名稱和訊息型別名一起寫出來會使得這些依賴關係看上去更明朗。
最後一點,包名和其含有的訊息型別放在一起將有助於猜測它的含義。例如,訊息型別ModelState單獨出現可能會讓人產生迷惑,但是以gazebo/ModelState的形式出現後,就會指明這個訊息型別是Gazebo模擬器中的一部分,而且很有可能包含了這個模擬器中某個模型的狀態資訊。
rosrun命令中的__name引數
rosrun turtlesim turtlesim_node __name:=A
這些引數覆蓋了每個節點賦予自己的預設名稱。覆蓋是必要的,因為ROS節點管理器不允許多個節點擁有相同的名稱。
話題通訊的多對多機制
基於話題和訊息的通訊機制是多對多的,即多個釋出者和多個訂閱者可以共享同一個
話題。
節點之間的鬆耦合關係
節點之間——更一般的,對於絕大多數設計精巧的ROS節點——是鬆耦合的。
每個節點都不需要顯式知道其他節點的存在與否;
它們的唯一互動方式是間接地發生在基於話題和訊息的通訊層。
這種節點之間的獨立性,以及其支援的任務可分解特性(即複雜任務分解成可重用的小模組),是ROS最關鍵的設計特性之一。
“生產”訊息的程式(例如turtle_teleop_key)只管釋出該訊息,而不用關心該訊息是如何被“消費”的。
“消費”訊息的程式(例如turtlesim_node)只管訂閱該話題或者它所需要訊息的所有話題,而不用關心這些訊息資料是如何“生產”的。
是否有必要建立多個工作區?
對於許多使用者來說,確實沒有必要使用多個ROS工作區。但是,ROS的catkin編譯系統(我們將在3.2.2節中介紹),試圖一次性編譯同一個工作區中的所有功能包。因此,如果你的工作涉及大量的功能包,或者涉及幾個相互獨立的的專案,則維護數個獨立的工作區可能是有幫助的。
所以,如果你的程式包很多,你可以建立多個workspace
ros 中的程式分析
1// This is a ROS version of the standard "hello , world"
2// program.
3
4// This header defines the standard ROS classes .
5#include <ros / ros.h>
6
7int main ( int argc , char ** argv ) {
8// Initialize the ROS system .
9ros::init ( argc , argv , " hello _ros " ) ;
10
11// Establ ish this program as a ROS node .
12ros::NodeHandle nh ;
13
14// Send some output as a log message .
15ROS_INFO_STREAM( " Hello , ␣ROS! " ) ;
16}
標頭檔案ros/ros.h包含了標準ROS類的宣告,你將會在每一個你寫的ROS程式中包含它。
ros::init函式初始化ROS客戶端庫。請在你程式的起始處呼叫一次該函式3。函式最後的引數是一個包含節點預設名的字串。
ros::NodeHandle(節點控制代碼)物件是你的程式用於和ROS系統互動的主要機制4。建立此物件會將你的程式註冊為ROS節點管理器的節點。最簡單的方法就是在整個程式中只建立一個NodeHandle物件。
編譯程式時的內部操作
宣告依賴庫首先,我們需要宣告程式所依賴的其他功能包。對於c++程式而言,此步驟是必要的,以確保catkin能夠向c++編譯器提供合適的標記來定位編譯功能包所需的標頭檔案和連結庫。
為了給出依賴庫,編輯包目錄下的CMakeLists.txt檔案。該檔案的預設版本含有如下行:
find_package(catkin REQUIRED)
所依賴的其他catkin包可以新增到這一行的COMPONENTS關鍵字後面,如下所示:
find_package(catkinREQUIRED COMPONENTS package-names)
我們需要新增名為roscpp的依賴庫,它提供了ROS的C++客戶端庫。因此,修改後的find_package行如下所示:
find_package(catkin REQUIRED COMPONENTSroscpp)
我們同樣需要在包的清單檔案中列出依賴庫,通過使用build_depend(編譯依賴)和run_depend(執行依賴)兩個關鍵字實現:
<build_depend>package-name</build_depend>
<run_depend>package-name</run_depend>
在我們的例程中,hello程式在編譯時和執行時都需要roscpp庫,因此清單檔案需要包括:
<build_depend>roscpp</build_depend>
<run_depend>roscpp</run_depend>
宣告可執行檔案接下來,我們需要在CMakeLists.txt中新增兩行,來宣告我們需要建立的可執行檔案。其一般形式是:
add_executable(executable-namesource-files)
target_link_libraries(executable-name${catkin_LIBRARIES})
第一行聲明瞭我們想要的可執行檔案的檔名,以及生成此可執行檔案所需的原始檔列表。如果你有多個原始檔,把它們列在此處,並用空格將其區分開。第二行告訴Cmake當連結此可執行檔案時需要連結哪些庫(在上面的find_package中定義)。如果你的包中包括多個可執行檔案,為每一個可執行檔案複製和修改上述兩行程式碼。
在我們的例程中,我們需要一個名為hello的可執行檔案,它通過名為hello.cpp的原始檔編譯而來。所以我們需要新增如下幾行程式碼到CMakeLists.txt中:
add_executable(hello hello.cpp)
target_link_libraries(hello${catkin_LIBRARIES})
##Declare a cpp executable
add_executable(position_plan_nodesrc/position_plan.cpp)
在執行自己編寫的一個cpp 程式或者節點node 前,要注意先啟動節點管理器rosrun
這個程式是一個節點,節點需要一個節點管理器才可以正常執行
重點關於c++ 語法程式設計說明
包含訊息型別宣告你應該還能回憶起我們在2.7.2節中談到過每一個ROS話題都與一個訊息型別相關聯。
每一個訊息型別都有一個相對應C++標頭檔案。你需要在你的程式中為每一個用到的訊息型別包含這個標頭檔案,程式碼如下所示:
#include <package_name/type_name.h>
這裡需要注意的是,功能包名應該是定義訊息型別的包的名稱,而不一定是你自己的包的名稱。在pubvel程式中,
我們想釋出一條型別為geometry_msgs/Twist的訊息(名為geometry_msgs的包所擁有的型別為Twist的訊息),我們應該這樣:
#include <geometry_msgs/Twist.h>
這個標頭檔案的目的是定義一個C++類,此類和給定的訊息型別含有相同的資料型別成員。
這個類定義在以包名命名的域名空間中。這樣命名的實際影響是當引用C++程式碼中的訊息類時,
你將會使用雙分號(::)來區分開包名和型別名,雙分號也稱為範圍解析運算子。在我們的pubvel例程中,標頭檔案定義了一個名為geometry_msgs::Twist的類。+
很常用的就是ros::
詳見《機器人作業系統(ROS)淺析》
使用套路如下:
新增標頭檔案:
#include <ros / ros.h> // fro ros::
定義類:
ros::NodeHandle nh
使用類:
ros::Publisher pub = nh . advertise<geometry_msgs::Twist >(" turtle1 /cmd_vel" , 1 0 0 0 ) ;
標頭檔案在哪裡?
建立釋出者物件
釋出訊息的實際工作是由類名為ros::Publisher的一個物件來完成的7。類似下面這行的程式碼建立了我們需要的物件:
ros::Publisher pub =node_handle.advertise<message_type>(topic_name, queue_size);
讓我們看下這一行程式碼的每一部分。
node_handle是ros::NodeHandle類的一個物件,是你在程式的開始處建立的。我們將呼叫這個物件的advertise方法。
在尖括號中的message_type部分,其正式名稱為模板引數,是我們要釋出的訊息的資料型別。這個應該是上面討論過的標頭檔案中定義的類名。在例程中,我們使用geometry_msgs::Twist類。
topic_name是一個字串,它包含了我們想釋出的話題的名稱。它應該和rostopic list或者rqt_graph中展示的話題名稱一致,但通常沒有前斜槓(/)。我們丟掉前斜槓使話題名為一個相對名稱;第5章解釋了相對名稱的機制和目的。在此例程中,話題名為turtle1/cmd_vel。
請注意話題名和訊息型別的區別
advertise最後的引數是一個整數,表示這個釋出者釋出的訊息序列的大小。在大多數情況下,一個相對比較大的值,比方說1000,是合適的。如果你的程式迅速釋出比佇列可以容納的更多的訊息,最早進入佇列的未傳送的訊息將被丟棄。
設定節點的迴圈頻率
19// Loop at 2Hz until the node is shut down.
20ros::Raterate ( 2 ) ;
從同一個節點發布關於多個話題的訊息,你需要為每個話題建立一個獨立的ros::Publisher物件。
建立一個釋出者是一個很耗時的操作,所以每當你想釋出一個訊息就去建立一個新的ros::Publisher物件是很不明智的。
建議為每一個話題建立一個釋出者,並且在你程式執行的全過程中一直使用那個釋出者。
在pubvel中,我們通過在while迴圈外面聲明發布者來達到這個目的。
如何確定包中有幾個類?確定方法的使用標準?
編譯前的注意事項p63
如何宣告對包的依賴
宣告訊息型別依賴庫
因為pubvel使用了來自geometry_msgs包的訊息型別,我們必須宣告對這個包的依賴關係,這和3.2.2節中討論的roscpp依賴庫的形式相同。具體而言,除了roscpp,我們必須修改CMakeLists.txt檔案的find_package行來宣告geometry_msgs:
我們是修改已有的find_package行,而不是新建一行。在package.xml檔案中,我們新增新的依賴項:
<build_depend>geometry_msgs</build_depend>
<run_depend>geometry_msgs</run_depend>
在編譯ROS程式時當你看到找不到標頭檔案的錯誤,最好確認一下你的功能包的依賴關係。
編寫回調函式p65
釋出和訂閱訊息的一個重要的區別是訂閱者節點無法知道訊息什麼時候到達。為了應對這一事實,我們必須把響應收到訊息事件的程式碼放到回撥函式裡,ROS每接收到一個新的訊息將呼叫一次這個函式。
建立訂閱者物件
為了訂閱一個話題,我們需要建立一個ros::Subscriber物件12:
ros::Subscriber sub =node_handle.subscribe (topic_name,queue_size, pointer_to_callback_function);
可以通過對函式名使用符號運算子(&,“取址”)來獲得函式的指標。
ros::Subscribersub = nh.subscribe ( " turtle1/pose " ,1000, &poseMessageReceived) ;
node_handle 從哪裡來?
ros::NodeHandlenode_handle;
這個建構函式有三個形參,其中大部分與ros::Publisher宣告中的類似:
node_handle與我們之前多次見到的節點控制代碼物件是相同的。
topic_name是我們想要訂閱的話題的名稱,以字串的形式表示。本例程中是"turtle1/pose"。再次強調,我們忽略了前斜線使其成為相對名稱。
queue_size是本訂閱者接收訊息的佇列大小,是一個整數。通常,你可以使用一個較大的整數,例如1000,而不用太多關心佇列處理過程。
回撥函式的作用
當新的訊息到達時,它們會被儲存在一個佇列中,直到ROS有機會去執行相應的回撥函式
可以通過如下兩個方法減少訂閱者佇列溢位的可能性:(1)通過呼叫ros::spin或者ros:spinOnce確保允許回調發生;(2)減少每個回撥函式的計算時間。
給ROS控制權
ros::spinOnce();
這個程式碼要求ROS去執行所有掛起的回撥函式,然後將控制權限返回給我們。另一個方法如下所示:
ros::spin();
這個方法要求ROS等待並且執行回撥函式,直到這個節點關機。換句話說,ros::spin()大體等於這樣一個迴圈:
while(ros::ok( ))
{
ros::spinOnce();
}
使用ros::spinOnce()還是使用ros::spin() p77
建議如下:你的程式除了響應回撥函式,還有其他重複性工作要做嗎?
如果答案是“否”,那麼使用ros::spin()---無其他事情要做;
否則,合理的選擇是寫一個迴圈,做其他需要做的事情,並且週期性地呼叫ros::spinOnce()來處理回撥。表3.5使用ros::spin(),因為程式唯一的工作就是接收和列印接收到的位姿訊息。
計算圖源名稱
節點、話題、服務和引數統稱為計算圖源,
每個計算圖源由一個叫計算圖源名稱(graph resource name)的短字串標識。事實上,計算圖源名稱在ROS命令列和程式碼中是廣泛存在的,前面我們已經多次接觸它們。例如,前面學習的rosnodeinfo命令列工具和ros::init函式都將節點名作為其引數,
rostopic echo命令列工具和ros::Publisher建構函式則都要求提供話題名作為引數,這些都是計算圖源名稱的具體例項。
這些計算圖源名稱都屬於全域性名稱,之所以叫做全域性名稱因為它們在任何地方
是一個全域性名稱的幾個組成部分:p101
前斜槓“/”表明這個名稱為全域性名稱。
由斜槓分開的一系列名稱空間(namespace),每個斜槓代表一級名稱空間。你可能已經猜到了,名稱空間用於將相關的計算圖源歸類在一起。上述名稱例子包含了兩個顯式的名稱空間,分別為turtle1和count_and_log。
ROS允許多層次的名稱空間,所以下面這個包含了11個巢狀名稱空間的名稱也是有效的全域性名稱,雖然看起來不太可能有人這麼用。
/a/b/c/d/e/f/g/h/i/j/k/l
如果沒有顯式提及所屬的名稱空間,包括上述三個例子在內,則對應的計算圖源名稱是歸在全域性名稱空間中的。
描述資源本身的基本名稱(base name)。上述例子中的基本名稱分別為:teleop_turle、cmd_vel、pose、run_id和
相對名稱
使用全域性名稱時,為了指明一個計算圖源,需要完整列出其所屬的名稱空間
讓ROS為計算圖源提供一個預設的名稱空間,具有此特徵的名稱叫做相對計算圖源名稱(ralative graph resource name),或簡稱為相對名稱(relative name)。相對名稱的典型特徵是它缺少全域性名稱帶有的前斜槓“/”
解析相對名稱
將相對名稱轉化為全域性名稱的過程相當簡單。ROS將當前預設的名稱空間的名稱加在相對名稱的前面,從而將相對名解析為全域性名稱。
相對名稱也可以以一系列的名稱空間開始,這些名稱空間被看作是預設名稱空間中的巢狀空間
舉個例子,如果我們在預設名稱空間為/a/b/c/d/e/f的地方使用相對空間g/h/i/j/k,ROS將會將其進行下面的組合:
/a/b/c/d/e/f/g/h/i/j/k
設定預設名稱空間
理解相對名稱的目的
如何在ros 中一次啟動多個節點?
基本思想是在一個XML格式的檔案內將需要同時啟動的一組節點羅列出來
當一個節點內的計算圖源全部使用相對名稱時,這本質上給使用者提供了一種非常簡單的移植手段,即使用者能方便地將此節點和話題移植到其他的(比如使用者自己程式的)名稱空間,而節點的原設計者並不一定參與這個過程。
這種靈活性可以使得一個系統的組織結構更清晰,更重要的是能夠防止在整合來自不同來源的節點發生名稱衝突。p104
啟動檔案 p108
同時啟動節點管理器(master)和多個節點
用 launch 批量啟動 node
rosrun一次只能啟動一個節點,而roslaunch可以同時啟動多個節點。
ROS也允許使用不歸屬於任何功能包的啟動檔案,此時需要向roslaunch提供啟動檔案的路徑,而不像上面的例子需要功能包名引數
roslaunch有一個可以請求輸出詳細資訊的選項:
roslaunch–v package-name launch-file-name
該資訊可以用來觀察roslaunch如何解釋你的啟動檔案,有時在除錯的時候會有所幫助。
launch檔案的語法結構
可以仿照 demo.launch 寫 launch檔案,內含呼叫函式庫的說明,是否連線real robot 實體,是否loadurdf 檔案
程式碼重對映 p122
用來對現有的節點資訊進行更改,使其變成新的翻轉或者逆向的指令
在啟動檔案中包含其他啟動檔案的內容(包括所有的節點和引數),可以使用包含(include)元素
此處file屬性的值應該是我們想包含的檔案的完整路徑。由於直接輸入路徑資訊很繁瑣且容易出錯,大多數包含元素都使用查詢(find)命令搜尋功能包的位置來替代直接輸入路徑:
<includefile=”$(find package-name)/launch-file-name”>
但是這種方法在普通的 cpp 程式中不好使
launch 中的啟動引數
不太明白到底有啥用處
引數伺服器
引數伺服器(parameterserver)維護一個變數集的值,包括整數、浮點數、字串以及其他資料型別,每一個變數用一個較短的字串標識1,2。由於允許節點主動查詢其感興趣的引數的值,它們適用於配置那些不會隨時間頻繁變更的資訊。
$ rosparam list
引數伺服器是節點管理器的一部分,因此,它總是通過roscore或者roslaunch自動啟動。在所有情況下,引數伺服器都能在後臺正常工作,因此沒有必要去花心思考慮它。然而,需要銘記的是,所有的引數都屬於引數伺服器而不是任何特定的節點。這意味著引數——即使是由節點建立的——在節點終止時仍將繼續存在。
查詢引數 rosparam get parameter_name
使用C++獲取引數
void ros::param::set(parameter_name,input_value);
boolros::param::get(parameter_name, output_value);
引數名是一個字串,它可以是全域性的、相對的或者是私有的。set函式中的輸入值input_value可以是std::string、bool、int或double型別;get函式的輸出值應該是上述某個型別的變數(通過引用傳遞)。如果引數值讀取成功,則get函式返回true;如果出現了問題,通常表示所請求的引數還沒有被指定一個值,則該函式返回false。
16 // overriding the default bluecolor .
17 ros::param::set("background_r" , 255) ;
服務呼叫與訊息的區別主要體現在兩個方面
服務呼叫是雙向的,一個節點給另一個節點發送資訊並等待響應,因此資訊流是雙向的。作為對比,當訊息釋出後,並沒有響應的概念,甚至不能保證系統內有節點訂閱了這些訊息。
服務呼叫實現的是一對一通訊。每一個服務由一個節點發起,對這個服務的響應返回同一個節點。另一方面,每一個訊息都和一個話題相關,這個話題可能有很多的釋出者和訂閱者。
列出所有服務通過下面這條指令,可以獲取目前活躍的所有服務1:
rosservicelist
當服務呼叫失敗的時候,可以呼叫ROS_ERROR_STREAM輸出錯誤資訊。
宣告依賴
前面已經介紹完所有客戶端程式碼相關的知識點。
但是要使catkin_make正確編譯一個客戶端程式,必須保證程式的功能包聲明瞭對定義服務型別的功能包的依賴。這種依賴,同訊息型別的使用一樣(參照3.3.3節),
需要編輯CMakeLists.txt和清單檔案packag.xml。為了編譯例子中的程式,我們必須保證CMakeLists.txt中的find_package行涉及了turtlesim功能包,如下所示:
find_package(catkinREQUIRED COMPONENTS roscpp turtlesim)
在package.xml中,我們應當確保build_depend和run_depend元素中存在相同名稱的包,即:
<build_depend>turtlesim</build_depend>
<run_depend>turtlesim</run_depend>
完成這些修改後,多次使用的catkin_make命令應該就能完成程式的編譯了。
回撥函式的功能及意義 p161
編寫服務的回撥函式如同訂閱一樣,節點提供的每一個服務必須關聯一個回撥函式,服務的回撥函式原型如下:
boolfunction_name(
package_name::service_type::Request&req,
package_name::service_type::Response&resp)
{
…
}
節點每次接收到一個服務請求,ROS就執行一次回撥函式。引數Request中包含了來自於客戶端的資料。回撥函式的工作是給Response物件的資料成員賦值。Request和Response資料型別與上面在客戶端使用的一致,因此需要相同的標頭檔案和相同的包依賴關係來編譯。回撥函式返回true表明成功,返回false則表示失敗。
錄製與回放包檔案
rosbag record -a 記錄所有資訊可能會造成大量的資訊,包的儲存空間佔用很大
rosbag record -j 可以在記錄的同時對資料進行壓縮
rosbag play
rosbag info
至此已將此教程過了一遍 2018-2-8