1. 程式人生 > >ROS機器人作業系統 基礎知識 節點 話題 訊息 服務 行動 引數 日誌 TF變換 目標結構 啟動檔案

ROS機器人作業系統 基礎知識 節點 話題 訊息 服務 行動 引數 日誌 TF變換 目標結構 啟動檔案

ROS機器人作業系統 基礎知識 節點 話題 訊息 服務 行動 引數 日誌 TF變換 目標結構 啟動檔案

1. 安裝

官方安裝指北

博文github

a 新增 sources.list

 sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

b 新增 keys

 sudo apt-key adv --keyserver hkp://pool.sks-keyservers.net --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116

c 安裝ros

 sudo apt-get update
 sudo apt-get install ros-indigo-desktop-full

d 初始化 rosdep

sudo rosdep init
rosdep update

e 環境變數設定

注意以後如果找不到 roscore啥的情況 重新設定一下環境變數
一勞永逸
echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc
source ~/.bashrc

單次
source /opt/ros/indigo/setup.bash

f 安裝軟體包 rosinstall

它可以方便讓你通過一條命令就可以給某個ROS軟體包下載很多原始碼樹。 
sudo apt-get install python-rosinstall

g 查詢錯誤

roswtf

2、常用快捷命令

a 檢視Lniux版本

lsb_release  -a
 檢視核心版本    cat /proc/version       uname  -a

b 檢視ros版本

roscore

c 檢視環境變數

printenv | grep ROS

export | grep ROS   
匯出所有環境變數 查詢 包含ROS的

d 檔案目錄

ll   ls -al 

e 刪除資料夾

rm -rf 資料夾/

f 返回上級

cd ..

g 進入檔案

cd ~/資料夾/
    建立資料夾  mkdir -p ~/catkin_ws/src    /home下建立/catkin_ws/src
		      -p  parents  如果沒有父目錄/catkin_ws 則自動建立

h 查詢軟體包package

rospack find roscpp
  rospy
  rosmsg
  rosnode
  rostopic
  rosservice
  std_msgs
  sensor_msgs

rospack find turtlesim
/opt/ros/indigo/share/turtlesim$ ls
cd images/
eog box-turtle.png     #使用 eye of  gnome影象檢視器檢視圖片

查詢支援的命令
package -h

i 建立功能包

 # catkin_create_pkg 包名字 依賴1 依賴2 依賴3 ...
 catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

j 查詢依賴關係

rospack depends1 beginner_tutorials    //直接依賴關係  少
rospack depends beginner_tutorials     //間接依賴關係   多

rospack depends1 beginner_tutorials   ->  std_msgs rospy roscpp

k 進入檔案路徑下

roscd只能切換到那些路徑已經包含在ROS_PACKAGE_PATH環境變數中的軟體包
roscd  roscpp
pwd   檢視當前路徑
roscd turtlesim/
roscd log  # 切換到ROS儲存日記檔案的目錄下

l 檢視路徑下包含的檔案

rosls
ls  
rosls turtlesim /images
ls 檔案

m 開啟檔案

cat package.xml    cat  檔名

n 編輯檔案
gedit package.xml gedit 檔名

o 執行程式前要執行的命令
roscore

p 列出活躍的節點

rosnode list

清理已經失活的節點
rosnode cleanup
>>>>   Unable to contact the following nodes:
   .....
 Cleanup will purge all information about these nodes from the master.
 Please type y or n to continue:
 y
 Unregistering   ...
 done

q 查詢節點的資訊

rosnode info 節點名字
rosnode info /rosout
rosnode info /turtlesim

------>>>>>
Node [/turtlesim]
Publications:   # 釋出的話題
 * /turtle1/color_sensor [turtlesim/Color]
 * /rosout [rosgraph_msgs/Log]
 * /turtle1/pose [turtlesim/Pose]

Subscriptions:  # 訂閱的話題
 * /turtle1/cmd_vel [unknown type]

Services:       # 節點提供的服務
 * /turtle1/teleport_absolute
 * /turtlesim/get_loggers
 * /turtlesim/set_logger_level
 * /reset
 * /spawn
 * /clear
 * /turtle1/set_pen
 * /turtle1/teleport_relative
 * /kill
    
contacting node http://ewenwan-Lenovo-G480:41932/ ...
Pid: 2907
Connections:
 * topic: /rosout
    * to: /rosout
    * direction: outbound
    * transport: TCPROS

r 執行一個新的節點

rosrun 包名 節點名

rosrun turtlesim turtlesim_node    //小烏龜

rosrun turtlesim turtlesim_node __name:=my_turtle   //重新命名節點

rosrun package-name executable-name
rosrun 包名字       可執行檔案的名字  (節點的編譯檔案)

s 清除rosnode列表 (更新rosnode list)

rosnode cleanup
用於終止節點時,節點未從節點節點管理器中清除,而更新節點管理器列表

rosnode kill node-name
rosnode kill turtlesim_node 
還可以用 Ctrl-C 命令終止節點。但使用這種方法時可能不
會在節點管理器中登出該節點,因此會導致已終止的節點
仍然在 rosnode 列表中。

    rosnode ping my_turtle      //節點活躍性測試

3 、鍵盤控制小烏龜

roscore                               master 節點

rosrun turtlesim turtlesim_node       小烏龜 節點

rosrun turtlesim turtle_teleop_key    鍵盤遙控節點 
                                      teleop 是 teleoperation(遙控操作)

