Pybricks 專業環境專區 (EXP6)
+
警告
請注意:您目前觀看的是 【Pybricks 專業環境】 教學。 適用於刷入 Pybricks 韌體的 SPIKE Prime。如果您使用的是官方 SPIKE App,請點擊 這裡切換至官方教學。
Pybricks 環境不僅提供了毫秒級的極速通訊,更完美支援「非同步多工併行 (Async/await)」。EXP6 的專屬庫利用此特性打造了「背景看門狗與心跳保活機制」,讓機器人在執行複雜任務時,永遠不會斷線。
下載專屬程式庫與範例
(注意:請將下載的 MBC_exp6_obj_Lib.py 放進 Pybricks 專案中,方可使用。)
1. 快速開始 (Quick Start)
歡迎使用 EXP6 擴充板!這份說明書將教你如何使用 MBC_expObj_Lib 函式庫來控制馬達與讀取感測器。
我們的程式庫主要支援「物件式(Object-Oriented)」寫法,這就像是你平常拖拉圖形積木一樣直覺。此外,為了因應各種挑戰,每個指令都分為 一般模式 與 多工模式 兩種寫法:
- 一般模式:一行一行乖乖排隊執行,最簡單直覺,適合基礎教學。
- 多工模式:每個指令前面必須加上
await魔法單字,可以讓機器人「同時」做很多件事情,適合高階機器人。
初始化擴充板與啟動任務 (Setup & Run Task)
在使用任何功能前,必須先在 set up 階段建立擴充板物件,並根據你選擇的模式(一般/多工)決定是否需要引入 run_task 啟動任務。假設擴充板接在主機的 Port C (孔 3):
- 一般模式:建立物件時將 multitask 設為
false,即可直接在program中開始下達控制指令。 - 多工模式:建立物件時將 multitask 設為
true,並且必須在set up階段從MBC_exp6_obj_Lib引入擴充板專屬的run_task。在圖形介面中,你只需要將程式放在program積木下方,轉成 Python 程式碼時,系統會自動將它包裝成main()並呼叫run_task(main())啟動。專屬的run_task內部除了執行程式外,還會同時啟動「背景心跳機制」來維持連線,並在程式結束時安全停機。
初始化積木 MBC_EXP6 與啟動任務
@turnRight set up :: #eeb014 from [MBC_exp6_obj_Lib] import [MBC_EXP6] :: #FF6680 @greenFlag [exp6] is a [MBC_EXP6] (3) (false :: #59C059) :: #FF6680@turnLeft program :: #eeb014 @greenFlag [exp6 v] [motor_power] (6) (100) ‹ › :: #FF6680 @greenFlag [exp6 v] [keep_alive_wait] (5000) ‹ › :: #FF6680
from MBC_exp6_obj_Lib import MBC_EXP6
# Set up.
exp6 = MBC_EXP6(3, False)
exp6.motor_power(6, 100)
exp6.keep_alive_wait(5000)
@turnRight set up :: #eeb014 from [MBC_exp6_obj_Lib] import [MBC_EXP6] :: #FF6680 from [MBC_exp6_obj_Lib] import [run_task] :: #FF6680 @greenFlag [exp6] is a [MBC_EXP6] (3) (true :: #59C059) :: #FF6680@turnLeft program :: #eeb014 @greenFlag [exp6 v] [await v] [motor_power] (6) (100) ‹ › :: #FF6680 @greenFlag [exp6 v] [await v] [keep_alive_wait] (5000) ‹ › :: #FF6680
from pybricks.tools import multitask, run_task, wait
from MBC_exp6_obj_Lib import MBC_EXP6, run_task
# Set up.
exp6 = MBC_EXP6(3, True)
async def main():
await exp6.motor_power(6, 100)
await exp6.keep_alive_wait(5000)
run_task(main())
2. 馬達控制 (Motor Control)
控制接在 EXP6 擴充板上的 SPIKE 馬達,支援指定轉速、PID 閉迴路控制、煞車、PID 參數調整以及雙馬達同步驅動。
啟動馬達 (Power)
使用純粹的電力 (開迴路 PWM) 驅動馬達。沒有速度補償,但反應最直接快速。
exp6.motor_power(port, power)
port: 擴充板上的孔位 (1~6)power: 馬達動力 (-100 ~ 100)。正數順時針,負數逆時針。
@greenFlag [exp6 v] [call v] [motor_power] (5) (50) ‹ › :: #FF6680
# 讓接在擴充板孔 5 的馬達以 50% 動力轉動
exp6.motor_power(5, 50)@greenFlag [exp6 v] [await v] [motor_power] (5) (50) ‹ › :: #FF6680
await exp6.motor_power(5, 50)閉迴路轉動 (Run)
使用 PID 閉迴路控制,擴充板會自動根據負載調整力量,確保轉速維持在設定值。
exp6.motor_run(port, speed)
port: 擴充板上的孔位 (1~6)speed: 目標速度 (-100 ~ 100)。正數順時針,負數逆時針。
@greenFlag [exp6 v] [call v] [motor_run] (1) (30) ‹ › :: #FF6680
# 讓擴充板孔 1 的馬達維持 30 的穩定速度轉動
exp6.motor_run(1, 30)@greenFlag [exp6 v] [await v] [motor_run] (1) (30) ‹ › :: #FF6680
await exp6.motor_run(1, 30)角度精準控制 (Angle Control)
設定馬達旋轉特定的相對角度,或是移動到指定的絕對角度。擴充板內建的 PID 控制與角度累積器可以確保動作精準。
exp6.motor_run_degrees(port, speed, degrees, stop) 與 exp6.motor_track_target(port, speed, angle, stop)
port: 擴充板上的孔位 (1~6)speed: 目標速度 (-100 ~ 100)。正數順時針,負數逆時針。degrees: 移動的相對角度(例如 360 就是往前轉一圈)。範圍為 -2499 ~ 2499。angle: 移動到指定的絕對角度 (0~359,會自動找最短路徑)。stop: 填寫數字決定到達目標後的行為。1: 滑行 (STOP_COAST)2: 煞車 (STOP_BRAKE)3: 鎖死 (STOP_HOLD)4: 續轉 (STOP_CONTINUE)
備註:motor_run_target 已更名為 motor_track_target,但舊名仍可相容使用。
⚠️ 角度指令送出就會往下執行,不會等馬達轉完。同一顆馬達還在轉的時候再送下一個角度指令,下一個指令會被擴充板丟掉。所以兩個角度指令中間要先等它轉完(例如用 keep_alive_wait 等一段時間;速度 30 轉 360 度大約要 1.2 秒)。
@greenFlag [exp6 v] [call v] [motor_run_degrees] (1) (30) (360) (3) ‹ › :: #FF6680 @greenFlag [exp6 v] [call v] [keep_alive_wait] (1500) ‹ › :: #FF6680 @greenFlag [exp6 v] [call v] [motor_track_target] (1) (30) (90) (3) ‹ › :: #FF6680
# 讓孔 1 馬達以速度 30 轉動 360 度 (相對角度),到達後鎖死 (HOLD)
exp6.motor_run_degrees(1, 30, 360, 3)
# 等它轉完再送下一個角度指令(不等的話,下一個指令會被丟掉)
exp6.keep_alive_wait(1500)
# 讓孔 1 馬達以速度 30 轉動到 90 度的位置 (絕對角度),到達後鎖死
exp6.motor_track_target(1, 30, 90, 3)@greenFlag [exp6 v] [await v] [motor_run_degrees] (1) (30) (360) (3) ‹ › :: #FF6680 @greenFlag [exp6 v] [await v] [keep_alive_wait] (1500) ‹ › :: #FF6680 @greenFlag [exp6 v] [await v] [motor_track_target] (1) (30) (90) (3) ‹ › :: #FF6680
await exp6.motor_run_degrees(1, 30, 360, 3)
await exp6.keep_alive_wait(1500) # 等轉完再送下一個角度指令
await exp6.motor_track_target(1, 30, 90, 3)設定 PID 參數 (Set PID)
進階功能,用於手動調整馬達閉迴路控制的 P (比例)、I (積分)、D (微分) 參數,優化轉動的穩定性。請注意:50 是系統預設的馬達控制參數基準值。以 50 為基準,往上調整就是等比例放大,往下調整就是等比例縮小。
exp6.motor_set_pid(port, p, i, d)
@greenFlag [exp6 v] [call v] [motor_set_pid] (1) (50) (50) (50) ‹ › :: #FF6680
# 設定孔 1 的馬達 PID 參數
exp6.motor_set_pid(1, 50, 50, 50)@greenFlag [exp6 v] [await v] [motor_set_pid] (1) (50) (50) (50) ‹ › :: #FF6680
await exp6.motor_set_pid(1, 50, 50, 50)停止與煞車 (Stop & Brake)
你可以選擇讓馬達自然滑行停止,或是用力咬死煞車 (鎖定維持在當前角度)。
exp6.motor_stop(port, stop) 與 exp6.stop_all(stop)
port: 擴充板上的孔位 (1~6)stop: 填寫數字決定停止模式。1: 滑行 (STOP_COAST)2: 煞車 (STOP_BRAKE)3: 鎖死 (STOP_HOLD)
@greenFlag [exp6 v] [call v] [motor_stop] (1) (1) ‹ › :: #FF6680 @greenFlag [exp6 v] [call v] [motor_stop] (1) (3) ‹ › :: #FF6680 @greenFlag [exp6 v] [call v] [stop_all] (1) ‹ › :: #FF6680
exp6.motor_stop(1, 1) # 馬達斷電,自然滑行停止
exp6.motor_stop(1, 3) # 咬死煞車,鎖定目前位置
exp6.stop_all(1) # 緊急停止!讓擴充板上所有馬達滑行停止@greenFlag [exp6 v] [await v] [motor_stop] (1) (1) ‹ › :: #FF6680 @greenFlag [exp6 v] [await v] [motor_stop] (1) (3) ‹ › :: #FF6680 @greenFlag [exp6 v] [await v] [stop_all] (1) ‹ › :: #FF6680
await exp6.motor_stop(1, 1)
await exp6.motor_stop(1, 3)
await exp6.stop_all(1)設定馬達轉向 (Set Inverted)
設定馬達的預設旋轉方向。當機構設計導致馬達安裝反向時,可以直接在程式初始階段將其反轉,後續所有指令(包含底盤控制)的邏輯就會自動匹配,不需手動修改數值正負號。
exp6.set_motor_inverted(port, inverted)
port: 擴充板上的孔位 (1~6)inverted: 布林值 (True/False)。True表示反轉,預設不填為True。
@greenFlag [exp6 v] [call v] [set_motor_inverted] (1) ‹ › :: #FF6680
# 將 1 號孔的馬達方向反轉
exp6.set_motor_inverted(1, True)@greenFlag [exp6 v] [await v] [set_motor_inverted] (1) ‹ › :: #FF6680
await exp6.set_motor_inverted(1, True)雙馬達同步控制 (Drive)
同時精準控制兩顆馬達,非常適合用來製作底盤輪型機器人(例如循線車)。
exp6.drive(left_port, right_port, left_speed, right_speed)
@greenFlag [exp6 v] [call v] [drive] (1) (2) (50) (40) ‹ › :: #FF6680 @greenFlag [exp6 v] [call v] [drive_stop] (1) (2) (1) ‹ › :: #FF6680
# 讓孔 1 與孔 2 的馬達同時以 50 與 40 的速度前進
exp6.drive(1, 2, 50, 40)
# 停止雙馬達(第 3 個參數 stop 必填:1 滑行、2 煞車、3 鎖死)
exp6.drive_stop(1, 2, 1)@greenFlag [exp6 v] [await v] [drive] (1) (2) (50) (40) ‹ › :: #FF6680 @greenFlag [exp6 v] [await v] [drive_stop] (1) (2) (1) ‹ › :: #FF6680
await exp6.drive(1, 2, 50, 40)
await exp6.drive_stop(1, 2, 1)3. 感測器讀取 (Sensors)
讀取擴充板上的感測器數據與馬達狀態。擴充板會自動判斷感測器類型並回傳對應的數值。
馬達角度與速度
取得馬達當前的累積角度、絕對角度或是速度。擴充板內建 32-bit 累積器,不用擔心角度溢位問題!
- 角度歸零:
reset_angle(port) - 讀取累積角度:
get_motor_angle(port) - 讀取絕對角度:
get_motor_abs_angle(port) - 讀取速度:
get_motor_speed(port)
port: 擴充板上的孔位 (1~6)
@greenFlag [exp6 v] [call v] [reset_angle] (1) ‹ › :: #FF6680 (@greenFlag [exp6 v] [call v] [get_motor_angle] (1) ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_motor_abs_angle] (1) ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_motor_speed] (1) ‹ › :: #FF6680)
# 將孔 1 馬達的角度歸零
exp6.reset_angle(1)
# 讀取累積角度、絕對角度與速度deg/s
angle = exp6.get_motor_angle(1)
abs_angle = exp6.get_motor_abs_angle(1)
speed = exp6.get_motor_speed(1)
print("累積角度:", angle, "絕對角度:", abs_angle, "速度:", speed)@greenFlag [exp6 v] [await v] [reset_angle] (1) ‹ › :: #FF6680 (@greenFlag [exp6 v] [await v] [get_motor_angle] (1) ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_motor_abs_angle] (1) ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_motor_speed] (1) ‹ › :: #FF6680)
await exp6.reset_angle(1)
angle = await exp6.get_motor_angle(1)
abs_angle = await exp6.get_motor_abs_angle(1)
speed = await exp6.get_motor_speed(1)
print(angle, abs_angle, speed)顏色感測器 (Color Sensor)
取得 SPIKE 顏色感測器的辨識結果與反射值。
顏色代碼 get_color_color(port) 與 反射值 get_color_reflection(port)
port: 擴充板上的孔位 (1~6)
(@greenFlag [exp6 v] [call v] [get_color_color] (3) ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_color_reflection] (3) ‹ › :: #FF6680)
# 讀取顏色代碼(-1 為無顏色,其他對應樂高標準色碼)
color_code = exp6.get_color_color(3)
# 讀取光線反射值 (0~100,適合循線)
reflection = exp6.get_color_reflection(3)(@greenFlag [exp6 v] [await v] [get_color_color] (3) ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_color_reflection] (3) ‹ › :: #FF6680)
color_code = await exp6.get_color_color(3)
reflection = await exp6.get_color_reflection(3)進階色彩通道 (RGB / HSV)
除了基本的顏色代碼,你也可以讀取完整的 RGB 或 HSV 數值,甚至單獨擷取其中一個通道(例如只抓取紅色或色相)。這在進階影像識別或色彩過濾時非常實用。
讀取完整 RGB 與 HSV 元組 get_color_rgb(port) 與 get_color_hsv(port)
port: 擴充板上的孔位 (1~6)
(@greenFlag [exp6 v] [call v] [get_color_rgb] (3) ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_color_hsv] (3) ‹ › :: #FF6680)
# 讀取 RGB,回傳 (R, G, B),範圍為 0~100
rgb = exp6.get_color_rgb(3)
# 讀取 HSV,回傳 (H, S, V),H 範圍 0~359,S 與 V 範圍 0~100
hsv = exp6.get_color_hsv(3)(@greenFlag [exp6 v] [await v] [get_color_rgb] (3) ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_color_hsv] (3) ‹ › :: #FF6680)
rgb = await exp6.get_color_rgb(3)
hsv = await exp6.get_color_hsv(3)單一通道擷取 get_color_red(port) 等
port: 擴充板上的孔位 (1~6)
(@greenFlag [exp6 v] [call v] [get_color_red] (3) ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_color_hue] (3) ‹ › :: #FF6680)
# 單獨讀取 RGB 通道 (範圍 0~100)
r = exp6.get_color_red(3)
g = exp6.get_color_green(3)
b = exp6.get_color_blue(3)
# 單獨讀取 HSV 通道 (H 範圍 0~359, S/V 範圍 0~100)
h = exp6.get_color_hue(3)
s = exp6.get_color_sat(3)
v = exp6.get_color_val(3)(@greenFlag [exp6 v] [await v] [get_color_red] (3) ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_color_hue] (3) ‹ › :: #FF6680)
r = await exp6.get_color_red(3)
g = await exp6.get_color_green(3)
b = await exp6.get_color_blue(3)
h = await exp6.get_color_hue(3)
s = await exp6.get_color_sat(3)
v = await exp6.get_color_val(3)超音波與觸碰感測器
距離 get_ultrasonic_distance(port) 與 深度 get_touch_force(port)
port: 擴充板上的孔位 (1~6)
(@greenFlag [exp6 v] [call v] [get_ultrasonic_distance] (4) ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_touch_force] (5) ‹ › :: #FF6680)
# 讀取超音波距離 (單位:毫米 mm)
dist = exp6.get_ultrasonic_distance(4)
# 讀取觸碰感測器按壓深度 (0~100)
force = exp6.get_touch_force(5)(@greenFlag [exp6 v] [await v] [get_ultrasonic_distance] (4) ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_touch_force] (5) ‹ › :: #FF6680)
dist = await exp6.get_ultrasonic_distance(4)
force = await exp6.get_touch_force(5)系統與進階狀態 (System & Raw)
你可以隨時檢查目前擴充板上插了什麼設備、電池電壓,或是抓取底層的 Raw Data 進行開發除錯。
取得 ID get_device_id(port)、Raw Data get_port_raw(port) 與 電壓 get_voltage()
port: 擴充板上的孔位 (1~6)
(@greenFlag [exp6 v] [call v] [get_device_id] (1) ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_voltage] ‹ › :: #FF6680) (@greenFlag [exp6 v] [call v] [get_port_raw] (1) ‹ › :: #FF6680)
# 回傳裝置 ID: 0=無, 1=觸碰, 3=顏色, 4=超音波, 5=馬達
dev_id = exp6.get_device_id(1)
# 回傳當前電池電壓 (例如 8.25 V)
volts = exp6.get_voltage()
# 取得孔位 1 的原始未解析資料 (Raw Data, uint16)
raw_data = exp6.get_port_raw(1)(@greenFlag [exp6 v] [await v] [get_device_id] (1) ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_voltage] ‹ › :: #FF6680) (@greenFlag [exp6 v] [await v] [get_port_raw] (1) ‹ › :: #FF6680)
dev_id = await exp6.get_device_id(1)
volts = await exp6.get_voltage()
raw_data = await exp6.get_port_raw(1)4. 系統心跳與維持 (Heartbeat)
EXP6 擴充板需要與主控端維持通訊的「心跳訊號」。如果您在初始化時設定了 multitask=True,系統會在背景自動發送心跳,您不需要使用以下指令。但如果您使用一般模式 (multitask=False),請務必使用以下指令來維持通訊,否則擴充板0.5秒內沒有收到心跳訊號會自動關閉馬達電力輸出。
心跳等待 (Wait)
在一般模式下,請使用這個指令來取代原本系統的 wait 或 sleep,它會在等待期間自動幫你維持與擴充板的通訊。
exp6.keep_alive_wait(ms)
ms: 等待時間 (毫秒)
@greenFlag [exp6 v] [call v] [keep_alive_wait] (1000) ‹ › :: #FF6680
# 等待 1 秒鐘 (1000 毫秒),期間會自動發送心跳訊號
exp6.keep_alive_wait(1000)手動維持心跳 (Keep Alive)
如果您在程式中寫了耗時的 while 或 for 迴圈,請在迴圈內部呼叫這個指令,以確保擴充板不會因為太久沒收到通訊而斷線。
exp6.keep_alive()
@greenFlag [exp6 v] [call v] [keep_alive] ‹ › :: #FF6680
# 在耗時的迴圈中手動補足心跳
while True:
# 執行一些繁重的計算或感測任務...
# 確保通訊不中斷
exp6.keep_alive()5. 進階探索 (Advanced)
這部分是留給想要深入了解程式庫底層運作原理的進階開發者。
函數式寫法 (Functional API)
函式庫另外提供一組全域函數,名稱就是物件方法加上 exp_ 前綴(例如 exp_motor_power)。這些函數會操作「最後建立的那個 MBC_EXP6 物件」,所以還是要先建立一次 MBC_EXP6(...) 物件,之後就可以不用寫 exp6.:
引入與使用函數式 API
from MBC_exp6_obj_Lib import MBC_EXP6, exp_motor_power, exp_get_motor_angle
# 先建立一次物件 (主機埠 3 = C, multitask=False)
MBC_EXP6(3, False)
# 啟動孔位 5 的馬達
exp_motor_power(5, 50)
# 讀取孔位 5 的角度
angle = exp_get_motor_angle(5)