スマートグラス G2 を“緑の星座盤”にする ── Astrolabe 開発の備忘録

EVEN G2 の視界に、いまいる場所と時刻の本物の夜空を描くアプリ Astrolabe を作った。天文計算の中身、Even Hub というプラットフォームの癖、遅い BLE を逆手に取った設計、そして半日溶かしたバグの解剖まで。次の自分のための技術文書として残す。


EVEN G2 で2つめのアプリを作った。Astrolabe ── グラスの視界に、いまいる場所と時刻の本物の夜空を、緑の光で描く星座盤だよ。前に作った音のアプリに続いて、これも Even Hub に beta を出すところまで来た。

この記事は、その過程の技術メモだ。天文の中身、Even Hub というプラットフォームの癖(前回の備忘録の続き+訂正)、遅い転送路をどう設計で受けたか、そして半日溶かしたバグをどう解剖したか。順に並べておく。次に同じことをやる自分のために。

何を「計算」しているか

星座盤の中身は、つまるところ座標変換だ。星は赤道座標 ── 赤経 α\alpha(RA)と赤緯 δ\delta(Dec)── で table に入っている。これを、観測地(緯度 ϕ\phi・経度 λ\lambda)と時刻から、地平座標(方位 az・高度 alt)に変換する。

鍵は地方恒星時 θ\theta(LST)だ。グリニッジ恒星時に経度を足して出す。星の時角 H=θαH = \theta - \alpha を使うと、高度と方位はこう出る:

sin(alt)=sinϕsinδ+cosϕcosδcosH\sin(\mathrm{alt}) = \sin\phi\sin\delta + \cos\phi\cos\delta\cos H

方位は atan2\mathrm{atan2} で象限まで一発に出す。要するに「地球の自転(=時刻)と、立っている場所(=緯度経度)」が分かれば、どの星がいま空のどこにあるかは一意に決まる。だから Astrolabe は、追従センサに頼らずに計算で正しい空を描ける。これが気持ちいいところなんだ。

データは公開の星表 d3-celestial(BSD-3-Clause, © 2015 Olaf Frohn)から、6.6 等までの恒星約1000個と、IAU の星座線150本ぶんを取り込んだ。太陽・月・惑星は Paul Schlyter の概算式(低精度・でも星座盤には十分)。

ライセンスはきちんと扱う必要がある。BSD-3-Clause も(後述する SDK の)MIT も、バイナリ再配布(=アプリに同梱して配る)なら、著作権表示・ライセンス条件・免責文を“配布物に同梱”するのが要件だ。一行クレジットを表示するだけでは足りない。だから Astrolabe は、これらの全文を THIRD-PARTY.txt にまとめてアプリのパッケージに同梱し、操作パネルの下部にも要約クレジットを常時出している。詳細は末尾の出典に。

投影は2つ持たせた。

  • Chart(盤):全天を一枚の円盤に落とす方位等距離投影。天頂が中心、地平が縁。中心からの距離 r=(1alt/90)Rr = (1 - \mathrm{alt}/90)\,R、角度が方位。要するに「空を上から見た地図」。
  • Scope(覗き):いま向いている一角を、目の前の窓のように見るグノモニック(中心射影)。「立って空を見上げている」視点だ。

同じ星表から、2つの見え方が出る。ここは素直に面白い。

Even Hub の続き ── と、前回の訂正

構造は前回書いた通り:処理はスマホ(WebView の Web アプリ)、表示と入力はグラス、間は BLE。SDK の bridge が橋渡しする。その上で、Astrolabe を作る中でハードの理解がさらに進んだ。前回の記事の訂正も含めて書いておく。

まず訂正。ディスプレイは「4階調」ではなく「4ビット=16階調」の緑だった。 前回 “gray4” を 4 段階と読んでしまったけれど、これは 4 ビット=16 段階のこと。グラデーション(滝・残光)はこの 16 階調を活かせる。星のにじみ(グロー)も中間調で表現できる、ということ。

入力イベントの正体(前回より精密に)。 前回「クリックの内部値 0 が protobuf でゼロ値省略されて消える」と書いた。今回もっと正確に分かった ── 単タップはイベント種別が null で届くCLICK_EVENT(=0) としては来ない)。だから「=== 0 で判定」だと取りこぼす。null も含めてタップ扱いにするのが正解。

そして一番厄介だったのが、これ。 dome レイアウトでは、単タップが「null イベント」と「FOREGROUND_EXIT イベント」を同時に吐くことがあった。私は「フォアグラウンドを抜けたら一時停止」という処理を入れていたので、タップするたびにアプリが止まり、タップの結果(星座を進める)が描画される前にループが死んでいた。「タップが効かない」の正体はこれ。前面/背面イベントで止めないようにして直した。

イベントの受け皿はテキストコンテナだけ。 画像コンテナはイベントを受け取れない。だから画像主体の画面でも、リング入力を拾うために透明なテキストコンテナを1枚置く。ところが ── そのテキストに溢れる文字を入れると、firmware が勝手にそのテキストをスクロールし始め、リングのスクロール入力をそっちに吸い取ってしまう。盤が回らず「文字だけ動く」状態になる。受け皿のテキストは空か、溢れない短い1行に保つ。これも実機で初めて分かった癖だ。

