概要
BLE デバイスのアドバタイジングパケットに含まれる「RSSI (受信電波強度)」と「TXPower (送信電波強度)」を使って BLE デバイスと RaspberryPi との距離を算出してみました
環境
- RaspberryPi Jessie 8.0 (kernel 4.1.7+ #817)
- Bluetoothレシーバ
- nodejs 4.2.1
- npm 2.14.7
- noble 1.6.0
- BLE モジュール (BLESerial2)
BLE デバイスは何でも OK です
今回は手持ちの BLESerial2 を使ってみました
RaspberryPi 側セットアップ
Bluetooth ドングルを RaspberryPi に接続してください
今回は Nodejs 製のライブラリ noble を使って Bluetooth ドングルの制御を行います
noble のインストール
- sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
- npm install noble
制御用スクリプト
BLE デバイスをスキャンして、スキャンできた BLE デバイスから必要な情報 (RSSI, TXPower) を取得し距離を算出します
- vim scan.js
var noble = require('noble');
var serviceUUIDs = ['bd011f227d3c0db6e44155873d44ef40']; // BLESerial2
var allowDuplicates = false;
noble.on('stateChange', function(state) {
if (state === 'poweredOn') {
noble.startScanning(serviceUUIDs, allowDuplicates);
} else {
noble.stopScanning();
}
});
var n = 2
noble.on('discover', function(peripheral) {
console.log(peripheral.advertisement.localName);
peripheral.on('rssiUpdate', function(rssi) {
if (peripheral.advertisement.txPowerLevel !== undefined) {
// var tx = peripheral.advertisement.txPowerLevel;
var tx = -67;
var distance = Math.pow(10.0, (tx - rssi) / (10 * n));
console.log('tx:' + tx + ', rssi: ' + rssi + ', distance: ' + distance);
}
});
peripheral.on('connect', function() {
setInterval(function() {
peripheral.updateRssi();
}, 1000);
});
peripheral.on('disconnect', function() {
console.log('on -> disconnect');
});
peripheral.connect();
});
処理はそれほど難しくなくスキャンして見つかったデバイスに接続して 1 秒おきに RSSI の情報を取得するリクエストを投げて、そのコールバック内で距離の計算をしています
距離を算出する公式は以下の通りです
var distance = Math.pow(10.0, (tx - rssi) / (10 * n));
n はとりあえず 2.0 で設定しています
このパラメータは各自の環境に合わせて変更する必要がありそうです
また、今回は 1 つの BLE デバイスに絞りたかったので serviceUUIDs に BLESerial2 の UUID を指定しています
ので、スキャンの対象が 1 台のデバイスになっています
動作確認
Bluetooth ドングルが RUNNING になっていることを確認したら早速動作させてみましょう
BLESerial2 側の電源を ON にしてください
- sudo node scan.js
起動すると以下のようなログが表示されると思います
tx:-67, rssi: -74, distance: 2.2387211385683394
tx:-67, rssi: -75, distance: 2.51188643150958
tx:-67, rssi: -75, distance: 2.51188643150958
tx:-67, rssi: -71, distance: 1.5848931924611136
tx:-67, rssi: -66, distance: 0.8912509381337456
tx:-67, rssi: -70, distance: 1.4125375446227544
tx:-67, rssi: -60, distance: 0.44668359215096315
tx:-67, rssi: -59, distance: 0.3981071705534972
tx:-67, rssi: -59, distance: 0.3981071705534972
tx:-67, rssi: -59, distance: 0.3981071705534972
tx:-67, rssi: -59, distance: 0.3981071705534972
tx:-67, rssi: -56, distance: 0.28183829312644537
tx:-67, rssi: -58, distance: 0.35481338923357547
単位はメートルになります
実際に BLE デバイスを動かしながら距離を測定して精度を確かめてみた感じだと、RSSI が安定してから実際に距離を測れば、誤差は数十cm ほどに収まる感じでした
が、やはり RSSI の値がとても不安定で動きながらだと急に RSSI の値が大きくなったり小さくなったりするので、距離の精度も悪くなりました
考察とポイント
今回の一番のポイントは「tx」の値でした
これを初め TXPowerLevel という値を使っていたのですが、どうやらこれがおかしな値になっていたようです
本来この「tx」は何かというと
BLE デバイスから 1m 離れた地点での電波強度 [dbm]
を設定しなければいけません
実際に peripheral.advertisement.txPowerLevel で値を取得してみると 4 という固定値が返って来ました
しかし、実際に 1m 離れて電波強度を測ってみるとだいたい -65 から -70 くらいになっておりこれが原因でおかしな距離を計算していました
もう少し詳しく調査してみるとこんな表も見つかったので TXPowerLevel にあった電波強度を設定する感じなのかなと思いました
で、いろいろ考えた結果 RSSI を使って距離を求める場合、一番良さそうな方法は
各環境ごとに RSSI と距離の対応表を作成し、RSSI の値が安定したら距離を算出する
という方法が一番いいかなと感じました
やはり一番の問題は RSSI が不安定だということです
RSSI は建物や他の電波の影響をめちゃくちゃ受けるので基本不安定だと思っていたほうがいいです
なので、まずは測定したい地点で安定した RSSI が算出できるような仕組みを作るといいと思います
( 例えば 10 回 RSSI を測定した結果、ノイズ等を除去してその平均を RSSI とする、など)
あとは距離に関してですが、これも計算式だと環境によって、やはりばらつきが出てしまうと思います
なので、RSSI を測定しながら実際メジャーなどを使ってその距離を測定し RSSI と距離の対応表を作るのが一番いいんじゃないかなと思います
( おい、じゃあそもそも今回の計算式とかいらないじゃん!って話にはなってしまうのですが、、、今回やってみた感じだとそれが一番いいかなと)
もちろん n のパラメータなどを各環境にあった値にチューニングすることで精度を上げるようにしてもいいと思います
あとは精度をあげる方法として RSSI の値が整数ではなく浮動小数で測定できるようになるともっといい精度になると思います ( 現状の仕組みだとできないと思いますが )
最後に
BLE デバイスを使って距離を求める方法を紹介しました
何とか頑張れば使えるレベルにまではなると思います
が、かなり精度の高いオペレーションやリアルタイムでの測定などは難しいという印象です
実際に使う場合には BLE 単体ではなく Wifi や超音波センサなど他のセンサと絡めて測定を行うことにより精度のいい測定ができるんじゃないかなと思います
この辺の技術 (位置測定や距離測定) は探してみると結構いろいろ出てくるのでおもしろい分野かなと思います
私も、ラズパイでBLEデバイス(半径10Mぐらいのデバイス)のアドレスとRSSiを取得出来ないか、考えておりますので、この記事は、大変参考になりました。
返信削除そこで一つ質問なのですが、最近のラズパイはBluetoothを搭載しておりますが、これでも動作しますでしょうか?
手元に検証できる環境がないので何ともですが公式のスペックを見る限りは RPi3 であれば Bluetooth 4.2 に対応しているので本記事のスクリプトも動作すると思います。https://www.raspberrypi.org/products/raspberry-pi-3-model-b-plus/
返信削除もちろんライブラリなどのインストールは必要ですが
ありがとうございます。
返信削除記事をよく読ませていただきましたが!!
やはり、接続状態にあるBLE端末でないと無理でしょうか?
discover しているだけなので peripheral との接続は不要です
返信削除rssi は scan 時に取得できるのでそれを使って距離を測定しています
すいません!!
返信削除記事中の
npmでnobleをインストールします。
を実行すると下記のようなエラーが帰ります!!
~ $ npm install noble
bash: npm: コマンドが見つかりません(パスが通っていないのでしょうか?)
なぜでしょうか??教えてもらえますか!!
npm コマンドは nodejs に含まれているので、nodejs をインストールしてください
返信削除お手持ちの OS が何か不明なのですが例えば Raspbian Stretch 9.4 であれば apt コマンドでインストールできます
sudo apt -y install nodejs npm
これでバージョン 8.11/1.4.21 あたりがインストールできると思います
もしくは公式からソースを持ってきて最新版をインストールしても良いかなと思います
https://nodejs.org/ja/
ありがとうございます!!
返信削除一歩前にいきました。(~ $ npm install nobleは完了しましたが)
sudo node scan.jsを実行しても無反応です!!
ちなみに、スキャンの対象が不特定の場合、制御スプリクトは、
var serviceUUIDs = [];
ファイル名は、scan.js
でいいですか?
すいません!!
返信削除無反応ではなく
noble: unknown peripheral undefined RSSI update!
でした。
ファイル名は好きな名前で OK です
返信削除serviceUUIDs は公式のドキュメントを見ると空でも大丈夫なようです
https://github.com/noble/noble/wiki/Getting-started
「noble: unknown peripheral undefined RSSI update!」に関してはこの辺りが怪しいかなと思います
https://github.com/noble/noble/issues/413
前回のご指導の下、https://github.com/noble/noble/issues/413を参考に、再インストールしてみましたが、だめでした!!
返信削除結果は、noble: unknown peripheral undefined RSSI update!
ラズパイOS(使っているのはNOOBS_v3_0_1です。)が影響しているのでしょうか?
記事に書いてあるバージョンで試験したほうがいいのでしょうか?
単純に BLE デバイスではない Bluetooth Classic なデバイスを検知しているだけではないでしょうか
返信削除RSSI が定義されていないため undefined が表示されているような気がします
BLESerial2 はもう手に入りませんが SensorTag などの BLE 対応のビーコンデバイスで試すとうまくできる気がします
あとは node を使わなくてもできそうなので node を使い分ないのも手だと思います
ありがとうございます!!
返信削除ちまみに・・・
私が持っているポケモンGOで接続しようとすると
sudo node scan.js
Pokemon GO Plus
on -> disconnect
noble: unknown peripheral undefined RSSI update!
です。
そこで、$ sudo hcitool lescanを実行すると
LE Scan ...
**:**:**:**:**:55 Pokemon GO Plus
**:**:**:**:A2:55 (unknown)
こうなります!!
Go Plus であれば BLE デバイスですね
返信削除hcitool で取得できているのであれば RPi や Bluetooth レシーバ側ではないと思うので noble が原因かなと思います
noble を諦めないのであれば、あとは serviceUUIDs に Go Plus の UUID を指定してみるとかでしょうか
python が書けるのであれば pybluez を使ってはいかがでしょうか
サンプルも充実しているので
https://github.com/pybluez/pybluez/blob/master/examples/advanced/inquiry-with-rssi.py
参考になります!
返信削除残念ながら、以下のエラーが発生。
can not find bluetooth-hci-socket