3000円で作るGPSロガーシステム(M5Atom+GPSモジュール+クラウド完全無料枠)

2020年12月11日 金曜日


【この記事を書いた人】
北河 直樹

名古屋支社所属。新しい技術・怪しいデバイス・GISが好き。名古屋から影響力のある開発チームを作って発信していくのを目標としている

「3000円で作るGPSロガーシステム(M5Atom+GPSモジュール+クラウド完全無料枠)」のイメージ

IIJ 2020 TECHアドベントカレンダー 12/13(日)の記事です】

はじめに

早いもので気が付けば2020年も終わりですね。

今年は自宅で過ごすことも多く、今までとは違う時間の使い方をした方も多くいたのでは?と思います。

こんな時こそ、童心に戻ってお金をかけずに大人の工作を始めてみませんか?

ここではAtomicGPSを使ってGPSロガーとそれを可視化するツールを作ってみたいと思います。

AtomicGPSとは

M5Stack、M5Atomシリーズご存じですか?

5cm四方の小箱(M5Atomは2.5cm四方)に、ディスプレイ、Wi-Fi、Bluetooth、スピーカー、ボタンなどが装備されており、拡張モジュールを追加することで様々なセンサー情報を取得できるマイコンです。

特筆するのはその値段で兄貴分のM5Stackシリーズが約2000円~、M5Atomシリーズが約1000円~となります。お財布にやさしいですね!

AtomicGPSはM5Stackシリーズの弟分にあたるM5Atom向けのGPSモジュールになります。

工作の方針

  • とにかく安く!低コストで実現!
    • 初期投資3000円(M5Atom Lite + GPSモジュール)のみで、クラウドは完全無料枠を使います
    • 無料枠を超えたら課金されるクラウドサービスは対象外とします

作るもの

  • GNSS位置情報をリアルタイムで地図上に表示します
  • 過去訪れた場所をヒートマップで可視化します

こんな感じで可視化します

© OpenStreetMap contributors

システム構成

利用機材とサービス

デバイス以外、無料サービスを前提に選定しています。

デバイス

MQTTブローカー

  • 無料のMQTTブローカーサービス、shiftr.ioを使います

位置情報I/F

データベース

WEBブラウザ

  • Google Chromeで動作確認を行います

解説

事前準備

 

M5Atom + GPSを入手しよう

無料サービスに登録しよう ※別のサービスでも可

ソースコードを入手しよう

 

デバイス開発

  • 格納先
    • /m5atom-gps

ここでは以下の機能を実現します。

  • GNSSから位置情報の取得
  • Wi-FiでMQTTブローカーに位置情報をPublish
  • SDカードから端末設定情報を取得

M5Stack/Atomの開発はC/C++をベースにしたArduino言語で行います。

開発、デプロイはArduino IDEを使用します。

Wi-FiのAPやパスワードなどの設定情報をSDカードから取得するようにしています。

MQTTのトピック名とメッセージはMQTTブローカー設定の項目を参照してください。

ソースコード、導入手順は以下を参照してください。

m5atom-gpsの導入

 

MQTTブローカー設定

ここでは以下の機能を実現します。

  • デバイスから上がってきた位置情報をSubscriberへ配信

IoTではおなじみのみんな大好きMQTTです。ここでもGNSS位置情報をMQTTで送信します。

IoTデバイスの通信は、「AWS IoT コア」やGCPの「Cloud IoT Core」を使えばより簡単に大量デバイスの管理や通信ができますが、無料で実現したいのでshiftr.ioという無料MQTTブローカーサービスを使用します。

トピックは「m5atom/location」とします。

「m5atom」の部分をデバイスIDとしてデバイス毎に変更すれば複数端末にも対応出来るようにしています。

メッセージは、緯度、経度、高さ、GNSS受信時刻とします。

{
    "lat":"35.159965",
    "lon":"136.907106",
    "alt":"3.10",
    "gpstime":"2020-11-20T00:00:37.907Z"
}

 

