メインコンテンツまでスキップ

import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

VerseGrip Stylusの使い始め

VerseGripsは、Inverse3、Inverse3X、MinVerseに姿勢(オリエンテーション)トラッキング機能を追加します。本記事では、VerseGrip Stylusのセットアップ手順とその機能について説明します。

VerseGrip Stylusについて​

VerseGrip Stylusは、独自の高速ワイヤレス通信技術を使用して、姿勢トラッキングと手に持った状態での入出力(I/O)を提供します。さまざまなアプリケーションに対応できるよう設計されています。

主な機能は以下のとおりです:

  • ユーザー入力ボタン 2 個、
  • キャリブレーションボタン 1 個、
  • 電源/スタンバイボタン 1 個
  • ステータスLEDライト 2 個
  • USB-C充電ポート
  • 最大 1 KHz のワイヤレス通信速度
  • バッテリー駆動時間 10~12 時間
  • 1 つのバンドにつき最大 8 個のVerseGrip Stylusをドングルとペアリング可能

カスタマーサポート​

デバイスまたはその動作について質問や懸念がある場合は、サポートチームまでお問い合わせください。VerseGrip Stylusには複雑で独自のワイヤレス技術が組み込まれています。デバイスを開けると保証が無効になり、動作しなくなるおそれがあります。配送期間の長期化や高額な修理を避けるため、デバイスを開けないでください。

VerseGrip Stylusのセットアップとキャリブレーション​

本セクションでは、ドングルの接続、VerseGrip Stylusの電源オン、およびキャリブレーションの手順について説明します。

セットアップ​

  • ドングルをコンピューターのUSBポートに接続します。
  • ハンドルは動かない平らな面に置いてください。ボタンは上向きに、ボールコネクターは画面の方向に向けます。

電源オンとキャリブレーション​

  • 電源ボタンを 1 回押します。ステータスライトが赤色に点灯し、その後、デバイス内のIMUが自己キャリブレーション中であることを示すために黄色に変わります。
  • 自己キャリブレーションが完了すると、スタイラスがコンピューターに接続されます。
  • スタイラスが正常に接続され、ワイヤレスでデータを送信している状態になると、ステータスライトが緑色に点滅します。
  • バッテリー残量が極端に少ない場合、VerseGrip Stylusは 2 分ごとに自動的に電源が切れます。すぐに充電してください。

再キャリブレーション​

キャリブレーション処理によりVerseGripの座標系がリセットされ、キャリブレーション中にデバイスを保持していた方向が新しい基準軸になります。

  • 再キャリブレーションするには、再設定したい位置でスタイラスを保持し、キャリブレーションボタンを 3 秒間押し続けるか、シミュレーション内で姿勢が変化するまで押し続けます。

以下は、デバイスの動作をキャリブレーションされていない場合とキャリブレーション済みの場合で比較したデモです。デモでは、キャリブレーションを実行する前に、VerseGripを図に示す姿勢で保持しておく必要があります。

スタンバイと電源オフ​

  • 電源ボタンを 1 回押すと、スタンバイモードに戻ります。ステータスライトが白色で点滅し始め、データ送信が停止します。
  • VerseGrip Stylusの電源を切るには、電源ボタンを 5 秒間押し続けてから離します。離すとステータスライトが消灯し、何も表示されなくなります。データ送信も停止します。

充電​

  • VerseGrip StylusをUSB-C充電ポート経由で接続します。
  • 電源に接続している間は充電ステータスライトが青色に点灯し、完全に充電されると消灯します。
  • スタイラスがオフの状態で電源に接続すると、自動的にオンになります。

警告:2024 年 8 月から 12 月の間に出荷されたVerseGrip Stylusをお持ちの場合は、バッテリーを完全に放電させないでください。一度完全に放電すると、充電を保持できなくなる場合があります。 この場合でも、電源に接続したままであればVerseGrip Stylusは動作を続けます。この問題を修正するファームウェア更新ファイルを入手するには、Haplyサポートにお問い合わせください。

状態とライトインジケーター​

