본문으로 바로 가기

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

VerseGrip 스타일러스 첫 사용 가이드

VerseGrips는 Inverse3, Inverse3X 및 MinVerse 에 방향 감지 기능을 추가합니다. 이 문서에서는 VerseGrip 스타일러스의 설정 방법과 기능을 설명합니다.

VerseGrip 스타일러스​

VerseGrip 스타일러스는 독자적인 고속 무선 기술을 활용하여 방향 감지 및 핸드 내 입출력(I/O) 기능을 제공합니다. 이 제품은 다용도로 사용할 수 있으며 다양한 용도에 맞게 설계되었습니다.

주요 기능으로는 다음이 있습니다:

  • 2개의 사용자 입력 버튼,
  • 1. 보정 버튼,
  • 1. 전원/대기 버튼
  • 2개의 상태 LED
  • USB-C 충전 포트
  • 최대 1 kHz의 무선 통신
  • 10~12시간의 배터리 사용 시간
  • 동글 하나를 사용해 한 개의 스트랩에 최대 8개의 VerseGrip 스타일러스를 페어링할 수 있습니다.

고객 지원​

기기 또는 사용 방법과 관련하여 질문이나 문의 사항이 있으시면 당사 지원팀에 문의해 주십시오. VerseGrip 스타일러스에는 복잡한 독자적인 무선 기술이 적용되어 있습니다. 기기를 개봉할 경우 보증이 무효화되며 기기가 작동하지 않을 수 있습니다. 배송 기간이 길어지거나 고액의 수리비가 발생하는 것을 방지하기 위해, 기기를 절대 개봉하지 마십시오.

VerseGrip 스타일러스 설정 및 보정​

이 섹션에서는 동글을 삽입하고, VerseGrip 스타일러스를 켜며, 보정하는 절차를 설명합니다.

설비​

  • 동글을 컴퓨터의 USB 포트에 꽂으십시오.
  • 손잡이를 미끄러지지 않는 평평한 표면에 올려놓고, 버튼이 위를 향하게 하며 볼 조인트가 화면 쪽을 향하도록 하십시오.

전원 켜기 및 보정​

  • 전원 버튼을 한 번 누르십시오. 상태 표시등이 처음에는 빨간색으로 켜졌다가 노란색으로 바뀌는데, 이는 기기 내부의 IMU가 자체 보정을 수행 중임을 나타냅니다.
  • 자동 보정 후 스타일러스가 컴퓨터와 연결됩니다.
  • 스타일러스가 성공적으로 연결되어 데이터를 무선으로 전송하기 시작하면 상태 표시등이 녹색으로 깜빡입니다.
  • 배터리 잔량이 매우 부족하면 VerseGrip Stylus는 2분마다 자동으로 전원이 꺼집니다. 즉시 충전해 주십시오.

재보정​

보정 과정은 VerseGrip의 좌표계를 초기화하여, 보정 중에 장치를 잡고 있는 방향이 새로운 기준축이 되도록 합니다.

  • 재보정을 하려면, 스타일러스를 재보정하려는 위치에 놓고 보정 버튼을 3초 동안 누르고 있거나, 시뮬레이션에서 방향이 바뀔 때까지 누르고 계십시오.

다음은 보정되지 않은 상태와 보정된 상태에서 장치의 동작을 비교하는 시연 영상입니다. 시연을 진행하려면 보정 전에 VerseGrip을 그림과 같은 구성으로 유지해야 합니다.

대기 모드 및 전원 끄기​

  • 전원 버튼을 한 번 누르면 대기 모드로 돌아갑니다. 상태 표시등이 흰색으로 깜빡이기 시작하며, 데이터 전송이 중단됩니다.
  • VerseGrip 스타일러스를 끄려면 전원 버튼을 5초 동안 길게 누른 다음 손을 떼십시오. 손을 떼면 상태 표시등이 꺼지고 화면이 더 이상 표시되지 않습니다. 이때 데이터 전송도 중단됩니다.

