Reconstruct an unknown outline by choosing where to touch next.
A simulated probe measures one point at a time. From those noisy contacts, it estimates the object's shape, tracks uncertainty, and chooses its next measurement. Moving the probe takes time, so a useful strategy needs to balance what it can learn against the cost of getting there.
The project asks two questions: where should the probe touch, and when does it have enough evidence to stop?
Four saved checkpoints from a real simulation run. Orange dots are measurements; blue is the estimate and its pointwise uncertainty band. Gray shows the true outline for the viewer—the controller cannot see it. This recess case retains local error even after 128 touches.
View the same checkpoints as a still figure.
Run it · Strategies · Mathematics · Results · Full report
The object stays fixed inside a free outer circle. Each action moves the probe along that circle, approaches inward until contact, takes a noisy radius reading, and retracts. The simulator accounts for the travel distance and duration of every stage.
- Start with eight contacts spread around the object.
- Fit a Gaussian process (GP): a smooth radius estimate with uncertainty between measurements.
- Score candidate angles and choose the next touch.
- Update the estimate; continue until the touch budget or a stopping rule ends the run.
The shape must be star-shaped about a known interior point: every outward ray from that point crosses the boundary once. Circles, ellipses, rectangles, wavy outlines, and recessed shapes are supported. Angles are exact, the probe is a point, and contact has no deformation or friction. These assumptions define what the simulation can test.
Python 3.12, managed by uv. Everything runs on the CPU; no pretrained model, training dataset, or GPU is needed.
uv sync --locked
uv run --frozen touch-explorer demo --config configs/demo.toml --output results/demo
xdg-open results/demo/replay.htmlThe browser replay has playback, scrubbing, speed controls, and a truth toggle. It uses saved predictions, so replaying does not rerun inference. Choose a fresh output directory each time; existing runs are preserved.
The package and CLI are still named touch-explorer. See the usage guide for all experiment commands and configuration options.
All strategies receive the same public observations and share the same motion model.
| Strategy | Next measurement | What it tests |
|---|---|---|
| Random | A random unvisited angle | A simple reference |
| Sweep | The next point in a clockwise uniform scan | Short travel and regular spacing |
| Largest gap | The midpoint of a largest unsampled angular gap | Even coverage without a GP-based score |
| Maximum variance | Where the GP is most uncertain | Whether local uncertainty is useful |
| Cost-aware | Largest expected average variance reduction per second | Whether predicted information gain is worth the travel |
Ties favor shorter predicted motion, then candidate index. That means even the largest-gap baseline has some travel awareness.
Represent the boundary by its radius
Here
The model treats angles just before and after a full turn as neighbors. With fixed kernel parameters, its variance depends on where measurements were taken, not their measured values. Maximum variance therefore does not automatically recognize a sharp feature.
The cost-aware strategy considers how a new touch would reduce uncertainty across the entire outline:
Embed angles on a unit circle, then apply a Matérn covariance function (also called a kernel):
The implementation uses Cholesky decomposition to solve the linear system rather than forming an inverse. The learned variants fit bounded kernel parameters at touch 16 and every eight touches afterward. Failed optimization retains the last valid parameters and refits using all current measurements.
Derivations, assumptions, and source references are in the project report and research notes.
720 held-out episodes completed across two frozen studies. Cases, settings, and analysis choices were fixed before running each study. Comparisons pair methods on the same shapes and noise realizations; uncertainty intervals resample whole shapes, not individual touches.
The primary study compared all five policies on 20 shapes, three noise levels, and two noise seeds, with 128 touches per run. RMSE is root mean square error: a summary of radial prediction errors around the outline that gives larger errors more weight. We also measure the largest error on a separate evaluation grid.
Lower error is better. The time plot includes the cost of moving and probing; it holds each estimate constant until the next measurement finishes.
Cost-aware probing showed no clear advantage over largest-gap sampling on the predeclared 50-second error metric. The cost-minus-gap difference was −0.0000226, with a nominal 95% interval of [−0.0003057, +0.0002979]. Cost-aware probing also used more total modeled motion time: 270.5 seconds versus 238.7 for gap. Full comparison →
A separate study used 12 fresh shapes and compared five fitting/stopping variants, all with cost-aware acquisition. Each variant ran 24 times.
| Variant | Mean touches | Mean radial RMSE ↓ | False / confidence stops |
|---|---|---|---|
| Fixed GP, full budget | 128 | 0.004212 | No confidence stops |
| Learned GP, full budget | 128 | 0.002702 | No confidence stops |
| Learned GP + periodic gap probing | 128 | 0.002717 | No confidence stops |
| Uncertainty stopping | 19.83 | 0.010455 | 8/24 |
| Guarded stopping | 40.88 | 0.004424 | 6/24 |
Learning reduced mean RMSE by about 36%, but did not improve the count passing both average- and maximum-error limits. Errors use the outer-circle radius as the unit of length.
Both stopping variants use periodic gap probes. Uncertainty stopping checks whether the largest pointwise half-width is at most 0.02. Guarded stopping additionally requires at least 24 contacts, no angular gap above 15°, and two new audit contacts with acceptable prediction residuals.
A false stop means declaring confidence while RMSE exceeds 0.01 or sampled maximum error exceeds 0.03. All six guarded failures were recess cases: average error was acceptable, but local error was too large. The two fewer failures than uncertainty stopping do not establish a general improvement in failure rate; the paired interval includes zero. Learning and stopping results →
See a confident but inaccurate reconstruction
This run stopped after 44 contacts. RMSE was 0.007729, but maximum error was 0.045087—above the 0.03 limit. A small error averaged around the outline can hide a bad local estimate. This example was selected after analysis as the guarded run with the largest final maximum error.
Separate development experiments also tested biased readings, underestimated noise, and outliers. A constant sensor bias caused false confidence in all six guarded cases tested. Repeated contacts cannot generally distinguish an unknown radius offset from sensor bias without calibration information. Sensor mismatch study →
139 tests passed at the completed study revision. They check geometry against analytic answers, GP predictions against independent linear algebra, motion accounting, shared noise, stopping transitions, and failure handling.
The controller receives only angle, measured radius, and assumed noise variance. True geometry and exact contact timing stay on the simulator/evaluation side. Every run saves its configuration, seeds, source revision, observations, decisions, metrics, and posterior snapshots.
| Code | Responsibility |
|---|---|
world.py |
Geometry, contact, and sensor noise |
model.py |
Periodic GP inference and parameter fitting |
policies.py |
Candidate scoring and action selection |
stopping.py |
Confidence checks and audit state |
heldout.py |
Frozen experiments and paired analysis |
uv run --frozen pytest
uv run --frozen ruff check src tests scripts
uv run --frozen ruff format --check src tests scriptsCompact results and figure data are committed in docs/data. Raw run directories live under results/ and are excluded from Git. The usage guide explains how to regenerate the experiments and replay individual runs.
The README animation is generated directly from archived numerical snapshots:
uv run --frozen python scripts/build_readme_animation.py \
docs/data/exploration-data.npz docs/data/active-touch.gifThe planned laptop simulation, evaluation, and report are complete. The observed stopping failures remain part of the result. Sensor calibration, robust noise models, or stopping bounds under explicit smoothness assumptions are possible next experiments. Physical hardware and more general shapes would require additional models and validation.
Project report · Usage guide · Original plan · Research notes
Licensed under the MIT License. Copyright © 2026 Hlib Strochkovskyi.
