SpaceMouse teleoperation¶
A 3Dconnexion SpaceMouse lets you drive the Piper arm from your desk — no headset, no room setup, no clutch choreography. You nudge the puck, the end-effector moves; you let go, it stops. This page covers setup, the button mapping, and how to tune the feel.
When to use it¶
Reach for the SpaceMouse instead of the Quest when:
- you don't have a headset handy (or don't want to wear one),
- you need precise, slow adjustments — full puck deflection tops out at a gentle 0.15 m/s by default,
- you're doing long desk sessions where holding a controller in mid-air would be tiring.
The key difference is the control mode:
| Quest | SpaceMouse | |
|---|---|---|
| Mode | Position (clutch) | Rate (velocity) |
| While engaged | Controller motion maps 1:1 to the EEF | Puck deflection commands EEF velocity |
| On release | Target freezes where it is | Arm stops |
| Clutch | Hold grip to engage | None — deflection is engagement |
Because it is rate control, there is nothing to re-grip or ratchet: the arm integrates your velocity command while the puck is deflected and holds still the moment you release it. The same safety envelope as the Quest applies — workspace box, velocity caps, pitch guard, and the 0.12 m target-to-measured tether (see Control modes).
Setup¶
One-time, after installation:
This runs install/04_spacemouse_setup.sh, which:
- installs a udev rule (
/etc/udev/rules.d/99-spacemouse.rules, needs sudo) granting non-root access to 3Dconnexion devices, and - runs a 5-second read test — deflect the puck and press the buttons; you should see live axis values and a report rate.
If the read test fails right after installing the rule, unplug and replug the SpaceMouse so the rule applies to the device node.
No spacenavd needed
The driver reads HID reports directly through the Python hidapi
package. You do not need to install spacenavd — and if it is running,
it can grab the device and block the driver. Stop it with:
Run¶
Power on the arm and home it first (make home — the controller refuses to
engage while the EEF is outside the workspace box):
For data collection (see Data collection for the full workflow):
The --input flag overrides the input: key in the config, so you can
switch between Quest and SpaceMouse without editing any file.
Controls¶
| Input | Action |
|---|---|
| Puck deflection | EEF velocity (translate + rotate); release = stop |
| Left button | Toggle gripper open/close |
| Right button, short press | Start / stop-and-save episode |
| Right button, hold 1 s | Home the arm |
| Both buttons together | Discard current episode |
Default axis mapping: puck forward → robot +x, puck right → robot −y, puck up → robot +z; tilting forward/back rotates about robot y, tilting left/right rotates about robot x, and twisting rotates about robot z.
Why single-button actions feel slightly deferred
With only two buttons, "both together" has to be distinguishable from
two staggered single presses. The controller waits a short chord window
(chord_window_s, 0.2 s by default) after the gripper button goes down
before toggling — if the other button arrives inside that window, the
press becomes a discard instead. Similarly, the record button fires on
release (a short press), because holding it for 1 s means "home".
The tiny delay is deliberate, not lag.
During piper-collect the keyboard also works: Space = start/stop,
D = discard, H = home, Q = quit.
Tuning the feel¶
All knobs live in the spacemouse: block of the config. Put your changes in
an overlay file and pass --config my.yaml — see
Configuration.
| Key | Default | What it does |
|---|---|---|
deadzone |
0.10 |
Normalized deflection below this is ignored; raise it if the arm creeps when your hand rests on the puck |
max_lin_vel |
0.15 |
Linear speed (m/s) at full deflection |
max_ang_vel |
0.9 |
Angular speed (rad/s) at full deflection |
axis_signs |
[1, 1, 1, -1, -1, -1] |
Per-axis sign flips, in order x, y, z, roll, pitch, yaw |
stale_timeout_s |
0.15 |
No HID report within this window → twist treated as zero |
Flipping an axis that feels backwards
If, say, pushing the puck forward moves the arm the wrong way, flip the
corresponding entry in axis_signs from 1 to -1 (or vice versa) in
your overlay. The order is x, y, z, roll, pitch, yaw of the puck
axes. The shipped defaults invert the three rotation axes to match
operator preference.
The device only sends reports while it is being touched, so stale_timeout_s
guarantees the commanded velocity drops to zero shortly after you let go —
the arm can never keep integrating a stale deflection.
Supported devices¶
The driver auto-detects the first supported device it finds (set
spacemouse.device to a name to pin one). Recognized models:
| Model | VID:PID |
|---|---|
| SpaceMouse Compact | 256f:c635 |
| SpaceMouse Wireless (cabled) | 256f:c62e |
| SpaceMouse Wireless (new) | 256f:c63a |
| 3Dconnexion Universal Receiver | 256f:c652 |
| SpaceNavigator | 046d:c626 |
| SpaceNavigator for Notebooks | 046d:c628 |
Verified on the Compact
The HID report parsing was written and verified against the
SpaceMouse Compact. The other models are recognized and are expected
to share the same report layout (wireless models pack translation and
rotation into a single combined report, which is handled), but they have
not all been tested — a different model may need small report-parsing
tweaks in piper_teleop/spacemouse_client.py.
If the driver reports no supported SpaceMouse found or cannot open the
device, re-run make spacemouse, replug, and check spacenavd — more in
Troubleshooting.