【micro:bit】MicroPython無線電通訊

覺得一個micro:bit的顯示LED不夠用?想要把結果傳送到另外一個micro:bit上面的LED顯示器上?想要兩個micro:bit連線對戰?想要在不同的micro:bit之間傳遞訊息?這些都難不倒micro:bit喔,它內建了無線電通訊模組,想要在不同的micro:bit之間交換訊息,只要簡單的幾個指令就可以完成了。

MicroPython有幾個函數負責在不同的micro:bit之間的無線電通訊,詳細的內容可以在以下這個網址中找到相關的說明:

https://microbit-micropython.readthedocs.io/en/latest/radio.html

其中radio.config()用來設定一些初始化的參數,最重要的部份是設定在板子之間要互相溝通用的頻道,如此才不會不小心接受到不相關的板子所傳來的無線電訊號,它使用channel參數來進行設定,預設是7,可以用的頻道是0~83。

第2個重要的函數是radio.on()和radion.off(),它們分別負責開啟和關閉板子的無線電訊號功能,在使用之前一定要利用radio.on(),才能進行後續的傳送和接收訊息的工作。

傳送訊息使用radio.send(),接收訊息使用radio.receive(),在接收端要特別留意,因為無線電訊號傳送的時候只會傳送一次,時間過了並不會保留該訊號,為了確保一定能夠接收到訊息,radio.receive()通常必需編寫在無窮迴圈中。

以下的練習要使用兩塊以上的micro:bit板子,而且兩塊板子上都要寫入具有無線電接收作業的程式才行。

先來看看以下的程式,透過無線電訊號傳送一個數字到另外一片板子上:

from microbit import *
import radio

radio.on()

while True:
    if button_a.was_pressed():
        radio.send('Hi')
    msg = radio.receive()
    if msg is not None:
        display.scroll(msg)
        sleep(500)

這段程式碼在第2行的地方要匯入radio模組才可順利執行無線電通訊。接著,在無窮迴圈中會檢查這片板子上的A按鈕是否曾被按下,如果有的話,就要送出Hi這個字串。接著,利用radio.receive()函數接收目前在同一個頻道中是否有人送出任何的訊息,在第10行的地方檢查訊息內容是否不為空(not None),如果是的話,就把該字串顯示在這片板子上。

執行上面這個程式,當按鈕A按下去之後,除了自己以外,其它位於同一頻道的板子都會出現Hi這個字樣喔。以下這個程式貼不顯示文字,而是以動畫的形式來取代,大家可以同時使用多片板子,看看會有什麼樣有趣的畫面出現!

from microbit import *
import random
import radio
images = [Image().invert()*(i/9) for i in range(10)]

radio.on()
display.show(Image.HAPPY)
while True:
    if button_a.was_pressed():
        radio.send('go')
    incoming = radio.receive()
    if incoming == 'go':
        sleep(random.randint(100, 500))
        display.show(images, delay=50, loop=False)
        display.show(reversed(images), delay=50, loop=False)
        if random.randint(0, 3) == 0:
            sleep(200)
            radio.send('go')

為了展示更多有趣的應用,以下的程式利用5片micro:bit,在每一片板子上寫入2種功能,且每一片板子各自有自己的編號,在收到無線電來的訊息的時候,每一個板子自己都要先確定是否自己是被點名到的對象,如果是的話,就執行動作,並在做完動作之後再送出無線電訊息,讓下一片板子開始工作。在這個例子中micro:bit的排列方式如下:

在一開始執行的時候,每一片板子都會顯示自己的編號,方便我們佈置它們的位置。程式設計如下:

from microbit import *
import random
import radio
images = [Image().invert()*(i/9) for i in range(10)]
airplane = list()
airplane.append(Image(
    '00000:'
    '00000:'
    '00000:'
    '00000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00000:'
    '00009:'
    '00000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00000:'
    '00099:'
    '00000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00009:'
    '00999:'
    '00009:'
    '00000'))
airplane.append(Image(
    '00009:'
    '00090:'
    '09999:'
    '00090:'
    '00009'))
airplane.append(Image(
    '00090:'
    '00900:'
    '99999:'
    '00900:'
    '00090'))
airplane.append(Image(
    '00900:'
    '09009:'
    '99999:'
    '09009:'
    '00900'))
airplane.append(Image(
    '09000:'
    '90090:'
    '99990:'
    '90090:'
    '09000'))
airplane.append(Image(
    '90000:'
    '00900:'
    '99900:'
    '00900:'
    '90000'))
airplane.append(Image(
    '00000:'
    '09000:'
    '99000:'
    '09000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '90000:'
    '90000:'
    '90000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00000:'
    '00000:'
    '00000:'
    '00000'))
my_channel = 1
next = 2
radio.on()
display.show(my_channel)
while True:
    if button_a.was_pressed():
        radio.send('go 1 1')
    elif button_b.was_pressed():
        radio.send('go 1 2')
    incoming = radio.receive()
    if incoming is not None:
        commands = incoming.split()
    else:
        commands = list()
    if len(commands) > 2:
        if commands[0] == 'go' and my_channel == int(commands[1]):
            if int(commands[2]) == 1:
                sleep(random.randint(100, 500))
                display.show(images, delay=50, loop=False)
                display.show(reversed(images), delay=50, loop=False)
                radio.send("go {} 1".format(next))
            elif int(commands[2]) == 2:
                display.show(airplane, loop=False, delay=200)
                radio.send("go {} 2".format(next))

在程式開始的地方除了記錄一些要製作動畫的串列變數之外,第78行設定的是自己的編號,第79行設定的next變數則是下一個要動作的號碼,利用next的指定,即可讓一些micro:bit的運用變成無窮的循環動畫。

在第84行送出第一個命令,它決定了開始動作的板子(第1個參數,在這個例子是1)以及要顯示的動畫(第2個參數),如果按下的是A按鈕,則執行第1個動畫,如果按下的是B按鈕,則執行第2個動畫。

在 89行拆解收到的訊息,在第93行的地方檢查是否是自己需要進行動畫,在第94行判斷是否為第1種動畫,第99行則是檢查是否為第2種動畫效果。以下是執行的結果影片:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *