Skip to content

Integration with Upper-Layer Applications

The SDK’s underlying communication is based on a self-encapsulated UDP Socket layer:

graph TB
A["Gamepad<KeysType>"] --> B["UdpReceiver"]
B --> C["Linux Socket API"]
  • UdpReceiver: Encapsulates Socket creation, port binding, and data receiving
  • Gamepad<KeysType>: Calls UdpReceiver::ReceiveData() in a separate thread in a loop, passing raw data to the subclass’s UpdateData() for parsing
graph TB
A["UdpReceiver blocks waiting for UDP data"] --> B["Receives raw byte stream"]
B --> C["Gamepad calls subclass UpdateData"]
C --> D{"DataIsValid three-level verification"}
D -->|"Pass"| E["Parse button and joystick data"]
E --> F["Trigger updateCallback_"]
D -->|"Fail"| A

The SDK uses a dedicated data receiving thread:

  • StartDataThread() creates and detachs a background thread
  • The thread loops calling ReceiveData() (blocking), protecting button data read/write with mutex_
  • GetKeys() ensures thread safety through the same mutex_
  • StopDataThread() sets the stop_thread_ atomic flag, and the thread exits on the next loop iteration

Reference the SDK in your project’s CMakeLists.txt:

# Specify gamepad SDK path
set(GAMEPAD_DIR "/path/to/gamepad")
# Include headers
include_directories(${GAMEPAD_DIR}/include)
# Link static library
link_directories(${GAMEPAD_DIR}/build)
target_link_libraries(your_target gamepad_receiver)
#include "retroid-gamepad.h"
#include "gamepad_keys.h"
// Create gamepad instance
RetroidGamepad gamepad(12121);
gamepad.StartDataThread();
// Method 1: Callback-based data retrieval
gamepad.SetUpdateCallback([](uint32_t count) {
// Data has been updated
});
// Method 2: Polling-based data retrieval
while (running) {
RetroidKeys& keys = gamepad.GetKeys();
float vx = keys.left_axis_y; // Forward velocity
float vy = keys.left_axis_x; // Lateral velocity
float omega = keys.right_axis_x; // Rotation velocity
if (keys.Y) {
// Y button pressed → Stand up
}
if (keys.A) {
// A button pressed → RL control
}
if (keys.left_axis_button && keys.right_axis_button) {
// Both joystick buttons pressed → Emergency damping
}
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}

In lite3_transfer, RetroidGamepadPublisher encapsulates the Gamepad SDK and periodically publishes gamepad data to the ROS2 topic /GAMEPAD_DATA:

auto gamepad_ptr = std::make_shared<RetroidGamepad>(12121);
gamepad_ptr->StartDataThread();
// Periodic read and publish
RetroidKeys rt_keys = gamepad_ptr->GetKeys();
drdds::msg::GamepadData msg;
msg.left_axis_x = rt_keys.left_axis_x;
msg.left_axis_y = rt_keys.left_axis_y;
msg.right_axis_x = rt_keys.right_axis_x;
msg.right_axis_y = rt_keys.right_axis_y;
msg.buttons = rt_keys.value;
  1. Ensure network isolation: The gamepad App broadcasts data via UDP. Ensure the development network is isolated from other networks to prevent data interference or interception.

  2. Firewall configuration: Ensure UDP ports are allowed before compilation and execution; otherwise, gamepad data cannot be received.

  3. Heartbeat detection: Upper-layer applications should implement a gamepad heartbeat detection mechanism. When no gamepad data is received for an extended period, automatically enter a safe mode (e.g., damping state) to prevent loss of control.

  4. Port conflicts: Ensure port 12121 is not occupied by other programs. Check with:

Terminal window
sudo lsof -i:12121