[Android 開発] GPS 衛星の情報を取得する

Posted by
ぴろり
Posted at
2015/02/06 17:19
Trackbacks
関連記事 (0)
Post Comment
コメントできます
Category
開発メモ カテゴリ
カバーイメージ

 GPS を利用して端末の位置情報を得るところまで実装できましたが、更に GPS エンジンの動作情報を取得することもできます。具体的には、GPS 測位に利用した GPS 衛星の位置や GPS 信号の受信状況を取得できるので、例えば GPS Status & ToolboxGPS Essentials のように、GPS 衛星の位置をレーダーっぽく表示するようなことができるようになります。
 位置情報を求めるシーンで、これら個々の GPS 衛星の情報まで必要とするケースはまず無いと思いますが、自分の書いたコードで、上空 20,000km を飛行する個々の GPS 衛星を追跡できていると思うとちょっとワクワクしますね。

この記事を Delicious に追加する   このエントリーをはてなブックマークに追加  

スクラップ帳 » Android アプリ開発 Tips ~ センサ入力

 Android アプリを開発する際の小技まとめ。GPS、コンパスなどの各種センサ デバイスからのデータの取得方法などの覚書きを網羅して、必要な機能をコピー&ペーストで再利用できるようにします。

  1. GPS を使う 2015/02/05
  2. GPS 衛星の情報を取得する 2015/02/06 今ココ
  3. GPS モジュールが出力する NMEA メッセージを取得する 2015/02/06
  4. 端末の傾きと方位角を求める (非推奨) 2015/02/07
  5. 端末の傾きと方位角を求める 2015/02/07

概要

 基本的な処理の流れは次の通りです。

  1. AndroidManifest.xml で、android.permission.ACCESS_FINE_LOCATION 権限を要求しておく
  2. LocationManager を取得する
  3. 位置情報が変化したら通知されるように、LocationManagerLocationListener を登録する
  4. GPS の動作状態を通知してもえるように、LocationManagerGpsStatus.Listener を登録する
  5. GPS の動作状態が変化したら、先ほど登録した GpsStatus.Listener のメンバ関数 onGpsStatusChanged がコールバックされる
  6. 動作を止めるには LocationManager から LocationListenerGpsStatus.Listener を外す

 必要なリスナを生成して LocationManager に登録する手順は、GPS で位置情報を得る場合と同じです。しかし注意すべき点として、GpsStatus.Listener だけでなく、位置情報を必要としていない場合であっても LocationListener も忘れずに登録しないと、更新通知がされません*1


Fig.1 スクリーンショット

PRN
 Pseudo Random Noise Code Number。GPS 信号を伝送する際に利用される GPS 衛星ごとに異なる擬似雑音符号のコード番号で、現在は衛星番号と同一に扱われています。
Azimuth
 衛星の位置する方位角。北を 0 度、東を 90 度、南を 180 度、西を 270 度とします。
Elevation
 衛星の位置する仰角。地平線を 0 度、天頂を 90 度とします。
S/N
 GPS 信号/ノイズ比で、単位は dB(デジベル)。

ソースコード

package com.example.helloworld;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.content.Context;
import android.location.LocationManager;
import android.location.LocationListener;
import android.location.Location;
import android.location.GpsStatus;
import android.location.GpsSatellite;
import android.widget.TextView;

