Quick Start: VerseGrip Stylus
VerseGrips add orientation tracking abilities to the Inverse3. This article outlines the VerseGrip Stylus setup procedure and its features.
The VerseGrip Stylus
The VerseGrip Stylus Inverse3 uses proprietary high-speed wireless communication technology to provide orientation tracking and in-hand input/output (I/O). It is engineered for versatility across a range of applications.
Key features include:
- 2 user input buttons,
- 1 calibration button,
- 1 power/standby button, and
- 2 indicator RGB LED lights
- 10-12 hours battery life
- USB-c connection for charging
- Wireless communication speed up to 1 KHz
- Up to 8 VerseGrip Stylus can pair to a dongle on a single band
The VerseGrip Stylus has seven main features on the outside: (1) The ball connector which fits into the Inverse3 gimbal, (2) and (3) Input buttons, (4) USB-C charging port, (5) Calibration button, (6) Status LEDs, and (7) A power button.
Customer Support
If you have any questions or concerns about your device or its operation, please contact our support team for assistance. The VerseGrip Stylus contains complex, proprietary wireless technology. Opening the device will void your warranty and may render it inoperable. To avoid extended shipping times and expensive repairs, DO NOT OPEN THE DEVICE.
VerseGrip Stylus Setup and Calibration
This section outlines the steps of plugging in the dongle, turning on your VerseGrip Stylus, and calibration.
Set Up
- Plug in the dongle into a USB receptacle in your computer.
- Put the handle on a flat surface where it wont move, buttons facing upwards and ball connector pointed towards the screen.
Power On and Calibration
- Press the power button once. The status light will turn red, then change to blue. Blue indicates that the IMU in the device is undergoing self-calibration.
- After self-calibration the status light will blink red once every 0.5 seconds. This is standby mode.
- Press any button to wake the device up from standby mode. You will see the status light flashing green while it’s walking up, and then turn to solid green. It is now transmitting data to wireless.
- When battery is low, the VerseGrip Stylus will turn itself off every 2 minutes; please recharge right away.
Recalibration
- To recalibrate, press and hold the calibration button for three seconds, or until you see that the orientation has shifted in your simulation.
Standby and Power Off
- Press the power button again to go back into standby mode. The status light will go red, blinking every 2 seconds, and data transmission will stop.
- To turn off the VerseGrip Stylus, hold the power button for 5 seconds and let go. When you let go, the status light should turn off and there will be no indications. It will stop transmitting data.
Charging
- Plug the VerseGrip Stylus into power via the USB-C charging receptacle.
- The charging light will be blue when plugged into power, and when fully charged it will rapidly blink blue. When you plug into power the device will start and go into standby.
WARNING: Do not allow the battery to fully discharge. Once depleted, it may not retain a charge. If this happens, the VerseGrip Stylus will continue to operate as long as it remains plugged in. This is only an issue for VerseGrip Stylus devices shipped between August and December 2024. Contact Haply Support to receive the firmware update which fixes this issue.
States and Light Indicators
Status Light Colour and Behaviour | State |
---|---|
Red, solid | Pending initialization of components |
Blue, solid | IMU in handle is undergoing self calibration |
Red, blinking every 2 seconds | Standby mode. No data transmission. |
Green, blinking every 2 seconds | Normal mode, automatically transmitting data to wireless. |
No light, no indication | The power is off. |
Charging Indicator Light Colour | State |
---|---|
Blue, solid | Charging |
Blue, rapidly blinking | This indicates the device is fully charged. |
No light, no indication | The device is not charging |
Sample code
Here’s a simple example of how to use the Versegrip Stylus with C++.
- Inverse SDK
- HardwareAPI
#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);
}
}