色ライトのシーケンス説明
黄色高速フェードイン/アウト初期自動センサー基準キャリブレーション(VerseGripを台の上に静止させてください)
高速点滅姿勢キャリブレーションボタンが押され、キャリブレーション処理が開始されました
点灯姿勢キャリブレーションボタンが押され、キャリブレーションが完了しました
赤高速フェードイン/アウトアダプターが切断され、ホストからの信号がありません
高速点滅電源ボタンが押され、シャットダウン処理が開始されました
緑フェードイン/アウトアダプターが接続され、VerseGripがアクティブなデータストリームモードです
点灯アダプターが接続され、VerseGripがアクティブなデータストリームモードで、USB電源も接続されています
白フェードイン/アウトアダプターが接続され、VerseGripがアイドル/スタンバイモードでデータストリーミングはありません
点灯アダプターが接続され、VerseGripがアイドル/スタンバイモードでデータストリーミングはなく、USB電源も接続されています
オレンジフラッシュ(インターレース)バッテリー残量低下の警告表示です。通知は現在の状態でインターレース表示されます
ダブルフラッシュ(インターレース)バッテリー残量が危険なほど低下したことを示す警告表示です。通知は現在の状態でインターレース表示されます
ティールフェードイン/アウトデバイスのファームウェア更新モードです
(明るい)点灯ユーザーボタンが押されました。現在の表示色は点灯し、より明るくなります
オフ消灯シャットダウン、電源オフ
充電インジケーターの色ライトのシーケンス説明
青点灯充電中
高速点滅充電完了間近
オフ消灯充電完了

旧バージョンの状態とライトインジケーター​

以下のステータスライトは、VerseGrip Stylusの旧バージョン(ファームウェア 1.10 以前)に見られた旧式の状態と色です。

色ライトのシーケンス説明
赤点灯コンポーネントの初期化待ち
点滅スタンバイモード。データ送信なし
青点灯初期自動センサー基準キャリブレーション(VerseGripを台の上に静止させてください)
緑点滅アダプターが接続され、VerseGripがアクティブなデータストリームモードです
オフ消灯シャットダウン、電源オフ
充電インジケーターの色ライトのシーケンス説明
青点灯充電中
高速点滅充電完了間近
オフ消灯充電完了

サンプルコード​

VerseGrip StylusをC++と組み合わせて使用する簡単な例を以下に示します。

#include <external/libhv.h>

#include <nlohmann/json.hpp>

#include <chrono>
#include <cstdio>
#include <string>

using namespace hv;
using json = nlohmann::json;

// Procedure to get the first detected and available Wired VerseGrip Stylus device id
std::string get_first_verse_grip_device_id(const json &data) {
const auto& vgs = data["wireless_verse_grip"];

if (vgs.empty()) {
return "";
}

return vgs.items().begin().key();
}

int main() {
const auto print_delay = std::chrono::milliseconds(100);
auto current = std::chrono::high_resolution_clock::now();
bool first_message = true;
std::string device_id;

WebSocketClient ws;

ws.onmessage = [&](const std::string &msg) {
json data = json::parse(msg);

if (first_message) {
first_message = false;
const std::string first_id = get_first_verse_grip_device_id(data);

if (first_id.empty()) {
printf("no Wireless VerseGrip found.\n");
ws.close();
return;
}

device_id = first_id;
}

if (device_id.empty() || !data["wireless_verse_grip"].contains(device_id)) {
return;
}

const auto now = std::chrono::high_resolution_clock::now();

if (std::chrono::high_resolution_clock::now() > current + print_delay) {
current = now;
const json state = data["wireless_verse_grip"][device_id];

printf("Rotation : { x:%f, y:%f, z:%f, w:%f }, Hall:%i, Button : [%d, %d, %d], Battery: {%f}\n",
state["orientation"]["x"].get<float>(),
state["orientation"]["y"].get<float>(),
state["orientation"]["z"].get<float>(),
state["orientation"]["w"].get<float>(),
state["hall"].get<int8_t>(),
state["buttons"]["a"].get<bool>(),
state["buttons"]["b"].get<bool>(),
state["buttons"]["c"].get<bool>(),
state["battery_level"].get<float>());
}
};

ws.open("ws://localhost:10000");

printf("Press ENTER to stop...\n\n");
while (std::cin.get() != '\n') {
}

if (ws.isConnected()) {
ws.close();
}

return 0;
}
#include <string.h>

#include <chrono>
#include <iostream>
#include <iterator>
#include <string>
#include <thread>

#include "HardwareAPI.h"

int main(int argc, char* argv[])
{
char* portName;

if (argc < 2)
{
std::printf("Usage: %s <port>\n", argv[0]);
}
else
{
#if defined(_WIN32) || defined(_WIN64)
portName = _strdup(argv[1]); // argv1;
#endif
#if defined(__linux__)
portName = strdup(argv[1]); // argv1;
#endif
}

Haply::HardwareAPI::IO::SerialStream serial_stream(portName);

Haply::HardwareAPI::Devices::Handle handle(&serial_stream);

while (true)
{
Haply::HardwareAPI::Devices::Handle::VersegripStatusResponse data;
data = handle.GetVersegripStatus();
std::printf(
"device_id: %d battery_level: %f quaternion: %f %f %f %f buttons: "
"%d error_flags: %d\n",
data.device_id, data.battery_level, data.quaternion[0],
data.quaternion[1], data.quaternion[2], data.quaternion[3],
data.buttons, data.error_flag);

}
}