1. 程式人生 > >ubuntu16.04下ROS作業系統學習(四 / 二)ROS基礎-ROS通訊程式設計

ubuntu16.04下ROS作業系統學習(四 / 二)ROS基礎-ROS通訊程式設計

1.話題程式設計

首先我們要有一個釋出話題的Talker,還要有一個訂閱話題的Listener,然後就是負責管理整個系統的ROS Master。

話題程式設計的流程主要是以下四個步驟:

  • 建立釋出者
  • 建立訂閱者
  • 新增編譯選項
  • 執行可執行程式

上面的前兩步是程式設計實現的,第三步是通過編譯的方式生成可執行檔案。最後一步就是去執行一下這個可執行的程式。

我們之前建立的功能包learning_communication裡面是沒有程式碼的:

然後在這個檔案下面建立一個talker.cpp檔案

裡面的程式碼解釋也非常清晰。通過控制代碼.advertise釋出訊息,裡面需要傳入釋出訊息的具體型別,以及佇列的長度。

程式碼的流程如下:

  • 初始化ROS節點
  • 向ROS Master註冊節點資訊,包括髮布的話題名和話題中的訊息型別。
  • 按照一定頻率迴圈釋出訊息。

有了釋出者之後,我們接下來需要去定義一個訂閱者,步驟如下:

  • 初始化ROS節點
  • 訂閱需要的話題
  • 迴圈等待話題訊息,接收到訊息後進入回撥函式。
  • 在回撥函式裡面完成訊息處理。

原始碼如下:

現在的話我們就已經寫好了c++檔案,我們需要對其進行編譯,如果我們使用的是python檔案的話,我們就不用對其進行編譯了。編譯程式碼主要有以下三個步驟:

  • 設定需要編譯的程式碼和生成的可執行檔案;
  • 設定連結庫;
  • 設定依賴。

在上面這個資料夾下面的CMakeLists.txt就是我們具體需要編譯的選項的。接下來我們需要在這個檔案下面設定我們需要編譯的選項。在這個檔案裡面很多都是被註釋掉了,我們很多時候去掉其中的註釋然後再改一點就可以了,並不需要我們自己寫。將程式碼生成可執行檔案就是需要使用add_executable這個配置。

這裡我們在下面再貼上一下:

這裡我們只需要看未被註釋的,第一行的意思就是將talker.cpp生成可執行檔案。如果需要更多的檔案來生成可執行檔案的話,需要在後面再多加幾個c++檔案。

因為我們需要依賴第三方的庫,所以我們需要新增target_link_libraries來與第三方的庫做一個連結。之後我們回到工作空間對其進行編譯。

編譯成功之後就會有以下提示:顯示達到1005並且沒有報錯的話就說明編譯成功了。

我們在下面這個檔案裡面就可以找到我們編譯生成的可執行檔案了。

之後我們啟動roscore

再執行傳送“hello world”可執行檔案:

再執行接收檔案的話,就可以看到下面的結果:

如果我們需要自己定義話題訊息的話,我們可以採取以下方式自定義話題訊息

string name

uint8 sex

unit8 age

unit8 unknown = 0

unit8 male = 1

unit8 female = 2

具體操作步驟如下:

  • 定義msg檔案
  • 在package.xml中新增功能包依賴

  <build_depend>message_generation</build_depend>

<exec_depend>message_runtime</exec_depend>

  • 在CMakeList.txt新增編譯選項

接下來具體操作一下:

首先建立一個資料夾,命名為msg檔案

在這個資料夾下面建立一個具體的Person.msg檔案

之後我們在package.xml檔案裡面去新增依賴。部分的ROS版本中的exec_depend需要改成run_depend。

之後的話我們需要在CMakeLists.txt檔案裡面新增編譯選項,在下面新增message_generation功能包。

然後新增編譯時候的依賴:

接下來新增是哪一個具體的msg檔案:

之後對其進行編譯:

我們可以在程式碼終端裡面驗證一下:

 

2.服務程式設計

listener通過請求的形式來完成跟talker的一個通訊,talker把處理完成之後的資料處理完成之後再發布給listener,整個服務程式設計流程可以大致分為以下四個步驟:

  • 建立伺服器
  • 建立客戶端
  • 新增編譯選項
  • 執行可執行程式

假設如下場景,listener釋出某兩個加數給talker,talker接收到這兩個加數之後將這兩個加數進行相加,並且把求和的結果告訴listener。具體步驟如下:

  • 定義srv檔案
  • 在package.xml中新增功能包依賴
  • 在CMakeLists.txt新增編譯選項

首先建立一個srv檔案:

然後在下面定義以下檔案:

中間的三條橫線將資料分成兩部分,上面的是服務的請求部分,下面的是服務的應答部分。

之後我們需要在pacaage.xml檔案中新增功能包依賴

<build_depend>message_generation</build_depend>

<exec_depend>message_runtime</exec_depend>

這個和之前的talker-listener是一樣的,因為我們剛才新增好了,這裡就不用去做任何修改:

之後修改CMakeLists.txt檔案,和之前的也差不多:

首先修改message_generation,和message_runtime。

之後再修改add_service_files:

之後進入工作空間下面,對其進行編譯:

我們接下來看一下怎麼實現一個服務端,實現伺服器的程式設計

我們在這個功能包下面的src資料夾下面建立一個server.cpp檔案:

一個伺服器的實現也需要分成四個步驟:

  • 初始化ROS節點;
  • 建立Server例項;
  • 迴圈等待服務請求,進入回撥函式;
  • 在回撥函式中完成服務功能的處理,並反饋應答資料。

