example - bluetooth low energy android studio tutorial
EstimaciĆ³n de proximidad/distancia de baliza basada en RSSI-Bluetooth LE (4)
El txPower
mencionado por @davidgyoung está dado por la fórmula:
RSSI = -10 n log d + A
dónde
-
d
= distancia -
A
= txPower -
n
= constante de propagación de la señal -
RSSI
= dBm
En el espacio libre n = 2
, pero variará en función de la geometría local, por ejemplo, un muro reducirá el RSSI
en ~3dBm
y afectará a n
consecuencia.
Si desea la mayor precisión posible, puede valer la pena determinar experimentalmente estos valores para su sistema en particular.
Referencia: consulte el documento Evaluación de la confiabilidad del RSSI para la localización en interiores por Qian Dong y Waltenegus Dargie para obtener una explicación más detallada de la derivación y la calibración.
Tengo una aplicación simple para iOS que muestra la proximidad de las balizas Bluetooth LE que detecta mediante expresiones como "inmediata", "cerca", etc. y necesito escribir algo similar en Android.
He seguido el tutorial del desarrollador de Android y puedo enumerar los dispositivos detectados y ahora quiero estimar la distancia / proximidad. Aquí es donde se ha convertido un problema. De acuerdo con este hilo SO , es solo un puñado de cálculos matemáticos. Sin embargo, requieren que proporcione un valor txPower.
De acuerdo con este tutorial de Dave Smith (y las referencias cruzadas con esta declaración SIG de Bluetooth ), debe ser transmitido por los dispositivos de baliza como una "estructura de AD" de tipo 0x0A
. Entonces, lo que hago es analizar las estructuras de AD y buscar la carga útil de la que coincide con el tipo.
Problema: Tengo 4 balizas - 2 estimotes y 2 llamamientos. Los estimotes no transmiten el txPower en absoluto y las aplicaciones emiten el suyo como 0.
¿Hay algo que me esté perdiendo aquí? La aplicación de iOS parece manejarlo todo sin ningún problema, pero al usar el SDK de iOS lo hace entre bastidores, por lo que no estoy seguro de cómo producir exactamente el mismo comportamiento o el mismo. ¿Hay alguna otra forma en que pueda resolver mi problema?
En caso de que quieras echar un vistazo al código que estoy usando para analizar las estructuras de AD, está tomado del github de Dave Smith mencionado anteriormente y se puede encontrar here . El único cambio que hice a esa clase fue agregar el siguiente método:
public byte[] getData() {
return mData;
}
Y así es como manejo la devolución de llamada de los escaneos:
// 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]));
}
}
}
}
};
Y lo que veo en la consola es:
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
No está claro si su incapacidad para leer la constante de calibración "txPower" o "measuringPower" se debe a la clase AdRecord
o a la falta de información en los anuncios que está intentando analizar. No me parece que esa clase analice un anuncio estándar de iBeacon. De cualquier manera, hay una solución:
SOLUCIÓN 1: Si sus balizas envían un anuncio estándar de iBeacon que incluye la constante de calibración, puede analizarlo utilizando el código de la clase IBeacon de la biblioteca iBeacon de Android de código abierto here.
SOLUCIÓN 2: Si sus balizas NO envían un anuncio estándar de iBeacon o no incluyen una constante de calibración:
Debe codificar una constante de calibración en su aplicación para cada tipo de dispositivo que pueda usar. Todo lo que realmente necesita del anuncio para calcular la distancia es la medición del RSSI. El objetivo principal de integrar una constante de calibración en la transmisión es permitir que una amplia variedad de balizas con una potencia de salida del transmisor bastante diferente funcione con el mismo algoritmo de estimación de distancia.
La constante de calibración, tal como la define Apple, dice básicamente cuál debería ser el RSSI si su dispositivo está exactamente a un metro de la baliza. Si la señal es más fuerte (menos RSSI negativo), entonces el dispositivo está a menos de un metro de distancia. Si la señal es más débil (RSSI más negativo), entonces el dispositivo está a más de un metro de distancia. Puedes usar una fórmula para hacer una estimación numérica de la distancia. Mira aquí.
Si no está tratando con anuncios que contienen una constante de calibración "txPower" o "measuringPower", entonces puede codificar una tabla de búsqueda en su aplicación que almacene las constantes de calibración conocidas para varios transmisores. Primero deberá medir el RSSI promedio de cada transmisor a un metro de distancia. Luego necesitará algún tipo de clave para buscar estas constantes de calibración en la tabla. (¿Quizás pueda usar alguna parte de la cadena de la estructura de AD, o la dirección mac?) Por lo que su tabla podría verse así:
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));
Luego, después de analizar un anuncio, puede buscar la constante de calibración en su método onLeScan
la onLeScan
manera:
String macAddress = device.getAddress();
Integer txPower = txPowerLookupTable.get(macAddress);
usa el método getAccuracy () en la biblioteca, te da la distancia de la baliza
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));
}