C++/Python SDK_Angle Manual
1. Introduction
1.1. Feature
This SDK provides access to hand joint angle data and supports different operating system environments, currently including Windows and Linux.
1.2. File Download
(Download the Angle file which is open sourced)
Windows:
Linux: You can refer to the example or compile and run it yourself
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.
The data format options—Euler, Quater, and VMC—are mutually exclusive (Select Euler for current SDK).
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).
For the SDK side, use the IP address format 0.0.0.0.
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 and data description
2.1.1. HandDriver2.1.2 version after 2.1.2.
Please refer to this document:Hand Model and Data Description
2.1.2. HandDriver2.1.1 version before 2.1.1
The data sent refers to the right-hand coordinate system standard, as shown in the figure below.

2.2. Data Format
The sending data is shown in the figure below and includes information such as the character name, calibration status, finger joint rotation angles, IMU quaternion data (only available when the glove is equipped with an IMU and IMU transmission is enabled) and controllers data.

{
"Udhand": { //the corresponding Character name in HandDriver
"Bones": [
{
"Name": "Head",
"Parent": 0,
"Location": [ 0,0,0 ],
"Rotation": [ 0,0,0 ],
"Scale": [ 0,0,0 ]
}
],
"Parameter": [
{ "Name": "L_CalibrationStatus", "Value": 3 },//Left hand calibration status -1:Not calibrated,0:fist,1:fingers together,2:fingers spreading,3:Calibration completed
{ "Name": "l0", "Value": 0 },//Left hand Thumb IP pitch
{ "Name": "l1", "Value": 0 },//Left hand Thumb MP pitch
{ "Name": "l2", "Value": 0 },//Left hand Thumb CM pitch
{ "Name": "l3", "Value": 0 },//Left hand Thumb CM yaw
{ "Name": "l4", "Value": 0 },//Left hand Index DIP pitch
{ "Name": "l5", "Value": 0 },//Left hand Index PIP pitch
{ "Name": "l6", "Value": 0 },//Left hand Index MP pitch
{ "Name": "l7", "Value": 0 },//Left hand Index MP yaw
{ "Name": "l8", "Value": 0 },//Left hand Middle DIP pitch
{ "Name": "l9", "Value": 0 },//Left hand Middle PIP pitch
{ "Name": "l10", "Value": 0 },//Left hand Middle MP pitch
{ "Name": "l11", "Value": 0 },//Left hand Middle MP yaw
{ "Name": "l12", "Value": 0 },//Left hand Ring DIP pitch
{ "Name": "l13", "Value": 0 },//Left hand Ring PIP pitch
{ "Name": "l14", "Value": 0 },//Left hand Ring MP pitch
{ "Name": "l15", "Value": 0 },//Left hand Ring MP yaw
{ "Name": "l16", "Value": 0 },//Left hand Pinky DIP pitch
{ "Name": "l17", "Value": 0 },//Left hand Pinky PIP pitch
{ "Name": "l18", "Value": 0 },//Left hand Pinky MP pitch
{ "Name": "l19", "Value": 0 },//Left hand Pinky MP yaw
{ "Name": "l20", "Value": 0 },//Left hand Thumb CM roll
{ "Name": "l21", "Value": 0 },//Left hand Index MP roll
{ "Name": "l22", "Value": 0 },//Left hand Pinky MP roll
{ "Name": "l23", "Value": -1 },//Left hand Reserved for gesture recognition
{ "Name": "l24", "Value": -1 },//Left hand IMU quaternion-W
{ "Name": "l25", "Value": -1 },//Left hand IMU quaternion-X
{ "Name": "l26", "Value": -1 },//Left hand IMU quaternion-Y
{ "Name": "l27", "Value": -1 },//Left hand IMU quaternion-Z
{ "Name": "l_joyX", "Value": 0 },
{ "Name": "l_joyY", "Value": 0 },
{ "Name": "l_aButton", "Value": false },
{ "Name": "l_bButton", "Value": false },
{ "Name": "l_joyButton", "Value": false },
{ "Name": "l_menu", "Value": false },
{ "Name": "R_CalibrationStatus", "Value": 3 },////Right hand calibration status -1:Not calibrated,0:fist,1:fingers together,2:fingers spreading,3:Calibration completed
{ "Name": "r0", "Value": 0 },//Right hand Thumb IP pitch
{ "Name": "r1", "Value": 0 },//Right hand Thumb MP pitch
{ "Name": "r2", "Value": 0 },//Right hand Thumb CM pitch
{ "Name": "r3", "Value": 0 },//Right hand Thumb CM yaw
{ "Name": "r4", "Value": 0 },//Right hand Index DIP pitch
{ "Name": "r5", "Value": 0 },//Right hand Index PIP pitch
{ "Name": "r6", "Value": 0 },//Right hand Index MP pitch
{ "Name": "r7", "Value": 0 },//Right hand Index MP yaw
{ "Name": "r8", "Value": 0 },//Right hand Middle DIP pitch
{ "Name": "r9", "Value": 0 },//Right hand Middle PIP pitch
{ "Name": "r10", "Value": 0 },//Right hand Middle MP pitch
{ "Name": "r11", "Value": 0 },//Right hand Middle MP yaw
{ "Name": "r12", "Value": 0 },//Right hand Ring DIP pitch
{ "Name": "r13", "Value": 0 },//Right hand Ring PIP pitch
{ "Name": "r14", "Value": 0 },//Right hand Ring MP pitch
{ "Name": "r15", "Value": 0 },//Right hand Ring MP yaw
{ "Name": "r16", "Value": 0 },//Right hand Pinky DIP pitch
{ "Name": "r17", "Value": 0 },//Right hand Pinky PIP pitch
{ "Name": "r18", "Value": 0 },//Right hand Pinky MP pitch
{ "Name": "r19", "Value": 0 },//Right hand Pinky MP yaw
{ "Name": "r20", "Value": 0 },//Right hand Thumb CM roll
{ "Name": "r21", "Value": 0 },//Right hand Index MP roll
{ "Name": "r22", "Value": 0 },//Right hand Pinky MP roll
{ "Name": "r23", "Value": -1 },//Right hand Reserved for gesture recognition
{ "Name": "r24", "Value": -1 },//Right hand IMU quaternion-W
{ "Name": "r25", "Value": -1 },//Right hand IMU quaternion-X
{ "Name": "r26", "Value": -1 },//Right hand IMU quaternion-Y
{ "Name": "r27", "Value": -1 },//Right hand IMU quaternion-Z
{ "Name": "r_joyX", "Value": 0 },
{ "Name": "r_joyY", "Value": 0 },
{ "Name": "r_aButton", "Value": false },
{ "Name": "r_bButton", "Value": false },
{ "Name": "r_joyButton", "Value": false },
{ "Name": "r_menu", "Value": false }
]
}
}
2.3. The Receiving Angle
Regarding the receiving angle value, please refer to the HandDriver data page. The data on this page is consistent with the SDK receiving data.
Consistent positive and negative
Specific values are expressed as integers when displayed in HandDriver
For detailed instructions, please see here: UDEXREAL HandDriver Hand Model and Data Description

3. C++ Windows SDK
3.1. Data Structure Definition
3.1.1. Character list
vector<GloveData>gloveDataList;
Data Structure Description: Save received character data.
Parameter Description: GloverData
contains information for a single character.
3.1.2. Glove data
struct GloveData
{
string deviceName;
HandData handDatas;
};
Data Structure Description: Save the character's name and hand data.
Parameter Description: handDatas
contains the hand data for a single character.
3.1.3. Hand data
struct HandData
{
Bone bones;
handsfingerJoint fingerJoints;
};
Data Structure Description: Save the character's skeletal data and finger joint data.
Parameter Description: bones
contain the glove skeletal data, while fingerJoints
contain the glove finger joint data.
3.1.4. Bone data
struct Bone
{
string name;
int parent = 0;
vector<float> location = {};
vector<float> rotation = {};
vector<float> scale = {};
};
Data Structure Description: Save skeletal data.
Parameter Description: Used for adapting data formats for Unreal Engine; the information is currently not in use.
3.1.5. Finger joint data
struct handsfingerJoint
{
vector<Parameter> fingerJoint_L;
vector<Parameter> fingerJoint_R;
};
Data Structure Description: Save the finger joint data for both hands of the character, including the hand calibration status.
Parameter Description: fingerJoint_L
contains the data for the character's left hand, while fingerJoint_R
contains the data for the character's right hand.
3.2. Data Calling
3.2.1. Retrieve glove data
3.2.1.1. Retrieve glove driver info
Example for retrieving device information. You can obtain other device information in a similar manner.
//Retrieve the character name for the device; "0" indicates the first device.
string name = glovePtr->gloveDataList[0].deviceName;
//Retrieve the left hand calibration status; note that this information is stored in the finger data array.
float L_CalibrationStatus= glovePtr->gloveDataList[0].handDatas.fingerJoints.fingerJoint_L[0].value;
3.2.1.2. Retrieve Finger Joint Rotation Data from the Glove
In the GloveSDK
class, there is an array gloveDataList
of type GloveData
, which stores data for all gloves. Access it using the index, for example: glovePtr->gloveDataList[0].handDatas.fingerJoints.fingerJoint_L[6].value
(Accessed the pitch data of the second phalanx of the left hand index finger for device 0, where fingerJoint_L[6]
corresponds to the image in The corresponding parameters are viewed in the data format.)。
//Retrieve left hand Index intermediate pitch
float L_indexIntermediate pitch= glovePtr->gloveDataList[0].handDatas.fingerJoints.fingerJoint_L[6].value;
3.3. Definition of Interface
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 print all data for a character to check the data status.
Parameter Description: inputGloveData
is a function of type GloveData
, which takes a GloveData
object as input when called.
Return value description: None.
3.4. Windows Demo and Description
3.4.1. Demo project description
The HandDriver_x64_Cpp_Angle
project contains the HandDriver_x64_Cpp_Angle
folder and the HandDriver_x64_Cpp_Angle.sln
file. The HandDriver_x64_Cpp_Angle
folder includes the library files, which can be copied for standalone use. The version of Visual Studio is VS2019(When using higher versions, follow the log changes), using C++14. To run the example program, open HandDriver_x64_Cpp_Angle.sln
and select the x64 platform.

