先日、Minecraft Java版とMinecraft 統合版(Windows10)を購入したのですが、サバイバルモードではゾンビたちにズタボロにされて1日の命もなかった自分ですが、ようやくポイントがわかってきたので、数日過ごせる(というかほぼ死ななくなった)状況になりました。ただ、クリア(?)まではあまりにも長い道のりになってきたので、そろそろ目線を変えたいなあ(オープンワールド系はあんまり集中力が続かない…)と思い始めました。
ってことで、折角だしプログラミングできないかなと思うようになりました。できればブロック言語ではなく、テキストベースでできると嬉しい感じです。電子工作的な要素もあるとさらにうれしい。
ネットで検索すると、RaspberryPi版のMinecraftとmcpi(pythonライブラリ)を使うとプログラミングができるということだったので、それを更に拡張して物理的な動きをMinecraftに持ってこれないかなと思いました。コントローラーに関してはいろいろありますが、子どもたちに自慢したいのでmicro:bitを使うことにします。
個人的には下にあるGameControllerizerの方が楽しいのではないかと思いますがチャレンジの意味を込めて、まずはmicro:bitで試してみようと思います(チャレンジは成功するとはいっていない)。
図にするとこんな感じになるかなと思います。

このなかで今回行うのは以下の部分になります。
micro:bitのBluetoothシリアル通信処理作成Minecraft Pi EditionのインストールRaspberryPiのBluetoothシリアル通信処理作成(ライブラリインストール含む)micro:bitとRaspberryPiのBluetoothシリアル通信テスト
ではやってみます!
今回のエントリーは以下を参考にしています。
micro:bit側の事前設定とプログラミング
今回のmicro:bit側のプログラムはmicro:bitの持っているボタンやセンサーが反応(トリガ)したらBluetooth UARTで文字列を送信するというものになります。
機能をまとめると以下のようになります。
Bluetooth UARTが準備できたらLEDにスマイルを表示する- Bluetooth接続が成功したらLEDにハートを表示する
- Bluetooth接続が失敗したらLEDに×を表示する
- Aボタンを押したら文字列"A"を送信する
- Bボタンを押したら文字列"B"を送信する
- micro:bit振ったら文字列"S"を送信する
- Bluetoothシリアルでデータを受信したら、受信文字列をLED表示する
まずは、ブロックプログラミングを行うのでmakecodeにアクセスします。
makecodeにアクセスしたら、【新しいプロジェクト】をクリックします。

すると新しいプロジェクトが作成されます。

デフォルトのブロックエリアにはBluetoothのブロックは含まれていないので、【高度なブロック】をクリックしメニューを展開し

更に展開された中から、【拡張機能】をクリックします。

拡張機能の一覧の表示に変わります。その中から【bluetooth】を選択してクリックします。

すると、以下のようなダイアログが表示されます。デフォルトでセットされている【radio】ブロックと【bluetooth】ブロックは機能的に同時に使用できないようです。 今回はBluetoothを使用するので、【一部の拡張機能を削除してbluetoothを追加する】をクリックします。

すると【radio】ブロックが【bluetooth】ブロックに変更されます。

Bluetoothシリアル(以下Bluetooth UARTと記載)が接続できるようにしておきます。
【bluetooth】のブロックの中から、【Bluetooth接続されたとき】【Bluetoothが切断されたとき】をプログラミングエリアにドロップします。


ブロックを取り出すと以下のようになります。

接続状態をmicro:bitのLEDで表示させておきます。【基本】のブロックから【アイコンを表示】のブロックを選択し

接続・切断の両方にいれて、それぞれ【ハート】と【×】にしておきます。

あとは、Bluetoothで使用する機能を設定します。使用するのはBluetooth UARTの機能なので、【bluetooth】ブロッククリックし、
その下に現れる【その他】をクリックし、【Bluetooth UARTサービス】をプログラミングエリアにドロップして

【最初だけ】のブロックの中に入れます。

【最初だけ】のブロックの処理が終わったら【アイコンを表示】のブロックを使ってLEDで【スマイル】マークを表示するようにします。

初期設定ができたので、あとは各種イベント(センサーの検出)が発生したらBluetooth UARTで文字列を送信する処理を作っていきます。
【入力】グループから【ボタン〇〇が押されたとき】と【ゆさぶられたの時】を選択してプログラミングエリアにドロップします。

あとは【Bluetooth UART 文字列を書き出す()】をブロック追加して、

以下のようにブロックを配置し、micro:bitのAボタンを押したら文字列”A"を、Bボタンを押したら文字列”B”を、micro:bitを揺さぶったら文字列”S”を送信するように変更をしていきます。

