Integration with Upper-Layer Applications
Communication Layer Implementation
Section titled “Communication Layer Implementation”UDP Communication Architecture
Section titled “UDP Communication Architecture”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 receivingGamepad<KeysType>: CallsUdpReceiver::ReceiveData()in a separate thread in a loop, passing raw data to the subclass’sUpdateData()for parsing
Data Receiving Flow
Section titled “Data Receiving Flow”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"| AThread Model
Section titled “Thread Model”The SDK uses a dedicated data receiving thread:
StartDataThread()creates anddetachs a background thread- The thread loops calling
ReceiveData()(blocking), protecting button data read/write withmutex_ GetKeys()ensures thread safety through the samemutex_StopDataThread()sets thestop_thread_atomic flag, and the thread exits on the next loop iteration
Integration into Upper-Layer Applications
Section titled “Integration into Upper-Layer Applications”Linking the Static Library
Section titled “Linking the Static Library”Reference the SDK in your project’s CMakeLists.txt:
# Specify gamepad SDK pathset(GAMEPAD_DIR "/path/to/gamepad")
# Include headersinclude_directories(${GAMEPAD_DIR}/include)
# Link static librarylink_directories(${GAMEPAD_DIR}/build)target_link_libraries(your_target gamepad_receiver)Code Integration Example
Section titled “Code Integration Example”#include "retroid-gamepad.h"#include "gamepad_keys.h"
// Create gamepad instanceRetroidGamepad gamepad(12121);gamepad.StartDataThread();
// Method 1: Callback-based data retrievalgamepad.SetUpdateCallback([](uint32_t count) { // Data has been updated});
// Method 2: Polling-based data retrievalwhile (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));}Integration with lite3_transfer
Section titled “Integration with lite3_transfer”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 publishRetroidKeys 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;Safety Considerations
Section titled “Safety Considerations”-
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.
-
Firewall configuration: Ensure UDP ports are allowed before compilation and execution; otherwise, gamepad data cannot be received.
-
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.
-
Port conflicts: Ensure port
12121is not occupied by other programs. Check with:
sudo lsof -i:12121