Files
orisys-app/apps/autocal/docs/sequence-format.md
T
ykcheungab 04adf17f60 完善 Autocal 多测点标定流程及会话复核
统一测点坐标、保持窗口和试验目录,补齐逐点初步分析。定向测试与真实视频闭环通过;两项轮询失败在修改前版本同样复现。
2026-10-11 17:43:16 +08:00

7.0 KiB

Calibration sequence format (.oryseq)

A calibration sequence is a small JSON document: the profile that generated the points, plus the points themselves. It is written by 导出序列… in the Sequence tab and read by 导入序列….

The Finger simulation page separately exports an operator CSV list with centred UV pixels, sensor/platform millimetres and mapping identity. It uses the manual calibration coordinate convention; that list is not an .oryseq and is not imported into the acquisition page.

Why JSON and not a binary container: a sequence is at most a few hundred points of text. It is read by a human, diffed in review, and emailed to whoever runs the bench. Binary would buy nothing and cost all three. (The acquired data of a run is a different problem — per-point time series are large and will need a sidecar; that decision belongs to workflow P8, not here.)

Conventions

The format follows this repository's existing documents rather than inventing a convention. Where it matches session.json and force_calibration.json, that is deliberate:

Convention Value
Version field "format_version": "1.0" — a dotted string, compared as a tuple
Identity "kind": "autocal.sequence" — checked on import
Extension .oryseq by convention; import accepts any .json
Encoding UTF-8, indent=2, ensure_ascii=False, trailing newline
Write temp file then Path.replace — a half-written sequence that still parses looks like a design

The document

{
  "format_version": "1.0",
  "kind": "autocal.sequence",
  "created_at": "2026-09-20T10:31:00+00:00",
  "name": "5 点灵敏度扫描",
  "note": "",
  "versions": { "app": "0.1.0", "shared": "0.1.0", "shared_api": "0.1" },
  "device": {
    "sensor_type": "box",
    "config_ref": "…\\config\\sensors\\box\\sensor.json",
    "geometry_id": "finger-1.0.0",
    "probe_tip_set": true
  },
  "frame": { "targets": "platform", "length_unit": "mm", "units_per_mm": 10.0 },
  "profile": {
    "mode": "flat", "pitch_mm": 2.0, "margin_mm": 1.0, "radius_mm": 0.0,
    "clear_height_mm": 5.0, "approach_speed_mm_s": 2.0, "press_speed_mm_s": 0.5,
    "press_depth_mm": 0.2, "dwell_s": 0.5, "settle_window_s": 0.5,
    "repeats": 3, "order": "serpentine"
  },
  "points": [
    {
      "id": 1,
      "target_mm": { "x": 0.0, "y": 0.0, "z": 12.4 },
      "sensor_mm": { "x": 0.0, "y": 0.0, "z": 0.0 },
      "clearance_mm": 5.0,
      "enabled": true,
      "note": ""
    }
  ],
  "summary": {
    "count": 12, "enabled": 12,
    "min_mm": { "x": 0.0, "y": 0.0, "z": 12.4 },
    "max_mm": { "x": 10.0, "y": 4.0, "z": 12.4 },
    "span_mm": { "x": 10.0, "y": 4.0, "z": 0.0 },
    "pitch_mm": 2.0,
    "estimated_duration_s": 380.0
  }
}

Fields

frame — required

Field Meaning
targets the frame target_mm is expressed in; today always "platform"
length_unit "mm"; anything else is refused
units_per_mm the pulse equivalent the points were built with

A sequence whose numbers do not say whether they are millimetres or user units is a sequence that will eventually be read wrong. units_per_mm is recorded so a file from a differently-configured axis is detectable rather than silently believed.

profile — required

The twelve fields the Sequence tab edits, and nothing else. A field absent from the file is kept at its current value and reported, never silently defaulted to another bench's number.

points — required, may be empty

Field Meaning
id 1-based, stable within the file; used for run progress and resume
target_mm where the axes go — required, with all three of x, y, z
sensor_mm where that point lands on the sensor; optional but written
clearance_mm the standoff for this point
enabled false = designed but deliberately skipped
note free text

Both positions are stored on purpose. The platform target is what the run uses; the sensor position is what makes the point checkable against the surface. Deriving one from the other on every load would silently change what the points mean the moment a sensor is re-fixtured — and a re-fixture is exactly when a stored transform should be noticed, not recomputed from.

summary — derived, not authoritative

Present so a human reading the file sees the point count and travel span without counting rows, and so a diff is legible. It is recomputed on load; a mismatch is reported as a warning and the recomputed values win. That is how a hand-edited document announces itself instead of quietly disagreeing with its own contents.

estimated_duration_s assumes a constant traverse rate (sequence_io.ASSUMED_TRAVERSE_MM_S) and ignores acceleration. It is a planning figure and is labelled an estimate wherever it is shown.

device — a reference, not a requirement

Records which sensor the sequence was designed for. Importing a sequence for another sensor is allowed and warned about, because re-fixturing deliberately is a normal thing to do.

Import rules

Every rejection names the specific problem — invalid file tells an operator nothing.

Condition Behaviour
not JSON refused, with line and column
top level not an object refused
kind missing or different refused, naming what was found
format_version missing or not a string refused
format_version newer than this build refused, naming both versions
frame missing, or length_unit not mm refused
profile not an object refused
a profile key absent imported; the current value is kept and the key is reported
points absent imported as profile-only, and reported
a point without target_mm.x/y/z refused, naming the point and the axis
summary disagreeing with points imported; recomputed, and reported
current design is unsaved the operator is asked before it is replaced

Version strings are compared as tuples, never as strings: "1.10" is newer than "1.9", and a string comparison would make a newer file look older and load it as if it were supported.

Compatibility rules

  • Adding an optional key does not change format_version.
  • Adding a required key, or changing a field's meaning or unit, does.
  • A reader must refuse a document whose version it does not support rather than interpreting the parts it recognises — a sequence half-applied is worse than one rejected.
  • 1.x readers are expected to accept 1.y for y <= x on the same major version and report anything they did not use.

Where the pieces live

Concern Module
The document, validation, the derived summary apps/autocal/src/orisys_autocal/sequence_io.py
The design screen and its controls apps/autocal/src/orisys_autocal/ui/sequence_panel.py
The file dialogs and the unsaved-work guard apps/autocal/src/orisys_autocal/ui/window.py
Why a sequence is an artifact (P8) apps/autocal/docs/workflow.md