VerseGripスタイラスを使い始める
VerseGripsは、Inverse3 。この記事では、VerseGrip Stylusのセットアップ手順とその機能について概説します。
ヴァースグリップ・スタイラス
VerseGrip StylusInverse3 、独自の高速ワイヤレス通信技術により、オリエンテーショントラッキングとインハンド入出力(I/O)を提供します。様々なアプリケーションに対応できるよう設計されています。
主な特徴は以下の通り:
- 2つのユーザー入力ボタン
- 1キャリブレーションボタン、
- 電源/スタンバイボタン×1
- 2インジケーターRGB LEDライト
- 10-12時間のバッテリー寿命
- 充電用USB-c接続
- 最大1KHzのワイヤレス通信速度
- 1つのバンドで最大8個のVerseGrip Stylusをドングルにペアリング可能

VerseGrip Stylusの外観は、(1) Inverse3 ジンバルに装着するボールコネクター、(2)と(3)入力ボタン、(4)USB-C充電ポート、(5)キャリブレーションボタン、(6)ステータスLED、(7)電源ボタンの7つの主要機能を備えている。
カスタマーサポート
お使いのデバイスやその操作についてご質問やご不明な点がございましたら、弊社サポートチームまでお問い合わせください。VerseGripスタイラスには、複雑な独自のワイヤレス技術が搭載されています。デバイスを開けると保証が無効になり、操作できなくなる場合があります。輸送時間の延長や高額な修理を避けるため、デバイスを開けないでください。
VerseGripスタイラスのセットアップとキャリブレーション
このセクションでは、ドングルの接続、VerseGrip Stylusの電源オン、キャリブレーションの手順について説明します。
セットアップ
- ドングルをコンピュータのUSBレセプタクルに差し込む。
- ハンドルは動かないように平らな場所に置き、ボタンは上に向け、ボールコネクターはスクリーンに向ける。
電源オンとキャリブレーション
- 電源ボタンを1回押します。ステータスランプが赤色に変わり、その後青色に変わります。青色は、デバイス内のIMUが自己校正中であることを示します。
- 自己較正後、ステータス・ライトは0.5秒に1回赤色に点滅します。これはスタンバイモードです。
- いずれかのボタンを押して、スタンバイモードからデバイスを起動します。起動中はステータスライトが緑色に点滅し、その後緑色の点灯に変わります。ワイヤレスにデータを送信中です。
- 電池残量が少なくなると、VerseGripスタイラスは2分ごとに電源が切れますので、すぐに充電してください。
再校正
- 再キャリブレーションを行うには、キャリブレーションボタンを3秒間、またはシミュレーションで向きがずれたことが確認できるまで押し続けます。 較正プロセスにより、VerseGripの座標系がリセットされ、較正中にデバイスが保持された方向が新しい基準軸となります。 例えば、以下は、キャリブレーションを行わない場合とキャリブレーションを行った場合のデバイスの動作を比較したデモです。このデモでは、VerseGripは較正が実行される前に示された構成で保持されている必要があります。

スタンバイと電源オフ
- 電源ボタンをもう一度押すと、スタンバイ・モードに戻ります。ステータス・ライトが赤くなり、2秒ごとに点滅し、データ通信が停止します。
- VerseGrip Stylusの電源を切るには、電源ボタンを5秒間押したまま放します。離すと、ステータスランプが消え、何も表示されなくなります。データの送信は停止します。
充電
- USB-C充電レセプタクルでVerseGrip Stylusを電源に接続します。
- 電源に差し込むと充電ランプが青く点灯し、満充電になると急速に青く点滅します。電源に接続すると、デバイスが起動し、スタンバイ状態になります。
警告:バッテリーを完全に放電させないでください。電池が消耗すると、充電が維持できなくなることがあります。この場合、VerseGrip Stylusはプラグに接続されている限り動作し続けます。これは、2024年8月から12月の間に出荷されたVerseGrip Stylusデバイスのみの問題です。この問題を修正するファームウェアのアップデートをご希望の場合は、Haply サポートまでご連絡ください。
ステートとライト・インジケータ
| 色 | ライトの点灯パターン | 説明 |
|---|---|---|
| イエロー | 速いフェードイン/フェードアウト | センサーの初期自動基準校正(VerseGripをテーブルの上に平らに置いてください) |
| 素早い瞬き | オリエンテーション校正ボタンが押され、校正プロセスが開始されました | |
| ソリッド | オリエンテーション校正ボタンを押しました。校正が完了しました。 | |
| レッド | 速いフェードイン/フェードアウト | アダプタが切断されました。ホストからの信号がありません |
| 素早い瞬き | 電源ボタンが押され、シャットダウン処理が開始されました | |
| グリーン | フェードイン/フェードアウト | アダプターが接続されています。VerseGripはアクティブデータストリームモードです。 |
| ソリッド | アダプターが接続されています。VerseGripがアクティブデータストリームモードです。USB電源が接続されています。 | |
| ホワイト | フェードイン/フェードアウト | アダプターが接続されています。VerseGripはアイドル/スタンバイモードで、データストリーミングは行われていません。 |
| ソリッド | アダプター接続済み、VerseGripはアイドル/スタンバイモードでデータ転送なし、USB給電接続済み | |
| オレンジ | Flash(インターレース方式) | バッテリー残量低下の警告表示、通知は現在の状態で交互に表示される |
| ダブルフラッシュ(インターレース方式) | バッテリー残量が危険なほど少ないという警告表示。現在の状態では、通知が交互に表示されます。 | |
| ティール | フェードイン/フェードアウト | デバイスのファームウェア更新モード |
| (より明るく) | ソリッド | ユーザーがボタンを押すと、現在の表示色が点灯し、明るくなります |
| オフ | 明かりがない | シャットダウン、電源オフ |
| 充電インジケーターの色 | ライトの点灯パターン | 説明 |
|---|---|---|
| ブルー | ソリッド | 充電 |
| 素早い瞬き | 充電がほぼ完了しました | |
| オフ | 明かりがない | 充電完了 |
レガシー状態とライトインジケーター
以下のステータスライトは、VerseGrip Stylusの以前のバージョンに見られた従来の状態と色です
| 色 | ライトの点灯パターン | 説明 |
|---|---|---|
| レッド | ソリッド | コンポーネントの初期化保留 |
| 瞬き | スタンバイモード。データ通信は行われません | |
| ブルー | ソリッド | センサーの初期自動基準校正(VerseGripをテーブルの上に平らに置いてください) |
| グリーン | 瞬き | アダプター接続済み、VerseGrip アクティブデータストリームモード |
| オフ | 明かりがない | シャットダウン、電源オフ |
| 充電インジケーターの色 | ライトの点灯パターン | 説明 |
|---|---|---|
| ブルー | ソリッド | 充電 |
| 素早い瞬き | 充電がほぼ完了しました | |
| オフ | 明かりがない | 充電完了 |
サンプルコード
C++でVerseGrip Stylusを使う簡単な例です。
- Inverse SDK
- ハードウェアAPI
#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);
}
}