C++/Python SDK_Quaternion Manual
1. Introduction
1.1. Feature
Obtain the quaternion of each joint through this SDK.
1.2. File Download
The quaternion SDK is open sourced.
Download address:
1.3. HandDriver Settings
Check "Data Transmission" to turn on the data transmission.
To transmit IMU data (only supported by gloves with IMU), select the IMU option; otherwise, IMU data will not be transmitted.
Select "Quater" as the data format of the transmission.
Select the FPS, which supports 120Hz, 90Hz, or 60Hz. The default FPS is 120Hz.
Click the "+" icon in the target address field, then enter the IP address and port number of the receiving side to enable data transmission (input 127.0.0.1 for local target).
The default port number is 5555. Unless otherwise specified, use this default port. Otherwise, modify the corresponding port number in the plugin.
After configuration, click the "Apply" button to save.

2. Coordinate system and data definition
2.1. Coordinate system
The data sent by the HandDriver follows a right-hand coordinate system standard, with the blue Z-axis pointing upwards, as shown in below figure:

2.2. Data format
The data content includes Device ID, Frame index, Device name, Calibration status, Battery, IMU data, bones quaternion and controllers data, as shown in below figure. Note: The quaternion order for fingers is XYZW, while for IMU it is WXYZ.

Index, Middle, Ring, Little Finger
MP
PIP
DIP
Thumb
CM
MP
IP
{
"DeviceID":0, //According to the HandDriver role list, the first role is "0", the second is "1", and so on
"FrameIndex":0,
"DeviceName":"UDXST0001L",
"CalibrationStatus":-1,//Uncalibrated -1, Fist 0, Fingers Straight&Together 1, Spread Fingers 2, Finish 3
"Battery":5,//Battery 1-5, max 5
"Bones":[
[1,1,1,1],//{"LeftindexProximal":[1,1,1,1]}
[1,1,1,1],//{"LeftindexIntermediate":[1,1,1,1]}
[1,1,1,1],//{"LeftindexDistal":[1,1,1,1]}
[1,1,1,1],//{"LeftMiddleProximal":[1,1,1,1]}
[1,1,1,1],//{"LeftMiddlelntermediate":[1,1,1,1]}
[1,1,1,1],//{"LeftMiddleDistal":[1,1,1,1]}
[1,1,1,1],//{"LeftRingProximal":[1,1,1,1]}
[1,1,1,1],//{"LeftRingIntermediate":[1,1,1,1]}
[1,1,1,1],//{"LeftRingDistal":[1,1,1,1]}
[1,1,1,1],//{"LeftLittleProximal":[1,1,1,1]}
[1,1,1,1],//{"LeftLittlelntermediate":[1,1,1,1]}
[1,1,1,1],//{"LeftLittleDistal":[1,1,1,1]}
[1,1,1,1],//{"LeftThumbProximal":[1,1,1,1]}
[1,1,1,1],//{"LeftThumbintermediate":[1,1,1,1]}
[1,1,1,1],//{"LeftThumbDistal":[1,1,1,1]}
[1,1,1,1],//{"IMU Data":[1,1,1,1]}
]
"joyX":0,
"joyY":0,
"aButton":false,
"bButton":false,
"joyButton":false,
"menu":false
}
3. Windows SDK Description
This DLL contains a GloveSDK class, which is used to create a separate receiving thread to receive and parse data sent by HandDriver.
3.1. Data structure definition
struct HandDriverData
{
int DeviceID=0;
int FrameIndex=0;
string DeviceName;
int CalibrationStatus;
int Battery;
// 15 finger joints, each with 4 data points, 16th is for IMU data
array<array<float, 4>, 16> JointDatas;
};
// This structure stores data for a pair of gloves, divided into L (left) and R (right)
struct PairGloveData
{
HandDriverData HandData_L;
HandDriverData HandData_R;
bool bPrintData;
};
3.2. Data call
3.2.1. Retrieve glove data
3.2.1.1. Retrieve glove driver info
The example of retrieving device information (see Figure), refer to this example to get other information about the device.
//Get the device name on the left hand of device '0'
string deviceName = glovePtr->GloveData[0].HandData_L.DeviceName;
//Get the battery level on the left hand of device '0'
int battery = glovePtr->GloveData[0].HandData_L.Battery;
3.2.1.2. Retrieve glove finger data
The GloveSDK class has an array GloveData with a length of 8, and its format of PairGloveData, meaning it can store data for 8 pairs of gloves. The data is accessed via subscripts.For example: GloveData[0].HandData_L.JointDatas[6]
(accesses the sixth joint data in the left-hand array of device 0. The data corresponding to JointDatas[6]
is shown in Figure.).
auto a = glovePtr->GloveData[0].HandData_L.JointDatas[6];
3.2.2. Quaternion to euler angle
Use glovePtr->toEulerAngle()
to convert a quaternion to Euler angles via glove_sdk
. Pay attention to the quaternion order.
glovePtr->toEulerAngle(a[0], a[1], a[2], a[3], roll, pitch, yaw);
3.2.3. Euler angle to rotation angle
Use the conversion method RadToAngle()
to obtain the rotation angle.
glovePtr->RadToAngle(pitch);
3.3. Interface function definition
3.3.1. Initialization
bool Initialize (const char* udp_ip, unsigned short udp_port);
Function description: Create a Socket according to the parameters. If successful, start a thread to receive data.
Parameter description: udp_ip is the IP address for receiving data, udp_port is the port number, which can be the same as the sending HandDriver.
Return value description: Returns true if successful, false if failed.
3.3.2. Close Thread
void Shutdown ();
Function description: Used to close the receiving thread and clean up the Socket.
Parameter description: None.
Return value description: None.
3.3.3. Registering callback function
void RegisterGloveCallBack(GloveCallBack callback);
Function description: Used to register a callback function, which is called after the program has parsed the JSON data.
Parameter description: callback
is a function of type GloveCallBack
, and the parameter types can be modified in the .h
file.
Return value description: None.
3.3.4. Print thread entry
void print_control_thread(GloveSDK* glove_sdk);
Function description: Used to print data on the console.
Parameter description: GloveSDK object pointer, the printing thread will print its data.
Return value description: None.
3.3.5. Restricting printing content
void OnlyPrintFrame();
Function description: After calling, printing parameters will only print the frame number for debugging.
Parameter description: None.
Return value description: None.
3.4. Demo and description
3.4.1. Demo project description
The HandDriver_x64_Cpp_Quater
project contains the HandDriver_x64_Cpp_Quater
folder and the HandDriver_x64_Cpp_Quater.sln
file. The HandDriver_x64_Cpp_Quater
folder contains the library files. If needed, they can be copied for separate use. The version of Visual Studio is vs2019(When using higher versions, follow the log changes), c++14. Run HandDriver_x64_Cpp_Quater.sln
, select the x64 platform, and run the sample program.

