Isaac Sim 實戰筆記 GitHub

32 · 把車做成真的會動的車:五個坑、一個錯的指標、以及為什麼它開不完路網

把車從「一顆會被搬的盒子」換成照 URDF 建的 articulation(兩顆驅動輪 + 四個萬向腳輪),中間卡了五次。每一次的症狀都是「車不動」,而五個成因完全不同。

它們的共同點比個別成因更有用:

USD 檢查、bbox、overlap 查詢在五種情況下全部是綠的。

這一篇講那五個坑、一個算錯的指標怎麼長出一整套合理但錯誤的成因、以及最後「車開不完路網」的五個原因——沒有一個是路線規劃不好

驗證狀態:內容來自一段多車 + 多樓層的 Isaac Sim 場域前期研究(2026-07 至 08),五台車、三款車型的實測。數字連同量測條件列出。⚠ 幾個結論明確標了「還沒量」,照原始紀錄標。

1. 五個都不報錯的坑

# 成因 症狀 怎麼判出來的
1 physxArticulation:enabledSelfCollisions 預設是 True 車一放進場景就自己炸開:靜置 150 步從 (30,12,0) 飛到 (188,−165,−51),關節速度 1.8 萬 rad/s 先關掉驅動只讓它靜置——還是炸,所以問題不在驅動
2 驅動增益填 1e4、上限填 500 N·m 輪速 3.3×10⁶ rad/s、位移十萬公尺 「留兩位數餘裕」不是餘裕:1 kg 的輪子在 500 N·m 下是 12 萬 rad/s²
3 physxJoint:maxJointVelocity 的單位是度/秒 輪速無論怎麼下指令都卡在 0.52 rad/s 那個數字太整齊——0.52 × 57.3 = 30,正好是填進去的值
4 UsdGeom.Cylinder 當碰撞體 五台車全部下沉 4.5 cm,cmd_vel 三秒只走 16 mm 用 0.004 m 的小球去探輪心 ±0.07 m:兩個方向都在碰撞體裡,而真的輪子在轉軸方向只有 ±0.03。改用凸包網格後車正好站在 z=0
5 凸包網格的軸向映射寫反(X 與 Y 對調) 輪子完全轉不動,500 N·m 也不動 沒有 drive 的腳輪加 20 N·m 可以飆到 1.7 萬 rad/s——關節是自由的,所以不是關節的問題,剩下的可能只有幾何。回頭量網格外框:y 方向是半徑而不是厚度

第 3 個特別值得記:當一個量卡在某個「太整齊」的數字上,先做單位換算再想別的。0.52 這種數字不會自然出現。

第 5 個示範了一種很有效的排除法:造一個「同類但少了嫌疑物」的對照。腳輪沒有 drive 卻轉得動,一次就把「關節設定」整類嫌疑排掉。

1.1 兩個量測腳本自己製造的假訊號

① USD 的預設 upAxis 是 Y。 量測腳本沒設,於是重力沿 −y、「地板」變成一面牆——量到的落定高度全部沒有意義,而數字看起來剛好支持當時的假設。差一點就把一個錯的結論寫進文件。

② 從高處丟一個輪子去測碰撞是錯的實驗設計。 r=0.09、厚 0.06 的圓柱落地會倒下來平躺,量到的高度是厚度的一半——那是真的物理,不是碰撞失效。

兩條的共同形狀:量測工具本身在製造你正在追的那個現象。這與 27 篇 §6.1 的「為了補救而加的儀器本身量錯東西」是同一件事。

2. 一個算錯的指標,長出一整套合理的成因

這是整篇最有教學價值的一段。

中間有一版把「滑移」量成指令距離 vs 車實際位移,得到 41%,並據此推論「載重跑到腳輪上、驅動輪吃不到正向力」。

那個推論是錯的,而它錯得很有說服力:數字穩定、可重現、而且有一個聽起來合理的力學解釋。

2.1 正確的定義

真正的滑移是輪子轉過的距離 vs 車走的距離,而輪子轉過多遠只能用角速度對時間積分

兩種簡便讀法都不行:

用積分量出來的滑移是 2~3%一開始就不是滑移問題。

2.2 錯的指標為什麼特別難發現

指標算錯時,錯的那個數字會自己長出一套合理的成因,而順著它做的每一步(降低腳輪摩擦、加大馬達扭矩、加懸吊)都會「有一點效果」——因為它們確實各自改善了一點別的東西。

這就是為什麼「改了有反應」不能當成「找對方向」。23 篇記過同一個形狀:排查停在第一個「調了有反應」的參數上。

2.3 真正的成因:慣量少了馬達與減速機

URDF 的驅動輪慣量原本只有輪胎本體:½mr² = 0.004 kg·m²

25 N·m 的力矩在一個 1/60 s 的步長裡可以把它加速 100 rad/s —— 速度伺服因此變成 bang-bang,輪速在目標的兩倍與零之間震盪,平均只有目標的 75%。