あとはエコーバックの文字列データ受信したらLEDに表示する処理を追加します。 以下の3つのブロックを使用して



以下のようにブロックを配置してBluetooth UARTデータを受信する処理を作成します。

ここまで出来上がったら以下のような状態になっていると思います。

ポイント
実はこのままでは、Bluetoothの接続はうまくできません。プロジェクトの設定からBluetoothの設定を変更する必要があります。 変更方法は以下のようになります。
画面の右上にある【歯車のマーク】をクリックして、プルダウンメニューの中から【プロジェクトの設定】をクリックします。

すると以下のような画面に遷移します。初期状態では

【JustWorks pairing (default): Pairing is automatic once the pairing is initiated.】のスイッチが有効になっているので、
【No Pairing Required: Anyone can connect via Bluetooth.】を有効にします。(有効にした瞬間にもとの画面に戻ってしまいます)
再度確認すると以下のような画面になっているので問題ありません。

ダウンロード
最後にこのデータ(HEXファイル)をダウンロードして、micro:bitに書き込みを行います。
まず、micro:bitをUSBケーブルでPCと接続します。すると、micro:bitはUSBストレージとして認識が行われます。
エクスプローラーからも以下の様に認識されます。

認識が完了したらmakecodeの画面に戻って、プロジェクト名を適切なものに変更し(今回はBTTestとしました)、【ダウンロード】ボタンをクリックします。

クリックするとそのままダウンロード先を指定するファイルダイアログが表示されるか

以下のようなダイアログ化が出てくると思います。

ダウンロードのファイルダイアログが表示されればそのままmicro:bitの認識されたドライブに保存し、後者のダイアログが表示されたら下ある緑色のHEXファイルのボタンをクリックします。どちらを行ってもmicro:bitにHEXファイルがダウンロードされます。
これでmicro:bitのBluetoothの通信機能ができあがりました。
では一旦、micro:bitから離れてRaspberryPi側の設定に入っていきます。
念の為ここまでのブロック図とソースを書き出して起きます。
【ブロック図】

ブロック図を参考に、そのまま同じものを作ってもいいですが、WebUIの上の方にJavaScriptソースを見るとスイッチがあるので、
切り替えると以下のようなプログラム表示されます。これをコピペしてもいいかもしれません。
(HEXファイルをドロップしてもいいのですが、サイズは大きいので、こっちのほうが楽かも)
【Javascriptソース】
bluetooth.onBluetoothConnected(function () { basic.showIcon(IconNames.Heart) }) bluetooth.onBluetoothDisconnected(function () { basic.showIcon(IconNames.No) }) input.onButtonPressed(Button.A, function () { bluetooth.uartWriteString("A") }) input.onButtonPressed(Button.B, function () { bluetooth.uartWriteString("B") }) input.onGesture(Gesture.Shake, function () { bluetooth.uartWriteString("S") }) bluetooth.onUartDataReceived(serial.delimiters(Delimiters.NewLine), function () { basic.showString(bluetooth.uartReadUntil(serial.delimiters(Delimiters.NewLine))) }) bluetooth.startUartService() basic.showIcon(IconNames.Happy) basic.forever(function () { })
RaspberryPi側の設定
micro:bitの事前設定が終わったのでRaspberryPiからBluetoothデバイスとして検出ができるようになりました。
ここからはRaspberryPi側の設定を行っていきます。
作業の手順は2つになります。
Minecraft Pi Editionをインストール- Bluetoothの
Pythonモジュールのインストール
今回使用したのはRaspberryPi 3Bとなります。Raspbianは2020-02-13-raspbian-buster.imgのイメージを使用しています。

Minecraft Pi Editionのインストール
昔はデフォルトでMinecraft Pi Editionがデフォルトでインストールされていたような気がするのですが、
最近はデフォルトではインストールされていないようです。
では、OSの設定の設定は終わっているという前提で、Minecraft Pi Editionをインストールします。
Minecraft Pi EditionはX上のプログラムなので、少なくとも起動後にX Window Systemが立ち上がるようにしておきます。
インストールは以下のようにします。
$ sudo apt update $ sudo apt upgrade $ sudo apt install minecraft-pi
インストールができたらメニューから起動ができるので起動してみましょう。 メニューのゲームカテゴリに進むと【Maincraft Pi】が追加されているのでそれをクリックします。

すると、Maincraft Pi EDITIONと表示されたウインドウが開きます。
今後のテストもあるので【Start Game】ボタンをクリックして、

