支持中心/快速上手

开始使用 VerseGrip 触控笔

VerseGrips 为Inverse3、Inverse3X 和MinVerse 增添了姿态追踪功能。本文概述了 VerseGrip 触控笔的设置流程及其功能。

VerseGrip 触控笔

VerseGrip 触控笔采用专有的高速无线通信技术,可实现方向追踪和手持输入/输出(I/O)功能。该产品专为满足多种应用场景的需求而设计,具有极高的通用性。

主要功能包括

  • 2 个用户输入按钮、
  • 1 个校准按钮、
  • 1 个电源/待机按钮
  • 2 个状态指示灯
  • USB-C 充电接口
  • 无线通信速度高达 1 KHz
  • 10-12 小时电池使用时间
  • 一个频段上最多可有 8 个 VerseGrip Stylus 与加密狗配对

客户支持

如果您对设备或其操作有任何问题或疑虑,请联系我们的支持团队寻求帮助。VerseGrip 触控笔包含复杂的专有无线技术。打开设备将使您的保修失效,并可能导致设备无法使用。为避免延长运输时间和昂贵的维修费用,请勿打开设备。

VerseGrip 触控笔的设置和校准

本节概述了插入加密狗、打开 VerseGrip 触控笔和校准的步骤。

设置

  • 将加密狗插入计算机的USB端口。
  • 将手柄放在不会移动的平坦表面上,按键朝上,球形连接器朝向屏幕。

开机和校准

  • 按一下电源按钮。状态指示灯将先变为红色,随后转为黄色,表示设备中的IMU正在进行自校准。
  • 完成自校准后,触控笔将与计算机连接。
  • 当触控笔成功连接并通过无线方式传输数据时,状态指示灯将闪烁绿色。
  • 如果电量极低,VerseGrip 触控笔会每 2 分钟自动关机一次;请立即为其充电。

重新校准

校准过程会重置 VerseGrip 的坐标系,使得校准期间握持设备时的方向成为新的参考轴。

  • 要重新校准,请将触控笔置于您希望校准的位置,按住校准按钮三秒钟,或直到模拟画面中的方向发生变化。

以下演示对比了设备未校准时与已校准时的行为表现。在进行演示时,必须按照图示配置握持VerseGrip,然后才能进行校准。

待机和关机

  • 按一下电源按钮即可返回待机模式。状态指示灯将开始闪烁白色,数据传输将停止。
  • 要关闭 VerseGrip 触控笔,请按住电源按钮 5 秒钟,然后松开。松手后,状态指示灯应该会熄灭,并且不会有任何指示。它将停止传输数据。

充电

  • 通过 USB-C 充电端口为 VerseGrip 触控笔充电。
  • 连接电源后,充电状态指示灯将持续显示蓝色,充满电后指示灯将熄灭。
  • 如果在连接电源时触控笔处于关闭状态,它会自动开启。

警告:如果您拥有的VerseGrip触控笔是在2024年8月至12月期间发货的——请勿让电池完全放电。一旦电量耗尽,电池可能无法再次充电。如果发生这种情况,只要VerseGrip触控笔保持连接电源,它就能继续工作。请Haply 以获取固件更新文件,从而解决此问题。

状态和指示灯

颜色灯光序列描述
黄色快速进入/退出传感器参考值的自动初始校准(将VerseGrip平放在桌面上)
快速闪烁方向校准按钮已按下,校准过程已启动
常亮方向校准按钮已被按下,校准已完成
红色快速进入/退出适配器已断开连接,主机无信号
快速闪烁电源按钮已强制触发,关机过程已启动
绿色输入/输出时闪烁适配器已连接,VersaGrip数据流模式激活
常亮适配器已连接,数据流模式激活,VersaGrip处于工作状态,USB电源已连接
白色输入/输出时闪烁适配器已连接,VerseGrip处于待机模式:无数据传输
常亮适配器已连接,VerseGrip处于待机/长待机模式,无数据传输,USB电源已连接
橙色闪烁(交替)低电量警告:通知集成在当前状态中
双闪(交错)电池电量极低警告;通知会与当前状态交替显示
蓝光闪烁输入/输出时闪烁设备固件更新模式
(更亮)常亮当用户按下按钮时,当前指示的颜色会变亮且更鲜艳
已关闭无光停止,断电

充电指示灯颜色灯光序列描述
蓝色常亮充电中
快速闪烁充电即将完成
禁用无光充电完成

继承状态和指示灯

以下状态指示灯对应VersaGrip笔在之前版本中使用的状态和颜色(微软件1.10及更早版本)。

颜色灯光序列描述
红色常亮等待组件初始化
闪烁待机模式。无数据传输
蓝色常亮传感器参考值自动初始化(将VersaGrip平放在桌面上)
绿色闪烁适配器已连接,数据流模式激活VerseGrip
禁用无光停止,断电

充电指示灯颜色灯光序列描述
蓝色常亮充电中
快速闪烁充电即将完成
已禁用无光充电完成

代码示例

以下是一个关于如何在 C++ 中使用 VerseGrip 触控笔的简单示例。

C++ VerseGrip 触控笔示例代码

                
                #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;
                }
            
              

C++ VerseGrip 触控笔示例代码

                
                #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);

                    }
                }