スマホ姿勢・移動量を表示する myapplication の画面

myapplication – 姿勢+移動量をリアルタイム表示し、NDJSONをgzipしてAWSにバッチ送信するアプリ

スマホの姿勢センサ(加速度・ジャイロ・回転ベクトルなど)から 「姿勢+移動量」をリアルタイムで取得し、画面上に可視化しながら、 一定量たまったところで NDJSON を gzip 圧縮して API Gateway → Lambda → S3 → SageMaker へ送ることを想定したセンサロガーアプリです。

作品の説明

myapplication は、スマホを手軽な IMU(慣性計測ユニット)+ログ端末として使うためのアプリです。 回転ベクトルセンサから得られるクォータニオンや、加速度からの簡易的な移動量推定を 画面にリアルタイム表示しつつ、それらを 10〜60 秒ごとにまとめて NDJSON に変換し、 gzip で圧縮して AWS に送信します。

1 サンプルごとに HTTP を叩くのではなく、 「100 件たまったら送信」「30 秒ごとにバッチ送信」など柔軟な条件で センサログをバッチ化することで、ネットワーク帯域とバッテリーを節約しながら 後から SageMaker 等で学習・解析できるデータセットを作ることを目指しています。

  • ① センサ(姿勢・加速度)を一定周期でサンプリング
  • ② 画面上で「姿勢ベクトル+移動量」をリアルタイム描画
  • ③ 1サンプル1行の NDJSON フレームをメモリに貯め込む
  • ④ バッチ条件(件数・時間)を満たしたら NDJSON を gzip 圧縮
  • ⑤ API Gateway に対して gzip バイナリを POST
  • ⑥ Lambda が S3オブジェクトとして保存(日時+端末IDごと)
  • ⑦ 後から SageMaker / Notebook で可視化・学習に利用

システム概要

myapplication のAWS連携システム構成図

スマホはセンサをサンプリングしつつ、一定間隔で NDJSON を gzip 圧縮して API Gateway に送信します。Lambda が受け取ったバイナリを解凍・バリデーションしたうえで S3 バケットに保存し、その S3 を SageMaker や Athena、 あるいはローカル Jupyter Notebook から分析する想定です。

技術スタック

  • Android / Sensors: Kotlin, SensorManager, TYPE_ROTATION_VECTOR, TYPE_ACCELEROMETER
  • Networking: OkHttp / Retrofit(gzipバイナリPOST), Coroutines
  • Backend: AWS API Gateway, AWS Lambda, Amazon S3, Amazon SageMaker
  • Data Format: NDJSON (Newline Delimited JSON) + gzip

主要コンポーネント

  • SensorCollector: センサイベントを一定周期で受け取り、時刻付きサンプルに整形。
  • PoseEstimator: 回転ベクトルをクォータニオンに変換し、姿勢・オイラー角を計算。
  • NdjsonBuffer: 1サンプル1行の NDJSON 文字列を蓄え、バッチ条件で flush。
  • GzipUploader: NDJSON を gzip に圧縮し、API Gateway に POST する役割。
  • Lambda Handler: 受信した gzip バイナリを解凍し、S3キー名(deviceId/date)を付けて保存。

技術解説

SENSOR FUSION

姿勢(クォータニオン)+移動量のリアルタイム推定

TYPE_ROTATION_VECTOR から取得できる回転ベクトルを SensorManager.getRotationMatrixFromVector() 経由で 回転行列・クォータニオン・オイラー角に変換し、画面にリアルタイム描画しています。 加速度は重力成分を除去したうえで時間積分し、簡易的な「移動量」も算出します。

NDJSON 1行の例:
{"t": 1732170000, "qx": 0.1, "qy": 0.0, "qz": 0.0, "qw": 0.99,
 "ax": 0.01, "ay": -0.02, "az": 0.98, "dx": 0.05, "dy": 0.00, "dz": 0.00}
NDJSON BUFFER

1サンプル1行の NDJSON バッファを作る

センササンプルは、1 行 1 JSON オブジェクトの NDJSON として内部バッファに追記します。 こうしておくことで、後から Athena や Python で「1行1レコード」として扱いやすくなり、 ストリーム処理とも相性の良い形式になります。

擬似コード:
buffer.append(jsonString)
buffer.append('\n')
if (buffer.size >= THRESHOLD || elapsed >= MAX_WINDOW) {
  flushAndUpload(buffer)
}
GZIP UPLOAD

