← 回專案總覽與驗證系統

第三支手臂:FT5425BL 標準舵機(B1 尺寸、B2 CAD、B3 URDF/MJCF、B4 模擬)

扭矩預算用「維持與 SG90 相同的扭矩佔比」把伸距外推到 306 mm。 實際把靜力算一遍——那個伸距空載就用掉連續額定的 88%。 問題不在算術,在於那個「相同的佔比」本身指的是什麼。

#48 第一支手臂的設計上限其實在連續工況之外 靜默

本頁一直寫著:「用 50% 堵轉當設計上限而不是 100%……以這個標準看, 這支手臂的機構尺寸對 SG90 是合適的,不是勉強。」

做第三支手臂時查到 FT5425BL 的資料同時給了堵轉與額定 (28.5 / 9.5 kg·cm,比值 3.0)。把同樣的比值套回 SG90:

SG90 堵轉 0.176 N·m → 連續約 0.059 N·m
第一支手臂最壞姿態 0.0788 N·m
                = 44.7% 堵轉
                = 約 134% 連續額定

也就是說,那個「50% 堵轉」的設計上限,本身就在連續工況之外。 第一支手臂撐得住,是因為它只有 70 g 的動件、酬載 4 g, 而且沒有人要求它保持同一個姿勢一小時。

這句話沒有算錯,但它把一個相對標準說成了絕對結論。 「以這個標準看是合適的」——而那個標準是我自己訂的, 訂的時候手上沒有任何一顆馬達的連續額定值可以對照。

影響:第一支手臂不改(它能動,而且用途是展示與教學); 但第三、第四支手臂改以連續額定為基準, 四支手臂的對照報告會把兩種基準並列,不會混在同一欄。

B1 決策:直接驅動,伸距 190 mm

先驗證「標準舵機該不該像 NEMA 17 那樣做成遠端驅動」。 A1 之所以把步進馬達移到底座,是因為它 280 g、是 SG90 的 31 倍。 FT5425BL 只有 67.6 g:

酬載直接驅動遠端驅動買到多少
100 g190 mm252 mm+33%
200 g143 mm182 mm+28%
500 g不可行80 mm—

兩顆舵機只佔靜態力矩的一小部分(306 mm 時 0.31 N·m 中的 0.11 N·m), 遠端驅動只買到 28–33% 伸距,卻要付出兩組同步帶、張緊機構與背隙。 標準舵機留在關節上是對的——這是算出來的,不是照慣例假設的。

B1 定案值
傳動直接驅動,每個關節一顆
伸距190 mm(上臂 105 / 前臂 85)
設計酬載100 g
肩關節力矩0.651 N·m = 69.9% 連續額定、23.3% 堵轉
舵盤索引25T → 14.4°/齒(整齒約束,同 SG90 的 21T)

與第一支手臂對照,這才是有意義的比較:

手臂伸距酬載扭矩依據
SG90202 mm4 g44.7% 堵轉(≈134% 連續)
FT5425BL190 mm100 g69.9% 連續額定

不是「標準舵機做出更短的手臂」——是伸距相當、酬載 25 倍, 而且待在連續工況內。

B2 CAD:直驅關節的三件事佔同一塊空間

直驅關節有三個東西在同一個位置:舵機、 夾住它的叉臂(屬於下連桿)、 被舵盤帶動的輪轂(屬於上連桿)。 第一版把上連桿畫成從關節軸開始的實心樑,於是三者重疊—— 算圖出來是一根融成一體的柱子,完全看不到關節。

問題症狀根因
拓樸重疊算圖是一根柱子三個實體佔同一空間
前臂裂成 3 個實體T0 會擋耳片沒包過關節軸就合攏,跨接槽從端面切穿
包絡 66.6 而非 40.0沒有斷面有這個寬度loft 預設是樣條,斷面突降時外凸
八個螺栓孔僅 79% 材料T10 擋下Cylinder 第一個參數是半徑,Ø9 寫成了 Ø18

參數掃描:耳片再厚也沒用

T10 報「八個舵盤螺栓孔只有 2 mm 要求的 79%」。 直覺是耳片太薄,於是把耳片厚度從 3.90 加到 6.0、再加到 10.0—— 三次都是 79%。

改動結果
耳片 3.90(基準)最低 79%(8 孔)
耳片 6.0最低 79%(8 孔)
耳片 10.0最低 79%(8 孔)
螺栓圓移到 R=13通過
孔徑縮到 Ø2.2通過

