11

I am working on app and try to get the speed and distance travelled by the user. I have used Google Play services location class to get the speed but it always returns me 0.0 value and not at all reliable. I wan accurate speed and distance travelled at real time.

I have installed GPS Speedometer app on my device and its so perfect that even if i am walking then it gives me the speed. I want to get the same thing. I am confused in how to get speed, using location or using accelerometer or is there any other way to do it?

My code is available on this link :-

Drawing route on Google Maps using Google Maps Android API v2

I am developing pure location based app which includes map, speed and other related things which are related to Locations.

If anyone has any idea please kindly help me on resolving the issue of Speed and Distance.

Community
  • 1
  • 1
Scorpion
  • 6,831
  • 16
  • 75
  • 123

4 Answers4

19

I had to deal with same problem, what you can do is to use Location Strategies code.

Then, on each update of location, you save the time of the current update. So, you will have the previous and current location, and time of update.

Then you calculate the distance in meters between those two locations (the old and new one)

private static long calculateDistance(double lat1, double lng1, double lat2, double lng2) {
    double dLat = Math.toRadians(lat2 - lat1);
    double dLon = Math.toRadians(lng2 - lng1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(Math.toRadians(lat1))
            * Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
            * Math.sin(dLon / 2);
    double c = 2 * Math.asin(Math.sqrt(a));
    long distanceInMeters = Math.round(6371000 * c);
    return distanceInMeters;
}

So, then you have the distance and the time difference, I think it wouldn't be a big deal to get the speed.

  • First of all thanks for the method, i am going to try it right away. But still for speed the problem is location.getSpeed() is not working. So basically you suggest me to use old location api instead of New googla play services updated location api? – Scorpion Dec 05 '13 at 11:46
  • 2
    The documentation of getSpeed (http://developer.android.com/reference/android/location/Location.html#getSpeed()) says : `Get the speed if it is available, in meters/second over ground`. Using this old way, you won't have to care if it's available or not. –  Dec 05 '13 at 11:49
  • I am working on speed issue since last 2 days and not understand why its not working. I am testing it on real device by running on vehicle and on feet as well. Also i tried one more thing that i will calculate distance traveled and divide it with time difference to get the speed. But that way also it won't worked. – Scorpion Dec 05 '13 at 11:50
  • 8
    Why don't get the Distance using `location.distanceTo(Location)`?? – Renan Bandeira Apr 11 '14 at 22:36
  • how to get time different, like current_time = 0 new_time = system.currentTimeMills(); then after cur_time = new_time; please explain... – Ashana.Jackol Mar 15 '17 at 09:05
2

I also encountered this problem when I was using Google Play Location API, I hope this can help.

It returns 0 because your device cannot get a lock on the GPS, or cannot connect to the GPS.

I tried to get the speed using an older lenovo device and it returns 0 because it cannot lock on a gps.

I tried using a samsung galaxy nexus and it returned my speed(has a better GPS sensor).

The GPS sensor in your phone might not be good or you are in an area that has a weak GPS signal such as inside a house or building.

What I did was compute for speed if location.hasSpeed is false and use location.getSpeed if location.hasSpeed is true.

I also tried to use the activity recognition to have a better accuracy of speed when computing.

    //Computation for speed
    cur_time = System.currentTimeMillis() / 1000L;
    if (location.hasSpeed()) {
        loc_Speed = location.getSpeed();
        //counter goes back to 0
        count_OnFoot = 0;
        Toast.makeText(getBaseContext(), "has speed", Toast.LENGTH_SHORT).show();
    } else {
        float[] result = new float[1];
        location.distanceBetween(prev_latitude, prev_longitude,
                loc_Latitude, loc_Longitude,
                result);
        float loc_distance = result[0];
        //speed if location.getSpeed is null
        loc_Speed = loc_distance/(cur_time - prev_time);

        //if activity type is on foot
        //estimate AVE_RUNNING_SPEED = 3m/s
        if (act_ActivityType.equals(ActivityRecognitionService.ACT_ON_FOOT) && loc_Speed > AVE_RUNNING_SPEED) {
            count_OnFoot++;
            if (count_OnFoot < 2) {
                Toast.makeText(getBaseContext(), "on foot and 1st > 3m/s", Toast.LENGTH_SHORT).show();
                /*
                 * Since the speed is more than
                 * the average running speed,we will
                 * assume that its not a correct value
                 * and a fault that it detected a very far signal from the previous one.
                 * (This happens sometimes)
                 * We will assign the previous speed
                 * as its current speed.
                 */
                loc_Speed = prev_Speed;
            } else {
                Toast.makeText(getBaseContext(), "on foot and TWICE > 3m/s in a row", Toast.LENGTH_SHORT).show();
                /*
                 * Do Nothing
                 * loc_Speed is equals the computed speed 
                 * if it happens twice or more in a row.
                 * We will assume that its running fast.
                 */
            }
        }else {

            count_OnFoot = 0;
        }
    }
    prev_Speed = loc_Speed;
    /*
     * If more than 60% sure that its still.
     * 
     * Let your speed and direction be 0
     * latitude and longitude should not change
     */
    if (act_ActivityType.equals(ActivityRecognitionService.ACT_STILL)) {
        loc_Speed = 0;
        loc_Direction = 0;
        if (prev_latitude != 0 && prev_longitude != 0) {
            loc_Latitude = prev_latitude;
            loc_Longitude = prev_longitude;
        }
    }

    prev_time = cur_time;
    prev_latitude = loc_Latitude;
    prev_longitude = loc_Longitude;

    //Note: My activity type will return on foot or still if its more than 60% sure
    //otherwise null.
black1011
  • 284
  • 3
  • 18
2

in this answer im gonna show you two main path to get current speed.one is by using location service (location.getSpeed()) and other one is old school manually calculate speed version.

first define three main global variables

double curTime= 0;
double oldLat = 0.0;
double oldLon = 0.0;

now move on to your onLocationChannged method and inside it call to this method,

getspeed(location);

now lets implement getSpeed method

private void getspeed(Location location){
    double newTime= System.currentTimeMillis();
    double newLat = location.getLatitude();
    double newLon = location.getLongitude();
    if(location.hasSpeed()){
        float speed = location.getSpeed();
        Toast.makeText(getApplication(),"SPEED : "+String.valueOf(speed)+"m/s",Toast.LENGTH_SHORT).show();
    } else {
        double distance = calculationBydistance(newLat,newLon,oldLat,oldLon);
        double timeDifferent = newTime - curTime;
        double speed = distance/timeDifferent;
        curTime = newTime;
        oldLat = newLat;
        oldLon = newLon;
        Toast.makeText(getApplication(),"SPEED 2 : "+String.valueOf(speed)+"m/s",Toast.LENGTH_SHORT).show();
    }
}

ok we are done with it, and now implement calculationBydistance method

public double calculationBydistance(double lat1, double lon1, double lat2, double lon2){
    double radius = EARTH_RADIUS;
    double dLat = Math.toRadians(lat2-lat1);
    double dLon = Math.toRadians(lon2-lon1);
    double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                    Math.sin(dLon/2) * Math.sin(dLon/2);
    double c = 2 * Math.asin(Math.sqrt(a));
    return radius * c;
}

in here else part the speed will comes in m/miliseconds you can convert it to seconds...and we are done

Ashana.Jackol
  • 3,064
  • 28
  • 22
2
public static double getSpeed(Location currentLocation, Location oldLocation)
{
    double newLat = currentLocation.getLatitude();
    double newLon = currentLocation.getLongitude();

    double oldLat = oldLocation.getLatitude();
    double oldLon = oldLocation.getLongitude();

    if(currentLocation.hasSpeed()){
        return currentLocation.getSpeed();
    } else {
        double radius = 6371000;
        double dLat = Math.toRadians(newLat-oldLat);
        double dLon = Math.toRadians(newLon-oldLon);
        double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                Math.cos(Math.toRadians(newLat)) * Math.cos(Math.toRadians(oldLat)) *
                        Math.sin(dLon/2) * Math.sin(dLon/2);
        double c = 2 * Math.asin(Math.sqrt(a));
        double distance =  Math.round(radius * c);

        double timeDifferent = currentLocation.getTime() - oldLocation.getTime();
        return distance/timeDifferent;
    }
}
user2746732
  • 119
  • 1
  • 9
  • 1
    @P.K if the current location has speed then it's meters/second, and if it doesn't then its meters/millisecond. Which is smart.. real smart.. – Carson J. Aug 27 '19 at 20:11