すでにライブラリは存在しているので意味は少ないですが参考までに。
他のライブラリは衛星の位置などの詳細なデータは分かりませんが、一応このライブラリはそれができます。
(Githubに載せます→載せました https://github.com/saradaabura/pygps/tree/main )
汚いコードで大変すみません
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です
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}
結構簡単に取得できるはずです。ちょっとプログラムを変更すれば、色々対応できると思います。