maddevsio / mad-location-manager

Mad Location Manager is a library for GPS and Accelerometer data "fusion" with Kalman filter
MIT License
538 stars 155 forks source link

Location returned by kalman filter is very noisy #82

Open arpansengupta-appsbee opened 4 years ago

arpansengupta-appsbee commented 4 years ago

Hello, I have implemented your library in a foreground service. I am using only the Kalman filter to get user's position every 10m. While setting Utils.GPS_MIN_DISTANCE to 0 the deviations in the points returned is acceptable but setting it to 10m it becomes very noisy.

Below is my locationService. I have used default values in KalmanLocationService.Settings except Utils.GPS_MIN_DISTANCE

` public class LocationMonitoringService extends Service implements LocationServiceInterface, ILogger {

private static final String TAG = LocationMonitoringService.class.getSimpleName();
private SensorCalibrator m_sensorCalibrator = null;
ApiGPSStream mApiGPSStream = new ApiGPSStream();
String NOTIFICATION_CHANNEL_ID = "FleetWorker";

class RefreshTask extends AsyncTask {
    boolean needTerminate = false;
    long deltaT;
    Context owner;
    RefreshTask(long deltaTMs, Context owner) {
        this.owner = owner;
        this.deltaT = deltaTMs;
    }

    @Override
    protected Object doInBackground(Object[] objects) {
        while (!needTerminate) {
            try {
                Thread.sleep(deltaT);
                publishProgress();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    protected void onProgressUpdate(Object... values) {
        if (!m_sensorCalibrator.isInProgress())
            return;

        if (m_sensorCalibrator.getDcAbsLinearAcceleration().isCalculated() &&
                m_sensorCalibrator.getDcLinearAcceleration().isCalculated()) {
            set_isCalibrating(false);
        }

    }
}

private RefreshTask m_refreshTask = new RefreshTask(1000l, this);

@Override
public void onCreate() {
    startService();
    XLog.init();
    super.onCreate();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    System.out.println("bind");
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    ServicesHelper.addLocationServiceInterface(this);
    initActivity();
    m_refreshTask = new RefreshTask(1000, this);
    m_refreshTask.needTerminate = false;
    m_refreshTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    return START_STICKY;
}

@Override
public void onDestroy() {
    m_refreshTask.needTerminate = true;
    m_refreshTask.cancel(true);
    if (m_sensorCalibrator != null) {
        m_sensorCalibrator.stop();
    }
    stopSelf();
    super.onDestroy();
}

private void initActivity() {
    SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    if (sensorManager == null || locationManager == null) {
        System.exit(1);
    }

    m_sensorCalibrator = new SensorCalibrator(sensorManager);
    ServicesHelper.getLocationService(this, value -> {
        set_isLogging(value.IsRunning());
    });
    set_isCalibrating(true);
}

private void set_isLogging(boolean isLogging) {
    Log.e("isLogging",""+isLogging);
    if (isLogging) {
        ServicesHelper.getLocationService(this, value -> {
            if (value.IsRunning()) {
                return;
            }
            value.stop();
            KalmanLocationService.Settings settings =
                    new KalmanLocationService.Settings(
                            Utils.ACCELEROMETER_DEFAULT_DEVIATION,
                            10,
                            2000,
                            6,
                            2,
                            10,
                            this,
                            false,
                            Utils.DEFAULT_VEL_FACTOR,
                            Utils.DEFAULT_POS_FACTOR
                    );
            value.reset(settings); //warning!! here you can adjust your filter behavior
            value.start();
        });

    } else {
        ServicesHelper.getLocationService(this, value -> {
            value.stop();
        });
    }
}

private void set_isCalibrating(boolean isCalibrating) {
    if (isCalibrating) {
        m_sensorCalibrator.reset();
        m_sensorCalibrator.start();
        set_isLogging(false);
    } else {
        m_sensorCalibrator.stop();
        set_isLogging(true);
    }
}

@Override
public void log2file(String s, Object... objects) {
    XLog.i(s, objects);
}

@Override
public void locationChanged(Location location) {
    Log.e("KALMAN",
            "LAT: "+location.getLatitude()
                    +" LONG: "+location.getLongitude()
                    +" Accuracy: "+ location.getAccuracy()
                    +" getTime: "+ location.getTime()
                    +" getElapsedRealtimeNanos: "+ location.getElapsedRealtimeNanos()
                    +" getAltitude: "+ location.getAltitude()
                    +" getSpeed: "+ location.getSpeed()
                    +" getBearing: "+ location.getBearing()
    );

}

public void startService(){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel serviceChannel = new NotificationChannel(
                NOTIFICATION_CHANNEL_ID,
                "Location service Channel",
                NotificationManager.IMPORTANCE_HIGH
        );
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(serviceChannel);
    }

    Intent resultIntent = new Intent(this, SplashActivity.class);
    resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addNextIntentWithParentStack(resultIntent);
    PendingIntent resultPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, resultIntent, 0);

    Notification notification = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID)
            .setContentTitle("Location service")
                .setContentText("Location streaming in progress")
            .setSmallIcon(R.mipmap.notification_icon)
            .setDefaults(Notification.DEFAULT_ALL)
            .setContentIntent(resultPendingIntent).build();

    startForeground(1,notification);
}

} ` Below are the poly lines drawn using these position. The actual polylines should be along the road. map1 map2

Lezh1k commented 4 years ago

I guess this is related to this GPS_MIN_DISTANCE. I mean gps receiver provides coordinates not frequently and sum of noise from accelerometer becomes bigger (we accumulate this error during predict step).