rekabhq / background_locator

A Flutter plugin for updating location in background.
MIT License
288 stars 338 forks source link

Crazy positions #74

Open leonardoayres opened 4 years ago

leonardoayres commented 4 years ago

I don't know if somebody else is facing this:

I tryed to use the BackgroundLocator to replace the Location plugin because of the background tracking aspect , but when using it "live", in active state, sometimes the tracking move my Marker to an aleatory position (a good amount of feets away) and then back to my position.

I'm drawing polylines when using the plugin; guys, my path looks like a heartbeat graph, with zigs and zags instead a straight line.

Have somebody experienced something like this with this package?

moovida commented 4 years ago

Hi @leonardoayres , I have been experiencing this lately. But only when I am not in the move. If I stop in a position for a while, I most often get a spike far away from where I am. But I am still trying to analyse the problem to understand what that might be.

leonardoayres commented 4 years ago

Exactly. I'm considering start to use some kind of accelerometer monitoring to guarantee that i'm on the move before start to track the positions.

mehdok commented 4 years ago

What's the platform? Android or iOS?

leonardoayres commented 4 years ago

Android.

I haven't tested on iOS yet.

moovida commented 4 years ago

Same here, Android. Should be able to do a test on an IPad today.

mehdok commented 4 years ago

What accuracy are you using? Navigation is the must accurate parameter. If your are getting this behavior with Navigation accuracy then there should be some problem. Please provide any information you can (Android version, device, logs, codes ....), so I can simulate the situation for further investigation;

leonardoayres commented 4 years ago

I already tried with HIGH and LOW.

Now i completely removed the accuracy and the "spikes" occured less; but they still there.

I'll try to make a demo...but as i'm using google maps, who test it must provide ones key.

moovida commented 4 years ago

I am actually using only Navigation accuracy, because no other works for me. I think there is an issue open on that, but I can't find it. Up to now, the issues were found on Android 10 on Google Pixel 3a.

leonardoayres commented 4 years ago

Here is an Android 10 with a Xiaomi Mi9T.

mehdok commented 4 years ago

I am actually using only Navigation accuracy, because no other works for me. I think there is an issue open on that, but I can't find it.

Yes I'm aware of the issue you are referring to, and I Think that issue is related to this. I will try to find an Android 10 device and test on that. This might be a platform specific issue, because I don't have this problem on my Android 8 device.

moovida commented 4 years ago

Good to know @mehdok , I will try on an android 9 to see if that is different. I guess I will be able to better test in the weekend. Testing location services is always a mess :-)

leonardoayres commented 4 years ago

Found an article that talks about "cleaning noise" of the GPS data. Looks like the scenario that we are facing.

https://blog.maddevs.io/reduce-gps-data-error-on-android-with-kalman-filter-and-accelerometer-43594faed19c

mehdok commented 4 years ago

@leonardoayres Really interesting, does this solve your problem?

leonardoayres commented 4 years ago

I haven't applied yet. Have to take off the rust of my math skills and see if my code can be changed without more surprises |-]

mehdok commented 4 years ago

There is another simple solution for getting rid of gps noise, just turn your phone in 8 shape several times, then open your app and let me know if it works. If this problem caused by gps noise this method will solve it;

moovida commented 4 years ago

I added some testresults to issue #76 in order to not pollute this issue to much.

leonardoayres commented 4 years ago

Guys,

I've found an implementation of a Kalman filter and converted to Dart:

import 'dart:math' as Math;

// Original code by Paul Doust (https://stackoverflow.com/users/2110762/stochastically)
class KalmanLatLong {
  final double _minAccuracy = 1;

  double _qMetresPerSecond;
  double _timeStampMilliseconds;
  double _lat;
  double _lng;
  double _variance; // P matrix.  Negative means object uninitialised.  NB: units irrelevant, as long as same units used throughout

  KalmanLatLong(double qMetresPerSecond) {
    this._qMetresPerSecond = qMetresPerSecond;
    this._variance = -1;
  }

  double get timeStamp {
    return this._timeStampMilliseconds;
  }

  double get latitude {
    return this._lat;
  }

  double get longitude {
    return this._lng;
  }

  double get accuracy {
    return Math.sqrt(this._variance);
  }

  void setState(double lat, double lng, double accuracy, double timeStampMilliseconds) {
    this._lat = lat;
    this._lng = lng;
    this._variance = accuracy * accuracy;
    this._timeStampMilliseconds = timeStampMilliseconds;
  }

