如何使用節點

繼前一篇 ROS Node 節點概念與意義 之後,我們聊解了結點的概念,那要如何使用呢?

如何啟動節點?

在啟動節點之前,請先啟動管理器,也就是 master,在終端機打:

$ roscore

啟動 Master 後,再來才能啟動所有節點。

$ rosrun [程式包名稱] [節點名稱]

例如;

$ rosrun turtlebotsim turtlebotsim_node

附帶一提,當使用 roslaunch 批次啟動節點時,由於 roslaunch 會自動啟動 master,所以便不必在啟動之前輸入 roscore。

rosrun 本身的設計是可以讓使用者直接修改節點內的參數,就只需用引數的方式加在節點後面。例如:

$ rospy_tutorials talker _param:=1.0

就像結尾那個 _para:=1.0 一樣,注意,給值是用":=",而不是"="或"=="。

參數伺服器(Parameter Server)

為了瞭解節點後面的參數是怎麼一回事,我們可以先簡介一下參數伺服器(更深入的探討可以參考這裡)。參數伺服器是一個儲存所有參數的字典大倉庫,其中的參數值可以在執行時間以 ROS 的 API 直接存取。當我們在節點內定義參數時,其中的參數以及包含的資料,就會被記錄在參數伺服器內。

其他特殊字元

像剛才的 _param,其實這些參數是我們在寫節點程序的時候,自己定義的,所以只要知道節點裡面有涉及哪些參數,便可以直接在諸端機後面直接當場指定,只是這只是暫時的,下次啟動節點,一樣會使用預設值。還有,以下的名稱為系統內定,我們在指定參數時,不可以使用。

__name

這個特殊保留字元讓使用者可以重新位節點取名。必須要啟動至少一個節點的情況下,才能使用。

__log

這個特殊字元讓使用者可以指定錯誤訊息(log)的謝入位置,一般不建議使用,因為錯誤訊息通常是給其他工具參照的。

__ip, __hostname

這兩者代表著系統參數 ROS_IP 和 ROS_HOSTNAME一般不建議使用,除非在系統無法設定系統參數的特殊狀況下。

__master

這個特殊字元代表 ROS_MASTER_URI一般不建議使用,除非無法設定系統參數。

__ns

這個特殊字元代表  ROS_NAMESPACE一般不建議使用,除非無法設定系統參數。

將引數 Remap

結尾的引述,也可以用來 Remap。其實這個功能是真的很實用。語法就是 name:= target_name 。例如今天我們要改變雷射測距儀發佈出來的話題名稱,我們可以像這樣做:

$ rosrun hokuyo_node hokuyo_node /scan:=/new_scan

這樣,就可以把原先的話題 /scan 改成 /new_scan 了。

其他好用的工具

rosnode

rosnode 是一個指令工具,用來顯示所有節點的資料,例如顯示目前執行中的所有節點。其支援的指令包括:

rosnode info [節點]

顯示節點的詳細資料。

rosnode kill [節點]

將一個節點強制關閉。

rosnode list

條列所有執行中的節點。

rosnode machine [hostname]

將某機台上的所有執行中的節點條列出來。

rosnode ping [節點]

測試節點連線。有點像終端機測試電腦連線的 ping 指令。

rosnode cleanup

將殭屍節點的註冊資訊清除。

注意:這只是暫時性的解法,一般操作時不建議使用。這個功能可能會誤砍正在執行中的節點。

rqt

rqt 是一個方便開發上除錯、執行時監控、動態調整參數等等功能的,基於 Qt寫成的 GUI 工具,有點像是電機工程師相當仰賴的示波器和三用電表。詳細的參考資料可以參考 rqt – ROS Wiki

ros_gui.png

rqt_graph

rqt_graph 是 rqt 中的 GUI 插件,用來直接觀看各節點的運作狀態。更詳細的資料可以參考 rqt_graph – ROS Wiki

snap_rqt_graph_moveit_demo

rqt_reconfigure

rqt_reconfigure 接替了 dynamic_reconfigure (reconfigure_gui),提供可以及時動態監控與調整dynamic_reconfigure 所能偵測到的參數的功能。詳細資料可以參考 rqt_reconfigure – ROS Wiki

使用的方法如下:

$ rosrun rqt_reconfigure rqt_reconfigure

reconfigure_gui3

Launch 檔中啟動節點的方法

啟動節點相當簡單,在 launch 檔中,使用 <node>標籤即可。roslaunch 無法確保節點是否會按照使用者寫的順序依依開啟,不過就筆者經驗,launch 會逐步將各節點啟動,所以有些需要時間啟動的節點,個人的經驗,是將其寫在 launch 檔的後面。在某些情況下,由於某類節點會需要接收到輸入,或需要花較久時間啟動,為了因應這種狀況,也會將這類節點放在後面啟動。啟動節點的語法如下

<node pkg="foo" type="foo" name="foo" [屬性1] [屬性2] … [屬性n] />

上面<node>標籤裡面可以加上其他屬性。屬性有以下:

pkg=””

 

程式包名稱

type=””

 

節點類型,必須對應到一個存在,有相同名稱的節點

name=””

 

節點名稱,跟 __name相似,但只要這個launch檔啟動,這個節點就會被這個使用者自訂的名稱稱之。注意,不要包含命名空間,若要加上命名空間,請使用
ns 屬性。

args=”arg1 arg2 arg3”

非必要

輸入節點所需的引數。通常會常使用在
nodelet
的啟動上。

machine=””

非必要

指定啟動某一機台上的節點,請參考
<machine>
,使用方法可以參考這篇

respawn=”true”

非必要

當節點關閉時,自動再啟動它。

respawn_delay=”30” (預設為0)

非必要

如果 respawn=true,系統會等待指定秒數,才會讓關閉的節點再度啟動。

