# Protobuf C++/Python SDK Manual

## 1. Introduction

### 1.1. Feature

This SDK acquires joint angles or quaternion data of the hand based on the Protobuf transmission format, supporting both Windows and Linux environments.

### 1.2. Download

<table><thead><tr><th width="101">Language</th><th width="103.5">OS</th><th width="93">OS Version</th><th>Description</th><th width="104.5">Download Link</th><th>Package Name Format</th></tr></thead><tbody><tr><td>CPP</td><td>Windows</td><td></td><td></td><td><a href="https://drive.google.com/drive/folders/1d1tvXMKl1VfYtydpMC73PxLrrYI5Adro?usp=drive_link">Download</a></td><td>HandDriver_Win_x64_Cpp_Protobuf_src_yyyymmddmmss</td></tr><tr><td>CPP</td><td>Ubuntu</td><td>22&#x26;24, amd</td><td></td><td><a href="https://drive.google.com/drive/folders/16uS8CqG3d3ts3YCvBEgy6MSfyyUtyGlb?usp=drive_link">Download</a></td><td>HandDriver_Linux_Cpp_Protobuf_src_yyyymmddmmss</td></tr><tr><td>CPP</td><td>Ubuntu</td><td>22&#x26;24, amd</td><td>Requires compilation before use.</td><td><a href="https://drive.google.com/drive/folders/16uS8CqG3d3ts3YCvBEgy6MSfyyUtyGlb?usp=drive_link">Download</a></td><td>HandDriver_Linux_Cpp_Protobuf_src_yyyymmddmmss</td></tr><tr><td>CPP</td><td>Ubuntu</td><td>20 amd</td><td>Requires compilation before use.</td><td><a href="https://drive.google.com/drive/folders/16uS8CqG3d3ts3YCvBEgy6MSfyyUtyGlb?usp=drive_link">Download</a></td><td>HandDriver_Linux_Cpp_Protobuf_src_yyyymmddmmss</td></tr><tr><td>Python</td><td>Windows<br>Ubuntu</td><td></td><td></td><td><a href="https://drive.google.com/drive/folders/1IvNKkvmgF1BGRKzS_IUknvXvWzYPf-GM?usp=drive_link">Download</a></td><td>HandDriver_Py_Protobuf_src_yyyymmddmmss</td></tr></tbody></table>

### 1.3. HandDriver Configuration

* Check "Data Transmission" to turn on the data transmission.
* Select the Format: Protobuf.
* Choose the Content: Euler or Quater. (Typically, the robotics field prefers Euler.)
* Options: To transmit IMU data (only supported for gloves with IMU sensors), check the IMU option; otherwise, IMU data will not be transmitted.
* The Old Plugin does not apply here.
* Select the FPS, which supports 120Hz, 90Hz, and 60Hz. The default FPS is 120Hz.
* In the target address section, click the "+" icon, then enter the IP address and port number of the receiving end to enable data transmission. (For local transmission, enter 127.0.0.1.)
* Multiple target addresses can be set.
* After completing the settings, click the "Apply" button to save.

<figure><img src="https://2082502898-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8s1Ia6TfFovgyJ5JsDJZ%2Fuploads%2FId5me6JyS9RCfmxQrZol%2Fimage.png?alt=media&#x26;token=1f272a10-3647-4ffb-a80b-6dc522c6c2a2" alt="" width="563"><figcaption></figcaption></figure>

## 2. Coordinate System and Data Definitions

### 2.1. Coordinate System and Data Description

