feat(gamepad): add direct joint control for Xbox/HID gamepad with SO100/SO101#3174
Open
slurms wants to merge 1 commit intohuggingface:mainfrom
Open
feat(gamepad): add direct joint control for Xbox/HID gamepad with SO100/SO101#3174slurms wants to merge 1 commit intohuggingface:mainfrom
slurms wants to merge 1 commit intohuggingface:mainfrom
Conversation
…00/SO101 Add support for controlling SO100/SO101 follower robots directly from an Xbox controller (or any HID gamepad) by mapping each gamepad axis to an individual joint servo, bypassing the IK pipeline. Gamepad axis mapping: - Left stick Y → shoulder_lift - Left stick X → shoulder_pan - Right stick Y → elbow_flex - Right stick X → wrist_flex - LB/RB → wrist_roll - LT/RT → gripper (close/open) Changes: - Add Xbox One GIP HID report parser (_update_xbox) with proper 16-bit LE stick/trigger parsing and Y-axis sign normalization - Add HID usage_page/usage-based gamepad detection (replaces string matching) - Add device_name config option for selecting a specific gamepad - Add MapGamepadToJointPositionsStep processor that reads current joint positions from observation and applies scaled gamepad deltas - Add make_processors() factory that auto-selects the direct joint pipeline for gamepad/keyboard_ee + SO follower combinations - Wire make_processors() into teleoperate and record scripts
aec8ef6 to
3b19515
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Title
feat(gamepad): add direct joint control for Xbox/HID gamepad with SO100/SO101
Type / Scope
Summary / Motivation
Adds support for teleoperating SO100/SO101 follower robots directly from an Xbox controller (or any HID gamepad) by mapping each gamepad axis to an individual joint servo.
Previously, gamepad teleoperation required an inverse kinematics pipeline with a URDF and the placo C++ dependency.
This approach is simpler, has zero extra dependencies, and gives the operator direct, predictable control over each joint.
The control mapping is:
This was intuitive enough for my 5 year old to master when playing with it locally.
Related issues
What changed
gamepad_utils.py: Added Xbox One GIP HID report parser (_update_xbox, see docs) with 16-bit LE stick/trigger parsing and Y-axis sign normalization to match SDL convention. Replaced string-based gamepad detection with HID usage_page/usage matching. Addedwrist_roll_command(LB/RB) andright_xto baseInputController. Fixedget_deltas()axis mapping so left stick Y →delta_xand left stick X →delta_y.configuration_gamepad.py: Addeddevice_name: str | Noneconfig for selecting a specific gamepad by product/manufacturer substring.teleop_gamepad.py: Action dict now includes delta_wx (right stick X) and delta_wz (wrist roll).delta_action_processor.py: AddedMapGamepadToJointPositionsStepprocessor that reads current joint positions from observation and applies scaled gamepad deltas. Also addeddelta_wzpassthrough to existingMapDeltaActionToRobotActionStep.factory.py: Extendedmake_default_processors()to accept optionalteleop_config/robot_configparams. When a delta teleop + SO follower combination is detected, it swaps in the joint control processor automatically.lerobot_teleoperate.py: Callsmake_default_processors(cfg.teleop, cfg.robot).make_default_processors()with no args behaves identically to before.How was this tested (or how to run locally)
Manual tested by teleoperating an SO101 follower with an Xbox One controller over USB on macOS using:
Run tests with
tests/teleoperators/test_gamepad_controller.pytests/processor/test_gamepad_joint_processor.pyChecklist (required before merge)
pre-commit run -a)pytest)Reviewer notes
_update_xbox()parser handles the Xbox One GIP protocol (18-byte reports with 0x20 header). Other Xbox-compatible controllers using this same protocol over USB should work. The existing_update_logitech()parser is preserved for Logitech RumblePad 2 and similar 8-byte HID reports.joint_step_sizedefaults to 3.0°/frame. At 60fps this gives ~180°/s at full stick deflection. This is tunable via theMapGamepadToJointPositionsStepdataclass field.right_xandwrist_roll_commandattributes from the base class.device_nameconfig option is useful when multiple HID devices are connected (e.g., webcams that register as HID devices - my Logitech Streamcam was detected when using--teleop.type=gamepadfor some reason, hence adding this).