
最近RaspberryPi沼にハマりかけているgoldear@goldear820です。


前回、ようやくGPSロガーとして形になりましたが、記録したCSVファイルではGoogleMapにインポートすることができません。
GPS情報をわざわざ記録するのは「地図に重ね合わせて楽しみたい」というものなので、このままでは非常に残念なCSVファイルだけが残ります。
今回はCSVファイルを、GoogleMapにインポートできる形式GPXファイルに変換していきます。またRaspberryPiは特に必要としないため、python実行環境であればWindows環境でもOKです。
目次
予備知識
CSV->GPX変換するにあたり、GPXフォーマットを知っておく必要があります。大まかなフォーマットは手持ちのGPXファイルをテキストエディタで開けば大体分かります。詳細仕様については以下を確認してください。
GPSで取得した位置情報はDMM(Degree Minute)でCSVに記録されますが、GPX形式ではDEG(Degree)で記述するため変換が必要です。以下のページが参考になり、分かりやすいです。

GPXファイルはXML記述されており、pythonに組み込まれている標準ライブラリを「ElementTree」を用いてGPXファイルを生成します。以下がpython公式のドキュメントになります。

ElementTreeでGPXファイルを生成すると改行が入らないため、書込みだけはpythonに組み込まれている標準ライブラリ「minidom」を用います。以下がpython公式のドキュメントになります。

実装
pythonプログラムの大まかな内容としては、CSVファイルを指定して、ファイル先頭から一行読み取り、経度緯度をtrkptの属性として付与し、高度・速度をサブ要素の値として記述します。これをCSVファイル末尾まで繰り返すことでGPXファイルに変換します。
CSVに保存したGPS情報群は第02回のソースコードに記載してあるので参考にどうぞ。

#!/usr/bin/env python3
# encoding: utf-8
## common
import os
from datetime import datetime as dt
import xml.etree.ElementTree as ET
import xml.dom.minidom as md
import re
INPUT_CSV = "2024-01-01.csv"
OUTPUT_GPX = "2024-01-01.gpx"
GPX_VER = "1.1"
CREATOR = "goldear - https://goldear.net"
XMLNS_XSD = "https://www.w3.org/2001/XMLSchema"
XMLNS_XSI = "https://www.w3.org/2001/XMLSchema-instance"
XSI_SL = "http://www.topografix.com/GPX/1/1/gpx.xsd"
####################################
# SUB FUNCTION
def get_date(file):
timestamp = os.path.getmtime(file)
date = dt.fromtimestamp(timestamp)
return date
def dmm2deg(dmm_lat, dmm_lon):
# Convert DMM(Degree Minute) -> DEG(Degree)
## Latitude: decimal -90.0 <= value <=90.0
d_lat = dmm_lat[0:2]
int_m_lat = str(dmm_lat[3:5])
sub_m_lat = "." + str(dmm_lat[5:])
float_m_lat = float(int_m_lat + sub_m_lat)
m2d_lat = float_m_lat/60
lat = float(d_lat) + m2d_lat
deg_lat = str(lat)
## Longitude: decimal -180.0 <= value <=180.0
d_lon = dmm_lon[0:3]
int_m_lon = str(dmm_lon[4:6])
sub_m_lon = "." + str(dmm_lon[6:])
float_m_lon = float(int_m_lon + sub_m_lon)
m2d_lon = float_m_lon/60
lon = float(d_lon) + m2d_lon
deg_lon = str(lon)
return deg_lat, deg_lon
####################################
# MAIN FUNCTION
def csv2gpx():
## Get time
date = get_date(INPUT_CSV)
s_date = date.strftime("%y-%m-%d")
s_time = date.strftime("%H:%M:%S")
## Create ROOT
root = ET.Element("gpx")
root.set("version", GPX_VER)
root.set("creator", CREATOR)
root.set("xmlns:xsd", XMLNS_XSD)
root.set("xmlns:xsi", XMLNS_XSI)
root.set("xsi:schemaLocation", XSI_SL)
## Set Time
l_time = ET.SubElement(root, "time")
l_time.text = str("20" + s_date + "T" + s_time + "+09:00")
## Create truck
l_trk = ET.SubElement(root, "trk")
## Create truck segment data
l_trkseg = ET.SubElement(l_trk, "trkseg")
## Read Log 1-line
with open(INPUT_CSV, mode="r", encoding="utf-8") as f_csv:
while True:
l_gpslog = f_csv.readline()
if not l_gpslog:
break
else:
### split
ls_gpslog = re.split("[,*]",l_gpslog)
if ls_gpslog[2] == "." or ls_gpslog[4] == ".":
continue
## Create truck point
l_trkpt= ET.SubElement(l_trkseg, "trkpt")
## Convert DMM -> DEG
lat, lon = dmm2deg(ls_gpslog[2], ls_gpslog[4])
l_trkpt.set("lat", lat[0:10] )
l_trkpt.set("lon", lon[0:11] )
## Create Elevation
l_ele = ET.SubElement(l_trkpt, "ele")
l_ele.text = ls_gpslog[5]
## Create time
l_tr_time = ET.SubElement(l_trkpt, "time")
l_tr_time.text = ls_gpslog[7][0:20]
## Create speed
l_speed = ET.SubElement(l_trkpt, "speed")
l_speed.text = ls_gpslog[6]
## Organize XML
XML = md.parseString(ET.tostring(root, "utf-8"))
## Write
with open(OUTPUT_GPX, "w") as f:
XML.writexml(f, encoding="utf-8", newl="\n", indent="", addindent=" ")
if __name__ == "__main__":
csv2gpx()
Google Map にインポートしてみる
テスト用に擬似位置情報を用いて、pythonコードを実行してCSVファイルをGPXファイルに変換してみます。
場所はぱらのま第02巻Line.07の描写を参考に抽出しました。
亀戸天神: 35.421017 139.491443
高円寺 : 35.421267 139.391011
有明 : 35.375419 139.473294
王子神社: 35.451306 139.441022
厳島神社: 35.373338 139.405905
2024-01-01 09:00:00,N,35.421017,E,139.491443,100,100,2024-01-01T00:00:00.000Z 2024-01-01 09:00:01,N,35.421267,E,139.391011,101,101,2024-01-01T00:00:01.000Z 2024-01-01 09:00:02,N,35.375419,E,139.473294,102,102,2024-01-01T00:00:02.000Z 2024-01-01 09:00:03,N,35.451306,E,139.441022,103,103,2024-01-01T00:00:03.000Z 2024-01-01 09:00:04,N,35.373338,E,139.405905,103,103,2024-01-01T00:00:03.000Z 2024-01-01 09:00:05,N,35.421017,E,139.491443,104,104,2024-01-01T00:00:04.000Z
変換したGPXファイルをGoogle Map にインポートしてみました。バッチリ変換できています。
GoogleMapへのインポート方法は以下にまとめてありますので参考にどうぞ。

まとめ
細かい部分(入出力ファイルを指定するなど)は改善の余地ありですが、CSV -> GPXファイル変換の基礎は完成しました。
次はGPSロガーの本体のケーシングやさらなる小型化を図っていきます。もしかすると Zero2 W ではなく Pico W で作り直すかもしれないです。


コメント