1. 程式人生 > >1.3 ROS學習筆記之服務I

1.3 ROS學習筆記之服務I

導覽

你將從本單元學到:

什麼是服務?
如何管理一個機器人的服務?
如何呼叫一個服務?

課前總結

  • 主題是棍棒,服務是屠龍刀
  • 呼叫服務(如人臉識別),一直等待,直到服務完成
  • 呼叫行為(某種方式移動機器人),可並行執行其他行為,且可以接收移動中的反饋
  • 檢視所有可用的服務: rosservice list
  • 獲取服務的資訊:rosservice info /name_of_your_service
  • 呼叫服務: rosservice call /gazebo/delete_model “model_name: ‘cafe_table’ 服務名+引數
  • 獲取場景中的物件列表: rostopic echo /gazebo/model_states -n1
  • 檢視服務的相關資訊(提供服務的節點,使用的資訊型別,呼叫服務時引數):rosservice info /name_of_the_service
  • 檢視服務訊息結構:rossrv show name_of_the_package/Name_of_Service_message
  • 節點提供服務,節點呼叫服務

服務概述

使用主題,你差不多就可以做自己想做的的任何事情。很多ROS功能包僅用到了主題就可以完美地工作。

那麼,為什麼還需要學習 服務 呢?
在某些情況下,主題是不夠的,或者使用起來太過麻煩。當然,你可以使用一根棍棒毀掉 死星,但需要花費很長很長時間。更好的辦法是,讓天行者盧克替你去做這件事情,對吧?服務的作用正是如此,它們使工作變得更加簡單

服務行為主題辨析

理解服務的概念和用法,必須把服務和主題與行為進行比較。

假設你有個自己的BB-8機器人,它有一個鐳射感測器,一套人臉識別系統和一個導航系統。鐳射感測器將向一個主題,以20HZ的頻率釋出資料。我們使用主題是因為我們需要使它釋出的那些資訊時刻能被其他ROS系統(比如導航系統)使用。

人臉識別系統將提供一個 服務。你的ROS程式將呼叫該服務,然後一直等著,直到識別系統告訴你BB-8前面所站著的人的姓名。

導航系統將提供一個 行為。你的ROS程式將呼叫該行為使機器人移動,並且當它在執行該任務時,你的程式還可以執行其他任務,比如抱怨C-3P0是多麼的辛苦。行為會在移動的過程中給你 反饋 資訊(例如,距離期望座標的距離)

服務與行為(同步非同步)

服務是 同步的。當你的程式呼叫一個服務時,從服務接收到一個結果前你的程式不能再做其他事情。
行為是 非同步的。就像啟動了一個新執行緒。當你的ROS程式呼叫一個行為時,你的程式可以在該行為被執行的同時在另一執行緒執行其他任務。

當你的程式從服務接收到結果前不需要執行其他任務時,使用服務

服務例項(啟動服務)

使用一個launch檔案啟動多個節點

第一個節點提供 服務。 該節點是包含該服務的節點。
第二個節點呼叫該服務。當該服務被呼叫時,機器人將按給定的軌跡執行

檢視所有可用的服務列表

rosservice list
有很多服務,其中一些是模擬器系統 (/gazebo/…)提供的, 其他的是Kinect Camera (/camera/…) 和機器人本身(/iri_wam/…)提供的

獲取關於服務的資訊

rosservice info /name_of_your_service

user ~ $ rosservice info /execute_trajectory
Node: /iri_wam_reproduce_trajectory
URI: rosrpc://ip-172-31-17-169:35175
Type: iri_wam_reproduce_trajectory/ExecTraj
Args: file

各引數意義如下:

Node: 表示提供(或建立)該服務的**節點**。
Type: 指該服務使用的**訊息型別**。其結構與主題相同。通常由 package_where_the_service_message_is_defined / Name_of_the_File_where_Service_message_is_defined 構成。該例中,功能包是 iri_wam_reproduce_trajectory,定義服務訊息的檔名為 ExecTraj。
Args:  從這裡可以找到該服務被呼叫時所使用的引數。該例中,只有一個引數 trajectory file path ,該引數儲存在一個名為file 的變數中。

服務是如何開始的?
下面是一個通過WebShell檢視 start_demo.launch 檔案的例子

檢視launch檔案

你還記得如何直接進入一個功能包嗎?你還記得從哪裡可以找到launch檔案嗎?

roscd iri_wam_aff_demo
cd launch/
cat start_demo.launch
<launch>

  <include file="$(find iri_wam_reproduce_trajectory)/launch/start_service.launch"/>

  <node pkg ="iri_wam_aff_demo"
        type="iri_wam_aff_demo_node"
        name="iri_wam_aff_demo"
        output="screen">
  </node>

</launch>

1) 該launch檔案的第一部分呼叫另一個名為 start_service.launch 的launch檔案

