2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi PicoでGPSを解析したい!!

Last updated at Posted at 2025-01-27

すでにライブラリは存在しているので意味は少ないですが参考までに。
他のライブラリは衛星の位置などの詳細なデータは分かりませんが、一応このライブラリはそれができます。
(Githubに載せます→載せました https://github.com/saradaabura/pygps/tree/main
汚いコードで大変すみません

pygps.py
import re
patterns = {
    'GGA': re.compile(r'\$GNGGA,.*?\*..'),
    'GLL': re.compile(r'\$GNGLL,.*?\*..'),
    'GSA': re.compile(r'\$GNGSA,.*?\*..'),
    'GSV': re.compile(r'\$GNGSV,.*?\*..|\$BDGSV,.*?\*..|\$GLGSV,.*?\*..|\$GPGSV,.*?\*..'),
    'RMC': re.compile(r'\$GNRMC,.*?\*..'),
    'VTG': re.compile(r'\$GNVTG,.*?\*..')
}
def parse_nmea_sentences(nmea_data):
    parsed_data = {key: [] for key in patterns.keys()}
    for sentence in nmea_data:
        for key, pattern in patterns.items():
            if pattern.match(sentence):
                parsed_data[key].append(sentence)
    return parsed_data
def parse_lat_lon(lat, lon, lat_dir, lon_dir):
    lat_deg = int(lat[:2])
    lat_min = float(lat[2:])
    lon_deg = int(lon[:3])
    lon_min = float(lon[3:])
    latitude = lat_deg + lat_min / 60.0
    longitude = lon_deg + lon_min / 60.0
    if lat_dir == 'S':
        latitude = -latitude
    if lon_dir == 'W':
        longitude = -longitude
    return latitude, longitude
def parse_speed_knots_to_kmh(speed_knots):
    return float(speed_knots) * 1.852
def parse_gga(data):
    for sentence in data:
        parts = sentence.split(',')
        latitude, longitude = parse_lat_lon(parts[2], parts[4], parts[3], parts[5])
        altitude = float(parts[9])
        satellites_used = int(parts[7])
        return {"Lat" : latitude, "Lon" : longitude, "Alt" : altitude, "SatellitesUsed" : satellites_used}
def parse_rmc(data):
    for sentence in data:
        parts = sentence.split(',')
        time = parts[1]
        hours, minutes, seconds, millisecond = int(time[0:2]), int(time[2:4]), int(time[4:6]), int(time[7:10])
        latitude, longitude = parse_lat_lon(parts[3], parts[5], parts[4], parts[6])
        speed_knots = parts[7]
        speed_kmh = parse_speed_knots_to_kmh(speed_knots)
        date = parts[9]
        day, month, year = int(date[0:2]), int(date[2:4]), int(date[4:]) + 2000
        return {"Lat" : latitude, "Lon" : longitude, "Speed" : speed_kmh, "year" : year, "month" : month, "day" : day, "hour" : hours, "minutes" : minutes, "seconds" : seconds, "millisecond" : millisecond}
def parse_gsv(data):
    satellite_info_list = []
    satellites = 0
    for sentence in data:
        parts = sentence.split(',')
        try:
            num_satellites = int(parts[3])
            for i in range(4, len(parts) - 4, 4):
                satellite_id = int(parts[i])
                elevation = int(parts[i+1])
                azimuth = int(parts[i+2])
                snr = int(parts[i+3]) if parts[i+3] else 0
                satellite_info_list.append({
                    'SV': satellite_id,
                    'EL': elevation,
                    'AZ': azimuth,
                    'SNR': snr
                })
                satellites += 1
        except (ValueError, IndexError):
            pass
    return satellites, satellite_info_list
def parse_vtg(data):
    for sentence in data:
        parts = sentence.split(',')
        course_true = float(parts[1])
        speed_knots = float(parts[5])
        speed_kmh = float(parts[7])
        return {"course" : course_true, "speed" : speed_kmh}
def parse_gsa(data):
    for sentence in data:
        parts = sentence.split(',')
        mode = parts[1]
        fix_type = int(parts[2])
        pdop = float(parts[15])
        hdop = float(parts[16])
        vdop = float(parts[17].split('*')[0])
        satellites_used = [int(parts[i]) for i in range(3, 15) if parts[i].isdigit()]
        return {"fixmode" : mode, "fixtype" : fix_type, "PDOP" : pdop, "HDOP" : hdop, "VDOP" : vdop, "SVUsed" : satellites_used}
def parse_gll(data):
    for sentence in data:
        parts = sentence.split(',')
        latitude, longitude = parse_lat_lon(parts[1], parts[3], parts[2], parts[4])
        time = parts[5]
        hours, minutes, seconds = int(time[0:2]), int(time[2:4]), float(time[4:])
        status = parts[6]
        return {"Time" : [hours, minutes, seconds], "Lat" : latitude, "Lon" : longitude, "Status" : status}

プログラムの設定
patterns = {
'GGA': re.compile(r'$GNGGA,.?*..'),
'GLL': re.compile(r'$GNGLL,.
?*..'),
'GSA': re.compile(r'$GNGSA,.?*..'),
'GSV': re.compile(r'$GNGSV,.
?*..|$BDGSV,.?*..|$GLGSV,.?*..|$GPGSV,.?*..'),
'RMC': re.compile(r'$GNRMC,.
?*..'),
'VTG': re.compile(r'$GNVTG,.*?*..')
}
このような欄があると思いますが、その中でもGSVについては使用しているGPSモジュールで改変してください。(GALILEOはGAGSVなど適度追加してください)

使い方

注意点
このままでは動作しません 以下の点に注意してください
・readするところ oo.read(2048)は適度変更してください。(バッファーも)
・nmea0183 = raw[raw.find("$GNGGA"):raw.find("$GNGST")]これは一連のNMEAメッセージが取得できればいいだけなので、これじゃなくてもいいです。

GPSがNo Fixの時について
常にgsaのデータを取得してください

gsa = pygps.parse_gsa(i["GSA"])
    if gsa["fixtype"] >= 2:
        rmc = pygps.parse_rmc(i["RMC"])
        gsv = pygps.parse_gsv(i["GSV"])
        gll = pygps.parse_gll(i["GLL"])
        gga = pygps.parse_gga(i["GGA"])
        vtg = pygps.parse_vtg(i["VTG"])

2以上だと2dfixsです

main.py
def gps(shared_data):
    raw = air530.read(2048)
    if raw:
        raw = str(raw)
        nmea0183 = raw[raw.find("$GNGGA"):raw.find("$GNGST")]###ここは自分のGPSデバイスに合わせてください。
        if raw.find("$GNGGA") != -1 and raw.find("$GNGST") != -1:
            listdata = nmea0183.split("\\r\\n")
            i = pygps.parse_nmea_sentences(listdata)
            gsa = pygps.parse_gsa(i["GSA"])
            if gsa["fixtype"] >= 2:###これがないと**データがNone~~**と怒られます。
                rmc = pygps.parse_rmc(i["RMC"])
                gsv = pygps.parse_gsv(i["GSV"])
                gll = pygps.parse_gll(i["GLL"])
                gga = pygps.parse_gga(i["GGA"])
                vtg = pygps.parse_vtg(i["VTG"])
                if rmc and gsv and gll and gga and vtg:###先程と同様
                    #好きなように...

変数の構成は以下です
RMC
{'Speed': 0.0, 'hour': 12, 'Lon': float型, 'seconds': 28, 'year': 2025, 'minutes': 45, 'millisecond': 0, 'month': 1, 'Lat': float型, 'day': 27}
GSV
(使用衛星数, [{衛星データ}, {衛星データ}])
(2, [{'SV': 3, 'EL': 13, 'AZ': 52, 'SNR': 0}, {'SV': 4, 'EL': 40, 'AZ': 67, 'SNR': 18}])
GLL
{'Time': [12, 48, 36.5], 'Lat': float, 'Lon': float, 'Status': 'A'}
GGA
{'Lat': float, 'Lon': float, 'Alt': 35.5, 'SatellitesUsed': 13}
1行のみを取得し2行目からは取得しません
VTG
{'course': 310.88, 'speed': 0.0}
結構簡単に取得できるはずです。ちょっとプログラムを変更すれば、色々対応できると思います。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?