turtlesim_node節點和turtle_teleop_key節點之間是通過一個ROS話題來互相通訊的。
urtle_teleop_key在一個話題上釋出按鍵輸入訊息,而turtlesim則訂閱該話題以接收該訊息。


rosnode list       #檢視執行的節點
	/ rosout   #rosout 節點是一個特殊的節點,通過 roscore 自動啟動
		       #其作用有點類似於控制檯程式中使用的標準輸出(即 std:: cout)。
		       #/rosout前面的反斜槓“/”表明該節點名稱屬於全域性名稱空間。
	/ teleop_turtle  #節點名並不一定與對應可執行檔名稱相同
	/ turtlesim

更改節點名稱    用__name 指定節點名稱
rosrun package-name executable-name __name:=node-name

ROS節點之間進行通訊所利用的最重要的機制就是訊息傳遞。
在ROS中,訊息有組織地存放在話題裡。

訊息傳遞的理念是:
當一個節點想要分享資訊時,它就會發布(publish)訊息到對應的
一個或者多個話題;

當一個節點想要接收資訊時,它就會訂閱(subscribe)它所需要的一個或者多個話題。
ROS節點管理器負責確保釋出節點和訂閱節點能找到對方;

而且訊息是直接地從釋出節傳遞到訂閱節點,中間並不經過節點管理器轉交。

4、檢視系統執行情況 視覺化資訊視窗

a. 節點關係拓撲

    rosrun rqt_grap rqt_grap
rqt_graph 能夠建立一個顯示當前系統執行情況的動態圖形  Graphical user interface

r 代表 ROS,qt 指的是用來實現這個視覺化程式的 Qt 圖形介面(GUI)工具包。
在該圖中, 橢圓形表示節點, 有向邊表示其兩端節點間的釋出-訂閱關係。
計算圖告訴我們, /teleop_turtle 節點向話題/turtle1/cmd_vel 釋出訊息,
而/turtlesim 節點訂閱了這些訊息(“cmd_vel”
是“command velocity”  命令的速度的縮寫。)。

b. 話題資料視覺化檢視

    rosrun rqt_plot rqt_plot
rqt_plot  可以實時顯示一個釋出到某個話題上的資料變化圖形

c. 系統問題檢查

roswtf    what  the fuck  搞什麼呀  fault 錯誤
這條命令會進行全面而深入的檢測,包括檢測你的環境變數、
安裝的檔案以及執行的節點。例如,roswtf 將會檢測在安裝過程
中 rosdep 初始化是否完成,任何節點是否出現了意外的掛起或者
終止,以及活躍的節點是否正確地和其他節點相連線等。

5、話題 訊息

a ROS話題的資訊查詢

rostopic

rostopic -h

rostopic list
rostopic list -h  //檢視 help

rostopic list -v    //檢視全部話題訊息型別。。。
rostopic list -p    //釋出的訊息
rostopic list -s    //訂閱的訊息

rostopic hz topic-name  #測量訊息釋出頻率   輸出每秒釋出的訊息數量
rostopic bw topic-name  #測量訊息佔用寬頻 Kb/s 輸出每秒釋出訊息所佔的位元組量

即使你一點都不關心這個特定的頻率,但是這些命令對調
試很有幫助,因為它們提供了一種簡單的方法來驗證這些
訊息確實有規律地在向這些特定的話題釋出

b 檢視話題上釋出的資料

rostopic echo [topic]       持續檢視更新話題上釋出的資料
rostopic echo /turtle1/cmd_vel

查詢話題  資訊引數
rostopic info topic-name  
# 利用 rostopic info 命令, 可以獲取更多關於話題資訊型別等引數:

rostopic info /turtle1/color_sensor
輸出中最重要的部分是第一行,給出了該話題的訊息型別。
因此 , 在/turtle1/color_sensor 話題中釋出 訂閱的消 息類 型是
/turtlesim/Color。Type 在文字輸出中表示資料型別

話題上釋出訊息型別的命名 :   
訊息型別名總會包含一個斜槓,斜槓前面的名字是包含它的包:
package-name/type-name
1 避免命名衝突。
2 依賴關係看上去更明朗
3 有助於猜測它的含義

    檢視訊息資料型別:
rosmsg show  /turtlesim/Color    
uint8 r
uint8 g
uint8 b

上述輸出的格式是域(field)的列表,每行一個元素。每一
個域由基本資料型別(例如 int8、bool、或者 string)以及域名稱
定義。上述輸出告訴我們 turtlesim/Color 包含三個無符號 8 位整型變數 r,g 和 b。
任何話題的訊息只要是 turtlesim/Color 型別,
都由上述三個域的值定義。

rostopic info /turtle1/cmd_vel  話題上釋出的訊息型別
Type: geometry_msgs/Twist

rosmsg show geometry_msgs/Twist 訊息 的具體資料格式
geometry_msgs/Vector3 linear    # 線速度  沿x y z軸的直線數度
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular   # 角速度  沿 x y z軸的旋轉叫速度 俯仰 偏行 滾轉
float64 x
float64 y
float64 z

該 例 中 , linear 和 angular 都 是 復 合 域 , 其 數 據 類 型 是
geometry_msgs/Vector3。縮排格式表示命名為 x,y 和 z 的域是對
應的上級兩個域之一的成員。也就是說,geometry_msgs/Twist 消
息包含六個成員,並且以兩個向量的形式組織,分別為 linear 和angular。
其中每個數值都是基本資料型別 float64,即每個數值都是 64 位浮點型資料。