3.4.2. Brief introduction to code flow
Declare a function to register the callback
void OnNewGloveData(GloveSDK* glovePtr)
{
/*
* 打印手数据
* Print gloveData
*/
//Print all data for character "0"
glovePtr->ShowGloveData(glovePtr->gloveDataList[0]);
cout << endl << endl;
}
Create an instance of GloveSDK
GloveSDK glove_sdk;
Register callback function
glove_sdk.RegisterGloveCallBack(OnNewGloveData);
Create a socket and check if it is successful. If successful, start receiving and parsing data
if (!glove_sdk.Initialize("127.0.0.1", 5555))
{
cerr << "Failed to initialize GloveSDK." << endl;
return -1;
}
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
while (true)
{
int a;
cin >> a;
switch (a)
{
case 1:
OnlyPrintFrame();
break;
case 0:
glove_sdk.Shutdown();
printf("Shutdown");
break;
}
}
Waiting for input save program
getchar();
Close and clean up the socket
glove_sdk.Shutdown();
printf("Shutdown");
4. C++ Linux SDK
4.1. File Directory
The Linux Cpp SDK folder contains: the folder "include" (which contains the header files required for JSON parsing), the folder "lib" (which contains the necessary JSON dynamic libraries such as libjsoncpp.so and libjsoncpp.so.27), UDEServer.h (the SDK header file), UDEServer.cxx (the implementation of methods), main.cxx (an example), build.sh (an example build file), CMakeLists.txt, and ReadMe.txt.

