跳过至主要内容

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

VerseGrip 触控笔的初次使用

VerseGrips 为Inverse3、Inverse3X 和 MinVerse 添加了姿态(方向)追踪功能。本文将介绍 VerseGrip Stylus 的设置步骤及其功能。

关于VerseGrip触控笔​

VerseGrip 触控笔采用独有的高速无线通信技术,可实现姿势追踪以及手持状态下的输入/输出(I/O)功能。其设计旨在满足各种应用场景的需求。

主要功能如下:

  • 2 个用户输入按钮、
  • 1 个校准按钮,
  • 1 个电源/待机按钮
  • 2 个状态 LED 指示灯
  • USB-C充电接口
  • 最高 1 KHz 的无线通信速率
  • 电池续航时间 10~12 小时
  • 每条腕带最多可将 8 支 VerseGrip 触控笔与适配器配对

客户支持​

如果您对设备或其运行有任何疑问或顾虑,请联系我们的支持团队。VerseGrip Stylus 内置了复杂且独特的无线技术。拆开设备将导致保修失效,并可能导致设备无法正常工作。为避免交货时间延长或产生高额维修费用,请勿拆开设备。

VerseGrip 触控笔的设置与校准​

本节将介绍加密狗的连接、VerseGrip Stylus的开机以及校准步骤。

设置​

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

开机与校准​

  • 按一下电源按钮。状态指示灯将亮起红色,随后变为黄色,表示设备内的IMU正在进行自校准。
  • 完成自动校准后,触控笔将连接到计算机上。
  • 当触控笔连接正常并处于无线数据传输状态时,状态指示灯会闪烁绿色。
  • 当电池电量极低时,VerseGrip Stylus 会每 2 分钟自动关机一次。请立即为其充电。

重新校准​

通过校准处理,VerseGrip的坐标系将被重置,校准过程中握持设备时的方向将成为新的基准轴。

  • 要重新校准,请将触控笔悬停在需要重新校准的位置,并按住校准按钮 3 秒钟,或者一直按住直到模拟场景中的姿态发生变化。

以下是一个演示,对比了设备未经校准和已校准时的运行情况。在演示中,必须在执行校准之前,将VerseGrip保持在图中所示的姿势。

待机与关机​

  • 按一下电源按钮,设备将返回待机模式。状态指示灯开始闪烁白色,数据传输将停止。
  • 要关闭VerseGrip触控笔的电源,请长按电源按钮5秒钟,然后松开。松开后,状态指示灯将熄灭,屏幕上将不再显示任何内容。数据传输也将停止。

充电​

  • 将VerseGrip触控笔通过USB-C充电端口连接。
  • 连接电源时,充电状态指示灯会亮起蓝色,充满电后指示灯将熄灭。
  • 当触控笔处于关闭状态时,若将其连接到电源,设备将自动开启。

警告:如果您拥有的是 2024 年 8 月至 12 月期间出厂的 VerseGrip Stylus,请勿让电池完全放电。一旦完全放电,电池可能无法保持电量。即使出现这种情况,只要保持连接电源,VerseGrip Stylus 仍可继续工作。如需获取可修复此问题的固件更新文件,请联系 Haply 客服。

状态与指示灯​

色灯光序列说明
黄色高速淡入/淡出初始自动传感器基准校准(请将VerseGrip静置在台面上)
高速闪烁已按下姿态校准按钮,校准过程已开始
点灯已按下姿态校准按钮,校准已完成
赤高速淡入/淡出适配器已断开连接,未收到来自主机的信号
高速闪烁已按下电源按钮,关机程序已启动
绿淡入/淡出适配器已连接,VerseGrip处于活动数据流模式
点灯适配器已连接,VerseGrip处于活动数据流模式,且已连接USB电源
白淡入/淡出适配器已连接,VerseGrip处于空闲/待机模式,没有数据流
点灯适配器已连接,VerseGrip处于空闲/待机模式,没有数据流,且已连接USB电源
橙子闪存(交错式)这是电池电量不足的警告提示。通知将以交错显示的方式呈现当前状态。
双闪(交错扫描)这是一条提示电池电量已降至危险水平的警告信息。该通知将以交错显示的方式呈现。
蒂尔淡入/淡出这是设备的固件更新模式
(明亮)点灯用户按钮已被按下。当前显示颜色将亮起,并变得更亮
关闭熄灯关机、关闭电源
充电指示灯的颜色灯光序列说明
青点灯正在充电
高速闪烁即将充满电
关闭熄灯已充满电

旧版本的状态与指示灯​

以下状态指示灯的显示方式和颜色是VerseGrip Stylus旧版本(固件1.10及更早版本)中采用的旧式设计。

色灯光序列说明
赤点灯正在等待组件初始化
闪烁待机模式。不发送数据
青点灯初始自动传感器基准校准(请将VerseGrip静置在台面上)
绿闪烁适配器已连接,VerseGrip处于活动数据流模式
关闭熄灯关机、关闭电源
充电指示灯的颜色灯光序列说明
青点灯正在充电
高速闪烁即将充满电
关闭熄灯已充满电

示例代码​

下面是一个将VerseGrip触控笔与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);

}
}