required=”true”

非必要

如果節點關閉,則關閉整個  launch 檔。

ns=””

非必要

指定節點的命名空間。

clear_params=”true|false”

非必要

在啟動之前,刪除節點私有空間中的所有參數

output=”log|screen”

非必要

如果選擇 screen,來自節點的stdout/stderr(輸出資訊/錯誤訊息)會顯示於終端機上,若為 log,則除了會被寫入 $ROS_HOME/log 內,也會顯示於終端機上。預設是 log

cwd=”ROS_HOME|node”

非必要

若引數值為 node,節點的工作路徑會被設為節點實際執行檔所在的路徑上。在
C-Turtle版本之後,預設值皆為ROS_HOME

Launch-prefix=”prefix arguments”

非必要

這個指令會將結點在 gdbvalgrind
xterm
nice等工具來在執行時間內除錯。更詳細的使用方法,請參考
Roslaunch Nodes in Valgrind or GDB

在<node>標籤中,你可以加上元素搭配使用。實例中會將命令指令與 launch 檔裡的語法做對應。元素的語法如下:

<node pkg=”” type=”” name=””>
    <element1/>

    <element2/>

     ….

    <element n />

</node>

可以用的元素如以下:

<env>

為節點設定環境變數。只有在這個元素後宣告的節點會起作用。

<remap>

為節點 remap 其引數。

<rosparam>

rosparam  檔載入該節點的 ~/local  命名框間中。簡言之,就是載入系統參數進節點中。

<param>

將參數載入節點的 ~/local 命名框間中。簡言之,就是將參數載入到節點內。

所以,如果終端機指令為:

$ rosrun my_pkg my_node __ns:=myns __name:=/new_node __param:=1.0 /old_topic:=/new_topic

對應到 launch 檔,則可以寫成:

 <node pkg="my_pkg" type="my_node" name="new_node" ns="myms" output="screen">

      <param name="param" value="1.0″ />

      <remap from="old_topic" to="new_topic" />

</node>

由於 launch 檔內直接載明了所有參數的設定值,所以在常使用某節點做測試,或執行的情況下,比每次都要打指令來得較為實際。

以上就是 ROS 中節點的使用方式。接下來,我們要探討如何撰寫節點。

ROS Node 節點的概念與意義

如果要理解節點的意義,需要從 ROS 的網狀架構說起。為什麼 ROS 是網狀架構呢?因為最初需要一整個軟體架構,來解決「抓取東西」的問題。這裡面就涉及如何擷取雷射掃描的資訊、馬達的控制、手臂每個環節的定位等等,如果每一個功能都由一個程序負擔,則會構成一個類似圖一的網狀行結構。

%e6%93%b7%e5%8f%96%e9%81%b8%e5%8f%96%e5%8d%80%e5%9f%9f_023
圖一  抓取東西的整個軟體架構

其實這樣的架構並非 ROS 首創,如果您學過網路架構相關知識,可以看得出來這樣的網路其實就是 Real-Time Publisher-Subscriber Protocol (RTPS),這個網狀圖或 Graph中,每個程序就是一個節點(Node),它們之間傳遞的訊息,就由邊(Edge)連起來。其中的節點為 POSIX 程序,邊則以 TCP連接。這樣的聯繫架構實作了平行運算,將功能與原始碼獨立開來,讓系統便得更簡潔,且有更大的容錯度。一個節點出問題掛了,只會自己關閉而不會連累到其他程序,錯誤的訊息會被寫進 logger 當中,供之後除錯時參考(圖二)。但其實更重要的特點,是可以極少依賴或根本不需要黏膠代碼(Software Glue)來組建一個複雜的系統,換個角度想,可以將不同語言寫成的節點串連起來構建出一個完整的系統。

b
圖二  節點之間除了溝通,也與 logger 連接,一單發生錯誤,錯誤訊息便會寫進 logger 裡。

所以,我們可以利用這樣彈性的網路,在執行時,將一個子網路接上另外一個子網路,或者即時將一個子網路替換成另外一個。這就是為什麼我們可以將真實機器人上使用的程式全套搬到模擬器上模擬,或者當場替換一個手臂抓取的功能等等。

那我們又要怎麼確定將不同節點,甚至不同機台上的節點接起來的時候,彼此可以找得到彼此呢?這就必須要藉由 roscore 來紀錄大家的存在,讓所有節點都可以看得見彼此。

a
圖三  節點管理器負責註冊所有節點,讓彼此能溝通。

想看一下實際的狀況嗎?我曾經開發一個用 RGB-D 相機辨識人體,並將辨識到的人過濾到的專案,發揮的功能,有點像是一個隱形斗篷的概念,就稱這個專案為「影行斗篷專案」吧!所有的節點串起來,就像圖五那樣。

figure001
圖四  節點分成兩種:發布者(Publisher)和訂閱者(Subscriber),連接節點的邊則為訊息,訊息會張貼在話題這個容器中,讓不同的訂閱者取用。

架構講完了,概括一下。ROS中有幾個基本的元素:

  • 節點(Node):一個節點極為一個執行序,收進來訊息,也傳出訊息,用這種方式,節點跟節點之間便可以溝通。節點也可以提供或使用某種服務。
  • 消息(Message):消息是一種 ROS 數據類型,用於訂閱或發布到一個話題。ROS 有預設的樣板,使用者也可以自訂樣板。
  • 話題(Topic):節點可以發布消息到話題,也可以訂閱話題以接收消息。
  • 節點管理器(Master):ROS 名稱服務
  • rosout:ROS中相當於 stdout/stderr。
  • roscore:主機+rosout+參數服務器 (parameter server)

 

