web-dev-qa-db-fra.com

Exemple de triangulation pour les iBeacons

Je suis en train d’étudier la possibilité d’utiliser plusieurs iBeacons pour effectuer un positionnement "approximatif" à l’intérieur. L'application est une sorte de "musée", et il serait plus facile de pouvoir former une grille avec des emplacements pour les différents objets, puis des balises individuelles (bien que cela puisse ne pas être impossible aussi).

Existe-t-il des exemples, des expériences d'utilisation de plusieurs balises pour effectuer une triangulation dans une sorte d'emplacement ou une logique pour m'aider à l'écrire moi-même?

73
Luuk D. Jansen

J'ai fait des expériences pour obtenir une position précise à l'aide de trois balises.

Résultats de la trilatération

Malheureusement, les résultats ont été très décevants en termes de qualité. Il y avait principalement deux problèmes:

  1. Dans les environnements non contrôlés, où vous pouvez trouver des métaux et d'autres objets qui affectent le signal, la force du signal reçu par les balises change si souvent qu'il semble impossible d'obtenir une plage d'erreur inférieure à 5 mètres.
  2. Selon la manière dont l'utilisateur gère le récepteur, les lectures peuvent également beaucoup changer. Si l'utilisateur place sa main sur l'antenne Bluetooth, alors l'algorithme aura des signaux bas en entrée, ce qui permettra aux balises d'être très éloignées de l'appareil. Voir cette image pour voir l'emplacement précis de l'antenne Bluetooth.

Solutions possibles

Après avoir discuté avec un ingénieur Apple) qui m’a activement découragé de choisir cette option, je me sens plus enclin à utiliser maintenant la force brute. Essayez d’installer une balise tous les X mètres (X étant l'erreur maximale tolérée dans le système) afin de pouvoir suivre sur cette grille de balises la position d'un appareil donné en calculant quelle balise sur la grille est la plus proche de l'appareil et en supposant que l'appareil se trouve sur la même position.

Algorithme de trilatération

Cependant, par souci d'exhaustivité, je partage ci-dessous la fonction principale de l'algorithme de trilatération. Il est basé sur le paragraphe 3 ("Trois distances connues") de cet article .

- (CGPoint)getCoordinateWithBeaconA:(CGPoint)a beaconB:(CGPoint)b beaconC:(CGPoint)c distanceA:(CGFloat)dA distanceB:(CGFloat)dB distanceC:(CGFloat)dC {
    CGFloat W, Z, x, y, y2;
    W = dA*dA - dB*dB - a.x*a.x - a.y*a.y + b.x*b.x + b.y*b.y;
    Z = dB*dB - dC*dC - b.x*b.x - b.y*b.y + c.x*c.x + c.y*c.y;

    x = (W*(c.y-b.y) - Z*(b.y-a.y)) / (2 * ((b.x-a.x)*(c.y-b.y) - (c.x-b.x)*(b.y-a.y)));
    y = (W - 2*x*(b.x-a.x)) / (2*(b.y-a.y));
    //y2 is a second measure of y to mitigate errors
    y2 = (Z - 2*x*(c.x-b.x)) / (2*(c.y-b.y));

    y = (y + y2) / 2;
    return CGPointMake(x, y);
}
73
Javier Chávarri

Voici une bibliothèque open source Java) qui effectuera la trilatération/multilatération: https://github.com/lemmingapex/Trilateration

example

Il utilise un optimiseur de moindres carrés non linéaire populaire, l'algorithme de Levenberg-Marquardt, de Apache Commons Math.

double[][] positions = new double[][] { { 5.0, -6.0 }, { 13.0, -15.0 }, { 21.0, -3.0 }, { 12.42, -21.2 } };
double[] distances = new double[] { 8.06, 13.97, 23.32, 15.31 };

NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(new TrilaterationFunction(positions, distances), new LevenbergMarquardtOptimizer());
Optimum optimum = solver.solve();

// the answer
double[] calculatedPosition = optimum.getPoint().toArray();

// error and geometry information
RealVector standardDeviation = optimum.getSigma(0);
RealMatrix covarianceMatrix = optimum.getCovariances(0);

La plupart des exemples savants, comme celui sur wikipedia , traitent avec exactement trois cercles et supposent des informations parfaitement précises. Ces circonstances permettent des formulations de problèmes beaucoup plus simples avec des réponses exactes, et ne sont généralement pas satisfaisantes pour des situations pratiques.

