夏休みにピッタリ!電子工作入門キット発売中!今すぐチェック

Raspberry Pi PicoとGPSモジュールで位置情報を取得する【初心者OK!】

  • URLをコピーしました!

皆さんこんにちは。yossyです。

ラズピコで現在地を取得してみたいと思ったことはありませんか?
今回は、GPSモジュールとラズピコを使って、位置情報を取得する方法をご紹介します。
初心者の方でも簡単に試せるように、配線やコード、使い方まで丁寧に解説します!

目次

GPSモジュールとは?

GPSモジュールは、GPS衛星の電波を受信して位置(緯度・経度)や時刻を取得できるモジュールです。

取れるデータはたくさんあります。

項目名説明
現在時刻UTC(協定世界時)で現在の時刻を取得できる
日付年・月・日が取得できる
緯度北緯/南緯の座標
経度東経/西経の座標
高度海抜高度(メートル)
地上速度ノット(または km/h)での移動速度
進行方位移動している方向(真北からの角度)
衛星の数現在使っている衛星の数
測位モード2D/3Dのモードや、Fixの有無(A=有効, V=無効)
DOP値(精度)測位の精度を示す数値(HDOP/VDOP/PDOP)
衛星情報衛星ID、仰角、方位角、信号強度など
磁気偏差真北と磁北のズレ(地域による)
yossy

意外と多い!

何ができる?:場所と時刻がわかる!

GPSモジュールは、地球上のどこにいるか&時刻を知ることができるので、

  • 移動ルートの記録
  • ロボットの現在位置を送信
  • 時刻同期

などに使うことができます。

GPSモジュールの注意点:屋外で使おう!

GPSモジュールは、人工衛星の電波をアンテナで受信するので、電波が遮られる屋内では使うことが出来ません。

そのため、GPSモジュールを使う場合は屋外でアンテナが電波を受信できるようにして使いましょう!

Raspberry Pi PicoでGPSモジュールを使う方法

それでは、Raspberry Pi PicoでGPSモジュールを使う方法を解説します。

必要なもの

  • Raspberry Pi Pico
  • GPSモジュール(UART接続)
  • ジャンパワイヤー
  • ブレッドボード

UART接続とは?

UARTは、2本の線を使ってデータをやりとりする通信方式です。

ピンには「TX」と「RX」という名前がついており、それぞれ「送信(Transmit)」と「受信(Receive)」を意味します。
接続の際は、TXを相手のRXに、RXを相手のTXにつなぐ「クロス接続」を行います。

わかりやすく言えば、「糸電話」のようなイメージです。
糸電話では、自分の口から出た声が、相手の耳に届くように糸がつながっています。
UARTでも同じように、自分のTX(送信)から出たデータが、相手のRX(受信)に届くようにつなぎます。

配線

配線はこのようになります。

ラズピコのピン名接続先(GPSモジュール)説明
GP0(TX)RXラズピコからGPSへのデータ送信
GP1(RX)TXGPSからラズピコへのデータ受信
3V3(OUT)VCC電源(3.3V供給)
GNDGNDグラウンド(共通接地)
yossy

クロス配線を間違えないように!

プログラム-1 GPSデータを取得

GPSモジュールから送られてくるデータは、NMEAセンテンスと呼ばれる形式になっています。

種類内容の概要
$GPRMC推奨最小データ:時刻、ステータス、緯度、経度、速度、進行方位、日付など
$GPGGA測位データ:時刻、緯度、経度、FIX品質、衛星数、HDOP、高度など
$GPGSADOP情報:使用衛星のID、測位モード、PDOP/HDOP/VDOPなど
$GPGSV衛星情報:衛星数、各衛星のSNR/方位/仰角など(複数センテンスに分割される)
$GPVTG速度・方位:地上速度(km/h, ノット)、進行方向など

まずは基本的な情報の$GPRMCを取得してみましょう!

プログラムはこんな感じです。

from machine import UART, Pin
import time

# UART0 を GPS モジュールと接続(GP0=TX, GP1=RX)
uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))

# NMEAセンテンスと最小の長さ
SENTENCE_MIN_LEN = {
    "$GPRMC": 12,   # 推奨最小データ(時刻・日付・緯度・経度・速度・方位…)
    "$GPGGA": 10,   # 測位データ(時刻・緯度・経度・FIX品質・衛星数・HDOP・高度…)
    "$GPGSA": 18,   # DOP情報(PDOP/HDOP/VDOP、使用衛星ID一覧…)
    "$GPGSV": 4,    # 衛星情報(衛星数)※実際は可変長ですが、最低4つ目までは必須
    "$GPVTG": 9,    # 速度・方位(km/h, ノット)
}
    