start_service.launch檔案啟動提供/execute_trajectory 服務的節點。注意,它使用一個特殊的ROS launch檔案函式查詢指定功能包的路徑。

2) 該launch檔案的第二部分啟動一個你剛在ROS Basics Unit學習過的節點。該節點呼叫 /execute_trajectory 服務來使機器人移動。

3) 第二個節點不是一個Python節點,而是一個編譯過的cpp節點(二進位制)。你既可以用CPP也可以用Python來構建ROS程式。該課程主要使用Python。

<node pkg ="package_where_cpp_is"
      type="name_of_binary_after_compiling_cpp"
      name="name_of_the_node_initialised_in_cpp"
      output="screen">
</node>

服務例項(呼叫服務)

可以從控制檯手動呼叫一個服務。這有助於測試,還有助於理解服務是如何工作的

rosservice call /the_service_name TAB-TAB

TAB-TAB表示快速按 TAB 鍵兩次。它會自動完成將被髮送的服務訊息。接著,你只需把值填上即可

當你快速按下 [TAB]兩次後,出現一個額外的資訊。ROS自動補全輸入,補全請求該服務的結構。
本例中,它給出下面的結構:

“model_name: ‘the_name_of_the_object_you_want_to_delete’”

/gazebo/delete_model 是一個由Gazebo模擬器提供的服務, 檢測場景中的任何物件。

使用該服務來移除桌子。在該模擬中桌子的model_name是cafe_table

rosservice call /gazebo/delete_model “model_name: ‘cafe_table’

獲取場景中的物件列表

若想對模擬中的任何物件進行操作的話,你必須學會如何獲取場景中的物件列表

rostopic echo /gazebo/model_states -n1

程式與服務互動

#! /usr/bin/env python

import rospy
from gazebo_msgs.srv import DeleteModel, DeleteModelRequest # 匯入服務 /gazebo/delete_model使用的服務訊息
import sys 

rospy.init_node('service_client') # 初始化一個名為 service_client的ROS節點
rospy.wait_for_service('/gazebo/delete_model') # 等待服務客戶端 /gazebo/delete_model 執行
delete_model_service = rospy.ServiceProxy('/gazebo/delete_model', DeleteModel) # 建立與服務的連線
kk = DeleteModelRequest() # 建立一個型別為 DeleteModelRequest的物件
kk.model_name = "bowl_1" # 為該物件的model_name變數賦值
result = delete_model_service(kk) # 通過連線,傳送要被服務刪除的物件名稱
print result # 列印被呼叫的服務給出的結果

檢視服務使用的訊息結構

  • 使用 rosservice info 命令可以檢視服務所使用的訊息型別
    rosservice info /name_of_the_service
    返回 name_of_the_package/Name_of_Service_message

  • 檢視該服務使用訊息的結構
    rossrv show name_of_the_package/Name_of_Service_message

輸出

user catkin_ws $ rossrv show gazebo_msgs/DeleteModel
string model_name
---
bool success
string status_message
  • 服務訊息包括請求和響應
  • 對於DeleteModel 服務這個例子, 請求 包含了一個名為 model_name 的字串, 響應 則由一個名為 success 的布林值和一個名為 status_message 的字串組成。

  • 服務訊息中每部分元素的數量各不相同,具體數量取決於所需要的服務。如果你覺得它與你的服務不相關,你甚至可以把它設定成“無”。訊息中最重要的部分是三個破折號—, 它們表示該訊息的型別為服務訊息。

1 - 服務訊息副檔名為 .srv。主題訊息副檔名為 .msg
2 - 服務訊息檔案定義在一個 srv 目錄中。主題訊息檔案定義在一個 msg 目錄中。

檢視所有服務訊息

roscd gazebo_msgs; ls srv

  • 請求 是服務訊息中定義 如何呼叫服務 的那一部分。它給出了你必須向訊息伺服器傳送哪些變數才能使它開始任務。

  • 響應 是服務訊息中定義完成任務後 你的服務如何響應 的那一部分。例如,如果一切執行正常,它將返回一個帶有特定訊息的字串;如果執行錯誤,它將什麼都不返回

總結

  • 服務為其他程式提供特定功能。如果一個節點知道如何在模擬中刪除一個物件,那麼它可以通過一個服務為其他節點提供該功能,以便其他節點需要刪除物件時呼叫該服務

練習

待補
- 當你啟動一個同名的新節點時,有時它會結束前面的那個節點。好的做法是手動結束而不是依賴系統來結束舊的節點
- 使用Web控制檯編輯器vim檢視一下這些trajectory_files 中的一個,或者拷貝至我們的工作空間 /home/user/carkin_ws/src,你將會明白它們是如何工作的。 讓我們檢視一下get_food.txt檔案
- 服務execute_trajectory 將基於呼叫中給出的路徑讀取上面這些值(呼叫時指定軌跡檔案,從而讀取相應值)