Le problème en R2 ou R3 l’espace euclidien dont les distances contiennent des erreurs de mesure, une zone (ellipse) ou un volume (ellipsoïde) d’intérêt est généralement obtenu au lieu d’un point. Si une estimation ponctuelle est souhaitée au lieu d'une région, vous devez utiliser le centroïde d'aire ou le centroïde de volume. R2 l'espace nécessite au moins 3 points et distances non dégénérés pour obtenir une région unique; et de même R3 l'espace nécessite au moins 4 points et distances non dégénérés pour obtenir une région unique.

22
Scott Wiedemann

J'ai examiné ceci. Le terme que vous voulez trilatération. (En triangulation, vous avez des angles à partir de 3 points connus. En trilatération, vous avez une distance à partir de 3 points connus.) Si vous utilisez Google, vous devriez trouver plusieurs articles, dont un sur Wiki. Il s’agit de résoudre un ensemble de 3 équations simultanées. Les documents que j'ai vus concernaient la trilatération 3D - La 2D est plus facile car vous pouvez simplement supprimer le terme Z.

Ce que j'ai trouvé, c'est des mathématiques abstraites. Je n'ai pas encore pris le temps de mapper l'algorithme général dans un code spécifique, mais je prévois de le traiter à un moment donné.

Notez que les résultats que vous obtiendrez seront TRES crus, en particulier dans tout sauf une pièce vide. Les signaux sont suffisamment faibles pour qu'une personne, une statue ou tout ce qui bloque la ligne de mire augmente de façon significative vos lectures de distance. Vous pouvez même avoir des endroits dans un bâtiment où des interférences constructives (principalement des murs) rendent certains endroits plus lus qu'ils ne le sont réellement.

15
Duncan C

Un positionnement précis à l'intérieur avec iBeacon constituera un défi pour les raisons suivantes:

  1. Comme indiqué dans les commentaires précédents, le signal iBeacon a tendance à beaucoup fluctuer. La raison inclut l'effet multipath , les obstructions d'objet dynamique entre le téléphone et iBeacon lorsque la personne se déplace, les autres interférences à 2,4 GHz, etc. Donc, idéalement, vous ne voulez pas faire confiance aux données d'un seul paquet, mais plutôt calculer la moyenne de plusieurs paquets de la même balise. Cela nécessiterait que la distance téléphone/balise ne change pas trop entre ces plusieurs paquets. Pour les paquets BLE généraux (comme les balises de StickNFind), il est facile de régler le taux de balisage à 10Hz. Cependant, pour iBeacon, ce sera difficile, car
  2. la fréquence de balisage d'iBeacon ne peut probablement pas dépasser 1Hz. Je serai heureux si quelqu'un peut indiquer une source qui dit le contraire, mais toutes les informations que j'ai vues jusqu'à présent confirment cette affirmation. Cela a du sens puisque la plupart des iBeacons sont alimentés par batterie et que les hautes fréquences ont un impact significatif sur leur durée de vie. Considérant que la vitesse moyenne de marche des personnes est de 5,3 km (~ 1,5 m/s), donc même si vous utilisez simplement 3 paquets de balises pour effectuer la moyenne, il vous sera difficile d’obtenir une précision d’environ 5 m.

D'autre part, si vous pouviez augmenter la fréquence iBeacon à plus de 10 Hz (ce dont je doute, c'est possible), il est alors possible d'obtenir une précision de 5 m ou plus en utilisant une méthode de traitement appropriée. Premièrement, les solutions triviales basées sur le loi inverse , comme la trilatération, ne donnent souvent pas de bons résultats car, dans la pratique, la relation distance/RSSI de différentes balises est souvent très éloignée de la loi inverse. 1 ci-dessus. Mais tant que le RSSI est relativement stable pour une certaine balise à un endroit donné (ce qui est généralement le cas), vous pouvez utiliser une approche appelée prise d'empreintes digitales pour obtenir une plus grande précision. Une méthode couramment utilisée pour les empreintes digitales est kNN ( k-plus proche voisin ).

Mise à jour du 2014-04-24

