Sport Client (Joystick) — C++ Example
Source: rbq_sdk/cpp/example/src/rbq_sport_client_joy.cpp
Drives the robot using a gamepad / joystick via the SportClient API.
Analog sticks stream continuous Move velocity commands; buttons trigger discrete actions (Damp, StandUp/Down, gait switches, acrobatics).
How it works
Two concurrent parts run together:
| Part | Rate | What it does |
|---|---|---|
| Main thread (joystick) | ~100 Hz | Reads joystick events, pushes discrete SportCmd entries onto a queue, updates atomic velocity setpoints |
| Control loop thread | 10 Hz | Drains the command queue first; if empty, calls sport.Move(vx, vy, vyaw) |
The control loop calls sport.SetNoReply(true) — commands are sent fire-and-forget without waiting for an RPC acknowledgement.
Prerequisites
- RBQ SDK built and installed — see C++ SDK Overview.
- A Linux joystick device (e.g. Logitech F710) available at
/dev/input/js*. - Robot stack running and reachable on the network interface you pass as
argv[1].
Build
From rbq_sdk/cpp/example/:
bash scripts/setup.bash
bash scripts/build.bashBinary: bin/rbq_sport_client_joy
Run
./bin/rbq_sport_client_joy <networkInterface> [joystickPath]
# auto-detect joystick:
./bin/rbq_sport_client_joy eth0
# explicit joystick device:
./bin/rbq_sport_client_joy eth0 /dev/input/js1If no joystick path is given, the binary auto-detects js* devices: it prefers a device whose name contains "Logitech", "gamepad", "Xbox", or "wireless", then falls back to the first available node, then /dev/input/js0.
The JOY environment variable can also override the path.
Gamepad bindings
The mapping follows the Logitech F710 / Xbox layout recognised by the Linux joystick driver.
Button chords (checked first)
| Buttons pressed | Robot action |
|---|---|
| L2 + B | Damp — high-damping emergency stop |
| L2 + A (1st press) | StandUp — lock joints in standing position |
| L2 + A (2nd press) | StandDown — go prone |
| START | DefaultMode — unlock / default gait |
| L2 + START | RunningMode — high-speed gait |
| L2 + X | RecoveryStand — stand up from fall |
| R1 + X | Climb — stair-climb gait |
| L1 + X | not supported on this robot |
| L1 + Y | not supported on this robot |
| BACK | StopMove — stop in place |
Double-click bindings
A second press within 400 ms of the first triggers the action.
| Button | Action |
|---|---|
| Double X | LeftSideGait |
| Double Y | RightSideGait |
| Double R1 | not supported on this robot |
| Double R2 (trigger) | not supported on this robot |
Analog stick velocity (continuous)
| Axis | Maps to | Max value |
|---|---|---|
| Left stick Y (push forward) | vel_x (forward) | ±0.55 m/s |
| Left stick X (push left) | vel_y (lateral) | ±0.35 m/s |
| Right stick X | vyaw (yaw rate) | ±1.0 rad/s |
A deadzone of 0.12 is applied to all axes before scaling.
Key implementation notes
lock_toggle_to_prone:L2+Aalternates betweenStandUpandStandDownon successive presses via a boolean toggle — matching the behaviour of the A2 robot's built-in controller.- Double-click detection: A
consume_double()lambda tracks the last edge timestamp. If a second edge arrives withinkDoubleClickWindow(400 ms), the action fires and the counter resets. - R2 as virtual button: The RT trigger (
AXIS_RT) is treated as a button by comparing the axis value against 0 — idle is −1, full press is +1. - Error streak logging: Consecutive errors are counted; a message is printed every 50 failures to avoid log spam.
