OculusGoでロボットを動かしたい
ROS#というライブラリ・ツールを使うと、UnityからROS (Robot Operating System)と通信することができます。
Unityが使えるならOculusGoでもできるのでは?と思って挑戦してみました。
次の3つのデバイスを使用します。
・OculusGo
・Unityを動かすWindows PC
・ROSを動かすLinux PC(Webカメラ付き)
1) UnityをセットアップしてOculusGoのサンプルを実行する
- Unityをインストール
- OculusGoの開発環境はUnity 2017.4.1等が推奨のようですが、深く考えずに2018.1.7をインストールしてしまったのでこのまま進めます。
https://developer.oculus.com/blog/everything-you-need-to-know-to-develop-for-oculus-go/
https://developer.oculus.com/documentation/unity/latest/concepts/unity-req/
- OculusGoの開発環境はUnity 2017.4.1等が推奨のようですが、深く考えずに2018.1.7をインストールしてしまったのでこのまま進めます。
- Android SDKとJDKをインストール
- OculusGoはAndroidベースなので、Android SDKとJDKが必要。
- Android SDKはAndroid Studioに付属しているので、以下のリンクからAndroid Studioダウンロード/インストール。
https://developer.android.com/studio/
- JDKは以下のリンクからダウンロード/インストール。
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
- OculusGoはAndroidベースなので、Android SDKとJDKが必要。
- PlatformをAndroidに変更
- File > Build Settingsを開き、Androidを選択してOpen load pageをクリック。
- UnitySetup-Android-Support-for-Editor-2018.1.7f1.exeをダウンロードして実行。
- File > Build Settings > Switch PlatformをクリックしてPlatformを変更。
- File > Build Settingsを開き、Androidを選択してOpen load pageをクリック。
- VRの設定
- Edit > Project Settings > Playerを選択。
- XR SettingsのVirtual Reality Supportedにチェック。
- Virtual Reality SDKsの欄にOculusを追加。
- Edit > Project Settings > Playerを選択。
- Oculus開発者に登録
- 以下のリンクからOrganizationを作成。
https://dashboard.oculus.com/
- スマホのOculusアプリから、設定 > その他設定 > 開発者モードをON。
USBケーブルをPCに接続してOculus Goを起動し、PCからのアクセスを許可。
- 以下のリンクからOrganizationを作成。
- サンプルをインポート
- OculusUtilities Unity packageをダウンロード。
https://developer.oculus.com/downloads/unity/
- 解凍して、packageファイルをAssetsフォルダにドラッグ&ドロップ。
Assets > Oculus > VR > Scenesで、GearVrControllerTestをダブルクリック。
- OculusUtilities Unity packageをダウンロード。
- Buildのための設定
- アプリのパッケージ名を設定。
Edit > Project Settings > Player > Other > Package Nameを、com.[CompanyName].[ProductName]の形で適当な組織名とプロダクト名に変更。
- APIレベルを設定。
Edit > Project Settings > Player > Other Settings > Identification > Minimum API Level > API Level 25
- Scripting Runtime Versionを設定。
Edit > Project Settings > Player > Other Settings > Configuration > Scripting Runtime Versionを.NET 4.x Equivalentに変更。
(後で試したところ、デフォルトの.NET 3.5 EquivalentだとROS#で受信ができなかったため)
- ビルドするシーンを選択。
File > Build Settings > Add Open Scenesをクリックし、現在のシーンをビルドの対象とする。
- アプリのパッケージ名を設定。
- 実行
- OculusGoをUSBでPCに接続した状態で、File > Build Settings > Build&Runをクリックする。ビルド完了後にOculusGoを起動するとすぐに実行される。
- もう一度実行するには、ライブラリ > 提供元不明 > リストの最後あたりに、7.で設定したパッケージ名があるのでそれを選択する。
- OculusGoをUSBでPCに接続した状態で、File > Build Settings > Build&Runをクリックする。ビルド完了後にOculusGoを起動するとすぐに実行される。
2) ROS#を使ってROSと通信する
- ROS#用の新しいSceneを作る
- File > New Sceneで新しいSceneを作成。
- Assetsフォルダ内にScenesフォルダを作成し、そこに現在のSceneを保存。
- HierarchyウィンドウからMain Cameraを削除。
- ProjectウィンドウからAssets/OculusGo/VR/Prefabsを開き、OVRCameraRigをHierarchyウィンドウにドラッグ&ドロップ。
- File > New Sceneで新しいSceneを作成。
- ROS#をインポート
- 以下のリンクから、RosSharp.unitypackageをダウンロード。
https://github.com/siemens/ros-sharp/releases - Assets > Import Package > Custom Packageから、先ほどダウンロードしたRosSharp.unitypackageを選択してインポートする。
- 以下のリンクから、RosSharp.unitypackageをダウンロード。
- RosConnectorの設定
- Hierarchyウィンドウで右クリック > Create EmptyでGameObjectを作成し、名前をRosConnectorに変更。
- RosConnectorのInspectorウインドウを開き、Assets/RosSharp/Scripts/RosCommunicationからRosConnectorをドラッグ&ドロップ
- RosBridgeServerUrlを設定。
ROS側のPCのURL(例:192.168.0.100)とポート番号(デフォルト:9090)をあわせて、"ws//192.168.0.100:9090"のように入力。
- Hierarchyウィンドウで右クリック > Create EmptyでGameObjectを作成し、名前をRosConnectorに変更。
- 準備と確認
- ROS側のPCの準備
- 以下のコマンドでROS側のPCにRosBridge Serverをインストール。
$ sudo apt-get install ros-<rosdistro>-rosbridge-server
http://wiki.ros.org/rosbridge_suite
- roscoreを立ち上げ、また別のターミナルで
$ roslaunch rosbridge_server rosbridge_websocket.launch
と入力し、RosBridge Serverを立ち上げる。
- 以下のコマンドでROS側のPCにRosBridge Serverをインストール。
- Unityの確認
- UnityのPCがROS側と同じネットワークにあることを確認。
- 画面上部のPlayボタンをクリック。
- ROS側のPCのターミナルに
Client connected
と表示されたら接続できている。
- ROS側のPCの準備
- OculusGoで実行
- 接続が上手くいかないと、OculusGoが入力を受け付けなくなって再起動が必要になる可能性があるので注意。
- OculusGoがROS側のPCと同じネットワークのWiFiに繋がっていることを確認。
- ROS側のPCでroscoreとRosBridgeServerを立ち上げる。
- OculusGoをUnity側のPCとUSBで繋げた状態で、UnityのFile > Build&Runを実行。
- ビルド完了後にOculusGoを起動し、ROS側のPCのターミナルに
Client connected
と表示されたら成功。
- 接続が上手くいかないと、OculusGoが入力を受け付けなくなって再起動が必要になる可能性があるので注意。
3) カメラ画像を受信する
- ImageReceiverの作成
- Hierarchyウィンドウで右クリック > 3D Object > Planeで平面を作成し、名前をImageReceiverに変更。
- InspectorウィンドウでPositionを(0, 0, 10)に、Rotationを(90, 0, 0)に、Scaleを(-1, -1, 0.75)に設定。
- ProjectウィンドウのAssets/RosSharp/Scripts/MessageHandlingからImageReceiverスクリプトを、ImageReceiverのInspectorウィンドウにドラッグ&ドロップ。
- RosConnectorの設定
- RosConnectorのInspectorウィンドウを開き、Assets/RosSharp/Scripts/RosCommunicationからSubscriberをドラッグ&ドロップ。
- SubscriberのTopicを”/cv_camera/image_raw/compressed”に設定。
- SubscriberのMessageReceiverにImageReceiverオブジェクトをドラッグ&ドロップ。
- ROS側のPCの設定
- Webカメラの映像をキャプチャして配信してくれるcv_cameraをインストール
$ sudo apt-get install ros-<rosdistro>-cv-camera
http://wiki.ros.org/cv_camera
- RosBridge Serverを立ち上げる。
- 以下のコマンドでcv_cameraを立ち上げることで、Webカメラの映像が/cv_camera/image_raw/compressedのTopicとして配信される。
$ rosrun cv_camera cv_camera_node
- Webカメラの映像をキャプチャして配信してくれるcv_cameraをインストール
- OculusGoで実行
4) OculusGoの姿勢にあわせてカメラ画像を動かす
- 初期方向を表すTargetオブジェクトを作成
- Hierarchyウィンドウで右クリック > Create EmptyでGameObjectを作成し、名前をTargetに変更。
- InspectorウィンドウでPositionを(0,0,10)に設定。
- Hierarchyウィンドウで右クリック > Create EmptyでGameObjectを作成し、名前をTargetに変更。
- 回転中心となるPlaneRotatorオブジェクトを作成
- Hierarchyウィンドウで右クリック > Create EmptyでGameObjectを作成し、名前をPlaneRotatorに変更。
- InspectorウィンドウでPositionを(0,0,0)に設定。
- HierarchyウィンドウでImageReceiverをPlaneRotatorの下層に配置。
- Hierarchyウィンドウで右クリック > Create EmptyでGameObjectを作成し、名前をPlaneRotatorに変更。
-
スクリプトを作成
- ProjectウィンドウでAssetsフォルダ内にScriptsフォルダを作成。
- Scriptsフォルダ内で右クリック > Create > C# Scriptでスクリプトを作成し、CamViewRotatorという名前に変更。
- CamViewRotatorを以下のように編集。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CamViewRotator : MonoBehaviour { public GameObject gameobject; // OculusGoの姿勢の参照用 public Transform target; // 初期方向の参照用 // Use this for initialization void Start () { } // Update is called once per frame void Update () { // PlaneRotatorを初期方向に向かせる transform.LookAt(target); // OculusGoの姿勢にあわせてPlaneRotatorを回転させる var trans = gameobject.transform; transform.Rotate(trans.eulerAngles.x, trans.eulerAngles.y, 0.0f, Space.World); // 2軸のpan-tiltカメラ用 // transform.Rotate(trans.eulerAngles.x, trans.eulerAngles.y, trans.eulerAngles.z, Space.World); // 3軸のpan-tilt-rollカメラ用 // OculusGoの位置にあわせてPlaneRotatorを移動させる transform.position = trans.position; } }
- ProjectウィンドウでAssetsフォルダ内にScriptsフォルダを作成。
-
PlaneRotatorの設定
- ProjectウィンドウのAssets/ScriptsからCamViewRotatorスクリプトを、PlaneRotatorのInspectorウィンドウにドラッグ&ドロップ。
- HierarchyウィンドウからOVRCameraRig/TrackingSpace/CenterEyeAnchorを、PlaneRotatorのInspectorウィンドウのGameobjectにドラッグ&ドロップ。
- HierarchyウィンドウからTargetを、PlaneRotatorのInspectorウィンドウのTargetにドラッグ&ドロップ。
- これでImageReceiverは常に画面中央に表示される。
5) OculusGoの姿勢を送信する
- PlaneRotatorの設定
- PlaneRotatorのInspectorウインドウを開き、Assets/RosSharp/Scripts/MessageHandlerからPoseProviderをドラッグ&ドロップ。
- Frame IdにUnityと入力
- PlaneRotatorのInspectorウインドウを開き、Assets/RosSharp/Scripts/MessageHandlerからPoseProviderをドラッグ&ドロップ。
- RosConnectorの設定
- RosConnectorのInspectorウインドウを開き、Assets/RosSharp/Scripts/RosCommunicationからUnityTimePubliserをドラッグ&ドロップ。
- RosConnectorのUnityTimePublisherのTopicに/cameraと入力し、Message ProviderにPlaneRotatorをドラッグ&ドロップ。
- TimeStepを適当に5と設定。
- RosConnectorのInspectorウインドウを開き、Assets/RosSharp/Scripts/RosCommunicationからUnityTimePubliserをドラッグ&ドロップ。
- 実行
おまけ
ROSを入れたRaspberryPi3を使って実際にロボットを動かしてみました。
クォータニオンをオイラー角に変換 → RosserialでArduinoに角度を送信 → Arduinoからサーボを制御