[Android 開発] GPS モジュールが出力する NMEA メッセージを取得する

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

 GPS で位置情報を取得する際に、GPS モジュールが一体どのようなデータを処理しているのか、その生データ(?)を取得することができます。GPS モジュールが出力する NMEA メッセージを解読することで、更に詳細な情報を得ることができます。

このエントリーをはてなブックマークに追加  

スクラップ帳 » 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. NMEA メッセージが通知されるように、LocationManagerGpsStatus.NmeaListener を登録する
  5. NMEA メッセージを受信したら、先ほど登録した GpsStatus.NmeaListener のメンバ関数 onNmeaReceived がコールバックされる
  6. 動作を止めるには LocationManager から LocationListenerGpsStatus.NmeaListener を外す

 必要なリスナを生成して、LocationManager と併せて一緒に登録/解除する手順は、GPS 衛星の情報を取得するケースと同じです。


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

 人工衛星を利用した衛星測位システムのことをざっくりと "GPS" と呼んでいますが、本来の "GPS" とはアメリカが運用する衛星測位システムのことであって、実際の測位には、ロシアが運用・開発中の GLONASS や、ヨーロッパが運用・開発中の Galileo、また日本が運用・開発中の準天頂衛星システムの衛星からの電波を受信して動作しています。ですので、正しくは Global Navigation Satellite System と呼ぶのが良いようです。コンピュータ ゲーム一般のことを"ファミコン"と呼んでいるような感じですかね。

 NMEA メッセージの "$" を除く最初の 2 文字は Talker ID と呼ばれ、どの機器から送信されたメッセージか識別するためのものです。例えば、手元にある実機で動作させてみたところ、LG L-05D は GPS 信号しか受信できないため、GLONASS を表す GL や、準天頂衛星システムの QZ は現れません。Nexus 7 (2012) では、準天頂衛星システムの衛星からの信号を受信できるため、GPS に加えて QZ の NMEA メッセージが現れます。Nexus 7 (2013) では更に GLONASS を受信できるようですが、手元にないため確認できていません。

GP
 アメリカが運用する GPS 衛星に関するメッセージ。
GL
 ロシアが運用・開発中の GLONASS に関するメッセージ。
QZ
 日本の JAXA が運用・開発中の準天頂衛星システムに関するメッセージ。

 この NMEA メッセージには衛星に関する情報や測位情報など全て含まれているので、メッセージを自前で解析してやれば、GPS 衛星の情報や、測位情報など全て得ることができます。

ソースコード

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.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.NmeaListener GpsNmeaListener = 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) {}
        };

        GpsNmeaListener = new GpsStatus.NmeaListener()
        {
            public void onNmeaReceived(long timestamp, String nmea) {
                TextView t = (TextView) findViewById( R.id.textView1 );
                String buf = t.getText().toString();
                // バッファの先頭に追加
                buf = nmea + buf;
                // 改行で分割
                String[] bufs = buf.split( "\\r\\n" );
                // 最初の 20 行だけ取り出して
                buf = ""; for( int i = 0; i < 25 && i < bufs.length; i++ ) buf += bufs[i] + "\r\n";
                t.setText( buf );
            }
        };
    }

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

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

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

        mLocationManager.removeNmeaListener( GpsNmeaListener );
        mLocationManager.removeUpdates( mLocationListener );
    }
}

解説

 ソースコードの基本的な部分は、前回までとほとんど同じです。

38~51 行目
 NMEA メッセージを受け取る GpsStatus.NmeaListener インスタンスを生成しています。
40~50 行目
 NMEA メッセージを、アクティビティに配置した TextView に書き出しています。NMEA メッセージは次々と受けとるので、最近の 25 件だけを残すようにしています。

参考リンク

このエントリーをはてなブックマークに追加  


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

カバー画像:[Android 開発] GPS 衛星の情報を取得する

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

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

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

コメントを投稿する

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