Skip to content

Fix SpaceMouse detection failing when the HID backend reports no product string - #7498

Open
rwiltz wants to merge 3 commits into
isaac-sim:developfrom
rwiltz:fix/spacemouse-hid-detection
Open

Fix SpaceMouse detection failing when the HID backend reports no product string#7498
rwiltz wants to merge 3 commits into
isaac-sim:developfrom
rwiltz:fix/spacemouse-hid-detection

Conversation

@rwiltz

@rwiltz rwiltz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Description

QA reported that isaaclab teleop run --teleop_device spacemouse aborts with
No device found by SpaceMouse. Is the device connected? while a SpaceMouse Compact
(256f:c635) is connected and visible on /dev/hidraw4, even after applying the
sudo chmod 666 /dev/hidraw<#> workaround our teleoperation guide documents.

Root cause

The hidapi wheel we depend on bundles a libusb-backed HID backend, not the hidraw one:

  $ readelf -d .venv/.../hid.cpython-312-x86_64-linux-gnu.so | grep NEEDED
    NEEDED  libusb-1-150b88da.0.so.0.1.0
  $ python -c "import hid; print(hid.enumerate()[0]['path'])"
    b'7-6:1.0'      # a USB path, not /dev/hidraw*

That backend reaches the device through /dev/bus/usb, and it can only read USB string
descriptors for devices the process is allowed to open. Without that access, hid.enumerate()
still lists the device but returns product_string == ''. Detection compared the product
string against an exact list:

  if device["product_string"] == "SpaceMouse Compact" or ...

so an empty string matched nothing and the device was reported as absent. The documented
chmod 666 /dev/hidraw<#> grants nothing to this backend, which is why the workaround
appeared to have no effect.

This reproduces on any USB HID device the user lacks USB permissions for — no SpaceMouse
required:

  0x048d:0x5702 product_string='' -> open failed        # kernel HID_NAME is "ITE Tech. Inc. ITE Device"
  0x1050:0x0407 product_string='YubiKey OTP+FIDO+CCID'  # has a udev rule, so strings resolve

The exact match is fragile in the other direction too: on a hidraw-backed hidapi the
product string can come back as the kernel's combined name, e.g.
3Dconnexion SpaceMouse Compact, which also fails to equal SpaceMouse Compact.

