アプリを使ってライド記録を地図上に描こう

いままでに走ったことのある場所を可視化したい。他の人と自分の走行記録を見比べたい。知らない道を手早く見つけたい。

スポーツ自転車に乗ってサイクルコンピュータで走行記録をとっている人であれば、現在までの走行記録をまとめて表示してみたくなることがあるものです。およそ半年前に Garmin / Strava の走行記録をまとめて表示するという記事を書いたところ、今でも毎日、それなりのアクセス数がありますので同じことを考えている人も少なくないのではないかと推測されます。

実際に表示してみると、もう走り尽くしたと思っていた地域にも行ったことがない場所が、そこかしこに残っていたりと、新しい発見につながるものです。

しかし、上の過去記事に取り上げた方法では、多少の事前知識と実行環境の準備が必要となりますので、誰でも直ぐに実現できるというわけではありません。

そこで今回はデスクトップアプリを使用して、1つ以上の FIT ファイルから位置情報を抜き出して、ウェブブラウザ上で地図に表示することを行います。

手っ取り早く使い方だけを知りたい人は、以下のリンクを見てください。


FITファイルから位置情報を取り出して地図上に表示する方法





そんなものがあるなら、どうして最初に紹介しなかったのかと言うと、無かったので(少なくとも私が探した限りでは見つからなかったので)自分で作ったからです。

ただし、要素技術に用いた Electron に触れることも今回が初めて、シングルページアプリケーション (SPA) に挑戦することも今回が初めて、そもそもフロントエンド自体の経験が全くありませんので、出来栄えについては保証できません。

当初は「週末の2日あれば完成するかな」と軽く考えていたところ、実際には見積もりの1.5倍ぐらいの作業時間が完成までに必要となりました。

とにかく未経験なので SPA のファイル構成や暗黙の規則などの勝手が分からないですし、標準エラー出力の表示からモジュールの読み込み、パッケージビルドまで躓き続けて、ドキュメントも部分的にしか目を通せていないので、一応は動くものを作成した現在においても完全に Electron を理解できたとは到底言えません。

と言うか、1年前の情報でも古くて役に立たなくなっていたりするのに、Electron どころか webpack に elecron-builder にと調べることがありすぎて沼が深すぎます。 JVM も Linux もインストールされていない環境でもプログラムを動かせるぞと思って飛び付いたことを後悔するレベルです。

それでは何故、こんな記事やコードやプログラムを公開しているのかと言えば、恥ずかしくても練習しないと上達しないからです。

とくに人が直接的に操作することを前提としたプログラムは、実際に触って動かしてみないと評価できません。そのために開発中においても評価目的でバイナリを公開しています。

現状は以下のとおりです。


読み込めるのは FIT 形式のファイルのみです(GPXファイルへの対応は未定)
FITファイルの保存形式はSI単位系のみ対応しています
ポリライン描画に使用できるのは赤のみです(何を基準に色を変えるかによって様々な表現ができるので実装を保留中)
地図タイルは OSM のみです
一度に読み込めるファイル容量はお使いの環境に依存します

緩募:アイコン、 Wahoo および CATEYE のアクティビティファイル、新機能のアイデア

私の会社ではありませんけれども、同業の知り合いの会社も3月からレイオフが実施されていていて、業績が悪いのにめちゃくちゃ忙しいので、通常にもまして自由時間が少ない(作業の進展が遅い)です。


具体的な使い方はこちらになります


パナレーサー(Panaracer) パナレーサー 日本製チューブ2本入 [W/O700x23~26C] 仏式バルブ 0TW700-25F-NP-2 仏式バルブ34mm

Gulp v4 は apt で入れるなという話

Gulp.js をインストールしたはずなのに Error: Cannot find module ‘gulp-util’ というエラーメッセージが表示されて、うまく動作しないことがあります。

まさに今、私が後輩から聞かされているように。

gulp-util は 2017年末の gulp v4.0.0-alpha.3 から非推奨になっているので、今さら出てくるのも一見すると不思議な話です。

公式ページでも以下のような手順でインストールすることが指示されていますので、理想的な場合にはこのような出力になるはずです。

$ npm install gulp-cli -g
$ npm install gulp -D
$ npx -p touch nodetouch gulpfile.js
$ gulp --version
CLI version: 2.2.0
Local version: 4.0.2

ところがエラーメッセージが表示されている画面を見ると、そうはなっていません。

$ gulp --version
module.js:550
    throw err;
    ^

Error: Cannot find module 'gulp-util'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._load (module.js:475:25)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/usr/lib/nodejs/gulp/bin/gulp.js:4:13)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)




動作環境は次の通りで、とくにシステム更新を怠っているわけでもなさそうです。

$ node --version
v13.2.0