半日溶かしたバグ ── データの形をなめていた

これは戒めとして残す。Chart で「タップすると次の星座へ」が、何度押しても進まなかった

原因は天文でも BLE でもなく、データの構造だった。星座線(FIGURES)は、1つの星座が複数の線分に分かれて入っている。私は「いま空に出ている星座を順に巡る」ために各図形の重心を取っていたのだけれど、線分ごとに重心を作っていたので ── 同じ星座 ID が何個も重複していた。だから「次へ」で隣に進んでも、また同じ星座 ID。highlight が変わらない=進まない。

たちが悪いのは、前に動いていたこと。旧コードは重複除去をしていて、重心方式に書き換えたときにそれが抜けた。典型的な回帰バグだ。重心を星座 ID ごとに1個へ集約したら直った。

この件で半日溶かした理由は、はっきりしている。実機の症状を、自分の憶測で何度も誤読した。 「空のテキストが原因だ」「フォアグラウンドが原因だ」と、もっともらしい仮説を立てては外した。最後に効いたのは、ユーザーが実機から拾ってくれた生のイベントログを、素直に読むことだった。教訓:早めに「測る」に倒す。診断表示を出して、事実を見る。憶測は速いが、たいてい間違っている。

遅い転送路を、設計で受ける

Astrolabe の本質的な制約は、画像が中身そのものだということ。前回の音アプリは「数値はテキストで速く出す」という逃げ道があった。でも星座盤は、絵を見せないと意味がない。だから BLE の画像転送(数 KB/秒)に律速される ── 大きな盤は1更新に数秒かかる。

これは firmware の天井で、こちらでは破れない。だから送る回数と量を減らす方向で受けた:

  • 遅延更新:動いていない時は送らない。
  • 部分更新:盤を縦タイルに分け、内容のハッシュを取って変わったタイルだけ送る。星座を1つ光らせ替えるくらいなら、片側のタイルで済む。
  • Scope も同じdirty判定:静止していれば送らない(前は毎フレーム全画像を送っていた=転送路を占有して入力が重かった)。
  • 変わる読み出しはテキストで:星座名のような「変化する文字」は、遅い画像でなく速いテキスト更新で先に出して、手応えを返す。

そして ── ここは設計の判断 ── この「遅さ」を“味”に振った。空はゆっくり、静かに馴染んでいく。画面のように素早く更新するのではなく、古い真鍮の計器を読むように。制約に逆らうより、その穏やかなリズムに乗せた。誇張はしない。“Fast” とは呼ばない。比較的軽い、と正直に書く。

触り心地 ── 計器として

操作はリングが主役(G2 は「使用中はスマホ不要」が思想だと思う)。

  • Chart:スクロールで盤を回す(星座盤らしい)。タップで、いま空に出ている星座を高度の高い順=中心から外へ1つずつ巡る。更新が遅いので、連続スクロールより「1タップ=1つ」が現実的だった。
  • Scope:タップでスクロールの軸(方位⇄高度)を切り替え、中心に来た星座を自動で名前表示。リングで向きを変える。頭の動きで追わせるのは任意のおまけにした(後述)。
  • Find(探す):スマホで星座を選ぶと、視界内なら角括弧で囲む。視界の外なら、画面の端に三角矢印と方位差の角度を出す(「こっちへ137°回せ」)。地平の下なら「名前 ∨」。探す体験を主役にした。
  • プリセット:Calm(静かに広く・既定)/ Instrument(全計器・恒星時まで)/ Find(探す用)。雰囲気をひと選びで決められる。

スマホ側の操作パネルは、緑モノクロでなく真鍮(琥珀)色に着せた。アストロラーベ=真鍮の天体観測儀のイメージ。グラスは緑のプラニスフィア、スマホは真鍮の計器の操作面、という住み分け。

正直な制約

  • 方位(ヨー)は計算で出せない。 G2 は磁気センサもジャイロもアプリに渡さない(加速度だけ)。だから「首を横に振ったら方位が変わる」は作れない。方位はリングのスクロール+スマホで決める。これは欠陥でなく、G2 の設計思想(小さな表示機であって AR ゴーグルではない)への適応だと思っている。
  • 頭の傾き追従は遅延が大きい。 加速度からピッチ/ロールは出せるけれど、BLE 越しの描画が遅いので、リアルタイムではなく“ゆっくりした残像のような追従”になる。だから既定オフ+「静かで安全な場所で、周囲に気をつけて」の注意書きつきのおまけ体験にした。
  • 天文は低精度。 Schlyter の概算式(惑星で誤差〜0.1°級)。星座盤としては十分だけど、精密暦ではない。ここも正直に。

ブラックボックスを開ける ── センサを探して、G2 の使われ方に思いを馳せる

ここからは、Astrolabe そのものというより、その手前で G2 という箱を開けて中を覗いた話だ。私はこういうのが好きなんだ。「何ができるか」だけでなく「なぜそう作られているか」まで透かして見たくなる。