rosmsg show 命令在顯示訊息型別時自動向下展
開復合域直到基本型別為止,同時使用縮排的形式來展示這種巢狀結構

c 檢視所釋出話題的訊息型別

rostopic type [topic]

rostopic type /turtle1/cmd_vel

rosmsg show 訊息型別
rosmsg show message-type-name

rosmsg show geometry_msgs/Twist

rostopic type /turtle1/cmd_vel | rosmsg show   管道命令

d 把資料釋出到當前某個正在廣播的話題上

大多數時候,釋出訊息的工作是由特定的程
序完成的 * 。但是,你會發現有時候手動釋出訊息是很實用的。
要實現該功能,利用rostopic命令列工具

rostopic pub –r rate-in-hz topic-name message-type message-content
	          頻率       話題名字    訊息型別    訊息的引數值

此處展示的命令 利用了 -r 來指定話題以頻率 rate 模式釋出訊息,
即以一定的時間週期釋出訊息。

這條命令同樣支援一次性發布的模式(-1“虛線後為數字 1”)和
特別的鎖存模式(-l“虛線後為字母 L 的小寫”),
鎖存模式雖然也只是釋出一次訊息,
但是會確保該話題的新訂閱者也會收到訊息。實際上,鎖存模式是預設的模式。

同樣也可以從檔案中讀取訊息(利用-f 引數)
或者從標準的輸入(把-f 引數和訊息的內容從命令中都刪掉)中讀取。
兩種情況下,輸入應該符合 rostopic echo 的輸出格式。

1次/1秒頻率釋出   位移線速度為2 直線行走 前進
rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[2,0,0]’ ’[0,0,0]’

1次/1秒頻率釋出   位移線速度為2 直線行走 倒退
rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[-2,0,0]’ ’[0,0,0]’

1次/1秒頻率釋出   角速度為2 逆時針旋轉  逆正順負
rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[0,0,0]’ ’[0,0,2]’

1次/1秒頻率釋出   角速度為2 順時針旋轉
rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist ’[0,0,0]’ ’[0,0,-2]’

事實上,上述兩個例子中的非零域——位移 linear.x  ’[-2,0,0]’ 以及角
度 angular.z   ’[0,0,2]’  ——是 turtlesim 重點關注的兩個變數,
而這兩個變數是 geometry_msgs/Twist 訊息中僅有的兩個變數。
因為其他四個變量表示的運動對於該二維模擬來說是不可能發生的,
所以 turtlesim 程式忽略了這些變數。

rostopic pub [topic] [msg_type] [args]
rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'        //轉一圈

rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'        //一直轉

話題通訊的 多對多機制:
rosrun turtlesim turtlesim_node __name:=A
rosrun turtlesim turtlesim_node __name:=B
rosrun turtlesim turtle_teleop_key __name:=C
rosrun turtlesim turtle_teleop_key __name:=D
遙控節點之一發送按鍵命令時,兩個海龜都會有同樣的運動來響應

節點之間的鬆耦合關係:
“生產”訊息的程式(例如 turtle_teleop_key)只管釋出該訊息,
而不用關心該訊息是如何被“消費”的。
“消費”訊息的程式(例如 turtlesim_node)只管訂閱該話題或
者它所需要訊息的所有話題,而不用關心這些訊息資料是如何“生產”的。

6、節點服務

此外,ROS 為更加直接的一對一通訊提供了一種稱為服務(services)的機制。
第二種通訊機制更為少見,但是也有其應用價值.

服務(services)是節點之間通訊的另一種方式。
服務允許節點發送請求(request) 並獲得一個響應(response)。
rosservice可以很輕鬆的使用 ROS 客戶端/伺服器框架提供的服務。
rosservice提供了很多可以在topic上使用的命令。

使用方法:
列出所有服務,
	rosservice list         輸出可用服務的資訊
	可以獲取目前活躍的所有服務.
	rosservice list 命令的輸出是所有服務的全域性名稱。

	rosservice call         呼叫帶引數的服務
	rosservice type         輸出服務型別
	rosservice find         依據型別尋找服務find services by service type
	rosservice uri          輸出服務的ROSRPC uri

服務呼叫(service calls)。服務呼叫與訊息的區別主要體現在兩個方面。
1 服務呼叫是雙向的,一個節點給另一個節點發送資訊並等待
  響應,因此資訊流是雙向的。作為對比,當訊息釋出後,並
  沒有響應的概念,甚至不能保證系統內有節點訂閱了這些訊息。

2 服務呼叫實現的是一對一通訊。每一個服務由一個節點發起,
  對這個服務的響應返回同一個節點。另一方面,每一個訊息
  都和一個話題相關,這個話題可能有很多的釋出者和訂閱者。

客戶端(client)節點發送一些稱為請求(request)
的資料到一個伺服器(server)節點,並且等待迴應。
伺服器節點接收到請求後,採取一些行動(計算、配置軟體或硬體、改變
自身行為等),然後傳送一些稱為響應(response)的資料給客戶端節點。

[client] ------> request-------->[server]--------->response------->[client]
客戶端         傳送請求           服務端            響應              客戶端
請求和響應資料攜帶的特定內容由服務資料型別(servicedata type)來決定,
它與決定訊息內容的訊息型別是類似的

同訊息型別一樣,服務資料型別也是由一系列域構成的。
唯一的區別就在於服務資料型別分為兩部分,分別表示
請求  (客戶端節點提供給伺服器節點)和
響應  (服務其節點反饋給客戶端節點)。