적재된​

  • VerseGrip 스타일러스를 USB-C 충전 포트를 통해 전원 공급 장치에 연결하십시오.
  • 전원이 연결되면 충전 상태 표시등이 파란색으로 계속 켜져 있으며, 배터리가 완전히 충전되면 꺼집니다.
  • 스타일러스가 꺼진 상태에서 전원 어댑터에 연결하면 자동으로 켜집니다.

경고: 2024년 8월부터 12월 사이에 출하된 VerseGrip 스타일러스 기기의 경우, 배터리가 완전히 방전되지 않도록 주의하십시오. 배터리가 완전히 방전되면, 경우에 따라 더 이상 충전을 유지하지 못할 수 있습니다. 이러한 상황이 발생하더라도 VerseGrip 스타일러스는 전원이 연결된 상태에서는 계속 작동합니다. 이 문제를 해결하기 위한 펌웨어 업데이트 파일을 받으려면 Haply 고객 지원팀에 문의하십시오.

상태 및 표시등​

색상조명 시퀀스설명
겔브빠른 표시/숨기기센서 기준값의 자동 초기 보정 (VerseGrip을 테이블 위에 움직이지 않게 올려놓으십시오)
빠른 깜빡임정렬·보정 버튼을 눌렀으며, 보정 절차가 시작되었습니다.
영구적정렬·보정 버튼을 눌렀으며, 보정이 완료되었습니다.
썩음빠른 표시/숨기기어댑터가 분리되었으며, 호스트로부터 신호가 수신되지 않습니다.
빠른 깜빡임전원 버튼이 눌려졌으며, 전원 차단 절차가 시작되었습니다.
그뤼ン표시/숨기기어댑터 연결됨, VerseGrip이 활성 데이터 전송 모드임
영구적어댑터 연결됨, VerseGrip이 활성 데이터 전송 모드임, USB 전원 공급 장치 연결됨
바이스표시/숨기기어댑터 연결됨, VerseGrip이 데이터 전송 없이 유휴/대기 모드 상태임
영구적어댑터 연결됨, VerseGrip이 데이터 전송 없이 유휴/대기 모드 상태, USB 전원 공급 연결됨
오렌지블리츠 (중첩형)배터리 잔량 부족 경고 표시, 현재 상태 알림이 중첩됨
도펠블리츠 (중첩형)배터리 잔량이 위험할 정도로 낮아졌음을 알리는 경고 표시, 현재 상태에서 알림이 중첩됨
튀르키스표시/숨기기기기의 펌웨어 업데이트 모드
(헬러)영구적사용자 버튼을 눌렀으며, 현재 표시 색상이 고정되고 더 밝아졌습니다.
Aus조명 없음종료, 전원 끄기
충전 표시기 색상조명 시퀀스설명
블라우영구적적재된
빠른 깜빡임충전이 거의 완료되었습니다
Aus조명 없음충전이 완료되었습니다

이전 상태 및 표시등​

다음 상태 표시등은 이전 버전의 VerseGrip Stylus(펌웨어 1.10 및 그 이전 버전)에서 사용되었던 상태와 색상입니다.

색상조명 시퀀스설명
썩음영구적구성 요소 초기화가 완료되지 않았습니다.
블링켄대기 모드. 데이터 전송 없음
블라우영구적센서 기준값의 자동 초기 보정 (VerseGrip을 테이블 위에 움직이지 않게 올려놓으십시오)
그뤼ン블링켄어댑터 연결됨, VerseGrip이 활성 데이터 전송 모드임
Aus조명 없음종료, 전원 끄기
충전 표시기 색상조명 시퀀스설명
블라우영구적적재된
빠른 깜빡임충전이 거의 완료되었습니다
Aus조명 없음충전이 완료되었습니다

예제 코드​

다음은 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);

}
}