位置情報I/F開発

  • 格納先
    • /insert-pubsub-mongo
    • /vector-tile-mongo

ここでは以下の機能を実現します。

  • insert-pubsub-mongo
    • MQTTブローカーから位置情報を取得してデータベースに保持
  • vector-tile-mongo
    • データベースから指定領域のベクトルタイルを返却するAPI

ともにNode.jsで開発します。

Oracle Cloud Free TierのIaaS上で実行します。

完全無料で、1/8 OCPUと1GBメモリが2台、10MbpsのLBが使えます。

 

insert-pubsub-mongo (MQTTブローカーから位置情報を取得する機能)

MQTTブローカーで設定したトピックを受信しデータベースに格納します。

ソースコード、および導入手順は以下を参照してください。

insert-pubsub-mongoの導入

 

vector-tile-mongo (ベクトルタイルを返却するAPI)

APIの入力パラメータにタイル座標を使用します。

タイル座標から領域を割り出し、GeoJSON形式のベクトルタイルを返却します。

ベクトルタイルを使えば情報量の多い地図データを広域から狭域まで扱えるようになります。

以下はタイル座標から矩形を求める計算です。

function tile2latlon(x, y, z){
    const mod = (a, b) => {
        return a * b < 0 ? a % b + b : a % b
    }
    
    const x2lon = (x,z) => {
        const lon = mod((x / Math.pow(2, z) * 360 ),  360) - 180
        return (lon != (-180) ? lon : 180)
    }

    const y2lat = (y,z) => {
        const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z)
        return 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))
    }

    const minlon = x2lon(x, z)
    const maxlon = x2lon(parseInt(x,10)+1, z)

    const minlat = y2lat(parseInt(y,10)+1,z)
    const maxlat = y2lat(parseInt(y,10),z)

    return { min: {lat: minlat, lon: minlon}, max: {lat: maxlat, lon: maxlon} }
}

タイル座標とは

Google Mapsの最大の功績は球面メルカトル図法(Webメルカトル図法)の発明でしょう。

南北86度程度以上を切る捨てることで正方形になることを利用し、4分割していくことでズームレベルとタイル座標で世界地図から詳細地図までをURLパスで表示可能としました。

この発明で今では当たり前なシームレスなWEB地図を実現したのです。

詳細は国土地理院の説明ページを参照してください

GeoJSONとは

JSONを用いたオープンな地理空間データフォーマットです。

地理空間データフォーマットは他にもWKT、KML、GML、Shapefileなどがありますが、GeoJSONはJavaScriptと相性が良いことからWEB地図ではよく使われる形式です。

ソースコード、導入手順は以下を参照してください。

vector-tile-mongoの導入

 

データベース設定

データベースは空間インデックスが利用できるMongoDBを利用します。

空間インデックスが扱えるデータベースはOracleDB、SQLServer、PostGISなどが有名ですが、サーバ運用込みで無料で利用したいのでMongoDB Atlasを利用します。

MongoDBはDocumentDBと呼ばれるNoSQLの一つです。GeoJSONを扱うことができ、空間インデックスを張ることができます。

MongoDB AtlasはそのMongoDBのSaaSで小容量ながら完全無料で利用することができます。

DB、コレクション名

DB名は「devices」、コレクション名は「locations」としています。

ドキュメントはデバイスID、GeoJSON、GNSS受信日時、更新日時です。

{
    _id: ObjectId(5fb6dd0c9018a66d7f27a3b7),
    deviceId: "m5atom",
    geometry: {
        type: "Point",
        coordinates: [ 136.883813, 35.171259, 2]
    },
    gpstime: "2020-11-19T21:00:58.803Z",
    uploadtime: "2020-11-19T21:00:59.095Z"
}

空間インデックスをgeometryに設定します。

devices.locations.createIndex( { geometry : "2dsphere" } )

