Gazebo 基礎:啟動模擬世界與物理引擎概念

2026-07-18
  • ros2
  • gazebo
  • simulation
  • physics-engine

問題定義

前面幾章寫的節點邏輯、URDF 模型,都還停留在「有沒有正確連接」「看起來對不對」的層次,沒有真正的物理世界會怎麼回應——機器人的輪子踩到障礙物會怎樣、手臂夾爪碰到物體會不會滑掉、感測器在特定角度會讀到什麼數值。這些問題不能光靠看模型或讀程式碼回答,需要一個真正計算物理行為的模擬環境。Gazebo 就是 ROS2 生態系裡標準的物理模擬器,讓你在花錢買硬體、或風險較高的場景(例如手臂高速揮動)之前,先在虛擬世界裡驗證。

核心概念說明

Gazebo 跟 ROS2 是兩個獨立的行程,透過橋接溝通

理解現在版本 Gazebo 架構的第一個關鍵:Gazebo 本身不是 ROS2 的一部分,它是一個獨立運作的模擬器(使用自己的通訊系統,稱為 Gazebo Transport),ROS2 節點要跟 Gazebo 裡的模擬世界互動(例如訂閱模擬出來的雷射掃描資料、發送速度指令),中間需要透過 ros_gz_bridge 這個橋接套件,把 Gazebo Transport 上的主題轉換成 ROS2 主題(反之亦然)。

這個架構解釋了一個新手常遇到的困惑:在 Gazebo 裡看到模擬世界正常運作,但 ros2 topic list 卻看不到對應的感測器資料——如果沒有啟動橋接、或橋接設定的主題名稱/型別對不上,Gazebo 那一側的資料就到不了 ROS2 這一側,兩邊各自獨立運作、互不影響。

SDF:Gazebo 世界的描述格式

Gazebo 用 SDF(Simulation Description Format)描述整個模擬世界,包括地面、光源、靜態障礙物等等。SDF 跟 URDF 概念上很像(都是用 XML 描述剛體與關節),但 SDF 的表達能力更完整,涵蓋了 URDF 不支援的東西(例如更豐富的物理材質參數、感測器雜訊模型)。實務上你通常不會直接手寫大段 SDF——世界檔案(.sdf.world)是手寫的,但機器人模型本身多半還是先寫 URDF/xacro,再靠工具轉換成 SDF 讓 Gazebo 讀取,這在下一節匯入機器人模型時會示範。

物理引擎與即時因子

Gazebo 底層的物理引擎(預設是 DART 或 Bullet,依版本而定)會用固定的時間步長(time step)反覆計算每個物體的受力、碰撞、位置更新。即時因子(real time factor, RTF) 是衡量「模擬時間」跟「真實經過時間」的比值:RTF 等於 1 代表模擬跟現實時間同步進行,小於 1 代表模擬因為運算量太大而落後於真實時間。

實作範例:啟動一個空世界,觀察橋接後的主題

1. 啟動 Gazebo

bash
gz sim empty.sdf

預期畫面

Gazebo 視窗開啟,顯示一片空曠的地面與預設光源,右下角會顯示目前的即時因子,例如:

text
Real Time Factor: 1.00
Sim Time: 00:00:12.450

2. 加入一個球體並讓它落下,觀察物理效果

在 Gazebo 視窗上方工具列選擇「Sphere」形狀,點擊場景放置一顆球,會看到球體因為重力立刻開始下墜,碰到地面後依照預設的彈性係數彈跳幾下後靜止——這是物理引擎在實際運算,不是預先寫好的動畫。

3. 啟動橋接,把 Gazebo 的時鐘資料接進 ROS2

