Software & Driver Setup
Install the Paxini SDK, stream pressure data in Python, visualize contact heatmaps, add optional ROS2 integration, and synchronize with your robot arm for full data collection pipelines.
Install the Paxini SDK
The Paxini Gen3 communicates over USB HID — no kernel modules or vendor drivers required. The Python SDK wraps the low-level HID protocol and exposes a clean streaming API.
Verify the install:
Detecting the Sensor
Plug the Gen3 sensor into your computer via USB-C. Use the SDK's device discovery utility to confirm it is recognized:
For multi-sensor setups (e.g., five fingers on a USB hub):
sudo python -m paxini.install_udev once to install the rule, then unplug and replug the sensor.
Python Streaming API
The core API is a callback-based stream. Each frame delivers a TactileFrame object containing the full pressure array and metadata.
All public API methods:
| Method / Property | Description | Returns |
|---|---|---|
| sensor.start() | Begin streaming; non-blocking | None |
| sensor.stop() | Stop the stream cleanly | None |
| sensor.stream() | Generator yielding TactileFrame objects at configured Hz | Generator[TactileFrame] |
| sensor.latest() | Returns the most recent frame without blocking | TactileFrame |
| sensor.set_rate(hz) | Set sample rate (50–500 Hz for USB-C, 50–200 Hz for BLE) | None |
| sensor.calibrate() | Zero-offset calibration against current resting load | None |
| sensor.serial | Device serial number string | str |
| sensor.variant | "fingertip" | "finger-pad" | "palm" | str |
Tactile Data Format
Each TactileFrame contains:
| Field | Type | Description |
|---|---|---|
| frame.timestamp_ns | int | Nanosecond timestamp (monotonic, host clock) |
| frame.pressure_map | np.ndarray (H, W) float32 | Pressure in kPa per taxel. Shape varies by variant: fingertip is 8×8, palm is 16×12. |
| frame.contact_mask | np.ndarray (H, W) bool | True where pressure exceeds contact threshold (default: 5 kPa) |
| frame.contact_area_mm2 | float | Sum of active taxel areas in mm² |
| frame.total_force_n | float | Integrated normal force across all taxels, in Newtons |
| frame.contact_centroid | (float, float) | (row, col) centroid of the contact region in taxel coordinates |
| frame.in_contact | bool | True if total_force_n exceeds contact threshold (default: 0.05 N) |
| frame.seq | int | Monotonically increasing frame sequence number |
Live Heatmap Visualization
The SDK ships a ready-to-run live visualizer. Run it directly from the command line:
Or embed in your own script using the paxini.viz module:
ROS2 Interface
The ROS2 bridge publishes a sensor_msgs/Image (pressure map) and a custom paxini_msgs/TactileFrame topic per sensor. Requires ROS2 Humble or Jazzy.
For multi-sensor setups, each device publishes under its serial number. You can remap topics in your launch file using standard ROS2 remapping.
Robot Arm Integration
To synchronize Paxini data with robot arm joint state, use the paxini.sync module. It timestamps all sensor frames against a shared clock and provides a blocking API that yields synchronized (arm_state, tactile_frame) pairs:
MultiSourceSync class handles interpolation when arm and sensor rates differ.
Top 3 Issues
The sensor is not being detected. Check in order: (1) Try a different USB-C cable — some cables are charge-only and do not carry data. (2) On Linux, run sudo python -m paxini.install_udev then unplug/replug the sensor. (3) Confirm the sensor LED is solid (not blinking) — blinking means it is in firmware update mode; hold the reset button for 5 seconds to exit.
The sensor needs calibration or the threshold is set too high. Run sensor.calibrate() with the sensor unloaded (no contact). If the issue persists, check that the sensor variant matches your mount — a palm sensor installed on a fingertip will show very low pressure values due to the larger taxel area. Also confirm firmware version 1.2+ with python -m paxini.discover.
The arm interface clock and sensor timestamp are diverging by more than max_dt_ms. This is usually caused by the arm SDK returning a stale joint state (e.g., buffered at a lower rate). Increase max_dt_ms to 10.0 as a first test, then investigate why the arm state refresh rate is lower than expected. For USB arms, confirm the USB polling rate is not being throttled by power management (sudo powertop on Linux).
Still stuck? Post in the forum questions thread with your OS, SDK version (paxini.__version__), and the exact error output.