$ npm --version
6.14.2

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

しかし gulp のインストール位置を調べてみると何かがおかしいです。

$ which gulp 
/usr/bin/gulp

どうしてこうなるの?と少し調べてみると Ubuntu 18.04.4 LTS で gulp コマンドが見つからない場合、apt からインストールできるというメッセージが表示されるようです。

$ gulp --help

Command 'gulp' not found, but can be installed with:

sudo apt install gulp

その指示通りにインストールするとうまく動かなくなりますので、最初にやるべきことは(もしインストールされているならば)古いバージョンの gulp を消すことです。

$ sudo apt remove --purge gulp -y

それから公式ページの手順に従って現在の安定版をインストールして、インストール先のディレクトリにパスを通します。

$ npm i -g gulp-cli 
$ export PATH=$(npm config get prefix)/bin:$PATH
$ which gulp
/home/hoge/.npm-global/bin/gulp

$ gulp --version
CLI version: 2.2.0
Local version: Unknown

うまくインストールできましたら大丈夫なはずなので、~/.bashrc にでも PATH を付け足しておけばいつでも使えるようになるはずです。

Raspberry Pi にカメラを接続して画像を NAS に転送

画像認識のための Raspberry Pi セットアップもいよいよカメラ設置段階まで進みました。今回の目標は Raspi でデジタルカメラを動作させて、得られた画像データをネットワークHDD (NAS) に転送することです。

ストレージも USB ポート数も何もかもが不足している Raspi の弱点はネットワーク接続機器を使って補います。

カメラモジュール
一般的に Raspi でカメラと言えば、カメラモジュールを用います。私も「ちょっと珍しいから」という理由で赤外線カメラモジュールを購入しました。


Raspberry Pi Camera Module V2 カメラモジュール

後述する理由から一般的なカメラモジュールは購入を見送りましたが、赤外線カメラでも接続方法は変わるところはありません。

モジュールに繋がっているフレキシブルケーブル (FFC)を Raspi 回路基板のクリップに差し込めば接続完了です。

Raspberry Pi Zero W の場合にはモジュール付属ケーブルの形状が合いませんので、モジュールからフレキケーブルを引き抜いて、対応するケーブルに差し替える必要があります。

このケーブルは専用ケースの付属品になっていますので、ケースを購入すると一緒に入手できます。


Raspberry Pi Zero W公式シェル新品

このモジュールを接続した状態で、ターミナルから以下のコマンドを打ち込むと動作確認ができます。

$ raspistill -o ~/Desktop/cam.jpg

さらに画像の上下を反転させたり、ビデオやタイムラプスを撮影することも可能です。詳しくは公式のドキュメントに詳細が書いてあります。




WEBカメラ
カメラモジュールは簡単に使えて便利なのですが、私のそもそもの目的はコンベアベルトを作成することです。

この目的であれば、電子部品としては高額であまり入手性もよくない公式モジュールを使用しなくても十分な可能性があります。

また、モジュールに付属するフレキケーブル (FFC) やフレキ基盤 (FPC) も本音を言えば、あまり積極的に使いたい部品ではありません。繊細で壊れやすいためです。

市販品のデジタルカメラにも使用されている部品ですが、故障品を修理に出したときに補修部品としてよく見かける印象があります。

さらには学生時代にレンズスパナレンチを使ってオートフォーカスレンズを分解したときにも、自身で誤って破断させました。苦い経験です(※保証対象外になりますので真似しないでください)。

そこで、できればフレキケーブルは使用しておらず、複数個を調達することを考えて、もっと安価かつ入手性の良いカメラを探して行き着いた先が WEB カメラです。

こちらは USB ケーブルに Micro USB 変換コネクタを噛ませて Raspi の USB ポートに接続すれば、使用できるようになります。当然ながら Raspi 以外の普通の Linux デスクトップ PC でも問題なく使用できます。

使い方も lsusb コマンドで接続を確認、fswebcam コマンドで静止画キャプチャを作成、ffmpeg コマンドでビデオを録画といった具合に Linux マシンでいつもやっていることと変わりません。

$ lsusb
Bus 001 Device 002: ID 058f:6366 Alcor Micro Corp. Multi Flash Reader
Bus 001 Device 005: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

$ fswebcam -d /dev/video0 -r 1280x720 ~/Desktop/cam.jpg

$ ffmpeg -t 30 -f v4l2 -framerate 25 -i /dev/video0 ~/Desktop/output.mkv

これでファイル作成に成功していれば、画像認識用のプログラムからでも問題なく呼び出せるはずです。なんだか、こちらの方が使い慣れていて安心感がありますが、画質の面ではピクセル数 3280 × 2464 の SONY IMX219 を搭載した Raspi カメラモジュール(Camera Module v2) の方に利があります。


