MBC EXP6 六路馬達擴充器 × Pybricks

三個步驟用 MicroPython 控制 EXP6

寫 Pybricks 程式一定照這個順序:先匯入函式庫,再建立物件、幫 EXP6 取名字,最後才用這個名字去呼叫功能(轉馬達、讀感應器)。左邊一步一步做,右邊的程式會跟著長出來;在模擬 EXP6 上選每個擴充孔接什麼,就能看到馬達怎麼轉、程式會印出什麼。

你的主機:SPIKE Prime(EXP6 只能接 SPIKE Prime,不能接 EV3)。EXP6 要接上自己的電池,馬達才會動。
1

匯入函式庫

程式的第一件事是告訴 Pybricks「我要用 EXP6 的函式庫」。沒有這行,後面寫的 MBC_EXP6 主機看不懂,會出現 NameError。EXP6 只有這一個函式庫,不用選。

  1. 下載函式庫(存成檔案,檔名不要改):MBC_exp6_obj_Lib.py;檔名是 MBC_exp6_obj_Lib.py。
  2. 在 Pybricks Code 左邊檔案區按「Import a file」,把它匯入同一個專案。
  3. 檔名不要改(程式裡寫的就是 MBC_exp6_obj_Lib),也不要放進子資料夾。
  4. 回到主程式,在最上面寫下面這幾行(右邊程式標 ① 的地方)。
2

建立物件:幫 EXP6 取名字

要「建立一個物件」:告訴程式 EXP6 的 Host 線插在主機哪個孔,並幫它取個名字。之後要轉馬達、讀感應器,都是叫這個名字。

EXP6 的 Host 線插在主機哪個孔?

要不要開啟多工?

程式裡的 3 是主機的孔:1~6 = A~F(只能寫數字,不能寫成 Port.C)。後面功能括號裡的第一個數字,才是 EXP6 上的擴充孔 1~6,兩個不要搞混。

3

使用功能

寫法都是「exp6.功能名稱(擴充孔, …)」:名字+小數點+功能,括號裡第一個數字通常是 EXP6 上的擴充孔 1~6。點一個功能,程式和輸出會換成它的範例,模擬 EXP6 的馬達也會照著動。

模擬 EXP6(從上面看):選每個擴充孔接什麼,看馬達怎麼轉、右邊印出什麼

一開始孔 1、2 接馬達,孔 4 顏色、孔 5 超音波、孔 6 力量感應器,跟範例程式用的孔一樣。模擬畫面是示意:馬達速度 1% 當成每秒 10 度(實際要看馬達型號),感應器的數值也簡化過;紅色指針是轉軸的朝向,↻ = 順時針。拔掉擴充板時馬達會停,讀到的值都變成 0(不是上一次的值)。程式跑完後大約 0.5 秒,EXP6 的看門狗會讓馬達停下(轉角度還沒轉完的會先轉完);開多工並用函式庫的 run_task 時,程式一結束馬達就停。

每個功能的範例

35 個功能(函式庫全部的功能),每個都有一段範例。轉馬達、停止這類動作多半放在迴圈外只做一次;讀值放進迴圈一直讀。按「試試看」會切到第 3 步,右邊的程式和輸出會換成這個範例。

完整範例

兩輪小車走正方形(左輪孔 1、右輪孔 2)

        

!只改最上面「要改的地方」就好。轉不到 90 度:把 TURN 改大一點;轉太多:改小。邊太長或太短:改 SIDE(720 度大約 35 公分)。車子往後退:把 set_motor_inverted(1, True) 的 1 改成 2。

多工寫法(進階):光控開關

        

!建立物件時第 2 個參數寫 True,物件要放在 run_task() 外面;每個功能前面都要加 await。run_task 一定要從 MBC_exp6_obj_Lib 匯入:背景會自動送心跳,程式結束時馬達自動停。

跟 MBC 感應器一起用:循線小車

        

!這個範例把循行者 8 路直接插主機,循行者的函式庫 MBC_line8.py 也要匯入同一個專案。MBC 感應器也可以插在 EXP6 的擴充孔上,寫法見下面「MBC 感應器插在 EXP6」。

MBC 感應器插在 EXP6(循行者、測距者、掌控者、神攝手)

主機的孔不夠用時,MBC 感應器可以直接插在 EXP6 的 1~6 號孔,跟插在主機上一樣,插上就能用、不用另外設定。EXP6 韌體要 2026-11-03 以後。跟上面一樣三步:選感應器、選它插在 EXP6 的幾號孔、選功能,右邊的程式會跟著換;一般寫法和多工都可以。

1

匯入:核心函式庫+這款的產品檔

插在 EXP6 上的是哪一款?

