Search code examples
androidgpsmapbox

Get user location at high speed


I have been using MapBox draw a map and the user position on the said map. At the same time using the location engine, I'm subscribing to location changes. The problem with location changes is that they happens once per second (at most) and my users mostly drive, so the recorded locations are pretty much often behind.

I realized that even the locations logged are behind, the marker showing the user's current location seems to always be accurate. I'm wondering if there is a possibility to get the "estimated" location of the current position marker.

Also according to the documentation from mapbox, I can get more accurate locations (more frequent as well) using the ProgressChangeListener. I tried setting up this way but it didn't work.

val nav = MapboxNavigation(this,getString(R.string.access_token))
    nav.addProgressChangeListener { location, routeProgress ->
        Timber.tag("GPSDEBUG").d("GOT LOC UPDATE on ${System.currentTimeMillis()} with ${location.longitude},${location.latitude}")
    }
    nav.startNavigation(DirectionsRoute.fromJson(""))

Obviously MapBox didn't like to have an empty road or a fake navigation.

I would be great to have a feedback on this before I try other suggestions such as using a Kalman algorithm to "estimate" the missing locations.

ULTIMATELY: The main goal is to retrieve accurate GPS coordinates even at high speed.


Solution

  • My solution was to calculate the missing location between pointA and pointB, knowing that the maximum rate at what the GPS gives updates is 1s. In real life situations I had to deduct 3 to 4 points when people drive in highways at high speed.

    private fun processMissingPoints() {
        val stepInMeters = lastUsedLocation.distanceTo(lastKnownLocation) / (numberOfMissingPoints).toDouble()
        val bearing = lastUsedLocation.bearingTo(lastKnownLocation)
        missingPoints.forEach{ point ->
            val newCoordinates = getNewCoordinates(lastUsedLocation.latitude , lastUsedLocation.longitude,stepInMeters*(index+1), bearing.toDouble())
        }
    }
    
    
    /**
     * http://www.movable-type.co.uk/scripts/latlong.html#dest-point
     * Given a start point, initial bearing, and distance, this will calculate the destination
     * point and final bearing travelling along a (shortest distance) great circle arc.
     */
    private fun getNewCoordinates(latitude: Double,longitude: Double,distanceInMetres: Double,bearing: Double) : LatLng{
        val brngRad = toRadians(bearing)
        val latRad = toRadians(latitude)
        val lonRad = toRadians(longitude)
        val earthRadiusInMetres = 6371000
        val distFrac = distanceInMetres / earthRadiusInMetres
    
        val latitudeResult = asin(sin(latRad) * cos(distFrac) + cos(latRad) * sin(distFrac) * cos(brngRad))
        val a = atan2(sin(brngRad) * sin(distFrac) * cos(latRad), cos(distFrac) - sin(latRad) * sin(latitudeResult))
        val longitudeResult = (lonRad + a + 3 * PI) % (2 * PI) - PI
    
        return LatLng(toDegrees(latitudeResult),toDegrees(longitudeResult))
    }