先日、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
と通信を行っていきます。中編に続きます。