// http://developer.android.com/reference/android/app/Activity.html
public class MainActivity extends ActionBarActivity
{
    private LocationManager mLocationManager = null;
    private LocationListener mLocationListener = null;
    private GpsStatus.Listener mGpsStatusListener = null;

    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLocationManager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );
        final boolean gpsEnabled = mLocationManager.isProviderEnabled( LocationManager.GPS_PROVIDER );
        if (!gpsEnabled) {
            // ToDo: GPS 有効にしてくれー
        }

        mLocationListener = new LocationListener()
        {
            public void onLocationChanged(Location location) {}
            public void onStatusChanged(String provider, int status, Bundle extras) {}
            public void onProviderEnabled(String provider) {}
            public void onProviderDisabled(String provider) {}
        };

        mGpsStatusListener = new GpsStatus.Listener()
        {
            public void onGpsStatusChanged( int event ) {
                // http://developer.android.com/reference/android/location/GpsSatellite.html
                Iterable<GpsSatellite> satellites = mLocationManager.getGpsStatus(null).getSatellites();
                int sat_used = 0;
                int sat_total = 0; // GpsStaus.getMaxSatellites() の返り値が謎
                String str = "PRN : Azimuth : Elevation : S/N\n";
                for( GpsSatellite sat : satellites ) {
                        if( sat.usedInFix()) {
                            str += "*"; sat_total++; sat_used++;
                        } else {
                            str += " "; sat_total++;
                        }
                        str += String.format( "%2d", (int) sat.getPrn()) + " : ";
                        str += String.format( "%7d", (int) sat.getAzimuth()) + " : ";
                        str += String.format( "%9d", (int) sat.getElevation()) + " : ";
                        str += String.format( "%4.1f", sat.getSnr()) + "\n";
                }
                str += String.format( "\nsatellites %d/%d\n" , sat_used, sat_total );

                TextView t = (TextView) findViewById( R.id.textView1 );
                t.setText( str );
            }
        };
    }

    protected void onStart() { // ⇔ onStop
        super.onStart();

        mLocationManager.addGpsStatusListener( mGpsStatusListener );
        mLocationManager.requestLocationUpdates(
                LocationManager.GPS_PROVIDER,
                1000 * 1/*mSec*/, 1/*meter*/,
                mLocationListener );
    }

    protected void onStop() { // ⇔ onStart
        super.onStop();

        mLocationManager.removeGpsStatusListener( mGpsStatusListener );
        mLocationManager.removeUpdates( mLocationListener );
    }
}

解説

 基本的な部分は、GPS で位置情報のみを取得する場合と同じです。

31~37 行目
 LocationListener のインスタンスを生成しています(概要の手順 3)。ただし、今回のサンプルでは位置情報を利用しないので、実装すべきメンバ関数は何の動作もしませんが、動作に必須のためインスタンスを省略できません。
39~63 行目
 GpsStatus.Listener のインスタンスを生成しています(概要の手順 4)。ここでは匿名クラスとしてリスナを生成していますが、お行儀よく GpsStatus.Listener を implements したサブクラスを定義すべきです。ここでリスナを生成していますが、まだ LocationManager に登録されていないので、位置情報は取得しません。
41 行目
 GPS の状態が変化した際に呼ばれます(概要の手順 5)。ここで、GpsStatus オブジェクトから GpsSatellite オブジェクトを取得できるので、確認のために内容を整形して、アクティビティに配置した TextView に出力しています。
69~70 行目
 GpsStatus.Listener だけでなく、LocationListener と一緒に登録しないと更新通知されません。
79~80 行目
 GpsStatus.Listener だけでなく、LocationListener も忘れずに一緒に止めます。

メモ

 ついでに開発中に出会った単語などのメモ。

GpsSatellite.usedInFix()
 該当する衛星の情報を測位に利用したか否かのフラグ。
Almanac (アルマナック)
 GPS 衛星から送信される GPS 信号(航法メッセージ)に含まれる衛星が飛行する軌道情報のこと。
Ephemeris (エフェメリス)
 GPS 衛星の正確な位置情報と、GPS 信号を発信した時間に関する情報のこと。
Cold Start (コールド スタート)
 GPS 受信機が、アルマナック データもエフェメリス データも無い状態から GPS 測位を開始すること。GPS 衛星から軌道情報を全て受信するのに少なくとも 12 分 30 秒を要する。
Warm Start (ウォーム スタート)
 GPS 受信機のアルマナック データだけで GPS 測位を開始すること。
Hot Start (ホット スタート)
 GPS 受信機にアルマナック データもエフェメリス データもある状態で GPS 測位を開始すること。

参考リンク

この記事を Delicious に追加する   このエントリーをはてなブックマークに追加  

  1. *1 登録した LocationListener からは位置情報を同時に取得できますが、このサンプルでは本題ではないので、取得した情報はそのまま捨てています。

この記事を読んだ人はこんな記事も読んでいます記事リコメンデーションについて

カバー画像:[Android 開発] GPS を使う

関連記事/トラックバック

関連記事/トラックバックはまだありません

この記事にトラックバックを送るには?

コメントを投稿する

 
 (必須, 匿名可, 公開, トリップが使えます)
 (必須, 匿名可, 非公開, Gravatar に対応しています)
 (必須)
スパム コメント防止のため「投稿確認」欄に ランダムな数字 CAPTCHAについて を入力してから送信してください。お手数ですがご協力のほど宜しくお願いいたします。