robot-notes — 機器人知識筆記 GitHub ↗
本章與本頁目次

關於

robot-notes /關於/GitHub Actions × gz sim playbook

用 GitHub Actions 驗證與「看」gz sim 模型(可重用 playbook)

把 Gazebo(新版 gz sim)的模型 / 世界 / 機器人,放到 GitHub Actions 上自動驗證——尤其當你沒有 GPU、本機 CPU 也吃緊時,讓 GitHub 的機器代勞。這份是從實際把 AWS Small Warehouse 遷到 Harmonic、搭一台舵輪叉車、再讓它「在倉庫裡走給人看」的過程,萃取出的可重用做法與一路踩過的雷。

活範例(完整 validate.yml + 腳本):aws_warehouse_model_for_gazebo_harmonic。相關:用 Gazebo + ROS2 模擬 AMR


第一原則:把「需不需要 render」當分水嶺

免費 GitHub runner 沒有 GPU。這條線決定一切——不需 render 的事 100% 可靠,需 render 的事又慢又不穩:

任務 需 render? 免費 runner
SDF 結構驗證(gz sdf -k)、XML 良構、model:// 路徑 ✅ 完全可靠
world headless 載入(gz sim -s,驗 include 解析) ✅ 可靠
機器人會不會動 / 走什麼軌跡(下指令、記位姿) 否(純物理) ✅ 可靠
相機出圖 / 錄影(視覺成品) ❌ 不可靠(軟體渲染慢且間歇)

設計原則:不需 render 的盡量自動化上 CI;需 render 的視覺產出,別硬塞免費 runner(改 GPU runner / 帶 GL 的 Docker / 本機一次性截圖)。但「視覺化」不一定要 render——見 §4 的軌跡圖。

把下面各節排成階梯,可以一眼看出這條線切在哪、每一關各買到什麼:

五關驗證階梯:靜態驗證、headless 載入 world、機器人會不會動、軌跡俯視圖四關不需 render 且可靠;紅色 render 分水嶺之下的相機出圖錄影在免費 runner 上不可靠

第 4 關是這張圖的關鍵:它把「讓人看到機器人在走」這個看似非得 render 不可的需求,用軌跡圖換到了分水嶺上面。多數以為必須跨線的需求,其實都值得先問一次「有沒有不需要像素的表達方式」。


1. 靜態驗證(最便宜、最可靠的一關)

不開模擬就能抓一堆錯。一支 scripts/validate.sh 做三件事:

  1. 每個 model.sdfgz sdf -k(抓結構錯、慣性張量違反三角不等式等)。
  2. 每個 world 用嚴格 XML 解析器(Python xml.dom.minidom)驗良構(抓 XML 註解內的 -- 這種 gz sdf 容忍、但其他工具會拒的)。
  3. world 裡每個 model://NAME 都對應得到本機 models/NAME/robot/NAME/ 目錄。

注意:gz sdf 解析不了 model://(那是 gz-sim 執行期 + GZ_SIM_RESOURCE_PATH 的 findFile callback;獨立 sdformat 工具沒有,會報 callback is empty)。所以 world 的 include 解析「能不能成」只能交給真正的 gz sim(下節)。

2. headless 載入 world(驗 include 真的接得上)

gz sim -s -r --iterations 300 <world>(server-only、跑幾百步退出),grep log 有沒有 Unable to find uri / Error Code / Failed to load。這一步不需 render(world 沒有相機 sensor 時 Sensors system 閒置),所以可靠。它是唯一能證明「整個倉庫 include 全解析、載得起來」的方法。

3. 機器人「會動」(純物理,可靠)

下指令、比對前後位姿:gz topic 發速度/角度指令給機器人,跑幾秒,用 gz topic -e -t /model/<name>/pose 讀位姿(機器人模型要掛 gz-sim-pose-publisher-system),算位移 ≥ 門檻就算「會動」。純物理、無渲染 → 可靠。

4. 「看」機器人走軌跡(不需 render 的視覺化)

要讓人「看到」機器人在場景裡走,不一定要 render 3D 畫面:把它的位姿軌跡記錄下來、用 matplotlib 畫成俯視路徑圖(純 CPU)。做法:

這是無 GPU 也能「看到機器人在倉庫走」的可靠方式。

CI 實跑的叉車位姿序列畫成俯視軌跡圖,倉庫佈局是事後從 world SDF 抽出座標疊上去的,純 CPU 無 render

上圖的軌跡是真的、佈局是疊的。 物理其實跑在一塊空平地上,倉庫的貨架位置是事後從 world SDF 的 <model><pose> 抽出來畫上去的——理由見下面那段「物理等價技巧」。

物理等價技巧:重場景(如貼了一堆 mesh 的倉庫)在免費 runner 上 sim 跑得很慢(見 §5),機器人在 wall-time 內幾乎走不動。但因為 dartsim 忽略 mesh 碰撞(§5),機器人「在倉庫開」與「在一塊平面地板上開」物理完全等價。所以可以在輕量世界(只有地板+機器人)把路徑開出來(sim 快、跑得遠),再把路徑疊到重場景的佈局圖上。


5. 物理層的雷(dartsim,Harmonic 預設)

6. headless 渲染(真的要 3D 畫面時)的 recipe 與雷

能動的組合:

export LIBGL_ALWAYS_SOFTWARE=true
export GALLIUM_DRIVER=llvmpipe      # 關鍵:EGL surfaceless 預設掉到最慢的 swrast
gz sim -s -r --headless-rendering <world>   # EGL surfaceless,免 X / xvfb(僅 ogre2)

免費 runner 上純軟體渲染勉強生出的一張畫面,解析度與品質都很勉強,而且不是每輪都生得出來

這張是真的在免費 runner 上生出來的——但同一份設定跑十輪大概只成功一兩輪。放在這裡是為了說明「做得到」與「可以依賴」是兩件事。

7. 工程習慣與雷總表

說明
gz 預設不寫 stdout -v 4 才把訊息 echo 到 console;否則 redirect 出來的 log 是空的
背景跑 + SIGKILL/SIGTERM 丟 log 緩衝未 flush → log 看似 0-byte(不是真的沒輸出);影格則是「已寫的留著、最後一張可能丟」
gz sdf -p 驗 world 會誤判 它解析不了 model://;world 結構/include 驗證要分開做(§1、§2)
先本機跑通再寫 CI CI 腳本自己有盲點(如上條),先在本機踩過,CI 才不會綠得不明不白或紅得冤枉
<physics type> 必填 SDFormat 必填屬性,別為了「引擎由 plugin 決定」就刪掉;留 ode 字串即可

來源