2015年4月13日 星期一

Android-藉由 BLE 取得 Beacon 距離資訊

更新項目 : 20150916_更新程式碼排列

雖然Beacon的出現已經不足為奇了
因為他單單只有十元硬幣的大小
且不占空間
它的應用仍然值得被探討
以下藉由小小的Demo來呈現出來

以下程式碼續接 : Android-Bluetooth Low Energy(BLE) 基本操作( 一 )

方向流程 :
1 . 藉由掃描 Bluetooth 裝置取得以下 CallBack ( OnLeScan )
2 . 在 OnLeScan 吐出來的裝置內容去分析裝置( scanRecord )
3 . 在 Sample 中,為何要判斷陣列裡的元素?
     藍芽裝置都有它的識別裝置!!!
     比如 :
     小名專長是體育
     小花專長是數學 ... 等
     如果請小名算數學,我想有時會友意想不到的驚奇吧
     話題拉回來
     如果非 Beacon 裝置大多不帶 Minor Major Txpower
     這樣我們取到的距離多少會偏差


@Override
public void onLeScan(final BluetoothDevice device, final int rssi,
        final byte[] scanRecord) {
    int startByte = 2;
    boolean patternFound = false;
    // 尋找ibeacon
    // 先依序尋找第2到第8陣列的元素
    while (startByte <= 5) {                
        // Identifies an iBeacon
        if (((int) scanRecord[startByte + 2] & 0xff) == 0x02 &&                 
                // Identifies correct data length
                ((int) scanRecord[startByte + 3] & 0xff) == 0x15) 
                {
                
             patternFound = true;
            break;
        }
        startByte++;
    }
            
    // 如果找到了的话
    if (patternFound) {
        mBluetoothAdapter.stopLeScan(mLeScanCallback);  
        // 轉換16進制
        byte[] uuidBytes = new byte[16];
        // 來源、起始位置
        System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16);
        String hexString = bytesToHex(uuidBytes);

        // UUID
        String uuid = hexString.substring(0, 8) + "-"
                + hexString.substring(8, 12) + "-"
                + hexString.substring(12, 16) + "-"
                + hexString.substring(16, 20) + "-"
                + hexString.substring(20, 32);

        // Major
        int major = (scanRecord[startByte + 20] & 0xff) * 0x100
                + (scanRecord[startByte + 21] & 0xff);

        // Minor
        int minor = (scanRecord[startByte + 22] & 0xff) * 0x100
                + (scanRecord[startByte + 23] & 0xff);

        String mac = device.getAddress();
        // txPower
        int txPower = (scanRecord[startByte + 24]);
        double distance = calculateAccuracy(txPower,rssi);
        
        Log.d(Tag, "Name:" + ibeaconName + "\nMac:" + mac
                + " \nUUID:" + uuid + "\nMajor:" + major + "\nMinor:"
                + minor + "\nTxPower:" + txPower + "\nrssi:" + rssi);

        Log.d(Tag,"distance:"+calculateAccuracy(txPower,rssi));

    }
}

將來源轉換為16進制
public String bytesToHex(byte[] bytes) {
    
    char[] hexArray = "0123456789ABCDEF".toCharArray();

    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}


計算距離 :
此方法是"即時"計算,所以很容易有大幅度波動
建議是 : 累加後均分這樣穩定度相對的高( 收集約 15 次以上後均分 )

public double calculateAccuracy(int txPower, double rssi) {
    if (rssi == 0) 
    {
        return -1.0; 
    }
    
    double ratio = rssi * 1.0 / txPower;
    
    if (ratio < 1.0) 
    {
        return Math.pow(ratio, 10);
    } 
    else 
    {
        double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
        return accuracy;
    }
}

相關連結 : 連結

-----
相關連結 : estimeote Beacon

9 則留言:

  1. 您好我有許多問題想詢問
    是否可以給個連絡方式呢?

    回覆刪除
  2. 請問距離除了平均次數的方法之外,還有哪些推薦的方法來提高更精準的數據嗎?

    回覆刪除
    回覆
    1. 如果真的要高精準,那就要3點以上定位了。

      刪除
  3. 請問有聯絡方式嗎 有問題想請教

    回覆刪除
  4. 請問一下 如果要讓他把抓到的距離傳送給藍芽 這樣有辦法嗎?

    回覆刪除
    回覆
    1. 這是可以做到的。
      不過可是這是另外的溝通方式
      你必須先知道TX/RX溝通模式

      刪除
  5. 作者已經移除這則留言。

    回覆刪除
  6. 我想請問關於BluetoothLeScanner.startScan要如何提取
    我建立ScanRecord scanRecord = result.getScanRecord()
    用String.valueOf(scanRecord.getServiceUuids())去提取
    可是一直抓不到Beacon的UUID

    回覆刪除
  7. 請問是否有其他部分教學
    啟動了藍牙但ble沒有搜尋

    回覆刪除