服務的型別
1) 特定節點的服務。一些服務,例如上表中 
  get_loggers 和 set_logger_level(roscore節點提供)
  是關於節點日誌訊息的服務,是用來從特定的節點獲取或者向其傳遞資訊的。
  這類服務通常將節點名用作名稱空間來防止命名衝突,
  並且允許節點通過 私 有 名 稱 來 提 供 服 務 , 
  例 如 ~get_loggers 或 者~set_logger_level 
  (參照 4.5 瞭解 loggers 和 logger level 的詳情)。
  
2) 通用節點服務。其他服務表示更一般的不針對某些特定節點的服務。
  例如,名 為 /spawn 的 服 務 用 於 生 成 一 個 新 的 仿 真 海 龜 , 是 由
  turtlesim 節點提供的。但是在不同的系統中,這個服務完全可能由其他節點提供;
  當我們呼叫/spawn 時,我們只關心是
  否有一個新的海龜出現,而不關心具體哪個節點起作用這種細 節 。 
  上 表 列 出 的 所 有 服 務 , 除 了 get_loggers 和
  set_logger_level,都可以歸入此類。這類服務都有特定的名稱來描述
  它們的功能,卻不會涉及任何特定節點。

7、檢視服務型別和服務的引數資訊

a. 檢視節點提供的服務

檢視某個節點的服務型別 要檢視一個特定節點提供的服務,使用 rosnode info 命令:
  rosnode info node-name

下面的例子給出了這條命令在 turtlesim 節點上輸出結果的相應部分:
roscore                               master 節點
rosrun turtlesim turtlesim_node       小烏龜 節點
rosnode info /turtlesim
>>>>>>>>>

Services:
*/turtle1/teleport_absolute
*/turtlesim/get_loggers
*/turtlesim/set_logger_level
*/reset
*/spawn
*/clear
*/turtle1/set_pen
*/turtle1/teleport_relative
*/kill

b. 檢視服務型別 與 其資料詳情

查詢提供服務的節點 要完成這個反向查詢,即查詢提供給定服務的節點,可以使用這條指令:
rosservice node service-name

rosservice type service-name     服務資料型別
rosservice type /clear    -------->>>>  std_srvs/Empty

rosservice type  /spawn   -------->>>> turtlesim/Spawn 

   rosservice info service-name  引數資訊
   rosservice info /spawn
   --->>
    -------->>>>>

Node: /turtlesim
URI: rosrpc://ewenwan-Lenovo-G480:33246
Type: turtlesim/Spawn                      #服務的資料型別
Args: x y theta name

turtlesim + Spawn ⇒ turtlesim/Spawn
功能包名     型別名    服務資料型別

檢視服務資料型別 詳情
當服務的資料型別已知時,我們可以使用rossrv 指令來獲得此服務資料型別的詳情:
rossrv show service-data-type-name
      檢視服務資料型別
      rossrv  同   rostopic 的訊息型別檢視  rosmsg show 一樣

      rossrv show service-data-type-name    

      rossrv show turtlesim/Spawn

      rosservice type  /spawn | rossrv show   管道命令
---->>>>>>
float32 x    #短橫線(---)之前的資料是請求項,這是客戶節點發送到服務節點的資訊。
float32 y        #request    新生成 小海龜的位置   x,y
float32 theta    朝向角度
string name      名字
---
string name     #response
#短橫線之後的所有欄位是響應項,或者說是服務節點完成請求後傳送回請求節點的資訊

		     Topics           Services
active things        rostopic         rosservice 查詢話題/服務用   
data types           rosmsg           rossrv     查詢訊息/服務資料型別用

8、呼叫服務

a 從命令列檢視和呼叫服務

rosservice call service-name request-content
rosservice call clear             //該服務不需要輸入引數

rosservice call /spawn 2 2 0.2 my_turtle  
//需要引數的服務   x y 朝向角度(弧度制)  名字    (名稱空間)

rosservice call /spawn  3 3 0 Mikey2     位置(3,3) 朝向0
rosservice call /spawn 5 5 1.57 Mikey3   位置(5,5) 朝向90度
rosservice call /spawn 5 5 3.14 Mikey4   位置(7,7) 朝向180度
rosservice call /spawn 5 5 6.28 Mikey4   位置(11,11) 朝向360度    最上角

響應應該是: name: Mikey2...   #名稱空間


 這些新的海龜有它自己的資源集,
 包括 cmd_vel、pose、color_sensor 話題、
 set_pen 服務、
 teleport_absolute 服務、
 teleport_relative 服務。
 在本例中,這些新的資源在一個名為 Mikey 的名稱空間中。
 這些資源在常用的 turtle1 名稱空間之外,
 也符合其他節點想要獨立控制這些海龜的需求。
 這一點很好地闡明瞭名稱空間可以有效地阻止命名衝突。


   檢視需要引數的服務 的引數
   rosservice type spawn | rossrv show

