Upgrade to Pro — share decks privately, control downloads, hide ads and more …

位置情報を正確にトラッキングする技術

 位置情報を正確にトラッキングする技術

DroidKaigi 2017で発表した資料です。

Takamitsu Mizutori

March 15, 2017
Tweet

More Decks by Takamitsu Mizutori

Other Decks in Programming

Transcript

  1. -PDBUJPO.BOBHFS LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); Criteria criteria = new

    Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Integer gpsFreqInMillis = 1000; Integer gpsFreqInDistance = 5; // in meters locationManager.addGpsStatusListener(this); locationManager.requestLocationUpdates(gpsFreqInMillis, gpsFreqInDistance, criteria, this, null); LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Integer gpsFreqInMillis = 1000; Integer gpsFreqInDistance = 5; // in meters locationManager.addGpsStatusListener(this); locationManager.requestLocationUpdates(gpsFreqInMillis, gpsFreqInDistance, criteria, this, null); LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Integer gpsFreqInMillis = 1000; Integer gpsFreqInDistance = 5; // in meters locationManager.addGpsStatusListener(this); locationManager.requestLocationUpdates(gpsFreqInMillis, gpsFreqInDistance, criteria, this, null); LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Integer gpsFreqInMillis = 1000; Integer gpsFreqInDistance = 5; // in meters locationManager.addGpsStatusListener(this); locationManager.requestLocationUpdates(gpsFreqInMillis, gpsFreqInDistance, criteria, this, null);
  2. $SJUFSJBͷ࡞੒ Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true);

    criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH);
  3. Ґஔ৘ใऔಘ࣌ͷίʔϧόοΫPO-PDBUJPO$IBOHFE ͜͜Ͱ-PDBUJPOΦϒδΣΫτΛऔಘͯ͠ɺ-PDBM#SPBEDBTU.BOBHFSΛ࢖ͬ ͯαʔϏεͷ֎ʹ௨஌͢Δɻ public void onLocationChanged(final Location newLocation) { if(isLogging){

    //locationList.add(newLocation); filterAndAddLocation(newLocation); } Intent intent = new Intent("LocationUpdated"); intent.putExtra("location", newLocation); LocalBroadcastManager.getInstance(this.getApplication()).sendBroadcast(intent); }
  4. mapView = (MapView) this.findViewById(R.id.map); mapView.onCreate(savedInstanceState); mapView.getMapAsync(new OnMapReadyCallback() { @Override public

    void onMapReady(GoogleMap googleMap) { map = googleMap; map.getUiSettings().setZoomControlsEnabled(false); map.setMyLocationEnabled(false); map.getUiSettings().setCompassEnabled(true); map.getUiSettings().setMyLocationButtonEnabled(true); w ζʔϜίϯτϩʔϧΛඇදࣔʹ͢Δɻ w ࣗ෼ͷҐஔΛࣔ͢ΠϯσΟέʔλʔΛඇදࣔʹ͢Δɻ ޙͰࣗ෼Ͱඳ͘ʣ w ίϯύεͷػೳΛΦϯʹ͢Δ w ݱࡏ஍ʹඈͿϘλϯΛදࣔʹ͢Δ
  5. Ґஔ৘ใͷݹ͞Λଌఆͯ͠ϑΟϧλʔ͢Δ private long getLocationAge(Location newLocation){ long locationAge; if(android.os.Build.VERSION.SDK_INT >= 17)

    { long currentTimeInMilli = (long)(SystemClock.elapsedRealtimeNanos() / 1000000); long locationTimeInMilli = (long)(newLocation.getElapsedRealtimeNanos() / 1000000 locationAge = currentTimeInMilli - locationTimeInMilli; }else{ locationAge = System.currentTimeMillis() - newLocation.getTime(); } return locationAge; } long age = getLocationAge(location); if(age > 5 * 1000){ //more than 5 seconds Log.d(TAG, "Location is old"); oldLocationList.add(location); return false; }
  6. ਫฏํ޲ͷਫ਼౓ͰϑΟϧλʔ͢Δ float horizontalAccuracy = location.getAccuracy(); if(horizontalAccuracy > 10){ //10meter filter

    Log.d(TAG, "Accuracy is too low."); inaccurateLocationList.add(location); return false; }
  7. ,BMNBO'JMUFSͰϑΟϧλʔ͢Δ /* Kalman Filter */ float Qvalue; long locationTimeInMillis =

    (long)(location.getElapsedRealtimeNanos() / 1000000); long elapsedTimeInMillis = locationTimeInMillis - runStartTimeInMillis; if(currentSpeed == 0.0f){ Qvalue = 3.0f; //3 meters per second }else{ Qvalue = currentSpeed; // meters per second } kalmanFilter.Process(location.getLatitude(), location.getLongitude(), location.getAccuracy(), elapsedTimeInMillis, Qvalue double predictedLat = kalmanFilter.get_lat(); double predictedLng = kalmanFilter.get_lng(); Location predictedLocation = new Location("");//provider name is unecessary predictedLocation.setLatitude(predictedLat);//your coords of course predictedLocation.setLongitude(predictedLng); float predictedDeltaInMeters = predictedLocation.distanceTo(location); if(predictedDeltaInMeters > 60){ Log.d(TAG, "Kalman Filter detects mal GPS, we should probably remove this from track"); kalmanFilter.consecutiveRejectCount += 1; if(kalmanFilter.consecutiveRejectCount > 3){ kalmanFilter = new KalmanLatLong(3); //reset Kalman Filter if it rejects more than 3 times in raw. } kalmanNGLocationList.add(location); return false; }else{ kalmanFilter.consecutiveRejectCount = 0; }
  8. 時間(秒) 距離(m) GPS個数 バッテリー
 (スタート時) バッテリー
 (ゴール) 消費量 42km走った 場合

    5時間走った 場合 Nexus6 Low Battery (every 5m) 1968 5710.0 790 16% 12% 4% 29.6% 36.6% Nexus6p Mid Battery (every 1m) 1785 5738.8 1349 50% 48% 2% 14.7% 20.1% Nexus6 Low Battery (every 5m) 1497 4583.8 581 22% 20% 2% 18.4% 24% Nexus6p High Battery (every 5m) 1684 5036.0 675 98% 95% 3% 25.1% 32% ෼ɺLNͰͷফඅྔ
  9. όοςϦʔ࢒ྔͷऔಘ private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver(){ @Override public void

    onReceive(Context ctxt, Intent intent) { int batteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); float batteryLevelScaled = batteryLevel / (float)scale; batteryLevelArray.add(Integer.valueOf(batteryLevel)); batteryLevelScaledArray.add(Float.valueOf(batteryLevelScaled)); batteryScale = scale; } };
  10.  όοςϦʔ࢒ྔʹΑͬͯ$SJUFSJBΛม͑Δ  .JOJNVN%JTUBODFͱ.JOJNVN5JNF͸ม͑ͯ΋(14νοϓ͕ফඅ͢ΔΤωϧΪʔ͸ಉ ͡ɻҐஔ৘ใΛड͚औ͔ͬͯΒͷॲཧʹΤωϧΪʔΛ࢖͍ͬͯΔ৔߹ʢαʔόʔ΁ͷૹ৴ͳͲʣ ͸ɺ.JOJNVN%JTUBODFͱ.JOJNVN5JNFͷ஋Λେ͖͘͢Δɻ όοςϦʔ࢒ྔΛҙࣝͨ͠ઃܭ LocationManager locationManager =

    (LocationManager) getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setPowerRequirement(Criteria.POWER_HIGH); criteria.setAltitudeRequired(false); criteria.setSpeedRequired(true); criteria.setCostAllowed(true); criteria.setBearingRequired(false); //API level 9 and up criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH); Integer gpsFreqInMillis = 1000; Integer gpsFreqInDistance = 5; // in meters locationManager.addGpsStatusListener(this); locationManager.requestLocationUpdates(gpsFreqInMillis, gpsFreqInDistance, criteria, this, null);
  11. 時間 (秒) 距離(m) GPS個数 バッテリー
 (スタート時) バッテリー
 (ゴール) 消費量 42km走った

    場合 5時間走った 場合 Nexus6p Mid Battery (every 1m, 1sec) 1785 5738.8 1349 50% 48% 2% 14.7% 20.1% Nexus6p High Battery (every 5m, 1sec) 1684 5036.0 675 98% 95% 3% 25.1% 32% .JOJNVN%JTUBODFͱ.JOJNVN5JNF͸ม͑ͨ৔߹ͷόοςϦʔফඅྔ