「イミディエート」、「ニア」などの表現を使用して検出したBluetooth LEビーコンの近接度を表示するシンプルなiOSアプリがあります。Androidでも同様のものを作成する必要があります。
Android developer のチュートリアルに従っていますが、検出されたデバイスを一覧表示できるようになり、距離/近接を推定したいと考えています。これが問題になります。 this SO thread によると、ほんの一握りの数学的計算ですが、txPower値を提供する必要があります。
Dave Smithによるこのチュートリアル (およびこれと相互参照 Bluetooth SIGステートメント )によると、ビーコンデバイスはタイプ0x0A
の「AD構造」としてブロードキャストする必要があります。 。だから私は、AD構造を解析し、タイプに一致するペイロードを探します。
問題:4つのビーコン-2つのエスティモートと2つのフレアがあります。 estimotesはtxPowerをまったくブロードキャストせず、appflaresは0としてブロードキャストします。
ここに足りないものはありますか? iOSアプリは問題なくすべてを処理しているようですが、iOS SDKを使用してバックグラウンドで処理するため、まったく同じまたは同様の動作を生成する方法がわかりません。私の問題を解決できる他の方法はありますか?
AD構造の解析に使用しているコードをご覧になりたい場合は、前述のDave Smithのgithubから取得し、 here にあります。そのクラスに対して行った唯一の変更は、次のメソッドを追加することでした。
public byte[] getData() {
return mData;
}
そして、これは私がスキャンからのコールバックをどのように処理するかです:
// Prepare the callback for BLE device scan
this.leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (!deviceList.contains(device)) {
MyService.this.deviceList.add(device);
Log.e("Test", "Device: " + device.getName());
List<AdRecord> adRecords = AdRecord.parseScanRecord(scanRecord);
for (AdRecord adRecord : adRecords) {
if (adRecord.getType() == AdRecord.TYPE_TRANSMITPOWER) {
Log.e("Test", "size of payload: " + adRecord.getData().length);
Log.e("Test", "payload: " + Byte.toString(adRecord.getData()[0]));
}
}
}
}
};
コンソールに表示されるのは:
04-01 11:33:35.864: E/Test(15061): Device: estimote
04-01 11:33:36.304: E/Test(15061): Device: estimote
04-01 11:33:36.475: E/Test(15061): Device: n86
04-01 11:33:36.475: E/Test(15061): size of payload: 1
04-01 11:33:36.475: E/Test(15061): payload: 0
04-01 11:33:36.525: E/Test(15061): Device: f79
04-01 11:33:36.525: E/Test(15061): size of payload: 1
04-01 11:33:36.525: E/Test(15061): payload: 0
「txPower」または「measuredPower」校正定数を読み取ることができないのは、AdRecord
クラスによるものなのか、解析しようとしている広告から情報が欠落しているためなのかは不明です。そのクラスが標準のiBeacon広告を解析するようには思えません。いずれにしても、解決策があります。
解決策1:ビーコンがキャリブレーション定数を含む標準iBeaconアドバタイズメントを送信する場合、オープンソースのコードを使用して解析できます Android iBeacon Library のIBeaconクラス ここ
解決策2:ビーコンが標準のiBeaconアドバタイズメントを送信しない場合、またはキャリブレーション定数を含めない場合:
使用する可能性のあるデバイスの種類ごとに、アプリでキャリブレーション定数をハードコーディングする必要があります。広告から距離を推定するために本当に必要なのは、RSSIの測定値だけです。伝送にキャリブレーション定数を埋め込むことの全体的なポイントは、まったく異なるトランスミッター出力パワーを持つ多種多様なビーコンが同じ距離推定アルゴリズムで動作できるようにすることです。
Appleが定義したキャリブレーション定数は、基本的に、デバイスがビーコンから1メートル離れている場合にRSSIがどうあるべきかを示しています。信号が強い場合(負のRSSIが小さい場合)、デバイスは1メートル以内にあります。信号が弱い場合(より負のRSSI)、デバイスは1メートル以上離れています。式を使用して、距離を数値で推定できます。 こちらをご覧ください
「txPower」または「measuredPower」キャリブレーション定数を含む広告を扱っていない場合は、さまざまなトランスミッターの既知のキャリブレーション定数を保存するルックアップテーブルをアプリにハードコーディングできます。最初に、1メートル離れた各送信機の平均RSSIを測定する必要があります。次に、表でこれらのキャリブレーション定数を検索するために、何らかの種類のキーが必要になります。 (おそらく、AD構造の文字列の一部、またはMACアドレスを使用できますか?)したがって、テーブルは次のようになります。
HashMap<String,Integer> txPowerLookupTable = new HashMap<String,Integer>();
txPowerLookupTable.put("a5:09:37:78:c3:22", new Integer(-65));
txPowerLookupTable.put("d2:32:33:5c:87:09", new Integer(-78));
次に、広告を解析した後、次のようにonLeScan
メソッドでキャリブレーション定数を検索できます。
String macAddress = device.getAddress();
Integer txPower = txPowerLookupTable.get(macAddress);
@davidgyoungによって言及されたtxPower
は、式によって与えられます:
RSSI = -10 n log d + A
どこで
d
=距離A
= txPowern
=信号伝搬定数RSSI
= dBm空き領域内n = 2
、ただし、ローカルジオメトリに基づいて異なります。たとえば、壁はRSSI
を~3dBm
そしてそれに応じてn
に影響します。
可能な限り最高の精度が必要な場合は、特定のシステムのこれらの値を実験的に決定する価値があります。
参照:導出とキャリブレーションのより詳細な説明については、Qian DongとWaltenegus Dargieによる論文 屋内位置特定のためのRSSIの信頼性の評価 を参照してください。
double getDistance(int rssi, int txPower) {
/*
* RSSI = TxPower - 10 * n * lg(d)
* n = 2 (in free space)
*
* d = 10 ^ ((TxPower - RSSI) / (10 * n))
*/
return Math.pow(10d, ((double) txPower - rssi) / (10 * 2));
}