File size: 11,355 Bytes
a3897c9
 
 
 
3cbbecf
a3897c9
 
 
 
 
 
 
 
 
6a31f4a
a3897c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d47f18b
 
 
 
a3897c9
d8e107c
6a31f4a
 
 
 
3cbbecf
d8e107c
6a31f4a
 
d8e107c
053e7a3
6a31f4a
 
 
 
 
 
 
 
053e7a3
 
6a31f4a
053e7a3
6a31f4a
 
 
053e7a3
d8e107c
71bf0be
6a31f4a
 
d8e107c
 
6a31f4a
 
 
3cbbecf
a63652b
d8e107c
 
 
a63652b
d8e107c
 
 
 
 
985cd8d
6a31f4a
 
 
 
 
 
 
 
 
 
 
 
fbea5bc
6a31f4a
 
 
 
 
 
 
 
 
 
 
d8e107c
 
6a31f4a
 
 
 
 
3cbbecf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Results</title><style>
:root{--bg:#0b1020;--fg:#e8eefb;--dim:#8ea0c2;--line:#1e2a45;--card:#111a2e;
--accent:#ffc46b;--ok:#7be0a0;--bad:#ff8f7a;
--s0:12px;--s1:14px;--s2:16px;--s3:20px;--s4:28px;--s5:40px}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);font-size:var(--s2);
font-family:'IBM Plex Sans',system-ui,sans-serif;line-height:1.6}
.wrap{max-width:1100px;margin:0 auto;padding:0 20px 72px}
a{color:var(--accent)}
h1{font-size:var(--s5);line-height:1.15;margin:40px 0 8px;font-weight:650}
h2{font-size:var(--s4);margin:44px 0 10px;font-weight:600}
h3{font-size:var(--s3);margin:28px 0 6px;font-weight:600}
p{margin:10px 0;max-width:70ch}
.dim{color:var(--dim);font-size:var(--s1)}
.bad{color:var(--bad);font-size:var(--s0)}
nav{display:flex;gap:8px;flex-wrap:wrap;margin:18px 0 4px}
nav a{display:inline-block;padding:10px 16px;min-height:44px;line-height:24px;
border:1px solid var(--line);border-radius:999px;text-decoration:none;
background:var(--card)}
nav a[aria-current]{border-color:var(--accent)}
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
gap:12px;margin:20px 0}
.card{background:var(--card);border:1px solid var(--line);border-radius:12px;
padding:16px}
.card b{display:block;font-size:var(--s4);color:var(--accent);font-weight:650}
.card span{color:var(--dim);font-size:var(--s1)}
figure{margin:24px 0}
figure img{width:100%;border-radius:10px;border:1px solid var(--line);
background:#fff}
figcaption{color:var(--dim);font-size:var(--s1);margin-top:8px;max-width:80ch}
table{border-collapse:collapse;width:100%;margin:14px 0;font-size:var(--s1)}
th,td{border-bottom:1px solid var(--line);padding:9px 10px;text-align:right}
th:first-child,td:first-child{text-align:left}
th{color:var(--dim);font-weight:500}
td b{color:var(--ok)}
details{background:var(--card);border:1px solid var(--line);border-radius:10px;
padding:12px 16px;margin:16px 0}
summary{cursor:pointer;color:var(--dim);font-size:var(--s1);min-height:44px;
display:flex;align-items:center}
code{background:#0d1526;padding:2px 6px;border-radius:5px;font-size:var(--s1)}
/* Inline links in prose measured 47x16 and 54x16 at 375 px — a tap target,
   because a finger does not know it is "only prose". Padding alone would
   break the line box, so the height comes from an inline-block with the
   line-height carrying it. */
p a,figcaption a{display:inline-block;min-height:44px;line-height:44px;
padding:0 2px}
/* The <pre> pipeline diagram and the results table are the two things wider
   than a phone. Let each scroll inside its own box rather than pushing the
   document sideways — a horizontally scrolling PAGE hides content with no
   affordance, a scrolling code block is a known idiom. */
pre{background:var(--card);border:1px solid var(--line);border-radius:10px;
padding:14px 16px;overflow-x:auto;font-size:var(--s1);max-width:100%}
.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.tablewrap table{min-width:640px}
img{max-width:100%;height:auto}
/* Subscripts default to a fraction of the parent and rendered at 11.7px —
   off the --s0..--s5 scale the audit counts. Pinned to the smallest step. */
sub,sup{font-size:var(--s0);line-height:0}
</style></head><body><div class="wrap"><nav><a href="index.html">overview</a><a href="method.html">method</a><a href="results.html" aria-current="page">results</a><a href="sensors.html">sensors</a><a href="gallery.html">gallery</a><a href="workbench.html">3D workbench</a></nav>
<h1>Results</h1>
<p>Both reconstructions through <b>one</b> protocol: half the frames in each
group fit a 5-feature least squares, half are scored; pooled ρ, five seeds,
beside a within-group label shuffle. The second number in each cell is ρ minus
that row's own floor — the comparable one — and bold marks the larger. Only
the image→gradient step differs.</p>

<h3>Presses the sensor images whole</h3>
<div class="tablewrap"><table><thead><tr><th>dataset</th><th>n</th><th>LUT<br>ρ / margin</th><th>calibration-free<br>ρ / margin</th><th>shuffle floor</th><th>groups fitted</th></tr></thead><tbody>
<tr><td>GelSight Mini, CNC presses, 0-20 N</td><td>605<br><span class='dim'>of 6,219</span><td><b>0.993<br><span class='dim'>+0.925</span></b></td><td>0.998<br><span class='dim'>+0.909</span></td><td class='dim'>+0.067 / +0.089</td><td class='dim'>6/6</td></tr><tr><td>FoTa cnc_Mini</td><td>604<br><span class='dim'>of 3,351</span><td><b>0.900<br><span class='dim'>+0.940</span></b></td><td>0.938<br><span class='dim'>+0.903</span></td><td class='dim'>-0.040 / +0.035</td><td class='dim'>6/6</td></tr><tr><td>FEATS (MARKER gel)</td><td>2,000<br><span class='dim'>of 16,276</span><td>0.642<br><span class='dim'>+0.553</span></td><td><b>0.706<br><span class='dim'>+0.617</span></b></td><td class='dim'>+0.089 / +0.089</td><td class='dim'>8/8</td></tr><tr><td>Sparsh / Meta, 10 gel pads</td><td>2,000<br><span class='dim'>of 129,389</span><td>0.959<br><span class='dim'>+0.909</span></td><td><b>0.986<br><span class='dim'>+0.956</span></b></td><td class='dim'>+0.050 / +0.030</td><td class='dim'>4/4</td></tr><tr><td>FeelAnyForce<br><span class='bad'>floor-dominated</span></td><td>2,000<br><span class='dim'>of 13,892</span><td>0.939<br><span class='dim'>+0.197</span></td><td><b>0.949<br><span class='dim'>+0.208</span></b></td><td class='dim'>+0.742 / +0.741</td><td class='dim'>13/14</td></tr></tbody></table></div>

<figure><img src="assets/truncation.png" alt="truncated presses">
<figcaption>A press is <b>truncated</b> when its contact core reaches a border:
the indentation continues outside the frame, so the free-boundary solve runs
off the edge with nothing to stop the ramp.
15.9% of them reconstruct deeper than the
4.25&nbsp;mm gel, against
0.0% of whole presses (441 and
59 frames). Their depth is not identifiable from the
image.</figcaption></figure>

<p>Excluding them is what the headline row buys: on GelSight Mini, CNC presses, 0-20 N
calibration-free scores ρ&nbsp;0.998
on whole presses against
0.851 once truncated frames are
mixed in. Three datasets reach the 2,000 this table samples; the two that
cannot have no more presses to give.</p>

<h3>All frames</h3>
<p class="dim">The same protocol without that exclusion.</p>
<div class="tablewrap"><table><thead><tr><th>dataset</th><th>n</th><th>LUT<br>ρ / margin</th><th>calibration-free<br>ρ / margin</th><th>shuffle floor</th><th>groups fitted</th></tr></thead><tbody>
<tr><td>GelSight Mini, CNC presses, 0-20 N</td><td>2,376<br><span class='dim'>of 6,219</span><td>0.707<br><span class='dim'>+0.571</span></td><td><b>0.851<br><span class='dim'>+0.713</span></b></td><td class='dim'>+0.135 / +0.138</td><td class='dim'>6/6</td></tr><tr><td>FoTa cnc_Mini</td><td>2,239<br><span class='dim'>of 3,351</span><td>0.442<br><span class='dim'>+0.416</span></td><td><b>0.482<br><span class='dim'>+0.449</span></b></td><td class='dim'>+0.026 / +0.033</td><td class='dim'>6/6</td></tr><tr><td>FEATS (MARKER gel)</td><td>2,956<br><span class='dim'>of 16,276</span><td><b>0.707<br><span class='dim'>+0.525</span></b></td><td>0.702<br><span class='dim'>+0.506</span></td><td class='dim'>+0.183 / +0.196</td><td class='dim'>8/8</td></tr><tr><td>Sparsh / Meta, 10 gel pads</td><td>3,091<br><span class='dim'>of 129,389</span><td>0.669<br><span class='dim'>+0.629</span></td><td><b>0.698<br><span class='dim'>+0.657</span></b></td><td class='dim'>+0.040 / +0.041</td><td class='dim'>4/4</td></tr><tr><td>FeelAnyForce</td><td>3,378<br><span class='dim'>of 13,892</span><td>0.905<br><span class='dim'>+0.509</span></td><td><b>0.935<br><span class='dim'>+0.531</span></b></td><td class='dim'>+0.396 / +0.404</td><td class='dim'>14/14</td></tr></tbody></table></div>

<p class="dim">The shuffle floor is an absolute ρ — what this protocol scores
with labels permuted inside each group; the margin beside each cell already has
it subtracted. React's production number adds a fitted position gain field and
lives on the <a href="method.html">method</a> page.</p>

<figure><img src="assets/pred_vs_gt.png" alt="predicted vs ground-truth force">
<figcaption>Held-out prediction against ground truth, shared axes per row.
Each panel carries its shuffle floor and the margin over it.</figcaption>
</figure>

<figure><img src="assets/cross_dataset.png" alt="cross-dataset transfer">
<figcaption>Fit on one dataset, predict on every other. Read each cell against
the random-weight baseline under its column: the features are collinear and all
monotone in contact size, so on an easy target almost any direction ranks
correctly.</figcaption></figure>

<p>FoTa cnc_Mini→FEATS, Sparsh→FEATS are ≥99&nbsp;% extrapolation. — there MAE is extrapolation, not prediction.
FeelAnyForce's row goes <i>negative</i>: collinear features let least squares
cancel opposite-sign terms (<a href="method.html">method</a>). Non-negative
weights fix it: off-diagonal ρ
0.574&nbsp;&nbsp;0.731, negative
cells 3&nbsp;&nbsp;0 of
20, costing 0.010 on the diagonal.
<b>The deployed estimator is unchanged</b>: on React both agree at
ρ&nbsp;0.989 (1.8&nbsp;% of
frames outside the rig's range), and 15 held-out seeds differ by
+0.002&nbsp;±&nbsp;0.014&nbsp;ρ.</p>

<h2>Which reconstruction for React's force channel?</h2>
<p>React's own calibration objects <b>cannot answer this</b>: calibration-free
scores ρ&nbsp;0.781 against the LUT's
0.763 on 158 held-out presses, but
a paired bootstrap puts the margin at 95%&nbsp;CI
[-0.081,
+0.120] — a coin flip. Nor does the
table: calibration-free leads on raw ρ everywhere, but over each row's own
floor it is ahead on 3 of 5. It ships because it needs no per-sensor lookup
table, not because it measures force better.</p>
<p>The two agree at ρ&nbsp;=&nbsp;0.925 over 2,400 React
frames, mean difference 0.86&nbsp;N. Published to <code>yxma/React</code>: this channel across all 72 sides of 36 episodes (480,080 frames).</p>

<h2>Error analysis</h2>
<p>The ten worst held-out frames reconstruct as well as the five best — same
gradient dipoles, same compact depth, no ramping. The residual is in the
depth→force fit, not in image→depth, so a better reconstruction will not move
them.</p>
<p class='dim'>Each panel: the ten worst held-out frames, with the five best as a control. Relative error is |pred−true| over the dataset's force span.</p><figure><img src="assets/errors_cnc_mini_26.png" alt="cnc_mini_26 errors"><figcaption>GelSight Mini CNC, span 19.50&nbsp;N — median 0.7%, p90 2.0%, worst 11.6%.</figcaption></figure><figure><img src="assets/errors_cnc.png" alt="cnc errors"><figcaption>FoTa cnc_Mini, span 4.01&nbsp;N — median 4.9%, p90 15.1%, worst 35.0%.</figcaption></figure><figure><img src="assets/errors_feats.png" alt="feats errors"><figcaption>FEATS (marker), span 59.86&nbsp;N — median 3.1%, p90 10.3%, worst 39.3%.</figcaption></figure><figure><img src="assets/errors_sparsh.png" alt="sparsh errors"><figcaption>Sparsh / Meta, span 1.07&nbsp;N — median 1.9%, p90 6.2%, worst 48.2%.</figcaption></figure><figure><img src="assets/errors_faf.png" alt="faf errors"><figcaption>FeelAnyForce, span 17.44&nbsp;N — median 1.7%, p90 9.7%, worst 41.3%.</figcaption></figure>
</div></body></html>