從你自己的 CAD 圖,到一隻真的會動的機器人。這份手冊把整條路拆成十一個步驟,每個數字都來自實際的原始碼。
這是 Microduck 策略每 20 毫秒讀進去的觀測向量。它由六段組成,六段全部來自真實機器人身上量得到的東西——這不是巧合,是被刻意設計成這樣的。
整份手冊的主旨就在這張圖裡。你設計自己的機器人時,這 61 個格子的內容會完全不同——但「每一格在真機上都必須拿得到」這條規則不會變。違反它,模擬裡跑得再漂亮,搬到真機就是一堆空欄位。
全篇分成三種資訊,用顏色區分,不用回頭找出處:
直接從 microduck_rl 原始碼讀出來的數字、檔名、指令。這些是事實,不是估計。
官方開發日誌(CLAUDE.md)裡記錄下來的教訓,每一條都是用實際除錯時間換來的。這類內容最值錢,因為它們通常不會寫在教學文章裡。
強化學習與機器人學的一般原理,換任何機器人都成立。
閱讀順序建議照編號走,不過有三個節點可以先挑著看:
最後附了名詞速查表,MJCF、ONNX、BAM 這些縮寫忘記了可以回去查,每個詞都標了在哪一節有完整說明。
這是最容易一開始就走錯的地方。很多人打開 microduck_rl,開始改裡面的檔案、改名字,想把它「改造」成自己的機器人。這個起點是錯的。
把 microduck_rl 整包複製 → 改名字 → 一個一個改參數,直到它變成我的機器人。
問題:你會一直在跟「鴨子留下來的假設」打架,而且分不清哪些數字是通用的、哪些是鴨子專屬的。
先回答「我的機器人長什麼樣、有哪些感測器、RL 看得到什麼、控制得了什麼」,再把答案寫成一份 mjlab 設定。
microduck_rl 的角色:教科書範例。看它怎麼寫,不要住在裡面。
microduck_rl 目前註冊了 18 個任務,全部共用同一套框架。這 18 個就是你最好的參考範本庫:走路(平地/崎嶇)、走路+跌倒自復原、站起來、坐↔站、地面撿取、踢球、前滾翻,以及六種輪滑相關任務。
在鑽進任何一個細節之前,先把整條路看一遍。下面每個方塊都是一個具體的產出物——一個檔案或一份資料,不是抽象概念。
MuJoCo 看不懂你的 SolidWorks 檔案。它需要的是另一種描述,回答這幾個問題:這台機器由哪些零件組成?零件之間怎麼連?哪裡可以轉?多重?重量分布在哪?哪些地方會撞到東西?
這份描述叫 MJCF,本質上就是一個 XML 檔。CAD 描述的是「長什麼樣」,MJCF 描述的是「怎麼動」。
| 要填什麼 | 意思 | 舉例 |
|---|---|---|
| 連桿 | 剛性的零件本身,以及它的長度與形狀 | 大腿 120mm、小腿 130mm |
| 關節 | 零件之間可以轉動的地方,以及轉軸方向 | hip_pitch、knee、ankle |
| 活動範圍 | 每個關節轉得到哪裡,超過就是機構撞死 | 膝蓋 −120° ~ +10° |
| 質量 | 每個連桿多重 | 大腿 48g、小腿 22g |
| 慣量 | 重量「分布」在哪裡,不只是總重 | 見下方說明 |
| 碰撞幾何 | 哪些表面會跟地面或自己碰撞 | 腳底板、身體外殼 |
兩根一樣重的棍子,一根重量集中在手握處、一根集中在末端,甩起來的感覺完全不同——後者難甩得多。機器人甩腿、轉頭時,這個差異會直接改變它的動態。只給總重而不給分布,模擬算出來的動作會跟真機對不上。
好消息是:慣量通常不用自己算。CAD 軟體知道每個零件的形狀和材料,可以直接算出來,匯出工具也會一併帶走。
下面是 Microduck 的分件與實際重量。這張圖剛好示範了 MJCF 需要的資訊長什麼樣子——每個色塊是一個連桿,旁邊的公克數就是它的質量。注意頭部總成 189g,是整機最重的單一零件。
官方開發日誌寫得很直白:目標高度這類數字,一定要從模擬裡的實際機器人量出來,絕對不要從舊版本沿用。曾經有一個站立目標高度差了 5mm,結果那個目標在物理上根本站不到,團隊卡了好幾天才發現問題不在獎勵函數、而在那個數字本身。
MJCF 是 MuJoCo 自己的模型描述格式,本質就是一個 XML 檔(副檔名 .xml)。你在上面看到的 robot_walk.xml 就是一份 MJCF。
它的核心設計是:巢狀結構代表機構連接。零件包在零件裡面,包法就是實際的連接順序。看一段真實寫法就懂了:
<body name="left_thigh" pos="0 0 -0.03">
<joint name="left_hip_pitch" type="hinge" axis="0 1 0" range="-90 90"/>
<geom type="capsule" fromto="0 0 0 0 0 -0.06" size="0.008" mass="0.048"/>
<body name="left_shin" pos="0 0 -0.06">
<joint name="left_knee" type="hinge" axis="0 1 0" range="-120 10"/>
<geom type="capsule" fromto="0 0 0 0 0 -0.05" size="0.007" mass="0.022"/>
</body>
</body>
三個標籤分工很清楚:
<body> 一個剛體(連桿)。pos 是它相對於上一層的位置。小腿寫在大腿的 <body> 裡面,就代表小腿長在大腿下面——這個巢狀關係就是運動鏈。<joint> 這個零件怎麼轉。type="hinge" 是鉸鏈(單軸旋轉),axis 是轉軸方向,range 是活動範圍。<geom> 形狀跟質量。它同時負責兩件事:碰撞判定用的形狀,以及這個零件多重。複雜外型會改成 type="mesh" 指向一個 STL 檔。<body> 寫在大腿裡面,實體上小腿就接在大腿下面。寫在某個 <body> 裡的 <joint>,描述的是「這個零件相對於它上一層」怎麼轉,不是它跟下一層之間。所以大腿的 <body> 裡寫的是髖關節(大腿接到機身的地方),膝關節則寫在小腿的 <body> 裡。第一次讀別人的 MJCF 時,這點最容易看反。
一份完整的 MJCF 除了機器人本身,還會描述整個場景:地面、重力、光源、要踢的球,以及 <actuator>(哪些關節是馬達驅動的)跟 <sensor>(模擬哪些感測器)。
range 的角度單位預設是弧度,除非檔案開頭寫了 <compiler angle="degree"/>。照抄別人的片段時,這個沒對到會讓活動範圍差一個數量級——寫 -120 10 本來想要 −120°~10°,結果變成 −120 弧度(約 −6875°),關節等於完全沒有限制。
如果你熟 ROS,MJCF 的地位相當於 URDF——同一類東西,但 MJCF 是 MuJoCo 專用,能描述 URDF 表達不了的接觸參數、肌腱那些。onshape-to-robot 這類工具兩種格式都匯得出來。
Onshape 是一套 CAD 軟體,跟 SolidWorks、Fusion 360 同類型。特別的地方是它完全跑在瀏覽器裡,不用安裝,檔案存在雲端。個人非商業用途有免費方案,但免費版的專案是公開的。
它之所以跟這個專案有關,是因為 Pollen 當初就是用 Onshape 畫 Microduck,然後用 onshape-to-robot 直接匯出成 MJCF。那支工具是專門為 Onshape 寫的——它透過 Onshape 的 API 去讀取零件結構、相對位置、質量,自動組成模擬器要的格式。
onshape-to-robot 直接可用,連桿層級、關節位置、質量慣量一次帶出來。
代價:要接受雲端 CAD,免費方案的專案是公開的。
匯出 STL,再自己手寫 MJCF 的骨架把連桿層級接起來;或者找對應你那套軟體的轉換工具。
代價:多一段工,關節位置與慣量要自己核對。
兩條路都走得通,差別只在前者有現成的自動化管線。如果你已經熟悉某套桌面 CAD,不必為了這個改用 Onshape——手寫 MJCF 骨架並不難,難的是量測數字要正確。
你自己的機器人應該在 src/<你的套件>/robot/ 底下開一個新資料夾,仿照現有結構擺放。
Microduck 的機器人資料夾裡有好幾個 XML,對應不同用途的模型:robot_walk.xml(走路用,碰撞幾何較精簡,跑得快)、robot_allcollisions.xml(全碰撞,站起來/地面撿取用)、*_rollers.xml(加輪子)、*_backlash.xml(每個關節串一個 ±1° 的被動齒隙關節)。同一台機器人會有多個模型檔,依任務挑用——這是值得抄的架構。
RL 輸出的不是「膝蓋轉到 30 度」這種指令就結束了。中間還有一層:真實的馬達收到目標角度之後,會用多大的力、多快去追這個目標?追得到嗎?負載重的時候會掉速嗎?停住的時候會抖嗎?
這層就是馬達模型。模擬裡如果沒有它,你等於假設馬達是完美的——而真實馬達從來不完美。
看目前角度跟目標角度差多少,再看目前轉速,算出一個力矩。白話版:「你還差 10 度,那我就用這麼大的力把你推過去。」
適合:剛開始,先讓整套 RL 系統能跑起來。之後再慢慢加真實特性。
拿真實馬達上測試台,量出它在各種電壓、負載、速度下的實際行為,建成模型放進模擬器。
適合:要真的搬到實機。模擬與真機的落差,有很大一部分來自這裡。
Microduck 用的是 BAM,官方描述為「電壓控制的 XL330 模型,摩擦力由致動器自行計算」。也就是說它模擬的不是理想力矩源,而是「一顆吃 7.4V、有內阻、有摩擦的真實伺服」。如果你也用 XL330,這份模型可以直接沿用;換別顆馬達,就得自己上測試台量一份。
兩者都是:一套建模方法(那些數學),加上實作它的程式碼。
BAM 是 Better Actuator Model 的縮寫,由法國 Rhoban 團隊開發——那是波爾多大學的機器人實驗室,長期參加 RoboCup 人形足球,對「模擬跟真機差在哪」這件事累積了很多經驗。
它的做法是把伺服當成電壓驅動的馬達來建模,而不是理想力矩源。輸入是電壓,模型內部去算摩擦、反電動勢這些,再推出實際輸出的力矩。參數不是憑空設的,是把真實馬達裝上測試台實際量出來的——這也是為什麼官方 repo 裡有 xl330_test_bench 那個治具(一顆馬達加一根配重手臂)。
它不是你會打開的應用程式,而是一個跑在模擬器裡的程式庫。在 microduck_rl 裡,BAM 以致動器類別的形式存在,寫在 src/mjlab_microduck/actuator.py,設定檔 import 進來用,例如 FrictionDRBamActuatorCfg。
所以「用 BAM」的實際意思是:在你的設定檔裡指定用這個致動器類別,並給它一組從真實馬達量出來的參數。
BAM 之下,MuJoCo 原本的關節摩擦欄位 dof_frictionloss 是被歸零的。你如果照一般教學去隨機化這個欄位,程式不會報錯、訓練照跑,但那段設定完全沒有作用——是個安靜的空操作。正確做法是去縮放致動器自己的 friction_scale。這種「不報錯但無效」的陷阱最難抓。
一句話講完:觀測空間裡只能放真實機器人量得到的東西。
聽起來像廢話,但這是模擬訓練搬到真機時最常見、也最致命的失敗原因。原因在於,模擬器知道的事情遠比真機多。
就這樣。沒有腳底力感測器,沒有外部定位系統,不知道自己在房間裡的哪個位置。
假設你在觀測裡偷偷加了「腳底接觸力」。訓練過程中,策略會發現這是個超好用的訊號:接觸力一變化,就知道該換腳了。模擬裡它走得非常漂亮。
然後你把它放到真機上。真機沒有那顆感測器,那幾個欄位只能餵零或餵雜訊。策略最依賴的輸入消失了,它立刻不知道自己在幹嘛——摔倒。
糟糕的是,這種失敗在模擬階段完全看不出來。你會以為問題出在別的地方,然後浪費好幾天找錯方向。
| 區段 | 維度 | 內容 | 真機從哪來 |
|---|---|---|---|
gyro | 3 | 機身三軸角速度 | IMU 陀螺儀 |
projected_gravity | 3 | 重力在機身座標的方向,等於知道自己傾斜多少 | IMU 加速度計 |
joint_pos | 14 | 14 顆伺服的目前角度 | 馬達編碼器 |
joint_vel | 14 | 14 顆伺服的目前角速度 | 馬達編碼器 |
last_action | 14 | 上一次策略自己輸出的 14 個目標角度 | 程式自己記得 |
command | 13 | 移動指令 3+頭部姿態 4+身體姿態 6 | 你的遙控器/App |
沒有一項需要真機裝額外的感測器。這是設計的結果,不是運氣。
官方把這 61 維訂為整個策略家族共用的硬性契約:走路、站起來、踢球、輪滑……每一個策略都必須是 61 維,一模一樣的排列順序。原因是真機執行時要能熱切換策略——按一個鍵就從走路切到站起來。某個任務用不到的欄位怎麼辦?補零,但絕對不能刪掉。刪了維度就對不上,ONNX 根本載入不進去。
IMU 是 Inertial Measurement Unit(慣性量測單元),一顆實體晶片,通常同時包含兩種感測器:
gyro 那 3 維。projected_gravity 那 3 維。Microduck 裝了兩顆(機身一顆、頭部一顆),型號是 LSM6DSV16X。
這個限制會直接影響你的觀測空間設計:不要放任何需要絕對位置才算得出來的東西。策略只知道自己正在怎麼動,不知道自己在哪裡——它就像閉著眼睛走路,靠平衡感而不是靠看路。
順序不是「先買馬達,之後再想 RL 要什麼資料」。是反過來的。
一般 PWM 舵機是單向的:你告訴它「去 90 度」,它說好,然後就沒有然後了。它不會告訴你「我現在實際在 87.3 度」。這叫開迴路——你永遠不知道它到底在 85 度還是 94 度。
而這個迴圈的第一步就是「讀 14 顆編碼器」。讀不到,joint_pos 和 joint_vel 這 28 個欄位就是空的,占了 61 維裡的 46%。整套方法從根本上不成立。
Dynamixel 這類智慧型伺服之所以是這類專案的標配,就是因為它回報得了目前位置、速度,部分型號還回報負載與電流。這不是品牌偏好,是方法論的硬性要求。
訓練時對 IMU 加的隨機擾動是零中心的——它訓練出來的是「對隨機晃動的容忍度」,治不了系統性的安裝偏差。如果你的 IMU 裝歪了一個固定角度,每次都偏同一邊,再怎麼訓練也解決不了。官方原文直接寫明:那是執行時的校正問題,不是訓練問題。
動作空間就是在回答一個問題:RL 到底能控制什麼?通常答案就是「每一顆受控馬達的目標角度」,所以維度等於受控自由度數量。
Microduck 的動作是 14 維,對應 14 顆受控伺服。注意這跟整機馬達數不一樣——實體有 15 顆,第 15 顆驅動鴨嘴,不歸策略管。「機器人有幾顆馬達」和「RL 控制幾顆」是兩個不同的數字,設計時要分清楚。
| 索引 | 部位 | 關節 |
|---|---|---|
0–4 | 左腿 | hip_yaw, hip_roll, hip_pitch, knee, ankle |
5–8 | 頸與頭 | neck_pitch, head_pitch, head_yaw, head_roll |
9–13 | 右腿 | hip_yaw, hip_roll, hip_pitch, knee, ankle |
每條腿 5 個自由度:髖部三軸(偏擺、側傾、前後)、膝、踝。這是雙足機器人相當典型的配置。
不要在程式裡寫死關節索引。加了輪子或齒隙模型之後,被動關節會插進序列中間,原本的 0–13 就整個位移了。官方的做法是提供一組輔助函式去解析,在單純模型上是恆等對應,在複雜模型上自動校正。另外,所有不受控的關節一律以 passive_ 開頭命名,選擇器再用正規表示式排除——這個命名慣例很值得抄。
獎勵函數就是 RL 的評分標準——你不是在教它「怎麼走」,而是在定義「什麼叫走得好」,剩下的動作細節讓它自己試出來。
大致長這樣:往前走得越快加越多分、摔倒扣大分、動作抖動扣一點分、浪費電力扣一點分。策略慢慢就會學成「往前走,但別摔倒,也別亂耗力」。
獎勵是整個流程裡最需要自己動腦、也最沒辦法抄的部分。架構可以參考,數值不能直接相信——一組對著矮胖鴨子調出來的權重,套到高瘦雙足機器人身上,通常直接學不起來。
下面這些全部來自官方開發日誌,每一條都標註是實際踩過的。對第一次設計獎勵函數的人來說,這是整份手冊性價比最高的一段。
專案裡有兩種懲罰寫法:一種回傳正值、要配負權重;另一種自己已經回傳負值、要配正權重。配錯就是雙重否定——本來要罰的行為變成有獎勵,策略會拚命去做。實際後果包括學會用屁股蹦跳、故意墜坐。萬無一失的檢查法:每次訓練,監看面板上每一個懲罰項的數值都必須 ≤ 0。
任何你沒講清楚的自由度,它一定會鑽。要它前滾翻,它學會用力甩頭代替翻滾;要它側滾,它用肩膀滾而不是照你想的軸向;要它站起來,它學會用頭當三腳架撐住。「什麼才算完成這個動作」必須寫成硬性的狀態閘門(支撐點接觸、姿態軸向檢查、狀態鎖存),不能只靠幾個小小的扣分去暗示。
任何「到達某狀態就給分」的獎勵,如果到了之後每一步都繼續領,那就是頭獎——策略會用任何暴力手段衝過去,因為早到就是多領。做法是追蹤一個等速推進的內部目標,超前於進度不給分,於是「慢慢來」才是最佳解。單純加個速度上限懲罰沒有用,那個成本是有限的,策略算得出來衝過去比較划算。
如果「倒下」或「趴低」這種狀態底下掛著某個正分項目,策略會找出最省力的合格姿勢,然後停在那裡一直領。改用「進步才給分」的寫法:姿態每往上改善一點就付一點分,維持不動付零分,這樣就farm 不了。設計休息類任務時,要逐一檢查每個正分項目對照各種癱倒姿勢——只要癱著還能拿到大部分分數,它就會去癱著。
動作阻礙型(角速度、角動量懲罰)會懲罰劇烈動作本來就需要的東西,做特技類任務時權重要壓低。平滑型(動作變化率)只抑制抖動、不擋大幅慢動作,比較安全——但要等技能學會之後再逐步加上去。在還在摸索困難動作的階段就課這種稅,「什麼都不做」會變成最佳解。
真實案例:頭部在走路時會下垂約 15 度。直覺反應是把頭部追蹤的容忍度調緊——結果策略乾脆完全不走了,因為一顆佔全身 38% 質量的頭在走路時必然會晃,那個誤差躲不掉,站著不動反而分數更高。正確做法是只針對躲得掉的部分收費(那個固定的下垂偏移),讓躲不掉的晃動自行抵消。
這張表可以直接當成開工時的判斷依據。
| 項目 | 為什麼 | |
|---|---|---|
| 可以沿用 | mjlab 框架本身 | 它本來就是通用的,跟你做什麼機器人無關 |
| 可以沿用 | PPO 訓練迴圈 | 同上 |
| 可以沿用 | 獎勵工具函式庫 | 那些是數學工具,不含鴨子的假設 |
| 可以沿用 | 程式架構與檔案組織 | 設定檔怎麼寫、任務怎麼註冊,照抄就好 |
| 可以沿用 | 開發方法論 | 先跑煙霧測試、檢查符號、不要一次改十個地方 |
| 可以沿用 | BAM 馬達模型 | 但前提是你也用 XL330 |
| 不能沿用 | 訓練好的權重檔 | 裡面學到的是鴨子的身體、質量、關節動態。維度不同的話連載入都載入不了 |
| 不能沿用 | 獎勵權重數值 | 那組數字是對著鴨子的體型調出來的 |
| 不能沿用 | 觀測/動作維度 | 你的自由度數量不同,整個向量就不同 |
| 不能沿用 | 目標高度等物理常數 | 必須從你自己的模型量出來 |
一句話總結:架構可以參考,數值不能直接相信。
雙足是強化學習裡最難的題目之一,原因很物理:支撐點太少。
這對訓練效率的影響很直接。雙足在學會之前,每一次嘗試常常是「站起來 → 走一步 → 重心偏掉 → 摔倒 → 這回合結束」,能收集到的有效資料很少。四足則是「站著 → 抬一隻腳 → 還有三隻撐著 → 調整 → 繼續」,學習空間寬容得多。
既然是自創,形態你自己決定。如果設計上能多幾個接觸點——四足、輪式、輪腿、三點支撐——訓練難度會降不只一個檔次。先用比較好訓練的形態把整套流程跑通一遍,確定自己掌握了 CAD→MJCF→訓練→部署的每一環,再挑戰雙足,會少走很多冤枉路。
另一個相關的提醒:不要拿人類的速度直覺去限制小機器人。一台 25 公分高的機器人翻滾時,3.5–5.5 弧度/秒是它的自然速度。如果你照人類的感覺加上轉速上限,等於在禁止它做物理上正常的動作。要壓制粗暴行為,應該去罰衝擊力和抖動,不是罰轉速。
寫好設定之後,要在 tasks/__init__.py 裡登記,它才會變成一個合法的任務代號。實際長這樣:
# 官方 Microduck 走路任務的登記方式,照這個格式改成你的
register_mjlab_task(
task_id="Mjlab-Velocity-Flat-MicroDuck", # 你自己取的代號
env_cfg=make_microduck_velocity_env_cfg(), # 你寫的設定 ← 只有這裡要花心思
play_env_cfg=make_microduck_velocity_env_cfg(play=True),
rl_cfg=MicroduckRlCfg, # 通常沿用
runner_cls=MicroduckOnPolicyRunner, # 通常沿用
)
五個參數裡,真正屬於「你的機器人」的只有 env_cfg 那一個——獎勵、觀測、終止條件都寫在裡面。另外兩個(rl_cfg 學習率那些、runner_cls 訓練迴圈機制)跟你做什麼機器人無關,直接沿用。
| 指令 | 做什麼 |
|---|---|
uv run list-envs | 列出目前所有已登記的任務,確認你的有登記成功 |
uv run train <任務> --env.scene.num-envs 64 --agent.max_iterations 5 | 煙霧測試,永遠先跑這個 |
uv run train <任務> --env.scene.num-envs 4096 | 正式訓練(加 --hf-jobs 送雲端 GPU) |
uv run play <任務> --wandb-run-path <...> | 開 3D 檢視器看訓練好的策略實際跑 |
uv run scripts/export.py <任務> --wandb-run-path <...> | 匯出 ONNX,準備上真機 |
uv run scripts/infer_policy.py --walking out.onnx | 在電腦上預演部署,用鍵盤操控 |
官方原文:64 個環境、5 次迭代的煙霧測試,能用幾分錢的成本抓出約 95% 的設定錯誤。絕對不要沒跑它就啟動長時間訓練。它會檢查:能不能建起來、步進時有沒有數值爆掉、觀測維度對不對、每個獎勵項算不算得出來、ONNX 匯不匯得出去。
ONNX(Open Neural Network Exchange)是一種神經網路的檔案格式,副檔名 .onnx。可以把它想成神經網路界的 PDF:不管用什麼軟體做出來的,存成這個格式後,到哪裡都打得開、都跑得動。
它在這條流程裡的位置很關鍵——訓練和執行是兩個完全不同的世界。訓練在電腦上用 Python 和 PyTorch 跑,吃 GPU;但機器人身上跑的是另一套東西(官方版是 Rust,開源版是 Pi 上的 Python)。兩邊語言、框架、硬體全都不一樣。ONNX 就是雙方都認得的中介格式。
是已經訓練完成的成品:網路的結構,加上學好的權重數值。它只負責做一件事——把輸入的觀測向量換成輸出的動作向量。官方版是「61 維進、14 維出」。
它不含訓練邏輯,也不能再繼續學。想改進行為,只能回到訓練世界重跑,再匯出一個新檔案蓋掉。
匯出必須走官方那支 scripts/export.py,因為觀測正規化的參數要一起烤進檔案裡(就是上圖那個紅框)。自己手動轉檔會漏掉這段,而且在模擬器裡測試完全看不出來——模擬環境會自己補上正規化,所以你會看到它跑得好好的。等搬到真機才爆掉,而那時你會以為問題出在硬體。
前面十一節講的是 Pollen 官方那套。但如果你的目標是真的做一台出來,有另一條路繞過了兩個最大的障礙——自製電路板,以及逆向工程的公差問題。
最關鍵的差別在伺服控制那一段。官方版用的是一塊自製的小轉接板——也就是我們一路討論、但原廠從未開源的那塊。這個開源版本根本不走那條路:它直接用 ROBOTIS 自己賣的現成控制板 OpenRB-150,樹莓派透過 USB 接上去就好。
3D 列印檔就附在 repo 裡(microduck3D打印.3mf,5.3MB)。我實際解開驗證過,是完整可切片的專案檔:Bambu Lab P1S、5 個列印盤、PLA、0.2mm 層高、15% 填充、2 層牆、樹狀支撐、自動裙邊、0.4mm 噴嘴。這不是模擬用網格,是真的排好版可以直接送印的檔案。
| 類別 | 物料 | 數量 | 說明 |
|---|---|---|---|
| 主控 | Raspberry Pi Zero 2 W | 1 | 跑控制程式、藍牙手把、Wi-Fi、SSH |
| 伺服控制 | ROBOTIS OpenRB-150 | 1 | USB 接樹莓派,負責跟 XL330 匯流排通訊 |
| 伺服 | Dynamixel XL330-M288-T | 14 | 雙腿 10+頭頸 4。嘴部(ID 15)選配,走路模型不用 |
| 電池 | 成品 6V 充電電池包 | 1 | 不必自組 2S 電池,但要確認瞬時電流夠 |
| IMU | BNO080 / 085 / 086 模組 | 1 | I2C 接 GPIO2/GPIO3,程式會自動探測位址 |
| 儲存 | 16GB 以上 microSD | 1 | 刷入官方映像檔 |
| 結構 | 3D 列印件 | 1 套 | PLA,用 repo 裡的 3MF |
| 五金 | M2 / M2.5 自攻螺絲 | 若干 | 建議多備 |
| 線材 | Dynamixel 3-pin 線 | 若干 | 伺服串聯與分線 |
| 其他 | 電源開關 | 1 | 主電源 |
跟官方版相比,它沒有攝影機、沒有深度感測、沒有 NFC——它只做「會走路」這一件事。對第一次要把整條流程跑通的人來說,這反而是優點:變數少很多。
組裝前要先用 Dynamixel Wizard 一顆一顆設定 ID。設錯的話機器人會立刻摔倒,而且很難從現象看出原因。
| ID | 名稱 | ID | 名稱 |
|---|---|---|---|
1 | right_ankle 右踝 | 8 | left_hip_pitch 左髖俯仰 |
2 | right_knee 右膝 | 9 | left_hip_roll 左髖橫滾 |
3 | right_hip_pitch 右髖俯仰 | 10 | left_hip_yaw 左髖偏航 |
4 | right_hip_roll 右髖橫滾 | 11 | head_pitch 頭部俯仰 |
5 | right_hip_yaw 右髖偏航 | 12 | neck_pitch 頸部俯仰 |
6 | left_ankle 左踝 | 13 | head_yaw 頭部偏航 |
7 | left_knee 左膝 | 14 | head_roll 頭部橫滾 |
Dynamixel Wizard 建議參數:Protocol 2.0、鮑率 1Mbps、Return Delay Time 0、PWM Slope 255。另外要取消 Shutdown 裡的「輸入電壓錯誤」觸發項,否則電池電壓稍微波動就會誤停。
最省事的地方在這裡——官方提供 microduck.img.xz,系統、Python 環境、走路模型、手把服務全部裝好了。用 Raspberry Pi Imager 刷進 SD 卡、設好 Wi-Fi、SSH 進去就能跑。
映像檔的預設帳號是 user、預設密碼就是 password。第一次登入後立刻用 passwd 改掉——這台機器會連上你家的 Wi-Fi。
啟動控制程式後,鍵盤操作是:v 開關行走、方向鍵前後左右、x 速度歸零、i 顯示 IMU 資訊、q 停止。手把模式則是按住 START 兩秒啟動、A 開關行走、左搖桿移動、右搖桿轉向、B 停止、同時按住兩個扳機兩秒安全關機。
手把連上時,服務會自動關閉 Wi-Fi,因為藍牙和 2.4GHz Wi-Fi 會互相干擾。所以你會發現手把一連上,SSH 就斷了——這是正常的,關掉手把 Wi-Fi 就會自己回來。
我實際讀了它附的 walk.onnx:輸入 51 維,輸出 14 維。這剛好是第 05 節那個道理的活教材——維度是照你的機器人和任務決定的,不是抄來的數字。
| 部分 | 授權 | 意思 |
|---|---|---|
| 最外層包裝 | MIT | 最寬鬆,可商用 |
| 部署控制程式碼 | GPL-3.0-or-later | 改了再散布,衍生作品也必須開源成 GPL |
| 機構 CAD 檔 | CC BY-NC-SA 4.0 | 禁止商業使用 |
| 訓練環境 | Apache-2.0 | 可商用,保留聲明即可 |
兩個地方擋住:機構檔是 NC(禁止商業),跟官方版的限制一樣;而且控制程式碼是 GPL-3.0,比 Apache 嚴格得多——你改過的版本只要對外散布,就必須連同原始碼一起以 GPL 釋出。這兩點跟「開源」不衝突,但跟「做成商品賣」衝突。
ersgtbgertgestrg.obj、dfbdfbbbbb1.obj),分辨不出哪個是哪個零件,只能靠切片軟體裡的盤面預覽圖對照。如果你的目標是「有一台會動的鴨子」,買官方成品最省事。如果目標是「搞懂每顆螺絲跟每行程式在幹嘛」,這條開源路線是目前最完整的:列印檔、接線圖、程式碼、訓練環境、預燒映像全都有,而且不用自己畫電路板。
在寫任何一行程式之前,先把這幾題答完。勾選狀態會存在你自己的瀏覽器裡,下次打開還在。
整份手冊如果只記一件事,記這個:不要從「我要怎麼改 microduck」開始,要從「我的機器人長什麼樣、它量得到什麼、控制得了什麼」開始。把這些答案寫成 mjlab 的設定,microduck_rl 從頭到尾只是放在旁邊的參考書。
按出現順序排列。「詳見」欄指向本手冊有完整說明的章節。
| 名詞 | 一句話解釋 | 詳見 |
|---|---|---|
| MuJoCo | 物理模擬引擎,負責算「這樣施力機器人會怎麼動」。整套訓練都跑在它上面。 | 02 |
| mjlab | 架在 MuJoCo 上的通用機器人強化學習框架。你的專案是建在它上面的一份設定。 | 01 |
| Onshape | 跑在瀏覽器裡的 CAD 軟體。官方用它畫 Microduck,所以匯出工具是為它寫的。 | 03 |
| CAD | 電腦輔助設計,就是畫 3D 零件圖。描述「長什麼樣」。 | 03 |
| MJCF | MuJoCo 的模型描述格式,一個 XML 檔。描述「怎麼動」:連桿、關節、質量、慣量、碰撞。 | 03 |
| URDF | ROS 世界的同類格式。MJCF 能表達的接觸參數等細節它表達不了。 | 03 |
| STL | 純三角網格檔,只有形狀,沒有零件關係或質量資訊。 | 03 |
| onshape-to-robot | 從 Onshape 自動匯出 MJCF/URDF 的工具,會一併帶出質量與慣量。 | 03 |
| 慣量 | 重量「分布在哪裡」,不只是總重。決定甩腿轉頭時的動態。 | 03 |
| PD 控制器 | 最簡單的馬達模型:看位置誤差加上速度,算出該施多大力。 | 04 |
| BAM | Better Actuator Model。把伺服當成電壓驅動的馬達來模擬,參數從真實馬達量出來。是程式庫,不是應用程式。 | 04 |
| IMU | 慣性量測單元。陀螺儀量轉速、加速度計量傾斜。量得到「怎麼轉」,量不到「在哪裡」。 | 05 |
| Observation | 觀測空間。策略每一步看得到的所有數字。只能放真機量得到的東西。 | 05 |
| Action | 動作空間。策略每一步輸出的數字,通常是每顆受控馬達的目標角度。 | 06 |
| Reward | 獎勵函數。定義「什麼叫做好」,是最花腦力也最不能抄的部分。 | 07 |
| PPO | 一種強化學習演算法,這套流程用的訓練方法。屬於可以直接沿用的部分。 | 08 |
| Sim2real | 把模擬裡訓練好的東西搬到真機上。落差主要來自馬達模型、感測器與機構公差。 | 05, 12 |
| Domain randomization | 訓練時隨機擾動各種參數,讓策略對現實的不確定性有容忍度。注意:零中心的擾動治不了系統性偏差。 | 05 |
| 煙霧測試 | 用極小規模(64 環境、5 迭代)快速驗證設定沒錯。官方說能抓出約 95% 的設定錯誤。 | 10 |
| ONNX | 神經網路的通用檔案格式。訓練世界與機器人世界之間的交接點,裡面是訓練完成的成品。 | 11 |
| Dynamixel | ROBOTIS 的智慧型伺服系列。關鍵特性是會回報目前角度——這是整套方法的硬性前提。 | 05 |
| XL330-M288-T | 這些專案用的那顆伺服,18 公克級。BAM 那份參數就是針對它量的。 | 04 |
| OpenRB-150 | ROBOTIS 的現成伺服控制板,USB 接主機。開源版用它取代自製轉接板。 | 12 |
| 3MF | 3D 列印的專案檔格式,除了模型還帶著切片參數與排版。比 STL 完整。 | 12 |