フロントエンド開発

  • 格納先
    • /demo-viewer

ここでは以下の機能を実現します。

  • 最新のデバイスの位置情報をリアルタイム表示
  • 過去の位置情報をヒートマップで可視化

 

地図を容易に扱うことができるleaflet.jsを利用します。

leaflet.jsはオープンソースなJavaScriptのWeb地図ライブラリです。

Vueなどのフロントエンドフレームワークと組み合わせて作れば、非常に簡単でリッチなWeb地図が開発できます。

今回はシンプルに開発したいのでフレームワークを使わずにhtmlのみで実現します。

ベクトルタイル対応

leafletはラスタタイルは標準で対応していますが、ベクトルタイルには対応していませんので個別で実装が必要です。

標準で用意されているグリットレイヤを拡張して対応します。

タイルが呼び出されるイベントで該当タイルのベクトルタイルを取得してヒートマップを表示します。

ヒートマップではなく、GeoJSONレイヤを使えば地図として表示も可能です。

以下は実装例です。

L.gridLayer.GeoJson = function (opts) {
  return new L.GridLayer(opts)
}
L.gridLayer.GeoJson({
  maxZoom: 22,
  minZoom: 10,
  maxNativeZoom: 16
}).on('tileload', function (event) {
  // タイルロードのタイミングでGeoJsonベクトルタイルを取得してヒートマップを生成
  const url = "http://localhost:3000/api/geojson/{z}/{x}/{y}"
  fetch(L.Util.template(url, event.coords))
    .then(res => res.json())
    .then(geojson => {
      if (!geojson || geojson.features.length == 0) {
        return
      }

      const latlons = geojson.features.map((feature) => {
        return [feature.geometry.coordinates[1], feature.geometry.coordinates[0], 0.5]
      })

      // ヒートマップの生成
      event.tile.heat = L.heatLayer(latlons, {
        radius: 15,
        maxZoom: 18,
        minZoom: 10,
        blur: 15
      }).addTo(heatLayer)
    })
}).on("tileunload", function (event) {
  // タイルがリリースされるタイミングで該当のヒートマップレイヤを削除
  if (event.tile.heat && heatLayer) {
    heatLayer.removeLayer(event.tile.heat)
  }
}).addTo(map)

MQTT対応

リアルタイム表示はMQTTでメッセージを受信します。

こちらも標準ではMQTTに対応していませんので、何らかのレイヤに拡張して実現します。

レイヤが作成されたイベントでマーカーレイヤの追加とMQTTの受信設定をします。そしてメッセージを受信する度にマーカーを更新します。

 

ソースコード、詳細は以下を参照してください。

demo-viewerの詳細

デモ

名古屋周辺のサンプルデータ(※)を定期的に更新するデモです。

(※)テスト用に作成したデータです。実機で取得した値ではありません。

名古屋駅周辺デモ

最後に

今回はGPSキットを使ってGNSS位置情報をWEB地図に表示するサンプルを作ってみました。

M5Stack/Atomは低価格ではありますが非常に拡張性に優れ、次々と拡張キットが追加されています。

また、最近では手軽で且つ無料でサービスを実現出来る環境も整っており、エンジニアにとってはおいしい時代になったと感じています。

コロナ禍の中、自宅にいる時間も増えています。

是非この時間を有意義につかって、安く楽しく大人の工作を楽しんでみましょう!

IIJ Engineers blog読者プレゼントキャンペーン
  • Twitterフォロー&条件付きツイートで「IoT米」を抽選で20名にプレゼント!
    応募期間は2020/12/01~2020/12/31まで。詳細はこちらをご覧ください。
    今すぐツイートするならこちら→ フォローもお忘れなく!

北河 直樹

2020年12月11日 金曜日

名古屋支社所属。新しい技術・怪しいデバイス・GISが好き。名古屋から影響力のある開発チームを作って発信していくのを目標としている

Related
関連記事