micro:bit と MicroPython と gazell で 4 x 5 cm リレー

* ねんがんの　[Qiita Advent Calendar](https://qiita.com/advent-calendar/2018/microbit)　の記事を　書いたぞ！
<br>

* 今年こそは Advent Calendar に参加したいということでネタを探してググっていると、
思いの外、 **gazell**（import radio のやつ）を取り上げている記事が少ないことに気付きました。

* ひょっとすると、こんなに便利な機能の良さがあまり認知されていないのでは？
と思い、勢いで「参加する」をクリックし現在に至ります。


## おさらい

### そもそも Gazell って何ぞ？

* [ハードウェア紹介](https://tech.microbit.org/hardware/#overview) の画像にある通り、
micro:bit の無線通信機能は [**Nordic nRF51822**](https://www.nordicsemi.com/Products/Low-power-short-range-wireless/nRF51822) という SoC が担っています。

* [**Gazell**](https://tech.microbit.org/hardware/#low-level-radio-communications) は、その Nordic さんの独自無線通信規格です。


### Gazell の Bad なところ

下げてから上げる方が良い印象が残りやすいそうなので、まずは残念な点から。

* 独自規格のため、その辺の PC やスマホと通信することはできず、  
乱暴に言うと通信するには **2 台以上の micro:bit** が必要になります。
	* この点で micro:bit でも BLE の方が人気が高いのは当然の帰結と言えます。


### Gazell の Good なところ

* **めちゃくちゃ手軽**に使えます。
	* 設計思想が UDP とよく似ており、事前のペアリングなどは無く  
	いきなり payload を投げます。
		* そのため、特定の相手に transfer するのではなく、  
		電波が届く範囲にいる相手に broadcast する動作になります。
	* Wi-Fi や Bluetooth など、無線通信と言うと事前の手続きが本当に煩わしく、  
	コードを順番に追っていくとうんざりしてしまったという方も多いと思いますが、  
	あまりに簡単に通信が成立してしまうのでびっくりします。

* **MicroPython** からでも利用できます。
	* [BLE は MakeCode Editor でのプログラミングでしか使うことができません。](https://microbit-micropython.readthedocs.io/ja/latest/ble.html)
	* MicroPython の処理系を RAM に置くことで、  
	stack size の大きな BLE は RAM に乗り切らないためです。
	* Gazell は simple & small なため、利用できます。


### 実際のサンプルコード

* [これが全てです。a-ha](https://microbit-micropython.readthedocs.io/ja/latest/radio.html#examples)
	* 送信／受信どちらの役割も兼ねているため、  
	2 台の micro:bit とも同じコードで動くのがナイスですね。


## つくろう

* 2 台の micro:bit でキャッキャするのもたいへん楽しいのですが、  
せっかくの機会なので、4 台の micro:bit で **4 x 5 cm リレー**をしたいと思います。
	* 上述の通り、送信は broadcast になるため、  
	誰が受け取るべき payload かは string の内容によって判断するようにします。

### import と定数定義

~~~python
# coding: utf-8

"""
flash :
  $ uflash [name].py
"""

from microbit import sleep as msleep
from microbit import button_a as ba
from microbit import button_b as bb

from microbit import display as dp
from microbit import Image

import radio

MEMBERS     = 4
MY_ID       = 1             # define : 1 ~ MEMBERS
CYCLE_MS    = 100
WAIT_MS     = 1000
~~~

* **MEMBERS** は参加する micro:bit の台数です。

* 今回は 4 台の micro:bit を使うので、
**MY_ID** は 1, 2, 3, 4 としたものを
それぞれの micro:bit に書き込みます。
	* 上述のサンプルコードにならい、  
	MY_ID 以外は書き換えなくて良いようにしました。


### GazellRelay クラス

~~~python
class GazellRelay :

    myid    = 0

    def __init__( self, myid) :

        radio.on()
        self.myid   = myid

    def get_id( self) :

        return  self.myid

    def send( self, cmd) :

        sendstr = '{}:{}'.format( self.myid + 1, str( cmd))
        print( sendstr)

        radio.send( sendstr)

    def recv( self) :

        recvstr = radio.receive()
        if recvstr is None :
            return  None, None

        print( recvstr)

        items   = recvstr.split( ':')
        if len( items) != 2 :
            return  None, recvstr

        print( items)

        return  items

gr  = GazellRelay( MY_ID)
~~~

* gazell 機能の処理を担当するクラスです。
	* 誰向けの payload かを識別するための **myid** と、  
	何をするのかの **cmd** を扱います。


### micro:bit の周期／イベント処理

~~~python
def init() :

    dp.show( Image.SAD)

def hdr_ba() :

    if gr.get_id() == 1 :
        dp.show( Image.HAPPY)
        gr.send( 'fire')

def hdr_bb() :

    pass

def loop() :

    r_id, cmd   = gr.recv()
    if r_id is None :
        return

    if cmd == 'finish' :
        dp.show( Image.HEART)
        return              # END

    if int( r_id) != gr.get_id() :
        return              # it's not my biz.

    if cmd == 'fire' :
        msleep( WAIT_MS)

        if gr.get_id() != MEMBERS :
            dp.show( Image.HAPPY)
            gr.send( cmd)

        else :              # I am anchor :)
            dp.show( Image.HEART)
            gr.send( 'finish')


if __name__ == "__main__" :

    init()

    while True :
        if ba.is_pressed() :
            hdr_ba()

        elif bb.is_pressed() :
            hdr_bb()

        else :
            loop()

        msleep( CYCLE_MS)
~~~

* 最初の 1 台だけＡボタンで送信します。
	* 残りは順次発火していきます。


## 実際の動作

こんな感じです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">demo: gazell relay on micro:bit. <a href="https://t.co/jPhnbHdyiL">pic.twitter.com/jPhnbHdyiL</a></p>&mdash; AndromeDroid (@AndromeDroid) <a href="https://twitter.com/AndromeDroid/status/1075788608479449088?ref_src=twsrc%5Etfw">2018年12月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

* 直列に配置することで中継器として使うこともでき、
離れた 4 点の気温をリレーして伝えてくるような使い方も
簡単にできます。

* 全体のコードは [GitHub](https://github.com/andromedroid/ame/tree/master/microbit/qiita_ac_2018/) に上げました。
	* GitHub のものは Tab indent にしています。

---

## 最後に

* micro:bit の生まれ故郷である遠い英国の地では [小学生にあまねく配布されている](https://makezine.jp/blog/2015/08/new-bbc-microbit-is-free-preteens-uk.html) と聞きます。
	* クラス全員でやったら、何台リレーできるんでしょうね？  
	ドミノチャレンジみたいで楽しそうです。

* 私が担任の先生なら「みんな１つずつピタゴラ装置を考えてー」なんて課題を出して
クラス全員でピタゴラスイッチしたら盛り上がるだろうなーと思います。
	* 伝達遅延も自由に設計できるので、  
	「止まっちゃった？…あっ動いた」みたいな演出もできますね。

* いやー、micro:bit って、本当にいいものですね！
それではまた、ご一緒に楽しみましょう。