  ///
  /// Kalman filter processing for lattitude and longitude.
  ///
  /// latMeasurement: New measurement of lattidude.
  ///
  /// lngMeasurement: New measurement of longitude.
  ///
  /// accuracy: Measurement of 1 standard deviation error in metres.
  ///
  /// timeStampMilliseconds: Time of measurement.
  ///
  /// returns: new state.
  ///
  void process(double latMeasurement, double lngMeasurement, double accuracy, double timeStampMilliseconds) {
    if (accuracy < this._minAccuracy) accuracy = this._minAccuracy;
    if (this._variance < 0) {
      // if variance < 0, object is unitialised, so initialise with current values
      this._timeStampMilliseconds = timeStampMilliseconds;
      this._lat = latMeasurement;
      this._lng = lngMeasurement;
      this._variance = accuracy * accuracy;
    } else {
      // else apply Kalman filter methodology

      double timeIncMilliseconds = timeStampMilliseconds - this._timeStampMilliseconds;
      if (timeIncMilliseconds > 0) {
        // time has moved on, so the uncertainty in the current position increases
        this._variance += timeIncMilliseconds * this._qMetresPerSecond * this._qMetresPerSecond / 1000;
        this._timeStampMilliseconds = timeStampMilliseconds;
        // TO DO: USE VELOCITY INFORMATION HERE TO GET A BETTER ESTIMATE OF CURRENT POSITION
      }

      // Kalman gain matrix K = Covarariance * Inverse(Covariance + MeasurementVariance)
      // NB: because K is dimensionless, it doesn't matter that variance has different units to lat and lng
      double K = this._variance / (this._variance + accuracy * accuracy);
      // apply K
      this._lat += K * (latMeasurement - this._lat);
      this._lng += K * (lngMeasurement - this._lng);
      // new Covarariance  matrix is (IdentityMatrix - K) * Covarariance
      this._variance = (1 - K) * this._variance;
    }
  }
}

Usage:

import '<the file with the implementation above>';

...

// the parameter represents the distanteInterval em m/s. Some say that 3 is the sweet spot, i haven't tried yet. KalmanLatLong filter = KalmanLatLong(2);

...

// on the code where you update your position, apply...

filter.process(position.latitude, position.longitude, position.accuracy, position.time);

<your method for position update>(filter.latitude, filter.longitude);

Hope it helps.

moovida commented 4 years ago

Hi @leonardoayres , from the link I can't find where the original implementation is. Could you link it please. If this works you might want to create a flutter package for this, it would be great to have accessible and upgradable once improved :-)

leonardoayres commented 4 years ago

@moovida The original code is from this link: https://stackoverflow.com/questions/1134579/smooth-gps-data

I think if it is relevant for anything, it could be added to the current background_locator package. There is already to many packages for the same problem :-)

moovida commented 4 years ago

You might be right. I will try to apply it to a set of logs I have to see how well if makes things. And a dynamic parameter will be necessary, since the decay speed seems to be very depending on the different speed (i.e. car vs walking vs bike). If you do some test it would be great if you could share some tests. :-)

moovida commented 4 years ago

Hi @leonardoayres , did you try to use the Kalman filter? This morning I made a quick copy-paste to have a test, since I had to walk mountainside. The result is as if nothing happened:

image

Clearly it is identified that this is an Android 10 issue of this library, but it still should have done some smoothing.

leonardoayres commented 4 years ago

Hi @moovida,

My need of background locator is for a software that i'm responsible for on my job. My experience with the background_locator in Foreground use (using wakelock package to keep the screen active) was terrible; too much track spikes. However, for background running, it was ok (go figure, right?).

So, i've made an hybrid: Location package for Foreground (active) tracking and Background_Locator for background (paused) tracking. I've implemented the aproach on the didChangeAppLifecycleState to manage the App lifecycle.

The Kalman filter was applied for both listeners (Location and Background_Locator) and generates a smoothest path, far from perfect, but better.

Currently i'm testing an implemetation with flutter_background_geolocation (from Transistor Software) and so far, so good.

jjjimenez100 commented 4 years ago

@leonardoayres Do you have any idea on what Q value range does the kalman filter work best in a scenario of a moving vehicle?

I'm thinking of using the accelerometer of the device for estimating an appropriate Q value, as the device might not always be in motion and vice versa.

HeikkiK commented 4 years ago

I don't know is my problem same issue what written here but when I am watching my app, location is jumping all the time and there may be spikes which may be kilometers long no matter is my app in foreground or is it running in background. I am using latest version and accuracy is Navigation (in android). At the same time when checking route from Google Maps Timeline, route looks quite nice there.

saurabhkumar8112 commented 4 months ago

Kalman filter might not solve the issue when the noise is too much. We have sometimes gotten noise where the position is ~ 1Km away from the actual position. But it would be better if its included in the plugin itself. It seems iOS does a lot of post-processing as well, that's why their graph is smoother