Overview
tactile_binary has already decided whether something touched the glove. tactile_residual hands you the continuous signal from the step before that: a signed residual per taxel, where positive means pressed harder than the calibrated baseline, near zero means no contact, and negative means lighter than baseline.
That’s the difference — the threshold belongs to the consumer. tactile_binary uses a threshold the SDK derives from sensitivity, while tactile_residual makes no judgment and leaves the line for you to draw.
This example lays the residual out as a 24x31 grid, shows intensity with a six-level character ramp, and lets you adjust the threshold live to watch the grid respond. It’s an observation tool, not another calibration workflow.
Matching examples: examples/python/wuji_glove/9.tactile_residual_view.py and examples/c/wuji_glove/7_tactile_residual_view.c.
For tactile field definitions, see Tactile. This page covers only how to run it and what the measurements show.
Prerequisites
Hardware
Software
- Python
- C
Before You Start
Run tactile calibration first. The residual is computed against a calibrated baseline, and without that baseline there’s no residual — this stream measures exactly zero on an uncalibrated glove. See Tactile Calibration.How the Residual Relates to the Binary Stream
Both streams come from the same model, andtactile_binary is tactile_residual after one threshold. Take the former when you want a ready-made verdict, the latter when you want to set the criterion yourself.
The Grid Matches the Binary View Exactly
tactile_residual also carries 744 values, with the same 218 invalid channels in the same places and the same row-major mapping of index = row * 31 + col. 24 x 31 = 744, so the grid is the sensor array’s physical layout.
The hand outline is therefore identical between the two views, and switching between them never shifts anything. For where the channel counts come from, see Subscribing With Callbacks.
Six-Level Character Ramp
This is the main display difference from the binary view:
The ramp maps proportionally:
., the second sixth shows :, and so on, with * meaning nearly at the threshold. The ramp is relative to the threshold, so adjusting the threshold redistributes the whole scale. It isn’t an absolute measure.
The invalid-channel test uses an approximate float comparison rather than == -1.0, avoiding an equality check:
Threshold Behavior
The clamp has a floor only:
[0.5, 3.0]. The residual threshold is your own criterion, and the example doesn’t bound it for you.
threshold = 0 is a special case: in cell_for, the value <= 0.0 or threshold <= 0.0 branch renders every valid channel as . and # never appears. To “show everything,” use a very small positive number rather than zero.
In an interactive terminal, + and - step by 0.1 (THRESHOLD_STEP = 0.1).
Status Line
The sign on
peak matters. A negative peak means a whole region reads lighter than the calibrated baseline, which usually points at a loose fit or a hand posture far from the one used during calibration.
seq confirms the stream is alive: a number that stops moving means no new frames.
Render Throttling
Throttled to 10 Hz, same as the binary view:Runtime Handling
Integration Steps
- Python
- C
set() on the device.
Running It
- Python
- C
peak=+0.000 and above=0 are what an uncalibrated glove looks like, while seq keeps incrementing to show the stream itself is alive — a stream carrying frames isn’t the same as a stream carrying content, which is what the seq field is for.
Once calibrated and worn, contact regions render as the . : - = + * ramp by intensity, places at or above the threshold turn into #, and peak gives the strongest current residual.
Adapting It
Find Your Threshold From peak
Use the example as follows: hold the lightest contact your application cares about, watch wherepeak settles, and set the threshold just below that. It beats guessing, and it beats tuning sensitivity by trial and error.
Read the Ramp for Contact Edges
# tells you only where the threshold was crossed, while the ramp shows how contact falls off toward the edges. For grasp-posture analysis or contact-area estimation, that gradient carries more than a binary verdict.
A Negative Residual Is a Signal
A persistently negativepeak means the whole glove reads lighter than its calibrated baseline, most often because it’s worn looser than during calibration. Refit the glove rather than lowering the threshold to compensate.
For a Verdict, Use the Binary Stream
Writing your own threshold logic costs real work: noise handling, temporal filtering, hysteresis. If all you need is whether something touched the glove, usetactile_binary, where the SDK has already done that. The residual earns its place when your criterion differs from the default.
Related
- Tactile Calibration: the hard requirement here, since the residual is computed against a calibrated baseline
- Tactile Contact Grid View: the same grid after the SDK’s own decision
- Subscribing With Callbacks: where 744, 526, and 218 come from
- Common Data Types: the
TactileResidualstructure