Joystick:bit 遙控 Q霸小車 V5:一對一配對、蜂鳴器與震動回饋
在兒童館同時使用多台 Q霸小車時,最需要避免的是「一支搖桿控制到別組小車」。本作品以每組設備專屬的 pairId 建立無線群組,讓每位小朋友只控制自己手上的搖桿所配對的小車;同時加入蜂鳴器、震動、超音波避障、斷線停車與緊急停止功能。
學習目標
學習 micro:bit 無線群組、一對一裝置配對、雙向訊息回傳、感測安全控制與觸覺回饋設計。
學習 micro:bit 無線群組、一對一裝置配對、雙向訊息回傳、感測安全控制與觸覺回饋設計。
一、材料準備
- Q霸小車(CuteBot)套件 × 1
- Joystick:bit2 擴充搖桿 × 1
- micro:bit × 2、電池盒與電池 × 2
- Q霸小車超音波模組 × 1
二、兒童館多組設備的配對原則
每一組設備的搖桿與小車,都設定相同的 pairId。程式會將廣播群組設為 100 + pairId,因此各組不會互相干擾。
| 設備組別 | pairId | 廣播群組 |
|---|---|---|
| 紅色 01 | 1 | 101 |
| 藍色 02 | 2 | 102 |
| 綠色 03 | 3 | 103 |
部署方式:將同色、同編號貼紙貼在搖桿與小車上,並在兩端程式都改成相同的 pairId 後再下載。建議館員事先完成燒錄,兒童不需要自行設定。
三、右側四鍵功能
| 按鍵 | 功能 | 回饋 |
|---|---|---|
| C(P12) | 慢速 40% | 1 聲短音+震動 1 次 |
| D(P13) | 一般速度 70% | 2 聲短音+震動 2 次 |
| E(P14) | 快速 100% | 3 聲短音+震動 3 次 |
| F(P15) | 緊急停止 | 低音+長震動;按 C/D/E 才能解除 |
四、程式設計重點
- 搖桿每秒送出一次配對訊號,小車回傳
ack確認;搖桿收到後以勾勾、短音和震動提示。 - 只有完成配對的小車才會接受 x、y 搖桿控制訊號。
- 小車前方 15~30 cm 時自動降速;15 cm 內自動停止。
- 若 0.5 秒沒有收到控制訊號,小車自動停止。
五、MakeCode Python 程式
請建立兩個專案。搖桿端加入 Joystick:bit 擴充功能,小車端加入 CuteBot 擴充功能。兩端皆使用 Radio。
(一)Joystick:bit 搖桿端
pairId = 1 # 同一組的小車也必須設為相同數字
x = 0
y = 0
speed = 70
paired = False
emergencyStop = False
lastPairRequest = -1000
lastStatus = -1
def feedback(times, tone):
for index in range(times):
music.play_tone(tone, music.beat(BeatFraction.SIXTEENTH))
joystickbit.Vibration_Motor(80)
basic.pause(60)
joystickbit.init_joystick_bit()
radio.set_group(100 + pairId)
basic.show_number(pairId)
def on_button_c():
global speed, emergencyStop
speed = 40
emergencyStop = False
radio.send_value("stop", 0)
basic.show_number(1)
feedback(1, 523)
joystickbit.on_button_event(joystickbit.JoystickBitPin.P12,
joystickbit.ButtonType.down, on_button_c)
def on_button_d():
global speed, emergencyStop
speed = 70
emergencyStop = False
radio.send_value("stop", 0)
basic.show_number(2)
feedback(2, 659)
joystickbit.on_button_event(joystickbit.JoystickBitPin.P13,
joystickbit.ButtonType.down, on_button_d)
def on_button_e():
global speed, emergencyStop
speed = 100
emergencyStop = False
radio.send_value("stop", 0)
basic.show_number(3)
feedback(3, 784)
joystickbit.on_button_event(joystickbit.JoystickBitPin.P14,
joystickbit.ButtonType.down, on_button_e)
def on_button_f():
global emergencyStop
emergencyStop = True
radio.send_value("stop", 1)
basic.show_icon(IconNames.NO)
feedback(1, 220)
joystickbit.on_button_event(joystickbit.JoystickBitPin.P15,
joystickbit.ButtonType.down, on_button_f)
def on_received_value(name, value):
global paired, lastStatus
if name == "ack" and value == pairId:
if not paired:
paired = True
basic.show_icon(IconNames.YES)
feedback(1, 988)
if name == "status" and value != lastStatus:
lastStatus = value
if value == 1:
feedback(1, 440)
elif value == 2:
feedback(2, 330)
elif value == 3:
feedback(1, 220)
radio.on_received_value(on_received_value)
def on_forever():
global x, y, lastPairRequest
if control.millis() - lastPairRequest > 1000:
radio.send_value("pair", pairId)
lastPairRequest = control.millis()
x = Math.map(joystickbit.get_rocker_value(joystickbit.rockerType.X),
0, 1023, -100, 100)
y = Math.map(joystickbit.get_rocker_value(joystickbit.rockerType.Y),
0, 1023, -100, 100)
if x >= -10 and x <= 10:
x = 0
if y >= -10 and y <= 10:
y = 0
if emergencyStop:
radio.send_value("stop", 1)
elif paired:
radio.send_value("x", x * speed / 100)
radio.send_value("y", y * speed / 100)
basic.pause(50)
basic.forever(on_forever)
(二)Q霸小車端
pairId = 1 # 必須和配對搖桿相同
xValue = 0
yValue = 0
distance = 0
paired = False
emergencyStop = False
lastControlTime = -1000
lastStatus = -1
def send_status(newStatus):
global lastStatus
if newStatus != lastStatus:
lastStatus = newStatus
radio.send_value("status", newStatus)
radio.set_group(100 + pairId)
basic.show_number(pairId)
cuteBot.motors(0, 0)
def on_received_value(name, value):
global xValue, yValue, paired, emergencyStop, lastControlTime
if name == "pair" and value == pairId:
paired = True
radio.send_value("ack", pairId)
elif paired and name == "x":
xValue = value
lastControlTime = control.millis()
elif paired and name == "y":
yValue = value
lastControlTime = control.millis()
elif paired and name == "stop":
emergencyStop = value == 1
lastControlTime = control.millis()
radio.on_received_value(on_received_value)
def on_forever():
global distance
if not paired:
cuteBot.motors(0, 0)
elif emergencyStop:
cuteBot.motors(0, 0)
basic.show_icon(IconNames.NO)
send_status(3)
elif control.millis() - lastControlTime > 500:
cuteBot.motors(0, 0)
basic.show_icon(IconNames.SAD)
send_status(4)
else:
distance = cuteBot.ultrasonic(cuteBot.SonarUnit.Centimeters)
leftSpeed = Math.constrain(yValue + xValue, -100, 100)
rightSpeed = Math.constrain(yValue - xValue, -100, 100)
if yValue > 0 and distance > 0 and distance <= 15:
cuteBot.motors(0, 0)
basic.show_icon(IconNames.NO)
send_status(2)
elif yValue > 0 and distance > 15 and distance <= 30:
cuteBot.motors(leftSpeed * 0.4, rightSpeed * 0.4)
basic.show_icon(IconNames.SMALL_DIAMOND)
send_status(1)
else:
cuteBot.motors(leftSpeed, rightSpeed)
basic.clear_screen()
send_status(0)
basic.pause(30)
basic.forever(on_forever)
六、測試步驟與除錯
- 先將兩端的
pairId都設為 1,下載程式並開機。 - 搖桿顯示勾勾、短響並震動一次,表示已與同組小車完成配對。
- 按 C、D、E 測試三段速度;按 F 確認小車立即停止,並按 C、D 或 E 解除停止。
- 在前方放置障礙物:15~30 cm 會降速,15 cm 內會停止。
- 若小車前進方向相反,將小車端兩個
yValue > 0改為yValue < 0。 - 若震動沒有反應,確認程式使用的是
joystickbit.Vibration_Motor(80),其中V、M必須大寫。
館員提醒:為每組設備貼上相同顏色與編號,並將搖桿與小車的
pairId 預先設好。這是讓多位兒童同時操作時仍保持安全、清楚且可管理的關鍵。
沒有留言:
張貼留言