Certaines iBeacons peuvent diffuser plus de 1Hz, comme Estimote utilisent 5Hz par défaut. Cependant, selon ce lien : ", ceci est Apple. IOS renvoie les balises mises à jour tous les deuxièmement, quelle que soit la fréquence de publicité de l'appareil. ". Il y a un autre commentaire (probablement de la part du fournisseur Estimote) disant" . Nos balises peuvent diffuser beaucoup plus rapidement et il peut améliorer les résultats et la mesure ". Ainsi, il n’est pas clair si une fréquence iBeacon plus élevée est bénéfique.

7
Penghe Geng

Si vous êtes un peu comme moi et que vous n'aimez pas les maths, vous voudrez peut-être effectuer une recherche rapide pour "indoor positionnement sdk". Il existe de nombreuses entreprises proposant un positionnement à l'intérieur en tant que service.

Prise sans scrupule: je travaille pour indoo.rs et je peux recommander ce service. Cela inclut également le routage et autres, en plus du positionnement "juste" à l'intérieur.

6
TomTasche

Mon architecte/gestionnaire, qui a écrit l'algorithme suivant,

public static Location getLocationWithCenterOfGravity(Location beaconA, Location beaconB, Location beaconC, double distanceA, double distanceB, double distanceC) {

    //Every meter there are approx 4.5 points
    double METERS_IN_COORDINATE_UNITS_RATIO = 4.5;

    //http://stackoverflow.com/a/524770/663941
    //Find Center of Gravity
    double cogX = (beaconA.getLatitude() + beaconB.getLatitude() + beaconC.getLatitude()) / 3;
    double cogY = (beaconA.getLongitude() + beaconB.getLongitude() + beaconC.getLongitude()) / 3;
    Location cog = new Location("Cog");
    cog.setLatitude(cogX);
    cog.setLongitude(cogY);


    //Nearest Beacon
    Location nearestBeacon;
    double shortestDistanceInMeters;
    if (distanceA < distanceB && distanceA < distanceC) {
        nearestBeacon = beaconA;
        shortestDistanceInMeters = distanceA;
    } else if (distanceB < distanceC) {
        nearestBeacon = beaconB;
        shortestDistanceInMeters = distanceB;
    } else {
        nearestBeacon = beaconC;
        shortestDistanceInMeters = distanceC;
    }

    //http://www.mathplanet.com/education/algebra-2/conic-sections/distance-between-two-points-and-the-midpoint
    //Distance between nearest beacon and COG
    double distanceToCog = Math.sqrt(Math.pow(cog.getLatitude() - nearestBeacon.getLatitude(),2)
            + Math.pow(cog.getLongitude() - nearestBeacon.getLongitude(),2));

    //Convert shortest distance in meters into coordinates units.
    double shortestDistanceInCoordinationUnits = shortestDistanceInMeters * METERS_IN_COORDINATE_UNITS_RATIO;

    //http://math.stackexchange.com/questions/46527/coordinates-of-point-on-a-line-defined-by-two-other-points-with-a-known-distance?rq=1
    //On the line between Nearest Beacon and COG find shortestDistance point apart from Nearest Beacon

    double t = shortestDistanceInCoordinationUnits/distanceToCog;

    Location pointsDiff = new Location("PointsDiff");
    pointsDiff.setLatitude(cog.getLatitude() - nearestBeacon.getLatitude());
    pointsDiff.setLongitude(cog.getLongitude() - nearestBeacon.getLongitude());

    Location tTimesDiff = new Location("tTimesDiff");
    tTimesDiff.setLatitude( pointsDiff.getLatitude() * t );
    tTimesDiff.setLongitude(pointsDiff.getLongitude() * t);

    //Add t times diff with nearestBeacon to find coordinates at a distance from nearest beacon in line to COG.

    Location userLocation = new Location("UserLocation");
    userLocation.setLatitude(nearestBeacon.getLatitude() + tTimesDiff.getLatitude());
    userLocation.setLongitude(nearestBeacon.getLongitude() + tTimesDiff.getLongitude());

    return userLocation;
}
  1. Calculer le centre de gravité pour un triangle (3 balises)
  2. calculer la distance la plus courte/balise la plus proche
  3. Calculer la distance entre la balise et le centre de gravité
  4. Convertissez la distance la plus courte en unités de coordonnées, ce qui n’est qu’une constante, il prédisait la précision. Vous pouvez tester avec varing la constante
  5. calculer le delta de distance
  6. ajoutez le delta avec la balise la plus proche x, y.

Après l'avoir testé, je l'ai trouvé précis à 5 mètres.

Veuillez commenter vos tests, si nous pouvons les affiner.

5
Vishnu Prabhu

Pour ceux qui ont besoin de @Javier Chávarri fonction de trilatération pour les appareils Android (pour gagner du temps):

public static Location getLocationWithTrilateration(Location beaconA, Location beaconB, Location beaconC, double distanceA, double distanceB, double distanceC){

    double bAlat = beaconA.getLatitude();
    double bAlong = beaconA.getLongitude();
    double bBlat = beaconB.getLatitude();
    double bBlong = beaconB.getLongitude();
    double bClat = beaconC.getLatitude();
    double bClong = beaconC.getLongitude();

    double W, Z, foundBeaconLat, foundBeaconLong, foundBeaconLongFilter;
    W = distanceA * distanceA - distanceB * distanceB - bAlat * bAlat - bAlong * bAlong + bBlat * bBlat + bBlong * bBlong;
    Z = distanceB * distanceB - distanceC * distanceC - bBlat * bBlat - bBlong * bBlong + bClat * bClat + bClong * bClong;

    foundBeaconLat = (W * (bClong - bBlong) - Z * (bBlong - bAlong)) / (2 * ((bBlat - bAlat) * (bClong - bBlong) - (bClat - bBlat) * (bBlong - bAlong)));
    foundBeaconLong = (W - 2 * foundBeaconLat * (bBlat - bAlat)) / (2 * (bBlong - bAlong));
    //`foundBeaconLongFilter` is a second measure of `foundBeaconLong` to mitigate errors
    foundBeaconLongFilter = (Z - 2 * foundBeaconLat * (bClat - bBlat)) / (2 * (bClong - bBlong));

    foundBeaconLong = (foundBeaconLong + foundBeaconLongFilter) / 2;

    Location foundLocation = new Location("Location");
        foundLocation.setLatitude(foundBeaconLat);
        foundLocation.setLongitude(foundBeaconLong);

    return foundLocation;
}
5
hrskrs

J'ai implémenté un très simple empreinte digitale algorithme pour Android 4.4, testé dans un "mauvais" environnement relatif:

  • près de 10 wifi AP à proximité.
  • plusieurs autres signaux Bluetooth à proximité.

la précision semble dans 5-8 mètres et dépend de la façon dont j'ai placé ce diffuseur 3 Ibeacon. L'algorithme est assez simple et je pense que vous pouvez en implémenter un par vous-même, les étapes sont les suivantes:

  1. charger la carte intérieure.
  2. échantillonnage avec la carte pour tout le point de positionnement en attente.
  3. enregistrer toutes les données d'échantillonnage, les données doivent inclure: les coordonnées de la carte, les signaux de position et leur RSSI.

ainsi, lorsque vous commencez à vous positionner, il s’agit simplement d’un processus inverse.

4
Shawn

Nous essayons également de trouver le meilleur moyen de localiser avec précision quelqu'un dans une pièce à l'aide d'iBeacons. Le fait est que la puissance du signal de balise n’est pas constante et qu’elle est affectée par d’autres signaux à 2,4 Ghz, objets métalliques, etc., de sorte que pour obtenir une précision maximale, il est nécessaire de calibrer chaque balise individuellement et une fois celle-ci réglée à la position souhaitée. . (et effectuez un test sur le terrain pour voir les fluctuations du signal lorsque d’autres périphériques Bluetooth sont présents). Nous avons également quelques iBeacons d’Evaluote (le même que dans la vidéo de Konrad Dzwinel), et ils ont déjà développé une démo technologique de ce qui peut être fait avec les iBeacons. Dans leur application, il est possible de voir un radar dans lequel des iBeacons sont affichés. Parfois, c'est assez précis, mais parfois ça ne l'est pas (et il semble que le téléphone n'est pas pris en compte pour calculer les positions). Regardez la démo dans la vidéo que nous avons faite ici: http://goo.gl/98hiza

Bien qu'en théorie, 3 balises soient suffisantes pour obtenir une bonne précision, peut-être que dans des situations réelles, davantage de balises sont nécessaires pour garantir la précision que vous recherchez.

3
tomacco

