把機器人模型匯入 Gazebo

2026-07-18
  • ros2
  • gazebo
  • urdf
  • simulation

問題定義

上一節啟動的是空蕩蕩的世界,這一節要解決的是「把自己寫的機器人放進這個世界」。這裡有一個容易被低估的環節:一份在 RViz2 裡顯示良好的 URDF,直接丟進 Gazebo 通常不會馬上正常運作——純視覺化用途的模型,往往缺少物理模擬需要的額外資訊。

核心概念說明

<gazebo> 標籤:在 URDF 裡插入模擬專屬設定

URDF 規範本身允許出現 <gazebo> 這個標籤,內容不會影響 RViz2 或其他純粹讀取幾何結構的工具,但 Gazebo 讀取時會額外解析這個區塊,用來指定材質摩擦係數、感測器插件、控制器插件等模擬專屬資訊。最常見的用法之一,是幫每個 link 指定摩擦力係數:

xml
<gazebo reference="wheel_link">
  <mu1>0.9</mu1>
  <mu2>0.9</mu2>
</gazebo>

reference 屬性指定這段設定套用在哪個 link 上,這也是為什麼 <gazebo> 標籤可以在同一份 URDF 裡出現多次——每個 link 或 joint 需要不同的模擬參數時,各自宣告一段。

ros2_control:讓 Gazebo 裡的關節可以被 ROS2 控制指令驅動

單純把模型 spawn 進 Gazebo,物理引擎會讓它受重力影響掉落、碰撞,但關節不會自動響應你從 ROS2 端發出的速度或位置指令——需要透過 gz_ros2_control 這個外掛把 Gazebo 裡的關節,橋接成 ROS2 生態系標準的 ros2_control 介面。這一節先示範最基本的 spawn 流程,ros2_control 的細節控制器設定會在後面控制相關章節深入。

實作範例:把第 4.2 節的雙臂模型 spawn 進 Gazebo

1. 在 xacro 裡加上 Gazebo 需要的最低限度設定

延續第 4.2 節 dual_arm.xacro,額外補上 <gazebo> 材質設定與必要的 ros2_control 骨架(這裡先聚焦在能成功 spawn,關節控制器留到後面章節深入):

xml
<gazebo reference="base_link">
  <material>Gazebo/Grey</material>
</gazebo>

<gazebo reference="left_upper_arm">
  <material>Gazebo/Blue</material>
</gazebo>

<gazebo reference="right_upper_arm">
  <material>Gazebo/Blue</material>
</gazebo>

2. 把 xacro 展開成 SDF 相容的 URDF 字串

bash
xacro ~/ros2_ws/src/my_package/urdf/dual_arm.xacro > /tmp/dual_arm_expanded.urdf

3. 啟動世界並 spawn 機器人

bash
gz sim empty.sdf

另開終端機,用 ros_gz_sim 提供的 create 工具,把展開後的 URDF 檔案 spawn 進正在執行的世界:

bash
ros2 run ros_gz_sim create -file /tmp/dual_arm_expanded.urdf -name dual_arm -z 0.5

-z 0.5 指定生成的初始高度,避免模型跟地面重疊造成初始瞬間的異常碰撞反應。

預期輸出

text
[INFO] [create]: Requesting list of world names.
[INFO] [create]: Requesting creation of entity.
[INFO] [create]: Waiting for `/world/empty/create` to be ready...
[INFO] [create]: entity creation successful.

Gazebo 視窗裡會看到模型從空中 0.5 公尺處落下,因為重力作用碰到地面後停止(如果 inertial 區塊沒有填寫合理數值,這一步經常會出現模型抖動或直接穿過地面的異常,是排查的第一個訊號)。

4. 確認橋接後的關節狀態能回到 ROS2