b 程式呼叫服務

  服務  之 client 客戶端 編寫
  1) 宣告請求 和 響應的型別   
     #include <package_name/type_name.h> // 包名/服務型別名

     就像訊息型別一樣(參照 3.3.1 節),每一種服務資料型別都對應一個我們必須包含的相關 C++標頭檔案
     #include <turtlesim/Spawn.h>
     來包含名為 turtlesim::Spawn 類的定義,
     這個類定義了我們想要呼叫的服務的資料型別,包括全部請求 和 響應欄位。

  2)建立客戶端物件
      在按照節點要求初始化後(通過呼叫 ros::init 和建立一個 NodeHandle 物件),
      我們的程式必須建立一個型別為
      ros::ServiceClient 的物件,實際上是這個物件完成服務呼叫。
      按照如下宣告一個 ros::ServiceClient 物件:

      ros::ServiceClient client = node_handle.serviceClient<service_type>(service_name);

      這條指令有三個重要部分。
	 a)  node_handle  是常用的 ros::NodeHandle 物件,這裡我們將呼叫它的 serviceClient 方法。
	 b)  service_type 是我們在上面標頭檔案中定義的服務物件的資料型別,
	                   在本例中,型別為 turtlesim::Spawn。
	 c)  service_name 是一個字串, 說明了我們想要呼叫的服務名稱。
	      再次強調, 這應當是一個相對名稱, 雖然也可以宣告為全域性名稱。
	      例子中使用的是相對名稱“spawn”。

      一般來講,建立這個物件的過程並不佔用多少計算量,
      因為除了存放之後想呼叫的服務詳情外,並不用做太多工作。
      值得注意的是,與建立類似的 ros::Publisher 物件相比,
      建立 ros::ServiceClient 物件不需要佇列大小。
      之所以會造成這種差異,是因為服務呼叫 直到響應抵達後 才會返回。
      由於客戶端要等待服務呼叫完成,
      因此沒有必要維持一個 傳送服務呼叫 的 佇列。

   3) 建立請求和響應物件
      我們上面包含的標頭檔案中分別定義了請求和響應的類, 
      命名為 Request 和 Response。
      這些類必須通過功能包名稱和服務型別來引用,
  
  如下所示:
// 呼叫 建立新的 小烏龜的 服務=============
#include <ros/ros.h>
#include <turtlesim/Spawn.h>
int main( int argc , char ** argv )
{
    ros::init ( argc , argv , "spawn_turtle") ; // ros初始化
    ros::NodeHandle nh ;// 節點控制代碼
    // 建立服務客戶端(呼叫服務)
    ros::ServiceClient spawnClient = nh.serviceClient <turtlesim::Spawn>("spawn") ;
    //Rros:: ServiceClient client =node_handle.advertise<service_type>(service_name, true);
    // 可以建立一個持續的服務客戶端 不推薦
    
    // Create the request and response objects.
    turtlesim::Spawn::Request req ;     // 請求
    turtlesim::Spawn::Response resp ;   /// 響應
    
    // Fill in the request data members. 請求需要傳遞的一些引數
    req.x = 2; // 生成的位置
    req.y = 3;
    req.theta = M_PI/2; // 角度朝向
    req.name = "my_spa_turtle" ;// 名字
    
    // 呼叫服務,等待並獲取響應
    bool success = spawnClient.call( req , resp ) ;
    //呼叫服務 一旦擁有了一個 ServiceClient、一個完整的 Request 以及 Response,我們就可以呼叫服務了
    //這個方法實際上完成了定位伺服器節點、傳輸請求資料、等待響應和儲存響應資料等一系列工作。
    //這個呼叫方法返回一個布林值來表明服務呼叫是否成功完成。
    //若呼叫失敗通常意味著另一隻有著被請求名稱的海龜已經存在。

    // Check for success and use the response .
    if ( success ) 
    {
        ROS_INFO_STREAM("Spawned a turtle named: "
        << resp.name) ;
     } 
    else 
    {
        ROS_ERROR_STREAM("Failed  to  spawn.") ;
        //當服務呼叫失敗的時候,可以呼叫 ROS_ERROR_STREAM 輸出錯誤資訊。
     }  
}
在預設情況下,查詢和連線伺服器節點的過程是在呼叫方法內部發生的。
這個連線 僅在 此次服務呼叫期間有效,在呼叫返回後將被關閉。
ROS 也支援持續服務客戶端的概念, ros::ServiceClient 
建構函式建立與伺服器節點的連線,然後可以被這個客戶端物件的所有後續呼叫重用。

通過傳遞 true 值給建構函式的第二個引數,
可以建立一個持續的服務客戶端(在前面的例子中使用了預設值 false):

Ros:: ServiceClient client =node_handle.advertise<service_type>(service_name, true);

線上文件中對持續客戶端的應用是輕微抵制的 ,因為這麼做並不能提升多少系統性能,作者的非正式實驗表明,
效能只提升了約 10%,然而其代價是導致系統在重啟和修改伺服器節點時的魯棒性變差。

!!!!!!!!!!!!!!!!!!!!!
宣告依賴
編譯服務cpp需要 修改 CMakeLists.txt 和清單檔案 packag.xml
為 了 編 譯 例 子 中 的 程 序 , 我 們 必 須 保 證

CMakeLists.txt 中的 find_package 行涉及了 turtlesim 功能包,如下所示:
find_package(catkin REQUIRED COMPONENTS roscpp turtlesim)

在 package.xml 中,我們應當確保 
build_depend 和 
run_depend
元素中存在相同名稱的包,即:
<build_depend>turtlesim</build_depend>
<run_depend>turtlesim</run_depend>
完成這些修改後,多次使用的 catkin_make 命令應該就能完
成程式的編譯了。

c 程式建立伺服器

示例提供名為 toggle_forward 服務,同時具備控制 turtlesim 機器人運動的功能,
每次服務呼叫時將在前進和轉向之間轉換。
可以看到,伺服器端的程式碼 與 訂閱話題的程式碼非常相似。
除了名稱上的區別,
我們必須建立一個 ros::ServiceServer 來代替ros::Subscriber,

