0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VIVE Ultimate Tracker を単体で動作させる (Windows 11/Python)

Last updated at Posted at 2025-12-07

VIVE Ultimate Tracker はお手軽な自己位置推定モジュールとして期待されていますが、2025/12/07現在、あまり情報はまとまっていません。そこで Windows 11で動作させる手順をまとめてみました。Pythonのopenvrライブラリを利用しています。なお Unity には依存していません。

動作の様子 https://x.com/ksasao/status/1997664729884496049

ポイント

  • SteamVR は ヘッドマウントディスプレイ(HMD)が存在することを前提としているため、HMDなしでは起動しません。そこで、設定を修正してHMDが無くてもSteamVRを起動するようにします

各種セットアップ

  1. https://store.steampowered.com/ より Steam をインストールする。
  2. https://store.steampowered.com/app/250820/SteamVR/ より SteamVR をインストールする。
  3. https://www.vive.com/jp/vive-hub/download/ より VIVE Hub をインストールする。インストールに失敗する場合には、テザリング回線を使うとなぜかインストールできる。
  4. ドングルとトラッカーをPCに接続する。これらはUSB-Cのコネクタだが、裏表を区別するようなので、うまくデバイスが認識されない場合には裏表を逆向きに刺す。
  5. VIVE Hub を起動し Settings > VIVE Ultimate Tracker を選択、 Pair tracker, Tracker setup を行う。これで絶対位置の原点を決めることができる。
  6. Ultimate Tracker のファームウェアアップデートが走るのでアップデートする(何回か実行した)。

Nullドライバ有効化

VIVE Hub, SteamVR, Steam を閉じて、下記のファイルを編集する

C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\null\resources\settings\default.vrsettings
をエディタで開き、それぞれの項目を以下のように修正

    "driver_null": {
        "enable": true,
        "loadPriority": -999,
        "serialNumber": "Null Serial Number",
        "modelNumber": "Null Model Number",

SteamVR の設定で HMD を必須にしない

C:\Program Files (x86)\Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings
をエディタで開き、それぞれの項目を以下のように修正


  "steamvr" : {
    "requireHmd": false,
    "forcedDriver": "null",
    "activateMultipleDrivers": true,

動作確認

  • Steam, SteamVR, VIVE Hub を起動する。HMDのセットアップを実行しようとするが無視でよい
  • 適当なフォルダを作成し、下記のコマンドで Python の仮想環境を作り、必要なライブラリをインストールする
python -m venv vive_env
vive_env\Scripts\activate
pip install openvr flask

下記のコードを作成し、実行

import time
import math
import openvr

def pose_to_pos_quat(m):
    # m は 3x4 の行列 (OpenVR HmdMatrix34_t)
    # 行列:
    # [ m[0][0] m[0][1] m[0][2] m[0][3] ]
    # [ m[1][0] m[1][1] m[1][2] m[1][3] ]
    # [ m[2][0] m[2][1] m[2][2] m[2][3] ]

    x = m[0][3]
    y = m[1][3]
    z = m[2][3]

    # 回転成分をクォータニオンに変換
    r00, r01, r02 = m[0][0], m[0][1], m[0][2]
    r10, r11, r12 = m[1][0], m[1][1], m[1][2]
    r20, r21, r22 = m[2][0], m[2][1], m[2][2]

    trace = r00 + r11 + r22
    if trace > 0:
        s = 0.5 / math.sqrt(trace + 1.0)
        w = 0.25 / s
        qx = (r21 - r12) * s
        qy = (r02 - r20) * s
        qz = (r10 - r01) * s
    elif r00 > r11 and r00 > r22:
        s = 2.0 * math.sqrt(1.0 + r00 - r11 - r22)
        w  = (r21 - r12) / s
        qx = 0.25 * s
        qy = (r01 + r10) / s
        qz = (r02 + r20) / s
    elif r11 > r22:
        s = 2.0 * math.sqrt(1.0 + r11 - r00 - r22)
        w  = (r02 - r20) / s
        qx = (r01 + r10) / s
        qy = 0.25 * s
        qz = (r12 + r21) / s
    else:
        s = 2.0 * math.sqrt(1.0 + r22 - r00 - r11)
        w  = (r10 - r01) / s
        qx = (r02 + r20) / s
        qy = (r12 + r21) / s
        qz = 0.25 * s

    return (x, y, z), (w, qx, qy, qz)

def main():
    openvr.init(openvr.VRApplication_Other)

    try:
        system = openvr.VRSystem()

        # 最大デバイス数
        max_devices = openvr.k_unMaxTrackedDeviceCount

        while True:
            # すべてのデバイスのPoseを取得
            poses = system.getDeviceToAbsoluteTrackingPose(
                openvr.TrackingUniverseStanding,
                0,  # 予測時間 (0: 現在)
                max_devices
            )

            for device_index in range(max_devices):
                pose = poses[device_index]
                if not pose.bDeviceIsConnected or not pose.bPoseIsValid:
                    continue

                device_class = system.getTrackedDeviceClass(device_index)

                # GenericTracker クラスのみを見る(Vive系トラッカー)
                if device_class == openvr.TrackedDeviceClass_GenericTracker:
                    m = pose.mDeviceToAbsoluteTracking
                    pos, quat = pose_to_pos_quat(m)

                    print(
                        f"idx={device_index} "
                        f"pos=({pos[0]:.2f}, {pos[1]:.2f}, {pos[2]:.2f}) "
                        f"quat=({quat[0]:.2f}, {quat[1]:.2f}, {quat[2]:.2f}, {quat[3]:.2f})"
                    )

            time.sleep(0.01)

    finally:
        openvr.shutdown()

if __name__ == "__main__":
    main()

注意点

  • SteamVRのバージョンアップなどがあると上記で編集した設定ファイルが上書きされてしまうことがあるので適宜修正する
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?