測距者 2 路 (TOF2) × SPIKE × Pybricks
這一頁只講 Pybricks(Python):在 SPIKE Prime/Robot Inventor 上用它讀測距者 2 路 (TOF2)的安裝步驟、每個值怎麼讀、能用的命令與範例。要換產品、主機或軟體,用上方的切換列。
安裝與設定
你需要
- 感應器:測距者 2 路 (TOF2)(SPIKE 版)。
- 主機:SPIKE Prime 或 Robot Inventor。
- 電腦:Chrome 瀏覽器,打開 code.pybricks.com 就能寫,不用安裝。
- 主機韌體:要先換成 Pybricks 韌體 v4.1(code.pybricks.com 正式版是 v4.1.1;MBC SPIKE 積木網站燒的 v4.1.0 也可以)。本站範例都照 v4.1 寫。
- 函式庫:
MBC_laser2_obj_Lib.py(要用「匯入函式庫」的寫法才需要)。自己寫新程式只要匯入MBC_sensors.py,一個檔適用全部 MBC 感應器。
注意
Pybricks 3.6.1 版的函式庫與範例已不再更新(2026 年新款 SPIKE Prime 也不能用 3.6.1)。還沒升級的主機,舊檔放在下載專區的「舊版(不再更新)」。
安裝軟體
- 用 Chrome 打開 code.pybricks.com。
- 主機換成 Pybricks 韌體:最簡單的方法是到 MBC SPIKE 積木網站 上方選單「SPIKE 主機 → 安裝/更新 Pybricks 韌體」,約 3 分鐘。
- 之後想回到樂高官方 App,用 SPIKE App 就能換回樂高原廠韌體。
讓軟體認得感應器
Pybricks 有兩種讀法,挑一種就好:
- 內建指令(不用函式庫):直接用 Pybricks 內建的感應器指令讀,不用載入額外檔案,最快上手。
- 匯入函式庫:下載 MBC_laser2_obj_Lib.py,拿到高解析位置、全部通道等更多資料。
匯入函式庫的步驟:
- 在 code.pybricks.com 左邊檔案區按「Import a file(匯入檔案)」。
- 範例檔和
MBC_laser2_obj_Lib.py兩個都要匯入,放在同一個專案列表裡。 - 點開範例,按 ▶ 執行。
重要
新專案用
MBC_sensors.py;舊專案只換掉原本那一個檔。MBC_sensors.py一個檔適用全部 MBC 感應器(EXP6、Servo6 擴充器的函式庫另外下載),寫法是from MBC_sensors import MBC_LINE8,類別名稱跟舊檔名裡的一樣。舊檔名(例如本頁範例用的MBC_laser2_obj_Lib.py)保留給舊程式:用新版的同名檔換掉原本那個檔就好,程式不用改。但每個舊檔名都是整份共用檔,一個程式匯入 3 個以上舊檔名,會超過 SPIKE 程式槽約 51 KB 的上限;要混用多款感應器,就只匯入MBC_sensors.py。
提示
檔名要跟程式裡
import的名字完全一樣,函式庫才載得進來,否則會出現ImportError。本站下載的函式庫檔名都沒有版本字尾,不用改名。
提示
函式庫建立物件時大多有
multitask參數:填False是一般模式,一行一行執行;填True是多工模式,每個呼叫前要加await,可以同時做很多件事。
接線
- 用連接線把感應器插在主機的 C 孔(A~F 任一孔都可以)。
- 程式裡的孔要選同一個:內建指令用
Port.A~Port.F;函式庫的port參數多半是1~6,對應 A~F。 - 接頭卡榫朝上,輕輕推進去。
左右怎麼分
左右以感應器朝前、從背後看為準(左=J5、右=J3)。 面對感應器看會剛好相反,所以用手測試時,請站到感應器後面、跟它同方向看。範例裡的「左邊比較近」「往左轉」都照這個方向。
上機結果(Pybricks 4.1.2)
SPIKE 版在 Pybricks 4.1.2 實測通過(2026-11-02):讀值、函式庫與新手範例都在主機上跑過。
- 用
ColorSensor直接讀時,2026-11 以後的感應器韌體在 Pybricks 4.x 的reflection()就是整數(例如 31);較舊的韌體會帶 1 位小數(例如 30.8)。程式裡寫int(...)新舊韌體都通,留著就好。
下命令改設定(E0~E4)
提示
SPIKE Pybricks 實測通過(2026-11-02):E0~E4 每個命令在主機上逐條驗過:正確的參數回「完成」、超出範圍的回「失敗」且設定不變、遠距離模式讀得到 200 cm、斷電後回出廠。
用 MBC 函式庫 MBC_laser2_obj_Lib.py 的 cmd() 送命令、wait_done() 等它做完(True=完成、False=失敗或沒回應)。官方 SPIKE App 和 Pybricks 內建 ColorSensor 積木送不了命令;感應器韌體要 2026-11 以後的版本。
from MBC_laser2_obj_Lib import MBC_LASER2
laser2 = MBC_LASER2(3) # 3 = C 埠
laser2.cmd(0xE0, 1) # 換成遠距離模式(最遠 200 cm)
if laser2.wait_done(): # True = 完成
print('已換成遠距離')| 命令 | 參數(超出範圍=失敗) | 會做什麼 | 什麼時候用 | 範例 |
|---|---|---|---|---|
E0 測距模式 |
0 一般(出廠,最遠 120 cm)/1 遠距離(最遠 200 cm)/2 精準(每 100 ms)/3 高速(每 20 ms) | 換模式,同時把更新時間、距離上限重設成這個模式的預設值 | 要量超過 120 cm 用遠距離;數字要穩用精準;要反應快用高速 | 1 |
E1 濾波 |
0 關/1 最近 3 筆中位數(出廠)/2 最近 5 筆中位數 | 把偶爾一次的怪值濾掉 | 數字跳來跳去 → 2;比賽要最快反應 → 0 | 2 |
E2 更新時間 |
20~200 ms(0=模式預設) | 每量一次花多久:越短越快、越長越穩 | 快速避障 → 20;量遠、要穩 → 200 | 3 |
E3 回出廠 |
一定要 0xA5 |
模式 0、濾波 1、33 ms、上限 120 cm | 程式一開始先送,從乾淨的狀態開始 | 4 |
E4 距離上限 |
10~模式上限 cm(一般 120、遠距離 200;0=模式上限) | 超過上限的東西一律當成沒東西,讀到的值就是上限 | 只想對近的東西反應,不被遠處走動的人干擾 | 5 |
- SPIKE 超出範圍=失敗、設定不變(
wait_done()回 False),不會像 Arduino I2C 那樣被夾到最近的值。 - 換模式(E0)會把更新時間和距離上限重設:要搭配 E2、E4,先送 E0 再送它們。
- 設定只存在感應器記憶體:拔線或主機關機就回出廠(一般模式、上限 120 cm),程式每次開始要重新送。
- 「沒東西」讀到的是上限:一般模式 120、遠距離模式 200,用 E4 改過就是你設的上限。
- 同一個命令+同樣參數再呼叫不會重做(放在迴圈裡也只做一次);要再做一次寫
cmd(..., again=True)(範例 4)。 wait_done()每次要多等幾十毫秒,不要放在循跡、避障這種快速迴圈裡;在程式開頭設定好就好。E0、E2、E3 要重新設定雷射晶片,約 0.1~0.5 秒。- EV3、MATRIX 版沒有命令(只能讀)。
命令範例(5 支)
每支都是:感應器接 C 埠,把範例和 MBC_laser2_obj_Lib.py 一起匯入 Pybricks Code 再執行;用主機的左、右鍵換設定,螢幕顯示目前設定、電腦畫面印讀值。打包下載(5 支範例+函式庫)
1. 測距模式(E0)
白牆或大白板放在正前方約 150 公分。一般模式讀到 120(超過上限=沒東西),按右鍵換成 1 遠距離就讀到約 150。
# 測距者 2 路 命令範例 01(Pybricks,SPIKE Prime/Robot Inventor 主機):測距模式:一般/遠距離/精準/高速
# 用主機的左、右鍵切換 4 種測距模式(命令 E0),螢幕顯示目前模式,主控台印距離:
# 0 一般(出廠,最遠 120 cm)、1 遠距離(最遠 200 cm)、2 精準(每 100 ms,最穩)、3 高速(每 20 ms,最快)
# 擺法:白牆或大白板放在左右兩顆雷射的正前方約 150 公分。一般模式會讀到 120(超過上限=當成沒東西),換成 1 就讀到約 150
# 接線:測距者 2 路 → C 埠;跟 MBC_laser2_obj_Lib.py 一起上傳(Pybricks Code 把兩個檔放在一起)
# 命令只有 SPIKE 版能下(感應器韌體 2026-11 以後);設定存在感應器記憶體,拔線就回出廠
# cmd(命令碼, 參數):送命令;wait_done():等它做完,True = 完成、False = 失敗(參數超出範圍)或沒回應
# 命令表:E0 測距模式、E1 濾波、E2 更新時間、E3 回出廠(參數 0xA5)、E4 距離上限
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠(1=A、2=B、3=C、4=D、5=E、6=F)
mode = 0
laser2.cmd(0xE3, 0xA5) # 先回出廠設定(一般模式)
laser2.wait_done()
hub.display.number(mode)
t = StopWatch()
while True:
pressed = hub.buttons.pressed() # 每 10 ms 看一次按鍵,按一下就收得到
if Button.RIGHT in pressed or Button.LEFT in pressed:
mode = (mode + (1 if Button.RIGHT in pressed else 3)) % 4 # 右鍵 +1、左鍵 -1
laser2.cmd(0xE0, mode) # 換測距模式(要重新設定雷射晶片,約 0.1~0.5 秒)
ok = laser2.wait_done() # 等它做完:True = 完成
hub.display.number(mode)
print('換成模式', mode, ['一般', '遠距離', '精準', '高速'][mode], '完成' if ok else '失敗')
while hub.buttons.pressed(): # 等放開按鍵
wait(10)
if t.time() >= 300: # 每 0.3 秒印一次距離
t.reset()
print('左', laser2.left(), '右', laser2.right(), 'cm|左', laser2.left_mm(), 'mm')
wait(10)2. 濾波(E1)
盒子或白板放在正前方約 50 公分不要動。每秒印「1 秒內最大-最小」=跳動幾 mm,濾波越大越穩。
# 測距者 2 路 命令範例 02(Pybricks,SPIKE Prime/Robot Inventor 主機):濾波:讓數字比較穩
# 用主機的左、右鍵切換濾波(命令 E1):0 關、1 最近 3 筆中位數(出廠)、2 最近 5 筆中位數
# 擺法:盒子或白板放在左右兩顆雷射的正前方約 50 公分不要動。每秒印「1 秒內最大−最小」=數字跳動幾 mm,濾波越大越穩
# 接線:測距者 2 路 → C 埠;跟 MBC_laser2_obj_Lib.py 一起上傳(Pybricks Code 把兩個檔放在一起)
# 命令只有 SPIKE 版能下(感應器韌體 2026-11 以後);設定存在感應器記憶體,拔線就回出廠
# cmd(命令碼, 參數):送命令;wait_done():等它做完,True = 完成、False = 失敗(參數超出範圍)或沒回應
# 命令表:E0 測距模式、E1 濾波、E2 更新時間、E3 回出廠(參數 0xA5)、E4 距離上限
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠(1=A、2=B、3=C、4=D、5=E、6=F)
filt = 1
laser2.cmd(0xE3, 0xA5) # 先回出廠設定(濾波 1)
laser2.wait_done()
wait(500) # 等感應器量到新的值再開始算
hub.display.number(filt)
while True:
lo, hi = 99999, -1
t = StopWatch()
while t.time() < 1000: # 1 秒內一直讀,記下最大、最小
mm = laser2.left_mm()
lo = min(lo, mm)
hi = max(hi, mm)
pressed = hub.buttons.pressed()
if Button.RIGHT in pressed or Button.LEFT in pressed:
filt = (filt + (1 if Button.RIGHT in pressed else 2)) % 3
laser2.cmd(0xE1, filt) # 換濾波(馬上生效)
laser2.wait_done()
hub.display.number(filt)
print('換成濾波', filt)
while hub.buttons.pressed():
wait(10)
lo, hi = 99999, -1
t.reset()
wait(20)
print('濾波', filt, '|左 mm', lo, '~', hi, '|跳動', hi - lo, 'mm')3. 更新時間(E2)
盒子或白板放在正前方約 50 公分不要動。每秒印「值換了幾次」(≈ 更新幾次)和跳動幾 mm:20 ms 最快、200 ms 最穩。
# 測距者 2 路 命令範例 03(Pybricks,SPIKE Prime/Robot Inventor 主機):更新時間:快一點還是準一點
# 用主機的左、右鍵切換更新時間(命令 E2):20、33(出廠)、100、200 ms
# 擺法:盒子或白板放在左右兩顆雷射的正前方約 50 公分不要動。每秒印「值換了幾次」(≈ 更新幾次)和「跳動幾 mm」
# 接線:測距者 2 路 → C 埠;跟 MBC_laser2_obj_Lib.py 一起上傳(Pybricks Code 把兩個檔放在一起)
# 命令只有 SPIKE 版能下(感應器韌體 2026-11 以後);設定存在感應器記憶體,拔線就回出廠
# cmd(命令碼, 參數):送命令;wait_done():等它做完,True = 完成、False = 失敗(參數超出範圍)或沒回應
# 命令表:E0 測距模式、E1 濾波、E2 更新時間、E3 回出廠(參數 0xA5)、E4 距離上限
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠(1=A、2=B、3=C、4=D、5=E、6=F)
CHOICES = [20, 33, 100, 200]
k = 1
laser2.cmd(0xE3, 0xA5) # 先回出廠設定(33 ms)
laser2.wait_done()
laser2.cmd(0xE1, 0) # 關濾波,比較看得出差別
laser2.wait_done()
wait(500) # 等感應器量到新的值再開始算
hub.display.number(CHOICES[k])
while True:
last, changes, lo, hi = -1, 0, 99999, -1
t = StopWatch()
while t.time() < 1000:
mm = laser2.left_mm()
if mm != last:
changes += 1
last = mm
lo = min(lo, mm)
hi = max(hi, mm)
pressed = hub.buttons.pressed()
if Button.RIGHT in pressed or Button.LEFT in pressed:
k = (k + (1 if Button.RIGHT in pressed else 3)) % 4
laser2.cmd(0xE2, CHOICES[k]) # 換更新時間(要重新設定雷射晶片)
ok = laser2.wait_done()
hub.display.number(CHOICES[k])
print('換成', CHOICES[k], 'ms', '完成' if ok else '失敗')
while hub.buttons.pressed():
wait(10)
last, changes, lo, hi = -1, 0, 99999, -1
t.reset()
wait(5)
print(CHOICES[k], 'ms|1 秒內換了', changes, '次|跳動', hi - lo, 'mm')4. 回出廠設定(E3)
白板放在正前方約 60 公分。先把上限改成 30 cm,讀數被「蓋」在 30;按中間鍵送 E3 回出廠,上限回到 120,又看得到 60 公分的白板。要停程式:按住中間鍵不放。
下載 cmd04_factory_reset.py + 函式庫
# 測距者 2 路 命令範例 04(Pybricks,SPIKE Prime/Robot Inventor 主機):回出廠設定
# 回出廠設定(命令 E3,參數一定要是 0xA5):先把距離上限改成 30 cm,看讀數被「蓋」在 30;
# 按中間鍵送 E3 回出廠 → 上限回到 120 cm,讀數又看得到遠的東西
# 擺法:白板放在左右兩顆雷射的正前方約 60 公分(比 30 遠、比 120 近)
# 接線:測距者 2 路 → C 埠;跟 MBC_laser2_obj_Lib.py 一起上傳(Pybricks Code 把兩個檔放在一起)
# 命令只有 SPIKE 版能下(感應器韌體 2026-11 以後);設定存在感應器記憶體,拔線就回出廠
# cmd(命令碼, 參數):送命令;wait_done():等它做完,True = 完成、False = 失敗(參數超出範圍)或沒回應
# 命令表:E0 測距模式、E1 濾波、E2 更新時間、E3 回出廠(參數 0xA5)、E4 距離上限
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠(1=A、2=B、3=C、4=D、5=E、6=F)
laser2.cmd(0xE4, 30) # 先把距離上限改成 30 cm(超過 30 = 當成沒東西,讀到 30)
laser2.wait_done()
hub.display.number(30)
print('距離上限 30 cm:按中間鍵送 E3 回出廠')
hub.system.set_stop_button(None) # 中間鍵拿來用(要停程式:按住中間鍵不放)
t = StopWatch()
while True:
if Button.CENTER in hub.buttons.pressed(): # 每 10 ms 看一次按鍵
laser2.cmd(0xE3, 0xA5, again=True) # 回出廠;again=True:同一個命令也要再做一次
ok = laser2.wait_done()
hub.display.number(120)
hub.speaker.beep()
print('回出廠', '完成' if ok else '失敗', ':上限回到 120 cm')
while hub.buttons.pressed():
wait(10)
if t.time() >= 300: # 每 0.3 秒印一次距離
t.reset()
print('左', laser2.left(), '右', laser2.right(), 'cm|左', laser2.left_mm(), 'mm')
wait(10)5. 距離上限(E4)
左、右鍵把上限改成 10、20…120 cm。比上限近就亮紅燈+嗶,否則綠燈:遠處有人走動也不會誤觸。
下載 cmd05_max_distance.py + 函式庫
# 測距者 2 路 命令範例 05(Pybricks,SPIKE Prime/Robot Inventor 主機):距離上限:只看近的東西
# 距離上限(命令 E4,cm):超過上限的東西當成「沒東西」,讀到的值就是上限 → 只對近的東西反應
# 左、右鍵把上限改成 10、20、30…120 cm(螢幕顯示),較近距離比上限近就亮紅燈+嗶,否則綠燈
# 接線:測距者 2 路 → C 埠;跟 MBC_laser2_obj_Lib.py 一起上傳(Pybricks Code 把兩個檔放在一起)
# 命令只有 SPIKE 版能下(感應器韌體 2026-11 以後);設定存在感應器記憶體,拔線就回出廠
# cmd(命令碼, 參數):送命令;wait_done():等它做完,True = 完成、False = 失敗(參數超出範圍)或沒回應
# 命令表:E0 測距模式、E1 濾波、E2 更新時間、E3 回出廠(參數 0xA5)、E4 距離上限
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠(1=A、2=B、3=C、4=D、5=E、6=F)
limit = 30
laser2.cmd(0xE3, 0xA5) # 先回出廠設定
laser2.wait_done()
laser2.cmd(0xE4, limit) # 距離上限 30 cm
laser2.wait_done()
hub.display.number(limit)
t = StopWatch()
while True:
pressed = hub.buttons.pressed() # 每 10 ms 看一次按鍵
if Button.RIGHT in pressed or Button.LEFT in pressed:
limit = limit + 10 if Button.RIGHT in pressed else limit - 10
limit = max(10, min(120, limit))
laser2.cmd(0xE4, limit) # 改上限(馬上生效)
laser2.wait_done()
hub.display.number(limit)
while hub.buttons.pressed():
wait(10)
if t.time() >= 200: # 每 0.2 秒看一次距離
t.reset()
cm = min(laser2.left(), laser2.right())
if cm < limit: # 比上限近 = 真的有東西
hub.light.on(Color.RED)
hub.speaker.beep(1000, 50)
else:
hub.light.on(Color.GREEN)
print('上限', limit, 'cm|', '左', laser2.left(), '右', laser2.right(), 'cm|左', laser2.left_mm(), 'mm')
wait(10)第一次測試
- 主機開機,在 code.pybricks.com 連上主機。
- 匯入並打開本頁的範例 1,按 ▶。
- 主控台印出的數字跟著感應器前方的東西變化,就是接好了。
常見問題
- 出現
ImportError? 函式庫沒有匯入到同一個專案,或檔名跟import的名字不同。把檔名改成MBC_laser2_obj_Lib.py再匯入一次。 - 範例跑不起來、指令不認得? 主機韌體太舊:本站範例照 Pybricks v4.1 寫,先把主機更新到 v4.1。3.6.1 已不再更新,舊版檔案在下載專區。
- 感應器拔線(或線鬆了)怎麼辦? 程式不會停下來:函式庫會回傳上一次讀到的值,並在主控台印一次提醒(中英並列:
MBC: Port C 讀不到感應器,先回傳上一次的值 / no sensor, using the last value);開機時就沒接上的話回傳None。要在程式裡檢查,用物件的sensor_ok():最近一次有讀到是True,讀不到是False(多工模式要寫await)。插回去後函式庫會繼續讀;如果是開機時就沒接上、又用多工模式,要重新執行程式。 - 標「只有 Pybricks 版」的範例讀到怪數字? 那個範例用的是感應器 2026-10 以後韌體的新模式,舊韌體讀到的會是別的數字。
- 換回官方 App 後連不上? 主機現在是 Pybricks 韌體:用 SPIKE App 換回樂高原廠韌體。
讀值
程式假設感應器插 A 孔。「MBC 函式庫」寫法要先把函式庫 .py 一起匯入 Pybricks。
左距離 cm leftCm
| 範圍 | 意思 |
|---|---|
0~120 cm |
左邊那顆的距離 0~120 cm(站在車後往前看,左 = 第 0 顆),120 = 前面沒東西/那顆失效 |
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port
dev = PUPDevice(Port.A) # 感應器插 A 孔
w = dev.read(9)[0]
leftCm = (w & 0xFF) # 左距離 cm(低 byte)MBC 函式庫
from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2
laser = MBC_LASER2(Port.A)
leftCm = laser.left()模式 0 (edu) byte 0 🔒;模式 0 (toy) byte 0 🔒;模式 1 byte 0;模式 2 byte 0;模式 3 byte 0 🔒;模式 4 v[0] lo;模式 5 v[0] 🔒;模式 8 v[0] lo;模式 9 v[0] lo 🔒。備註:16 B = [左, 右, 0, 左, 0, 右, 0, 平均, 0×8]:App 顏色 = 左、原始紅 = 256×左; 8 B 原樣(不壓縮); 韌體註解寫「最近」,實際送左(INO:261-263); 網站 read(3) 在用:[左, 右, 0]; Pybricks reflection() 編碼:L = 左 cm,a = L/25、b = 10×(L mod 25)+9,3 個 int16 = a×256+b → reflection() = L; 只送 4 B,v0 = 左 + 256×右
右距離 cm rightCm
| 範圍 | 意思 |
|---|---|
0~120 cm |
右邊那顆的距離 0~120 cm(右 = 第 1 顆),120 = 前面沒東西/那顆失效 |
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port
dev = PUPDevice(Port.A) # 感應器插 A 孔
w = dev.read(9)[0]
rightCm = ((w >> 8) & 0xFF) # 右距離 cm(高 byte)MBC 函式庫
from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2
laser = MBC_LASER2(Port.A)
rightCm = laser.right()模式 0 (edu) byte 1 🔒;模式 0 (toy) byte 1 🔒;模式 3 byte 1 🔒;模式 4 v[0] hi;模式 7 v[2] 🔒;模式 8 v[0] hi;模式 9 v[0] hi 🔒。備註:App 反射光 = 右、原始綠 = 256×右; 網站 read(3) 在用; Pybricks ambient() = int16[2]/100 = 右 cm(INO:300-312)
左距離 mm leftMm
| 範圍 | 意思 |
|---|---|
0~1200 mm |
左邊那顆的距離 0~1200 mm,1200 = 前面沒東西/那顆失效 |
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port
dev = PUPDevice(Port.A) # 感應器插 A 孔
leftMm = dev.read(6)[0] # 左距離 mmMBC 函式庫
from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2
laser = MBC_LASER2(Port.A)
leftMm = laser.left_mm()模式 6 v[0]。備註:#67 新:HSV 3×int16 = [左 mm, 右 mm, 平均 mm](原本是基底緩衝合併值)
右距離 mm rightMm
| 範圍 | 意思 |
|---|---|
0~1200 mm |
右邊那顆的距離 0~1200 mm,1200 = 前面沒東西/那顆失效 |
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port
dev = PUPDevice(Port.A) # 感應器插 A 孔
rightMm = dev.read(6)[1] # 右距離 mmMBC 函式庫
from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2
laser = MBC_LASER2(Port.A)
rightMm = laser.right_mm()模式 6 v[1]。備註:#67 新
初始化位元圖 initOk
| 範圍 | 意思 |
|---|---|
0~3 bit |
bit0 = 左、bit1 = 右,1 = 那顆開機初始化成功(失敗不重試);3 = 兩顆都好 |
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port
dev = PUPDevice(Port.A) # 感應器插 A 孔
w = dev.read(9)[1]
initOk = (w & 0xFF) # 初始化位元圖(低 byte)MBC 函式庫
from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2
laser = MBC_LASER2(Port.A)
initOk = laser.is_ok(1)模式 9 v[1] lo 🔒
故障位元圖 fault
| 範圍 | 意思 |
|---|---|
0~3 bit |
bit0 = 左、bit1 = 右,1 = 那顆目前失效(I2C 讀失敗或 200 ms 沒更新);失效那顆距離回 120/1200 |
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port
dev = PUPDevice(Port.A) # 感應器插 A 孔
w = dev.read(9)[1]
fault = ((w >> 8) & 0xFF) # 故障位元圖(高 byte)MBC 函式庫
from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2
laser = MBC_LASER2(Port.A)
fault = laser.is_ok(1)模式 9 v[1] hi 🔒
左右平均 mm avgMm
| 範圍 | 意思 |
|---|---|
0~1200 mm |
(左 mm + 右 mm) / 2,0~1200;跟 EV3 模式 3、SPIKE 模式 6 第 3 個值一致(共識 #8 補上) |
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port
dev = PUPDevice(Port.A) # 感應器插 A 孔
avgMm = dev.read(0)[7] # 左右平均 mmMBC 函式庫
from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2
laser = MBC_LASER2(Port.A)
avgMm = laser.average_mm()模式 0 (edu) byte 7 🔒;模式 6 v[2]。備註:byte7 = (左 cm + 右 cm)>>1;App 原始藍 = 256×平均; #67 新:平均 mm
這個軟體讀不到:較近距離 cm。要用這些值請改用 Arduino/mBlock/micro:bit。
範例
範例 1:看見距離
這個範例會做什麼:主機螢幕一直捲動顯示「左距離 右距離」兩個數字(單位公分),例如「40 80」。
要準備什麼
- SPIKE 主機 1 台
- 測距者 2 路 1 個
- 一本書或一個盒子當作「障礙物」
怎麼接:測距者 2 路插 C 孔。
下載程式
| Pybricks |
|---|
| ex01_show_distance.py+函式庫 |
Pybricks 程式碼
# 測距者 2 路 範例 1:看見距離(螢幕捲動顯示「左距離 右距離」)
# 接線:測距者 2 路 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠(1=A、2=B、3=C、4=D、5=E、6=F)
while True:
left = laser2.left() # 左邊雷射量到的距離(公分,0~120;120 = 前面沒東西)
right = laser2.right() # 右邊雷射量到的距離
hub.display.text(str(left) + ' ' + str(right)) # 主機螢幕捲動顯示,例如「40 80」
print('左', left, ' 右', right) # 電腦畫面也印出來
wait(200) # 等 0.2 秒再讀下一次一步一步看懂程式
- 一直重複:下面的積木會一直做,直到你按停止。
- 讀左距離、右距離:官方 App 是「原始紅 ÷ 256 取整數」和「原始綠 ÷ 256 取整數」,存進兩個「變數」(變數=有名字的盒子,可以放一個數字);MBC 積木網站和 Pybricks 直接有「左雷射距離」「右雷射距離」。
- 顯示在螢幕上:把「左距離」「空格」「右距離」接成一串文字,讓螢幕捲動顯示。MBC 積木網站和 Pybricks 也會在電腦畫面印出來。
- 等 0.2 秒再讀下一次。
跑起來應該看到什麼
- 前面什麼都沒有:顯示 120 120。
- 把書放在前面 30 公分:兩個數字都變成 30 左右。
- 用手只擋住左邊那顆雷射:第一個數字變小、第二個不變。
重要
請先用這個範例確認左右。 感應器正面朝前、元件面朝上的時候,站在感應器後面、跟它同方向往前看,用手只擋住左邊那顆(J5):應該是第一個數字變小。如果是第二個數字變小,代表你的裝法跟範例相反(例如感應器上下顛倒裝),後面範例的「左」「右」也要跟著對調。
常見問題
- 一直顯示 120 120? → 前面真的沒東西,或東西太遠、是黑色/透明的。拿一本白色的書放在 20 公分前試試。剛開機的 1~2 秒也會是 120。
- 只有一邊一直是 120? → 那顆雷射可能被擋住、髒了或壞了。用 MBC 積木網站的「雷射正常」積木或 Pybricks 的
laser2.is_ok(1)可以檢查。 - 數字一直跳? → 正常,雷射每秒量十幾次,會有 1~2 公分的誤差。
- 官方 App 顯示好幾千的數字? → 忘了「÷ 256 取整數」。
範例 2:太近就嗶
這個範例會做什麼:左右任何一邊有東西小於 20 公分,主機燈變紅色並且嗶嗶叫;沒有就亮綠色。
要準備什麼:同範例 1。
怎麼接:測距者 2 路插 C 孔。
下載程式
| Pybricks |
|---|
| ex02_too_close_beep.py+函式庫 |
Pybricks 程式碼
# 測距者 2 路 範例 2:太近就嗶(任何一邊小於 20 公分:紅燈+嗶聲;否則綠燈)
# 接線:測距者 2 路 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Color
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠
while True:
if laser2.min_distance() < 20: # 左右兩邊比較近的那個距離,小於 20 公分
hub.light.on(Color.RED)
hub.speaker.beep(880, 100) # 頻率 880 Hz,響 0.1 秒
else:
hub.light.on(Color.GREEN)
wait(100)一步一步看懂程式
- 讀距離:官方 App 讀左、右兩個距離;MBC 積木網站和 Pybricks 直接讀「較近的距離」(左右比較小的那個)。
- 如果 太近就…:官方 App 寫成「左 < 20 或 右 < 20」,意思跟「較近的距離 < 20」一樣 → 亮紅燈、嗶一聲。
- 否則…:亮綠燈。
- 等 0.1 秒再檢查一次。
跑起來應該看到什麼
- 前面沒東西:綠燈。
- 手慢慢靠近,到 20 公分以內:紅燈+一直嗶嗶叫。手拿開又變回綠燈。
常見問題
- 手貼到感應器上反而不叫? → 貼太近(幾公分以內)雷射可能量不到,會讀成 120。這是雷射的特性,留一點距離就好。
- 想改成 30 公分就叫? → 把「20」改成「30」(官方 App 有兩個 20 都要改)。
範例 3:哪一邊比較近
這個範例會做什麼:主機螢幕用箭頭告訴你東西在哪邊:左邊比較近 → ⬅,右邊比較近 → ➡,兩邊差不多 → ⬆,什麼都沒有 → ✕。
要準備什麼:同範例 1。
怎麼接:測距者 2 路插 C 孔。
下載程式
| Pybricks |
|---|
| ex03_which_closer.py+函式庫 |
Pybricks 程式碼
# 測距者 2 路 範例 3:哪一邊比較近(主機螢幕顯示箭頭)
# 接線:測距者 2 路 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Icon
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠
while True:
diff = laser2.diff() # 左距離 減 右距離:負的 = 左邊比較近,正的 = 右邊比較近
if laser2.min_distance() >= 120: # 兩邊都是 120 → 前面什麼都沒有
hub.display.icon(Icon.FALSE) # 顯示 ✕
elif diff < -5: # 左邊近了 5 公分以上
hub.display.icon(Icon.ARROW_LEFT)
elif diff > 5: # 右邊近了 5 公分以上
hub.display.icon(Icon.ARROW_RIGHT)
else: # 兩邊差不多 → 東西在正前方
hub.display.icon(Icon.ARROW_UP)
wait(100)一步一步看懂程式
- 先算 左減右=左距離 減 右距離。左邊比較近時,左距離比較小,所以結果是負的。
- 如果 兩邊都是 120 → 顯示 ✕(前面沒東西,要最先檢查)。官方 App 寫成「左 > 119 而且 右 > 119」。
- 否則,如果 左減右 < -5 → 左邊近了 5 公分以上 → 左箭頭。
- 否則,如果 左減右 > 5 → 右邊近了 5 公分以上 → 右箭頭。
- 都不是(差不到 5 公分)→ 上箭頭,代表東西在正前方。
跑起來應該看到什麼:拿一本書從左邊慢慢移到右邊(距離 30 公分左右),箭頭依序變成 ⬅ → ⬆ → ➡;把書拿走,變成 ✕。
常見問題
- 為什麼要差 5 公分以上才算? → 雷射本身有 1~2 公分的誤差,留一點空間,箭頭才不會一直跳來跳去。
- 箭頭左右相反? → 左右以感應器朝前、從背後看為準(左=J5、右=J3),面對感應器看會剛好相反。從背後看還是相反,就回到範例 1 確認左右,感應器可能裝反了。
- 東西很遠時箭頭亂跳? → 兩顆雷射的光束會越遠越寬、在遠處重疊,所以 50 公分以外很難分左右。這個範例請在 50 公分內玩。
範例 4:前面有東西就後退轉彎
這個範例會做什麼:機器人一直往前走。前面有東西(小於 20 公分)就停車 → 嗶一聲 → 後退 10 公分 → 右轉 90 度,然後繼續走。
要準備什麼
- 範例 1 的東西,再加上
- 兩輪小車(兩顆馬達當輪子)
- 一塊空地,放幾個盒子當障礙物
怎麼接
- 測距者 2 路插 C 孔,裝在車頭、朝正前方,離地至少 5 公分(太低會量到地板)
- 左輪接 E、右輪接 F
下載程式
| Pybricks |
|---|
| ex04_obstacle_back.py+函式庫 |
Pybricks 程式碼
# 測距者 2 路 範例 4:一直往前走,前面有東西(小於 20 公分)就停車、嗶一聲、後退、右轉
# 接線:測距者 2 路 → C 埠(裝在車頭、朝前);左輪馬達 → E 埠;右輪馬達 → F 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Direction, Port
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠
left = Motor(Port.E, Direction.COUNTERCLOCKWISE) # 左輪:反過來裝,所以設成逆時針才是往前
right = Motor(Port.F) # 右輪
robot = DriveBase(left, right, wheel_diameter=56, axle_track=112) # 輪子直徑 56 mm、兩輪距離 112 mm
while True:
if laser2.min_distance() < 20: # 左右任何一邊小於 20 公分 → 前面有東西
robot.stop() # 先停車
hub.speaker.beep(880, 200)
robot.straight(-100) # 後退 100 mm(10 公分)
robot.turn(90) # 原地右轉 90 度
else:
robot.drive(150, 0) # 每秒 150 mm 直直往前走
wait(50)一步一步看懂程式
- 告訴主機輪子接在哪裡:官方 App 是「set movement motors to E+F」;MBC 積木網站和 Pybricks 是「移動底盤 左輪 E、右輪 F」。
- 設定速度:官方 App 速度 30%;另外兩種是每秒 150 mm。
- 一直重複:讀距離。
- 如果 較近的距離 < 20 → 停車 → 嗶 → 後退 10 公分 → 原地右轉。官方 App 的「右轉」是「以轉向 100 移動 0.5 圈」,樂高標準小車大約轉 90 度。
- 否則 → 往前走。
跑起來應該看到什麼:小車往前走,快撞到盒子時停下來、嗶一聲、退一點點、右轉,再繼續往前。
常見問題
- 撞上去才停? → 開太快了,或障礙物是黑色、透明的(量不到)。把速度調低,或把「20」改大一點(例如 25)。
- 轉的角度不到 90 度/轉太多? → 官方 App:改「0.5 圈」那個數字;MBC 積木網站和 Pybricks:改「90」。
- 小車往後退、方向相反? → 馬達的裝法跟樂高標準小車相反。官方 App:請照樂高「標準驅動底盤」的方向裝馬達;MBC 積木網站:「移動底盤」積木裡左右輪的「正轉」方向都換成另一個;Pybricks:左輪改成
Direction.CLOCKWISE、右輪改成Motor(Port.F, Direction.COUNTERCLOCKWISE)。 - 一直原地打轉不前進? → 感應器裝太低,量到地板了。把感應器墊高一點、稍微朝上。
範例 5:開到牆前並把車頭轉正
這個範例會做什麼:機器人往前開到離牆 20 公分停下,再原地慢慢轉,直到左右兩顆雷射量到的距離一樣(差 1 公分以內),代表車頭正對著牆。完成後嗶一聲、螢幕顯示笑臉。比賽時常用這招讓機器人「對正」。
要準備什麼:同範例 4,再加一面牆(或一個大紙箱的平面)。
怎麼接:測距者 2 路插 C 孔、裝在車頭朝前;左輪接 E、右輪接 F。
下載程式
| Pybricks |
|---|
| ex05_square_up.py+函式庫 |
Pybricks 程式碼
# 測距者 2 路 範例 5:往前開到離牆 20 公分停下,再原地轉到兩邊距離一樣(車頭對正牆面)
# 接線:測距者 2 路 → C 埠(裝在車頭、朝前);左輪馬達 → E 埠;右輪馬達 → F 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Direction, Icon, Port
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠
left = Motor(Port.E, Direction.COUNTERCLOCKWISE)
right = Motor(Port.F)
robot = DriveBase(left, right, wheel_diameter=56, axle_track=112)
# 第 1 步:往前開,直到左右平均距離 ≤ 20 公分
robot.drive(100, 0)
while laser2.average() > 20:
wait(20)
robot.stop()
# 第 2 步:原地轉,直到左右只差 1 公分以內
while abs(laser2.diff()) > 1: # diff = 左 減 右
if laser2.diff() < 0: # 左邊比較近 → 車頭偏右了 → 往左轉
robot.drive(0, -30) # 速度 0(不前進),每秒左轉 30 度
else: # 右邊比較近 → 往右轉
robot.drive(0, 30)
wait(20)
robot.stop()
# 第 3 步:完成!
hub.speaker.beep(880, 500)
hub.display.icon(Icon.HAPPY)一步一步看懂程式(這個範例不是「一直重複」,而是照順序做完 3 步就結束)
- 第 1 步:往前開,「等待直到」平均距離 ≤ 20 公分,就停車。官方 App 的平均距離是「原始藍 ÷ 256 取整數」,寫成「< 21」意思一樣。
- 第 2 步:轉正。「重複直到」左右只差 1 公分以內:
- 左減右 < 0(左邊比較近)→ 車頭偏右了 → 往左轉;
- 否則 → 往右轉。
- 官方 App 一開始先把「左減右」設成 99,這樣「重複直到」才會至少檢查一次。
- 第 3 步:完成:停車、嗶一聲、顯示笑臉。
跑起來應該看到什麼:把小車斜斜地對著牆放好(車頭偏一點點),按執行。小車往前開、停下,左右扭一下轉正,然後嗶一聲。
常見問題
- 一直左右轉、停不下來? → 牆面不平,或「差 1 公分」太嚴格。把「1」改成「2」(官方 App 是把「< 2」改成「< 3」)。
- 轉正的方向反了,越轉越歪? → 左右以感應器朝前、從背後看為準(左=J5、右=J3)。回到範例 1 確認左右;左右相反的話,把「往左轉」「往右轉」對調。
- 斜太多(超過 30 度)就轉不正? → 斜太多時,其中一顆雷射會打到牆外面去(讀到 120)。先把車大致擺正再開始。
- 牆是黑色的? → 黑色牆面雷射量得比較短、比較不準,換成淺色的牆或在牆上貼白紙。
範例 6(進階):用毫米精準停車
注意
這個範例只有 Pybricks 版。 它用的「毫米距離」放在感應器的模式 6,樂高官方 App 和 MBC 積木網站讀不到(它們只讀公分)。感應器韌體要是 2026-10 以後的版本,舊韌體讀到的會是別的數字。 程式碼就是範例,不需要截圖。
這個範例會做什麼:機器人往前開,離牆 20 公分時放慢,到 15 公分(150 mm) 就停,嗶一聲、螢幕顯示停下來時的距離(公分)。公分只能分到 1 公分,毫米可以分到 0.1 公分,所以停的位置更準。
要準備什麼:同範例 5(小車+一面牆)。
怎麼接:測距者 2 路插 C 孔、裝在車頭朝前;左輪接 E、右輪接 F。
下載程式
| Pybricks |
|---|
| ex06_park_mm.py+函式庫 |
Pybricks 程式碼
# 測距者 2 路 範例 6(進階):用毫米精準停車(離牆 20 公分放慢、15 公分停)
# 接線:測距者 2 路 → C 埠(裝在車頭朝前);左輪馬達 → E 埠;右輪馬達 → F 埠
# 只有 Pybricks 版:毫米距離放在感應器的「模式 6」,官方 App 和積木網站讀不到;感應器韌體要 2026-10 以後
from pybricks.hubs import PrimeHub
from pybricks.parameters import Direction, Port
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2
hub = PrimeHub()
laser2 = MBC_LASER2(3) # 3 = C 埠
left = Motor(Port.E, Direction.COUNTERCLOCKWISE)
right = Motor(Port.F)
robot = DriveBase(left, right, wheel_diameter=56, axle_track=112)
robot.drive(100, 0) # 每秒 100 mm 往前開
while laser2.average_mm() > 200: # 左右平均距離(毫米)還大於 200 mm = 20 公分
wait(10)
robot.drive(40, 0) # 剩 20 公分:放慢到每秒 40 mm
while laser2.average_mm() > 150: # 到 150 mm = 15 公分
wait(10)
robot.stop() # 停車
hub.speaker.beep()
mm = laser2.average_mm() # 停下來之後再量一次
hub.display.number(mm // 10) # 螢幕顯示公分(15 或 14)
print('停在', mm, 'mm')一步一步看懂程式
laser2.average_mm():左右平均距離,單位毫米(0~1200;1200=前面沒東西)。感應器自己算好平均,不用自己加。- 先用每秒 100 mm 往前開,等到平均距離 ≤ 200 mm(20 公分)。
- 換成每秒 40 mm 慢慢開,等到 ≤ 150 mm 就停車。
- 嗶一聲,把停下來的距離 ÷ 10 顯示在螢幕上(公分)。
- 函式庫還有
laser2.left_mm()、laser2.right_mm()(左、右各自的毫米)和laser2.device_id()、laser2.firmware_version()(感應器型號與韌體版本)。
跑起來應該看到什麼:小車往前開、接近牆時變慢、在離牆 15 公分左右停下來,嗶一聲、螢幕顯示 15 或 14。
常見問題
- 停的位置每次都差 1~2 公分? → 雷射本身有 1~2 公分的誤差,而且車子有慣性。把「40」改更小(例如 25),停得更準。
- 想同時用公分和毫米? → 可以,但不要在同一個迴圈裡混著用:每次切換模式感應器要多花幾十 ms。
- 數字一直是 1200 不動? → 前面真的沒東西;或感應器韌體太舊(2026-10 以前)沒有毫米模式,請更新韌體。
其他問題
- 主機認不到感應器? 拔掉重插一次,等 2 秒;換一個孔試試。官方 App 會把它顯示成「顏色感應器」,這是正常的。
- 可以同時用官方 App 和 Pybricks 嗎? 一次只能裝一種韌體:Pybricks 與 MBC 積木網站用 Pybricks 韌體,官方 App 用樂高原廠韌體;隨時可以用 SPIKE App 換回原廠韌體。
還有問題?到 聯絡我們 附上你用的軟體和程式截圖。
下載
- Pybricks 函式庫 MBC_laser2_obj_Lib.py
- 共用函式庫(新專案用,一個檔適用全部 MBC 感應器) MBC_sensors.py
- tof2_pybricks_spike_v4.x.zip
- 下載中心(全部產品的函式庫、韌體、型錄)
本頁依據
- 主機與軟體清單:
_build/guides.json - 值與命令:
_build/protocol/tof2.json(單一真相來源) - 安裝與設定:
_build/guides/software/spike-pybricks.zh.md、_build/guides/product/tof2/spike-pybricks.zh.md - 範例:
sensors/tof2/spike-examples.md