唯一的區別在於伺服器端可以通過一個 響應物件 和一個表明 成功與否 的布林變數給客戶端回傳資料。

編寫服務的回撥函式 如同訂閱一樣,節點提供的每一個服務必須關聯一個回撥函式,服務的回撥函式原型如下:
bool function_name(
package_name::service_type::Request &req), //請求
package_name::service_type::Response &resp)// 響應
) 
{
...
}
節點每次接收到一個服務請求,ROS 就執行一次回撥函式。
引數 Request 中包含了來自於客戶端的資料。
回撥函式的工作是給 Response 物件的資料成員賦值。 
Request 和 Response 資料型別與上面在客戶端使用的一致,
因此需要相同的標頭檔案和相同的包依賴關係來編譯。
回撥函式返回 true 表明成功,返回 false 則表示失敗。

在該例中, Request 和 Response 都使用了 std_srvs/Empty (空字串)
作為其資料型別,因此無需針對這兩個物件做任何資料處理。
回撥函式的唯一工作是切換一個稱為 forward 的全域性布林變數,用於管理在主函式中釋出的速度訊息。
 // 提供一個 切換旋轉與前進的 服務=====================
  #include <ros/ros.h>
  #include <std_srvs/Empty.h>      // 服務資料型別           
  #include <geometry_msgs/Twist.h> // 釋出小烏龜速度訊息型別  
 
  bool forward = true ;
  bool toggleForward (
                      std_srvs::Empty::Request &req ,
                      std_srvs::Empty::Response &resp ) {
     forward = !forward ; //改變 前進 旋轉 標誌 在主迴圈中判斷
     ROS_INFO_STREAM("Now sending " << ( forward ?"forward" : " rotate ") << "  commands.") ;
     return true ;
   }
  
   int main( int argc , char** argv ) 
   {
   ros::init ( argc , argv , "change_forward_rotate") ;// ros初始化
   ros::NodeHandle nh ;// 節點控制代碼
  
   // 服務客戶端,被呼叫者
   ros::ServiceServer server = nh.advertiseService ("change_forward_rotate" , &toggleForward ) ;
  
   // Publish commands, using the latest value for forward ,
   // until the node shuts down.
   // 話題釋出速度命令
   ros::Publisher pub = nh.advertise <geometry_msgs::Twist>("turtle1/cmd_vel" , 1000) ;
   ros::Rate rate (2) ;
   while ( ros::ok () ) 
   {
	   geometry_msgs::Twist msg ;
	   msg.linear.x = forward ? 1.0 : 0.0 ;//前進
	   msg.angular.z = forward ? 0.0 : 1.0 ;//旋轉
	   pub.publish (msg) ;
	   ros::spinOnce () ;
	   rate.sleep () ;
    }
 }
rosrun agitros changeForwardRotate    執行節點
rosservice list  檢視是否出現相應的服務
rosservice call /change_forward_rotate   呼叫相應的服務


由於在私有名稱的解析上存在一些理解上的歧義,
ros::NodeHandle::advertiseService
拒絕接受私有名稱(即那些以~開始的名稱)。
這種約束的解決方案是基於以下事實—一種目前我們還沒用使用過的節點建立方法,

即可以利用節點自身的預設名稱空間來建立 ros::NodeHandle 物件。
舉個例子,我們可以按照以下方式來建立
ros::NodeHandle:
ros::NodeHandle nhPrivate("~");

這種情況下,傳送給這個節點控制代碼的任意區域性名稱的預設名稱空間同節點名稱一致。

特別指出的是,這意味著如果我們用這個控制代碼和相對名稱來發佈一個服務,效果將與使用私有名稱相同。

例如在一個名為/foo/bar 的節點,像如下廣播一個名為/foo/bar/baz 的服務:

ros::ServiceServer server =nhPrivate.advertiseService("baz", Callback);

如果控制代碼願意接受私有名稱的話,這段程式碼的效果與使用通常的 NodeHandle 廣播名為~baz 的服務效果相同。


複製服務:
roscp [package_name] [file_to_copy_path] [copy_path]
roscp rospy_tutorials Add

9、引數伺服器

除 了 前 面 介 紹 過 的 消 息 傳 遞 , ROS 還 提 供 另 一 種 參 數
( parameters )機制用於獲取節點的資訊。其主要思想是使用集中
引數伺服器( parameter server )維護一個變數集的值,包括整數、
浮點數、字串以及其他資料型別,每一個變數用一個較短的字
符串標識 1,2 。由於允許節點主動查詢其感興趣的引數的值,它們
適用於配置那些不會隨時間頻繁變更的資訊。

 使得我們能夠儲存並操作ROS 引數伺服器(Parameter Server)上的資料。
 引數伺服器能夠儲存整型、浮點、布林、字串、字典和列表等資料型別。
 rosparam使用YAML標記語言的語法。一般而言,YAML的表述很自然:
 1 是整型, 1.0 是浮點型, one是字串, true是布林, 
 [1, 2, 3]是整型列表, {a: b, c: d}是字典. 
 rosparam有很多指令可以用來操作引數,

a 檢視引數列表

rosparam  list   僅執行 roscore
>>>>                         
/rosdistro         ros版本
/roslaunch/uris/host_ewenwan_lenovo_g480__40299
/rosversion
/run_id

