gpt4 book ai didi

android - Android-卫星信息(计数,信号等)的融合位置提供程序API问题

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:31:51 26 4
gpt4 key购买 nike

我正在一个项目中,我们试图跟踪设备的位置并保留数据以备后用。在谈论这个问题之前,我想提供一些背景知识。

通过在StackExchange和Google以及其他地方进行搜索,我得出的结论是,实际上几乎不可能使用Fused Location API(有关Google的信息)来获取有关卫星的信息。

大多数人使用的方法是在融合位置旁边实际使用LocationManager来获取GPS状态。我的第一个问题是:
我们如何100%确保LocationManager提供的数字与融合位置提供给我们的信息保持同步?融合地点是否在内部使用Manager?

现在是问题。该应用程序使用“始终在线”粘性服务来获取职位,无论如何。如果没有卫星,一切都会按预期进行。将设备放置在可以看到卫星的位置,它似乎没有锁。使用调试器,GpsStatus.getSatellites()会带来一个空列表。现在,在不移动设备的情况下,我启动了具有GPS类型指南针方案的应用程序指南针(由Catch.com提供)。那个锁定卫星的速度非常快,从那一刻起,我的应用程序还报告了这些卫星。如果指南针关闭,则应用程序将卡在指南针提供的最后一个数字上!!!我个人用于测试的设备是带有最新官方更新(Android 6.0.1)的Nexus 7 2013。

这是一些代码:

