How to get accurate distance estimations using Beacons

87 Views Asked by At

I am trying to develop an Android application that calculates the position between 3 Eddystone beacons.

I have my 3 beacons:

    final double BEACON_1_X = 0.50, BEACON_1_Y = 6.38;
    Identifier BEACON_1_ID = Identifier.parse("0x111111111111");
    final double BEACON_2_X = 5.86, BEACON_2_Y = 0.1;
    Identifier BEACON_2_ID = Identifier.parse("0x222222222222");
    final double BEACON_3_X = 0.05, BEACON_3_Y = 2.63;
    Identifier BEACON_3_ID = Identifier.parse("0x333333333333");

I am using the AltBeacon library in order to calculate the distance from the scanning device to the beacons.

Here is my code which I use in order to scan for the beacons and calculate the position according to the beacons.

for (Beacon beacon : beacons) {
                    if (!uuids.contains(beacon)) {
                        uuids.add(beacon);
                        noBeacons.setText("" + ++beaconsFound);
                    }

                    // If the beacon we see uses the Eddystone-UID frame
                    if (beacon.getServiceUuid() == 0xfeaa && beacon.getBeaconTypeCode() == 0x00) {
                        curr_dist = Double.parseDouble(df.format(beacon.getDistance()));
                        
                        if(beacon.getId2().equals(BEACON_1_ID)){
                           BEACON_1_DISTANCE = curr_dist;
                        } else if (beacon.getId2().equals(BEACON_2_ID)) {
                            BEACON_2_DISTANCE = curr_dist;
                        } else if (beacon.getId2().equals(BEACON_3_ID)) {
                            BEACON_3_DISTANCE = curr_dist;
                            if (BEACON_1_DISTANCE != 0 && BEACON_2_DISTANCE != 0){
                                calculatePosition(BEACON_1_DISTANCE,BEACON_2_DISTANCE,BEACON_3_DISTANCE);
                                logger.append("\nUser Position ("+SCANNER_X + ", " + SCANNER_Y + ")");
                            }
                        }
                        // Show its id and distance
//                        String item = "id: " + beacon.getId2() + ", distance: " + curr_dist + " m.";
//                        logger.append("\n" + item);
                    }
                }

Now in order to calculate the position I have this function: (I have found this formula on the internet that finds the position from 3 known distances so I suppose it's correct)

    void calculatePosition(double d1, double d2,double d3) {
        double A = 2*BEACON_2_X - 2*BEACON_1_X;
        double B = 2*BEACON_2_Y - 2*BEACON_1_Y;
        double C = d1*d1 - d2*d2 - BEACON_1_X*BEACON_1_X + BEACON_2_X*BEACON_2_X - BEACON_1_Y*BEACON_1_Y + BEACON_2_Y*BEACON_2_Y;
        double D = 2*BEACON_3_X - 2*BEACON_2_X;
        double E = 2*BEACON_3_Y - 2*BEACON_3_X;
        double F = d2*d2 - d3*d3 - BEACON_2_X*BEACON_2_X + BEACON_3_X*BEACON_3_X - BEACON_2_Y*BEACON_2_Y + BEACON_3_Y*BEACON_3_Y;
        SCANNER_X = (C*E - F*B) / (E*A - B*D);
        SCANNER_Y = (C*D - A*F) / (B*D - A*E);
    }

Anyway, my problem here is that the curr_dist = Double.parseDouble(df.format(beacon.getDistance())); is not accurate at all.

    /**
     * Provides a calculated estimate of the distance to the beacon based on a running average of
     * the RSSI and the transmitted power calibration value included in the beacon advertisement.
     * This value is specific to the type of Android device receiving the transmission.
     *
     * @see #mDistance
     * @return distance
     */
    public double getDistance() {
        if (mDistance == null) {
            double bestRssiAvailable = mRssi;
            if (mRunningAverageRssi != null) {
                bestRssiAvailable = mRunningAverageRssi;
            }
            else {
                LogManager.d(TAG, "Not using running average RSSI because it is null");
            }
            mDistance = calculateDistance(mTxPower, bestRssiAvailable);
        }
        return mDistance;
    }

I can have a beacon at 3m and get estimations that it is at 6m or so. I can have a beacon at 0.3m and get an estimation of 2.5m. My point is that this function doesn't work for me. I don't know if I am doing something wrong or is it some fault of AltBeacon or is it just impossible to get a correct distance. If you know any way to get more accurate distance estimates I would appreciate it. It can be a library or a manual way. Thank you in advance.

1

There are 1 best solutions below

2
davidgyoung On

You have to set your expectations when using Bluetooth distance estimates. The word estimate is used for a reason -- the value will never be highly accurate. Under ideal conditions, they will give you a general idea of distance (e.g. it estimate 1-5 meters when you are really two meters away). As you have seen, this isn't accurate enough to work well for techniques for trilateration.

I wrote a deep dive explaining why distance estimates are not more accurate, the steps you can take to make them as accurate as possible, what you shouldn't do with them, and why they are still very valuable for some use cases.