import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';
VerseGrip 스타일러스 시작하기
VerseGrips는 Inverse3, Inverse3X 및 MinVerse 방향 추적 기능을 추가합니다. 이 글에서는 VerseGrip 스타일러스의 설정 절차와 주요 기능을 설명합니다.
버즈그립 스타일러스
VerseGrip 스타일러스는 독자적인 고속 무선 통신 기술을 활용하여 방향 추적 및 손 안에서의 입출력(I/O) 기능을 제공합니다. 이 제품은 다양한 용도에 걸쳐 폭넓게 활용될 수 있도록 설계되었습니다.
주요 기능은 다음과 같습니다:
- 사용자 입력 버튼 2개,
- 보정 버튼 1개,
- 전원/대기 버튼 1개
- 상태 표시 LED 2개
- USB-C 충전 포트
- 최대 1KHz의 무선 통신 속도
- 10~12시간의 배터리 수명
- 하나의 밴드에서 최대 8개의 VerseGrip 스타일러스를 동글에 페어링할 수 있습니다.

고객 지원
장치 또는 장치 작동에 대한 질문이나 우려 사항이 있는 경우 지원팀에 문의하여 도움을 받으세요. VerseGrip 스타일러스에는 복잡한 독점 무선 기술이 포함되어 있습니다. 장치를 개봉하면 보증이 무효화되고 작동이 불가능해질 수 있습니다. 배송 시간이 길어지고 수리 비용이 많이 드는 것을 방지하려면 장치를 열지 마세요.
VerseGrip 스타일러스 설정 및 보정
이 섹션에서는 동글 연결, VerseGrip 스타일러스 켜기 및 보정 단계를 간략하게 설명합니다.
설정
- 동글을 컴퓨터의 USB 포트에 연결하세요.
- 손잡이를 움직이지 않는 평평한 곳에 올려놓고, 버튼이 위를 향하게 하며 볼 커넥터가 화면을 향하도록 하세요.
전원 켜기 및 보정
- 전원 버튼을 한 번 누르세요. 상태 표시등이 빨간색으로 켜졌다가 노란색으로 바뀌며, 이는 기기 내 IMU가 자체 보정 중임을 나타냅니다.
- 자동 보정 후, 스타일러스가 컴퓨터에 연결됩니다.
- 스타일러스가 무선으로 성공적으로 연결되어 데이터를 전송 중일 때, 상태 표시등이 녹색으로 깜빡입니다.
- 배터리 잔량이 매우 부족하면 VerseGrip 스타일러스가 2분마다 자동으로 꺼집니다. 즉시 충전해 주십시오.
재보정
보정 과정은 VerseGrip의 좌표계를 재설정하여, 보정 시 장치를 잡고 있는 방향이 새로운 기준축이 되도록 합니다.
- 재보정하려면, 재보정하려는 위치에 스타일러스를 대고 보정 버튼을 3초 동안 누르거나 시뮬레이션 화면에서 방향이 바뀌기까지 계속 누르고 계십시오.
다음은 보정 전과 보정 후 기기의 작동 방식을 비교한 시연 영상입니다. 시연을 진행하려면 보정을 시작하기 전에 그림과 같이 VerseGrip을 잡아야 합니다.

대기 및 전원 끄기
- 전원 버튼을 한 번 눌러 대기 모드로 돌아가십시오. 상태 표시등이 흰색으로 깜빡이기 시작하며, 데이터 전송이 중단됩니다.
- 버즈그립 스타일러스를 끄려면 전원 버튼을 5초간 누르고 있다가 놓습니다. 손을 놓으면 상태 표시등이 꺼지고 아무 표시도 나타나지 않습니다. 데이터 전송이 중지됩니다.
충전
- VerseGrip 스타일러스를 USB-C 충전 포트에 연결하세요.
- 전원에 연결하면 충전 상태 표시등이 파란색으로 계속 켜져 있으며, 충전이 완료되면 꺼집니다.
- 전원에 연결할 때 스타일러스가 꺼져 있으면 자동으로 켜집니다.
주의: 2024년 8월부터 12월 사이에 출고된 VerseGrip 스타일러스를 사용 중이신 경우, 배터리가 완전히 방전되지 않도록 주의하십시오. 배터리가 완전히 방전되면 다시 충전되지 않을 수 있습니다. 이 경우, VerseGrip 스타일러스는 전원에 연결된 상태에서는 계속 작동합니다. 이 문제를 해결하기 위한 펌웨어 업데이트 파일을 받으려면 Haply 문의하십시오.
상태 및 표시등 표시기
| 색상 | 조명 시퀀스 | 설명 |
|---|---|---|
| 노란색 | 빠른 페이드 인/아웃 | 초기 자동 센서 기준 보정 (VerseGrip을 테이블 위에 평평하게 놓으십시오) |
| 빠른 깜빡임 | 보정 시작 버튼을 눌렀으며, 보정 과정이 시작되었습니다 | |
| 단단한 | 보정 시작 버튼을 눌렀습니다. 보정이 완료되었습니다. | |
| 빨간색 | 빠른 페이드 인/아웃 | 어댑터가 분리되었습니다. 호스트에서 신호가 수신되지 않습니다. |
| 빠른 깜빡임 | 전원 버튼을 눌렀습니다. 종료 절차가 시작되었습니다. | |
| 녹색 | 점진적 시작/종료 | 어댑터 연결됨, VerseGrip 데이터 스트림 모드 활성화됨 |
| 단단한 | 어댑터 연결됨, VerseGrip 데이터 스트림 모드 활성화됨, USB 전원 연결됨 | |
| 흰색 | 점진적 시작/종료 | 어댑터 연결됨, VerseGrip 대기 모드에서 데이터 스트리밍 없음 |
| 단단한 | 어댑터 연결됨, VerseGrip 유휴/대기 모드(데이터 전송 없음), USB 전원 연결됨 | |
| 오렌지 | 플래시 (인터레이스 방식) | 배터리 부족 경고 표시, 현재 상태에서 알림이 교대로 표시됩니다 |
| 더블 플래시 (인터레이스 방식) | 배터리 잔량이 매우 낮을 때의 경고 표시가 현재 상태에서 간헐적으로 나타납니다 | |
| 청록색 | 점진적 시작/종료 | 기기 펌웨어 업데이트 모드 |
| (더 밝게) | 단단한 | 사용자가 버튼을 누르면, 현재 표시 색상이 단색으로 변하고 더 밝아집니다 |
| 꺼짐 | 빛이 없다 | 종료, 전원 끄기 |
| 충전 표시등 색상 | 조명 시퀀스 | 설명 |
|---|---|---|
| 파란색 | 단단한 | 충전 |
| 빠른 깜빡임 | 충전이 거의 완료되었습니다 | |
| 꺼짐 | 불이 안 들어옴 | 충전이 완료되었습니다 |
레거시 상태 및 표시등
아래의 상태 표시등은 이전 버전의 VerseGrip 스타일러스(펌웨어 1.10 이하)에서 사용되던 상태 및 색상입니다.
| 색상 | 조명 시퀀스 | 설명 |
|---|---|---|
| 빨간색 | 단단한 | 구성 요소 초기화 보류 중 |
| 깜빡 | 대기 모드. 데이터 전송 없음 | |
| 파란색 | 단단한 | 초기 자동 센서 기준 보정 (VerseGrip을 테이블 위에 평평하게 놓으십시오) |
| 녹색 | 깜빡 | 어댑터 연결됨, 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;
}
#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);
}
}