Overview
The rawtactile stream gives a z-score per taxel, which doesn’t tell you whether anything touched the glove. Tactile calibration trains a contact model that turns that raw signal into two directly usable streams: tactile_binary for contact or not, and tactile_residual for continuous contact strength.
The model is scoped by SDK user and glove serial number, and once installed it loads automatically at runtime with no path to specify in code.
The flow is: record four guided motions, train, install into the runtime directory. The whole thing takes about 2 to 5 minutes depending on how long you record each motion.
Matching examples: examples/python/wuji_glove/7.tactile_calibration.py and examples/c/wuji_glove/5_tactile_calibration.c.
For when to calibrate, where output is stored, and version requirements, see Calibration and Configuration. This page covers only how to run it and what the measurements show.
Prerequisites
Hardware
Calibration reads sensors and writes an SDK-side model file. It writes no firmware.
Software
The training step needs an SDK built with
model-export. A build without it fails during training.
- Python
- C
Before You Start
Nothing required. Tactile calibration and hand model calibration are independent, and each runs on its own.Four Guided Motions
step_total measures 4, in a fixed order:
Together the four motions must cover the entire tactile array. Any region that never gets pressed is one the trainer treats as dead taxels.
Data Flow
Prompt Protocol
on_pose_prompt is the interaction hub of this flow, firing twice per motion for 8 calls in a full round.
Two Kinds
pose_ready lets you tell the user to get ready. pose_review reports capture quality for that motion so the user can keep it or redo it.
Only Four Return Values Are Valid
Anything else raises
RuntimeError rather than warning. This is the first thing you’ll hit when integrating.
State Machine
A full round captured 11 state transitions withseconds_per_pose=3.0 and epochs=5:
check and train carry no step_index, because neither stage has a step number. Handle that when drawing a progress bar rather than reading step_index unconditionally.
Capture time tracks the parameter exactly: four motions at 3.0 seconds each measured 394 frames per motion. 131 Hz x 3 s = 393, a precise match.
What an Unworn Glove Costs: dead_pct 99.3%
Running a full round on a glove resting on a desk with nobody wearing it produced this summary:done with no error and wrote its output normally, yet the model is unusable.
The reason is direct: the trainer decides a taxel is alive by whether its signal changed meaningfully during the motions. On a resting glove nothing moves, so everything is marked dead.
The operating rule this gives you: dead_pct is the first measure of calibration quality. Read it before anything else in the summary. A high value means insufficient coverage, whether from not wearing the glove, motions that are too small, too little pressure, or regions never reached.
For a sense of the healthy range, compare against the raw array: 526 of the 744 channels are valid and the remaining 218 are hardware-masked. A good calibration should put alive_taxels near 526.
Output Layout
Calibration data is stored per user and serial number:~/.wuji/sdk/tactile/<serial number>/, while named users each get their own space under users/<user_id>/.
contact.json is a manifest carrying contract and checksum information:
tactile_pixels: 744 matches the raw tactile stream’s channel count, so the model trains against the complete array.
With install=False the model stays in the run directory and the runtime directory is never created. The summary reports installed as false and no model/ directory exists. Pass it when you want to evaluate before committing.
One calibration’s raw data measures about 6.6 MB across four bags plus the model. Each run adds another run_<timestamp> directory, and old ones are never cleaned up.
Parameters
Full signature:
At defaults, a round is four 30-second captures plus 60 training epochs. Shrinking those only suits flow verification, and real calibration should keep the defaults, because capture duration directly determines coverage.
Runtime Handling
Before and After Calibration
Sampling all three streams at the same moment before calibration:
The raw stream carries data as usual while both derived streams are exactly zero, not merely close to it. So to tell whether a glove has been calibrated, check whether those two streams are all zeros instead of digging through directories.
Integration Steps
- Python
- C
Running It
- Python
- C
seconds_per_pose=3.0, epochs=5, install=False, glove unworn:
dead_pct reached 99.3%. All output from this run was deleted afterward and nothing was installed into the runtime directory.
Adapting It
dead_pct Is the Number to Read First
Finishing without an error doesn’t mean the calibration worked. Readdead_pct, then check whether alive_taxels lands near 526. If either looks wrong, recalibrate before installing.
Use pose_review Warnings to Decide on a Retry
Every motion ends with apose_review whose warnings apply to that motion alone. Returning 'retry' on the spot costs far less than finishing the round and starting over.
Don’t Shrink seconds_per_pose for Speed
Capture duration directly determines array coverage. The 30-second default exists for a reason, and 3 seconds suits nothing beyond checking that your code runs.Clean Up Run Directories
Each calibration creates arun_<timestamp> directory of about 6.6 MB and nothing removes them. After several rounds, clear them by hand.
Check the Grid After Calibrating
Once the model is installed, run the contact grid view and touch the glove to confirm it responds. That’s far more direct than reading numbers. See Tactile Contact Grid View.Related
- Tactile Contact Grid View: verify the result after calibrating
- Tactile Residual Grid View: the continuous signal behind a contact verdict
- Subscribing With Callbacks: where 744, 526, and 218 come from
- Hand Model Calibration: the other calibration path, producing a hand model
- SDK User Management: calibration output is scoped per user