目前 ROS 支援的語言,或者筆者看過的有以下幾種:

  • roscpp,也就是用 C++撰寫。
  • rospy,使用 Python 撰寫。
  • rosjava,使用 JAVA 撰寫,對應連接 Android 等智慧裝置開發的需求。
  • ROS support from Robotics Sytem Toolbox ,將 MATLAB 結合 ROS 的方案。安裝方式請參考這裡
  • RobotOS.jl,對於使用日漸廣泛的 Julia 語言,也提供了介面

 

 

10708648_10153865053736842_1265985979016866474_o
圖五  啟動「隱形斗篷專案」中所有節點後的網狀圖,其中一行一行毛毛蟲,就是整個系統的中一個一個節點。

我們會在之後的篇章中,討論如何使用節點,以及更重要的,如何撰寫節點。

 

 

 

 

 

讓機器人平滑移動以及增加應用彈性的方法

有沒有一個經驗,為什麼我做的機器人移動上永遠無法像 PR2 或者吸塵器機器人一樣平滑?為什麼我的機器人每次移動都好像一瞬間花了洪荒之力,而機身就是被不情願的往前脫去,這樣久了不只對馬達是種損害,對電力系統也宣判了慢性癌症,總有一天會讓電力系統中某個元件壞掉(如果你的電力系統跟我設計的一樣永遠都不完美)。

 

因此,我們需要為自己的導航系統加點控制系統,讓機器人移動上不會這麼魯莽。我們使用 Yujin robot (他們的 GitHub) 開發的 kobuki_safety_controllerkobuki_velocity_smoother 。其實這兩個 packages 是包在yujin_yocs 這個 stack 中。詳細的官方資訊可以參考這裡。有一點稍微提下,就是這些 Packages 裡面裝的,並不是節點,而是 nodelets (不知道怎麼翻XDD)。但這之後我們會再聊到,本篇先從略。我們來看一下整個驅動控制架構:

si_Ih7qGws9qsRJwX5xTb_g
圖一:Kobuki 整體控制架構

Source: kobukiTutorialsKobuki’s Control System

 

 

 

由圖一中可以觀察到,Kobuki 這台吸塵器機器人(加上上面的架子後就進化成 Turtlebot了,看倌可以花三萬塊台幣去收服它!)所採用的,就是這一套馬達驅動控制架構。yocs_safety_controller 其實由三個程式組成:kobuki_node 、cmd_vel_mux、kobuki:_safety_controller。其中,kobuki_node 其實就是 kobuki 吸塵器機器人的控制驅動節點。cmd_vel_mux 是一種多進單出的速度切換器。kobuki_safety_controller 則是檢查機器人是否碰撞到障礙物、輪子脫落、有沒有跑到懸崖上的檢查機制。

 

啟動速度切換器!

 

所以,我們可以利用這三個節點中的 cmd_vel_mux 來作切換器,這個節點確認就算有不同的速度指令同時要操控這台機器人,只有一種速度指令會傳送給馬達。它有10個 /cmd_vel 的接口,可以接上十種速度指令,並指定每個速度指令的優先性先後順序,由最優先的10到最後一位的第0位。預設是讓 ROS Nav stack 的優先性設在最後一位,第零位,而讓 safety controller 輸出的速度指令設在第十位,使用者遙控輸出的指令排在前述兩者之間。這樣子,多進單出的 cmd_vel_mux 切換器就完善了。另外,這個切換器還會輸出一個總輸出速度 /cmd_vre_mux/output 作為閉路回饋控制迴圈的輸入依據。

這樣講有點抽象,讓我舉個例子:

優先性:

10 . (highest priority) safety controller

  1.   keyboard teleop
  2.   joystick teleop
  3.   android teleop
  4.  (Lowest priority) nav cmd vel

 

以這個方式,我們一次接上了5個速度指令,而一次只有一個總輸出給馬達控制器。但在輸出到馬達之前,我們要在加上一個控制器。

 

那要如何實做呢?既然我們都有節點了,那麼現在要擔心的,是怎麼用 Launch file 來開啟每個節點以及輸出的 topics。其實不只是要學會用 launch,具體的速度指令優先順序,必須另外寫個社檔宣告,然後匯入到 launch 檔。範例如下:

 

<launch>
 <arg name="nodelet_manager_name" default="nodelet_manager" />
 <!–Velocity Smoother’s settings–>  <arg name="smoother_node_name"    default="velocity_smoother" />

 <arg name="config_file"           default="$(find mybot_bringup)/launch/velocity_smoother_param.yaml"/>

 <arg name="raw_cmd_vel_topic"     default="cmd_vel_mux/output"/>                <!–subscribed topic –>

 <arg name="smooth_cmd_vel_topic"  default="/smooth_vel"/>                          <!–publish topic–>

 <arg name="robot_cmd_vel_topic"   default="cmd_vel_mux/output"/>               <!–subscribed topic–>

 <arg name="odom_topic"            default="odom"/>                                             <!–subscribed topic–>
 <!– ****** Nodelet manager ******** –>

 <node pkg="nodelet" type="nodelet" name="$(arg nodelet_manager_name)" args="manager" />
 <!– ***** cmd_vel_mux ************* –>

 <node pkg="nodelet" type="nodelet" name="cmd_vel_mux" args="load yocs_cmd_vel_mux/CmdVelMuxNodelet $(arg nodelet_manager_name)">

    <param name="yaml_cfg_file" value="$(find mybot_bringup)/launch/cmd_vel_mux_minimal_with_safety.yaml" />

 </node>

  <!– ****Velocity Smoother (just regulate the overall output from cmd_vel_mux) ***** –>

 <node pkg="nodelet" type="nodelet" name="$(arg smoother_node_name)"

       args="load yocs_velocity_smoother/VelocitySmootherNodelet $(arg nodelet_manager_name)">

   <!– parameters –>

   <rosparam file="$(arg config_file)" command="load"/>
   <!– velocity commands I/O –>

   <remap from="$(arg smoother_node_name)/raw_cmd_vel"        to="$(arg raw_cmd_vel_topic)"/>

   <remap from="$(arg smoother_node_name)/smooth_cmd_vel"  to="$(arg smooth_cmd_vel_topic)"/>
   <!– Robot velocity feedbacks –>

   <remap from="$(arg smoother_node_name)/robot_cmd_vel"  to="$(arg robot_cmd_vel_topic)"/>

   <remap from="$(arg smoother_node_name)/odometry"          to="$(arg odom_topic)"/>

 </node>

</launch>

 

接著我們來看一下設定檔,範例如下,:

 

cmd_vel_mux_with_safety_priority.yaml

subscribers:

 – name:        “Default input"

   topic:       “def_cmd_vel"

   timeout:     0.1

   priority:    0

   short_desc:  “Default velocity topic; controllers unaware that we are multiplexing cmd_vel will come here"
 – name:        “Navigation stack"

   topic:       “nav_cmd_vel"

   timeout:     0.5

   priority:    1

   short_desc:  “ROS navigation stack controller"
 – name:        “Safety Controller"

   topic:       “cmd_vel_safety"

   timeout:     0.2

   priority:    10

   short_desc:  “Kobuki’s safety controller"
 – name:        “Keyboard operation"

   topic:       “key_cmd_vel"

   timeout:     0.1

   priority:    9
 – name:        “Remote control"

   topic:       “rem_cmd_vel"

   timeout:     0.1

   priority:    8
 – name:        “Onboard joystick"

   topic:       “joy_cmd_vel"

   timeout:     0.1

   priority:    7
 – name:        “Web application"

   topic:       “web_cmd_vel"

   timeout:     0.3

   priority:    6

 

平滑輸出速率!

 

儘管 ros_control 架構下的控制程式本身就有速度平滑化的特點。但萬一我們使用的平台並非遵守這個架構,或者只想雙倍確認速度控制不會出錯,那麼我們可以使用 Yujin Robot 「出品」的 yocs_velocity_smoother 。方法很簡單,把 cmd_vel_mux 輸出的速度指令直接接到 yocs_velocity_smoother 的入口,這樣子,以目前 Yujin 給的 PID 參數,應該就可以應付您的機器人控制了。

 

從官網的ROS Wiki網頁上可以看得出來,Velocity Smoother Nodelet 的輸入與輸出:

輸入:

~raw_cmd_vel (geometry_msgs/Twist)

~odometry (nav_msgs/Odometry)

~robot_cmd_vel (geometry_msgs/Twist)

 

其中,如果沒有額外付上其他閉路控制設計,那麼 raw_cmd_vel 的輸入 topic 可以和輸入 robot_cmd_vel 的一樣。

 

輸出:

~smooth_cmd_vel (geometry_msgs/Twist):即平滑化後的速度指令,直接給 base_controller 節點。

此外,對於網頁上提及的參數,也可以另外寫成一個設定檔,由 launch 載入,讓其自動存進 parameter server 裡面。範例如下:

 

# Example configuration:

# – velocity limits are around a 10% above the physical limits

# – acceleration limits are just low enough to avoid jerking
# Mandatory parameters

speed_lim_v: 0.8

speed_lim_w: 5.4
accel_lim_v: 0.3

accel_lim_w: 3.5
# Optional parameters

frequency: 20.0

decel_factor: 1.0
# Robot velocity feedback type:

#  0 – none

#  1 – odometry

#  2 – end robot commands

robot_feedback: 2

 

在 launch 檔載入的方式其實已經出現在上述的範例裡面,我們節錄出來:

 

  <!– ****Velocity Smoother (just regulate the overall output from cmd_vel_mux) ***** –>

 <node pkg="nodelet" type="nodelet" name="$(arg smoother_node_name)"

       args="load yocs_velocity_smoother/VelocitySmootherNodelet $(arg nodelet_manager_name)">

   <!– parameters –>

   <rosparam file="$(arg config_file)" command="load"/>

 </node>

 

好了,如果把所有的節點搞定,輸出與輸入或對接的 Topics 都有接對(我還真的自己拿筆出來畫圖!),那麼,現在就可以打開你的機器人,遠端遙控一下!光是只給一個 Twist 都可以發現機器人的移動行為變了!這就表示,你成功了!

 

如何讓一台機台中的 Launch 檔也能啟動其他機台中的節點?

distributed-computing
之前看了林信男的這篇如何用一個 launch 檔啟動期胎台機器人上的節點(程式),看得我也心癢癢的,想說這樣的功能,真是 ROS 界的福音啊!趁著研究告一段落,比較有空的時候,也來試試。以下就是我的使用心得!
在開始之前,請先確定你已經完成了 DSA 無密碼遠端連線的設定,請參考這裡。如果還沒設定或還沒閱讀過,請連過去看。對!就是現在!我在這邊等著(啜飲焦糖瑪奇朵中)。
OK了嗎?好,確定一下你的 ~/.bashrc 裡面已經設定好 ROS Master 地址、你自己的 workspace 位置。都設定好了嗎?那我們繼續。
Launch 檔中有幾款標籤可以自由使用,請參考 這篇官方Launch/XML machine 標籤的用法教學 。雖然裡面有提供 password 選項,但既然我們能不須密碼遠端登入,那洩漏密碼這件事遍布成問題了。
ROS 的 Launch 檔裡,允許使用者針對各機台上的節點做啟動,但不可以遠端啟動另外一個 Launch 檔。此外,當初的設計應該是讓 Master 端用這樣的「至尊 Launch 檔」呼風喚雨,所以如果你是在非 master 的機台上呼叫這樣的 Launch 檔,你只會開啟這台基台上的節點而已。這是使用尚要注意的地方。在撰寫這類至尊 Launch 檔的語法上,我們需要用 <machine>標籤先宣告各機台,然後啟動各節點時,用 <node>裡面的 machine="" 來指定機台。
以下是一個範例檔。有很多標籤,既然是 Optional ,我就不使用了:
 ———————————————————————-
<launch>
<!–
This launch file activates both the robot and client side launches
going across all machines. Before using, please verify that all machines
are connected under the same network.
Make sure to set up DSA or password-less login to avoid compromising
your own password. Better if you can set DSA on all computers.
CAUTION: ONLY LAUNCH THIS FILE AT THE MASTER side, otherwise it won’t work.
–>
<arg name="client_ip" default="charly-MSI.local" />
<arg name="client_name" default="charly" />
  <!–The robot–>
  <machine name="myRobot"
  address="myRobot.local"
  user="bot" />
  <!–The client–>
  <machine name="client_pc"
  address="$(arg client_ip)"
  user="$(arg client_name)" />
  <!–機器人端開啟雷射測距儀–>
  <node machine="myRobot" pkg="hokuyo_node" type="hokuyo_node" name="hokuyo_node">
      <param name="frame_id" type="string" value="hokuyo_link" />
  </node>
  <!–客戶端開啟 Rviz–>
  <node machine="client_pc" name="rviz" pkg="rviz" type="rviz" args="-d $(arg rvizconfig)" required="true" />

</launch>

——————————————————————

自己使用的心得

雖然期盼已久的遠端單 launch file 開啟節點的夢終於實現了,但是我也碰到另外兩個問題,

問題一

所有的文件都解釋了如何啟動遠端節點的實作方法,但是竟然沒有超出四篇在談論如何遠端啟動對方的 launch 檔,亦言之,無法用 machine 標籤將別台機器的 launch 檔包進來。對我而言,目前我手上的專案根本無法一個節點一個節點置入 machine 標籤,因為一個專案就包括了數十個節點,改完手會斷。因次,我個人的使用經驗是挫折的,目前好像尚未能找到這樣的實作方法,看起來又必須重新回覆到之前遠端到各機台並個別啟動該機的 launch file 模式了,否則根本無法順利運作。

問題二

若你在非 master 節點所在的機台上啟動這個可控遠端的 launch 檔,你會遭遇到一則錯誤的訊息,就是 ROS 找不到 master, 所以無法啟動節點,laumch 就此關閉。這就表示,你只能在 master 的機台端啟動該 laumch 檔。
如果你的 master 剛好就在你現在所使用的電腦上,那就沒問題了,但如果你跟我一樣,master 放在機器人端,那麼你依舊每次還要遠端過去,然後才執行該 launch 檔,用久了自己都會嫌麻煩。那你可能會問,那為什麼不乾脆直接把 master 設在自己的電腦上就好?Well, 這世界上永遠都有特例,例如,當你所使用的機器人是公用的,隨時都會有好幾個人一起連到機器人的電腦上。除非今天你是老闆,否則應該沒有人敢一直請你開電腦,然後才遠端到你的電腦上,只為了啟動他的程式吧?
所以,主要的問題是 master 節點,這也可能是為什麼 ROS 2.0 可以改進的,就是去除必須啟動 master 節點才能做事的奇怪要求。

對於 Navigation Stack 的基本了解

呼!從何談起?

Navigation Stack 在 ROS 整個架構中佔相當重要的份量,但是截至目前為止,我個人認為網路上能找到的資料雜亂不堪,官方教學有些部分並沒有寫得太清楚,對於剛要入門的新手而言,反而會起更大的心理壓力,不知從何學起。那我就以我自己的理解盡量寫,希望能幫助各位了解 Navigation Stack,並附上學理部分的講解,希望可以讓大家更加熟悉其徵的道理。

楔子

關於Navigation Stack 的介紹,我建議先看過我的良師益友賴柏任的部落格,他整理得很清楚。此外,如果要以更實際的方向來看,可以參考這位網友的文章。而對我而言,Navigation Stack 是一整組可以讓機器人或自動化載具可以在空間中全穩定的移動的相關程式。這些程式可以大致上分為:

  • 感測器、馬達編碼器、各種感測器的輸入輸出
  • 世界、機器人各關節之座標轉換
  • 即時建圖與定位
  • 分層導航(路徑規劃)
  • 上層傳動機制

別緊張,我們下面會娓娓道來。

overview_tf_small

相信大家對上面這張圖並不陌生。這一大組程式大致上就符合上面五個種類。

感測器、馬達編碼器、各種感測器的輸入輸出

這包括:odometry source, sensor sources

每個感測器都有一個驅動程式負責擷取底層的資料,並轉換成 ROS 格式的 messages,例如在途中可以看到的 senosr_msgs/LaserScan, sensor_msgs/PointCloud, nav_msgs/Odometry。ROS 的特有應用就是,其他節點可以收到這些資料,並做後續的處理。

世界、機器人各關節之座標的轉換

這包括:sensors transform

這跟機器人的定位有著密切的關係。可以參考這邊。機器人內部個關節的定義通常寫在 URDF 內,由最中心的關節 base_link 連接到其他元件,有其相對的位置與幾何關係。此外,馬達的傳動也會關係到 odom 相對於虛擬位於機器人正中心的座標 base_footprint的關係,最後,odometry 座標到 map 座標之間的關係,則會由 SLAM 的節點提供。

目前可能看得一頭霧水,沒關係,我們只要知道,必須有程式隨時關心各元件相對於世界的位置關係。

即時建圖與定位

這包括:amcl, map_server, gmapping