{% content-ref url="hand-model-and-data-specification" %}
[hand-model-and-data-specification](https://udexreal.gitbook.io/udexreal-docs/glove-data-c++-python-sdk-for-robotics/hand-model-and-data-specification)
{% endcontent-ref %}

### 2.2. Protocol Buffer Definition File

The Protocol Buffer definition file is as follows:

<figure><img src="https://2082502898-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8s1Ia6TfFovgyJ5JsDJZ%2Fuploads%2Fvw4QOusGWZnaoIIBGQMl%2Fimage.png?alt=media&#x26;token=fa9f5547-1c5b-4a56-befe-fdb070267a5b" alt="" width="375"><figcaption></figcaption></figure>

#### handdriver\_teleop.proto

```protobuf
syntax = "proto3";

package HandDriver;

import "handdriver_algebra.proto";

// Index description for joints array (Angle)
enum JointsIndex_Angle
{
    THUMB_DISTAL_PITCH = 0;         // Thumb Distal Pitch
    THUMB_INTERMEDIATE_PITCH = 1;   // Thumb Intermediate Pitch
    THUMB_PROXIMAL_PITCH = 2;       // Thumb Proximal Pitch
    THUMB_PROXIMAL_YAW = 3;         // Thumb Proximal Yaw
    INDEX_DISTAL_PITCH = 4;         // Index Distal Pitch
    INDEX_INTERMEDIATE_PITCH = 5;   // Index Intermediate Pitch
    INDEX_PROXIMAL_PITCH = 6;       // Index Proximal Pitch
    INDEX_PROXIMAL_YAW = 7;         // Index Proximal Yaw
    MIDDLE_DISTAL_PITCH = 8;        // Middle Distal Pitch
    MIDDLE_INTERMEDIATE_PITCH = 9;  // Middle Intermediate Pitch
    MIDDLE_PROXIMAL_PITCH = 10;     // Middle Proximal Pitch
    MIDDLE_PROXIMAL_YAW = 11;       // Middle Proximal Yaw
    RING_DISTAL_PITCH = 12;         // Ring Distal Pitch
    RING_INTERMEDIATE_PITCH = 13;   // Ring Intermediate Pitch
    RING_PROXIMAL_PITCH = 14;       // Ring Proximal Pitch
    RING_PROXIMAL_YAW = 15;         // Ring Proximal Yaw
    PINKY_DISTAL_PITCH = 16;        // Pinky Distal Pitch
    PINKY_INTERMEDIATE_PITCH = 17;  // Pinky Intermediate Pitch
    PINKY_PROXIMAL_PITCH = 18;      // Pinky Proximal Pitch
    PINKY_PROXIMAL_YAW = 19;        // Pinky Proximal Yaw
    THUMB_PROXIMAL_ROLL = 20;       // Thumb Proximal Roll
    INDEX_PROXIMAL_ROLL = 21;       // Index Proximal Roll
    PINKY_PROXIMAL_ROLL = 22;       // Pinky Proximal Roll
}

// Index description for joints array (Quat)
enum JointsIndex_Quat{
    INDEX_PROXIMAL = 0;       // Index Proximal
    INDEX_INTERMEDIATE = 1;   // Index Intermediate
    INDEX_DISTAL = 2;         // Index Distal
    MIDDLE_PROXIMAL = 3;      // Middle Proximal
    MIDDLE_INTERMEDIATE = 4;  // Middle Intermediate
    MIDDLE_DISTAL = 5;        // Middle Distal
    RING_PROXIMAL = 6;        // Ring Proximal
    RING_INTERMEDIATE = 7;    // Ring Intermediate
    RING_DISTAL = 8;          // Ring Distal
    PINKY_PROXIMAL = 9;       // Pinky Proximal
    PINKY_INTERMEDIATE = 10;  // Pinky Intermediate
    PINKY_DISTAL = 11;        // Pinky Distal
    THUMB_PROXIMAL = 12;      // Thumb Proximal
    THUMB_INTERMEDIATE = 13;  // Thumb Intermediate
    THUMB_DISTAL = 14;        // Thumb Distal
}

message GloveHandDataAngle{
  string serialNumber = 1;      // Device Serial Number
  int32 battery = 2;            // Battery Level
  int32 calibrationState = 3;   // Calibration State
  bool aButton = 4;             // A Button State
  bool bButton = 5;             // B Button State
  bool menuButton = 6;          // Menu Button State
  bool joyButton = 7;           // Joystick Button State
  Vec2 joyPosition = 8;         // Joystick Position
  Quat imu = 9;                 // Hand IMU Orientation
  repeated float joints = 10;   // Joint Angles
  int32 gesture = 11;           // Recognized Gesture Index
}

message GloveHandDataQuat{
  string serialNumber = 1;      // Device Serial Number
  int32 battery = 2;            // Battery Level
  int32 calibrationState = 3;   // Calibration State
  bool aButton = 4;             // A Button State
  bool bButton = 5;             // B Button State
  bool menuButton = 6;          // Menu Button State
  bool joyButton = 7;           // Joystick Button State
  Vec2 joyPosition = 8;         // Joystick Position
  Quat imu = 9;                 // Hand IMU Orientation
  repeated Quat joints = 10;    // Joint API Rotations
  int32 gesture = 11;           // Recognized Gesture Index
}

message TeleopDataAngle
{
  int64 TimeStamp = 1; // Milliseconds
  uint64 FrameIndex = 2; // Frame index at start of transmission
  string RoleName = 3;         // User Role Name
  GloveHandDataAngle LeftHand = 4;  // Left Hand Data
  GloveHandDataAngle RightHand = 5; // Right Hand Data
}

message TeleopDataQuat
{
  int64 TimeStamp = 1; // Milliseconds
  uint64 FrameIndex = 2; // Frame index at start of transmission
  string RoleName = 3;         // User Role Name
  GloveHandDataQuat LeftHand = 4;   // Left Hand Data
  GloveHandDataQuat RightHand = 5;  // Right Hand Data
}
```

#### handdriver\_teleop.proto

```protobuf
syntax = "proto3";

package HandDriver;

message Vec2 {
  float x = 1;
  float y = 2;
}

message Vec3 {
  float x = 1;
  float y = 2;
  float z = 3;
}

message Quat {
  float x = 1;
  float y = 2;
  float z = 3;
  float w = 4;
}
```

### 2.3. Angle Value Reception Notes

Regarding the received angle values, please refer to the data page in the HandDriver. The data displayed on that page is consistent with the data received by the SDK:

* Sign conventions are consistent.
* Specific numerical values are displayed as integers in HandDriver.
* For detailed explanations, please refer to:

{% content-ref url="hand-model-and-data-specification" %}
[hand-model-and-data-specification](https://udexreal.gitbook.io/udexreal-docs/glove-data-c++-python-sdk-for-robotics/hand-model-and-data-specification)
{% endcontent-ref %}

<figure><img src="https://2082502898-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8s1Ia6TfFovgyJ5JsDJZ%2Fuploads%2F2rtYhJ6ZqwtL1E455Hom%2Fimage.png?alt=media&#x26;token=cc5a5333-0f77-459c-a279-ace87f7b43c5" alt="" width="563"><figcaption></figcaption></figure>

## 3. C++ SDK Windows

This project is a C++ application designed for real-time reception and parsing of hand data. It utilizes Windows Socket (Winsock2) for UDP communication and integrates Google Protocol Buffers (Protobuf) for serialized data parsing.

### 3.1. Overview

This program operates as a UDP server, listening for broadcast or unicast data packets on a specified port.

**Core Features:**

* **UDP Communication:** Based on the UDP protocol to ensure low-latency data transmission.
* **Protobuf Parsing:** Supports parsing two core data packet types:
  * `TeleopDataAngle`: Data based on joint angles (suitable for robotic hand control).
  * `TeleopDataQuat`: Data based on quaternions (suitable for 3D rendering/Unity/UE).
* **Cross-Platform Design:** The core logic is compatible with Linux, while the network layer is adapted for Windows using Winsock2.

### 3.2. Structure

```
d:/udp_receiver_cpp/
├── CMakeLists.txt              # CMake build script, managing dependencies and compilation rules
├── main.cpp                    # Main program entry point, containing Socket logic and data printing
├── handdriver_teleop.proto     # Core data protocol definitions (hand data, telemetry packets)
├── handdriver_algebra.proto    # Basic mathematical type definitions (vectors, quaternions)
├── build/                      # (Auto-generated) CMake build directory
   └── Release/                # Output directory for compiled Release executable files
```

### 3.3. Environment Setup and Compilation

This project relies on **CMake** for build management and **vcpkg** for third-party library (Protobuf) management.

#### 3.3.1. Dependency Preparation

1. **Install Visual Studio**: Ensure the "Desktop development with C++" workload is included.
2. **Install CMake**: Version 3.10 or higher is recommended.
3. **Install vcpkg**:
   * Download vcpkg and run `bootstrap-vcpkg.bat`.
   * Install the Protobuf library: `powershell vcpkg install protobuf:x64-windows`

#### 3.3.2. Compilation Steps

We provide two compilation modes: **Release** (recommended, better performance) and **Debug** (for debugging purposes).

{% stepper %}
{% step %}
**Generate Project Files**

In the project root directory, use CMake to configure the project. Please ensure you replace the path with your local vcpkg path.

```powershell
# Replace <path_to_vcpkg> with the actual path, for example C:/vcpkg.
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=<path_to_vcpkg>/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release
```

{% endstep %}

{% step %}
**Execute Compilation**

```powershell
cmake --build build --config Release
```

{% endstep %}
{% endstepper %}

**Compilation Output:**

After successful compilation, the executable file `udp_receiver.exe` and its required DLLs (`libprotobuf.dll`, `abseil_dll.dll`) will be automatically generated in the `build/Release` directory.

### 3.4. Execution and Parameter Description

The program is a command-line tool that supports flexible configuration through parameters.

#### 3.4.1. Startup Command Format

```powershell
./udp_receiver.exe [--port port_number] [--type data_type]
```

#### 3.4.2. Parameter Details

<table><thead><tr><th width="94.5">Parameter</th><th width="84.5">Short Form</th><th width="106.5">Required</th><th width="96">Default Value</th><th width="82.5">Data Type</th><th>Description</th></tr></thead><tbody><tr><td><code>--port</code></td><td><code>-p</code></td><td>No</td><td>5555</td><td>Integer</td><td>The local UDP port the program listens on. Ensure this port is not blocked by the firewall.</td></tr><tr><td><code>--type</code></td><td><code>-t</code></td><td>No</td><td><code>angle</code></td><td>String</td><td>Specifies the protocol to parse:<br><code>angle</code>: Parses joint angle data.<br><code>quat</code>: Parses joint quaternion data.</td></tr></tbody></table>

#### 3.4.3. Execution Examples

* **Scenario 1: Default Execution**

Listens on port 5555 and parses angle data.

&#x20; `powershell build\Release\udp_receiver.exe` &#x20;

* **Scenario 2: Receiving Data from a Unity Client**

Assuming Unity sends quaternion data to port 6666.

`powershell build\Release\udp_receiver.exe -p 6666 -t quat`

### 3.5. Code Logic Analysis

The core flow of `main.cpp` is as follows:

1. **Initialize Winsock:** Call `WSAStartup` to initialize the Windows network library.
2. **Parse Arguments:** Parse command-line arguments to obtain the port and data type.
3. **Create Socket:** Establish a UDP socket (`SOCK_DGRAM`).
4. **Bind Port (Bind):** Bind the socket to `INADDR_ANY` and the specified port, allowing it to receive traffic from all network interfaces.
5. **Receive Loop (While Loop):**
   * `recvfrom`: Block and wait until a data packet is received.
   * **Deserialization:** Based on the `--type` argument, select either a `TeleopDataAngle` or `TeleopDataQuat` object and call `ParseFromString()` to parse the binary data.
   * **Data Processing:** If parsing is successful, call the `print_*_data` function to print the string representation (`DebugString()`) of the data content.
6. **Resource Cleanup:** Close the socket and clean up Winsock.

### 3.6. Secondary Development Guide

If you need to write your own code to read the data, please refer to the following C++ example:

{% stepper %}
{% step %}
**Include Header Files**

```cpp
#include "handdriver_teleop.pb.h" // Auto-generated header files
```

{% endstep %}

{% step %}
**Parsing Logic**

```cpp
// Assuming buffer is the received char* data and n is its length
std::string raw_data(buffer, n);
HandDriver::TeleopDataAngle packet;

if (packet.ParseFromString(raw_data)) {
    // 1. Get the timestamp
    long long ts = packet.timestamp();
    
    // 2. Get the bending degree of the left thumb tip
    // Access path: TeleopData -> LeftHand -> Joints Array -> Index 0
    float thumb_bend = packet.lefthand().joints(0); 
    
    // 3. Get the wrist pose
    auto imu = packet.lefthand().imu();
    printf("Wrist Quat: x=%.2f, y=%.2f\n", imu.x(), imu.y());
}
```

{% endstep %}
{% endstepper %}

## 4. C++ SDK Linux

### 4.1. Overview

This project is a C++-based UDP network receiver program, specifically designed to receive and parse glove data serialized via Google Protocol Buffers (Protobuf). The program supports two primary data transmission modes: **Angle** mode and **Quaternion** mode.

### 4.2. Compilation and Build

This project uses CMake for build management.

#### 4.2.1. **Environment Dependency Installation**

This project runs in a Linux (Ubuntu/Debian) environment. Please follow the steps below to install the required dependencies:

{% stepper %}
{% step %}
**Update the Software Source**

```
sudo apt-get update
```

{% endstep %}

{% step %}
**Install Basic Build Tools**

Install the C++ compiler (g++) and the CMake build tool:

```
sudo apt-get install -y build-essential cmake
```

{% endstep %}

{% step %}
**Install Protocol Buffers**

This project relies on Google Protocol Buffers for data serialization. It requires the installation of the compiler (`protoc`) and the C++ development library (`libprotobuf-dev`):

```
sudo apt-get install -y protobuf-compiler libprotobuf-dev
```

{% endstep %}
{% endstepper %}

#### 4.2.2. **Compilation Steps**

Please execute the following commands in the project's root directory:

```
# 1. Generate the build files
cmake .

# 2. Compile the executable
make
```

After successful compilation, the executable file `udp_receiver` will be generated in the current directory.

### 4.3. Usage Instructions

The program is configured via command-line parameters, supporting custom listening ports and data types.

#### 4.3.1. **Parameter Description**

<table><thead><tr><th width="110">Parameter</th><th width="85.5">Short Form</th><th width="107">Required</th><th width="95.5">Default Value</th><th>Description</th></tr></thead><tbody><tr><td><code>--port</code></td><td><code>-p</code></td><td>No</td><td>5555</td><td>Sets the UDP listening port.</td></tr><tr><td><code>--type</code></td><td><code>-t</code></td><td>No</td><td><code>angle</code></td><td>Sets the data parsing type. Options: <code>angle</code>, <code>quat</code>.</td></tr></tbody></table>

#### 4.3.2. **Execution Examples**

1. **Run with default settings** (Listens on port 5555, parses Angle type data):

```
./udp_receiver
```

2. **Specify port and type** (Listens on port 6000, parses Quat type data):

```
./udp_receiver --port 6000 --type quat
```

### 4.4. Code Logic and Interfaces

#### 4.4.1. **Main Program Flow (`main.cpp`)**

1. **Parameter Parsing:** Uses `getopt_long` to parse command-line arguments `port` and `type`.
2. **Socket Initialization:** Creates a UDP socket and binds it to the specified port (`INADDR_ANY`).
3. **Reception Loop:**

* `recvfrom` blocks and receives a UDP data packet.
* Based on the `type` argument, selects the corresponding Protobuf message type (`TeleopDataAngle` or `TeleopDataQuat`) for deserialization (`ParseFromString`).
* If parsing is successful, calls the corresponding print function.
* If parsing fails, outputs an error message and continues to the next loop iteration.

#### 4.4.2. **Key Functions**

* **`void print_angle_data(const HandDriver::TeleopDataAngle& data)`**
  * **Function:** Prints the details of Angle type telemetry data.
  * **Implementation:** Calls the Protobuf auto-generated `DebugString()` method to output formatted text.
* **`void print_quat_data(const HandDriver::TeleopDataQuat& data)`**
  * **Function:** Prints the details of Quaternion type telemetry data.
  * **Implementation:** Same as above, calls `DebugString()`.

## 5. Python SDK - Linux/Win

This SDK supports both Windows and Linux.

This tool listens on a specified port via the UDP protocol, receives binary data packets, and uses Google Protocol Buffers (Protobuf) to deserialize them according to the specified data type (`angle` or `quat`), finally printing the parsed data to the console.

### 5.1. Environment Dependencies

* Python 3.x
* Protobuf library

Install dependencies:

```
pip install protobuf==3.20.3
```

### 5.2. Interface Description and Data Access

#### 5.2.1. **Communication Protocol**

* **Protocol:** UDP
* **Default Port:** 5555
* **Data Format:** Protobuf-serialized binary stream

#### 5.2.2. **Reception Process (Python)**

1. **Create Socket:** Establish a UDP socket.
2. **Bind Port:** Bind to a specified IP (`0.0.0.0`) and port.
3. **Reception Loop:** Use `recvfrom` to receive data packets.
4. **Deserialization:**
   * If the data type is `angle`, use `TeleopDataAngle.ParseFromString(data)`.
   * If the data type is `quat`, use `TeleopDataQuat.ParseFromString(data)`.
5. **Data Access:** Access fields of the parsed object (e.g., `msg.LeftHand.joints[0]`).

### 5.3. Usage Demo

The script `udp_receiver.py` provides a simple command-line interface.

#### 5.3.1. **Parameter Description**

* `--port`: Specifies the listening port (default: 5555)
* `--type`: Specifies the expected data type (`angle` or `quat`, default: `angle`)

#### 5.3.2. **Example 1: Receiving Angle Data (Default)**

```
python udp_receiver.py
```

Or specify explicitly:

```
python udp_receiver.py --port 5555 --type angle
```

#### 5.3.3. **Example 2: Receiving Quaternion Data**

If the sender is transmitting data in quaternion format:

```
python udp_receiver.py --port 5555 --type quat
```

#### 5.3.4. **Example 3: Changing the Listening Port**

To listen on port 6000:

```
python udp_receiver.py --port 6000
```
