SpaceMouse teleoperation plugin and Cartesian control adapters for LeRobot.
Project description
lerobot-teleoperator-spacemouse
A LeRobot plugin that turns a 3Dconnexion SpaceMouse into a 6-DoF robot teleoperator.
Push the puck to move the end-effector in X/Y/Z. Tilt/twist to rotate. Press the side buttons to open or close the gripper. Works out of the box with SO-101 / SO-ARM follower robots via built-in inverse kinematics, and supports any custom URDF through a profile API.
Features
- 6-DoF teleoperation — translation and rotation deltas from SpaceMouse physical axes
- IK mode — converts end-effector targets to joint commands using LeRobot's
RobotKinematicsand a bundled SO-101 URDF (no calibration file needed) - Direct EEF mode — passes Cartesian targets straight to robots that already accept
ee.*action keys - Gripper control — left/right buttons open and close the gripper at a configurable speed
- Axis remapping & sign flip — remap any physical SpaceMouse axis to any robot axis; flip signs per axis
- Deadzone & timeout — configurable deadzone and input-stale timeout prevent drift when the puck is released
- Workspace clamping — optional per-axis position limits and max-step rate limiter
- Custom robot profiles — register your own URDF + frame + motor list at runtime
Installation
pip install lerobot-teleoperator-spacemouse
SO-101 / SO-ARM IK support is included by default. For other robot families (e.g. Dynamixel-based arms), register a custom kinematics profile — see Extending to Other Robots.
Quick Start
SO-101 follower over USB
lerobot-teleoperate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_robot \
--teleop.type=spacemouse \
--teleop.adapter.mode=ik \
--fps=60
Conservative first run (smaller steps, display enabled)
lerobot-teleoperate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_robot \
--teleop.type=spacemouse \
--teleop.adapter.mode=ik \
--teleop.deadzone=0.1 \
--teleop.input_timeout_s=0.08 \
--teleop.adapter.translation_step_m=0.001 \
--teleop.adapter.rotation_step_rad=0.005 \
--display_data=true
Test your SpaceMouse (no robot needed)
lerobot-teleoperator-spacemouse-test
This prints raw SpaceMouse state for 30 seconds so you can verify axes and buttons before connecting a robot.
Configuration Reference
All options are set via --teleop.<option> or --teleop.adapter.<option> on the command line.
Teleoperator options (--teleop.*)
| Option | Default | Description |
|---|---|---|
device |
None |
HID device path. Auto-detected when None. |
deadzone |
0.08 |
Ignore inputs below this fraction of full deflection. |
rescale_after_deadzone |
True |
Rescale remaining range to [0, 1] after deadzone. |
max_axis_value |
1.0 |
Clamp raw axis values to [-max, max]. |
input_timeout_s |
0.08 |
Zero-out input if no new state arrives within this window (seconds). |
read_drain_count |
32 |
Max HID reads per get_action() call to drain the queue. |
x_axis |
"y" |
SpaceMouse attribute name mapped to robot target_x. |
y_axis |
"x" |
SpaceMouse attribute name mapped to robot target_y. |
z_axis |
"z" |
SpaceMouse attribute name mapped to robot target_z. |
wx_axis |
"roll" |
SpaceMouse attribute name mapped to robot target_wx. |
wy_axis |
"pitch" |
SpaceMouse attribute name mapped to robot target_wy. |
wz_axis |
"yaw" |
SpaceMouse attribute name mapped to robot target_wz. |
x_sign |
1.0 |
Sign multiplier for target_x. Use -1.0 to flip. |
y_sign |
-1.0 |
Sign multiplier for target_y. |
z_sign |
1.0 |
Sign multiplier for target_z. |
wx_sign |
1.0 |
Sign multiplier for target_wx. |
wy_sign |
1.0 |
Sign multiplier for target_wy. |
wz_sign |
1.0 |
Sign multiplier for target_wz. |
use_gripper |
True |
Enable gripper button control. |
gripper_open_button |
1 |
Button index that opens the gripper. |
gripper_close_button |
0 |
Button index that closes the gripper. |
require_enable_button |
False |
Require a dedicated button to enable motion. |
idle_enabled |
False |
Whether enabled=True is sent when the device is idle. |
Adapter options (--teleop.adapter.*)
| Option | Default | Description |
|---|---|---|
mode |
"auto" |
"ik", "eef", or "auto" (uses "eef" if robot exposes ee.* keys). |
robot_profile |
"so101_follower" |
Built-in kinematics profile. Use "custom" to supply your own URDF. |
translation_step_m |
0.001 |
End-effector translation per frame at full SpaceMouse deflection (meters). |
rotation_step_rad |
0.005 |
End-effector rotation per frame at full deflection (radians). |
workspace_min |
None |
[x, y, z] lower workspace bound (meters). |
workspace_max |
None |
[x, y, z] upper workspace bound (meters). |
max_ee_step_m |
0.02 |
Maximum allowed end-effector step per frame (rate limiter). |
position_weight |
1.0 |
IK position tracking weight. |
orientation_weight |
0.01 |
IK orientation tracking weight. |
gripper_speed_factor |
2.0 |
Gripper velocity → position integration scale. |
gripper_min |
0.0 |
Gripper position lower bound (normalized joint units). |
gripper_max |
100.0 |
Gripper position upper bound (normalized joint units). |
Linux HID Setup
The SpaceMouse uses the hidraw subsystem. On Linux you need the shared library and a udev rule.
conda environment:
conda install -c conda-forge libhidapi
Debian / Ubuntu system Python:
sudo apt-get install libhidapi-hidraw0 libhidapi-dev
udev rule (allows non-root access):
sudo tee /etc/udev/rules.d/99-spacemouse-hidraw.rules >/dev/null <<'EOF'
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="256f", MODE="0660", GROUP="plugdev", TAG+="uaccess"
EOF
sudo usermod -aG plugdev "$USER"
sudo udevadm control --reload-rules
sudo udevadm trigger
Unplug and replug the SpaceMouse. Log out and back in after the group change.
Extending to Other Robots
One-off custom URDF
lerobot-teleoperate \
--teleop.type=spacemouse \
--teleop.adapter.mode=ik \
--teleop.adapter.robot_profile=custom \
--teleop.adapter.urdf_path=/path/to/robot.urdf \
--teleop.adapter.target_frame_name=gripper_tip \
--teleop.adapter.motor_names='["joint1","joint2","joint3","joint4","joint5","gripper"]' \
--teleop.adapter.gripper_name=gripper
Reusable profile (Python)
Register a profile from your own package and it becomes available as a named robot_profile:
from lerobot_teleoperator_spacemouse.profiles import KinematicsProfile, register_kinematics_profile
register_kinematics_profile(
"my_arm",
KinematicsProfile(
urdf_resource=None, # set urdf_path on the adapter instead
target_frame_name="tip_link",
motor_names=("j1", "j2", "j3", "j4", "j5", "gripper"),
gripper_name="gripper",
),
)
Then use --teleop.adapter.robot_profile=my_arm.
Troubleshooting
Arm keeps moving after releasing the SpaceMouse — Increase --teleop.deadzone (e.g. 0.15) or lower --teleop.input_timeout_s (e.g. 0.05).
Motion is too fast / too slow — Tune --teleop.adapter.translation_step_m and --teleop.adapter.rotation_step_rad.
Axis direction is wrong — Flip the sign: --teleop.x_sign=-1, --teleop.y_sign=-1, etc.
Device not found / permission denied — Run lerobot-teleoperator-spacemouse-test first. Follow the Linux HID Setup section if it fails.
Development
git clone https://github.com/Jas000n/lerobot-teleoperator-spacemouse.git
cd lerobot-teleoperator-spacemouse
pip install -e ".[dev]"
pytest
License
Apache 2.0.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lerobot_teleoperator_spacemouse-0.1.4.tar.gz.
File metadata
- Download URL: lerobot_teleoperator_spacemouse-0.1.4.tar.gz
- Upload date:
- Size: 19.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28675c3515d80189b32ec0881581308e6fb6bc183f002fe71609367051ae1705
|
|
| MD5 |
dee9d5694c60a8429cbcbb5ade696503
|
|
| BLAKE2b-256 |
f82ef0c058cdc2c09437a72da8f22e1f062cc176feb79d0e2bb45d6cee683bec
|
File details
Details for the file lerobot_teleoperator_spacemouse-0.1.4-py3-none-any.whl.
File metadata
- Download URL: lerobot_teleoperator_spacemouse-0.1.4-py3-none-any.whl
- Upload date:
- Size: 16.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7fc0d4b42d6b47cb517c3d135fb249c879a37f8a737b0b9ef55749e774337db9
|
|
| MD5 |
d01130110eb273e4e38a68fb854178ef
|
|
| BLAKE2b-256 |
01fbeceb6e3adea72a920a35e22f1d107c5874de3e4e6057699601fefc04bfa2
|