KATVRをOculusに無線接続させる（Part1: Windowsアプリの開発）

# ごあいさつ
初めて投稿します。私立の医大で情報系教員をしています黄色い戌です。不定期ですが、研究で生まれてきたシステム（知財にはならないようなもの）を他のユーザーさんと共有して情報交換する目的でQiita始めました。UnityもC#も初心者です・・・公開した情報はガンガン活用していただいて大丈夫です！（寧ろ手直ししてくれたら教えてください）

---
# KATVRとは
KATVRとは、VR内で使用できる歩行型デバイスを開発している企業で、KATWALK（全方位トレッドミル）やKAT loco S（慣性式歩行センサ）などのデバイスが知られています。歩行センサとしては、非常に優秀なデバイスなのですが、なにぶん「対応しているアプリ・デバイスが少ない！！」というのが、非常にもったいないシステムです。
　特にデフォルトでは、PCVRのみの対応だったので、Stand aloneで動作するHMD（Meta Questとか）には対応していないなどの問題がありました。そこで、KATVRとHMDを無線接続して、VRアプリで動かすことができるシステムを開発してみました。但し、Oculus公式のアプリには非対応で、OSC（Open Sound Control）に対応しているアプリのみを動かせます。

https://katvr.jp/


---
# システム構成（センサの使い方は説明書を見てください）
システムの構成は非常に単純で、、、
1. KATVRシステムによる計測（今回は、KAT loco Sを対象としています）
2. KATSDKによるUnity Appへのデータの取り込み
3. OscJack（[OscJack](https://github.com/keijiro/OscJack "OscJack")）を利用した、Meta Quest2へのデータ転送です

KATSDKは、同社に利用申請することで、無償で使用することができます。但し、KATVR SDKは、Windowsのみの対応となっております。そのため、Meta Questで利用するのも、必ずWindowsのPCを間に挟んで使用する必要があります。今回の記事では、PCでKATVRで計測した速度・回転などのデータをOSCで送信するアプリまでを作っていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212402/b90007d5-51de-86dd-0c7a-41d34b81eb04.png)

---
# KATSDKの基本
## 1.KATSDKのインポート
KATVR社に利用申請することで、SDKのリンクを教えてもらえます。Unityフォルダ内の"KAT Universal SDK 0.99.unitypackage"というファイルがあるので、こちらをダウンロードし、Unity Editorで「Assets=>Import Package=>Custom Package...」により、プロジェクトのAssetフォルダにインポートします。

---
## 2. KATSDKの基本的な使い方
現在のところ、歩行に関するデータは、速度（Vector3型）と回転（Quaternion型）のみ取得できます。Assets/KAT/KATNativeSDK.csがKATVRからデータを取り出す際に使用するスクリプトです。下記のようなプログラムを適当なGameObjectにアタッチすることで、Consoleに速度とrotationを投げ込むことができるようになります。
```cs:KAT_basic_function.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KAT_basic_function : MonoBehaviour
{
    private Vector3 speed;
    private Quaternion rotation;
    void Start()
        {
        }
    void Update()
        {
            var data = KATNativeSDK.GetWalkStatus();//KATVRライブラリへのアクセス
            speed = data.moveSpeed;//歩行速度（x,y,z）の取得
            rotation = data.bodyRotationRaw;//回転（x,y,z,w）の取得
            Debug.Log("speed: "+ speed);
            Debug.Log("rotation: " + rotation);
        }
}
```
![console.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212402/3e0b87d8-371d-3872-822e-2873dcb35c85.gif)

簡単ですね。

---
## 3. KATVRでCubeを動かしてみよう
では実際にKATSDKを使用してCubeを動かしてみましょう。初めに、ヒエラルキーにCubeを追加して、scaleを(1，1，1)、positionとrotationは両方とも（0，0，0）に設定します。Main Cameraはposition (0,15,0)、rotation (90,0,0)に、つまりは真上からキューブを見るように設定してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212402/0f1cbbf9-92b6-3e99-ca23-01a9c61f79fa.png)

