|
6 | 6 | 3. Create a pull request to `master` and assign a reviewer. |
7 | 7 | 4. The reviewer will review your code and merge it into `master`. |
8 | 8 |
|
| 9 | +## Adding a new device |
| 10 | + |
| 11 | +This section describes how to add support for a new SpaceMouse or similar 6-DOF device. |
| 12 | + |
| 13 | +### 1. Find Device IDs |
| 14 | + |
| 15 | +First, identify your device's **Vendor ID (VID)** and **Product ID (PID)**. |
| 16 | + |
| 17 | +**Linux/macOS:** |
| 18 | +```bash |
| 19 | +lsusb |
| 20 | +# Example output: Bus 001 Device 013: ID 256f:c652 3Dconnexion Universal Receiver |
| 21 | +# VID = 256f, PID = c652 |
| 22 | +``` |
| 23 | + |
| 24 | +**Using [hidapitester](https://github.com/todbot/hidapitester):** |
| 25 | +```bash |
| 26 | +./hidapitester --list |
| 27 | +# Example: 046D/C626: 3Dconnexion - SpaceNavigator |
| 28 | +``` |
| 29 | + |
| 30 | +### 2. Analyze HID Data |
| 31 | + |
| 32 | +Use `hidapitester` to read raw data from your device: |
| 33 | + |
| 34 | +```bash |
| 35 | +./hidapitester --vidpid <VID/PID> --open --read-input |
| 36 | +``` |
| 37 | + |
| 38 | +Move the SpaceMouse knob in each direction and identify which bytes change: |
| 39 | + |
| 40 | +- **Channel 1**: Usually translation data (X, Y, Z) |
| 41 | +- **Channel 2**: Usually rotation data (pitch, roll, yaw) |
| 42 | +- **Channel 3**: Button data |
| 43 | + |
| 44 | +Each axis is typically a signed 16-bit value (2 bytes, little-endian). |
| 45 | + |
| 46 | +### 3. Add Device to `devices.toml` |
| 47 | + |
| 48 | +Edit `pyspacemouse/devices.toml` and add your device: |
| 49 | + |
| 50 | +```toml |
| 51 | +[YourDeviceName] |
| 52 | +hid_id = [0xVID, 0xPID] # Vendor ID and Product ID in hex |
| 53 | +led_id = [0x04, 0x01] # Optional: [report_id, on_value] for LED control |
| 54 | +axis_scale = 350.0 # Scaling factor (adjust based on device sensitivity) |
| 55 | + |
| 56 | +# Axis mappings: [channel, byte1, byte2, scale] |
| 57 | +# - channel: HID report number (1, 2, or 3) |
| 58 | +# - byte1, byte2: Byte positions for the 16-bit value |
| 59 | +# - scale: 1 for normal, -1 for inverted axis |
| 60 | +mappings.x = [1, 1, 2, 1] |
| 61 | +mappings.y = [1, 3, 4, -1] |
| 62 | +mappings.z = [1, 5, 6, -1] |
| 63 | +mappings.pitch = [2, 1, 2, -1] |
| 64 | +mappings.roll = [2, 3, 4, -1] |
| 65 | +mappings.yaw = [2, 5, 6, 1] |
| 66 | + |
| 67 | +# Button mappings: [channel, byte, bit] |
| 68 | +[YourDeviceName.buttons] |
| 69 | +LEFT = [3, 1, 0] # Channel 3, byte 1, bit 0 |
| 70 | +RIGHT = [3, 1, 1] # Channel 3, byte 1, bit 1 |
| 71 | +``` |
| 72 | + |
| 73 | +**Mapping format explained:** |
| 74 | + |
| 75 | +| Field | Description | |
| 76 | +|-------|-------------| |
| 77 | +| `channel` | HID report ID (first byte of each HID message) | |
| 78 | +| `byte1`, `byte2` | Byte positions within the report (1-indexed) | |
| 79 | +| `scale` | Sign modifier: `1` = normal, `-1` = inverted | |
| 80 | +| `bit` | For buttons: which bit in the byte (0-7) | |
| 81 | + |
| 82 | +### 4. Test Your Configuration |
| 83 | + |
| 84 | +```python |
| 85 | +import pyspacemouse |
| 86 | + |
| 87 | +# Check if device is recognized |
| 88 | +devices = pyspacemouse.get_connected_devices() |
| 89 | +print(devices) # Should show your device name |
| 90 | + |
| 91 | +# Test reading |
| 92 | +with pyspacemouse.open() as device: |
| 93 | + while True: |
| 94 | + state = device.read() |
| 95 | + print(f"X:{state.x:.2f} Y:{state.y:.2f} Z:{state.z:.2f}") |
| 96 | + print(f"Roll:{state.roll:.2f} Pitch:{state.pitch:.2f} Yaw:{state.yaw:.2f}") |
| 97 | + print(f"Buttons: {state.buttons}") |
| 98 | +``` |
| 99 | + |
| 100 | +### 5. Fine-tune Axis Directions |
| 101 | + |
| 102 | +If an axis moves in the wrong direction, change its `scale` from `1` to `-1` or vice versa in `devices.toml`. |
| 103 | + |
| 104 | +### 6. Submit a Pull Request |
| 105 | + |
| 106 | +Once your device works correctly: |
| 107 | + |
| 108 | +1. Create a branch: `git checkout -b add-device-<name>` |
| 109 | +2. Add your device entry to `devices.toml` |
| 110 | +3. Test thoroughly with the examples in `examples/` |
| 111 | +4. Submit a PR with your device name and any notes about testing |
| 112 | + |
| 113 | +### Using Custom Configuration (Without Modifying Library) |
| 114 | + |
| 115 | +If you don't want to modify the library, use `create_device_info()`: |
| 116 | + |
| 117 | +```python |
| 118 | +import pyspacemouse |
| 119 | + |
| 120 | +device_spec = pyspacemouse.create_device_info({ |
| 121 | + "name": "MyCustomDevice", |
| 122 | + "hid_id": [0x256F, 0xC652], |
| 123 | + "axis_scale": 350.0, |
| 124 | + "mappings": { |
| 125 | + "x": [1, 1, 2, 1], |
| 126 | + "y": [1, 3, 4, -1], |
| 127 | + "z": [1, 5, 6, -1], |
| 128 | + "pitch": [2, 1, 2, -1], |
| 129 | + "roll": [2, 3, 4, -1], |
| 130 | + "yaw": [2, 5, 6, 1], |
| 131 | + }, |
| 132 | + "buttons": { |
| 133 | + "LEFT": [3, 1, 0], |
| 134 | + "RIGHT": [3, 1, 1], |
| 135 | + }, |
| 136 | +}) |
| 137 | + |
| 138 | +with pyspacemouse.open(device_spec=device_spec) as device: |
| 139 | + state = device.read() |
| 140 | +``` |
| 141 | + |
| 142 | +See [Custom Device Configuration](https://spacemouse.kubaandrysek.cz/mouseApi/#custom-device-configuration) for more details. |
9 | 143 |
|
10 | 144 | ## How to write documentation |
11 | | -To install the required dependencies, run `pip install pyspacemouse[develop]`. |
| 145 | +To install the required dependencies, run `pip install pyspacemouse[docs]`. |
12 | 146 |
|
13 | 147 | Edit `README.md` only in the root folder. The documentation is automatically generated from `README.md` and `docs/` folder. |
14 | 148 | To update documentation from root to `/docs` use macro `make fixRelativeLinkDocs` which will replace all relative links from `/` to `/docs` folder. |
|
0 commit comments