neXenio / BLE-Indoor-Positioning

Multilateration using bluetooth beacons
Apache License 2.0
430 stars 129 forks source link

Sample code in README #150

Closed balachanthiran closed 5 years ago

balachanthiran commented 5 years ago

Hi,

I'm working bluetooth beacons and wanted to use this library to get the position of the device, so I am following the sample code provided in the README. I'm a little bit confused on how to use the distance to get the position of the device. I've tried to look at the sample app without luck. Can anybody clarify this?

Thanks.

Steppschuh commented 5 years ago

Please refer to #89

Sorry for still not providing more documentation. If you look at the sample app, you'll see that each beacon will get assigned a geo location via a LocationProvider. This is required for the indoor positioning to work.

balachanthiran commented 5 years ago

Thanks for the answer.

I have beacons assigned to a geo location with the IBeaconLocationProvider and I'm doing the following in the processScanResult():

private void processScanResult(ScanResult scanResult) {
    String macAddress = scanResult.getBleDevice().getMacAddress();
    byte[] advertisingData = scanResult.getScanRecord().getBytes();
    int rssi = scanResult.getRssi();
    AdvertisingPacket advertisingPacket = BeaconManager.processAdvertisingData(macAddress, advertisingData, rssi);
    Beacon beacon = BeaconManager.getBeacon(macAddress, advertisingPacket.getBeaconClass());
    beacon.setLocationProvider(createDebuggingLocationProvider((IBeacon) beacon));
    beacon.getDistance();
    Log.d(TAG, "RSSI: " + rssi + "distance: " + beacon.getDistance());

    IndoorPositioning.registerLocationListener(new LocationListener() {
        @Override
        public void onLocationUpdated(LocationProvider locationProvider, Location location) {
            Log.d(TAG, "Test");

        }
    });
}

Will this be sufficient enough? Does not seem like it to me.

Steppschuh commented 5 years ago

This method looks messed up. For each Bluetooth scan result (may be hundreds per second), you are creating new location providers and registering new location listeners.

You only need to add one location provider for each beacon. You also only need one location listener to get location updates.

As soon as the location provider that you created assign a valid geo location to your beacons, and as soon as you have at least three beacons in reasonable range, the IndoorPositioning singleton will be able to determine your current location and trigger your location listener.

balachanthiran commented 5 years ago

Thanks for your feedback.

I've modified the processScanResult() method to this:

private void processScanResult(@NonNull ScanResult scanResult) {
    String macAddress = scanResult.getBleDevice().getMacAddress();
    byte[] data = scanResult.getScanRecord().getBytes();
    AdvertisingPacket advertisingPacket = BeaconManager.processAdvertisingData(macAddress, data, scanResult.getRssi());

    if (advertisingPacket != null) {
        Beacon beacon = BeaconManager.getBeacon(macAddress, advertisingPacket.getBeaconClass());
        if (beacon instanceof IBeacon && !beacon.hasLocation()) {
            beacon.setLocationProvider(createDebuggingLocationProvider((IBeacon) beacon));
            System.out.println("Has location: " + beacon.hasLocation() + " Rssi: " + beacon.getRssi() + "UID: " + ((IBeacon) beacon).getMinor());
        }
    }
}

And moved the locationlistener:

    IndoorPositioning.registerLocationListener(new LocationListener() {
    @Override
    public void onLocationUpdated(LocationProvider locationProvider, Location location) {
           System.out.println("test");
    }
  });

But it does not seem like the onLocationUpdated method runs. Do you have any idea why?

balachanthiran commented 5 years ago

Hi again,

Do you have any previous experience with the LocationListener not picking up anything?

Steppschuh commented 5 years ago

The IndoorPositioning singleton may not be able to perform the multilateration if there are not enough (at least 3) usable beacons available. Usable means that they match the filter specified by IndoorPositioning.getInstance().setIndoorPositioningBeaconFilter(...), that the have recently received advertising frames (and thus can calculate a distance) and that they have a LocationProvider assigned that provides a valid location.

If your specified locations or distances do not make sense (e.g. one beacon has a location in New York and another one a location in Berlin, but both report a distance of one meter), the multilateration will fail and not emit a new location.

balachanthiran commented 5 years ago

Hi @Steppschuh, Thanks for you answer.

Regarding the filter, I can see that your sample app uses the filter: protected IBeaconFilter uuidFilter = new IBeaconFilter(IndoorPositioningAdvertisingPacket.INDOOR_POSITIONING_UUID, UUID.fromString("acfd065e-c3c0-11e3-9bbe-1a514932ac01"));

Does that IBeaconFilter only filter for one beacon? How does that work when you have at least three beacons?

Steppschuh commented 5 years ago

This particular IBeaconFilter will match all beacons that advertise IBeacon frames with one of the two specified UUIDs. Many IBeacons can advertise the same UUID (and should, if they serve the same purpose), you can use the major and minor value to differentiate them (e.g. for assigning a location in this context).

You can check out the different implementations of BeaconFilter to learn more.