public class BackgroundLocationService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
GpsStatus.Listener,
LocationListener {

// Constants here....

private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private LocationManager locationManager;
// Flag that indicates if a request is underway.
private boolean mInProgress;

private NotificationManagement myNotificationManager;
private Boolean servicesAvailable = false;

//And other variables here...

@Override
public void onCreate()
{
super.onCreate();

myNotificationManager = new NotificationManagement(getApplicationContext());
myNotificationManager.displayMainNotification();

mInProgress = false;
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval
mLocationRequest.setInterval(PREFERRED_INTERVAL);
// Set the fastest update interval
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

servicesAvailable = servicesConnected();

locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.addGpsStatusListener(this);

setUpLocationClientIfNeeded();
}

/**
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
protected synchronized void buildGoogleApiClient()
{
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}

private boolean servicesConnected()
{

// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode)
{
return true;
}
else
{
return false;
}
}

public int onStartCommand(Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);

if (!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;

setUpLocationClientIfNeeded();
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress)
{
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}


private void setUpLocationClientIfNeeded()
{
if (mGoogleApiClient == null)
buildGoogleApiClient();
}

public void onGpsStatusChanged(int event)
{

}

// Define the callback method that receives location updates
@Override
public void onLocationChanged(Location location)
{
simpleGPSFilter(location);
}

// Other fancy and needed stuff here...

/**
* "Stupid" filter that utilizes experience data to filter out location noise.
* @param location Location object carrying all the needed information
*/
private void simpleGPSFilter(Location location)
{
//Loading all the required variables
int signalPower = 0;
satellites = 0;
// Getting the satellites
mGpsStatus = locationManager.getGpsStatus(mGpsStatus);
Iterable<GpsSatellite> sats = mGpsStatus.getSatellites();
if (sats != null)
{
for (GpsSatellite sat : sats)
{
if (sat.usedInFix())
{
satellites++;
signalPower += sat.getSnr();
}
}
}
if (satellites != 0)
signalPower = signalPower/satellites;
mySpeed = (location.getSpeed() * 3600) / 1000;
myAccuracy = location.getAccuracy();
myBearing = location.getBearing();
latitude = location.getLatitude();
longitude = location.getLongitude();
Log.i("START OF CYCLE", "START OF CYCLE");
Log.i("Sat Strength", Integer.toString(signalPower));
Log.i("Locked Sats", Integer.toString(satellites));

// Do the math for the coordinates distance
/*
* Earth's radius at given Latitude.
* Formula: Radius = sqrt( ((equatorR^2 * cos(latitude))^2 + (poleR^2 * sin(latitude))^2 ) / ((equatorR * cos(latitude))^2 + (poleR * sin(latitude))^2)
* IMPORTANT: Math lib uses radians for the trigonometry equations so do not forget to use toRadians()
*/
Log.i("Lat for Radius", Double.toString(latitude));
double earthRadius = Math.sqrt((Math.pow((EARTH_RADIUS_EQUATOR * EARTH_RADIUS_EQUATOR * Math.cos(Math.toRadians(latitude))), 2)
+ Math.pow((EARTH_RADIUS_POLES * EARTH_RADIUS_POLES * Math.cos(Math.toRadians(latitude))), 2))
/ (Math.pow((EARTH_RADIUS_EQUATOR * Math.cos(Math.toRadians(latitude))), 2)
+ Math.pow((EARTH_RADIUS_POLES * Math.cos(Math.toRadians(latitude))), 2)));
Log.i("Earth Radius", Double.toString(earthRadius));

/*
* Calculating distance between 2 points on map using the Haversine formula (arctangent writing) with the following algorithm
* latDifference = latitude - lastLatitude;
* lngDifference = longitude - lastLongitude;
* a = (sin(latDifference/2))^2 + cos(lastLatitude) * cos(latitude) * (sin(lngDifference/2))^2
* c = 2 * atan2( sqrt(a), sqrt(1-a) )
* distance = earthRadius * c
*/
double latDifference = latitude - lastLatitude;
double lngDifference = longitude - lastLongitude;
double a = Math.pow((Math.sin(Math.toRadians(latDifference / 2))), 2) + (Math.cos(Math.toRadians(lastLatitude))
* Math.cos(Math.toRadians(latitude))
* Math.pow((Math.sin(Math.toRadians(lngDifference / 2))), 2));
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = earthRadius * c;
Log.i("New point distance", Double.toString(distance));

// Filter logic
// Make an initial location log
if ((!isInit) && (myAccuracy < ACCEPTED_ACCURACY))
{
isInit = true;
lastLatitude = latitude;
lastLongitude = longitude;
logLocations(location);
}
else
{
// Satellite lock (use of GPS) on the higher level
if (satellites == 0)
{
// Accuracy filtering at the second level
if (myAccuracy < ACCEPTED_ACCURACY)
{
if ((distance > ACCEPTED_DISTANCE))
{
lastLatitude = latitude;
lastLongitude = longitude;
logLocations(location);
Log.i("Location Logged", "No Sats");
/*
// Calculate speed in correlation to perceived movement
double speed = distance / (PREFERRED_INTERVAL / 1000); // TODO: Need to make actual time dynamic as the fused location does not have fixed timing
if (speed < ACCEPTED_SPEED)
{
lastLatitude = latitude;
lastLongitude = longitude;
logLocations(location);
} */
}
}
}
else if ((satellites < 4) && (signalPower > ACCEPTED_SIGNAL))
{
if (myAccuracy < (ACCEPTED_ACCURACY + 50))
{
logLocations(location);
Log.i("Location Logged", "With Sats");
}
}
else
{
if (myAccuracy < (ACCEPTED_ACCURACY + 100))
{
lastSpeed = mySpeed;
lastBearing = myBearing;
lastLatitude = latitude;
lastLongitude = longitude;
logLocations(location);
Log.i("Location Logged", "With Good Sats");
}
}
}
Log.i("END OF CYCLE", "END OF CYCLE");
}

private void logLocations(Location location)
{
String myprovider = "false";

String temp = timestampFormat.format(location.getTime());
MySQLiteHelper dbHelper = new MySQLiteHelper(getApplicationContext());

try
{
dbHelper.createEntry(latitude, longitude, allschemes, temp, mySpeed, myAccuracy, myBearing, myprovider, satellites);
}
catch (Exception e)
{
e.printStackTrace();
}

CheckAutoArrive(String.valueOf(latitude), String.valueOf(longitude));

}

这是我认为可能需要的代码部分。给定纬度和 map 上两点之间的距离,我将所有过滤代码和数学信息一起保留在那里。如果需要,可以随意使用它。

关于Compass应用程序实际上可以使系统获得卫星而我的应用程序却不能的事实。有没有一种方法实际上可以强制读取位置服务?融合位置是否可能实际上使用了GPS,但位置管理器不知道它?

最后,我想提一提的是,该应用程序已在具有不同版本Android的其他设备(电话,而非平板电脑)中进行了测试,并且似乎可以正常运行。

任何想法都将受到欢迎。当然,请问任何我可能忘记提及的问题。

编辑:我的实际问题被隐藏在文本中,以便进行布局:

1)是我们从融合位置获得的位置数据,还是从同步管理器中获得的其余GPS数据,看似只能从位置管理器中获得,还是有可能获得位置但针对特定点的锁定卫星数错误?

