iPhoneの位置情報をsocket.ioでリアルタイムにGoogle Mapに表示する

前エントリ iPhoneとsocket.ioサーバを常時接続。その時バッテリは? からの続きです。
今回はiPhone側で取得した位置情報をsocket.io経由でnodejs側へ流してgoogle mapで表示というサンプルアプリを作ってみました。

実現するために必要な主要機能は以下となります。

  • iPhone側で位置情報を取得してsocket.ioに流す
  • node側(socket.io)側では受信した位置情報をDBに格納しつつブロードキャスト
  • node側(web UI)側では受信した位置情報をgoogle mapに表示する

f:id:growthfield:20120226074449p:plain

構成要素

サーバ

Z Clould上のnodejsMVCフレームワークであるMatadorとリアルタイムな双方向通信のためにsocket.ioを利用します。
DBにはMongoDBを使用し、node側からはMongooseを利用してアクセスします。

iPhoneクライアント

iPhone4端末にネイティブのクライアントアプリにNNSocketIOを組み込んで利用します。
アプリはvoipかつlocation型として登録しバックグラウンドでも位置を測定しつつsocket.ioでサーバへ送信できるようにします。

WEB UI

BootstrapjQueryGoogle Maps JavaScript APIを使用します。

機能

マップ表示

Google Map上にiPhoneと現在位置と過去6時間の移動経路を表示します。
これらの情報はリアルタイムに反映します。
現在位置はマーカー、移動経路は青い線によって示されます。
f:id:growthfield:20120226111501p:plain赤いマーカーはiPhone側がオンライン状態
f:id:growthfield:20120226111610p:plain灰色のマーカーはオフライン状態
を表します。

f:id:growthfield:20120226094421p:plain

iPhone側では標準位置情報サービスを使用して現在位置を要求精度「kCLLocationAccuracyBestForNavigation」で取得し、位置が20メートル以上変化したらサーバへ送信するようにしています。なので上図のように小道では移動経路が若干カクカクになります。
閾値を5メートル程度にすると移動経路はいい感じになりますが、その分送信データが増えるためバッテリの消耗が激しくなってしまいます。

ちなみに自分が試した限り屋外では概ね誤差+-20メートル以下の精度で位置情報が得られました。また建物内や地下鉄などでは誤差が大きくなりました。(+-150メートル以上)
標準位置情報サービスはGPSだけではなくWiFiスポット、携帯基地局なども併用して位置を求めるためか、地下鉄でも駅構内ならばそれなりに位置を測定できます。

ストリートビュー表示

マップ表示は地味でいまいちリアルタイム性を体感できなかったので、iPhoneの磁力センサーから取得した方位角をストリートビューにリアルタイム反映させてみました。

f:id:growthfield:20120226102827p:plain

スクリーンショットでは全く分からないですがiPhoneの向きに応じてストリートビューが360度ぐりぐりと動きます。

DEMO

作成したサンプルアプリケーションは数日間以下に公開します。
chromesafariで動作確認しています。
http://node.growthfield.jp:8080

デモを公開しておいてなんですが、最近自分の行動範囲は自宅と会社の往復でかつ地下鉄多用なので退屈なデータしか表示されないと思います。
デモ終了しました。

ソースコードは以下にあります。

課題的なもの

取得した位置情報の精査

iPhone側では測定した位置を使用するかどうかのフィルタ処理が重要になります。
精度が高いデータしか使用しないようにすると地下鉄などでは位置が記録されなくなってしまいますし、逆に精度の低いデータを使用するとマップ上の移動経路が拡散してしまいます。
そこで今回は誤差が+-20メートル以下の場合は即利用し、この精度のデータが取得できない場合は15秒間隔で取得したデータの内もっとも精度が高いものを利用するようにしてみました。なにもしないよりは多少マシですが、もっと良い精査アルゴリズムを適用したいところです。

また取得したデータ上高精度となっていても実際には誤差以上かけ離れた場所を指し、測定位置が転々とする場合もあるので、一カ所に留まっていてもマップ上ではあたりを徘徊しているように表示されることがあります。

バッテリ

分かっていた事ではありますが、socket.io常時接続とGPS併用という二重苦で一時間あたり7〜8%を消費します。移動している時間帯はある程度消費するのは仕方ないのですが、職場や自宅など一定箇所に長く留まる際にはこの消費はキツイですね。
実際に試してはいないのですが、もし標準位置情報サービスより領域観測サービスの方が低電力で動作するのであれば移動量が極めて小さく一定箇所に留まっている状態を検出したらその領域に領域観測サービスをかけて標準位置情報サービスをオフ、領域外に出たら再度標準位置情報サービスをオンにするなんて対策もあるかもしれません。
またEnergy diagnosticsをかけつつ丁寧に最適化を試みるというのも面白そうではありますが、低電力動作の追求は今回の勉強の趣旨から外れてしまうのでまたの機会に。