人間のあるべき姿の探索

思索・人形・エンジニアリング

PICO4でヘッドセットの姿勢を取得してロボットを動かす

Demo

youtu.be

前書き

以前から人形を動かしており、Androidから加速度センサの値を元に姿勢をトレースするアプリケーションを作っていたのですが、せっかくなのでHMDで作ることにしました。HMDを持っていなかったので試しにPICO4を買ってみたのですが、前評判で聞いていた通り全然情報が無かったので、少し苦労しました(VR開発歴が7日なのでご指摘等あればぜひお願いします)。

結論から述べると、Main Cameraの姿勢を取得します。解決法だけ興味のある方は下の方までスクロールしてください。

PICO4の開発方法

VRアプリケーションの開発では、OpenXRというVR/ARの標準規格があり、UnityのSDKが提供されている為、このSDKを使用してUnity上にカメラやPrefabを置いて開発ができます。その他に、Oculus QuestシリーズやPICOシリーズではそれぞれ専用のSDKが提供されており、機器ごとに機能やコントローラーのモデルが提供されています。

PICO4での開発の基本設定はこちらの記事が参考になりました。逆にこの方以外で情報を提供されている方がおらず、泣きながらSDKのリファレンスやGitHubのコードを見ていました。

qiita.com

また、PICOシリーズのUnityのSDKは古いバージョンがあり、そちらは2022年末でメンテナンスが終了しますよとの告知がされています。

developer-global.pico-interactive.com

ここまで調べたところで両バージョンのSDKのリファレンスを一通り確認したのですが、少し問題がありました。まず、古いSDKの方にはヘッドセットの姿勢を取得するメソッドがありました*1。一方で、新しいSDKのリファレンスを確認すると、Eye Tracker関連のクラスはあったのですが、全てのメソッドがPICO Neo2, Neo3用でPICO4非対応でした。Documentの更新漏れに期待してPXR_EyeTracking.GetPoseMatrixメソッドさえ使えればと思い試したところ、Unityのコンパイルは実機に依存しないため通りますが、実機でエラーを吐くのでダメでした。因みに、Oculus Questの方はそれらしい情報が出てきたので、枯れた技術を使った方がよいと思いました。

GitHubにサンプルコードが上がってないかと思ったのですが、旧バージョンのSDKを使用したサンプルがほとんどで、新バージョンの方でどうやって書けばよいか分からないものも多いです*2

というわけで路頭に迷いました。

解決法

XR Origin配下にあるMainCameraの姿勢取ればよいじゃん、というStack Over Flowの回答を見つけました。PICO4開発の際にSDKで提供されているXR OriginというPrefabを設置することでヘッドセットの移動に合わせてカメラが動くので、このカメラの姿勢を取得すればよかったんですね*3

というわけで以下Updateメソッドのようにカメラから姿勢を取得します。折角なのでDemoで見せたような姿勢の送信までの処理を載せておきますが、裏側を隠ぺいしているので疑似コードの気持ちで眺めてください。

GetPoseメソッドでは5自由度(yaw, pitch, rollの回転+左右, 前後の移動)のプロパティを格納するPoseModelにしています。回転角の計算式は少し調べると出てくる式で、Degreesで角度が取れます。また、移動距離の方がメートル単位で取れるので変換が簡単だったのは結構嬉しかったです。実際にヘッドセットを10cm前に動かすとposition[2](z軸)が0.10の値を返します。

あとはロボット側でヘッドセットの姿勢を受け取ったらその角度にロボットを動かすプログラムを走らせればヘッドセットの動きをトレースしてくれます。The Endってね。

完全な余談

ロボットの姿勢を扱うとき、cmで扱うかmで扱うか結構悩むことが多く、この辺りValueObjectでうまく扱えたらな…とか思いつつ、// cm単位とか書いていて対応しなきゃな…と思っています。その辺りのベストプラクティスを知りたいですね。

また、-180度と180度の境目を越えるときの処理がかなり面倒なので何とかしたいです。以前こういうものを見つけたので、多分その辺りを複素数で扱うとよしなにできそうなのですが、考慮できずにいます。

qiita.com

 

追記(2023/12/05)

 PoseModelとは何ぞや?とコメントを頂いたので説明。自作のエンティティで、今回使用したかった5自由度分の姿勢を定義しています。これらに対してしたい独自の計算などがあった為、できるだけプリミティブなクラス定義が必要だったわけですね。既存のロボットでサンプルコードもたくさんある場合はそちらのSDKに従った方が良いです、特にROS対応ロボットはかなり資産があるので肩に乗っかった方が圧倒的に楽です。

 yaw, pitch, rollはそれぞれ角度、side, frontはそれぞれ角度となりますが、値オブジェクトを用いて単位を揃えたりしています。

godiva-frappuccino.hatenablog.com

*1:ただ、内部で使用しているjarファイルが古いなどのエラーを吐くようで、旧バージョンのSDKは使えるか怪しい上メンテナンスされない予定なので使用をあきらめました

*2:僕もソースコードを公開してないので、はい。

*3:All you need is StacOverFlow.