次に、以下のC#スクリプトをCubeにアタッチします。KATSDKでは３次元の速度を出力しますが、ポジションの出力はありません。そのため、Translateにより相対的な移動距離を算出する必要があります。
```cs:KAT_cube_move.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KAT_cube_move : MonoBehaviour
{
    private Vector3 speed;
    private Quaternion rotation; 
    void Start()
        {
        }
    void Update()
        {
            var data = KATNativeSDK.GetWalkStatus();//KATVRライブラリへのアクセス
            speed = data.moveSpeed;//歩行速度（x,y,z）の取得
            rotation = data.bodyRotationRaw;//回転（x,y,z,w）の取得
            this.transform.Translate(speed * Time.deltaTime, Space.Self);//移動
            this.transform.rotation = rotation;//回転
        }
}

```
![Cube_Move.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212402/a4dbe001-d9a6-69a7-557e-b124628b8a3d.gif)

これまた、簡単ですね。

---
## 4. KATVRで取得したデータをOSCで送信する
　それでは、無事にCubeが動いたところで、今回の記事のクライマックス、OSCでのデータ転送にトライします。OSCは、keijiroさんの[OscJack](https://github.com/keijiro/OscJack "OscJack")を利用します。

Edit=>Project settingからPackage Managerを選択して、Scoped Registriesに、Name：Keijiro、URL: https://registry.npmjs.com, Scopes: jp.keijiroを追加します。その後、package managerのmy registoriesからOscJackをインポートします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212402/74ff2c74-9c54-e7bb-7abe-7f46e76d1c8b.png)

先ほどのCubeに以下のスクリプトをアタッチしてみてください。このスクリプトは、Cubeの速度と回転、歩行判定、座標を/KAT/xxxというアドレスに0.025秒ごとに送信します。送信先はローカルホストにしていますので、WindowからOSC Monitorを選択して、Playボタンを押してみましょう。変数isWalkは、アニメーター用（アバターを使用する人向け）に作ったものです。各自の環境でPortは変えてください。

```cs:OSC_stream.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using OscJack;

public class OSC_stream : MonoBehaviour
{
    private Vector3 speed;//歩行速度
    private Quaternion rotation;//回転
    private float speed2;//歩行の速さ（絶対値）
    private int isWalk = 0;//0：停止、1:歩行、2：走行
    public int thr_walk_run = 8;//歩行とランニングの境界線
    [SerializeField] string ipAddress = "127.0.0.1";//送信先のIPアドレス
    [SerializeField] int port = 9000;//Port番号
    OscClient client;//Clientの変数宣言
    [SerializeField] float sendInterval = 0.025f;// OSCメッセージの送信間隔（秒）
    private float lastSendTime = 0f;

    void Start()
    {
        client = new OscClient(ipAddress, port);//Clientの起動
    }

    void OnDestroy()
    {
        client.Dispose();//Clientの停止
    }


    void Update()
    {
        var data = KATNativeSDK.GetWalkStatus();//KATVRライブラリへのアクセス
        speed = data.moveSpeed;//歩行速度（x,y,z）の取得
        rotation = data.bodyRotationRaw;//回転（x,y,z,w）の取得
        this.transform.Translate(speed * Time.deltaTime, Space.Self);//移動
        this.transform.rotation = rotation;//回転
        speed2 = speed.magnitude;//速さの絶対量
        if (speed2 > 0)
        {
            if (speed2 >= thr_walk_run)//速さが閾値を超えた場合
            {
                isWalk = 2;//走行
            }
            else
            {
                isWalk = 1;//歩行
            }
        }
        else
        {
            isWalk = 0;//停止
        }
        // 一定間隔でOSCメッセージを送信する
        if (Time.time - lastSendTime >= sendInterval)
        {
            client.Send("/KATVR/position", this.transform.position.x, this.transform.position.y, this.transform.position.z);
            client.Send("/KATVR/rotation", this.transform.rotation.x, this.transform.rotation.y, this.transform.rotation.z, this.transform.rotation.w);
            client.Send("/KATVR/status", isWalk);
            client.Send("/KATVR/speed", speed.x, speed.y, speed.z);
            lastSendTime = Time.time;
        }
    }
}


```
![OSC1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3212402/01586218-7dbd-4038-5b1b-0ca2f2b5ebbd.gif)

移動と同時に、データがモニターに表示されますね。例えば、IPアドレスを同じネットワークに接続しているOculusやスマホに設定すれば、KATVRをケーブルなしで、各デバイスで使用できるようになります。動作未確認ですが、このコードは、KAT Walk C2でも使用可能です。そのうち、動作確認をしてみようと思います。

今回の記事は、ここまでで、次回にMeta Quest2で接続できるようなアプリを作っていきます。