真實 AMR 的驅動輪後面接著馬達與減速機,減速比 n 會把轉子慣量放大 。補上反射慣量(0.046 kg·m²)之後,穩態追隨誤差從 22.8% 降到 0.7%

⚠ 同一處還有一個附帶錯誤:URDF 的碰撞圓柱被 rpy 轉成沿 y,而慣量張量沒有跟著轉——自轉慣量寫在 izz,但關節繞的是 y。差 43%。

2.4 懸吊留下來了,但理由改寫了

懸吊(prismatic joint + 彈簧,行程 ±2 cm、剛度 25000 N/m、預壓 1.5 cm)留在模型裡,理由不是修滑移(那個問題不存在)。

真正的理由是:剛體底盤 + 兩顆驅動輪 + 四個腳輪是六個共面接觸點的靜不定問題,載重分配由求解器決定而不是由設計決定。彈簧讓「驅動輪吃多少載重」變成一個寫得下來的數字(k × 預壓 = 375 N/輪)。實測它把輪速震盪的峰值從 37 rad/s 壓到 6 rad/s。

一個措施可以是對的,而支持它的理由是錯的。 根因查清楚之後,要回頭把理由改寫——否則下一個人會照那個錯的理由去調它。

3. 腳輪半徑只有驅動輪的一半,車就在平地上被彈飛

一款車在平坦、空曠、沒有任何障礙的 9 m 走廊上,以 0.6 m/s 前進約 1.3 m 之後被推到離地 0.39 m、傾角 106°,98% 的步數在空中。同一條路、同樣的控制律與速度上限,另外兩款車 15.6 秒走完、傾角 0.1°、零步離地。

唯一相關的差異:

車型 驅動輪 腳輪 結果
櫃車型 0.09 m 0.09 m ✅ 15.6 s、傾角 0.1°
平板型 0.10 m 0.10 m ✅ 15.6 s、傾角 0.1°
拖車型 0.09 m 0.045 m 1.3 m 就翻

把腳輪改成 0.09(連同 hub 高度與慣量一起)之後,兩台拖車型都變成 15.6 秒、傾角 0.1°、零步離地、輪載 158/173 N——單一變數的干預,症狀完全消失。

3.1 被排除的兩個假設,各自示範一種排除法

① 靜態輪載不足 → 否。 量到五台車靜止時都是 243 N/輪、懸吊 0.0 mm、傾角 0°,三款車完全相同

靜態正常與動態正常是兩件事。

② 小碰撞體被暴力排出(maxDepenetrationVelocity 預設 3 m/s)→ 否。 壓到 0.5 之後干預確實生效(翻車點從 x=10.3 移到 14.1、離地 390 → 795 mm),而症狀沒解掉

干預生效但症狀不動,就是假設錯了。 改動已還原。

第二條特別值得記:一個假設可以「被證實有影響」卻「不是成因」。若當時停在「有效果」就收工,那個 maxDepenetrationVelocity=0.5 會永遠留在設定裡,變成一個沒人敢動的魔數。

3.2 守衛寫成「相等」而不是下限

新增的斷言是:腳輪半徑要等於驅動輪半徑

取「相等」而不是某個下限,因為相等是三款車現在都成立的事實,而「0.045 壞、0.09 好」中間那一段沒有量過——寫一個中間值等於把沒驗過的猜測寫成門檻。負對照跑過:把半徑改回 0.045 之後守衛立刻紅。

⚠ 中間曾經用「分車型速度上限」把那款車壓到 0.3 m/s 繞過去。成因查到之後那個繞過整個移除——留著會變成一個沒有理由的魔數,而且會掩蓋同一類的下一個模型錯誤。(這是 23 篇「捷徑的前提會過期」的正面示範:前提消失了,捷徑跟著拆掉。)

4. 宣告 1.0 m/s 的車撐不住 1.0 m/s,而限速之後反而更快

即時鏈路上量到一台車傾角 85.6°(躺著)跑完整輪並判 pass

往回查是輪子離地:懸吊壓到行程底(−15.8 mm)、驅動輪載重從 245 N 掉到 0 N、車身抬到離地 16~28 cm。沒有載重就沒有摩擦力,馬達再出力也只是空轉,車靠慣性亂滑,終點是翻覆。

同一條路,只改速度上限:

上限 最大傾角 最高離地 最小輪載 離地步數 航向擺動 實際耗時
1.0 m/s 31.1° / 43.4° 162 / 280 mm 0.1 / 0.0 N 13% / 18% ±33° / ±106° 12.6 / 22.5 s
0.6 m/s 0.1° / 0.7° 1.0 / 2.1 mm 146 / 156 N 0% / 0% ±1.3° / ±9.3° 10.8 / 16.1 s

限速之後絕對時間更快(第二段 22.5 → 16.1 秒)。1.0 m/s 的時間大半花在空中與落地後的修正,而不是花在前進——「調高上限 = 跑更快」在有物理的世界裡不成立。

4.1 ⚠ 0.6 不是「室內 AMR 的合理速度」