後兩列才指出約束是徑向的、不是壁厚。 追進去發現 Cylinder(9.0, 200.0) 的第一個參數是半徑: 我要的是 Ø9 的舵盤讓位孔,實際做出 Ø18, 螺栓孔緣離孔壁只剩 0.61 mm。

不掃參數的話,我會一路加厚耳片而永遠修不好。 「猜一個原因去修」和「量哪個變數真的驅動這個數字」是兩件事。

三個拍出來的數字改為由約束推導

常數原本改為
HUB_HSB_L*0.85 = 34.51跨接槽 + 2×(螺栓半徑 + R7 邊距) = 35.80
END_SOLID20.0(硬寫)輪轂伸出 + 螺栓位置 + 邊距 = 40.0
HORN_BOLT_R8.0(硬寫)由舵盤孔直徑推導 = 7.85/軸

驗證結果

層結果
T0 幾何完整性8/8(2 項跳過:尚未產出網格與連桿屬性)
T8 可組裝性5/5(螺絲起子伸得到、無干涉)
T10 可列印性5/5

接上 ArmBundle 只花了三行——這正是當初做那層抽象的目的。

實測質量回推,B1 的尺寸站得住

項目質量 g力臂 mm力矩 N·m
upper_arm79.042.60.033
forearm65.3133.90.086
j3 舵機67.6105.00.070
j4 腕舵機67.6190.00.126
夾爪50.0190.00.093
酬載100.0230.00.226
肩關節合計0.633

67.9% 連續額定(B1 用估計質量算的是 69.9%)。 實測連桿比估計重 10%,但質心比「連桿中點」的假設更靠內 (上臂 42.6 mm 而非 52.5),兩者相抵之後比原估計還好一點。空載 43.7%。

B3 URDF/MJCF:極限有兩個作者

NEMA 17 那支的關節極限只有一個來源——步進沒有自身行程,機構就是極限。 這支相反:舵機有硬性的 180°,怎麼樣都過不去。 所以每個關節的極限是兩個獨立約束的交集:

關節機構掃描舵機行程生效綁住的是
j1 迴轉±150°±90°±90°舵機
j2 肩±75°±90°±75°機構
j3 肘±95°±90°±90°舵機

取交集不是重點,記錄「哪一邊綁住」才是——兩者的意思相反: 機構綁住代表改幾何可以放寬;舵機綁住代表幾何幫不上忙, 只能重新索引舵盤,而那是拿一端換另一端。 只報一個數字而不說是誰造成的,就會有人去加厚一面牆, 想買一段舵機本來就不會給的行程。

#49 掃出來的肩關節行程是 0°——連續三次,三個不同原因 已修正

掃描把實體轉到干涉為止。前三次跑出來的肩關節範圍是 [+5, −5](負寬度)、然後 [0, 0]、再一次 [0, 0]。 每一次都是不同的原因,而且每修好一個才看得見下一個:

第幾次根因
一:[+5, −5]跨接槽用叉臂的半邊長(23.9)挖, 註解卻寫「half-diagonal」——真值是 29.7,叉臂角落卡在輪轂實心區
二:[0, 0]零位就相交 4667 mm³: 舵機截面的 X/Y 寫反了(舵機 40.6 在 X、20.0 在 Y, 我寫成 X=26.8 裝不下、Y=46.6 撞耳片)
三:[0, 0]耳片往下伸 34.3,旋轉時最低點掃到軸下 41.5, 而肩軸只在轉盤面上 36——耳片掃到圓盤

共通點:這三個數字全是我拍的,不是從它們要配合的東西推導出來的。 改成推導之後:

YOKE_R      = √((SB_L/2+WALL)² + (SB_H/2+WALL)²)   叉臂在輪轂座標系掃出的圓盤
HUB_REACH   = YOKE_R + 間隙 + 4                     耳片必須包過那個圓盤
HUB_SWEPT_R = √((SB_L/2+WALL)² + HUB_REACH²)        耳片自己掃出的半徑
Z_J2        = 轉盤面 + HUB_SWEPT_R + 1.5            肩軸高度

還有一個結構認知的錯誤:我把耳片在關節下方也接起來, 於是叉臂沒有路徑往下接回轉盤——轉盤因此變成 3 個分離的實體。 真實的伺服 U 型接頭是在舵機上方合攏、下方留兩片自由板, 把跨接槽加上向下的開口才對。

#50 docstring 宣稱了 MuJoCo 做不到的事 靜默 已修正

MJCF 產生器的說明寫著速度上限「以關節速度限制放進去」。 MuJoCo 沒有關節速度上限這種東西,而程式也確實沒寫進 XML—— 那句話是一個只存在於散文裡的限制。