在當前版本的 ROS 中,引數伺服器是節點管理器的一部分,
因此,它總是通過 roscore 或者 roslaunch 自動啟動。在所
有情況下,引數伺服器都能在後臺正常工作,因此沒有必
要去花心思考慮它。然而,需要銘記的是,所有的引數都
屬於引數伺服器而不是任何特定的節點。這意味著引數—
—即使是由節點建立的——在節點終止時仍將繼續存在。

b 查詢引數

rosparam get            獲取引數  查詢引數 
rosparam get parameter_name
rosparam get /rosdistro
>>> indigo

除此以外,還可以檢索給定名稱空間中的每一個引數的值,其命
令為:rosparam get namespace
例如,通過查詢全域性名稱空間,我們可以一次性看到所有引數的值:
rosparam get /

c 設定引數

rosparam set           
rosparam set  parameter_name  parameter_value

該命令可以修改已有引數的值或者建立一個新的引數。例如,
以下命令可以建立一系列字串引數,用以儲存一組卡通鴨子的
顏色偏好:
rosparam set /duck_colors/huey red
rosparam set /duck_colors/dewey blue
rosparam set /duck_colors/louie green
rosparam set /duck_colors/webby pink

另外,我們可以同時設定同一名稱空間中的幾個引數:
rosparam set  namespace  values

這裡要以 YAML 字典的形式表示引數和對應值的對映關係。
下面的例子和前面四行命令具有同樣的作用:  (冒號後有空格)
rosparam set /duck_colors "huey: red
dewey: blue
louie: green
webby: pink"

檢視是否設定成功
rosparam get /duck_colors/
>>>>
{dewey: blue, huey: red, louie: green, webby: pink}


需要注意的是,這種語法需要在命令中使用換行符。
當然,這並不會造成什麼問題,因為第一個引號告訴 bash 命令尚
未完成。當在引號內按下回車時,終端將插入一個換行符而不是執行命令。
冒號後的空格是非常重要的,以確保 rosparam 將其作為一個/duck_colors 
名稱空間內的引數集,而不是全域性名稱空間中的單個字串引數 duck_colors。


在launch檔案中設定:
這是所有node節點的全域性 相對名稱

<group ns="duck_colors">
<param name="huey" value="red" />
<param name="dewey" value="blue" />
<param name="louie" value="green" />
<param name="webby" value="pink" />
</group>

也可在各自的node節點內設定引數
<node ... >
<param name="param-name" value="param-value" />
. . .
</node>

在該結構下,引數名將被當做該節點的私有名稱。
這是 ROS 命名規則的一個例外。作為節點元素的子集時,
param 元素中給出的引數名總是被當做私有名稱解析,無論它們是否以~或者/開始。

從檔案中讀取引數:
最後,啟動檔案也支援 與rosparam load等價的命令,可以一次性從檔案中載入多個引數:
<rosparam command="load" file="path-to-param-file" />
這裡列出的引數檔案通常是通過 rosparam dump 命令建立的。
<rosparam
command="load"
file="$(find package-name)/param-file"
/>
與 rosparam load 一樣,這個功能有助於測試,因為它允許使用者重現在過去的某個時間有效的引數。

d 儲存 引數

為了以 YAML 檔案的形式 儲存 名稱空間 中的所有引數,可以使用
rosparam dump 命令
rosparam dump filename namespace

e 載入引數檔案

rosparam load           從檔案讀取引數
它從一個檔案中讀取引數,並將它們新增到引數伺服器:
rosparam load filename namespace

對於這些命令,名稱空間引數是可選的,預設值為全域性名稱空間(/)。
儲存和載入的組合可以用來測試,因為它提供了一種

快捷方式獲取一定時間內的引數“快照”,並且可以進行場景復現。

f 例子 turtlesim 中的引數

作為一個引數的具體例子,讓我們來看看在 turtlesim 中如何使用它們的。
如果你啟動 roscore 和 turtlesim_node,
然後查詢rosparam 列表,會看到像下面這樣的輸出:

rosparam  list
>>>>
/background_b
/background_g
/background_r
/rosdistro
/roslaunch/uris/host_ewenwan_lenovo_g480__37268
/rosversion
/run_id

會多出 背景顏色的 三個分量,它們指定在 turtlesim 視窗中使用背景色,
分別為紅色、綠色和藍色通道,一個好的策略,也是演示真正的 ROS 節點
如何工作的更好案例,是 turtlesim 首先測試這些引數是否存在,當且僅當
這些引數不存在時,才指定預設的藍色。

g 獲取背景顏色值

可以使用 rosparam get 命令獲取背景引數的值:
rosparam get /background_r
rosparam get /background_g
rosparam get /background_b
這些命令的返回值分別是 69、86 和 255。由於這些值是比較小的整數,讓人容易聯想到,
而且確實是,每個通道是一個 8 位整數,範圍從 0 到 255。
因此,turtlesim 預設其背景顏色為(69,86,255),這正是我們平時所稱的深藍色。

h 設定背景顏色值

//設定為紅色
rosparam set background_r 250
rosparam set background_g 0
rosparam set background_b 0

    rosparam deleat  引數名  刪除引數

然而,即使我們設定完引數後,背景顏色仍然是原來的顏色。
這是為什麼呢?這是因為只有當 turtlesim_node 的/clear 服務被調
用時, 它才會從引數伺服器讀取這些引數的值。呼叫這個服務可
以使用以下命令:
rosservice call /clear

對一個節點來說,可以請求引數伺服器在引數更新後將新引數值發給它,
這個功能可以通過 ros::param::getCached
命令替換 ros::param::get 來實現。
然而,這種方法只是為了提高效率,並沒有消除節點檢查引數值的需要。

