Quick Start: Stylus VerseGrip
VerseGrips add orientation tracking abilities to the Inverse3. This article outlines the Stylus VerseGrip setup procedure and its features.
The Stylus VerseGrip
The Stylus VerseGrip PROTOTYPE Inverse3 applies cutting-edge, proprietary edge high-speed wireless communication technology to provide orientation and in-your-hand I/O. Reimagining what is possible in this space for unmatched versatility.
Some of the incredible features we made for you:
- 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 VerseGrips can pair to a dongle on a single band
Customer Support
If you ever have questions or concerns about your device and how to use it, don’t hesitate to contact us, we would be happy to help answer your questions. The Stylus VerseGrip PROTOTYPE is a functional device with complex and proprietary wireless technology inside. Any attempt to open the device will not only void your warranty but may very quickly render the device unusable. To prevent lengthy shipping and costly repair processes, DO NOT ATTEMPT TO OPEN THE DEVICE.
Stylus VerseGrip SetUp and Calibration
This section outlines the steps of plugging in the dongle, turning on your VerseGrip,, 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.
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, 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 Stylus VerseGrip into power via the USB-C charging receptacle.
- The charging light will be blue when plugged into power, and fully charged it will rapidly blink blue. When you plug into power the device will start and go into standby.
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 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);
}
}