24

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

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

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

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

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

如果你想看看我用来解析 AD 结构的代码,它取自前面提到的 Dave Smith 的 github,可以在这里找到。我对该类所做的唯一更改是添加以下方法:

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
4

4 回答 4

33

@davidgyoungtxPower 提到的由公式给出:

RSSI = -10 n log d + A

在哪里

  • d= 距离
  • A= 发送功率
  • n= 信号传播常数
  • RSSI= 分贝

在自由空间n = 2中,但它会根据局部几何形状而有所不同——例如,墙会减少RSSI~3dBm会产生n相应的影响。

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

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

于 2014-06-16T14:13:49.407 回答
27
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));
}
于 2014-12-18T15:56:23.453 回答
24

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

解决方案 1:如果您的信标发送包含校准常量的标准 iBeacon 广告,您可以在此处使用开源Android iBeacon 库的 IBeacon 类中的代码对其进行解析

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

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

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

如果您不处理包含“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));

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

String macAddress = device.getAddress();
Integer txPower = txPowerLookupTable.get(macAddress);
于 2014-04-01T13:35:54.030 回答
-2

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

于 2014-06-24T06:50:14.873 回答