i 使用 C++獲取引數

使用ROS引數的C++介面是相當簡單的 :
void ros::param::set(parameter_name, input_value);
bool ros::param::get(parameter_name, output_value);

在這兩種情況下,引數名是一個字串,它可以是全域性的、相對的或者是私有的。set 函式中的輸入值 input_value
可以是std::string、bool、int 或 double 型別;
get 函式的輸出值應該是上述某個型別的變數(通過引用傳遞)。

如果引數值讀取成功,則 get 函式返回 true;如果出現了問題,通常表示所請求的引數還沒
有被指定一個值,則該函式返回 false。為了檢視函式的行為,讓 我們來看看下面兩個例項。

ros::param::set 功能 cpp 檔案

  // This program waits for a turtlesim to start up , and
  // changes its background color .
  #include <ros/ros.h>
  #include <std_srvs/Empty.h>//服務
 
  int main( int argc , char** argv )
  {
  ros::init ( argc , argv , "set_bg_color") ;
  ros::NodeHandle nh ;

  // Wait until the clear service is available , which
  // indicates that turtlesim has started up , and has
  // set the background color parameters .
   ros::service::waitForService ("clear") ;//等待 /clear服務可用 即turtlesim 節點已經啟動
 
  // Set the background color for turtlesim ,
  // overriding the default blue color .
   ros::param::set ("background_r" , 255) ;// set 設定引數
   ros::param::set ("background_g" , 255) ;
   ros::param::set ("background_b" , 0) ;
 
 // Get turtlesim to pick up the new parameter values.
 //rosservice call /clear
   ros::ServiceClient clearClient = nh.serviceClient <std_srvs::Empty>("/clear") ;
   std_srvs::Empty srv ;
   clearClient.call(srv); //更新
 }
說明了 ros::param::set 的功能,它為 turtlesim 背景顏
色三個引數賦值。本程式的程式碼在啟動 turtlesim 節點前等待
/clear 服務呼叫結束,從而確保 turtlesim 不會覆蓋這裡設定
的值。並且通過呼叫/clear 服務強制 turtlesim 讀取我們設定
的引數值。
 //最大線速度從引數讀取 產生隨機數0~1
 //
 // This program publishes random velocity commands, using
 // a maximum linear velocity read from a parameter.
 #include <ros/ros.h>
 #include <geometry_msgs/Twist.h>//速度和姿態
 #include <stdlib.h>

 int main( int argc , char** argv ) 
 {
 ros::init ( argc , argv , "publish_velocity") ;
 ros::NodeHandle nh ;
//建立釋出者 釋出在話題  turtle1/cmd_vel 上佇列大小1000
 ros::Publisher pub = nh.advertise<geometry_msgs::Twist>( "turtle1/cmd_vel", 1000) ;
 //生成產生隨機數的種子點
 srand ( time (0) ) ; //初始化隨機數 種子

// Get the maximum velocity parameter .
  const std::string PARAM_NAME = "~max_vel;
  double maxVel;
  bool ok = ros::param::get (PARAM_NAME, maxVel) ;// get 讀取引數
  if (!ok) {
  ROS_FATAL_STREAM("Could not get parameter:"
  << PARAM_NAME) ;
  exit (1) ;
 }

  ros::Rate rate (2) ;
  while ( ros::ok () ) 
  {
 // Create and send a random velocity command.
   geometry_msgs::Twist msg ;// 速度訊息型別
   msg.linear.x = maxVel*double ( rand () )/double (RAND_MAX) ;  //線速度  為 0 到 1 之間的某個值 * maxVel
   msg.angular.z = 2*double ( rand () )/double (RAND_MAX) -1;    //角速度  弧度制 為-1 到 1 之間的某個值
   //釋出訊息
   pub.publish(msg) ;
  // Wait untilit's time for another iteration .
  rate.sleep () ;
   }
 }
是命令 ros::param::get 的例程。
作為原 pubvel 例程(表3.4)的拓展,這裡讀取私有浮點引數 max_vel 的值,
並使用這個引數值來調整隨機生成線速度的大小

rosparam set /publish_velocity/max_vel 0.1

如果這個引數不存在,那麼,該程式將會報錯並且終止。

通過在命令列中使用類似重對映的語法為節點的私有引數賦值在技術上是可行的(但是有些混亂),
可以通過給引數名新增下劃線字首實現,如下所示:

_param-name:=param-value
這種命令列引數將被轉換為 ros::param::set 的呼叫,通過
ros::init 將“_”替換為“~”構成私有引數的形式。
例如,我們可以使用下面的命令成功啟動 pubvel_with_max 節點:

rosrun agitr pubvel_with_max _max_vel:=1
rosrun agitros pubVelWMVel _max_vel:=6

rosparam delete         刪除引數

rosparam get background_g 
rosparam get /              //得到全部引數資料

rosparam dump params.yaml   //將所有的引數寫入params.yaml檔案

rosparam load params.yaml copy   //將yaml檔案過載入新的名稱空間,比如說copy空間
rosparam get copy/background_b   

10、日誌操作

a 視覺化日誌

rqt_console

屬於ROS日誌框架(logging framework)的一部分,用來顯示節點的輸出資訊。
rqt_logger_level

 允許我們修改節點執行時輸出資訊的日誌等級(logger levels)
(包括 DEBUG、WARN、INFO和ERROR)。

b 錄製訊息/資料 與回放

mkdir ~/bagfiles   //建立一個用於錄製的臨時目錄

cd ~/bagfiles      //