Juqiao Tactile Glove

Software & Driver Setup

Install the USB CDC driver, stream 64-node pressure data in Python, visualize contact heatmaps, and integrate with Orca Hand recording pipelines.

Step 1 — Installation

Install the juqiao-glove Package

The glove communicates over USB CDC serial — no kernel modules, no custom drivers. The Python package wraps pyserial and handles the binary frame protocol.

Any OS supported The glove appears as a standard CDC-ACM serial device. Windows, macOS, and Linux all enumerate it automatically with inbox drivers. No vendor driver installer required.
# Python 3.10+ recommended pip install juqiao-glove # Or with optional visualization extras (matplotlib, numpy) pip install "juqiao-glove[viz]" # Or with ROS2 bridge extras (requires ROS2 Humble or later) pip install "juqiao-glove[ros2]"

Verify the install:

python -c "import juqiao_glove; print(juqiao_glove.__version__)" # Expected: 0.4.x or later
Step 2 — Port Detection

Detecting the USB Port

Plug in the glove via the 1.5 m USB-C cable. The device enumerates as a CDC-ACM serial port.

OSTypical port nameNotes
Linux/dev/ttyACM0Add user to dialout group if permission denied
macOS/dev/tty.usbmodem*Use ls /dev/tty.usb* to find exact name
WindowsCOM3 (varies)Check Device Manager → Ports (COM & LPT)

Auto-detect the glove from Python:

from juqiao_glove import JuqiaoGlove # Auto-scan all serial ports and return the first Juqiao device found glove = JuqiaoGlove.find() print(glove.port) # → '/dev/ttyACM0' or 'COM3' etc. print(glove.info()) # → firmware version, node count, sample rate

Or specify the port explicitly:

glove = JuqiaoGlove(port="/dev/ttyACM0", baudrate=3000000)
Linux permission error? Run sudo usermod -aG dialout $USER then log out and back in. Alternatively, use sudo chmod 666 /dev/ttyACM0 for a one-session workaround.
Step 3 — Streaming API

Python Streaming API

The glove streams at 200 Hz. Each frame contains a 64-element pressure array (16-bit ADC, normalized 0.0–1.0) plus a timestamp.

from juqiao_glove import JuqiaoGlove import time glove = JuqiaoGlove.find() glove.connect() # Single-frame read frame = glove.read_frame() print(frame.timestamp) # float, seconds since epoch print(frame.pressures) # np.ndarray shape (64,), float32, range 0.0-1.0 print(frame.pressures.reshape(8, 8)) # 8×8 spatial grid # Continuous callback stream def on_frame(frame): max_node = frame.pressures.argmax() print(f"t={frame.timestamp:.4f} peak_node={max_node} val={frame.pressures[max_node]:.3f}") glove.stream(callback=on_frame, duration=5.0) # stream for 5 seconds # Or use as an iterator with glove.stream() as frames: for frame in frames: process(frame) if done: break glove.disconnect()

Frame Object Reference

AttributeTypeDescription
frame.timestampfloatHost-side receive time (seconds, Unix epoch)
frame.pressuresnp.ndarray (64,)Normalized pressure per node, 0.0 (none) to 1.0 (max)
frame.pressures_rawnp.ndarray (64,)Raw 16-bit ADC counts (0–65535)
frame.contact_masknp.ndarray (64,) boolTrue where pressure exceeds threshold (default 0.05)
frame.contact_nodesList[int]Indices of nodes currently in contact
frame.grasp_regionstr or NoneHeuristic region: "palm", "thumb", "index", "middle", "ring", "pinky", None
frame.sequenceintFrame counter (wraps at 65535); use to detect dropped frames
Reference — Sensor Layout

64-Node Sensor Layout

The 64 taxels are arranged as a woven fiber matrix covering the palm and all five finger segments. Node indices follow a consistent dorsal-view row-major order.

0–12
Palm (central pad)
13–23
Thumb (3 segments)
24–34
Index finger
35–45
Middle finger
46–54
Ring finger
55–63
Pinky finger
# Access region slices by name from juqiao_glove.layout import REGION_SLICES palm_nodes = frame.pressures[REGION_SLICES["palm"]] thumb_nodes = frame.pressures[REGION_SLICES["thumb"]] index_nodes = frame.pressures[REGION_SLICES["index"]] # Reshape to 8×8 spatial grid (dorsal view, row-major) grid = frame.pressures.reshape(8, 8)
Optional — Visualization

Pressure Heatmap Visualization

The [viz] extra installs a live matplotlib heatmap renderer useful for calibration and debugging.

# Requires: pip install "juqiao-glove[viz]" from juqiao_glove import JuqiaoGlove from juqiao_glove.viz import PressureHeatmap glove = JuqiaoGlove.find() glove.connect() viz = PressureHeatmap(title="Juqiao Glove — Live Pressure") viz.show(glove) # Opens a matplotlib window; press Q to quit

For headless environments or data review, save frames as a video:

