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

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

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

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

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

Avatar for Takamitsu Mizutori

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͸ม͑ͨ৔߹ͷόοςϦʔফඅྔ