def get_sentence(sentence_type):

    while True:
        # 受信データがあれば一行読み取り
        if uart.any():
            raw = uart.readline()
            if not raw:
                continue
            
            #受信データのデコード
            try:
                line = raw.decode('utf-8', 'ignore').strip()
            except:
                continue
            
            #正しく始まっているかチェック
            if not line.startswith(sentence_type):
                continue
            
            #リストに変換
            parts = line.split(',')
            
            #要素が揃っているかチェック
            if len(parts) < SENTENCE_MIN_LEN.get(sentence_type):
                continue
            
            #センテンスが有効かチェック
            if sentence_type == "$GPRMC" and parts[2] != 'A':
                continue
            
            print(parts)
            return parts
            
            
        time.sleep(0.1)

data = get_sentence("$GPRMC")
print(data)

プログラムの基本的な流れを説明すると

  1. UARTにデータが来てたら読み取り
  2. バイナリデータ(そのままでは使えない)を文字に変換(デコード)
  3. カンマで区切ってリストに変換

という流れになります。

これを実行すると、Thonnyのシェルに受信したデータが表示されます。
(電波を受信するまで時間がかかる場合があります!)

実際の画面

🧾 各データの意味

フィールド番号データ説明
0センテンスの種類どの情報か$GPRMC
1UTC時刻(hhmmss.ss)時間(協定世界時)075849.00 → 07:58:49
2ステータスA=有効, V=無効A
3緯度(ddmm.mmmm)度分形式(DMM)3456.7890
4北緯/南緯(N/S)北ならN、南ならSN
5経度(dddmm.mmmm)度分形式(DMM)13512.3456
6東経/西経(E/W)東ならE、西ならWE
7地上速度(ノット)1ノット ≒ 1.852 km/h0.288
8進行方位(度)真北からの角度(未入力もあり)空(未取得)
9日付(ddmmyy)日/月/年(2桁表記)120725 → 2025/07/12
10磁気偏差(度)方位の補正値(未入力もあり)空(GPSモジュールが対応していないことが多い)
11磁気偏差の方向(E/W)東(E)または西(W)空(上記と同じ)
12測位モード(NMEA 2.3以降)A=自律測位、D=DGPS、N=無効などA
13チェックサムデータ検査用16進値*7F

プログラム-2 緯度経度を取得

お次は、緯度経度を取得してみましょう。

NMEAセンテンスの緯度経度は、度分表記という形になっています。
このままではわかりにくいので、いつも使っている十進度に変換します!

プログラムを紹介する前に、下の度分表記を手動で変換してみます。

  • 緯度:3456.7890
  • 経度:13512.3456

まずは、度と分に分けます。

  • 緯度:34度 / 56.7890分
  • 経度:135度 / 12.3456分

これを下の変換式に代入します。

十進度 = 度 +(分 ÷ 60)

計算すると…?

  • 緯度:34.94648
  • 経度:135.20576

こうなります。
ここで次のように符号を変えます。

  • 北緯(N)・東経(E) → 正の値
  • 南緯(S)・西経(W) → 負の値

今回は北緯・西経で考えます。

  • 緯度:34.94648°
  • 経度:-135.20576°

度分表記を十進度に変換することができました!

yossy

場所は北太平洋の海上ですね!


それではプログラムを紹介します!
プログラム-1の続きにこのプログラムを追加してください。

def nmea_to_decimal(raw, hemi):
    """
    入力と出力の解説
    
    raw : 度分表記の緯度/経度(文字列)  例 "3745.1234"(DDMM.MMMM または DDDMM.MMMM)
    hemi: 東西南北(文字列) "N"/"S"/"E"/"W"
    return: 変換結果(浮動小数点), 例 37.752056
    """
    
    # まず小数点より前の桁数で「度」の桁数を判定
    # 緯度は DDMM.MMMM → 最初の2桁が度、経度は DDDMM.MMMM → 最初の3桁が度
    if len(raw.split('.')[0]) > 4:
        # 経度
        deg_len = 3
    else:
        # 緯度
        deg_len = 2

    degrees = float(raw[:deg_len])
    minutes = float(raw[deg_len:])
    dec = degrees + minutes / 60

    # 南半球・西経はマイナス
    if hemi in ('S', 'W'):
        dec = -dec

    return dec

#受信データから緯度経度と場所を取得
ido_raw = data[3]
ido_houkou = data[4]
keido_raw = data[5]
keido_houkou = data[6]

#変換
ido = nmea_to_decimal(ido_raw, ido_houkou)
keido = nmea_to_decimal(keido_raw, keido_houkou)

#表示
print(f"緯度: {ido}°, 経度: {keido}°")

これを実行すると、十進度に変換された緯度と経度が表示されます!

まとめ

今回は、Raspberry Pi PicoとGPSモジュールを使って、位置情報(緯度・経度)を取得する方法を紹介しました!

  • UART通信を使ってGPSと接続
  • NMEAフォーマットの読み取り
  • 緯度・経度を変換

GPSのデータは「位置」だけでなく、「速度」や「時間」なども取得できるため、工夫次第でさまざまな応用が可能です。

ラズピコとGPSを使えば、屋外で使える電子工作がグッと広がります。ぜひ今回の記事を参考に、オリジナルのGPSプロジェクトにチャレンジしてみてください!

この記事が気に入ったら
いいねしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次