from juqiao_glove.viz import record_heatmap_video record_heatmap_video( input_npy="session_pressures.npy", # shape (N, 64) saved during recording output_mp4="heatmap.mp4", fps=30, colormap="inferno", )
Optional — ROS2

ROS2 Interface

The juqiao_glove_ros2 package publishes a custom TactileArray message at 200 Hz. Compatible with ROS2 Humble and Iron.

# Install the package (requires ROS2 to be sourced) pip install "juqiao-glove[ros2]" # Or build from source in your workspace cd ~/ros2_ws/src git clone https://github.com/roboticscenter/juqiao_glove_ros2 cd ~/ros2_ws && colcon build --packages-select juqiao_glove_ros2

Launch the driver node:

source /opt/ros/humble/setup.bash source ~/ros2_ws/install/setup.bash # Auto-detect port ros2 launch juqiao_glove_ros2 glove.launch.py # Specify port explicitly ros2 launch juqiao_glove_ros2 glove.launch.py port:=/dev/ttyACM0

Topics published:

TopicMessage typeRateDescription
/juqiao_glove/tactile_arrayjuqiao_glove_ros2/TactileArray200 HzFull 64-node pressure array
/juqiao_glove/contact_maskstd_msgs/UInt8MultiArray200 HzBinary contact per node (0 or 1)
/juqiao_glove/grasp_regionstd_msgs/String200 HzActive region heuristic or empty string
/juqiao_glove/statusdiagnostic_msgs/DiagnosticStatus1 HzFirmware version, frame drop rate

Combined Orca Hand + Glove Launch

When using the glove alongside the Orca Hand for synchronized recording:

# Launch Orca Hand driver ros2 launch orca_ros2 orca_hand.launch.py port:=/dev/ttyUSB0 # In a second terminal, launch Juqiao Glove driver ros2 launch juqiao_glove_ros2 glove.launch.py port:=/dev/ttyACM0 # Verify synchronized topics ros2 topic list | grep -E "orca|juqiao" ros2 topic hz /juqiao_glove/tactile_array ros2 topic hz /orca_hand/joint_states
Step 4 — Calibration

Baseline Calibration

The glove ships with factory calibration. Recalibrate if you notice baseline drift (nodes reading non-zero at rest) or after extended storage.

Remove the glove before calibrating Calibration captures the zero-pressure baseline. Do not wear or touch the glove during the calibration sequence — lay it flat on a surface.
# CLI calibration — lay glove flat, do not touch python -m juqiao_glove.calibrate --port /dev/ttyACM0 # Or from Python from juqiao_glove import JuqiaoGlove glove = JuqiaoGlove.find() glove.connect() glove.calibrate_baseline(duration=3.0) # averages 3 seconds of idle frames glove.save_calibration("~/.juqiao_glove_cal.json") glove.disconnect()

Load calibration at runtime:

glove = JuqiaoGlove.find() glove.connect() glove.load_calibration("~/.juqiao_glove_cal.json") # Now frame.pressures reflects calibrated values frame = glove.read_frame() print(frame.pressures.max()) # Should be ~0.0 at rest

Threshold Tuning

The default contact threshold is 0.05 (5% of full scale). Adjust per task:

# For delicate objects (lower threshold detects light touch) glove.set_contact_threshold(0.02) # For heavy manipulation tasks (reduce false positives) glove.set_contact_threshold(0.10) # Per-region thresholds glove.set_contact_threshold({"palm": 0.08, "thumb": 0.03, "index": 0.03})
Troubleshooting

Common Issues

SerialException: [Errno 13] Permission denied: '/dev/ttyACM0'
Run sudo usermod -aG dialout $USER then log out and back in. Alternatively: sudo chmod 666 /dev/ttyACM0 (resets on unplug).
JuqiaoGlove.find() returned None — no device found
Check USB connection. Run dmesg | tail -20 (Linux) or ls /dev/tty.usb* (macOS) to verify OS enumerated the device. Try a different USB port or cable (the connector is USB-C but must be a data cable, not charge-only).
All 64 nodes read 0.0 — no pressure data
Call glove.info() to confirm firmware responds. If it does, check that calibration file isn't over-subtracting. Delete ~/.juqiao_glove_cal.json and recalibrate with the glove lying flat.
Baseline drift — nodes read 0.1–0.2 at rest
Recalibrate: lay glove flat with no pressure and run glove.calibrate_baseline(). Can occur after temperature changes or extended storage. If drift > 0.4 with glove flat, the sensing fabric may need replacement (contact Juqiao support).
Frame drops — sequence numbers skip
Check USB cable quality and port. Use a USB 3.0 port. On Linux, avoid USB hubs with other high-bandwidth devices. Ensure your on_frame callback returns quickly — do heavy processing in a separate thread.
ROS2 node starts but no messages on /juqiao_glove/tactile_array
Verify the port argument: ros2 launch juqiao_glove_ros2 glove.launch.py port:=/dev/ttyACM0. Check node logs: ros2 node info /juqiao_glove_driver. Ensure the dialout group fix was applied to the user running the ROS2 node.