4.2. Data Format
Please click here for the format.
4.3. Data Calling
Include the header file UDEServer.h first and complete the initialization of the server.The method for obtaining the received list of character names is as follows:
#include "UDEServer.h"
//create new SDK instance
UDEGloveSDK sdk;
//initialization method
sdk.Initialize();
//start server listening
sdk.StartListening();
//Call the GetRoleNameList() method to get the list of received character names
vector<string> list = sdk.GetRoleNameList();
The default port number of the server is 5555. You can obtain the current port number or set the port through below method:
int port = sdk.GetPortNum();
int newPort = 1234;
sdk.SetPortNum(newPort);
Close data reception or obtain current status in server listening.
//Server status enumeration parameters
enum ServerStatus
{
NO_INIT,
READY,
IN_LISTENING,
END
};
int status = sdk.GetStatus()
//close server listener
sdk.EndListening();
According to the specified character name, all knuckle data can be obtained with the type of vector. The names of the finger joints and the array of Euler angles can be obtained corresponding to the index order in GloveDataHeaders. The controller data can also be obtained. An array of the type float can be obtained according to the index order in ControllerHeaders, which corresponds to the controller parameters.
//Vector3Float struct
struct Vector3Float
{
float x;
float y;
float z;
Vector3Float(float X, float Y, float Z)
{
this->x = X;
this->y = Y;
this->z = Z;
}
};
//The name index corresponding to the return value of the finger joint
string GloveDataHeaders[30] =
{
"LeftThumb1",
"LeftThumb2",
"LeftThumb3",
"LeftIndex1",
"LeftIndex2",
"LeftIndex3",
"LeftMiddle1",
"LeftMiddle2",
"LeftMiddle3",
"LeftRing1",
"LeftRing2",
"LeftRing3",
"LeftPinky1",
"LeftPinky2",
"LeftPinky3",
"RightThumb1",
"RightThumb2",
"RightThumb3",
"RightIndex1",
"RightIndex2",
"RightIndex3",
"RightMiddle1",
"RightMiddle2",
"RightMiddle3",
"RightRing1",
"RightRing2",
"RightRing3",
"RightPinky1",
"RightPinky2",
"RightPinky3",
};
//The name index corresponding to the controller return value
string ControllerHeaders[12] =
{
"Left Joy X",
"Left Joy Y",
"Left A Button",
"Left B Button",
"Left Joy Button",
"Left Menu Button",
"Right Joy X",
"Right Joy Y",
"Right A Button",
"Right B Button",
"Right Joy Button",
"Right Menu Button"
};
vector<string> list = sdk.GetRoleNameList();
if(list.size() > 0)
{
//Get the data of the first character by default
auto FingerData = sdk.GetVecFingerData(list[0]);
//Controller parameters
auto ControllerData = sdk.GetVecControllerData(list[0]);
}
The corresponding entries obtained are as follows:
{
"LeftThumb1", {0, 0, 0};
"LeftThumb2", {0, 0, 0};
"LeftThumb3", {0, 0, 0};
...
"RightThumb1", {0, 0, 0};
"RightThumb2", {0, 0, 0};
"RightThumb3", {0, 0, 0};
...
"Left Joy X", 0;
"Left Joy Y", 0;
"Left A Button", 0;
"Left B Button", 0;
...
}
The rules for knuckle names are Left/Right + Thumb/Index/Middle/Ring/Pinky + 1/2/3 (joint 1/joint 2/joint 3). The order of the angle array is {pitch, yaw, roll}.
Joy X and Joy Y in the controller data correspond to joystick parameters, ranging from (-1,1) as floating numbers. All other button parameters are also set to floating numbers 0 or 1 for consistency, corresponding to untriggered or triggered.
4.4. Definition of Interface
Initialization
int Initialize();
Function description: Socket initialization, including the required declaration and calling to create a server.
Return value description: If successful, return 0; if failed, return -1.
Set Port Number
void SetPortNum(int port);
Function description: Set the server listener port number.
Parameter description: The port number is integer type.
Get Port Number
int GetPortNum();
Function description: Get the server listener port number.
Return value description: The port number is integer type.
Start server listener
void StartListening();
Function Description: The start server listener method can obtain parameters in the loop.
Shut down server listener
void EndListening();
Function description: Close the server listener.
Get server status
ServerStatus GetStatus();
Function description: Get the current server status.
Return value description: ServerStatus enumeration parameter, 0 means NO_INIT (not initialized), 1 means READY, 2 means IN_LISTENING (listening), 3 means END (listening terminated).
Get a list of character names
vector<string> GetRoleNameList();
Function description: Get a string list of all received character names.
Return value description: name string array.
Get knuckle data
map<string, vector<float>> GetFingerData(string RoleName);
Function description: Get the knuckle data of the specified character.
Parameter description: Character name in String type.
Return value description: Euler angle array sorted in the same order as the character index in GloveDataHeaders.
Get controller data
map<string, float> GetControllerData(string RoleName);
Function description: Get controller data for the specified character.
Parameter description: Character name in String type.
Return value description: A float array sorted in the same order as the character index in ControlHeaders.
4.5. Example
The main.cxx provides an example of calling the SDK interface within the main method to receive and print data. An executable file can be generated by running build.sh.
Start the "Terminal", enter the root folder of the SDK, run the following command:
$ sudo sh ./build.sh
This can generate an executable example ServerSample, which can be run in the same directory using the following command:
$ ./ServerSample
And then the link library libUDEServer.so of the project can be found in the folder "build".
5. Python Linux SDK
5.1. Data Format
Please click here for the format.
5.2. Data Calling
The method for obtaining the received list of character names is as follows:
sdk = UDEGloveSDK() # Create an instance of the SDK
sdk.initialize() # Initialize the SDK
sdk.start_listening() # Start listening for data
role_list = sdk.get_role_name_list() # Get the list of role names
The default port number of the server is 5555. You can obtain the current port number or set the port through below method:
self.port = 5555 # Port number for the server
self.sock = None # Socket object for communication
self.server_addr = ("0.0.0.0", self.port) # Server address and port
Close data reception or obtain current status in server listening.
# Enum-like class to represent server status
class ServerStatus:
NO_INIT = 0 # Server not initialized
READY = 1 # Server ready
IN_LISTENING = 2 # Server is listening for data
END = 3 # Server has stopped
status = sdk.cur_status # Get the current server status
sdk.end_listening() # Stop listening
According to the specified character name, all knuckle data can be obtained with the type of vector. The names of the finger joints and the array of Euler angles can be obtained corresponding to the index order in GloveDataHeaders. The controller data can also be obtained. An array of the type float can be obtained according to the index order in ControllerHeaders, which corresponds to the controller parameters.
# Class representing a 3D vector with float values
class Vector3Float:
def __init__(self, x: float, y: float, z: float):
self.x = x
self.y = y
self.z = z
# Headers for glove data
GloveDataHeaders = [
"LeftThumb1", "LeftThumb2", "LeftThumb3", "LeftIndex1", "LeftIndex2", "LeftIndex3",
"LeftMiddle1", "LeftMiddle2", "LeftMiddle3", "LeftRing1", "LeftRing2", "LeftRing3",
"LeftPinky1", "LeftPinky2", "LeftPinky3", "RightThumb1", "RightThumb2", "RightThumb3",
"RightIndex1", "RightIndex2", "RightIndex3", "RightMiddle1", "RightMiddle2", "RightMiddle3",
"RightRing1", "RightRing2", "RightRing3", "RightPinky1", "RightPinky2", "RightPinky3"
]
# Headers for controller data
ControllerHeaders = [
"Left Joy X", "Left Joy Y", "Left A Button", "Left B Button", "Left Joy Button",
"Left Menu Button", "Right Joy X", "Right Joy Y", "Right A Button", "Right B Button",
"Right Joy Button", "Right Menu Button"
]
role_list = sdk.get_role_name_list() # Get the list of role names
if len(role_list) > 0:
for role_name in role_list:
finger_data = sdk.get_vec_finger_data(role_name) # Get finger data
controller_data = sdk.get_vec_controller_data(role_name) # Get controller data
The corresponding entry examples obtained are as follows:
{
"LeftThumb1", {0, 0, 0};
"LeftThumb2", {0, 0, 0};
"LeftThumb3", {0, 0, 0};
...
"RightThumb1", {0, 0, 0};
"RightThumb2", {0, 0, 0};
"RightThumb3", {0, 0, 0};
...
"Left Joy X", 0;
"Left Joy Y", 0;
"Left A Button", 0;
"Left B Button", 0;
...
}
The rules for knuckle names are Left/Right + Thumb/Index/Middle/Ring/Pinky + 1/2/3 (joint 1/joint 2/joint 3). The order of the angle array is {pitch, yaw, roll}.
Joy X and Joy Y in the controller data correspond to joystick parameters, ranging from (-1,1) as floating numbers. All other button parameters are also set to floating numbers 0 or 1 for consistency, corresponding to untriggered or triggered.
5.3. Definition of Interface
Initialization
def initialize(self):
Function description: Socket initialization, including the required declaration and calling to create a server.
Return value description: If successful, return 0; if failed, return -1.
Set Port Number
def __init__(self):
self.port = 5555
Function description: Set the port number of server listener.
Parameter description: The port number is integer type.
Get Port Number
Port = sdk.port
Function description: Get the port number of server listener.
Return value description: The port number is integer type.
Start service listener
def start_listening(self):
Function description: start service listener.
Shut down server listener
def end_listening(self):
Function description: Close the server listener.
Get server status
status = sdk.cur_status
Function description: Get the current server status.
Return value description: ServerStatus enumeration parameter, 0 means NO_INIT (not initialized), 1 means READY, 2 means IN_LISTENING (listening), 3 means END (listening terminated).
Get a list of character names
def get_role_name_list(self) -> List[str]:
Function description: Get a string list of all received character names.
Return value description: name string array.
Get knuckle data
def get_vec_finger_data(self, role_name: str) -> List[Vector3Float]:
Function description: Get the knuckle data of the specified character.
Parameter description: Character name in String type.
Return value description: Euler angle array sorted in the same order as the character index in GloveDataHeaders.
Get controller data
def get_vec_controller_data(self, role_name: str) -> List[float]:
Function description: Get the controller data of the specified character.
Parameter description: Character name in String type.
Return value description: A float array sorted in the same order as the character index in ControlHeaders.
5.4. Example
Start "Terminal" in the directory where the .py file is located and run the following command:
$ python3 HandDriver_Linux_Py_Angle_20250402.py
Last updated