讓機器人能自動定位自己在空間中的位置,對於對於環境的感知,以及規劃到達目的地的路徑都相當重要。大家耳熟能詳的 Simultaneous Localization and Mapping (SLAM)演算法實際上可以直接使用 ROS 中的 gmapping 包寡達成,而裡面的定位,仍然是使用 AMCL實作的 Adaptive Monte Carlo Localization 定位演算法,依照編碼器推斷出 odometry 給出自己相對於周遭空間的關係。

分層導航(路徑規劃)

這包括:global planner, local planner, global costmap, local costmap, recovery_behaviour

ROS 架構採取分層導航的方式,使得機器人的導航更安全。系統一方面會用較低更新率的全域路徑規劃演算法計算出從現在位置到終點位置的路徑,另一方面,會使用更高頻的節點做路徑規劃。move_base 建立在 nav_core 基礎上,把這幾個程式,或節點,包起來,讓使用者只需呼叫一個節點,就可以包辦全部。其中運作的機制,其實就是上圖的架構。此外,move_base 把所得到的地圖轉換成象棋盤一樣,一格一格的 grid map,上面用數值標定障礙物與可通行空間的數值(如果障礙物的數值為1、可通行的空間為0,則整份地圖就成為二元地圖 binary map)(更多學理可以參考這裡)這樣的地圖被稱之為 Occupancy Map,這種格式尚無法拿來做導航,所以會再轉成 cost map 的格式,方能實行路經規劃。

當地圖有了,Global Planer 便根據這張 costmap、座標關係、位置座標作為依據,在有限的時間內規劃出安全的路徑。路徑規劃的演算法則從上個世紀60年代以來第一次提出路徑規劃演算法,便不斷精益求精,隨著經驗的積累,更貼近真實應用的能力。但是通常這樣的路徑規劃並沒有顧及實際機器模型在空間中要怎麼移動,這即是所謂的"The piano moving problem"。想像你搬家時,好幾個搬運工辛苦的將你家的平台式鋼琴左僑右僑避開你家的家具搬到電梯口。在機器人導航中,這牽涉到機器人動力運動學(kinodynamics)。由於這攸關於瞬息萬變在空間中移動,所以區域規劃計算的更新率必須比全域規劃頻率還要高,譬如說全域頻率為 20 Hz,但區域頻率就必須提高到 50 Hz甚至更高。

從官方的文件中可以得知,move_base 的 global planner 預設使用 Dijstra 演算法。大家可能會問,欸?那 A* 呢?可能 Willow Garrage 真的太忙了,所以直到 2013年,David Lu! 才把後者寫成一個 Global Planner Plug-in,方才能供大家使用。

抱歉,八卦說的有點多,請先別擔心。

上層傳動機制

這包括:base_control

當區域規劃已經算出一條區域路徑後,便會輸出一個虛擬層的速度 /cmd_vel (原來的名稱:command velocity)。這個速度再透過 base_control轉成真正對每顆馬達輸出訊號,使馬達轉動,讓機體到達目的地。這不只是輪型機器人而已,也可能是機器手臂上每顆馬達的轉動速度。

 

所以…move_base怎麼用?

一般來說,要用的時候必須要啟動建圖、座標轉換、sensor_transform, sensor_source, move_base 等節點節點。如果要使用不同的規劃演算法,可以把演算法寫成 plug-in 加進 move_base 中啟動,這部分之後會再解說。整體怎麼啟動,也會用實際範例解說。

 

安裝 Gazebo

如果你決定要馬上模擬自己的機器人,那就趕緊來安裝 Gazebo 吧!其實
Gazebo
是一個跨平台的獨立軟體,所以你可以選擇安裝在自己慣用得平台上。但由於我們要讓 ROS
能連得上 Gazebo 做各種模擬,所以這篇只講解在
Linux
上安裝的過程。更多詳細的安裝流程可以參考 Gazebo 官方安裝教學。

內容一覽

  1. 確認應該安裝哪一版本的 Gazebo
  2. 在 Linux 上安裝 Gazebo
    1. 一行安裝
    2. 一步步安裝
  3. 安裝 gazebo_ros_pkgs
    1. 第一種:Debian 安裝
    2. 第二種:自己編譯安裝
  4. 測試整合了ROS的Gazebo
    1. Rosrun啟動Gazebo
    2. Roslaunch啟動Gazebo
    3. 用rostopic 檢查Gazebo
    4. 用rosservice確認Gazebo

1. 確認應該安裝哪一版本的 Gazebo

在安裝之前,請先確認哪一個版本才能支援自己目前使用的 ROS 版本。ROS
只支援稍微舊一點的版本,但儘管說舊一點的版本,其實對機器人模擬上,也已經夠用了。請查看 這裡
來了解自己應該安裝哪一版本的 Gazebo
例如說,我正在使用 ROS Indigo,則需要安裝的 Gazebo 版本是 2.x 開頭。 

2. 在 Linux 上安裝 Gazebo

筆者所使用的環境為 Linux Ubuntu Precise 14.04。先將獨立的
Gazebo
安裝起來,在安裝 gazebo_ros,將
ROS
Gazebo 連結起來。

2.1 一行安裝

1. 打開你的終端機,依照你目前使用的 ROS 版本,安裝支援的 Gazebo 版本(請參考這篇的Installing Gazebo 小節)。例如如果是 ROS Indigo 的話,所能支援的 Gazebo 就是2.x 版本,請輸入:

$ sudo apt-get install gazebo2

這樣應該就安裝起來了,可以直接在終端機上開分頁,執行看看:

$ gazebo

你也可以

2.2 一步步安裝

1. 首先讓你的電腦接受來自  packages.osrfoundation.org. 的下載:

$ sudo sh -c ‘echo “deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list’

2. 加上金鑰:

$ wget http://packages.osrfoundation.org/gazebo.key -O – | sudo apt-key add –