bash
ros2 run ros_gz_bridge parameter_bridge /world/empty/model/dual_arm/joint_state@sensor_msgs/msg/JointState[gz.msgs.Model
bash
ros2 topic echo /world/empty/model/dual_arm/joint_state --once
text
name: ['left_shoulder_joint', 'left_elbow_joint', 'right_shoulder_joint', 'right_elbow_joint']
position: [0.0, 0.0, 0.0, 0.0]

常見錯誤與除錯技巧

錯誤一:spawn 指令回報成功,但 Gazebo 畫面裡完全看不到模型

text
[INFO] [create]: entity creation successful.

現象:終端機顯示成功,但畫面上什麼都沒出現。

原因:常見原因是模型的生成座標剛好在鏡頭視角之外,或模型的 <visual> 幾何設定有誤(例如尺寸單位寫錯,實際生成了一個肉眼難以察覺的極小或極大模型)。

排除方式:用 Gazebo 介面裡的「Entity tree」面板確認模型確實存在於場景樹裡,存在的話用滑鼠操作視角尋找,或重新用更合理的 -z 座標生成;如果 Entity tree 裡根本沒有這個模型,代表 spawn 實際上失敗了,需要回頭檢查展開後的 URDF/SDF 是否有結構問題。

錯誤二:模型落地瞬間劇烈抖動或彈飛

現象:模型碰到地面的瞬間,不是自然停止,而是像被彈簧彈開一樣劇烈跳動。

原因:幾乎都是 inertial 區塊的數值不合理——質量填 0、慣性張量的值過小、或跟碰撞幾何的實際尺寸完全不成比例,導致物理引擎計算出的角動量/線動量出現數值不穩定。

排除方式:檢查每個有實際物理意義的 link,<mass> 是否為合理的正數,<inertia> 的數值量級是否與 link 的實際大小、質量相符(可以用簡單幾何形狀的慣性公式估算,例如均勻長方體的慣性張量公式),避免直接複製貼上跟實際模型尺寸不匹配的慣性數值。

小結

把 URDF 模型變成「模擬就緒」,關鍵在於補上 <gazebo> 專屬標籤(材質、插件設定)以及確保 inertial 數值合理,ros2_run ros_gz_sim create 負責實際把展開後的模型放進正在執行的世界。模型能成功 spawn 且穩定落地之後,下一節要處理的是機器人上的感測器——怎麼在模擬世界裡產生雷射掃描、相機影像這類感測資料,並確保它們的座標系與噪聲模型符合真實感測器的行為特性。

延伸閱讀

常見問題

faq_01.log
同一份 URDF,不加任何修改,可以直接拿去 Gazebo 模擬嗎?
純視覺化用途的 URDF(例如只在 RViz2 裡看模型)通常缺少 Gazebo 需要的資訊,尤其是每個 link 的 inertial 區塊如果沒有正確填寫,或缺少 <gazebo> 標籤指定的插件設定,模型丟進 Gazebo 後可能會出現穿模、無法正確受力、或關節完全不受控制等問題。實務上會在 URDF/xacro 裡額外加上 Gazebo 專屬的標籤與插件設定,才算是『模擬就緒』的模型。
faq_02.log
spawn 進 Gazebo 的機器人,跟 RViz2 裡看到的是同一個 TF 樹嗎?
如果正確設定了 joint_state_broadcaster 之類的橋接元件,是的——Gazebo 模擬出來的關節角度會透過橋接送回 ROS2 側的 /joint_states,robot_state_publisher 讀到這些角度後廣播出跟 RViz2 章節介紹的完全相同的 TF 樹,兩邊看到的座標關係會是一致的。
faq_03.log
可以在同一個世界裡 spawn 多台一樣的機器人嗎?
可以,但每次 spawn 時要給不同的名稱(-name 參數)與不同的初始位置,且如果機器人模型內部有寫死的 TF 座標系名稱,多台之間可能會發生座標系名稱衝突,通常需要搭配 namespace 或 TF prefix 機制來區分,這是多機器人模擬時常見的額外複雜度。