AndroidからGNSS衛星情報を取り出す
もともとはRTCMの動作確認をするうえでGNSSアンテナとレシーバを自費で購入するわけにもいかず(そこまで興味はない)、android端末で代わりにならないかと考えたことが発端です。
rawデータを取得する前段階として、android端末が受信している衛星情報(svid、方位角、仰角、CNR等)を取得するプログラムを考えます。
自位置を取得するだけならばFusedLocationProviderClient
を使用して取得できるので、衛星情報を使う必要性は一般的にありません。
衛星情報取得までの流れ
衛星情報を取得するためにAPI level 24で追加されたGnssStatus
を使用します。API Level 24なのでAndroid 7以降のプラットフォームが必要です。
GnssStatus.Callback
GnssStatus.CallbackはGNSSステータスが変化したときに呼び出されます。
onSatelliteStatusChanged
は「定期的」に呼び出されると定義されており、実測では1秒ごとに呼び出されているようです。
private val gnssCallback: GnssStatus.Callback = object:GnssStatus.Callback() { override fun onFirstFix(ttffMillis: Int) { super.onFirstFix(ttffMillis) // 最初のFixまでの時間(ミリ秒)が設定される } override fun onStarted() { super.onStarted() } override fun onSatelliteStatusChanged(status: GnssStatus?) { super.onSatelliteStatusChanged(status) val satelliteCount: Int = status?.satelliteCount ?: 0 for(i in 0 until satelliteCount) { val constellation: Int? = status?.getConstellationType(i) // 衛星システム val svid: Int? = status?.getSvid(i) // svid val azimuth: Float? = status?.getAzimuthDegrees(i) // 方位角 val elevation: Float? = status?.getElevationDegrees(i) // 仰角 val cnr: Float? = status?.getCn0DbHz(i) // carrier-to-noise val usedInFix: Boolean? = status?.usedInFix(i) // Fixに使用したか } } override fun onStopped() { super.onStopped() } }
パーミッションチェックからCallback登録、削除
private val permissionRequestCode: Int = 1000 private lateinit var locationManager: LocationManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) locationManager = getSystemService(LOCATION_SERVICE) as LocationManager } override fun onStart() { super.onStart() getGnssStatus() } override fun onStop() { closeGnssStatus() super.onStop() } // GnssCallbackの設定 private fun getGnssStatus() { // 位置情報のパーミッションを取得 if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // パーミッションが設定されていなければ許可リクエスト ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), permissionRequestCode) } else { // パーミッションが設定されていればGnssCallbackを登録 locationManager.registerGnssStatusCallback(gnssCallback) } } // GnssCallbackの削除 private fun closeGnssStatus() { locationManager.unregisterGnssStatusCallback(gnssCallback) } // パーミッション許可、不許可時に呼び出される override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { when(requestCode) { permissionRequestCode -> if((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { getGnssStatus() } else { // パーミッションが許可されなければ終了 finish() } } }