其程式碼與之前的比較類似。再回調函式裡面,由於之前是將資料分成了兩個部分,所以這個也是做兩個部分,一個是request,一個是response。

之後我們還要建立一個客戶端

具體程式碼如下:

之後需要對其進行編譯:

  • 設定需要編譯的程式碼和生成的可執行檔案;
  • 設定連結庫;
  • 設定依賴;

add_executable(server src/server.cpp)

target_link_libraries(server ${catkin_LIBRARIES})

add_dependencies(server ${PROJECT_NAME}_gencpp)

add_executable(client src/client.cpp)

target_link_libraries(client ${catkin_LIBRARIES})

add_dependencies(client ${PROJECT_NAME}_gencpp)

設定完成之後,需要回到工作空間的根目錄下面對其進行編譯:

接下來我們執行編譯成功之後的可執行檔案:

首先我們roscore啟動master,之後啟動服務端,再啟動客戶端,傳入引數:

roscore
rosrun learning_communication server
rosrun learning_communication client 1 1

 

3.動作程式設計

動作也是話題服務的一種機制,但是跟話題服務又有一些區別。比如說我們想讓機器人前往一個目標點,並且讓機器人不斷地返回自己的實時狀態,甚至說在機器人運動過程當中,我們不想讓機器人前往這個目標點了,給他釋出他一個資訊,讓它停止下來。像這種需要維持一段時間,並且有反饋的這樣一種通訊是沒有辦法用話題或者服務來完成的。動作的實現也是通過ROS的訊息機制來實現的。

實現原理圖如下所示:

同樣也是分為服務端與客戶端,通過二者之間的通訊來實現。

Action的介面有:

  • goal:釋出任務目標。客戶端可以給服務端傳送一個動作的目標。
  • cancel:請求取消任務。在執行的過程當中,也可以將其取消。
  • status:通知客戶端當前的狀態。通知客戶端當前伺服器的狀態。
  • feedback:週期反饋任務執行的監控資料。週期性地反饋,告訴機器人當前伺服器的狀態。
  • result:向客戶端傳送任務的執行結果,只發布一次。當完成客戶端的命令之後會執行一次。

那麼我們如何來實現這樣一個具體的動作程式設計呢:

  • 定義action檔案
  • 在package.xml中新增功能包依賴

<build_depend>actionlib</build_depend>

<build_depend>actionlib_msgs</build_depend>

<exec_depend>actionlib</exec_depend>

<exec_depend>actionlib_msgs</exec_depend>

  • 在CMakeLists.txt中新增編譯選項

find_package(catkin REQUIRED actionlib_msgs actionlib)

add_action_files(DIRECTORY action FILES DoDishes.action)

generate_messages(DEPENDENCIES actionlib_msgs)

同樣,如果ROS中有自定義的工作訊息給我們的話我麼可以直接呼叫,如果沒有的話那我們就需要自己來定義這樣一個自定義的動作訊息。

我們現在來假設一個洗盤子這樣的任務,客戶端傳送一個洗盤子的命令給服務端,服務端接收到這個命令之後開始洗盤子,然後反饋給客戶端洗了多少了,客戶端也可以讓服務端終止洗盤子這個命令。盤子洗碗之後返回一個洗碗的訊號給客戶端。

如果我們想要建立一個動作訊息,我們需要在功能包裡面建立一個資料夾action。然後在action裡面建立具體的動作訊息。

這裡有兩個三橫槓,把這整個資料內容分成了三個部分。

第一部分是定義目標資料的,也就是客戶端傳送什麼樣的一個動作的目的給服務端。

第二部分定義的是結果的,也就是說我們整個動作執行完成之後到底是一個什麼樣的結果。

第三部分是一定週期內反饋給客戶端的資料內容。這裡的話就是反饋洗盤子的百分比。

定義完成之後需要在package.xml裡面去新增功能包的依賴。

package.xml改完之後要去改CMakeLists.txt檔案。

之後我們編譯一下工作空間,看看定義的這些action是否是正確的

編譯是沒有錯誤的,所以我們剛才的操作是沒有錯誤的。

我們現在來看一下如何實現一個動作的伺服器,主要是以下步驟:

  • 初始化ROS節點
  • 建立動作伺服器例項
  • 啟動伺服器,等待動作請求
  • 在回撥函式中完成動作服務功能的處理,並反饋進度資訊
  • 動作完成,傳送結束資訊。

我們從視訊資源中把原始碼拷貝過來:

我們首先看一下服務端程式碼:

在main函式裡面,程式流程大致都差不多。啟動伺服器之後伺服器就會一直迴圈等待命令。一旦接收到命令之後,伺服器就會進入到回撥函式裡面。回撥函式裡面就會開始具體的服務處理。

完成服務端之後我們需要去完成客戶端的功能:

  • 初始化ROS節點
  • 建立動作客戶端例項
  • 連線動作服務端
  • 傳送動作目標
  • 根據不同型別的服務端反饋處理回撥函式

程式碼完成之後就是來編譯這些程式碼:

add_executable(DoDishes_client src/DoDishes_client.cpp)

target_link_libraries( DoDishes_client ${catkin_LIBRARIES})

add_dependencies(DoDishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS})

add_executable(DoDishes_server src/DoDishes_server.cpp)

target_link_libraries( DoDishes_server ${catkin_LIBRARIES})

add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})

之後進入工作空間目錄下對其進行編譯

我們接下來對其進行驗證測試:

roscore
rosrun learning_communication DoDishes_client
rosrun learning_communication DoDishes_client