快速入门:触控笔 VerseGrip
VerseGrips 为 Inverse3 增加了方向跟踪功能。本文概述了 Stylus VerseGrip 的设置步骤及其功能。
触控笔 VerseGrip
Stylus VerseGrip PROTOTYPE Inverse3 应用了尖端的专有边缘高速无线通信技术,提供定位和手持输入/输出功能。重新想象这一领域的可能性,实现无与伦比的多功能性。
我们为您提供的一些令人难以置信的功能:
- 2 个用户输入按钮、
- 1 个校准按钮、
- 1 个电源/待机按钮,以及
- 2 个 RGB LED 指示灯
- 10-12 小时电池使用时间
- USB-c 连接用于充电
- 无线通信速度高达 1 KHz
- 一个频段上最多可有 8 个 VerseGrips 与加密狗配对
客户支持
如果您对您的设备和使用方法有任何问题或疑虑,请随时联系我们,我们非常乐意为您解答。 Stylus VerseGrip PROTOTYPE 是一款功能强大的设备,内含复杂的专有无线技术。任何试图打开设备的行为不仅会使您的保修失效,而且可能很快导致设备无法使用。为避免漫长的运输和昂贵的维修过程,请勿尝试打开设备。
触控笔 VerseGrip 设置和校准
本节概述了插入加密狗、打开 VerseGrip 和校准的步骤。
设置
- 将加密狗插入电脑的 USB 接口。
- 将手柄放在不会移动的平面上,按钮朝上,球形连接器指向屏幕。
开机和校准
- 按一次电源按钮。状态指示灯将变为红色,然后变为蓝色。蓝色表示设备中的 IMU 正在进行自校准。
- 自校准后,状态指示灯将每隔 0.5 秒闪烁一次红灯。这是待机模式。
- 按下任意按钮即可将设备从待机模式唤醒。唤醒时,您会看到状态指示灯闪烁绿光,然后变为纯绿色。现在它正在向无线网络传输数据。
重新校准
- 要重新校准,请按住校准按钮三秒钟,或直到您看到模拟的方向发生了移动。
待机和关机
- 再次按下电源按钮即可返回待机模式。状态指示灯将变为红色,每 2 秒闪烁一次,数据传输将停止。
- 要关闭 VerseGrip,请按住电源按钮 5 秒钟后松开。松手后,状态指示灯应该会熄灭,并且不会有任何指示。它将停止传输数据。
充电
- 通过 USB-C 充电插座将 Stylus VerseGrip 插入电源。
- 插入电源时,充电指示灯将呈蓝色;充满电后,充电指示灯将快速闪烁蓝光。插入电源后,设备将启动并进入待机状态。
状态和指示灯
状态指示灯的颜色和行为 | 国家 |
---|---|
红色,固体 | 待初始化组件 |
蓝色,纯色 | 手柄中的 IMU 正在进行自校准 |
红色,每 2 秒闪烁一次 | 待机模式。无数据传输。 |
绿色,每 2 秒闪烁一次 | 正常模式,自动向无线网络传输数据。 |
没有灯光,没有指示 | 电源已关闭。 |
充电指示灯颜色 | 国家 |
---|---|
蓝色,纯色 | 充电 |
蓝色,快速闪烁 | 这表明设备已充满电。 |
没有灯光,没有指示 | 设备未充电 |
代码示例
下面是一个如何用 C++ 使用 Versegrip 触控笔的简单示例。
- 逆向 SDK
- 硬件接口
#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 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);
}
}