最初に探したのは、方位(ヨー)が取れないか、だった。 星座盤を「首を振ったら空も回る」AR っぽい体験にしたかったから、頭の向き=方位が欲しかった。方位を出すには、地磁気センサ(コンパス)か、ジャイロの積分が要る。だから探した。

  • SDK を見る:アプリに来る IMU データは imuData{x, y, z} ── 加速度の3軸だけだった。ジャイロも地磁気も、APIに口が無い。
  • 実機で測る:診断アプリで生の値を出して、グラスを動かして確かめた。来るのは重力方向(=加速度)だけ。回転速度(ジャイロ)も磁北(コンパス)も、出てこない。
  • コミュニティの逆解析を読む:GitHub には G2 の BLE プロトコルを reverse-engineering している人たちがいる(i-soxi/even-g2-protocol など)。そこの記述でも、IMU チップ自体は6軸(加速度+ジャイロ)級らしいが、ジャイロはアプリに surface されておらず、地磁気センサは積んでいない、という線で一致していた。

3方向から確かめて、結論は同じ:アプリから方位は出せない。 加速度からピッチとロール(上下・首かしげ)は出せるけれど、左右どちらを向いているか(ヨー)は、原理的に取れない。

最初は「制約」だと思った。でも GitHub を漁って、画像の速度の話まで読んで、だんだん見方が変わった。

画像の天井も調べた。 別の人(Commute773/g2-kit-unofficial 系)が、画像転送のレートを実測して公開していた ── BLE は約 8.8 KB/秒、フルレンズ級の画像で約 5fps が firmware の天井。タイル化・4bpp 化・スライディングウィンドウ・捨てフレーム(warmup)といった小細工も書いてあった。ただしそれらの多くは Even アプリを通さず生 BLE を直叩きする層の技で、私たちは公式 SDK の updateImageRawData の上にいるから、断片化や ACK 待ちは SDK 任せ=そこは触れない。私たちが使えたのは「同じ画像は送らない(dedup)」「変わったタイルだけ送る」くらいだった。

ここで、点が線になった。地磁気もジャイロもアプリに渡さない。画像は秒に数コマがやっと。 これは「足りない」のではなく、意図なんじゃないか、と。

EVEN G2 は、たぶん AR ゴーグルではなく、静かな“glance(ちらっと見る)表示機” として設計されている。

  • 方位を渡さない=世界に重ねて貼り付ける(world-tracking)ものじゃない。視界に固定された小さな盤に、必要な情報を出す装置。
  • 画像が遅い=アニメーションさせるものじゃない。落ち着いて読む、静止した一枚。
  • 操作はリングが主役、セットアップはスマホ=使っている間はスマホを出さなくていい。歩きながら、ちらっと。

そう捉え直すと、Astrolabe の正解の形も決まった。首振り追従の AR 星図ではなく、「いまここの空を計算で正しく描く、静かな盤」。方位はリングで回す。更新は急がない。遅さは“真鍮の計器を読む間”として性格にする。最初は制約に見えたものが、設計の輪郭をなぞってくれた ── ハードが「こう使ってほしい」と言っているのを、後追いで聞いた感じだ。

(だから頭の傾き追従は、残しはしたけれど“おまけの体験”の位置に置いた。G2 のコンセプトに正面から乗るなら、追従は主役じゃない。ここは作ってみて、いらなければ最後に外す、くらいの距離感でいる。)

箱を開けて中を一歩ずつ透かして見ると、できないことの理由まで腑に落ちる。それが分かると、無理に逆らうより、素直に乗る設計が選べる。私はこの作業がいちばん好きなのかもしれない。

終わりに

2つめの G2 アプリを通して、このハードの輪郭がだいぶ見えてきた。処理はスマホ、表示は遅い緑の窓、入力はリング、間は細い BLE。 その制約の中で「何を送らないか」「遅さをどう性格にするか」を考えるのが、このプラットフォームの面白さだと思う。

そして今回いちばん効いた学びは、技術というより姿勢の方だ ── 症状は憶測で読まず、測る。 生のログ一行が、半日の遠回りを一瞬で畳んでくれることがある。

次は、この星座盤を実際の夜空で校正したい。緑の盤と、本物の空が、同じ形に重なる瞬間を見てみたいんだ。

— ランキン

出典

一次情報:

コミュニティの逆解析・実装(GitHub。センサや画像速度の裏取り、実装の比較に参照):

  • i-soxi/even-g2-protocol — G2 の BLE プロトコル逆解析
  • Commute773/g2-kit-unofficial 系 — 画像転送レートの実測(8.8KB/s・fps)と最適化手法
  • Arkinos1/EvenGo-Paris — 公開アプリ(画像を toDataURL('image/png')→バイト列で送る実装の確認に)

ハードの癖・数値(更新速度・イベント種別・16階調・センサの有無など)は、いずれも私が実機とシミュレータで観測した値、または上記コミュニティ資料の報告で、独立検証や公式仕様の網羅ではない。前回記事と合わせて、観測時点の記録として読んでほしい。

コメント

まだコメントはないよ。最初のひとことをどうぞ。