Reduce argument numbers with data class and constants
This commit is contained in:
parent
8a0836f368
commit
9fe6ad8efb
1 changed files with 98 additions and 131 deletions
|
|
@ -15,6 +15,7 @@ this is 10% of the expected motion is the measured axis.
|
||||||
|
|
||||||
from typing import Literal, Any, Optional
|
from typing import Literal, Any, Optional
|
||||||
import time
|
import time
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from scipy.optimize import curve_fit
|
from scipy.optimize import curve_fit
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
@ -38,6 +39,11 @@ CSMDep = lt.deps.direct_thing_client_dependency(
|
||||||
)
|
)
|
||||||
AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocus/")
|
AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocus/")
|
||||||
|
|
||||||
|
## Size of movement in percentage of field of view
|
||||||
|
SMALL_STEP = 20
|
||||||
|
MEDIUM_STEP = 50
|
||||||
|
BIG_STEP = 200
|
||||||
|
|
||||||
|
|
||||||
class RomDataTracker:
|
class RomDataTracker:
|
||||||
"""Class for tracking range of motion data."""
|
"""Class for tracking range of motion data."""
|
||||||
|
|
@ -64,6 +70,20 @@ class RomDataTracker:
|
||||||
self.cor_lat_steps.clear()
|
self.cor_lat_steps.clear()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RomDeps:
|
||||||
|
"""Grouped dependencies for the Range of motion Thing.
|
||||||
|
|
||||||
|
These are used to pass the dependencies from actions to other sub-functions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
autofocus: AutofocusDep
|
||||||
|
stage: StageDep
|
||||||
|
cam: CamDep
|
||||||
|
csm: CSMDep
|
||||||
|
logger: lt.deps.InvocationLogger
|
||||||
|
|
||||||
|
|
||||||
class ParasiticMotionError(Exception):
|
class ParasiticMotionError(Exception):
|
||||||
"""Custom exception raised when parasitic motion is detected.
|
"""Custom exception raised when parasitic motion is detected.
|
||||||
|
|
||||||
|
|
@ -71,8 +91,6 @@ class ParasiticMotionError(Exception):
|
||||||
is too high.
|
is too high.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _parasitic_detect(delta: float, max_allowed_delta: float) -> None:
|
def _parasitic_detect(delta: float, max_allowed_delta: float) -> None:
|
||||||
"""Compare two values and raise parasitic motion error."""
|
"""Compare two values and raise parasitic motion error."""
|
||||||
|
|
@ -132,9 +150,9 @@ def _predict_z(
|
||||||
|
|
||||||
lateral_positions = [i[axis] for i in positions] # x or y positions
|
lateral_positions = [i[axis] for i in positions] # x or y positions
|
||||||
z_positions = [i["z"] for i in positions]
|
z_positions = [i["z"] for i in positions]
|
||||||
parameters, _ = curve_fit(quadratic, lateral_positions, z_positions)
|
fit_params, *_others = curve_fit(quadratic, lateral_positions, z_positions)
|
||||||
z_dest = quadratic(
|
z_dest = quadratic(
|
||||||
stage.position[axis] + (relative_move / pixel_step[axis]), *parameters
|
stage.position[axis] + (relative_move / pixel_step[axis]), *fit_params
|
||||||
)
|
)
|
||||||
|
|
||||||
return z_dest - stage.position["z"]
|
return z_dest - stage.position["z"]
|
||||||
|
|
@ -146,9 +164,7 @@ def _move_and_measure(
|
||||||
data: RomDataTracker,
|
data: RomDataTracker,
|
||||||
image1: npt.ArrayLike,
|
image1: npt.ArrayLike,
|
||||||
autofocus_proc: bool,
|
autofocus_proc: bool,
|
||||||
csm: CSMDep,
|
rom_deps: RomDeps,
|
||||||
autofocus: AutofocusDep,
|
|
||||||
cam: CamDep,
|
|
||||||
) -> tuple[npt.ArrayLike, str]:
|
) -> tuple[npt.ArrayLike, str]:
|
||||||
"""Move the stage and measure the offset between the two positions.
|
"""Move the stage and measure the offset between the two positions.
|
||||||
|
|
||||||
|
|
@ -156,22 +172,19 @@ def _move_and_measure(
|
||||||
:param axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
:param axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
||||||
:param data: The object used to track stage coordinates, correlation and delta.
|
:param data: The object used to track stage coordinates, correlation and delta.
|
||||||
:param image1: An image taken before moving to be correlated with image2.
|
:param image1: An image taken before moving to be correlated with image2.
|
||||||
:param autofocus_proc: If true, looping.autofocus will be used after the stage moves.
|
:param rom_deps: All dependencies that were passed to the calling Action
|
||||||
:param csm: A direct_thing_client dependency for camera stage mapping.
|
|
||||||
:param autofocus: A direct_thing_client dependency for autofocus.
|
|
||||||
:param cam: A raw_thing_client depeendency for the camera.
|
|
||||||
:return: All required data for the next move. This includes the updated delta value and offset.
|
:return: All required data for the next move. This includes the updated delta value and offset.
|
||||||
Also returns what wrong_axis is i.e. if the direction is 'x', wrong_axis = 'y'.
|
Also returns what wrong_axis is i.e. if the direction is 'x', wrong_axis = 'y'.
|
||||||
"""
|
"""
|
||||||
if axis == "x":
|
if axis == "x":
|
||||||
csm.move_in_image_coordinates(x=step_size["x"], y=0)
|
rom_deps.csm.move_in_image_coordinates(x=step_size["x"], y=0)
|
||||||
wrong_axis = "y"
|
wrong_axis = "y"
|
||||||
else:
|
else:
|
||||||
csm.move_in_image_coordinates(x=0, y=step_size["y"])
|
rom_deps.csm.move_in_image_coordinates(x=0, y=step_size["y"])
|
||||||
wrong_axis = "x"
|
wrong_axis = "x"
|
||||||
if autofocus_proc:
|
if autofocus_proc:
|
||||||
autofocus.looping_autofocus(dz=800)
|
rom_deps.autofocus.looping_autofocus(dz=800)
|
||||||
image2 = np.array(Image.open(cam.grab_jpeg().open()))
|
image2 = np.array(Image.open(rom_deps.cam.grab_jpeg().open()))
|
||||||
offset = fft_image_tracking.displacement_between_images(
|
offset = fft_image_tracking.displacement_between_images(
|
||||||
image_0=image1, image_1=image2, sigma=10, fractional_threshold=0.1, pad=True
|
image_0=image1, image_1=image2, sigma=10, fractional_threshold=0.1, pad=True
|
||||||
) # Units is pixels
|
) # Units is pixels
|
||||||
|
|
@ -186,11 +199,7 @@ def _acquire_z_predict_points(
|
||||||
direction: Literal[1, -1],
|
direction: Literal[1, -1],
|
||||||
axis: Literal["x", "y"],
|
axis: Literal["x", "y"],
|
||||||
data: RomDataTracker,
|
data: RomDataTracker,
|
||||||
csm: CSMDep,
|
rom_deps: RomDeps,
|
||||||
cam: CamDep,
|
|
||||||
stage: StageDep,
|
|
||||||
autofocus: AutofocusDep,
|
|
||||||
logger: lt.deps.InvocationLogger,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Complete 5 medium sized steps to collect stage coordinates for prediction.
|
"""Complete 5 medium sized steps to collect stage coordinates for prediction.
|
||||||
|
|
||||||
|
|
@ -200,32 +209,26 @@ def _acquire_z_predict_points(
|
||||||
:param direction: The direction the stage moves.
|
:param direction: The direction the stage moves.
|
||||||
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
||||||
:params data: The object used to track stage coordinates, correlation and delta.
|
:params data: The object used to track stage coordinates, correlation and delta.
|
||||||
:param csm: A direct_thing_client dependency for camera stage mapping.
|
:param rom_deps: All dependencies that were passed to the calling Action
|
||||||
:param camera: A raw_thing_client depeendency for the camera.
|
|
||||||
:param stage: A raw_thing_client depeendency for the microscope stage.
|
|
||||||
:param autofocus: A direct_thing_client dependency for autofocus.
|
|
||||||
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
||||||
"""
|
"""
|
||||||
medium_step = 50
|
|
||||||
wrong_axis_max_medium = _generate_move_dicts(
|
wrong_axis_max_medium = _generate_move_dicts(
|
||||||
medium_step, stream_resolution, direction, factor=0.1
|
MEDIUM_STEP, stream_resolution, direction, factor=0.1
|
||||||
)
|
)
|
||||||
for _loop in range(5):
|
for _loop in range(5):
|
||||||
image1 = np.array(Image.open(cam.grab_jpeg().open()))
|
image1 = rom_deps.cam.grab_as_array()
|
||||||
offset, wrong_axis = _move_and_measure(
|
offset, wrong_axis = _move_and_measure(
|
||||||
step_size=_generate_move_dicts(medium_step, stream_resolution, direction),
|
step_size=_generate_move_dicts(MEDIUM_STEP, stream_resolution, direction),
|
||||||
axis=axis,
|
axis=axis,
|
||||||
data=data,
|
data=data,
|
||||||
image1=image1,
|
image1=image1,
|
||||||
autofocus_proc=True,
|
autofocus_proc=True,
|
||||||
csm=csm,
|
rom_deps=rom_deps,
|
||||||
autofocus=autofocus,
|
|
||||||
cam=cam,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"Offset measured as {data.delta[axis]}")
|
rom_deps.logger.info(f"Offset measured as {data.delta[axis]}")
|
||||||
|
|
||||||
data.measure(stage.position, offset)
|
data.measure(rom_deps.stage.position, offset)
|
||||||
|
|
||||||
_parasitic_detect(
|
_parasitic_detect(
|
||||||
delta=abs(data.delta[wrong_axis]),
|
delta=abs(data.delta[wrong_axis]),
|
||||||
|
|
@ -234,17 +237,12 @@ def _acquire_z_predict_points(
|
||||||
|
|
||||||
|
|
||||||
def _check_stage_operation(
|
def _check_stage_operation(
|
||||||
small_step: int,
|
|
||||||
stream_resolution: list[int],
|
stream_resolution: list[int],
|
||||||
direction: Literal[1, -1],
|
direction: Literal[1, -1],
|
||||||
axis: Literal["x", "y"],
|
axis: Literal["x", "y"],
|
||||||
data: RomDataTracker,
|
data: RomDataTracker,
|
||||||
minimum_offset_small: dict[str, float],
|
minimum_offset_small: dict[str, float],
|
||||||
csm: CSMDep,
|
rom_deps: RomDeps,
|
||||||
cam: CamDep,
|
|
||||||
stage: StageDep,
|
|
||||||
autofocus: AutofocusDep,
|
|
||||||
logger: lt.deps.InvocationLogger,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Carries out 3 small moves in a given direction and axis.
|
"""Carries out 3 small moves in a given direction and axis.
|
||||||
|
|
||||||
|
|
@ -254,46 +252,41 @@ def _check_stage_operation(
|
||||||
image quality is not causing the correlation to be unsuccessful. If the correlation
|
image quality is not causing the correlation to be unsuccessful. If the correlation
|
||||||
is still too low then the edge is found.
|
is still too low then the edge is found.
|
||||||
|
|
||||||
:params small_step: The integer value used to generate the small step sizes.
|
Delta is updated and tracked after each move.
|
||||||
|
|
||||||
:params stream_resolution: The resolution of the stream from the camera.
|
:params stream_resolution: The resolution of the stream from the camera.
|
||||||
:param direction: The direction the stage moves.
|
:param direction: The direction the stage moves.
|
||||||
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
:params axis: The axis which is being measured. This must be 'x' or 'y'.
|
||||||
:params data: The object used to track stage coordinates, correlation and delta.
|
:params data: The object used to track stage coordinates, correlation and delta.
|
||||||
:params minimum_offset_small: A dictionary containing the minimum values for
|
:params minimum_offset_small: A dictionary containing the minimum values for
|
||||||
a successful correlation.
|
a successful correlation.
|
||||||
:param csm: A direct_thing_client dependency for camera stage mapping.
|
:param rom_deps: All dependencies that were passed to the calling Action
|
||||||
:param camera: A raw_thing_client depeendency for the camera.
|
|
||||||
:param stage: A raw_thing_client depeendency for the microscope stage.
|
|
||||||
:param autofocus: A direct_thing_client dependency for autofocus.
|
|
||||||
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
:return: Stage_coords and cor_lat_steps are lists of data tracked throughout the test.
|
||||||
Delta is updated and tracked after each move.
|
|
||||||
"""
|
"""
|
||||||
failure_count = 0
|
failure_count = 0
|
||||||
|
|
||||||
for _loop in range(3):
|
for _loop in range(3):
|
||||||
image1 = np.array(Image.open(cam.grab_jpeg().open()))
|
image1 = rom_deps.cam.grab_as_array()
|
||||||
offset, wrong_axis = _move_and_measure(
|
offset, wrong_axis = _move_and_measure(
|
||||||
step_size=_generate_move_dicts(small_step, stream_resolution, direction),
|
step_size=_generate_move_dicts(SMALL_STEP, stream_resolution, direction),
|
||||||
axis=axis,
|
axis=axis,
|
||||||
data=data,
|
data=data,
|
||||||
image1=image1,
|
image1=image1,
|
||||||
autofocus_proc=False,
|
autofocus_proc=False,
|
||||||
csm=csm,
|
rom_deps=rom_deps,
|
||||||
autofocus=autofocus,
|
|
||||||
cam=cam,
|
|
||||||
)
|
)
|
||||||
logger.info(f"Offset measured as {data.delta[axis]}")
|
rom_deps.logger.info(f"Offset measured as {data.delta[axis]}")
|
||||||
|
|
||||||
# If correlation is too small, refocuses and capture new image 3 times.
|
# If correlation is too small, refocuses and capture new image 3 times.
|
||||||
while (
|
while (
|
||||||
np.abs(data.delta[axis]) < np.abs(minimum_offset_small[axis])
|
np.abs(data.delta[axis]) < np.abs(minimum_offset_small[axis])
|
||||||
and failure_count < 3
|
and failure_count < 3
|
||||||
):
|
):
|
||||||
logger.info(
|
rom_deps.logger.info(
|
||||||
f"Correlation failed. Refocusing to check. Attempt {failure_count + 1}/3"
|
f"Correlation failed. Refocusing to check. Attempt {failure_count + 1}/3"
|
||||||
)
|
)
|
||||||
autofocus.looping_autofocus(dz=1000)
|
rom_deps.autofocus.looping_autofocus(dz=1000)
|
||||||
image2 = np.array(Image.open(cam.grab_jpeg().open()))
|
image2 = rom_deps.cam.grab_as_array()
|
||||||
failure_count += 1
|
failure_count += 1
|
||||||
offset = fft_image_tracking.displacement_between_images(
|
offset = fft_image_tracking.displacement_between_images(
|
||||||
image_0=image1,
|
image_0=image1,
|
||||||
|
|
@ -305,45 +298,39 @@ def _check_stage_operation(
|
||||||
# Units is pixels
|
# Units is pixels
|
||||||
data.delta["x"] = int(offset[1])
|
data.delta["x"] = int(offset[1])
|
||||||
data.delta["y"] = int(offset[0])
|
data.delta["y"] = int(offset[0])
|
||||||
logger.info(
|
rom_deps.logger.info(
|
||||||
f"Displacement found was {data.delta[axis]}.\
|
f"Displacement found was {data.delta[axis]}.\
|
||||||
Minimum offset is {minimum_offset_small[axis]}"
|
Minimum offset is {minimum_offset_small[axis]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
data.measure(stage.position, offset)
|
data.measure(rom_deps.stage.position, offset)
|
||||||
|
|
||||||
_parasitic_detect(
|
_parasitic_detect(
|
||||||
abs(data.delta[wrong_axis]),
|
abs(data.delta[wrong_axis]),
|
||||||
abs(
|
abs(
|
||||||
_generate_move_dicts(
|
_generate_move_dicts(
|
||||||
small_step, stream_resolution, direction, factor=0.1
|
SMALL_STEP, stream_resolution, direction, factor=0.1
|
||||||
)[wrong_axis]
|
)[wrong_axis]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# this means the edge has been found
|
# this means the edge has been found
|
||||||
if np.abs(data.delta[axis]) < np.abs(minimum_offset_small[axis]):
|
if np.abs(data.delta[axis]) < np.abs(minimum_offset_small[axis]):
|
||||||
logger.info("Edge has been found.")
|
rom_deps.logger.info("Edge has been found.")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def _motion_detection(
|
def _motion_detection(
|
||||||
axis: Literal["x", "y"],
|
axis: Literal["x", "y"],
|
||||||
direction: Literal[1, -1],
|
direction: Literal[1, -1],
|
||||||
csm: CSMDep,
|
rom_deps: RomDeps,
|
||||||
stage: StageDep,
|
|
||||||
cam: CamDep,
|
|
||||||
logger: lt.deps.InvocationLogger,
|
|
||||||
) -> dict[str, int]:
|
) -> dict[str, int]:
|
||||||
"""Move the stage until motion is detected along a specified axis and direction.
|
"""Move the stage until motion is detected along a specified axis and direction.
|
||||||
|
|
||||||
:params axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
:params axis: The axis in which the stage is moving. This must be 'x' or 'y'.
|
||||||
:params direction: The direction in which the stage was moving
|
:params direction: The direction in which the stage was moving
|
||||||
previous to motion detection being used.
|
previous to motion detection being used.
|
||||||
:param csm: A direct_thing_client dependency for camera stage mapping.
|
:param rom_deps: All dependencies that were passed to the calling Action
|
||||||
:param stage: A raw_thing_client depeendency for the microscope stage.
|
|
||||||
:param camera: A raw_thing_client depeendency for the camera.
|
|
||||||
:return: The stage coordinates where motion was detected.
|
|
||||||
"""
|
"""
|
||||||
# Array of increasing pixel sizes (powers of 2 from 1 to 512)
|
# Array of increasing pixel sizes (powers of 2 from 1 to 512)
|
||||||
displacements = [2**i for i in range(10)]
|
displacements = [2**i for i in range(10)]
|
||||||
|
|
@ -356,10 +343,12 @@ def _motion_detection(
|
||||||
|
|
||||||
for loop in range(np.shape(displacements)[0]):
|
for loop in range(np.shape(displacements)[0]):
|
||||||
this_motion_step[axis] = displacements[loop] * direction * -1
|
this_motion_step[axis] = displacements[loop] * direction * -1
|
||||||
logger.info(f"Testing with step size {this_motion_step[axis]}")
|
rom_deps.logger.info(f"Testing with step size {this_motion_step[axis]}")
|
||||||
image1 = np.array(Image.open(cam.grab_jpeg().open()))
|
image1 = rom_deps.cam.grab_as_array()
|
||||||
csm.move_in_image_coordinates(x=this_motion_step["x"], y=this_motion_step["y"])
|
rom_deps.csm.move_in_image_coordinates(
|
||||||
image2 = np.array(Image.open(cam.grab_jpeg().open()))
|
x=this_motion_step["x"], y=this_motion_step["y"]
|
||||||
|
)
|
||||||
|
image2 = rom_deps.cam.grab_as_array()
|
||||||
offset = fft_image_tracking.displacement_between_images(
|
offset = fft_image_tracking.displacement_between_images(
|
||||||
image_0=image1,
|
image_0=image1,
|
||||||
image_1=image2,
|
image_1=image2,
|
||||||
|
|
@ -369,19 +358,19 @@ def _motion_detection(
|
||||||
)
|
)
|
||||||
delta["x"] = int(offset[1])
|
delta["x"] = int(offset[1])
|
||||||
delta["y"] = int(offset[0])
|
delta["y"] = int(offset[0])
|
||||||
logger.info(f"Offset measured as {np.abs(delta[axis])}")
|
rom_deps.logger.info(f"Offset measured as {np.abs(delta[axis])}")
|
||||||
if np.abs(delta[axis]) > motion_minimum:
|
if np.abs(delta[axis]) > motion_minimum:
|
||||||
logger.info("Motion detected.")
|
rom_deps.logger.info("Motion detected.")
|
||||||
break
|
break
|
||||||
|
|
||||||
return stage.position
|
return rom_deps.stage.position
|
||||||
|
|
||||||
|
|
||||||
def _collate_data(data: dict, time: float, csm: CSMDep) -> dict[str, Any]:
|
def _collate_data(data: dict, total_time: float, csm: CSMDep) -> dict[str, Any]:
|
||||||
"""Collate and calculate all useful data from ROM test.
|
"""Collate and calculate all useful data from ROM test.
|
||||||
|
|
||||||
:param data: Dictionary created from ROM test.
|
:param data: Dictionary created from ROM test.
|
||||||
:param time: Total time of the range of motion test.
|
:param total_time: Total time of the range of motion test.
|
||||||
:param csm: A direct_thing_client dependency for camera stage mapping.
|
:param csm: A direct_thing_client dependency for camera stage mapping.
|
||||||
"""
|
"""
|
||||||
x_range = abs(
|
x_range = abs(
|
||||||
|
|
@ -394,7 +383,7 @@ def _collate_data(data: dict, time: float, csm: CSMDep) -> dict[str, Any]:
|
||||||
)
|
)
|
||||||
step_range = [x_range, y_range]
|
step_range = [x_range, y_range]
|
||||||
|
|
||||||
data["Time"] = time
|
data["Time"] = total_time
|
||||||
data["CSM Matrix"] = csm.image_to_stage_displacement_matrix
|
data["CSM Matrix"] = csm.image_to_stage_displacement_matrix
|
||||||
data["Step Range"] = step_range
|
data["Step Range"] = step_range
|
||||||
return data
|
return data
|
||||||
|
|
@ -403,67 +392,56 @@ def _collate_data(data: dict, time: float, csm: CSMDep) -> dict[str, Any]:
|
||||||
class RangeofMotionThing(lt.Thing):
|
class RangeofMotionThing(lt.Thing):
|
||||||
"""A class used to measure the range of motion of the stage in X and Y."""
|
"""A class used to measure the range of motion of the stage in X and Y."""
|
||||||
|
|
||||||
|
last_calibration = lt.ThingSetting(initial_value=None, model=dict, readonly=True)
|
||||||
|
|
||||||
def rom_axis(
|
def rom_axis(
|
||||||
self,
|
self,
|
||||||
autofocus: AutofocusDep,
|
|
||||||
stage: StageDep,
|
|
||||||
cam: CamDep,
|
|
||||||
csm: CSMDep,
|
|
||||||
logger: lt.deps.InvocationLogger,
|
|
||||||
axis: Literal["x", "y"],
|
axis: Literal["x", "y"],
|
||||||
direction: Literal[1, -1],
|
direction: Literal[1, -1],
|
||||||
|
rom_deps: RomDeps,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Measure the range of motion in a single axis and direction.
|
"""Measure the range of motion in a single axis and direction.
|
||||||
|
|
||||||
:param stage: A raw_thing_client depeendency for the microscope stage.
|
:param rom_deps: All dependencies that were passed to the calling Action
|
||||||
:param cam: A raw_thing_client depeendency for the camera.
|
|
||||||
:param csm: A raw_thing_client depeendency for camera stage mapping.
|
|
||||||
:param logger: A raw_thing_client depeendency for the logger.
|
|
||||||
:param axis: The axis which is being measured. This must be 'x' or 'y'.
|
:param axis: The axis which is being measured. This must be 'x' or 'y'.
|
||||||
:param direction: The direction which is being measured. This must be 1 or -1.
|
:param direction: The direction which is being measured. This must be 1 or -1.
|
||||||
:return: Results dictionary containing stage positions,
|
:return: Results dictionary containing stage positions,
|
||||||
correlations and the final position.
|
correlations and the final position.
|
||||||
"""
|
"""
|
||||||
autofocus.looping_autofocus(dz=1000)
|
rom_deps.autofocus.looping_autofocus(dz=1000)
|
||||||
|
|
||||||
starting_position = list(stage.position.values())
|
starting_position = list(rom_deps.stage.position.values())
|
||||||
|
|
||||||
rom_data = RomDataTracker() # initialise data tracking object
|
rom_data = RomDataTracker() # initialise data tracking object
|
||||||
axis_results = {}
|
axis_results = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(
|
dir_str = "positive" if direction == 1 else "negative"
|
||||||
f"Beginning the {axis}-axis in the {'positive' if direction == 1 else 'negative'} "
|
rom_deps.logger.info(
|
||||||
"direction"
|
f"Beginning the {axis}-axis in the {dir_str} direction"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate required dictionaries for step sizes and minimum offsets
|
# Generate required dictionaries for step sizes and minimum offsets
|
||||||
stream_resolution = [820, 616]
|
stream_resolution = [820, 616]
|
||||||
big_step = 200
|
|
||||||
small_step = 20
|
|
||||||
step_sizes_big = _generate_move_dicts(
|
step_sizes_big = _generate_move_dicts(
|
||||||
big_step, stream_resolution, direction
|
BIG_STEP, stream_resolution, direction
|
||||||
)
|
)
|
||||||
|
|
||||||
rom_data.stage_coords.append(stage.position)
|
rom_data.stage_coords.append(rom_deps.stage.position)
|
||||||
|
|
||||||
logger.info("Moving the stage in 5 medium sized steps.")
|
rom_deps.logger.info("Moving the stage in 5 medium sized steps.")
|
||||||
_acquire_z_predict_points(
|
_acquire_z_predict_points(
|
||||||
stream_resolution=stream_resolution,
|
stream_resolution=stream_resolution,
|
||||||
direction=direction,
|
direction=direction,
|
||||||
axis=axis,
|
axis=axis,
|
||||||
data=rom_data,
|
data=rom_data,
|
||||||
csm=csm,
|
rom_deps=rom_deps,
|
||||||
cam=cam,
|
|
||||||
stage=stage,
|
|
||||||
autofocus=autofocus,
|
|
||||||
logger=logger,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 1 big step followed by 3 small steps
|
# 1 big step followed by 3 small steps
|
||||||
|
|
||||||
minimum_offset_small = _generate_move_dicts(
|
minimum_offset_small = _generate_move_dicts(
|
||||||
small_step, stream_resolution, direction, factor=0.65
|
SMALL_STEP, stream_resolution, direction, factor=0.65
|
||||||
)
|
)
|
||||||
|
|
||||||
while np.abs(rom_data.delta[axis]) > np.abs(minimum_offset_small[axis]):
|
while np.abs(rom_data.delta[axis]) > np.abs(minimum_offset_small[axis]):
|
||||||
|
|
@ -471,46 +449,38 @@ class RangeofMotionThing(lt.Thing):
|
||||||
positions=rom_data.stage_coords,
|
positions=rom_data.stage_coords,
|
||||||
axis=axis,
|
axis=axis,
|
||||||
relative_move=step_sizes_big[axis],
|
relative_move=step_sizes_big[axis],
|
||||||
stage=stage,
|
stage=rom_deps.stage,
|
||||||
csm=csm,
|
csm=rom_deps.csm,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info("Z calibration complete.")
|
rom_deps.logger.info("Z calibration complete.")
|
||||||
stage.move_relative(z=z_diff)
|
rom_deps.stage.move_relative(z=z_diff)
|
||||||
logger.info(f"Moved in z by {z_diff}")
|
rom_deps.logger.info(f"Moved in z by {z_diff}")
|
||||||
|
|
||||||
# Big step
|
# Big step
|
||||||
if axis == "x":
|
if axis == "x":
|
||||||
csm.move_in_image_coordinates(x=step_sizes_big["x"], y=0)
|
rom_deps.csm.move_in_image_coordinates(x=step_sizes_big["x"], y=0)
|
||||||
else:
|
else:
|
||||||
csm.move_in_image_coordinates(x=0, y=step_sizes_big["y"])
|
rom_deps.csm.move_in_image_coordinates(x=0, y=step_sizes_big["y"])
|
||||||
|
|
||||||
autofocus.looping_autofocus(dz=800)
|
rom_deps.autofocus.looping_autofocus(dz=800)
|
||||||
rom_data.stage_coords.append(stage.position)
|
rom_data.stage_coords.append(rom_deps.stage.position)
|
||||||
|
|
||||||
_check_stage_operation(
|
_check_stage_operation(
|
||||||
small_step=small_step,
|
|
||||||
stream_resolution=stream_resolution,
|
stream_resolution=stream_resolution,
|
||||||
direction=direction,
|
direction=direction,
|
||||||
axis=axis,
|
axis=axis,
|
||||||
data=rom_data,
|
data=rom_data,
|
||||||
minimum_offset_small=minimum_offset_small,
|
minimum_offset_small=minimum_offset_small,
|
||||||
csm=csm,
|
rom_deps=rom_deps,
|
||||||
cam=cam,
|
|
||||||
stage=stage,
|
|
||||||
autofocus=autofocus,
|
|
||||||
logger=logger,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Motion detection
|
# Motion detection
|
||||||
logger.info("Running motion detection")
|
rom_deps.logger.info("Running motion detection")
|
||||||
final_pos = _motion_detection(
|
final_pos = _motion_detection(
|
||||||
axis=axis,
|
axis=axis,
|
||||||
direction=direction,
|
direction=direction,
|
||||||
csm=csm,
|
rom_deps=rom_deps,
|
||||||
stage=stage,
|
|
||||||
cam=cam,
|
|
||||||
logger=logger,
|
|
||||||
)
|
)
|
||||||
rom_data.stage_coords[np.shape(np.array(rom_data.stage_coords))[0] - 1] = (
|
rom_data.stage_coords[np.shape(np.array(rom_data.stage_coords))[0] - 1] = (
|
||||||
final_pos
|
final_pos
|
||||||
|
|
@ -525,14 +495,14 @@ class RangeofMotionThing(lt.Thing):
|
||||||
rom_data.reset_tracker()
|
rom_data.reset_tracker()
|
||||||
|
|
||||||
except ParasiticMotionError:
|
except ParasiticMotionError:
|
||||||
logger.info("Parasitic motion detected.")
|
rom_deps.logger.error("Parasitic motion detected.")
|
||||||
return {
|
return {
|
||||||
"correlation_lateral_steps": 0,
|
"correlation_lateral_steps": 0,
|
||||||
"stage_positions": 0,
|
"stage_positions": 0,
|
||||||
"final_position": {"x": 0, "y": 0, "z": 0},
|
"final_position": {"x": 0, "y": 0, "z": 0},
|
||||||
}
|
}
|
||||||
finally:
|
finally:
|
||||||
stage.move_absolute(
|
rom_deps.stage.move_absolute(
|
||||||
x=starting_position[0],
|
x=starting_position[0],
|
||||||
y=starting_position[1],
|
y=starting_position[1],
|
||||||
z=starting_position[2],
|
z=starting_position[2],
|
||||||
|
|
@ -559,6 +529,9 @@ class RangeofMotionThing(lt.Thing):
|
||||||
:param logger: A raw_thing_client depeendency for the logger.
|
:param logger: A raw_thing_client depeendency for the logger.
|
||||||
:return: Results dictionary separated into keys of each axis and direction.
|
:return: Results dictionary separated into keys of each axis and direction.
|
||||||
"""
|
"""
|
||||||
|
rom_deps = RomDeps(
|
||||||
|
autofocus=autofocus, stage=stage, csm=csm, cam=cam, logger=logger
|
||||||
|
)
|
||||||
logger.info(
|
logger.info(
|
||||||
"Using the stage to measure the Range of Motion. "
|
"Using the stage to measure the Range of Motion. "
|
||||||
"Please ensure you are using a big enough sample."
|
"Please ensure you are using a big enough sample."
|
||||||
|
|
@ -569,13 +542,9 @@ class RangeofMotionThing(lt.Thing):
|
||||||
# Loop through all axes and directions.
|
# Loop through all axes and directions.
|
||||||
for axis_dir in [["x", 1], ["x", -1], ["y", 1], ["y", -1]]:
|
for axis_dir in [["x", 1], ["x", -1], ["y", 1], ["y", -1]]:
|
||||||
axis_dir_results = self.rom_axis(
|
axis_dir_results = self.rom_axis(
|
||||||
autofocus,
|
|
||||||
stage,
|
|
||||||
cam,
|
|
||||||
csm,
|
|
||||||
logger,
|
|
||||||
axis=axis_dir[0],
|
axis=axis_dir[0],
|
||||||
direction=axis_dir[1],
|
direction=axis_dir[1],
|
||||||
|
rom_deps=rom_deps,
|
||||||
)
|
)
|
||||||
# Save results from single axis and direction
|
# Save results from single axis and direction
|
||||||
rom_json[
|
rom_json[
|
||||||
|
|
@ -585,7 +554,7 @@ class RangeofMotionThing(lt.Thing):
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
total_time = (end_time - start_time) / 60
|
total_time = (end_time - start_time) / 60
|
||||||
|
|
||||||
rom_results = _collate_data(data=rom_json, time=total_time, csm=csm)
|
rom_results = _collate_data(data=rom_json, total_time=total_time, csm=csm)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Range of motion is {rom_results['Step Range'][0]} x {rom_results['Step Range'][1]} steps"
|
f"Range of motion is {rom_results['Step Range'][0]} x {rom_results['Step Range'][1]} steps"
|
||||||
|
|
@ -594,5 +563,3 @@ class RangeofMotionThing(lt.Thing):
|
||||||
self.last_calibration = DenumpifyingDict(rom_results).model_dump()
|
self.last_calibration = DenumpifyingDict(rom_results).model_dump()
|
||||||
|
|
||||||
return rom_results
|
return rom_results
|
||||||
|
|
||||||
last_calibration = lt.ThingSetting(initial_value=None, model=dict, readonly=True)
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue