ブロックを積みながら(15) micro:bitのBLEをラズパイPythonで捕捉

Joseph Halfmoon

ここまでmicro:bitからのBLEパケットを送受するのにスマホアプリを使用してきました。スマホは便利ですが、やりたい事によっては固定された場所で常時動作している「基地局」的なものが欲しくなります。そこで手元のラズパイ上でBLE通信プログラムの作成環境セットアップ。やはりPythonが楽だ。

※「ブロックを積みながら」投稿順 index はこちら

マクドナルドのBluetoothロケータの話を書いたときに、micro:bitを使って似たような「ロケータもどき」作れるんじゃないの、と思った記憶があるのです。ようやく実験に向けて準備をすることにいたしました。

「番号立て札」に相当する micro:bit は電池動作としてアドバタイズパケットを垂れ流し出力すればとりあえず良さそうです。すでにGoogleのEddystone型式のアドバタイズパケットを送信しつづけるものは、第11回第12回で作成済です。

対するに、移動する「番号立て札」を捕捉するための常時稼働の受信装置、こちらは固定位置のもの、が複数台あれば、RSSIから位置の推定は出来そうです、なんちゃって。この目的にはBLEの送受信ができるRaspberry Pi 3もしくはRaspberry Pi 4が適任かと考えました(長らく懸案であったRaspberry Pi 4をGW前に入手いたしました。これで Pi 3 model B+と併せて2台体制が組めます。)

また micro:bit とラズパイ間の通信が可能になれば、Pi 3 model B+ 上で動作している MQTTブローカとNode-REDサーバへの通信も簡単。やらずにはおられませんな。

さて、ラズパイ上でBLEパケットの受信もしくは送受信をするにあたって考えたのは以下の3レベルです。

  • BlueZ(Raspberry Pi OSが使用しているBluetoothプロトコルスタック)のAPIを使ってC/C++で実装する。
  • 上記のプロトコルスタック上で動作するコマンドレベルのツール、hcitoolやgattoolを利用する。
  • Pythonでスクリプトを書く。

BlueZに関しては立派なサイトがありますが、これを直接呼び出して「お楽」にプログラムが組める気がしません。どうせ下の方でお世話になるので、もっと上のレイヤで使いたいです。

hcitoolとgattoolについては過去も使ったことが無いわけでないです。Bluetoothのデバッグを行うには必須のツールだとは思います。が、BLEの内部構造をちゃんと理解していないと使いこなすのは難しいじゃないか(BLEの入門書、読み始めたのだけれどまだ三分の1くらい。GATTも全部は読めていない。ちゃんと読んだら、gatttoolを覚えたいという希望であります。)

そういう分けで、ラズパイ上のPythonでスクリプトを書く方針であります。さて、Pythonから「Bluetoothする」ためのモジュールはいろいろあるようなのですが、私の場合一択であります。

bluepy

インストールしてみて、使い方が難しかったら別のにしよう、くらいのお気楽さでまずインストールしてみたのです。一撃でラズパイ3B+上で動作してしまいました。お手軽。

環境は以下の通りで、Python3での運用です。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 10 (buster)
Release: 10
Codename: buster
$ uname -a
Linux Pi3 5.10.17-v7+ #1403 SMP Mon Feb 22 11:29:51 GMT 2021 armv7l GNU/Linux
$ python3 -V
Python 3.7.3
$ bluetoothd -v
5.50
$ bluetoothctl -h
bluetoothctl ver 5.50

bluepyのインストール方法などについては、以下に書かれています。

Github  IanHarvey/bluepy

必要なライブラリが入っていれば、pip3で普通にインストールするだけです。こんな感じ。

$ sudo pip3 install bluepy
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting bluepy
Downloading https://www.piwheels.org/simple/bluepy/bluepy-1.3.0-cp37-cp37m-linux_armv7l.whl (560kB)
100% |████████████████████████████████| 563kB 525kB/s 
Installing collected packages: bluepy
Successfully installed bluepy-1.3.0

使用方法については、以下のところに立派なドキュメントがあり、困ることはありません。

bluepy -a Bluetooth LE interface for Python

まずは、上記のドキュメントの The Scanner class というページにScannerのサンプルスクリプトが置かれているのでこれを走らせてみました。1点だけ本質的でない注意点ありです。上記のドキュメントのサンプルコードは Python 2系用で、print文になっています。Python 3系で走らせるには print() の型式にしておく必要があります。

micro:bit には第12回で作成済の Eddystone のプログラムを書きこんで走らせておき、作成したBLE SCANのプログラムを走らせました。こんな感じ。

$ sudo python3 bleSCAN_sample.py
~省略~
Discoverd device f5:d1:5f:02:68:25
~省略~
Device f5:d1:5f:02:68:25 (random), RSSI=-53 dB
Flags = 06
Complete 16b Services = 0000feaa-0000-1000-8000-00805f9b34fb
16b Service Data = aafe00f6000000000000000010000000000000ff
~省略~

フィルタも何もないBLE SCANなので複数のBluetoothデバイスが見つかっており、人力で~省略~いたしました。

UUID、0000feaa のところ、まさにEddystoneであることが分かります。データ部分を見れば

  • 00000000000000001000 = namespaceId
  • 0000000000ff = instanceId

であります。また、RSSIもちゃんと測れているみたい。まあこれだけPythonのスクリプトで取り出せれば、2箇所の結果をまとめて、どっちゃに近いとか遠いとか判定するスクリプトを書くのは簡単そうです。まずその前に、もう一台のラズパイ、Raspberry Pi 4 model Bを立ち上げないと。

ブロックを積みながら(14) micro:bit V2、BLEで出力スピーカ切り替え へ戻る

ブロックを積みながら(16) 2台のラズパイのBLE受信信号強度をNodeRedで比較 へ進む