0.08 s/60° = 13.1 rad/s,在 190 mm 的手臂上是尖端 2.5 m/s。 忽略它,模擬就會允許手臂做出舵機做不到的動作。

修法:說清楚 MuJoCo 放不下,改由 B4 的模擬迴圈執行—— 和步進的發步率上限放在同一個地方。並在 B3 加一條檢查驗 MAX_RADPS 有被匯出,因為只寫在註解裡的限制等於不存在。

B3 驗證層(27 項,變異測試 5/5)

刻意把幾條拆成兩句話,因為「數字對」和「關係對」不是同一件事:

B4 模擬:伺服的失效不是漂移,是「一直撐著然後燒掉」

步進手臂問的是「有沒有失步」。伺服問不出這個問題——它永遠知道自己在哪。 它的失效安靜得多:撐住、繼續撐、過熱。 所以這一層報的是工作時率,不是漂移。

#51 我把關節速度夾在額定值,藏掉了最該報告的事件 靜默 已修正

#50 說速度上限要在模擬迴圈裡執行。第一版夾在設定點的迴轉速率, 關節本身仍衝到 14.21 rad/s(資料表的 109%)。於是我改夾關節速度—— 先夾在 mj_step 之後(沒用,位置已經走完了), 再移到之前。三次都沒對。

追進去看那一刻發生什麼,才發現方向根本錯了:

k=744  肩 -75.13°   nefc 0
k=745  肩 -75.36°   nefc 1   ← 越過機構極限 -75°,約束啟動
       肘速度單步 -9.86 rad/s(≈9863 rad/s²,是致動器上限 913 的十倍)

(ncon 是接觸數;關節極限在 MuJoCo 裡是約束, 不出現在那裡。查錯欄位讓我多繞了一圈。)

那不是舵機在驅動,是手臂撐不住、被重力反驅動、然後撞進極限, 衝擊把前臂甩到 21.7 rad/s。

0.08 s/60° 限制的是舵機能驅動多快,不是別人能對它做多快。 夾住關節速度會把整件事抹掉——而那正是這次模擬最該講的事。 改成分開報「自由運動速度」與「含撞擊速度」,並在撞到極限時明講。

#52 資料表的速度在這支手臂上不能用 已納入設計

照資料表 13.09 rad/s 下指令,酬載 100 g 時:

指令速率佔資料表肩峰值佔額定撞極限追蹤誤差
13.09 rad/s100%0.951102%是48.7°
6.54 rad/s50%0.55359%否20.0°
3.27 rad/s25%0.51555%否8.4°
1.31 rad/s10%0.51455%否4.1°

60° 的肩部動作以滿速下達,會過衝 15° 撞進 −75° 的機構極限, 而且拉到連續額定的 102%。減半就完全不撞,扭矩掉到 59%; 再減到 1/4 幾乎沒有額外好處——50% 就是那個轉折點,是量出來的不是挑的。

這是伺服版的「datasheet 300 rpm 韌體開不出來」: 0.08 s/60° 是空載值,帶著 190 mm 手臂根本跑不到。 B5 的韌體必須限速到這裡。

靜態保持 vs 動態運行:兩個不同的酬載上限

問題答案
空載靜態最壞姿態0.401 N·m = 43% 額定(肩 −75°、肘 −10°)
能保持的酬載上限≈ 235 g
能運行的酬載(滿速)< 50 g(過衝就撞極限)
能運行的酬載(限速 50%)100 g 用 59% 額定

「撐得住」和「動得了」是兩個數字,而且差 4 倍以上。 B1 的靜態預算算的是前者——同 #34 那一類: 受限集合的最大值不是可達集合的最大值。

B4 驗證層(10 項)

刻意把「限速有效」拆成三條:會撞極限、限速後不撞、以及扭矩顯著下降。 只驗最後一條的話,一個把限速寫成無效的模型仍會通過。 另外驗「read() 回報的是指令不是軸位置」—— 四支手臂裡只有 DM-J4310 報得出真實位置,模型不可以假裝別的做得到。

這支手臂的尺寸是暫定的,而且程式會一直這樣說

上面每一個數字都建立在「額定 9.5 kg·cm」上, 而那個值只有單一經銷商來源,且剛好是堵轉的 1/3。 sizing_ft5425bl.py 每次執行都會印出 BUDGET_UNVERIFIED_BASIS 並說明:真值若是堵轉的 1/4, 伸距要再縮約 10%。

不擋住工作,但也不讓「沒驗證」這件事悄悄消失—— 這跟 #44 那個裝飾了一整段時間的旗標是同一個教訓。