如何在Android应用中利用位置或加速度计等方式提高速度

11

我正在开发一个应用程序,尝试获取用户的速度和行驶距离。我已经使用了Google Play服务位置类来获取速度,但它总是返回给我0.0值,并且不可靠。我想要实时准确的速度和行驶距离。

我在我的设备上安装了GPS速度表应用程序,非常完美,即使我在走路时也能给我速度。我想获得同样的结果。我困惑于如何获取速度,使用位置还是使用加速度计,或者是否有其他方法可以做到?

我的代码可在此链接中找到:

使用Google Maps Android API v2在Google Maps上绘制路线

我正在开发基于位置的纯定位应用程序,其中包括地图,速度和其他与位置相关的内容。

如果有任何人有任何想法,请帮助我解决速度和距离问题。

4个回答

20

我曾经碰到过同样的问题,你可以使用位置策略代码来处理。

然后,在每次位置更新时,保存当前更新的时间。这样,你就会有之前和当前的位置,以及更新的时间。

然后,你可以计算这两个位置(旧的和新的)之间的距离,单位为米。

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;
}

所以,你已经有了距离和时间差,我认为获取速度不是什么大问题。


首先感谢这个方法,我会立刻尝试它。但是为了提高速度,问题在于 location.getSpeed() 不起作用。所以基本上您建议我使用旧的位置 API 而不是新的谷歌播放服务更新的位置 API? - Scorpion
2
getSpeed(http://developer.android.com/reference/android/location/Location.html#getSpeed())的文档说明:`如果可用,则获取地面上每秒的速度,单位为米/秒`。使用这种旧的方式,您就不必担心它是否可用。 - user2058839
我已经在处理速度问题上工作了两天,但不明白为什么它不起作用。我正在真实设备上测试,包括在车辆和步行中运行。我还尝试了另一种方法,即计算行驶距离并将其除以时间差以获得速度。但是这种方式也没有起作用。 - Scorpion
8
为什么不使用location.distanceTo(Location)来获取距离? - Renan Bandeira
如何获取时间差,例如当前时间为0,新时间为system.currentTimeMills();然后在cur_time = new_time之后,请解释... - Ashana.Jackol

2

当我使用Google Play位置API时,我也遇到了这个问题,希望这可以帮到你。

返回0是因为您的设备无法锁定GPS,或无法连接到GPS。

我尝试使用旧的联想设备获取速度,它返回0,因为它无法锁定GPS。

我尝试使用三星Galaxy Nexus,它返回我的速度(具有更好的GPS传感器)。

您手机中的GPS传感器可能不太好,或者您所处的区域GPS信号较弱,例如在房屋或建筑物内。

如果location.hasSpeed为false,则我计算速度,并使用location.getSpeed如果location.hasSpeed为true。

我还尝试使用活动识别来提高计算速度的准确性。

    //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.

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;
    }
}

1
@P.K 如果当前位置有速度,则为米/秒,如果没有,则为米/毫秒。这很聪明...非常聪明... - Carson J.

2
在这个回答中,我将展示两种获取当前速度的主要方法。一种是使用位置服务(location.getSpeed()),另一种是老派的手动计算速度版本。
首先定义三个主要的全局变量。
double curTime= 0;
double oldLat = 0.0;
double oldLon = 0.0;

现在转到您的onLocationChanged方法,并在其中调用此方法,

getspeed(location);

现在让我们实现 getSpeed 方法

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();
    }
}

好的,我们已经完成了这个步骤,现在需要实现calculationBydistance方法。

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;
}

在这个else部分,速度将以m /毫秒的形式显示,你可以将其转换为秒...然后我们就完成了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接