paxini-sdk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- paxini_sdk-0.1.0/LICENSE +21 -0
- paxini_sdk-0.1.0/PKG-INFO +234 -0
- paxini_sdk-0.1.0/README.md +196 -0
- paxini_sdk-0.1.0/paxini_sdk/__init__.py +59 -0
- paxini_sdk-0.1.0/paxini_sdk/boards/__init__.py +6 -0
- paxini_sdk-0.1.0/paxini_sdk/boards/high_speed.py +414 -0
- paxini_sdk-0.1.0/paxini_sdk/boards/serial_converter.py +267 -0
- paxini_sdk-0.1.0/paxini_sdk/cli.py +205 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stdcp03a_points.json +1449 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stdcp03b_points.json +477 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stddp03a_points.json +825 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stddp03b_points.json +777 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stddp03c_points.json +711 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stddp03d_points.json +321 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stddp03e_points.json +591 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stddp03f_points.json +201 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stddp03g_points.json +327 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stdip03a_points.json +423 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stdip03b_points.json +165 -0
- paxini_sdk-0.1.0/paxini_sdk/data/pxsr_stdmc03a_points.json +69 -0
- paxini_sdk-0.1.0/paxini_sdk/data/registry.json +125 -0
- paxini_sdk-0.1.0/paxini_sdk/exceptions.py +25 -0
- paxini_sdk-0.1.0/paxini_sdk/protocol.py +414 -0
- paxini_sdk-0.1.0/paxini_sdk/recording.py +223 -0
- paxini_sdk-0.1.0/paxini_sdk/registers.py +144 -0
- paxini_sdk-0.1.0/paxini_sdk/sensor_registry.py +111 -0
- paxini_sdk-0.1.0/paxini_sdk/tools/__init__.py +1 -0
- paxini_sdk-0.1.0/paxini_sdk/tools/characterize.py +596 -0
- paxini_sdk-0.1.0/paxini_sdk/tools/record.py +110 -0
- paxini_sdk-0.1.0/paxini_sdk/tools/smoke_test.py +165 -0
- paxini_sdk-0.1.0/paxini_sdk/tools/smoke_test_serial.py +215 -0
- paxini_sdk-0.1.0/paxini_sdk/tools/to_rerun.py +398 -0
- paxini_sdk-0.1.0/paxini_sdk/transport.py +415 -0
- paxini_sdk-0.1.0/paxini_sdk.egg-info/PKG-INFO +234 -0
- paxini_sdk-0.1.0/paxini_sdk.egg-info/SOURCES.txt +44 -0
- paxini_sdk-0.1.0/paxini_sdk.egg-info/dependency_links.txt +1 -0
- paxini_sdk-0.1.0/paxini_sdk.egg-info/entry_points.txt +7 -0
- paxini_sdk-0.1.0/paxini_sdk.egg-info/requires.txt +18 -0
- paxini_sdk-0.1.0/paxini_sdk.egg-info/top_level.txt +1 -0
- paxini_sdk-0.1.0/pyproject.toml +57 -0
- paxini_sdk-0.1.0/setup.cfg +4 -0
- paxini_sdk-0.1.0/tests/test_auto_push_decoder.py +234 -0
- paxini_sdk-0.1.0/tests/test_module_force_decoder.py +84 -0
- paxini_sdk-0.1.0/tests/test_protocol.py +138 -0
- paxini_sdk-0.1.0/tests/test_recording.py +231 -0
- paxini_sdk-0.1.0/tests/test_serial_converter.py +69 -0
paxini_sdk-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jingyi Zou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: paxini-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Cross-platform Python SDK + tools for Paxini PX-6AX GEN3 multidimensional tactile sensors.
|
|
5
|
+
Author-email: Jingyi Zou <jingyizou1999@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/Jingyi-Z/paxini-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/Jingyi-Z/paxini-sdk/issues
|
|
9
|
+
Keywords: tactile,robotics,paxini,hall-effect,force-sensor
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: pyserial>=3.5
|
|
24
|
+
Provides-Extra: viz
|
|
25
|
+
Requires-Dist: rerun-sdk>=0.18; extra == "viz"
|
|
26
|
+
Provides-Extra: char
|
|
27
|
+
Requires-Dist: numpy>=1.20; extra == "char"
|
|
28
|
+
Requires-Dist: matplotlib>=3.5; extra == "char"
|
|
29
|
+
Provides-Extra: test
|
|
30
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
33
|
+
Requires-Dist: rerun-sdk>=0.18; extra == "dev"
|
|
34
|
+
Requires-Dist: openpyxl>=3.1; extra == "dev"
|
|
35
|
+
Requires-Dist: numpy>=1.20; extra == "dev"
|
|
36
|
+
Requires-Dist: matplotlib>=3.5; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# paxini-sdk
|
|
40
|
+
|
|
41
|
+
Cross-platform Python SDK and command-line tools for **Paxini PX-6AX GEN3
|
|
42
|
+
multidimensional tactile sensors** — Hall-effect tactile sensors that
|
|
43
|
+
report 3-axis resultant force plus a 9–239-point distributed-force grid
|
|
44
|
+
depending on the variant.
|
|
45
|
+
|
|
46
|
+
Talks to the hardware the vendor's Windows host app supports
|
|
47
|
+
(Serial Converter Board / High-Speed Communication Board), with byte-exact
|
|
48
|
+
protocol match verified against the vendor's reference scripts and
|
|
49
|
+
real-hardware cross-checks.
|
|
50
|
+
|
|
51
|
+
Status: **beta**. Verified on hardware:
|
|
52
|
+
|
|
53
|
+
- High-Speed Communication Board **PXSR-STDOTO4B** (FW02.22) with the
|
|
54
|
+
**DP-S2015-Elite** fingertip (PXSR-STDDP03G, 15 mm, 52 points) — 2026-05-18.
|
|
55
|
+
- Serial Converter Board with the **DP-L3530-Omega** fingertip
|
|
56
|
+
(PXSR-STDDP03A, 30 mm, 135 points) — 2026-05-19.
|
|
57
|
+
- Host OS: Windows 10/11 and macOS (both exercised on hardware).
|
|
58
|
+
|
|
59
|
+
> Disclaimer: this is a community wrapper, not an official Paxini SDK.
|
|
60
|
+
> Force-decoding rules cross-checked against the vendor's `Hand_UI.py` and
|
|
61
|
+
> `USB_UI.py` reference programs; cross-validation against the vendor host
|
|
62
|
+
> app's CSV output is documented in `docs/FINDINGS.md`.
|
|
63
|
+
|
|
64
|
+
## What ships
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
paxini_sdk/ Importable package
|
|
68
|
+
protocol.py Frame builders + parsers + LRC + fin error codes
|
|
69
|
+
transport.py pyserial wrapper; length-based frame readers
|
|
70
|
+
registers.py Register addresses, module-name table, bitmap parser
|
|
71
|
+
sensor_registry.py Lookup for 12 GEN3 sensor variants
|
|
72
|
+
recording.py Streaming CSV writer (vendor + native formats)
|
|
73
|
+
boards/
|
|
74
|
+
high_speed.py HighSpeedHandBoard + AutoPushFrame + AutoPushConfig
|
|
75
|
+
serial_converter.py SingleSensorBoard (Serial Converter Board)
|
|
76
|
+
data/ Per-variant (x, y, z) mm coordinate JSONs
|
|
77
|
+
tools/
|
|
78
|
+
smoke_test.py → paxini-smoke console script (high-speed)
|
|
79
|
+
smoke_test_serial.py → paxini-smoke-serial console script (serial board)
|
|
80
|
+
record.py → paxini-record console script
|
|
81
|
+
to_rerun.py → paxini-rerun console script
|
|
82
|
+
characterize.py → paxini-characterize console script
|
|
83
|
+
tests/ 52 offline unit tests (pytest)
|
|
84
|
+
docs/ Usage guide, Windows + Mac setup, full findings log
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Install
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# From a clone (recommended while in beta)
|
|
91
|
+
git clone https://github.com/Jingyi-Z/paxini-sdk.git
|
|
92
|
+
cd paxini-sdk
|
|
93
|
+
pip install -e ".[viz]" # viz: also installs rerun-sdk
|
|
94
|
+
|
|
95
|
+
# Or just the core (no visualizer)
|
|
96
|
+
pip install -e .
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Python ≥ 3.9. Only hard dependency is `pyserial`; `rerun-sdk` is optional
|
|
100
|
+
for visualization. Use `pip install -e ".[dev]"` for tests + everything.
|
|
101
|
+
|
|
102
|
+
## Two communication boards
|
|
103
|
+
|
|
104
|
+
The GEN3 sensors connect through one of two vendor boards; the SDK has a
|
|
105
|
+
driver class for each.
|
|
106
|
+
|
|
107
|
+
| Board | Driver class | Protocol | Rate | Sensors |
|
|
108
|
+
| --- | --- | --- | --- | --- |
|
|
109
|
+
| High-Speed Communication Board | `HighSpeedHandBoard` | auto-push stream | ~91 Hz | up to 28 modules; reports each module's point count |
|
|
110
|
+
| Serial Converter Board | `SingleSensorBoard` | request/response | ~176 Hz round-trip (length-based read) | one sensor; **cannot** report its model |
|
|
111
|
+
|
|
112
|
+
The High-Speed board reads the point count from register `0x0030`, so it
|
|
113
|
+
auto-detects the sensor variant. The Serial Converter Board has no such
|
|
114
|
+
register — you must tell `SingleSensorBoard` which sensor is attached
|
|
115
|
+
(`sensor="PXSR-..."` or `n_points=...`), exactly as the vendor `USB_UI.py`
|
|
116
|
+
makes the operator pick the model from a dropdown.
|
|
117
|
+
|
|
118
|
+
## Quick start
|
|
119
|
+
|
|
120
|
+
Plug the comm board into USB. Make sure the USB-to-UART driver is loaded
|
|
121
|
+
(CH340 on Windows, see `docs/SETUP_WINDOWS.md` / `docs/SETUP_MACOS.md`).
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Discover ports
|
|
125
|
+
paxini list
|
|
126
|
+
|
|
127
|
+
# --- High-Speed Communication Board ---
|
|
128
|
+
paxini-smoke --port COM7 --calibrate # Windows
|
|
129
|
+
paxini-smoke --port /dev/cu.usbserial-XXXX --calibrate # macOS
|
|
130
|
+
paxini-rerun --port COM7 --calibrate # 3D rerun viewer
|
|
131
|
+
paxini-record --port COM7 --out runs/session1.csv --calibrate
|
|
132
|
+
|
|
133
|
+
# --- Serial Converter Board (must name the sensor) ---
|
|
134
|
+
paxini-smoke-serial --port COM3 --sensor PXSR-STDDP03A --calibrate
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Replay an existing host-app CSV without hardware:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
paxini-rerun --csv data/2026-05-18-160858.csv
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Python API
|
|
144
|
+
|
|
145
|
+
High-Speed Communication Board:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from paxini_sdk import HighSpeedHandBoard
|
|
149
|
+
|
|
150
|
+
with HighSpeedHandBoard("COM7") as hand:
|
|
151
|
+
print("Firmware:", hand.read_version())
|
|
152
|
+
hand.calibrate()
|
|
153
|
+
for frame in hand.stream_auto_push(duration=10.0):
|
|
154
|
+
forces = frame.resultant_forces_newtons
|
|
155
|
+
# {'Index-Tip': (0.2, -0.1, 0.8)} in N
|
|
156
|
+
distributed = frame.distributed_forces_newtons
|
|
157
|
+
# {'Index-Tip': [(0.0, 0.0, 0.4), (0.0, 0.0, 0.5), ...]}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Serial Converter Board (request/response; name the sensor so the
|
|
161
|
+
distributed-force read uses the right length):
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from paxini_sdk import SingleSensorBoard
|
|
165
|
+
|
|
166
|
+
with SingleSensorBoard("COM3", sensor="PXSR-STDDP03A") as board:
|
|
167
|
+
board.calibrate()
|
|
168
|
+
fx, fy, fz = board.read_resultant_force() # raw counts
|
|
169
|
+
points = board.read_distributed_force() # list of DistributedPoint
|
|
170
|
+
# multiply counts by 0.1 for newtons
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Force decoding rules (verified against vendor `Hand_UI.py` / `USB_UI.py`):
|
|
174
|
+
|
|
175
|
+
- High-speed module: 6 wire bytes `[Fx_lo Fx_hi Fy_lo Fy_hi Fz_lo Fz_hi]`,
|
|
176
|
+
only low bytes meaningful, Fx/Fy signed int8, Fz uint8.
|
|
177
|
+
- Each distributed-force point: 3 wire bytes `[Fx_lo Fy_lo Fz_lo]`,
|
|
178
|
+
same signed/unsigned rule.
|
|
179
|
+
- Scale: 0.1 N / LSB on every axis.
|
|
180
|
+
|
|
181
|
+
See `docs/USAGE_GUIDE.md` for the full walkthrough and `docs/FINDINGS.md`
|
|
182
|
+
for the protocol-decoding write-up and bugs found during cross-validation.
|
|
183
|
+
|
|
184
|
+
## Run the tests
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pip install -e ".[test]"
|
|
188
|
+
pytest -q
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Should print `52 passed`. Tests don't need hardware — they verify frame
|
|
192
|
+
builders, parsers, LRC, the payload-aware decoder, and the Serial Converter
|
|
193
|
+
Board point-count handling against synthetic frames and the vendor protocol
|
|
194
|
+
PDF's worked examples.
|
|
195
|
+
|
|
196
|
+
## Supported hardware
|
|
197
|
+
|
|
198
|
+
| Sensor variant | Vendor part code | Points |
|
|
199
|
+
| --- | --- | --- |
|
|
200
|
+
| MC-M2020-Elite (palm) | PXSR-STDMC03A | 9 |
|
|
201
|
+
| IP-S1610-Elite (finger pad) | PXSR-STDIP03B | 25 |
|
|
202
|
+
| DP-S1813-Elite (13 mm fingertip) | PXSR-STDDP03F | 31 |
|
|
203
|
+
| DP-S1813-Core (13 mm fingertip) | PXSR-STDDP03D | 51 |
|
|
204
|
+
| **DP-S2015-Elite (15 mm fingertip)** | **PXSR-STDDP03G** | **52** |
|
|
205
|
+
| IP-M2324-Core (finger pad) | PXSR-STDIP03A | 68 |
|
|
206
|
+
| CP-M3025-Core (finger pad) | PXSR-STDCP03B | 77 |
|
|
207
|
+
| DP-S3013-Core (integrated tip+pad) | PXSR-STDDP03E | 96 |
|
|
208
|
+
| DP-S2716-Core (16 mm fingertip) | PXSR-STDDP03C | 116 |
|
|
209
|
+
| DP-M2826-Omega (26 mm fingertip) | PXSR-STDDP03B | 127 |
|
|
210
|
+
| **DP-L3530-Omega (30 mm fingertip)** | **PXSR-STDDP03A** | **135** |
|
|
211
|
+
| CP-L5325-Omega (finger pad) | PXSR-STDCP03A | 239 |
|
|
212
|
+
|
|
213
|
+
All 12 variants have distinct point counts, so the High-Speed board's
|
|
214
|
+
reported count resolves the variant unambiguously. The Serial Converter
|
|
215
|
+
Board does not report a point count — pass the part code explicitly.
|
|
216
|
+
|
|
217
|
+
| Comm board | Class | Status |
|
|
218
|
+
| --- | --- | --- |
|
|
219
|
+
| **High-Speed Communication Board** | `HighSpeedHandBoard` | Verified on hardware (2026-05-18) |
|
|
220
|
+
| **Serial Converter Board** | `SingleSensorBoard` | Verified on hardware (2026-05-19) |
|
|
221
|
+
| 10-Channel SPI Hub | Not implemented | Patches welcome |
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT. See `LICENSE`.
|
|
226
|
+
|
|
227
|
+
## Acknowledgements
|
|
228
|
+
|
|
229
|
+
Built against the vendor's reference scripts shipped in the
|
|
230
|
+
*PaXini PX-6AX GEN3 product package_20251202* (`Hand_UI.py`,
|
|
231
|
+
`Read_Single_Sensor_Hand.py`, `Read_Single_Sensor_Usb.py`, `USB_UI.py`,
|
|
232
|
+
`Read_Single_Sensor_Spi.py`) and the *Communication Board Communication
|
|
233
|
+
Protocol_V1.0.5* PDF. The vendor docs were the source of truth for every
|
|
234
|
+
framing decision; the wrapper code is original.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# paxini-sdk
|
|
2
|
+
|
|
3
|
+
Cross-platform Python SDK and command-line tools for **Paxini PX-6AX GEN3
|
|
4
|
+
multidimensional tactile sensors** — Hall-effect tactile sensors that
|
|
5
|
+
report 3-axis resultant force plus a 9–239-point distributed-force grid
|
|
6
|
+
depending on the variant.
|
|
7
|
+
|
|
8
|
+
Talks to the hardware the vendor's Windows host app supports
|
|
9
|
+
(Serial Converter Board / High-Speed Communication Board), with byte-exact
|
|
10
|
+
protocol match verified against the vendor's reference scripts and
|
|
11
|
+
real-hardware cross-checks.
|
|
12
|
+
|
|
13
|
+
Status: **beta**. Verified on hardware:
|
|
14
|
+
|
|
15
|
+
- High-Speed Communication Board **PXSR-STDOTO4B** (FW02.22) with the
|
|
16
|
+
**DP-S2015-Elite** fingertip (PXSR-STDDP03G, 15 mm, 52 points) — 2026-05-18.
|
|
17
|
+
- Serial Converter Board with the **DP-L3530-Omega** fingertip
|
|
18
|
+
(PXSR-STDDP03A, 30 mm, 135 points) — 2026-05-19.
|
|
19
|
+
- Host OS: Windows 10/11 and macOS (both exercised on hardware).
|
|
20
|
+
|
|
21
|
+
> Disclaimer: this is a community wrapper, not an official Paxini SDK.
|
|
22
|
+
> Force-decoding rules cross-checked against the vendor's `Hand_UI.py` and
|
|
23
|
+
> `USB_UI.py` reference programs; cross-validation against the vendor host
|
|
24
|
+
> app's CSV output is documented in `docs/FINDINGS.md`.
|
|
25
|
+
|
|
26
|
+
## What ships
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
paxini_sdk/ Importable package
|
|
30
|
+
protocol.py Frame builders + parsers + LRC + fin error codes
|
|
31
|
+
transport.py pyserial wrapper; length-based frame readers
|
|
32
|
+
registers.py Register addresses, module-name table, bitmap parser
|
|
33
|
+
sensor_registry.py Lookup for 12 GEN3 sensor variants
|
|
34
|
+
recording.py Streaming CSV writer (vendor + native formats)
|
|
35
|
+
boards/
|
|
36
|
+
high_speed.py HighSpeedHandBoard + AutoPushFrame + AutoPushConfig
|
|
37
|
+
serial_converter.py SingleSensorBoard (Serial Converter Board)
|
|
38
|
+
data/ Per-variant (x, y, z) mm coordinate JSONs
|
|
39
|
+
tools/
|
|
40
|
+
smoke_test.py → paxini-smoke console script (high-speed)
|
|
41
|
+
smoke_test_serial.py → paxini-smoke-serial console script (serial board)
|
|
42
|
+
record.py → paxini-record console script
|
|
43
|
+
to_rerun.py → paxini-rerun console script
|
|
44
|
+
characterize.py → paxini-characterize console script
|
|
45
|
+
tests/ 52 offline unit tests (pytest)
|
|
46
|
+
docs/ Usage guide, Windows + Mac setup, full findings log
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# From a clone (recommended while in beta)
|
|
53
|
+
git clone https://github.com/Jingyi-Z/paxini-sdk.git
|
|
54
|
+
cd paxini-sdk
|
|
55
|
+
pip install -e ".[viz]" # viz: also installs rerun-sdk
|
|
56
|
+
|
|
57
|
+
# Or just the core (no visualizer)
|
|
58
|
+
pip install -e .
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Python ≥ 3.9. Only hard dependency is `pyserial`; `rerun-sdk` is optional
|
|
62
|
+
for visualization. Use `pip install -e ".[dev]"` for tests + everything.
|
|
63
|
+
|
|
64
|
+
## Two communication boards
|
|
65
|
+
|
|
66
|
+
The GEN3 sensors connect through one of two vendor boards; the SDK has a
|
|
67
|
+
driver class for each.
|
|
68
|
+
|
|
69
|
+
| Board | Driver class | Protocol | Rate | Sensors |
|
|
70
|
+
| --- | --- | --- | --- | --- |
|
|
71
|
+
| High-Speed Communication Board | `HighSpeedHandBoard` | auto-push stream | ~91 Hz | up to 28 modules; reports each module's point count |
|
|
72
|
+
| Serial Converter Board | `SingleSensorBoard` | request/response | ~176 Hz round-trip (length-based read) | one sensor; **cannot** report its model |
|
|
73
|
+
|
|
74
|
+
The High-Speed board reads the point count from register `0x0030`, so it
|
|
75
|
+
auto-detects the sensor variant. The Serial Converter Board has no such
|
|
76
|
+
register — you must tell `SingleSensorBoard` which sensor is attached
|
|
77
|
+
(`sensor="PXSR-..."` or `n_points=...`), exactly as the vendor `USB_UI.py`
|
|
78
|
+
makes the operator pick the model from a dropdown.
|
|
79
|
+
|
|
80
|
+
## Quick start
|
|
81
|
+
|
|
82
|
+
Plug the comm board into USB. Make sure the USB-to-UART driver is loaded
|
|
83
|
+
(CH340 on Windows, see `docs/SETUP_WINDOWS.md` / `docs/SETUP_MACOS.md`).
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Discover ports
|
|
87
|
+
paxini list
|
|
88
|
+
|
|
89
|
+
# --- High-Speed Communication Board ---
|
|
90
|
+
paxini-smoke --port COM7 --calibrate # Windows
|
|
91
|
+
paxini-smoke --port /dev/cu.usbserial-XXXX --calibrate # macOS
|
|
92
|
+
paxini-rerun --port COM7 --calibrate # 3D rerun viewer
|
|
93
|
+
paxini-record --port COM7 --out runs/session1.csv --calibrate
|
|
94
|
+
|
|
95
|
+
# --- Serial Converter Board (must name the sensor) ---
|
|
96
|
+
paxini-smoke-serial --port COM3 --sensor PXSR-STDDP03A --calibrate
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Replay an existing host-app CSV without hardware:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
paxini-rerun --csv data/2026-05-18-160858.csv
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Python API
|
|
106
|
+
|
|
107
|
+
High-Speed Communication Board:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from paxini_sdk import HighSpeedHandBoard
|
|
111
|
+
|
|
112
|
+
with HighSpeedHandBoard("COM7") as hand:
|
|
113
|
+
print("Firmware:", hand.read_version())
|
|
114
|
+
hand.calibrate()
|
|
115
|
+
for frame in hand.stream_auto_push(duration=10.0):
|
|
116
|
+
forces = frame.resultant_forces_newtons
|
|
117
|
+
# {'Index-Tip': (0.2, -0.1, 0.8)} in N
|
|
118
|
+
distributed = frame.distributed_forces_newtons
|
|
119
|
+
# {'Index-Tip': [(0.0, 0.0, 0.4), (0.0, 0.0, 0.5), ...]}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Serial Converter Board (request/response; name the sensor so the
|
|
123
|
+
distributed-force read uses the right length):
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from paxini_sdk import SingleSensorBoard
|
|
127
|
+
|
|
128
|
+
with SingleSensorBoard("COM3", sensor="PXSR-STDDP03A") as board:
|
|
129
|
+
board.calibrate()
|
|
130
|
+
fx, fy, fz = board.read_resultant_force() # raw counts
|
|
131
|
+
points = board.read_distributed_force() # list of DistributedPoint
|
|
132
|
+
# multiply counts by 0.1 for newtons
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Force decoding rules (verified against vendor `Hand_UI.py` / `USB_UI.py`):
|
|
136
|
+
|
|
137
|
+
- High-speed module: 6 wire bytes `[Fx_lo Fx_hi Fy_lo Fy_hi Fz_lo Fz_hi]`,
|
|
138
|
+
only low bytes meaningful, Fx/Fy signed int8, Fz uint8.
|
|
139
|
+
- Each distributed-force point: 3 wire bytes `[Fx_lo Fy_lo Fz_lo]`,
|
|
140
|
+
same signed/unsigned rule.
|
|
141
|
+
- Scale: 0.1 N / LSB on every axis.
|
|
142
|
+
|
|
143
|
+
See `docs/USAGE_GUIDE.md` for the full walkthrough and `docs/FINDINGS.md`
|
|
144
|
+
for the protocol-decoding write-up and bugs found during cross-validation.
|
|
145
|
+
|
|
146
|
+
## Run the tests
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
pip install -e ".[test]"
|
|
150
|
+
pytest -q
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Should print `52 passed`. Tests don't need hardware — they verify frame
|
|
154
|
+
builders, parsers, LRC, the payload-aware decoder, and the Serial Converter
|
|
155
|
+
Board point-count handling against synthetic frames and the vendor protocol
|
|
156
|
+
PDF's worked examples.
|
|
157
|
+
|
|
158
|
+
## Supported hardware
|
|
159
|
+
|
|
160
|
+
| Sensor variant | Vendor part code | Points |
|
|
161
|
+
| --- | --- | --- |
|
|
162
|
+
| MC-M2020-Elite (palm) | PXSR-STDMC03A | 9 |
|
|
163
|
+
| IP-S1610-Elite (finger pad) | PXSR-STDIP03B | 25 |
|
|
164
|
+
| DP-S1813-Elite (13 mm fingertip) | PXSR-STDDP03F | 31 |
|
|
165
|
+
| DP-S1813-Core (13 mm fingertip) | PXSR-STDDP03D | 51 |
|
|
166
|
+
| **DP-S2015-Elite (15 mm fingertip)** | **PXSR-STDDP03G** | **52** |
|
|
167
|
+
| IP-M2324-Core (finger pad) | PXSR-STDIP03A | 68 |
|
|
168
|
+
| CP-M3025-Core (finger pad) | PXSR-STDCP03B | 77 |
|
|
169
|
+
| DP-S3013-Core (integrated tip+pad) | PXSR-STDDP03E | 96 |
|
|
170
|
+
| DP-S2716-Core (16 mm fingertip) | PXSR-STDDP03C | 116 |
|
|
171
|
+
| DP-M2826-Omega (26 mm fingertip) | PXSR-STDDP03B | 127 |
|
|
172
|
+
| **DP-L3530-Omega (30 mm fingertip)** | **PXSR-STDDP03A** | **135** |
|
|
173
|
+
| CP-L5325-Omega (finger pad) | PXSR-STDCP03A | 239 |
|
|
174
|
+
|
|
175
|
+
All 12 variants have distinct point counts, so the High-Speed board's
|
|
176
|
+
reported count resolves the variant unambiguously. The Serial Converter
|
|
177
|
+
Board does not report a point count — pass the part code explicitly.
|
|
178
|
+
|
|
179
|
+
| Comm board | Class | Status |
|
|
180
|
+
| --- | --- | --- |
|
|
181
|
+
| **High-Speed Communication Board** | `HighSpeedHandBoard` | Verified on hardware (2026-05-18) |
|
|
182
|
+
| **Serial Converter Board** | `SingleSensorBoard` | Verified on hardware (2026-05-19) |
|
|
183
|
+
| 10-Channel SPI Hub | Not implemented | Patches welcome |
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT. See `LICENSE`.
|
|
188
|
+
|
|
189
|
+
## Acknowledgements
|
|
190
|
+
|
|
191
|
+
Built against the vendor's reference scripts shipped in the
|
|
192
|
+
*PaXini PX-6AX GEN3 product package_20251202* (`Hand_UI.py`,
|
|
193
|
+
`Read_Single_Sensor_Hand.py`, `Read_Single_Sensor_Usb.py`, `USB_UI.py`,
|
|
194
|
+
`Read_Single_Sensor_Spi.py`) and the *Communication Board Communication
|
|
195
|
+
Protocol_V1.0.5* PDF. The vendor docs were the source of truth for every
|
|
196
|
+
framing decision; the wrapper code is original.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""paxini_sdk — cross-platform Python SDK for Paxini PX-6AX GEN3 multidimensional
|
|
2
|
+
tactile sensors.
|
|
3
|
+
|
|
4
|
+
This package wraps the GEN3 communication protocol used by the official
|
|
5
|
+
Paxini USB communication boards (Serial Converter Board and High-Speed
|
|
6
|
+
Communication Board) so that the sensors can be driven on macOS / Linux / Windows
|
|
7
|
+
without the vendor's Windows-only host application.
|
|
8
|
+
|
|
9
|
+
Quick start:
|
|
10
|
+
|
|
11
|
+
from paxini_sdk import list_serial_ports, SingleSensorBoard
|
|
12
|
+
|
|
13
|
+
print(list_serial_ports())
|
|
14
|
+
with SingleSensorBoard("/dev/tty.usbserial-XXXX") as board:
|
|
15
|
+
board.calibrate()
|
|
16
|
+
fx, fy, fz = board.read_resultant_force()
|
|
17
|
+
print(fx, fy, fz)
|
|
18
|
+
|
|
19
|
+
For the high-speed (robotic hand) board:
|
|
20
|
+
|
|
21
|
+
from paxini_sdk import HighSpeedHandBoard
|
|
22
|
+
|
|
23
|
+
with HighSpeedHandBoard("/dev/tty.usbserial-XXXX") as hand:
|
|
24
|
+
print(hand.read_version())
|
|
25
|
+
for frame in hand.stream_auto_push(duration=5.0):
|
|
26
|
+
print(frame.module_forces)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from .exceptions import (
|
|
30
|
+
PaxiniError,
|
|
31
|
+
FrameError,
|
|
32
|
+
LRCError,
|
|
33
|
+
DeviceError,
|
|
34
|
+
TimeoutError as PaxiniTimeoutError,
|
|
35
|
+
)
|
|
36
|
+
from .protocol import lrc, build_fin_request, build_simple_request, parse_simple_response
|
|
37
|
+
from .transport import SerialTransport, list_serial_ports
|
|
38
|
+
from .boards.serial_converter import SingleSensorBoard
|
|
39
|
+
from .boards.high_speed import HighSpeedHandBoard, AutoPushFrame
|
|
40
|
+
|
|
41
|
+
__version__ = "0.1.0"
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
"PaxiniError",
|
|
45
|
+
"FrameError",
|
|
46
|
+
"LRCError",
|
|
47
|
+
"DeviceError",
|
|
48
|
+
"PaxiniTimeoutError",
|
|
49
|
+
"lrc",
|
|
50
|
+
"build_fin_request",
|
|
51
|
+
"build_simple_request",
|
|
52
|
+
"parse_simple_response",
|
|
53
|
+
"SerialTransport",
|
|
54
|
+
"list_serial_ports",
|
|
55
|
+
"SingleSensorBoard",
|
|
56
|
+
"HighSpeedHandBoard",
|
|
57
|
+
"AutoPushFrame",
|
|
58
|
+
"__version__",
|
|
59
|
+
]
|