NDJSON → gzip で圧縮し、API Gateway にバイナリ POST

バッファが一定サイズに達したら、GZIPOutputStream で圧縮し、 Content-Encoding: gzip を付与して API Gateway に POST します。 これにより、数秒〜数十秒分のログでも通信量を数分の一に抑えられます。

擬似コード:
val gzipBytes = gzip(ndjsonBytes)
val request = Request.Builder()
  .url(endpoint)
  .post(RequestBody.create(MEDIA_TYPE_GZIP, gzipBytes))
  .addHeader("Content-Encoding", "gzip")
  .build()
S3 & SAGEMAKER

S3に蓄積し、SageMakerやNotebookからオフライン解析

Lambda では解凍後の NDJSON をそのまま S3 に保存する想定です。 オブジェクトキーに deviceId/date/hour などを含めておくことで、 SageMaker の Notebook から特定の走行・特定の実験だけを抽出し、 すぐに Python / Pandas / PyTorch で扱えるようにします。

実験・結果・課題

歩行・回転・停止のログ収集

スマホを手に持って歩いたり、止まった状態で回転したり、 カバンに入れて移動してみるなど、いくつかのパターンでログを収集しました。 その結果、クォータニオンと移動量の変化パターンから、 「どのタイミングで加速度の積分誤差が暴れ始めるか」が見えてきました。

リアルタイム姿勢・移動量表示画面
(a) リアルタイム描画画面
S3から読み込んだログのNotebook可視化
(b) S3ログをNotebookで可視化

現在の課題

・加速度積分による位置のドリフトが大きく、あくまで「移動量の目安」にとどまること ・センササンプリングレートとバッテリー消費のバランス ・回線状況が悪いときのアップロードリトライと、バッファの上限管理 など、長時間の運用に向けて解決したい課題が見えています。

位置推定はまだ簡易版 長時間運用時のバッテリー最適化

動画リンク

スマホを動かしながら姿勢・移動量がリアルタイムに変化し、 一定時間ごとに NDJSON gzip バッチが送信される様子を撮影したデモ動画です。

myapplication – センサログ取得&AWSバッチ送信デモ

まだできていない部分と今後

センサログ基盤として、他プロジェクトの土台に

myapplication は、単体のアプリというより、 今後の CanSat ローバーや EEG 実験、Rootine などのプロジェクトにまたがる 「センサログ収集基盤」として育てていくイメージを持っています。 ロガー部分と AWS 連携部分をうまくモジュール化できれば、 どのアプリからでも同じ形式でデータを集められるようになります。

  • 短期: ログフォーマットの固定(バージョニング)と、S3上でのパーティション設計。
  • 中期: 位置推定・歩行検出・姿勢クラスタリングなど、簡単な特徴量抽出を追加。
  • 長期: 専用ダッシュボードや可視化ツール(Web / Jupyter)との連携。

これからの改善点と開発計画

ログ品質・アップロード戦略・再利用性の3つの軸で改善していきます。

  • Quality: センサキャリブレーション・ドリフト補正・ノイズフィルタ。
  • Upload: ネットワーク状況に応じたバッチサイズの自動調整。
  • Reuse: ロガーをライブラリ化し、他アプリからも利用可能に。
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ログフォーマット・S3パーティション設計
センサドリフト補正・簡易特徴量の追加
ロガーライブラリ化・他アプリへの組み込み

このプロジェクトを通して

感じていること

スマホ単体でも、きちんとログを残す仕組みを作れば、 立派な実験プラットフォームになることを実感しました。 一方で、「その場で便利な表示」と「後から解析しやすいログフォーマット」を 同時に満たす設計は意外と難しく、何度か NDJSON の構造を作り直しています。

しかし、S3 に蓄積されたログを Notebook で眺めていると、 「この時はこう動いていたはずだ」という自分の記憶と、 センサの値が一致した瞬間に、小さな感動があります。 こうした「現実世界の動き」と「データ」が結びつく感覚を、 今後も大事にしていきたいです。

今の自分へのメモ

  • ・ログ形式は一度決めたら変更が重いので、早めに「最低限の完成形」を決めること。
  • ・可視化用のNotebookは、技育博などでもそのまま見せられるように整理しておくこと。

リファレンス & リンク

リファレンス

  • Android Developers – Sensors Overview / SensorManager
  • GZIP file format specification
  • NDJSON – Newline Delimited JSON
  • AWS API Gateway, Lambda, S3, SageMaker 公式ドキュメント

リンク