3.4.2. Brief introduction to code flow
Declare a function to register the callback
void OnNewGloveData(GloveSDK* glovePtr) //The cache size defines a function for registering a callback
{
//This function will be called in the receiving thread
//Get finger joint data
auto a = glovePtr->GloveData[0].HandData_L.JointDatas[6];//Get the 6th data
cout << "LeftRingProximal: " << a[1] << endl;//Print the second number of quaternions
glovePtr->toEulerAngle(a[0], a[1], a[2], a[3], roll, pitch, yaw);//Convert quaternions to Euler angles, note that IMU data is in WXYZ order
cout << "roll:" << glovePtr->RadToAngle(roll) << " pitch:" << glovePtr->RadToAngle(pitch) << " yaw:" << glovePtr->RadToAngle(yaw) << endl;//Print angle
}
Create an instance of GloveSDK
//Create an instance of GloveSDK
GloveSDK glove_sdk;
Register callback function
//Registering callback function
glove_sdk.RegisterGloveCallBack(OnNewGloveData);
Create a socket and check if it is successful. If successful, start receiving and parsing data
//Create a Socket and check if it is successful. If successful, receive and parse the data
if (!glove_sdk.Initialize("127.0.0.1", 7777))
{
cerr << "Failed to initialize GloveSDK." << endl;
return -1;
}
Start the print thread and print the glove_sdk data
//Start the print thread and print the glove_sdk data
thread print_th(print_control_thread, &glove_sdk);
Calling the function to print only the frame number
//After calling, only the number of frames is printed
while (true)
{
int a;
cin >> a;
switch (a)
{
case 1:
OnlyPrintFrame();
break;
case 0://Close and clean up the socket
glove_sdk.Shutdown();
printf("Shutdown");
break;
}
}
Waiting for input save program
//Waiting for input, Save program
getchar();
Close and clean up the socket
//close and clean up the socket
glove_sdk.Shutdown();
printf("Shutdown");
Last updated