Changes

  • Se2SpaceMouse/Se3SpaceMouse now match enumerated devices by USB vendor/product id
    (SPACEMOUSE_USB_IDS in devices/spacemouse/utils.py, ids taken from the USB ID
    repository at https://www.linux-usb.org/usb.ids), covering exactly the models each device
    class already supported. The product string is kept as a fallback so devices with ids we
    do not list keep working, and is matched both verbatim and with a leading 3Dconnexion
    stripped.
  • The "no device found" error now lists the enumerated HID devices and explains that the
    backend needs access to /dev/bus/usb, not /dev/hidraw*.
  • A detected-but-unopenable device now raises that same guidance instead of a bare
    OSError: open failed.
  • teleop_imitation.rst: replaced the ineffective chmod 666 /dev/hidraw<#> tip with a
    udev rule for vendor 256f (covering both SUBSYSTEM=="usb" and hidraw), and corrected
    the Docker recipe to mount /dev/bus/usb with the matching device_cgroup_rules.

Fixes # (issue)

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Release backport

  • Backport this pull request to the active release branch after it merges into develop

Checklist

Docker and GPU tests run on demand. Push the commits you want tested, then
comment run-ci on the pull request.

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package (do not edit CHANGELOG.rst or bump extension.toml — CI handles that)
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

The hidapi wheels bundle a libusb-backed HID backend, which reports an empty
product string unless the process may open the USB node. Detection compared the
product string against an exact list, so a connected SpaceMouse was reported as
'No device found', and the documented '/dev/hidraw*' permission workaround has
no effect on that backend.

Match the enumerated devices by their USB vendor and product ids, keeping the
product string as a fallback and also accepting the '3Dconnexion ' prefix that
some backends prepend. Report the enumerated devices and the required USB
permissions when no device is found or when opening one fails, and document the
udev rule that actually grants access.
@rwiltz
rwiltz requested a review from a team September 2, 2026 20:46
@github-actions github-actions Bot added bug Something isn't working documentation Improvements or additions to documentation isaac-mimic Related to Isaac Mimic team isaac-lab Related to Isaac Lab team labels Sep 2, 2026
@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR makes SpaceMouse discovery independent of optional HID product strings and improves permission diagnostics. It also completes the prior review fixes:

  • Discovery continues after an inaccessible supported device and can open a later usable model.
  • The documented udev rules now scope access to local-seat users and the plugdev group instead of every local account.
  • Constructor tests cover USB-ID detection, continued discovery, and actionable failure messages.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/devices/spacemouse/utils.py Adds USB-ID and normalized-product-name resolution plus clearer discovery and permission diagnostics.
source/isaaclab/isaaclab/devices/spacemouse/se2_spacemouse.py Uses shared device resolution and continues discovery after supported devices fail to open.
source/isaaclab/isaaclab/devices/spacemouse/se3_spacemouse.py Uses shared device resolution, preserves the resolved model name, and continues to later candidates after open failures.
docs/source/overview/imitation-learning/teleop_imitation.rst Replaces global USB permissions with group/local-seat access and documents the libusb container configuration.
source/isaaclab/test/devices/test_device_constructors.py Covers missing and prefixed product strings, fallback to a later accessible device, and diagnostic errors.

Reviews (2): Last reviewed commit: "Address review feedback on SpaceMouse di..." | Re-trigger Greptile

Comment thread source/isaaclab/isaaclab/devices/spacemouse/utils.py Outdated
Comment thread docs/source/overview/imitation-learning/teleop_imitation.rst Outdated

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isaac Lab Review Bot

The USB-id-based SpaceMouse detection and permission guidance are coherent overall, but the updated teleoperation tip introduces contradictory compatibility guidance for older supported devices.

  • Design and architecture: The shared detection helpers centralize USB-id and product-name resolution while preserving distinct supported-device sets for the SE(2) and SE(3) implementations. No architectural issue was identified.
  • API: Constructor signatures and exception types remain unchanged, and USB-id matching extends the previous product-string behavior. However, the documentation now gives setup instructions for SpaceNavigator for Notebooks while the same tip still claims only SpaceMouse Wireless and Compact are compatible; the documented support surface must be made consistent.
  • Implementation: The changed detection paths correctly map known USB identifiers to the report-layout names consumed by the listeners, retain product-string fallback behavior, and preserve the original open failure through exception chaining. The actionable issue is limited to reconciling the contradictory supported-model statements in the teleoperation documentation.

Minor fixes needed. Posted 1 actionable finding inline.

Automated review; human maintainers own approval decisions.

Comment thread docs/source/overview/imitation-learning/teleop_imitation.rst Outdated
Only the directly attached SpaceMouse Compact and SpaceMouse Wireless ids are
confirmed against the USB ID repository and the report layout the listener
threads assume. Wireless receivers enumerate under their own product ids and use
a different report layout, so match those by product string only, as before.
- Do not abandon discovery when a supported device cannot be opened: an
  inaccessible device enumerated first no longer hides a usable one behind it.
  Discovery now stops at the first device it opens, matching the documented
  contract, and reports the collected open failures only when none succeeded.
- Scope the documented udev rule to the local seat and the plugdev group instead
  of granting every account read and write access to the vendor's devices.
- List the actually supported models in the teleoperation tip, which still
  claimed only the SpaceMouse Wireless and Compact were compatible.
@rwiltz

rwiltz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

@greptile

@rwiltz

rwiltz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team isaac-mimic Related to Isaac Mimic team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant