【问题标题】:GPS Location FluctuatingGPS位置波动
【发布时间】:2018-06-12 09:48:53
【问题描述】:

我在谷歌地图上将心画成一条折线,取决于半径(1 - 100 米)。一旦画出心形,用户需要在该心形边界上行走,并且需要从头到尾完成(从底部开始,然后向左然后向右,然后再从底部开始)。

我可以画心,我得到了 360 分(latlng)。这是我的代码,它将绘制心脏和图像。

private void initPath() {
    path = new PolylineOptions();
    path.color(ContextCompat.getColor(mActivity,R.color.heart_green));
    path.width(25);

    // offset to bottom
    double offsetY = getY(Math.toRadians(180));

    for (int angle = 0; angle <= 360; angle++) {
        double t = Math.toRadians(angle);
        double x = getX(t);
        double y = getY(t) - offsetY;
        //Log.d(TAG, "angle = " + angle + "(x = " + x + ",y= " + y + ")");

        //convert x,y to lat lng
        LatLng latLng = getLatLng(x, y, center);
        path.add(latLng);

        heart360Points.add(latLng);

    }

}

private double getX(double t) {
    return radius * 16 * Math.sin(t) * Math.sin(t) * Math.sin(t) / HEART_RATIO;
}

private double getY(double t) {
    return radius * (13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t)) / HEART_RATIO;
}

private LatLng getLatLng(double dx, double dy, LatLng centerHeart) {
    return new LatLng(centerHeart.latitude + Math.toDegrees(dy / EARTH_RADIUS),
            centerHeart.longitude + Math.toDegrees(dx / EARTH_RADIUS) / Math.cos(Math.toRadians(centerHeart.latitude)));

}   

这是心脏图像。

但是每当我尝试在心脏边界上行走时,GPS 位置波动太大,所以我永远无法完成心脏行走。我目前每秒都在请求位置。

这是我的位置代码。

 private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 2000 ;
 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.love_lead_perform);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    mApiClient = new GoogleApiClient.Builder(this)
            .addApi(ActivityRecognition.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

    mApiClient.connect();


    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    mSettingsClient = LocationServices.getSettingsClient(this);
    createLocationCallback();
    createLocationRequest();
    createLocationSettingsRequest();


} 

private void createLocationSettingsRequest() {
    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
    builder.addLocationRequest(mLocationRequest);
    mLocationSettingsRequest = builder.build();
}

private void createLocationRequest() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
    mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}   

我不明白为什么 GPS 位置波动太大。即使我站着,我也会得到不同的 GPS 位置。

如何获得准确的 GPS 位置?

【问题讨论】:

  • 您在 manifest.xml 上调用了哪些权限?
  • 也许你需要参军 - 我听说他们比普通人获得更好的 GSP 数据 :) 但我认为你并不孤单,即使是 PokemonGo(我不玩)也会摇摆不定一直在地图周围。因此,您可能遭受设备上 GPS 信号的“默认”随机性,这可能会受到您的位置(隧道、建筑物、树木 == 遮挡 GPS 所需的卫星)和/或天气的影响 -这似乎会影响寻宝。
  • 是的,确实如此,但“Waz3”、“Ub3r”和正确的“G00gle Directions”也确实像一个魅力,在几米左右的移动和精度......我认为他们对我们隐瞒了一些秘密,小开发者。
  • @statosdotcom - 他们可能会将手机位置数据与 gps 结合起来,或者平均滑动 5 到 20 秒的数据,以根据您移动的速度消除曲折。甚至可能根据从您最近 n 个位置获取的向量丢弃突然的“侧向移动” - 即需要填充/删除错误数据并预测“好”样本的大量内容。
  • @PatrickArtner 很好的分析和评论,谢谢。你完全正确,这不仅仅是使用正确工具的问题,而是将其与人类理性方面的专业知识结合起来,即,不仅仅是盲目地依赖技术数据,而是使用准确的数据来预测发生了什么。人+机器...哇...我们要去哪里? :D

标签: android gps google-maps-android-api-2 google-location-services


【解决方案1】:

位置波动是正常现象。问题是,您应该何时/如何接受或丢弃意外的位置。正如用户(Patrick Artner)所说,你应该放弃突然的侧向运动。