3. 執行以下安裝:

$ sudo apt-get update

$ sudo apt-get install gazebo[你適用的版本,例如說 2]

# 如果之後要開發自己的插件(plugin)的話,請再多安裝一個包裹

$ sudo apt-get install libgazebo[你適用的版本]-dev

4. 檢查有沒有安裝起來:

$ gazebo

檢查你有沒有安裝正確版本的 Gazebo,查看有沒有將 Gazebo 安裝到正確的路徑下:

$ which gzserver

$ which gzclient

如果安裝正確,第一行輸入進去,會回覆:

/usr/local/bin/gzserver

/usr/local/bin/gzclient

第二行則會回覆:

/usr/bin/gzserver>/usr/bin/gzclient

3. 安裝 gazebo_ros_pkgs

3.1 第一種:Debian 安裝

ROS Hydro 後,Gazebo_ros 有很大的變動,可能是為了實際使用上,不要讓獨立的
gazebo
ROS 版本的Gazebo 名稱上發生混淆。從Hydro 後的 debian 安裝方法,若你使用:

ROS Hydro

$ sudo apt-get install ros-hydro-gazebo-ros-pkgs ros-hydro-gazebo-ros-control

ROS Indigo

$ sudo apt-get install ros-indigo-gazebo-ros-pkgs ros-indigo-gazebo-ros-control

ROS Jade

目前2015Jade 並沒有釋出 gazebo-ros-control  封包。詳情請關注https://github.com/ros-controls/ros_control/issues/201

$ sudo apt-get install ros-jade-gazebo-ros-pkgs

3.2 第二種:自己編譯安裝

首先,確認你已經安裝了ROS,架設好 Workspace,並在~/.bashrc 中 source
這個工作空間的路徑。大致上catkin_worspace 的安裝,可以參考這裡。
接著,我們要來克隆 Git 上面的檔案庫,並在本地端編譯。首先,確認 Git 已經安裝,其安裝方法如下:

$ sudo apt-get install git

安裝好後,在終端機移到自己的工作空間/src下,將克隆後的檔案庫放在這裡:

cd ~/catkin_ws/src

若你使用 ROS Jade

$  git clone https://github.com/ros-simulation/gazebo_ros_pkgs.git -b jade-devel

若你使用 ROS Indigo

$  git clone https://github.com/ros-simulation/gazebo_ros_pkgs.git -b indigo-devel

若你使用 ROS Hydro

$  git clone https://github.com/ros-simulation/gazebo_ros_pkgs.git -b hydro-devel

檢查是否有缺少的相依程式庫

$ rosdep update

$ rosdep check –from-paths . –ignore-src –rosdistro jade

然後安裝上缺少的程式庫:

$ rosdep install –from-paths . –ignore-src –rosdistro jade -y

如上所述,ROS Jade 尚未包含 gazebo-ros-control 封包,所以先暫時忽略不編譯:

$ touch gazebo_ros_pkgs/gazebo_ros_control/CATKIN_IGNORE

回到工作空間最上層路徑,編譯:

$ cd ~/catkin_ws/

$ catkin_make

4. 測試整合了ROS的Gazebo

請確認你有在~/.bashrcsource
ROS系統路徑和自己的工作空間 catkin_workspace 的路徑。 
現在,你可以用 roslaunchrosrun或者rosservice的方式啟動Gazebo

4.1 Rosrun啟動Gazebo

首先,在終端機上輸入:

$ roscore

再開一個分頁,輸入

$ rosrun gazebo_ros gazebo

或者把 client 和 server 一起啟動:

$ rosrun gazebo_ros gazebo

也可以各別啟動,例如只開 server

$ rosrun gazebo_ros gzserver

和只開 client

$ rosrun gazebo_ros gzclient

另外,也可以只開Server,用 GDB 進入除錯模式:

$ rosrun gazebo_ros debug

4.2 Roslaunch啟動Gazebo 

你可以輸入以下來載入一個空白的世界:

$ roslaunch gazebo_ros empty_world.launch

4.3 用rostopic 檢查Gazebo

輸入 

$ rostopic list

應該會看到運作中的 topics,如下:

/gazebo/link_states>/gazebo/model_states>
/gazebo/parameter_descriptions>/gazebo/parameter_updates>
/gazebo/set_link_state

/gazebo/set_model_state

表示gazebo_ros_pkgs 運作正常。

4.4 用rosservice確認Gazebo 已安裝

也可以用 rosservice 確認 Gazebo有沒有正常運作,如下輸入:

$ rosservice list

應該會返回:

/gazebo/apply_body_wrench>
/gazebo/apply_joint_effort>/gazebo/clear_body_wrenches>
/gazebo/clear_joint_forces>/gazebo/delete_model>
/gazebo/get_joint_properties>/gazebo/get_link_properties>
/gazebo/get_link_state>/gazebo/get_loggers>
/gazebo/get_model_properties>/gazebo/get_model_state>
/gazebo/get_physics_properties>/gazebo/get_world_properties>
/gazebo/pause_physics>/gazebo/reset_simulation>/gazebo/reset_world>
/gazebo/set_joint_properties>/gazebo/set_link_properties>
/gazebo/set_link_state>/gazebo/set_logger_level>
/gazebo/set_model_configuration>/gazebo/set_model_state>
/gazebo/set_parameters>/gazebo/set_physics_properties>
/gazebo/spawn_gazebo_model>/gazebo/spawn_sdf_model>
/gazebo/spawn_urdf_model>/gazebo/unpause_physics>
/rosout/get_loggers

/rosout/set_logger_level

表示 Gazebo 運作正常。


 

Referece:
http://wiki.ros.org/gazebo_ros_pkgs

http://gazebosim.org/tutorials?tut=install_ubuntu&cat=install