La chose qui m'a vraiment aidé est ce projet sur Code.Google.com: https://code.google.com/p/wsnlocalizationscala/ il contient beaucoup de code, plusieurs algorithmes de trilatération, tous écrits en C #. C'est une grande bibliothèque, mais pas vraiment destinée à être utilisée "prête à l'emploi".

3
woutercx

Veuillez vérifier la référence https://proximi.io/accurate-indoor-positioning-bluetooth-beacons/

Proximi SDK se chargera de la triangulation. Ce SDK fournit des bibliothèques permettant de gérer toute la logique de positionnement, de triangulation et de filtrage des balises en arrière-plan. En plus des balises, vous pouvez combiner IndoorAtlas, Wi-Fi, GPS et positionnement cellulaire.

2
Ambi

J'ai trouvé la solution de Vishnu Prahbu très utile. Je l'ai porté en c #, si quelqu'un en a besoin.

public static PointF GetLocationWithCenterOfGravity(PointF a, PointF b, PointF c, float dA, float dB, float dC)
    {
        //http://stackoverflow.com/questions/20332856/triangulate-example-for-ibeacons
        var METERS_IN_COORDINATE_UNITS_RATIO = 1.0f;

        //http://stackoverflow.com/a/524770/663941
        //Find Center of Gravity
        var cogX = (a.X + b.X + c.X) / 3;
        var cogY = (a.Y + b.Y + c.Y) / 3;
        var cog = new PointF(cogX,cogY);

        //Nearest Beacon
        PointF nearestBeacon;
        float shortestDistanceInMeters;
        if (dA < dB && dA < dC)
        {
            nearestBeacon = a;
            shortestDistanceInMeters = dA;
        }
        else if (dB < dC)
        {
            nearestBeacon = b;
            shortestDistanceInMeters = dB;
        }
        else
        {
            nearestBeacon = c;
            shortestDistanceInMeters = dC;
        }

        //http://www.mathplanet.com/education/algebra-2/conic-sections/distance-between-two-points-and-the-midpoint
        //Distance between nearest beacon and COG
        var distanceToCog =  (float)(Math.Sqrt(Math.Pow(cog.X - nearestBeacon.X, 2)
                + Math.Pow(cog.Y - nearestBeacon.Y, 2)));

        //Convert shortest distance in meters into coordinates units.
        var shortestDistanceInCoordinationUnits = shortestDistanceInMeters * METERS_IN_COORDINATE_UNITS_RATIO;

        //http://math.stackexchange.com/questions/46527/coordinates-of-point-on-a-line-defined-by-two-other-points-with-a-known-distance?rq=1
        //On the line between Nearest Beacon and COG find shortestDistance point apart from Nearest Beacon
        var t = shortestDistanceInCoordinationUnits / distanceToCog;
        var pointsDiff = new PointF(cog.X - nearestBeacon.X, cog.Y - nearestBeacon.Y);
        var tTimesDiff = new PointF(pointsDiff.X * t, pointsDiff.Y * t);

        //Add t times diff with nearestBeacon to find coordinates at a distance from nearest beacon in line to COG.
        var userLocation = new PointF(nearestBeacon.X + tTimesDiff.X, nearestBeacon.Y + tTimesDiff.Y);

        return userLocation;
    }
1
Tom

Équation alternative

- (CGPoint)getCoordinateWithBeaconA:(CGPoint)a beaconB:(CGPoint)b beaconC:(CGPoint)c distanceA:(CGFloat)dA distanceB:(CGFloat)dB distanceC:(CGFloat)dC {


CGFloat x, y;
x = ( ( (pow(dA,2)-pow(dB,2)) + (pow(c.x,2)-pow(a.x,2)) + (pow(b.y,2)-pow(a.y,2)) ) * (2*c.y-2*b.y) - ( (pow(dB,2)-pow(dC,2)) + (pow(c.x,2)-pow(c.x,2)) + (pow(c.y,2)-pow(b.y,2)) ) *(2*b.y-2*a.y) ) / ( (2*b.x-2*c.x)*(2*b.y-2*a.y)-(2*a.x-2*b.x)*(2*c.y-2*b.y) );

y = ( (pow(dA,2)-pow(dB,2)) + (pow(c.x,2)-pow(a.x,2)) + (pow(b.y,2)-pow(a.y,2)) + x*(2*a.x-2*b.x)) / (2*b.y-2*a.y);



return CGPointMake(x, y);
}
0
jdog