除了核心 MBC_exp6_obj_Lib,還要匯入插上去那一款的產品檔(例如 from MBC_exp6_line import *,裡面有 LINE8、LINE16 這些名字)。為什麼分成好幾個檔:Pybricks 主機的程式(你的程式加上全部函式庫)上限大約 52 KB,全部放進去會超過,所以用到哪款才載入哪款。

    2

    建立物件:先 EXP6,再感應器

    感應器插在 EXP6 的幾號孔?

    要不要開啟多工?

    3

    使用功能:名稱跟直插主機一樣

    完整範例:循行者 8 路插 EXP6 做 PD 循線

    PD 循線(循行者 8 路插 EXP6 第 5 孔、左馬達擴充孔 1、右馬達擴充孔 2)

    函式名稱、回傳值都跟感應器直接插主機時一樣(例如循行者的 pos100()、width())。多工模式每個函式前面都要加 await,等待直接用 wait:匯入的 run_task 是 EXP6 函式庫的,會在背景送心跳,馬達不會被看門狗停掉。

    from pybricks.hubs import PrimeHub
    from pybricks.tools import multitask, run_task, wait
    
    from MBC_exp6_line import EXP6_LINE8
    from MBC_exp6_obj_Lib import MBC_EXP6, run_task
    
    # Set up.
    hub = PrimeHub()
    exp6 = MBC_EXP6(3, True)
    line8 = EXP6_LINE8(exp6, 5)
    SPEED = 50
    KP = 0.4
    KD = 1.5
    error = 0
    lastError = 0
    PD = 0
    
    async def main():
        global error, PD, lastError
        # 接線:EXP6 的 Host 線插主機 C 孔;循行者 8 路插 EXP6 第 5 孔;左馬達接 EXP6 擴充孔 1(反裝)、右馬達接擴充孔 2
        # 只匯入用到的產品檔:主機程式上限約 52 KB,循行者只要 MBC_exp6_line(EXP6_LINE8)。EXP6_LINE8(exp6, 5) = 插在 exp6 的 5 號孔
        await exp6.set_motor_inverted(1, True)
        while True:
            await wait(0)
            if await line8.width() > 5:
                await exp6.motor_power(1, 0)
                await exp6.motor_power(2, 0)
            else:
                error = await line8.pos100()
                PD = error * KP + (error - lastError) * KD
                await exp6.motor_power(1, SPEED + PD)
                await exp6.motor_power(2, SPEED - PD)
                lastError = error
            await wait(10)
    
    
    run_task(main())

    下載這個範例:積木檔 exp6_line8_pd_block.py、Python 檔 exp6_line8_pd_python.py(PD 循線:左馬達接擴充孔 1、右馬達接擴充孔 2;在 Pybricks Code 按「Import a file」匯入,跟 MBC_exp6_obj_Lib.py、MBC_exp6_mbc_common.py、MBC_exp6_line.py 放同一個專案)。

    使用注意

    1. 一定要接 EXP6 的電池。擴充孔上的馬達全部靠 EXP6 自己的電池(建議 2S 鋰電池),只接 Host 線、不接電池,什麼都不會動。EXP6 的擴充孔可以接樂高馬達、樂高 SPIKE 的顏色、超音波、力量感應器,也可以接 MBC 感應器(見上面「MBC 感應器插在 EXP6」)。
    2. 兩種孔號不要搞混。MBC_EXP6(3) 的 3 是主機的孔(1~6 = A~F);exp6.motor_run(1, 50) 的 1 是 EXP6 上的擴充孔(板子上印的 1~6)。
    3. 等待用 keep_alive_wait(),不要用 wait()。EXP6 超過 0.5 秒沒收到主機的訊號,會讓馬達自己停下來(看門狗,保護用,關不掉)。一般寫法的等待一律寫 exp6.keep_alive_wait(毫秒);算很久的地方中間補一次 exp6.keep_alive()。開多工時用函式庫的 run_task(),背景會自動送,直接 await wait() 就好。
    4. 拔掉擴充板不會讓程式停。讀到的值會變成 0(不是上一次的值),動作送不出去,電腦畫面每秒最多印一行提醒;插回去會自己重新連線。要知道有沒有接好就看 exp6.connected。在模擬 EXP6 勾「拔掉擴充板」可以看到這個情形。
    5. 轉角度送出就往下做,不會等轉完。motor_run_degrees()、motor_track_target() 後面要等一下,或一直讀角度等它到;還沒轉完又送一個轉角度,第二個會被丟掉。剛開機時馬達大約要 1 秒才準備好,程式開頭先等 get_device_id(孔) == 5。程式最後寫一行 stop_all(1) 讓馬達全部停下。