http://gazebosim.org/tutorials?cat=connect_ros

Gazebo 是什麼?為什麼要用它?

Gazebo 這個單字的英文原意是類似 Pavilion 的涼亭,也沒人能解釋這個單字的來源。Anyway,我們不是來上英文課的。在模擬界,Gazebo 是一個功能強大的模擬軟體,如果你覺得還未能滿足你在模擬上的需求(譬如說你想模擬當個創世神中的地獄、或者火星環境、或者月球表面、或者土星環上的狀況時),你可以加上自己的 Plugins。而其實 Gazebo 是一整套跟 ROS 毫無相關的獨立軟體。截至目前為止(2015年11月)已經推到了 6.0.0.0 版,推陳出新的速度可真是驚人!

gazebo-10x14b
所以別人在沙盒裡面堆城堡玩車車,而我們則是在涼亭裡面玩機器人!

那你可能會問,既然 Gazebo 是獨立軟體,那跟 ROS 的模擬又有什麼關係?那就是,ROS 既然是一個包山包海的架構,它當然也連結了 Gazebo 方便開發者把自己的機器人同時匯入 Gazebo 又可以自行存取 Gazebo 中自己辛苦打造的機器人的所有資訊。

Screenshot-from-2014-03-14-07_34_30
Fig.1. Husky 在模擬世界中的樣子

maxresdefault
ATLAS 機器人相對於桌面和箱子的樣子。其實許多家具都是直接拿官方檔案庫中的模型檔直接匯入的

gazebo11
Fig.3. Pioneer 機器人在家具環境中的模擬

14399417397131117
Fig.4. 整個 Willow Garage 的辦公室都已經是可以直接當場匯入的世界檔

我講太快了,我們一步步慢慢來。

  1. Gazebo 是什麼?
  2. 為什麼要用 Gazebo?

1. Gazebo 是什麼?

Gazebo 是一套能真實模擬物理世界中各種模型及物體的軟體,很適合用來實驗機器人如何與周遭環境互動。Gazebo 的參考資源其實跟 ROS 一樣豐富,可以參考 Gazebo Wiki,或者 Gazebo Tutorial。可以先瀏覽完後,再來看我這邊的個人心得,會比較了解我為什麼這樣做。

gazebo_logo

另外,Gazebo實際上由兩個部分,或者兩個執行檔組成,Client和Server 端。Server端主宰了基本的物理運動相關的運算,以及感測器產生數據等,它可以單獨被開啟使用。你只要輸入"run headless"這樣的參數(怎麼讓我想到無頭騎士??XDD),它就可以直接被執行,在這裡可以了解如何啟動。而 Client 端主要就是執行圖形化使用者介面 (GUI),方便視覺化模擬。

Gazebo client server
我把 Server 和 Client 的關係想像成了冰山的樣子,也許整個架構其實是 50: 50 的,兩者佔的比重可能並不是這麼懸殊

PS: 這純屬各人的心得。有時候就算某個軟體的教學很完整,偶爾還是碰到一些文章沒交待到或者只能意會不能言傳的經驗時,便會讓不知情的初學者卡觀的情形,因此,我也將秉持著建議讀者先略讀官方教學文件後,再救自己的開發經驗分享,讓大家能以較少成本的方式,立刻上手,以期縮短學習曲線。

2. 為什麼要用 Gazebo?

就目前而言,Gazebo 所提供的模組與開發彈性遠優於其他模擬器,而這包括環境的建置、空間中的物品種類、可擴充性能與物理特性的彈性、已經建置好的機器人種類多寡、物理特性調整、匯入模型難易度等等,遠遠優於同類軟體。

據說,DARPA 的參賽團隊都有使用 Gazebo 來幫助他們開發各種所需的演算法。

而就個人而言,每次要實機操作時,心理壓力也很大,因為機器人可能會因為許多機構上的耗損或其他問題而突然間無法運作,或者必須時時注意其電量是否準確,儀器有無耗損,線材是否都能正常傳輸訊號,馬達與控制器間是否溝通不良等等,種種非核心的問題,可能就會耗費掉一個早上在硬體上除錯。除非你特別愛修硬體,否則實在是沒什麼產能的苦工。此外,如果因為自己的演算法讓機器人暴衝的話,也會造成一起開發的其他夥伴們實際上的困擾與危險。

如果今天是一個團隊要協作一整個專案的話,實機操作除了要顧慮人手一多會把硬體搞砸外,更重要的就是大家都想檢測自己寫的程式在機器人上會不會出問題,而模擬可以更實際的得出一個相當安全也相對低成本的解答。

但是也有不需要做模擬的時候。如果你覺得自己實體的機器人很容易使用,環境單純,或者操作上很安全,且只是單純跑一個簡單的程式,那麼就不建議實作模擬,畢竟從建立機器人模型到實際操作虛構的機器人,這中間也要耗費不少心力。

總之,一個訣竅就是,請善用自己最熟練的方式,來達成目標,而不是別人怎麼做,自己就要跟著做。


圖片來源:

涼亭 http://www.shawneestructures.com/2009-old-images/gazebo-10x14b.jpg

Gazebo Logo http://gazebosim.org/assets/gazebo_vert-f8ad1a52e3f233c2ff74fb43ee770f75.png

冰山 http://www.pvisoftware.com/blog/wp-content/uploads/2013/11/Pegasus_vertex_Iceberg.png

Fig.1. http://robohub.org/wp-content/uploads/2014/03/Screenshot-from-2014-03-14-07_34_30.png

Fig.2. https://i.ytimg.com/vi/yVICMC_BAiU/maxresdefault.jpg

Fig.3. http://traclabs.com/wp/wp-content/uploads/2010/11/gazebo11.png

Fig.4. http://answers.gazebosim.org/upfiles/14399417397131117.jpg