ロジクール ウェブカメラ C270n 国内正規品 2年保証

カメラから静止画像やビデオが取り込めるようになりましたら、次に問題になるのはストレージです。

画像認識の学習用データを自作しようと思ったら、どれだけ容量の大きなSDカードを用意したところで気休め程度にしかなりません。

むしろSDカードを補助記憶装置がわりに使用する Raspi の性質を考慮すると、学習データごときで容量を圧迫するのは「もったいない」とすら思えてきます。そこでデータの保存には無線接続されたハードディスク(NAS)をすることを考えます。

NAS(ネットワーク接続ストレージ)
一般的に市販されている NAS を購入してきて無線 LAN ルータやハブに接続すると、機器の内部ではローカル IP アドレスという 32bits のユニークな整数値が割り当てられます(※表示としては10進法に変換されて4桁ごとにドットで区切られたものが用いられます)。

このIPアドレスに同じネットワークに繋がっているパソコンやスマートフォンから接続すると、データを転送して保存したり、読み込んだりすることができるようになります。

Raspi を含む Linux マシンからローカル IP アドレスを調べるには、ずばりネットワーク自体のアドレスに対してホストスキャンをかければ一覧が表示されます。ネットワーク(※正確にはクラスCネットワークといいます)自体のアドレスは 192.168.1.0 に決まっているので対象の IP アドレスは 192.168.1.0 です。

$ sudo apt -y install nmap
$ sudo nmap -sn 192.168.1.0/24
[sudo] password for Goddard: 
Starting Nmap 7.60 ( https://nmap.org ) at 2019-08-31 13:04 JST
Nmap scan report for _gateway (192.168.1.1)
Host is up (0.00036s latency).
MAC Address: 00:00:00:00:00:00 (Mitsubishi Electric)
Nmap scan report for 192.168.1.3
Host is up (0.044s latency).
MAC Address: 00:00:00:00:00:00 (Sony Mobile Communications AB)
Nmap scan report for 192.168.1.6
Host is up (0.12s latency).
MAC Address: 00:00:00:00:00:00 (Asustek Computer)
Nmap scan report for 192.168.1.10
Host is up (0.11s latency).
MAC Address: 00:00:00:00:00:00 (Hon Hai Precision Ind.)
Nmap scan report for 192.168.1.11
Host is up (0.11s latency).
MAC Address: 00:00:00:00:00:00 (Raspberry Pi Foundation)
Nmap scan report for 192.168.1.13
Host is up (0.00024s latency).
MAC Address: 00:00:00:00:00:00 (I-O Data Device)
Nmap scan report for Ganymede (192.168.1.7)
Host is up.
Nmap done: 256 IP addresses (7 hosts up) scanned in 6.56 seconds

ここで私が使用している NAS は I-O DATA LAN DISK なので、目的のローカル IP アドレスは 192.168.1.13 と言うことがわかります。


I-O DATA NAS 4TB RAID 1/デュアルコアCPU/高速モデル/2ドライブ/日本製 3年保証

I-O DATA もしくは組み込み Linux と Samba で動いている NAS をお持ちの方は、試しにウェブブラウザから NASのローカルIPアドレス(私の場合では http://192.168.1.13/) にアクセスされると、そのまま設定画面にアクセスできちゃったりします。

この IP アドレスの SMB/CIFS ファイルシステムにある任意のディレクトリを Raspi にマウントしてしまえば、ターミナルやファイルシステムから自由にアクセスできるようになります。

ここではルート直下にある disk1 ディレクトリをマウントします。お使いの環境によっては share だったり Public だったりと言った別の名前がつけられているかもしれませんので、適宜改編してください。

$ sudo apt install cifs-utils
$ sudo mkdir /mnt/iodata && chmod 755 /mnt/iodata
$ sudo mount -t cifs //192.168.1.13/disk1 /mnt/iodata -o username=PI,password=RASPBERRY,iocharset=utf8

うまく実行できましたら、カメラから取得したデータを実際に保存してみます。うまく保存できていれば成功です。

$ sudo mkdir /mnt/iodata/raspberryPi/
$ sudo fswebcam -d /dev/video0 -r 1280x720 /mnt/iodata/cam.jpg

再起動時に毎回マウントすることが面倒であれば、あらかじめ設定しておけば起動時に自動的にマウントされます。

$ sudo vi /etc/fstab
//192.168.1.13/disk1 /mnt/iodata cifs username=PI,password=RASPBERRY,file_mode=0755,dir_mode=0755,iocharset=utf8,

これでようやくカメラを使って画像認識をはじめる準備が整いました。ここまで来て、ようやく学習データづくりとソフトウェアの着手に取り掛かれます。

まだまだ先は長いのです。