車を買ったものの使う用事があまり無い。
バッテリーが上がるのが嫌なので週1回、半日程度のドライブをしている。
近場の道の駅、観光地などを巡るうち
楽しくなってきて走行コースを地図上で見直したいと
思うようになった。
以前マラソンの練習をしていたころ、
走ったルートを
GARMINのランニングウォッチで
見るのが楽しかった。
車載しやすいGPSトラッカーを探すが、
良さげなものがみつからない。
ドライブ・レコーダー(以下ドラレコと記す)が
安いし使いやすい。
どうせ必要なものなので購入することにした。
購入したのは
コムテックのZDR036、
アマゾンから 27,055円。
スペーシアに取付け頑張ってケーブルも隠した。
で、ドライブに行ってみた。
ドラレコのSDカードをPCに接続すると
コムテック提供の
ビューワソフトで映像とともに地図を表示できるが,
地図上の軌跡は30秒刻みで、全体像が見れない。
運行管理ソフト
であればコース全体を表示できそうだが、
ZDR036は対象外。
自分でドラレコのファイルからGPS情報を抜き出し、自力で地図上に表示することを
考える。ネットで検索するとやっている人もいるようだ。
|
コムテックのビューワソフト |
AVIファイルからGPS情報を抜き出す
ドラレコのSDカードの中身を調べる。
AVIファイルしかない。
メディアプレイヤー等で開くと動画を再生することができる。
30秒毎にファイルが分かれている。
AVIファイルはコンテナファイルで色んな情報が含まれている
のでGPS情報も含まれているのかもしれない。
|
SDカードの中身はAVIファイルばかり |
AVIファイルは
RIFFというファイル形式で、これはチャンクと呼ばれるデータの塊で構成されている。チャンクは4バイトの識別子、4バイトの符号なしリトルエンディアンの長さ、可変長データフィールド、パディングから構成される。
長さは可変長データフィールドの長さである。
チャンクの長さが偶数でない場合には1バイトのパディングが追加される。
識別子が'RIFF'と'LIST'のチャンクは可変長データフィールドの中身も
定義されている。先頭は4バイトの識別子で、それ以降は
長さが尽きるまでRIFFのチャンクが続く。
ファイル全体は 識別子RIFFのチャンクとなっている。
これだけわかれば、AVIファイルの構造を表示できる。
ダンプ・プログラムをpythonで作ってみた。
from struct import unpack
from sys import argv
class Riff:
def __init__(self, name: str, size: int):
self.name = name
self.size = size
self.type = ""
self.children = []
def parse(f, pos: int):
f.seek(pos)
buf = f.read(8)
(name, size) = unpack("4sI", buf)
name = name.decode("UTF-8")
node = Riff(name, size)
node.end = pos + 8 + size
if size % 2:
node.end += 1
if name == "RIFF" or name == "LIST":
f.seek(pos + 8)
buf = f.read(4)
node.type = buf.decode("UTF-8")
pos2 = pos + 12
while pos2 < node.end:
child = Riff.parse(f, pos2)
node.children.append(child)
pos2 = child.end
return node
def dump(self, level: int = 0):
print(f"{' ' * level}{self.name} {self.type} size:{self.size}")
for c in self.children:
c.dump(level + 1)
if __name__ == "__main__":
f = open(argv[1], "rb")
node = Riff.parse(f, 0)
node.dump()
ドラレコのAVIファイルをダンプさせるとこうなる。
$ python riff2.py data/t240218/NORMAL/Rear/20240218_091403_R_Nor.AVI
RIFF AVI size:67215100
LIST hdrl size:440
avih size:56
LIST strl size:116
strh size:56
strf size:40
LIST strl size:92
strh size:56
strf size:16
LIST strl size:140
strh size:56
strf size:64
LIST movi size:67167256
00dc size:306740
01wb size:4200
02tx size:145
00dc size:72882
01wb size:4200
02tx size:145
01wb size:4200
... 以下略 ...
AVI RIFF File Reference
に hdrlやstrh,strfのフォーマットの説明がある。
00dcは圧縮された画像のチャンク、01wbは音声のデータらしい。
ということで 145byteの 02txチャンクが怪しい。
プログラムを修正し、 02txの内容を出力してみる
$ python riff3.py ../data/t240218/NORMAL/Rear/20240218_091403_R_Nor.AVI
ZDR036:2024-02-18 09:14:03 X: 0.00 Y: 0.00 Z: 0.00 031.0T 12.6V G 32.6847116 N 130.7532066 E 0km/hE:255 M:255 EM:255 DO:255 SA:0 V:100 S:24897k
ZDR036:2024-02-18 09:14:03 X: 0.00 Y: 0.00 Z: 0.00 031.0T 12.6V G 32.6847116 N 130.7532066 E 0km/hE:255 M:255 EM:255 DO:255 SA:0 V:100 S:24897k
ZDR036:2024-02-18 09:14:03 X: 0.00 Y: 0.00 Z:-0.00 031.0T 12.6V G 32.6847116 N 130.7532066 E 0km/hE:255 M:255 EM:255 DO:255 SA:0 V:100 S:24897k
ZDR036:2024-02-18 09:14:03 X: 0.00 Y: 0.00 Z:-0.00 031.0T 12.6V G 32.6847116 N 130.7532066 E 0km/hE:255 M:255 EM:255 DO:255 SA:0 V:100 S:24897k
... 以下略 ...
いろんな情報が出力されている。
緯度経度、加速度、車速、バッテリー電圧等も見える。
これで走行軌跡の緯度、経度が取得できる。
地図への表示
Javascriptのライブラリ
leafletを使用すると簡単に地図の表示をすることができる。
地図画像は
openstreetmapや
国土地理院のものが使える。
GoogleMapも使用できるのだが、
使用して良いかどうかはよくわからない。
地図の表示をWebアプリで作るか、PC上の
Electronのアプリで作るか少し悩む。
ドラレコのSDカード上のファイルというかなり大きなファイルを
扱うのでPC上のアプリの方が便利そうだが、
日常使用するにはリンクで起動できるWebアプリの方が使いやすい。
結局、ドラレコのSDカードのファイル操作は別プログラムで処理する
ことにして、Webアプリとして作ることにした。
Webアプリのフレームワークには
Mojoliciousを使用。
ページのひな型とapiを提供。
実際の処理はtypescriptで行う。
MojoliciousはCGIとしても使用可能なので
expressのように常時サーバーを動かしていなくても良い。
低負荷の自分専用のサービスなどに便利だ。
完成した画面を以下に示す。
|
御船の恐竜博物館、豊野アグリパーク方面をドライブ |
|
御船恐竜公園に行くつもりが、ナビに恐竜博物館と入力したため迷っている様子 |
ドラレコのGPSの情報は画像のフレーム毎に記録されているが
内容は1秒ごと更新されるので間引いて表示している。
それでも1秒ごとに2点で、4時間のドライブだと2×3600×4=28,800点ほどになるが
leafletは難なく表示する。遅いと感じることはない。
今後
現状、ドラレコのSDカードからのデータを処理するのに
手作業が多く発生しているが、これを自動化/省力化したい。
また、動画データも地図から指定して再生できるようにしたい。
場所ごとの通過時間はわかっているので、
その時間の動画を再生すればいいのだが、
ひとつの動画ファイルにしてしまうと
ダウンロードだけで時間がかかってしまう。
この辺はどうしたらいいのだろうと調べて
HLSプロトコルというものを知る。
わりと簡単にできそうなので試してみたい。