import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';
VerseGrip スタイラスの使い始め
VerseGripsは、Inverse3 、Inverse3X、およびMinVerseに方向追跡機能を追加します。このドキュメントでは、VerseGrip Stylusの設定手順と機能について説明します。
VerseGrip スタイラスのご紹介
VerseGrip Stylusは、方向追跡機能と、手に持った状態での入出力(I/O)を実現するために、独自の高速無線通信技術を採用しています。さまざまな用途で幅広く活用できるよう設計されています。
主な機能は以下の通りです:
- ユーザー入力用ボタン2つ、
- キャリブレーションボタン 1個、
- 電源/スタンバイボタン 1個
- ステータスLEDインジケーター2個
- USB-C充電ポート
- 最大1 kHzの無線通信速度
- バッテリー駆動時間 10~12時間
- 1つのバンドにつき、1つのドングルに最大8組のVerseGrip Stylusをペアリング可能

カスタマーサポート
本製品やその操作についてご質問やご不明な点がございましたら、サポートチームまでお問い合わせください。VerseGrip Stylusの内部には、複雑で独自の無線技術が搭載されています。本製品を開封すると、保証が無効となり、動作しなくなる可能性があります。配送期間の長期化や高額な修理費用を避けるため、絶対に本製品を開封しないでください。
VerseGrip スタイラスの設定とキャリブレーション
このセクションでは、ドングルの接続、VerseGrip Stylusの電源投入、およびキャリブレーションの手順について説明します。
設定
- ドングルをコンピュータのUSBポートに接続してください。
- ハンドルを動かさないように、平らな面に置いてください。ボタンが上向きになり、ボールコネクタが画面の方を向くようにしてください。
電源の投入とキャリブレーション
- 電源ボタンを1回押してください。ステータスランプが赤色に点灯した後、黄色に変わります。これは、本体内のIMUが自己校正を行っていることを示しています。
- 自動キャリブレーションが完了すると、スタイラスがコンピュータに接続されます。
- スタイラスが正常に接続され、ワイヤレスでデータが送信されると、ステータスインジケーターが緑色に点滅します。
- バッテリー残量が非常に少なくなると、VerseGrip Stylusは2分ごとに自動的に電源が切れます。直ちに充電してください。
再校正
キャリブレーションの過程では、VerseGripの座標系をリセットし、キャリブレーション中にデバイスを保持している方向を新しい基準軸とします。
- 再キャリブレーションを行うには、希望の位置でスタイラスを保持した状態で、キャリブレーションボタンを3秒間押し続けるか、シミュレーション内で方向が変わるまで押し続けてください。
以下は、キャリブレーションを行っていない場合と行った場合におけるデバイスの動作を比較したデモンストレーションです。デモンストレーションでは、キャリブレーションを実行する前に、VerseGripの姿勢を下図のように保つ必要があります。

スタンバイモードおよび電源オフ
- 電源ボタンを1回押すと、スタンバイモードに戻ります。ステータスランプが白く点滅し始め、データ転送が停止します。
- VerseGrip Stylusの電源を切るには、電源ボタンを5秒間押し続けてから指を離してください。ボタンを離すと、ステータスインジケーターが消え、何も表示されなくなります。データ転送も停止します。
充電
- USB-C充電ポートにVerseGrip Stylusを接続してください。
- 電源に接続すると、充電状態インジケーターが青色で点灯し続け、充電が完了すると消灯します。
- スタイラスがオフの状態のときに電源に接続すると、自動的に電源が入ります。
警告:2024年8月から12月の間に出荷されたVerseGrip Stylusをご使用の場合は、バッテリーが完全に放電しないようにしてください。バッテリーが放電すると、充電状態を維持できなくなる可能性があります。この場合、VerseGrip Stylusは電源に接続されている限り動作し続けます。この問題を解決するためのファームウェア更新ファイルを入手するには、Haply のサポートチームにお問い合わせください。
状態およびインジケーター
| 色 | 表示灯のパターン | 説明 |
|---|---|---|
| 黄色 | 速いフェードイン/フェードアウト | 初期の自動センサー基準校正(VerseGripをテーブルの上に静かに置いてください) |
| 速い点滅 | 方向キャリブレーションボタンが押され、キャリブレーション処理が開始された | |
| 点灯し続ける | 方向キャリブレーションボタンが押され、キャリブレーションが完了しました | |
| 赤色 | 速いフェードイン/フェードアウト | アダプタの接続が解除されました。ホストからの信号がありません。 |
| 速い点滅 | 電源ボタンが押され、シャットダウン処理が開始されました | |
| 緑色 | フェードイン/フェードアウト | アダプターが接続されています。VerseGripはアクティブデータストリームモードです。 |
| 点灯し続ける | アダプターが接続されています、VerseGripがアクティブデータストリームモード、USB電源が接続されています | |
| 白 | フェードイン/フェードアウト | アダプターが接続されています、VerseGripがアイドル/待機モード、データストリーミングなし |
| 点灯し続ける | アダプターが接続されています、VerseGripがアイドル/待機モード、データストリーミングなし、USB電源が接続されています | |
| オレンジ色 | 点滅(インターレース) | バッテリー残量不足の警告表示。現在の状態では、通知がインターレース方式で表示されています。 |
| 二重点滅(インターレース) | 「バッテリー残量が非常に少ない」という警告が表示され、現在の状態では通知がインターレース方式で表示されています | |
| 青緑色 | フェードイン/フェードアウト | デバイスのファームウェア更新モード |
| (より明るい) | 点灯し続ける | ユーザーボタンが押された。現在の表示色が点灯したままで、より明るく表示されている。 |
| オフ | 表示灯なし | 終了、電源オフ |
| 充電インジケーターの色 | 表示灯のパターン | 説明 |
|---|---|---|
| 青色 | 点灯し続ける | 充電中 |
| 速い点滅 | 充電がほぼ完了しました | |
| オフ | 表示灯なし | 充電完了 |
旧バージョンの状態およびインジケーター
以下のインジケーターの状態と色は、VerseGrip Stylusの旧バージョン(ファームウェア1.10以下)で使用されていた従来のものです。
| 色 | 表示灯のパターン | 説明 |
|---|---|---|
| 赤色 | 点灯し続ける | コンポーネントの初期化を待機中 |
| ちらつき | 待機モード。データ転送なし | |
| 青色 | 点灯し続ける | 初期の自動センサー基準校正(VerseGripをテーブルの上に静かに置いてください) |
| 緑色 | ちらつき | アダプターが接続されています。VerseGripはアクティブデータストリームモードです。 |
| オフ | 表示灯なし | 終了、電源オフ |
| 充電インジケーターの色 | 表示灯のパターン | 説明 |
|---|---|---|
| 青色 | 点灯し続ける | 充電中 |
| 速い点滅 | 充電がほぼ完了しました | |
| オフ | 表示灯なし | 充電完了 |
サンプルコード
以下は、C++連携環境でVerseGrip Stylusを使用する方法を示す簡単な例です。
#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);
}
}