autocal layout first design
This commit is contained in:
@@ -0,0 +1,335 @@
|
||||
# AutoCal workflow — platform bring-up to calibration data
|
||||
|
||||
This is the operating workflow the application is built around. It is written to
|
||||
be argued with: each phase names what it needs, what it produces, why it exists,
|
||||
and what must be true before the next one starts.
|
||||
|
||||
A **gate** is a checkpoint. The app's job at a gate is to make the operator's
|
||||
answer trustworthy, not to ask "are you sure?".
|
||||
|
||||
```text
|
||||
P0 Session & safety baseline [gate]
|
||||
P1 ECAT setup [gate]
|
||||
P2 Homing + test motion [gate]
|
||||
P3 Sensor & probe setup [gate]
|
||||
P4 Coordinate setup: sensor <-> platform [gate]
|
||||
P5 Sequence design [gate]
|
||||
P6 Simulate & dry run [gate]
|
||||
P7 Run + acquire [gate]
|
||||
P8 Store raw
|
||||
P9 Post-process [gate]
|
||||
P10 Calibration export
|
||||
P11 Verify [gate]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## P0 — Session & safety baseline
|
||||
|
||||
**Why:** the machine can move from P2 onward. Everything that limits that motion
|
||||
should be decided while nothing is moving.
|
||||
|
||||
**Inputs:** operator identity, machine/bench identifier, units per axis,
|
||||
`units_per_mm`.
|
||||
|
||||
**Safety limits, set here, enforced from P2:**
|
||||
|
||||
| Limit | Meaning |
|
||||
|---|---|
|
||||
| maximum travel per axis | never commanded past this, in user units |
|
||||
| maximum Z descent per step | a single approach may not exceed this |
|
||||
| press-depth ceiling | the press depth a sequence profile is allowed to request |
|
||||
| no-contact abort | if contact is not detected within the descent budget, stop the run |
|
||||
| following-error bound | how far a drive may lag before the move counts as stalled |
|
||||
|
||||
**Outputs:** a session record — who, when, which machine, and the limits in
|
||||
force. Stamped onto everything the session produces.
|
||||
|
||||
**Gate:** every limit has a value; no limit is "unset" (an unset limit is an
|
||||
unlimited machine).
|
||||
|
||||
**Currently missing from the workflow:** this phase did not exist. Without it,
|
||||
step 1 went from bus setup straight to jogging five axes.
|
||||
|
||||
---
|
||||
|
||||
## P1 — ECAT setup
|
||||
|
||||
**Why:** nothing else can be trusted until the controller has actually found its
|
||||
slaves. A missing drive discovered at P7 wastes the whole run.
|
||||
|
||||
**Inputs:** controller address, the matching `.bas` program
|
||||
(`ECAT.bas` / `RTEX.bas`).
|
||||
|
||||
**Steps:** connect → download and run the BAS program → watch
|
||||
`Bus_InitStatus` to completion or timeout → read `BUS_TYPE`,
|
||||
`Bus_TotalAxisnum`, and the node count.
|
||||
|
||||
**Outputs:** bus type, node count, axis count, init status.
|
||||
|
||||
**Gate:** init status is success, **and** the node/axis counts match what this
|
||||
bench is expected to have. A mismatch is a finding, not a warning.
|
||||
|
||||
**Existing code:** `MotionService.download_bas` / `poll` already implement the
|
||||
state machine and the 25 s timeout.
|
||||
|
||||
---
|
||||
|
||||
## P2 — Homing + test motion
|
||||
|
||||
**Why:** a drive that homes and jogs cleanly at low speed is the precondition for
|
||||
letting a sequence drive it.
|
||||
|
||||
**Inputs:** per-axis homing mode, speeds, offset; a test-motion profile.
|
||||
|
||||
**Steps:** enable → home each axis → low-speed jog each axis in both directions
|
||||
→ confirm movement and return.
|
||||
|
||||
**Outputs:** per-axis pass/fail with the evidence (distance moved, following
|
||||
error, alarm state).
|
||||
|
||||
**Gate — the test motion needs a criterion.** This was missing. Proposed:
|
||||
|
||||
- the axis moved at least a configured minimum distance;
|
||||
- it returned within a tolerance of its start position;
|
||||
- following error stayed under the bound from P0;
|
||||
- no alarm before, during or after.
|
||||
|
||||
**Existing code:** the axis panel does the jog/homing; the criterion is new.
|
||||
|
||||
---
|
||||
|
||||
## P3 — Sensor & probe setup
|
||||
|
||||
**Why:** which sensor is under test, what touches it, and how far the touching
|
||||
point is from the axis reference. Contact depth is meaningless without the tool.
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- sensor type and config reference (the same `config/sensors/<type>/sensor.json`
|
||||
the studio uses);
|
||||
- the sensor's 3D scene package and its `geometry_id`;
|
||||
- the **probe tip** (tool): which axis presses, and the tip offset from the
|
||||
platform's reference point;
|
||||
- the mounting pose: how the sensor is fixtured on the platform.
|
||||
|
||||
**Outputs:** a saved setup block.
|
||||
|
||||
**Gate:**
|
||||
|
||||
- the calibration's `geometry_id` matches the scene's, or the app says which is
|
||||
which rather than colouring the wrong geometry;
|
||||
- the probe tip offset is set (a zero offset that was never entered is not the
|
||||
same as a probe at the origin).
|
||||
|
||||
---
|
||||
|
||||
## P4 — Coordinate setup: sensor ↔ platform
|
||||
|
||||
**Why this is the load-bearing phase.** "Which points on the sensor should be
|
||||
tested" is a question in the *sensor's* frame. The platform moves in *platform*
|
||||
coordinates. Without the transform between them:
|
||||
|
||||
- a generated grid cannot be checked against the sensor's surface;
|
||||
- a measured point cannot be placed on that surface for the sensitivity map;
|
||||
- a calibration cannot be re-applied to a re-fixtured sensor.
|
||||
|
||||
**Inputs:** the probe tip from P3, and a set of **at least four non-collinear
|
||||
known features** on the sensor or its fixture, probed in platform coordinates.
|
||||
|
||||
**Steps:** probe each feature → solve for the rigid transform (rotation and
|
||||
translation; scale if the units are not yet trusted) → report the residual.
|
||||
|
||||
**Outputs:** a 4×4 transform from sensor frame to platform frame, with its
|
||||
residual and the feature set that produced it.
|
||||
|
||||
**Gate:** residual under a configured tolerance, and at least four non-collinear
|
||||
points (four collinear points determine a rotation about that line, not a
|
||||
transform — the app should refuse that set rather than return a number).
|
||||
|
||||
**Not built in this step:** the solver. Only the workflow step, the stored
|
||||
transform, and the place its residual is displayed.
|
||||
|
||||
---
|
||||
|
||||
## P5 — Sequence design
|
||||
|
||||
**Why:** this is the decision the whole run exists to carry out.
|
||||
|
||||
**Inputs (the profile, persisted and reusable):**
|
||||
|
||||
| Parameter | Meaning |
|
||||
|---|---|
|
||||
| mode | flat surface or curved (a cylindrical/spherical sensor area) |
|
||||
| grid pitch | spacing between points, in mm |
|
||||
| margin / radius | how far in from the active edge the grid stays; radius for curved |
|
||||
| clear height | standoff above the surface to travel at |
|
||||
| approach speed | descent speed before contact |
|
||||
| press speed | descent speed after contact |
|
||||
| press depth | how far past contact to press |
|
||||
| dwell | how long to hold the press |
|
||||
| settle window | how long to wait before the measurement is considered settled |
|
||||
| repeats | how many times each point is measured |
|
||||
| point order | row-wise, serpentine, or by distance |
|
||||
|
||||
**Steps:** generate the grid → validate **every point** three ways:
|
||||
|
||||
1. **on the sensor** — its sensor-frame position falls on the modelled surface,
|
||||
not off the edge and not inside a hole;
|
||||
2. **within travel** — the platform can reach it inside the P0 limits;
|
||||
3. **confirmable** — the sensor's sensing area is under the point, so a contact
|
||||
there can actually be seen by the sensor.
|
||||
|
||||
**Outputs:** a point list with a sensor-frame position and a platform-frame
|
||||
target for each, plus a validation verdict per point.
|
||||
|
||||
**Gate:** no point may be unusable without being marked as such. A run may
|
||||
proceed with skipped points if the operator says so explicitly; it may not
|
||||
proceed with unvalidated ones.
|
||||
|
||||
**The interface:** three zones in the Sequence tab — profile parameters, a 3D
|
||||
preview of the surface with the points and their visiting order, and the
|
||||
validation list. See `apps/autocal/README.md`.
|
||||
|
||||
---
|
||||
|
||||
## P6 — Simulate & dry run
|
||||
|
||||
**Why:** a wrong Z or a wrong grid is much cheaper to find now.
|
||||
|
||||
**Simulate:** play the full toolpath in the 3D view — a moving marker with a
|
||||
phase label (standoff → descend → press → dwell → retract), the estimated
|
||||
duration, and per-point reachability. No motion.
|
||||
|
||||
**Dry run:** execute the real XY path, descending only to the clear height,
|
||||
never pressing. This proves the geometry, the ordering, and the timing.
|
||||
|
||||
**Outputs:** estimated duration, per-point reachability, and (dry run) the
|
||||
measured time per point.
|
||||
|
||||
**Gate:** the operator has seen the path and a dry run has completed without a
|
||||
guard violation.
|
||||
|
||||
---
|
||||
|
||||
## P7 — Run + acquire
|
||||
|
||||
**Why:** the only phase that touches the sensor.
|
||||
|
||||
**Per step, in order:**
|
||||
|
||||
1. move to the point's XY at clear height;
|
||||
2. descend at approach speed;
|
||||
3. **detect contact by position** — the axis stalls / following error rises
|
||||
while descending;
|
||||
4. **confirm with the sensor under test** — its reading must change when the
|
||||
probe presses. This is the second opinion: position says "I stopped moving",
|
||||
the sensor says "something real is happening";
|
||||
5. press to the configured depth at press speed;
|
||||
6. dwell, then acquire the settle window;
|
||||
7. retract, move to the next point.
|
||||
|
||||
**Failure semantics (per point, because resume needs them):**
|
||||
|
||||
| Outcome | Run behaviour |
|
||||
|---|---|
|
||||
| contact confirmed | record the point as measured |
|
||||
| contact detected, sensor shows no change | mark **suspect**, continue; a suspect point is visible, not silently averaged in |
|
||||
| no contact within the descent budget | **abort** the run (P0 limit) and leave the point unfinished |
|
||||
| guard violation | abort the run, name the step and the limit |
|
||||
|
||||
**Writes are incremental**: each point is written as it completes, with its
|
||||
status, so an interrupted run resumes at the first unfinished point and partial
|
||||
data stays valid.
|
||||
|
||||
**Existing code:** the motion layer has the guards and the poller; the step
|
||||
machine, the contact detection and the acquisition binding are new.
|
||||
|
||||
---
|
||||
|
||||
## P8 — Store raw
|
||||
|
||||
**Why:** post-processing will change. The raw record must not.
|
||||
|
||||
**Contents:**
|
||||
|
||||
- the sequence profile and the instantiated point list (positions and order);
|
||||
- per point: the position trace, the raw sensor series, the settle window used,
|
||||
timings, the contact position, and the status;
|
||||
- the setup: sensor identity, geometry id, probe tip, the P4 transform and its
|
||||
residual;
|
||||
- the session record and app/version stamps from P0.
|
||||
|
||||
Nothing derived is authoritative. The requirement that makes this reproducible:
|
||||
**a dataset can be regenerated from the profile, the setup and the raw series**,
|
||||
with no dependency on a previously computed result.
|
||||
|
||||
---
|
||||
|
||||
## P9 — Post-process
|
||||
|
||||
**Why:** turning samples into a number is a decision, and it has to be visible.
|
||||
|
||||
**Steps:** choose the settle window per point → stability check (is the point
|
||||
actually settled, or drifting?) → sensitivity per point per axis → outlier
|
||||
detection → residual per point → fit the surface across points.
|
||||
|
||||
**Outputs:** per-point sensitivity with a quality verdict, and a surface field
|
||||
over the sensor's geometry ready for the 3D colour map.
|
||||
|
||||
**Gate:** every point is either valid or explicitly excluded, with a reason.
|
||||
A point with too few samples or a drifting window is not a coefficient.
|
||||
|
||||
---
|
||||
|
||||
## P10 — Calibration export
|
||||
|
||||
**Per-point results and the fitted surface, explicitly linked.** They are one
|
||||
calibration; exporting them as unrelated artefacts is how a map ends up in a
|
||||
report that does not match the table beside it.
|
||||
|
||||
---
|
||||
|
||||
## P11 — Verify
|
||||
|
||||
**Why this exists:** P9 and P10 produce numbers. Nothing yet checks they are
|
||||
right. "Post process → calibration data" had no acceptance test.
|
||||
|
||||
**Steps:** apply the calibration → re-measure a small subset of the points →
|
||||
compare the measured sensitivity against what the calibration predicts →
|
||||
report the discrepancy per point.
|
||||
|
||||
**Gate:** the discrepancy is within tolerance, or the verification is recorded
|
||||
as failed. A calibration that was never verified is labelled as such wherever it
|
||||
is used.
|
||||
|
||||
---
|
||||
|
||||
## Gaps this document closes
|
||||
|
||||
| # | Gap | Phase |
|
||||
|---|---|---|
|
||||
| 1 | no limits before motion | P0 |
|
||||
| 2 | no session identity (who/when/which machine) | P0 |
|
||||
| 3 | the sensor↔platform transform was absent | P4 |
|
||||
| 4 | the probe tip (tool) was never defined | P3 |
|
||||
| 5 | the test motion had no pass/fail criterion | P2 |
|
||||
| 6 | grid validity was not checked per point | P5 |
|
||||
| 7 | the settle window and stability criterion were undefined | P9 |
|
||||
| 8 | a point's failure had no defined behaviour | P7 |
|
||||
| 9 | the sequence was transient, not a saved, versioned artefact | P8 |
|
||||
| 10 | no verification pass | P11 |
|
||||
|
||||
## Data flow
|
||||
|
||||
```text
|
||||
P0 limits ─┬───────────────────────────────> enforced at P2, P6, P7
|
||||
P1 bus ────┴─> axis availability ─────────> P2
|
||||
P3 sensor setup ─┬─ geometry id ──────────> P5 validation, P10 surface
|
||||
└─ probe tip ────────────> P4, P7 press depth
|
||||
P4 transform ─────> sensor <-> platform ──> P5 point generation, P9 map
|
||||
(residual) P11 re-fixture check
|
||||
P5 profile + points ──> P6 simulate/dry run ──> P7 run
|
||||
P7 raw series ─────> P8 dataset ──> P9 post-process ──> P10 export
|
||||
└─> P11 verify
|
||||
```
|
||||
Reference in New Issue
Block a user