同級的真實 AMR 跑得到 1.0~1.5 m/s,所以模型裡還有東西不對。三個候選,都還沒量:質心高度、輪徑(反推出來是 9.2 cm,偏小)、懸吊行程(15 mm,而它在平地上就壓到底了)。

在量出來之前不要把 0.6 寫成通則——它是目前這組物理參數撐得住的速度

4.2 為什麼這個缺陷拖到現在才浮現

車先前根本跑不到 1.0(平均行駛速度 0.28 m/s),所以這個缺陷一直躺在工作範圍外面。把控制律的煞停上限補上之後平均速度變成 0.66、峰值 0.98,缺陷才第一次被觸發。

修好一個問題會把下一個問題帶進工作範圍,而在那之前它在每一份產出裡都是不存在的。

4.3 判準的兩個洞

判準不是太寬,是少了一個維度。

5. 車開不完路網:五個成因,沒有一個是「路線規劃不好」

多車即時鏈路一跑,兩台車都停在半路——而它們一直在下速度指令。九分鐘一輪的鏈路查不動這種問題,所以先做了一支一分鐘的路線檢查工具(不要雲端、不要調度層,只留「路網的一段路 + 這台車的控制律 + 這個物理世界」)。

成因一個一個量出來,五個都不是規劃的問題:

# 成因 修法
1 控制器下階躍指令 → 馬達全力 → 0.65 g 牽引力 → 車頭抬起、懸吊壓到底(1.0 m/s 直線走廊上兩秒內傾角 0.5° → 117°、z 彈到 1.5 m) 控制器加加速度上限(0.5 m/s²、0.45 rad/s²);驅動力矩照 0.5 m/s² 重推(25 → 18 N·m)
2 角速度上限填 1.5 rad/s 而車宣告 1.0 —— 1.5 rad/s 要四個腳輪瞬間轉向 90°(原地轉力矩需求飆到 30 N·m 以上) 上限照車的規格
3 邊走邊大幅修正對差速車是不穩的(直線走廊上航向擺到 ±60°) 改成停下、原地轉、再走(15° 轉、40° 遲滯、行進中轉向 ≤0.35 rad/s)
4 偏出去還全速前進;轉向量有上限,回到線上需要距離(偏出 1 m 之後再也回不來) 偏 0.5 m 以上速度收到 25%
5 車不看它自己的雷射(1.24 m 的縫裡照標稱速度衝,擦到牆就楔住) 前方 ±40° 最近回波 −0.45 m ÷ 1.2 s = 這一刻的速度上限(真車就是這樣做的)

修完之後,那五條任務路線的同層段全部走得完,比「距離 ÷ 標稱速度」慢 2.5~7.6 倍——那個倍數本身就是「有物理」的代價。

5.1 「翻車」與「被牆擋住」要分開

兩者在「輪子照轉而車不動」上完全一樣,而處置相反(一個要改車的動力學,一個要改路線或幾何)。

分開的方法是量車身的傾角:

傾角 117° + z 彈高  = 翻了
傾角 0°   + 位置不動 = 真的被擋住

這一格是第一項成因現形的關鍵。 在它出現之前,那個現象被讀成「幾何太窄」,而順著那個讀法做的事(移路網、改電梯)都不會有用。

5.2 檢查工具自己的兩個坑

5.3 空轉集中的那一格,就是最窄的那一點

有一輪某台車在某一格空轉 1042 步(佔它全部步數的 13%)。量那一格的路網淨空:0.43 m,而車半寬 0.35 m——只剩 8 cm 餘裕

空轉的分佈是一張免費的幾何地圖。 不必先知道哪裡窄,讓車跑,然後看它卡在哪。

6. ⚠ 陳舊的輸入不會報錯,它只會給你一組合理的數字

路線檢查報「車翻了,最大傾角 122.8°、97% 的步數輪子離地」。把嫌疑的層門搬走重跑,數字一模一樣——不是層門。

真正的原因:輪次腳本只把程式碼同步到模擬主機,地圖目錄沒有跟,而那台上那份路網停在 18 天前。舊圖裡某個節點在 y=13.6,正好壓在轎廂門口,於是車被放成半截在轎廂裡、半截在門檻上,一開就卡住再被彈開。新圖裡它在 y=12.9,同一條腿通過,傾角 10.2°。

這個陳舊輸入還連帶產生過一個錯誤的機制假說(「車的對角線 0.968 m 大於 0.95 m 的淨開口」)——那個假說不成立,它只是那份舊路網的產物。

修法有兩層:同步範圍補上地圖目錄,而且每一次檢查都印出路網的 sha256 與長度

那一行的用處不是給讀者看,是讓「這一輪讀的是哪一份」變成可以比對的事實

7. 檢查清單


延伸閱讀:24 把「會瞬移的底盤」換成「真的有輪子的車」(轉向式底盤的前提鏈,與本篇的差速車互補)、27 失效模式分類學23 物理模擬不可以偷懶33 電梯與多樓層