Android 基于 RSSI 估计信标接近度/距离 - 蓝牙 LE

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22784516/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:27:00  来源:igfitidea点击:

Estimating beacon proximity/distance based on RSSI - Bluetooth LE

androidbluetoothbluetooth-lowenergyandroid-bluetoothrssi

提问by JakeP

I've got a simple iOS app which displays the proximity of the Bluetooth LE beacons it detects using such expressions as "immediate", "near" etc. and I need to write something similar on Android.

我有一个简单的 iOS 应用程序,它使用诸如“立即”、“接近”等表达方式来显示它检测到的蓝牙 LE 信标的接近程度,我需要在 Android 上编写类似的内容。

I've followed the tutorial at Android developerand I'm able to list detected devices and now want to estimate the distance/proximity - this is where it's become a problem. According to this SO threadit's just a handful of mathematical calculations. However, they require me to provide a txPower value.

我遵循了Android 开发人员的教程,我能够列出检测到的设备,现在想要估计距离/接近度 - 这就是问题所在。根据this SO thread,它只是少数数学计算。但是,他们要求我提供 txPower 值。

According to this tutorial by Dave Smith(and cross-referencing with this Bluetooth SIG statement), it should be broadcast by the beacon devices as an "AD structure" of type 0x0A. So what I do is parse the AD structures and look for the payload of the one that matches the type.

根据Dave Smith 的本教程(并与此蓝牙 SIG 声明交叉引用),它应该由信标设备作为 类型的“AD 结构”进行广播0x0A。所以我要做的是解析 AD 结构并查找与类型匹配的有效负载。

Problem:I've got 4 beacons - 2 estimotes and 2 appflares. The estimotes don't broadcast the txPower at all and the appflares broadcast theirs as 0.

问题:我有 4 个信标 - 2 个 estimotes 和 2 个 appflares。estimotes 根本不广播 txPower,appflares 将它们的广播为 0。

Is there anything I'm missing here? The iOS app seems to be handling it all without any problem, but using the iOS SDK it does it behind the scenes so I'm not sure how to produce the exact same or similar behaviour. Is there any other way I could solve my problem?

有什么我在这里想念的吗?iOS 应用程序似乎可以毫无问题地处理这一切,但是使用 iOS SDK 是在幕后进行的,所以我不确定如何产生完全相同或相似的行为。有没有其他方法可以解决我的问题?

In case you'd like to take a look at the code I'm using to parse the AD structures, it's taken from the aforementioned Dave Smith's github and can be found here. The only change I did to that class was add the following method:

如果您想查看我用来解析 AD 结构的代码,它取自上述 Dave Smith 的 github,可以在此处找到。我对该类所做的唯一更改是添加以下方法:

public byte[] getData() {

    return mData;
}

And this is how I handle the callback from the scans:

这就是我处理扫描回调的方式:

// 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]));
                }
            }
        }
    }
};

And what I see in the console is:

我在控制台中看到的是:

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

回答by tep

The txPowermentioned by @davidgyoung is given by the formula:

txPower通过@davidgyoung提到由下式给出:

RSSI = -10 n log d + A

RSSI = -10 n log d + A

where

在哪里

  • d= distance
  • A= txPower
  • n= signal propagation constant
  • RSSI= dBm
  • d= 距离
  • A= 交易功率
  • n= 信号传播常数
  • RSSI= 分贝米

In free space n = 2, but it will vary based on local geometry – for example, a wall will reduce RSSIby ~3dBmand will affect naccordingly.

在自由空间n = 2,但它会根据本地的几何形状-例如,墙壁会减少RSSI通过~3dBm,并会影响n相应。

If you want the highest possible accuracy, it may be worthwhile to experimentally determine these values for your particular system.

如果您想要尽可能高的准确度,可能值得为您的特定系统通过实验确定这些值。

Reference: see the paper Evaluation of the Reliability of RSSI for Indoor Localizationby Qian Dong and Waltenegus Dargie for a more detailed explanation of the derivation and calibration.

参考:有关推导和校准的更详细说明,请参阅Qian Dong 和 Waltenegus Dargie 撰写的论文评估 RSSI 室内定位的可靠性

回答by sergey.n

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));
}

回答by davidgyoung

It is unclear whether your inability to read the "txPower" or "measuredPower" calibration constant is due to the AdRecordclass or due to the information being missing from the advertisements you are trying to parse. It doesn't look to me like that class will parse a standard iBeacon advertisement. Either way, there is a solution:

目前尚不清楚您无法读取“txPower”或“measuredPower”校准常数是由于AdRecord类还是由于您尝试解析的广告中缺少信息。在我看来,该类不会解析标准的 iBeacon 广告。无论哪种方式,都有一个解决方案:

SOLUTION 1: If your beacons send a standard iBeacon advertisementthat includes the calibration constant, you can parse it out using code in the open source Android iBeacon Library's IBeacon class here.

解决方案 1:如果您的信标发送包含校准常数的标准 iBeacon 广告,您可以使用开源Android iBeacon 库IBeacon类中的代码将其解析出来

SOLUTION 2: If your beacons DO NOT send a standard iBeacon advertisementor do not include a calibration constant:

解决方案 2:如果您的信标不发送标准 iBeacon 广告或不包含校准常数:

You must hard-code a calibration constant in your app for each device type you might use. All you really need from the advertisement to estimate distance is the the RSSI measurement. The whole point of embedding a calibration constant in the transmission is to allow a wide variety of beacons with quite different transmitter output power to work with the same distance estimating algorithm.

您必须在您的应用程序中为您可能使用的每种设备类型硬编码校准常数。您真正需要从广告中估算距离的是 RSSI 测量值。在传输中嵌入校准常数的全部意义在于允许具有完全不同的发射机输出功率的各种信标以相同的距离估计算法工作。

The calibration constant, as defined by Apple, basically says what the RSSI should be if your device is exactly one meter away from the beacon. If the signal is stronger (less negative RSSI), then the device is less than one meter away. If the signal is weaker (more negative RSSI), then the device is over one meter away. You can use a formula to make a numerical estimate of distance. See here.

Apple 定义的校准常数基本上表示如果您的设备距离信标正好一米,RSSI 应该是多少。如果信号更强(负 RSSI 更小),则设备距离不到一米。如果信号较弱(RSSI 更负),则设备距离超过一米。您可以使用公式对距离进行数值估计。 看这里。

If you aren't dealing with advertisements that contain a "txPower" or "measuredPower" calibration constant, then you can hard-code a lookup table in your app that stores the known calibration constants for various transmitters. You will first need to measure the average RSSI of each transmitter at one meter away. You'll then need some kind of key to look up these calibration constants in the table. (Perhaps you can use the some part of the string from the AD structure, or the mac address?) So your table might look like this:

如果您不处理包含“txPower”或“measuredPower”校准常数的广告,那么您可以在应用程序中硬编码一个查找表,用于存储各种发射器的已知校准常数。您首先需要测量一米外每个发射器的平均 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));

Then after parsing an advertisement, you can look up the calibration constant in your onLeScanmethod like this:

然后在解析广告后,您可以在您的onLeScan方法中查找校准常数,如下所示:

String macAddress = device.getAddress();
Integer txPower = txPowerLookupTable.get(macAddress);

回答by user1423561

use the getAccuracy() method in the library, it gives you the distance of the beacon

使用库中的 getAccuracy() 方法,它为您提供信标的距离