您可以通过两种方式丢弃这些动作,

  1. 让我们决定最低标准(1 米)。

    假设最小距离为 1 米,因为如果人类“行走(非站立)”,这是可能的,人类可以在“X”秒内走完至少 1 米的距离。因此,如果覆盖距离返回小于 1 米,您可以简单地丢弃。

  2. 让我们决定最大标准(5 米)。

    假设最大距离为 5 米,因为万一人类“走路(不跑步)”,这是不可能的,人类可以在“X”秒内走完超过 5 米的距离。因此,如果覆盖距离返回超过 5 米,您可以简单地丢弃。

在哪里,

距离 = NEW_LOCATION - OLD_LOCATION (How to get distance?)

X = 一定的时间(以秒为单位)

只接受小于5m和大于1m的位置(距离范围您可以根据自己的理解选择)。

【讨论】:

    【解决方案2】:

    描述了 GPS 系统错误的基本信息,例如 here。使用Extended Kalman Filter 融合来自 GPS 的数据(恕我直言,原始的、未过滤的、从GpsStatus.NmeaListener/OnNmeaMessageListener 接收的 GPS 数据)和其他传感器(加速度计、陀螺仪、磁力计等)可以提高准确性,但今天有不可能创建具有描述功能的良好应用程序(轨道路径大约 100m “复杂”图形)。如果你简化路径(如图所示)

    并跟踪交叉检查点“地理围栏”及其顺序 - 可能是您可以实现功能,但在许多情况下准确性将是不可接受的。

    【讨论】:

      【解决方案3】:

      无法获得准确的 GPS 坐标是很常见的,因为它取决于许多因素,例如

      • 开阔的天空或室内条件
      • 云、建筑物等障碍物
      • 设备上的 GPS 芯片配置/CPU 电源
      • 蜂窝网络信号强度

      你可以做一些解决方法

      • 使用@andrii-omelchenko 建议的卡尔曼滤波器算法
      • 或者您可以使用geofencing 机制并设置地理围栏,Android 系统会在进入/退出地理围栏时为您提供回调

        • A) 设置几个地理围栏圈(下一组纬度可能需要 3~5 个)
        • B) 在进入地理围栏时将步骤标记为完成
        • C) 重复 A,直到整个心脏被用户覆盖
      • 使用Android activity recognition 和上述地理围栏逻辑来检查用户是否步行

      下面是示例地理围栏图片,让您了解一下

      【讨论】:

        【解决方案4】:

        是的,gps 位置波动是正常的,但如果您想要更准确,请做一件事。在这里,我向您展示我的技巧。

        我相信你也在做同样的事情。只是给你指路。

        步骤 1. 制作这个类 GoogleLocationService.java

        public class GoogleLocationService {
        private GoogleServicesCallbacks callbacks = new GoogleServicesCallbacks();
        LocationUpdateListener locationUpdateListener;
        Context activity;
        protected GoogleApiClient mGoogleApiClient;
        protected LocationRequest mLocationRequest;
        
        public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 2000;
        
        
        public GoogleLocationService(Context activity, LocationUpdateListener locationUpdateListener) {
            this.locationUpdateListener = locationUpdateListener;
            this.activity = activity;
            buildGoogleApiClient();
        }
        
        protected synchronized void buildGoogleApiClient() {
            //Log.i(TAG, "Building GoogleApiClient");
            mGoogleApiClient = new GoogleApiClient.Builder(activity)
                    .addConnectionCallbacks(callbacks)
                    .addOnConnectionFailedListener(callbacks)
                    .addApi(LocationServices.API)
                    .build();
            createLocationRequest();
            mGoogleApiClient.connect();
        }
        
        protected void createLocationRequest() {
            mLocationRequest = new LocationRequest();
            mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        
        }
        
        private class GoogleServicesCallbacks implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
        
            @Override
            public void onConnected(Bundle bundle) {
                startLocationUpdates();
            }
        
            @Override
            public void onConnectionSuspended(int i) {
                mGoogleApiClient.connect();
            }
        
            @Override
            public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        
                if (connectionResult.getErrorCode() == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED) {
                    Toast.makeText(activity, "Google play service not updated", Toast.LENGTH_LONG).show();
        
                }
                locationUpdateListener.cannotReceiveLocationUpdates();
            }
        
            @Override
            public void onLocationChanged(Location location) {
                if (location.hasAccuracy()) {
                    if (location.getAccuracy() < 30) {
                        locationUpdateListener.updateLocation(location);
                    }
                }
            }
        }
        
        private static boolean locationEnabled(Context context) {
            boolean gps_enabled = false;
            LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
            try {
                gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return gps_enabled;
        }
        
        private boolean servicesConnected(Context context) {
            return isPackageInstalled(GooglePlayServicesUtil.GOOGLE_PLAY_STORE_PACKAGE, context);
        }
        
        private boolean isPackageInstalled(String packagename, Context context) {
            PackageManager pm = context.getPackageManager();
            try {
                pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
                return true;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
                return false;
            }
        }
        
        
        public void startUpdates() {
            /*
             * Connect the client. Don't re-start any requests here; instead, wait
             * for onResume()
             */
            if (servicesConnected(activity)) {
                if (locationEnabled(activity)) {
                    locationUpdateListener.canReceiveLocationUpdates();
                    startLocationUpdates();
                } else {
                    locationUpdateListener.cannotReceiveLocationUpdates();
                    Toast.makeText(activity, "Unable to get your location.Please turn on your device Gps", Toast.LENGTH_LONG).show();
                }
            } else {
                locationUpdateListener.cannotReceiveLocationUpdates();
                Toast.makeText(activity, "Google play service not available", Toast.LENGTH_LONG).show();
            }
        }
        
        //stop location updates
        public void stopUpdates() {
            stopLocationUpdates();
        }
        
        //start location updates
        private void startLocationUpdates() {
        
            if (checkSelfPermission(activity, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(activity, ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            if (mGoogleApiClient.isConnected()) {
                LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, callbacks);
            }
        }
        
        public void stopLocationUpdates() {
            if (mGoogleApiClient.isConnected()) {
                LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, callbacks);
            }
        }
        
        public void startGoogleApi() {
            mGoogleApiClient.connect();
        }
        
        public void closeGoogleApi() {
            mGoogleApiClient.disconnect();
        }
        
         }
        

        第二步。制作这个界面 LocationUpdateListener.java

         public interface LocationUpdateListener {
        
        /**
         * Called immediately the service starts if the service can obtain location
         */
        void canReceiveLocationUpdates();
        
        /**
         * Called immediately the service tries to start if it cannot obtain location - eg the user has disabled wireless and
         */
        void cannotReceiveLocationUpdates();
        
        /**
         * Called whenever the location has changed (at least non-trivially)
         * @param location
         */
        void updateLocation(Location location);
        
        /**
         * Called when GoogleLocationServices detects that the device has moved to a new location.
         * @param localityName The name of the locality (somewhere below street but above area).
         */
        void updateLocationName(String localityName, Location location);
        }
        

        您可以在需要更新位置的类中直接调用下面的代码并删除位置服务。

         private GoogleLocationService googleLocationService;
        
         googleLocationService = new GoogleLocationService(context, new LocationUpdateListener() {
            @Override
            public void canReceiveLocationUpdates() {
            }
        
            @Override
            public void cannotReceiveLocationUpdates() {
            }
        
            //update location to our servers for tracking purpose
            @Override
            public void updateLocation(Location location) {
                if (location != null ) {
                    Timber.e("updated location %1$s %2$s", location.getLatitude(), location.getLongitude());
        
                }
            }
        
            @Override
            public void updateLocationName(String localityName, Location location) {
        
                googleLocationService.stopLocationUpdates();
            }
        });
        googleLocationService.startUpdates();
        
        
        and call this onDestroy 
        if (googleLocationService != null) {
            googleLocationService.stopLocationUpdates();
        }
        

        如果你看,我做了一件事。 getAccuracy() 以米为单位描述偏差。所以,数字越小,准确率越高。

        public void onLocationChanged(Location location) {
            if (location.hasAccuracy()) {
                if (location.getAccuracy() < 30) {
                    locationUpdateListener.updateLocation(location);
                }
            }
        }
        

        谢谢,希望对你有帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-11
          • 1970-01-01
          相关资源
          最近更新 更多