2)奇怪的行为背后的原因是什么,即该应用程序无法获得卫星锁定,但如果该锁定来自另一个应用程序,则该应用程序似乎已正确使用了该锁定?为了使这个问题变得更奇怪,这发生在Nexus 7(Android 6.0.1)上,而不是其他使用不同Android版本进行测试的设备上。

最佳答案

据我了解:

1)

每当客户端设备上的任何相关提供商(WiFi,CellTower,GPS,蓝牙)提供新的读数时,FusedLocationApi都会返回一个新位置。该读数与先前的位置估计值融合在一起(可能使用扩展的卡尔曼滤波器或类似方法)。最终的位置更新是对多个源的融合估计,这就是为什么没有附加来自各个提供程序的元数据的原因。

因此,您从API获取的位置数据可能与从LocationManager获得的纯GPS读数一致(如果GPS是最新且相关的位置来源),但并非必须如此。因此,从最后一次纯GPS读取获得的卫星数量可能适用于FusedLocationApi返回的最新位置,也可能不适用于该位置。

简而言之:

无法保证从LocationManager获得的位置读数与FusedLocationApi 的位置同步。

2)

首先,要查明此问题的根本原因,您需要在多个位置使用多个设备进行测试。既然你问了

What could be the reason behind the weird behavior?



我将提出一个理论:假设LocationManager和FusedLocationApi完全分开工作,由于您仅依赖GPS,因此LocationManager可能难以获得修复。
除了GPS外,还尝试使用 NETWORK_PROVIDER来加快首次定位的时间(从而使LocationManager可以使用 Assisted GPS)。几乎可以肯定其他应用程序(例如Compass应用程序)正在执行此操作,这可以解释为什么它们得到更快的修复。
注意:开始接收GPS数据后,您当然可以注销网络提供商。或者,您可以继续使用它,而只是忽略其更新。

这是怪异行为的一种可能解释。 您可能已经知道位置行为取决于您所在的设备,操作系统,GPS芯片组,固件和位置-因此,如果您打算手动操作(即不使用FusedLocationApi),则必须进行大量试验。

除了答案之外,让我对您的问题提供一个有根据的看法(用一粒盐;-):我认为您正在尝试将针对非常不同的用例而做出的两件事结合起来,而不是意味着要合并。

获得卫星的数量完全是技术性的。 ,除非您的应用程序教他们有关GNSS的信息,否则最终用户将永远不会对此类信息感兴趣。如果您想为内部分析目的记录它,那很好,但是您必须能够处理该信息不可用的情况。

场景1 :出于某种原因,您决定绝对需要GPS读数的详细(技术)细节。在这种情况下, 自己构建逻辑,这是老式的方式。 IE。通过LocationManager要求获取GPS读数(并可能通过使用网络提供商来加快此过程),然后自行融合这些内容。但是,在这种情况下,请勿触摸FusedLocationApi。
即使在当今看来过时和不可思议,将位置管理器与DIY融合逻辑结合使用仍然对少数用例来说是非常合理的。这就是API仍然存在的原因。

方案2 :您只是想快速,准确地更新客户的位置。在这种情况下, 指定所需的更新频率和准确性,并让FusedLocationApi进行其工作。在过去的几年中,FusedLocationApi取得了长足的进步,如今,比起任何DIY逻辑,现在它在找出如何获取位置信息方面将更加快捷,更好。这是因为获取位置信息是一个非常异构的问题,它取决于客户端设备(芯片组,固件,OS,GPS,WiFi,GSM/LTE,蓝牙等)的功能以及物理环境(WiFi/CellTower)的能力/附近,内部或外部,晴朗的天空或城市峡谷等的蓝牙信号)。
在这种情况下,请勿触摸手动提供程序。如果这样做,不要期望对各个提供者的读数与融合结果之间的关系做出任何有意义的推断。

最后两句话:
  • Android提供了Location.distanceTo()Location.distanceBetween(),因此无需在代码中实现Haversine公式。
  • 如果您只是需要FusedLocationApi的快速而可靠的更新,我已经写了a small utility class, called the LocationAssistant,可以简化设置并为您完成大部分繁重的工作。
  • 关于android - Android-卫星信息(计数,信号等)的融合位置提供程序API问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40162272/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com