ウィンドウの下にある、【Create new】ボタンをクリックして、新しいワールドを作成します。

クリックすると新しいワールドを生成する処理が行われて

開始することができました。

ここまでできたらMinecraft Pi Editionのインストール作業は完了です。
bluepyのインストール
bluepyは、Bluetooth Low Energyデバイスとの通信を可能にするPythonモジュールで、Linux上で実装されています。(内部的にはBlueZプロジェクトのコードを使用)
bluepy is a Python module which allows communication with Bluetooth Low Energy devices. The current implementation runs on Linux (internally it uses code from the BlueZ project), although it can be ported to other platforms.
こちらをインストールしてmicro:bitとBluetooth接続を行っていきます。
インストールは以下のコマンドを実行します。python2系でも大丈夫ですが、python3系でも実行できるのでpip3を使用します。
$ sudo apt update $ sudo apt upgrade $ sudo apt install python3-pip libglib2.0-dev $ sudo pip3 install bluepy
インストールすると、hcitoolコマンドが使用可能になるので、以下のコマンドを実行してBluetooth機器をスキャンする事ができます。
$ sudo hcitool lescan
上記のように実行すると【Ctrl+C】を押さないと終了しないので、以下のようにtimeoutコマンドと組み合わせることで一定時間で終了させることができます。(以下の場合は5秒でタイムアウト)
$ sudo timeout 5s hcitool lescan
【実行例】
$ sudo timeout 5s hcitool lescan LE Scan ... (略) DB:BE:XX:XX:XX:XX BBC micro:bit [tizup] (略)
上記のようにmicro:bitが検出されます。今回はIDをDB:BE:XX:XX:XX:XXとしていますが、それぞれの環境で違う値になると思いますので
この値を覚えておきましょう。[]中の文字列も異なると思います。
RaspberryPi側のプログラム
では、実際にRaspberryPi側のプログラムをドキュメントを参考にして作成していきます。
lancaster-university.github.io
使用するUUIDは以下の通りです。 ドキュメントのUUIDは”-”が含まれていないのですが、ソースコード側には”-”が含まれているので注意が必要です。
| UUID | |
|---|---|
| UART SERVICE | 6E400001-B5A3-F393-E0A9-E50E24DCCA9E |
| UART SERVICE - CHARACTERISTICS(TX) | 6E400002-B5A3-F393-E0A9-E50E24DCCA9E |
| UART SERVICE - CHARACTERISTICS(RX) | 6E400003-B5A3-F393-E0A9-E50E24DCCA9E |
【BtSerial.py】
from bluepy import btle class MyDelegate(btle.DefaultDelegate): def __init__(self, TX, RX): btle.DefaultDelegate.__init__(self) self.TX = TX self.RX = RX def handleNotification(self, hd, data): print("notification: {},{}".format(hd,data)) chRX.write("!\n".encode("utf-8")) # 第一引数はhcitool lescanで得られたIDに変更すること、変更しないとエラーとなります。 per = btle.Peripheral("DB:BE:XX:XX:XX:XX", btle.ADDR_TYPE_RANDOM) # UART Service svcUART = per.getServiceByUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E") # TX Characteristics chTX = svcUART.getCharacteristics("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")[0] ch_cccd=chTX.getDescriptors(forUUID=0x2902)[0] ch_cccd.write(b"\x03\x00", False) # RX Characteristics chRX = svcUART.getCharacteristics("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")[0] dg = MyDelegate(chTX, chRX) per.setDelegate(dg) chRX.write("start!\n".encode("utf-8")) while True: if per.waitForNotifications(0.1): continue
こちらのプログラムを動作させると以下のような結果を得ることができます。
$ python3 BTSerial.py notification: 39,b'S' notification: 39,b'S' notification: 39,b'A' notification: 39,b'B' notification: 39,b'A'
micro:bit側でエコーされたデータを受信し、LEDに文字表示している最中に、データを受信するとエラーが発生します。
実際に使用する場合にはmicro:bit側の文字列などの表示はしないようにした方がいいでしょう。
以下のようなエラーが発生します。
Traceback (most recent call last):
File "BTSerial.py", line 31, in <module>
if per.waitForNotifications(0.1):
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 407, in _getResp
resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 362, in _waitResp
raise BTLEDisconnectError("Device disconnected", resp)
bluepy.btle.BTLEDisconnectError: Device disconnected
おわりに
ここまででmicro:bitとRaspberryPiのBluetooth UART通信ができるようになりました。ここからはmcpiを使ってMinecraft Pi Editionと通信を行っていきます。中編に続きます。