Files
orisys-app/apps/autocal/docs/workflow.md
T
2026-09-20 21:15:39 +08:00

13 KiB
Raw Blame History

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?".

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

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