bash
ros2 run ros_gz_bridge parameter_bridge /clock@rosgraph_msgs/msg/Clock[gz.msgs.Clock

預期輸出

text
[INFO] [ros_gz_bridge]: Creating GZ->ROS Bridge: [/clock (gz.msgs.Clock) -> /clock (rosgraph_msgs/msg/Clock)]

另開終端機確認 ROS2 這一側確實收到了資料:

bash
ros2 topic echo /clock --once
text
clock:
  sec: 47
  nanosec: 210000000

這條指令示範了橋接語法的基本結構:<主題名稱>@<ROS2型別>[<Gazebo型別>,中括號的方向([ 代表由 Gazebo 傳向 ROS2,] 則相反,@ 代表雙向)決定資料流動的方向,實務上為每個需要的主題手動打這種指令太麻煩,通常會寫成一份 yaml 設定檔一次性橋接多個主題,這在下一節匯入完整機器人模型時會用到。

常見錯誤與除錯技巧

錯誤一:Gazebo 視窗開啟後畫面全黑或完全沒有反應

原因:多半是顯示卡驅動或圖形渲染相關的環境問題,尤其常見於虛擬機或遠端桌面環境,沒有正確的 GPU 直通或渲染後端設定。

排除方式:先確認是不是渲染問題,而不是 Gazebo 本身沒有正常啟動——用 gz topic -l 檢查 Gazebo Transport 上是否確實有主題資料在流動(如果有,代表模擬本身跑起來了,只是畫面渲染有問題):

bash
gz topic -l
text
/clock
/gazebo/resource_paths
/gui/camera/pose
/stats
/world/empty/pose/info

如果這裡看得到 /stats 這類代表模擬正在運行的主題,問題範圍就縮小到顯示層,而不是模擬邏輯本身。

錯誤二:即時因子持續遠低於 1,模擬跑得非常慢

text
Real Time Factor: 0.15

原因:場景裡碰撞幾何過於複雜(例如直接拿高精度的視覺 mesh 當碰撞幾何,而不是簡化過的形狀,呼應第 4.1 節提到 collision 應該用簡化幾何的建議)、或是同時模擬的物體數量太多,超出目前硬體的運算能力。

排除方式:檢查場景裡每個模型的碰撞幾何設定是否過度複雜,優先簡化非必要細節的碰撞形狀;也可以透過 Gazebo 內建的統計面板(Window → Plugins → 加入 Performance 面板)觀察哪個環節(物理運算、渲染)是效能瓶頸,再針對性優化。

小結

Gazebo 是獨立於 ROS2 運作的物理模擬器,兩者透過 ros_gz_bridge 轉換彼此的主題資料;SDF 是 Gazebo 描述世界的格式,即時因子則是判斷模擬效能是否吃緊的關鍵指標。這一節先建立最基本的世界啟動與橋接概念,下一節要把前面章節寫好的機器人 URDF 模型,實際匯入 Gazebo 世界,讓它受物理引擎控制。

延伸閱讀

常見問題

faq_01.log
Gazebo 跟 RViz2 有什麼本質上的不同?
RViz2 純粹是視覺化工具,它不會計算物理行為,只是把已經存在的資料(TF、感測器主題)畫出來;Gazebo 則是一個帶有物理引擎的模擬器,會實際計算重力、碰撞、摩擦力,讓機器人模型在虛擬世界裡『真的』受物理法則影響並產生對應的感測器資料。兩者常常搭配使用:Gazebo 負責模擬物理與產生感測器資料,RViz2 負責把 ROS2 這一側收到的資料視覺化確認。
faq_02.log
為什麼現在的 Gazebo 跟以前教學看到的指令不一樣(gazebo 變成 gz sim)?
ROS2 生態系近年從舊版 Gazebo Classic 遷移到新一代的 Gazebo(原本代號 Ignition,後改回 Gazebo 但架構整個重寫),指令列工具也從 gazebo 改成 gz sim,並改用 ros_gz_bridge 這個獨立的橋接套件跟 ROS2 溝通,而不是像以前那樣把 ROS 插件直接編進 Gazebo 本體。如果查到的教學指令對不上,多半是新舊版本的差異,本文以新一代 Gazebo(gz sim)為準。
faq_03.log
即時因子(real time factor)低於 1 代表什麼?
代表模擬跑得比真實時間慢——例如即時因子 0.5,代表模擬裡經過 1 秒,實際上你在螢幕前已經等了 2 秒。這通常是場景太複雜(碰撞幾何過細、物體數量太多)超出電腦運算能力導致,並不是程式邏輯錯誤,但長時間跑高延遲的模擬會讓依賴即時互動的測試(例如手動遙控)變得很不順手。