Fix the phase-1/2 review findings in recording, calibration and depth replay
What - record: one packet->row conversion (record/sample.py). A failed compute chain records no force value at all, a newton value is written only for an axis that really has a calibration curve, and mono_t (not the wall clock) orders history with a per-row calibration hash. - record lifecycle: explicit starting/recording/stopping/stopped/failed states owned by the writer thread; stop() reports completed=False on timeout and does not write ended_at; consecutive write failures stop acceptance immediately. - record capacity: byte budget for the video queue (512 MiB default); a full queue sheds the *frame* and parks the tiny data row, so a video overflow no longer deletes CSV rows. Lost rows leave a dropped=1 index row and are counted as dropped_gaps / unrecorded_gaps. - calibration identity: sha256 content hash instead of a path, minted from the calibration the sensor actually loaded (reported before the first frame) and confirmed by the acquisition thread; events are timestamped when they happen. - calibration diagnostics: the fit summary, residual and validation error now come from the model that export/apply would use (piecewise_linear); validation points are held out of the build; repeated reference loads are merged with an n-weighted mean and pooled std. - calibration record: every point keeps its full three-axis sample series (frame id, time, raw, newtons, valid) plus diagnostics, written to an independent calibration_session_*.json that can be reopened for inspection; save record / export coefficients / apply to device are three separate actions. - depth replay: the cursor's frame is bound to the depth result by request sequence and frame id, so a moved cursor never shows another frame's map; the SDK is stepped from its current position instead of re-reading from the start; the live chain (box deformation+contact, finger unroll+tactile) is replayed with the exact resolved config path; algorithm state is rebuilt from a reset marker or from the recorded pre-roll, and says so when it cannot be. Why The review (D:/orisys_ws/_review_phase12/review.md) showed the app writing raw counts into the newton columns, recording a stale value after a failed compute, losing CSV rows when the video queue filled, reporting success while a writer was still running, diagnosing a model nobody applies, applying a calibration before the device confirmed it, dropping the samples behind a calibration point, showing a stale depth map under a moved cursor and recomputing depth of the wrong frame. Verification - D:/orisys_ws/_review_phase12/reproduce.py: all ten acceptance lines flipped (log saved as _review_phase12/reproduce_after.log). Including 25/25 rows kept with 8 video frames shed, frames [2]->[3], depth 8.0/8.0, fit 2/2 points. - apps/studio/tools/ui_check.py: 249 checks, 0 failures (twice). - shared suites: 91 tests, 0 failures (new: test_record_semantics, test_record_lifecycle, test_calibration_model, test_calibration_record, test_depth_replay). - apps/studio/tests/test_ui_smoke.py: 23/30; the 7 remaining are harness artifacts of the sandbox (4 tmp_path PermissionError, 3 parametrized tests the shim cannot drive), unchanged from before this change. - compileall clean; locale parity zh/en + t() key coverage: 0 failures. Not in this change - P2#10 disk-based browsing of a long recording and range CSV export (next round, per your choice). - Stability-triggered calibration sampling, replay fixed colour scale, PyOpenGL three-dimensional view. - Hardware verification: no camera attached, so the SDK's real processing chain and the pre-roll's effect on a live tracker were exercised with fakes only.
This commit is contained in:
@@ -146,12 +146,22 @@
|
||||
"depth_config_missing": "Cannot recompute: the recording has no sensor config reference",
|
||||
"depth_config_file_missing": "Cannot recompute: the config file no longer exists at that path",
|
||||
"depth_no_video": "Cannot recompute: this recording has no video segment",
|
||||
"depth_not_recomputed": "Depth has not been recomputed for this cursor position\n(the previous frame's map is not reused)",
|
||||
"depth_recomputing": "Recomputing depth for the current cursor position…",
|
||||
"depth_frame_not_recorded": "This frame was not recorded: its data row was lost to a full queue and only the index row remains",
|
||||
"depth_frame_not_in_video": "This frame never reached the video, so its depth cannot be recomputed",
|
||||
"depth_state_across_segment": "Replay cannot carry the algorithm state across segments: this one restarts at its first frame",
|
||||
"depth_state_approximate": "No reset or pre-roll history for this segment: the algorithm state is an approximation",
|
||||
"depth_warnings": "Recomputation notes: {detail}",
|
||||
"warnings": "Replay notes: {detail}",
|
||||
"warn_config_changed": "the config differs from recording time, so the recomputed depth may differ",
|
||||
"warn_sdk_changed": "the SDK version differs from recording time, so the recomputation may differ",
|
||||
"warn_config_missing": "no config hash was recorded, so recomputation cannot be verified",
|
||||
"warn_depth_recomputed": "depth comes from offline recomputation, not from stored data",
|
||||
"warn_rows_skipped": "some unparsable CSV rows were skipped"
|
||||
"warn_rows_skipped": "some unparsable CSV rows were skipped",
|
||||
"warn_frames_dropped": "frames were lost to a full queue; only their index rows remain (shown as \"not recorded\")",
|
||||
"warn_state_across_segment": "the algorithm state cannot be carried across a segment",
|
||||
"warn_state_approximate": "the algorithm state is an approximation"
|
||||
},
|
||||
"record": {
|
||||
"label": "Record",
|
||||
@@ -180,7 +190,23 @@
|
||||
"delete_row": "Delete row",
|
||||
"clear_channel": "Clear channel",
|
||||
"clear_all": "Clear all",
|
||||
"export": "Export…", "sn": "SN",
|
||||
"export": "Export coefficients…",
|
||||
"export_tip": "Write the SDK coefficient file only; the running device is untouched",
|
||||
"apply": "Apply to device",
|
||||
"apply_tip": "Push the last export to the running device (confirmed again)",
|
||||
"apply_no_export": "No exported coefficients yet — export them first",
|
||||
"save_record": "Save record…",
|
||||
"save_record_tip": "Save every point of this session with its full three-axis samples (audit data), independently of the coefficient file",
|
||||
"save_record_empty": "No calibration points to save yet",
|
||||
"save_record_ok": "Saved the calibration record to {path}\n{points} point(s), {samples} three-axis samples",
|
||||
"save_record_failed": "Could not save the calibration record: {error}",
|
||||
"open_record": "Open record…",
|
||||
"open_record_tip": "Reopen a saved calibration session to inspect every point's samples and diagnostics",
|
||||
"open_record_filter": "Calibration records (*.json)",
|
||||
"open_record_ok": "Loaded {path} ({points} point(s))",
|
||||
"open_record_warnings": "Note: {detail}",
|
||||
"open_record_failed": "Could not open the calibration record: {error}",
|
||||
"sn": "SN",
|
||||
"sn_placeholder": "Serial number (optional)",
|
||||
"live_raw_label": "Live raw",
|
||||
"live_raw": "Live raw FN={fn} FX={fx} FY={fy}",
|
||||
@@ -206,8 +232,10 @@
|
||||
"marked_validation": "Point marked as a validation point",
|
||||
"unmarked_validation": "Validation mark removed",
|
||||
"fit_insufficient": "A fit needs at least 2 usable points (currently {count})",
|
||||
"fit_summary": "Fit {channel}: N = {gain} × raw + {offset} ({count} points, max residual {residual} N)",
|
||||
"fit_summary": "Exported model {channel}: {method} ({count} points / {breakpoints} breakpoints, max residual {residual} N)",
|
||||
"fit_validation": "Independent validation on {count} point(s), max deviation {error} N",
|
||||
"method_piecewise_linear": "piecewise linear",
|
||||
"method_linear": "linear",
|
||||
"point_title": "Calibration point {channel} @ {load} N",
|
||||
"point_channel": "Loaded axis",
|
||||
"point_direction": "Direction",
|
||||
@@ -230,7 +258,9 @@
|
||||
"apply_title": "Apply calibration",
|
||||
"apply_confirm": "Apply the calibration just exported to the current device?\n\nSensor type: {sensor_type}\nConfig: {config}\n\nChoosing No keeps the exported file and leaves the running device untouched.",
|
||||
"apply_skipped": "Exported; not applied to the device",
|
||||
"apply_done": "Calibration applied to {sensor_type}",
|
||||
"apply_pending": "Requested calibration for {sensor_type}; waiting for the device to confirm…",
|
||||
"applied": "Device confirmed the calibration is in effect (version {version})",
|
||||
"export_only": "Exported coefficients to {path} (not applied to the device)",
|
||||
"apply_no_target": "No device to apply to (run an acquisition first)"
|
||||
},
|
||||
"status": {
|
||||
|
||||
Reference in New Issue
Block a user