Save useful ROM data to data directory

This commit is contained in:
Chish36 2026-05-14 11:14:40 +01:00
parent 182c67e105
commit 03dc0a065f

View file

@ -13,10 +13,13 @@ is tracked and an error is raised if it exceeds a minimum amount. Currently
this is 10% of the expected motion is the measured axis.
"""
import json
import os
import time
from copy import copy
from datetime import datetime
from threading import Lock
from typing import Any, Literal, Mapping, Optional, overload
from typing import Any, Literal, Mapping, Optional, Self, overload
import numpy as np
@ -24,6 +27,8 @@ import labthings_fastapi as lt
from camera_stage_mapping import fft_image_tracking
# Things
from openflexure_microscope_server.things import OFMThing
from .autofocus import AutofocusThing
from .camera import BaseCamera
from .camera_stage_mapping import CameraStageMapper
@ -114,7 +119,7 @@ class ParasiticMotionError(lt.exceptions.InvocationError):
"""
class RangeofMotionThing(lt.Thing):
class RangeofMotionThing(OFMThing):
"""A class used to measure the range of motion of the stage in X and Y."""
_class_settings = {"validate_properties_on_set": True}
@ -128,6 +133,14 @@ class RangeofMotionThing(lt.Thing):
default=None, readonly=True
)
csm_matrix: Optional[list[list[float]]] = lt.setting(default=None, readonly=True)
stage_coords: Optional[Any] = lt.setting(default=None, readonly=True)
correlations: Optional[Any] = lt.setting(default=None, readonly=True)
time: Optional[float] = lt.setting(default=None, readonly=True)
def __init__(self, thing_server_interface: lt.ThingServerInterface) -> None:
"""Initialise and create the lock."""
super().__init__(thing_server_interface)
@ -135,6 +148,11 @@ class RangeofMotionThing(lt.Thing):
self._stream_resolution: Optional[tuple[int, int]] = None
self._rom_data = RomDataTracker()
def __enter__(self) -> Self:
"""Open hardware connection when the Thing context manager is opened."""
super().__enter__()
return self
@lt.action
def perform_rom_test(self) -> Mapping[str, Any]:
"""Measures the range of motion of the stage across the x and y axes.
@ -162,6 +180,9 @@ class RangeofMotionThing(lt.Thing):
axes: tuple[Literal["x"], Literal["y"]] = ("x", "y")
directions: tuple[Literal[1], Literal[-1]] = (1, -1)
stage_dic = {}
cor_dic = {}
for axis in axes:
# The final position of the axis under test in the given direction
axis_limits = []
@ -171,14 +192,37 @@ class RangeofMotionThing(lt.Thing):
self._move_until_edge(axis=axis, direction=axis_dir)
# Append final position from tracker
axis_limits.append(self._rom_data.final_position[axis])
axis_string = "positive" if axis_dir == 1 else "negative"
stage_dic[f"{axis}_{axis_string}"] = self._rom_data.stage_coords
cor_dic[f"{axis}_{axis_string}"] = self._rom_data.offsets
# Calculate step range.
step_range.append(abs(axis_limits[0] - axis_limits[1]))
total_time = time.time() - start_time
total_time = (time.time() - start_time) / 60
self.logger.info(
f"Range of motion is {step_range[0]} x {step_range[1]} steps"
)
self.calibrated_range = (step_range[0], step_range[1])
data = {
"calibrated_range": [step_range[0], step_range[1]],
"stage_coords": self.stage_coords,
"correlations": self.correlations,
"csm_matrix": self._csm.image_to_stage_displacement_matrix,
"time": self.time,
}
if not os.path.exists(self.data_dir):
os.makedirs(self.data_dir)
with open(
os.path.join(
self.data_dir,
f"rom_data_{datetime.now().strftime('%Y_%m_%d_%H_%M')}.json",
),
"w",
encoding="utf-8",
) as f:
json.dump(data, f, indent=4)
finally:
self._lock.release()
return {