Adding even more ROM tests

This commit is contained in:
Julian Stirling 2025-10-17 01:29:36 +01:00
parent 664c7de5f8
commit 3d49cbf921
2 changed files with 60 additions and 12 deletions

View file

@ -43,6 +43,7 @@ MEDIUM_STEP = 50
BIG_STEP = 200
PARASITIC_MOTION_TOL = 0.1
DETECT_MOTION_TOL = 0.65
class RomDataTracker:
@ -196,7 +197,7 @@ class RangeofMotionThing(lt.Thing):
}
def _set_stream_resolution(self, cam: CamDep) -> None:
"""Set the self._stream_reolution attribute by reading camera.
"""Set the self._stream_resolution attribute by reading camera.
:param cam: The camera dependency.
"""
@ -288,7 +289,7 @@ class RangeofMotionThing(lt.Thing):
"""
if self._stream_resolution is None:
raise RuntimeError(
"Stream resolution mut be set before generating movement in coords"
"Stream resolution must be set before generating movement in coords"
)
img_index = 0 if axis == "x" else 1
@ -372,13 +373,11 @@ class RangeofMotionThing(lt.Thing):
) -> bool:
"""Carry out 3 small moves in a given direction and axis.
Each position after the first is correlated with the previous position
to check the stage has moved as far as it should. If the correlation is
less than expected, 3 attempts are made to refocus the image to ensure that
image quality is not causing the correlation to be unsuccessful. If the correlation
is still too low then the edge is found.
Delta is updated and tracked after each move.
An image is taken before and after each move to check has moved as far as it
should. If the offset (calculated by cross correlation) is less than expected,
3 attempts are made to refocus the image to ensure that image quality is not
causing the offset to mistakenly be reported as too low be unsuccessful. If the
calculated offset is still too low then the edge is found.
:param axis: The axis which is being measured. This must be 'x' or 'y'.
:param direction: The direction the stage moves.
@ -387,7 +386,7 @@ class RangeofMotionThing(lt.Thing):
movement = self._movement_in_img_coords(
fov_perc=SMALL_STEP, axis=axis, direction=direction
)
abs_min_offset = abs(movement[axis] * 0.65)
abs_min_offset = abs(movement[axis] * DETECT_MOTION_TOL)
for _loop in range(3):
offset = self._move_and_measure(
@ -472,8 +471,7 @@ class RangeofMotionThing(lt.Thing):
if ``abs_min_offset`` is also set
:param abs_min_offset: The absolute minimum (on-axis) offset, under which the
autofocus is repeated.
:return: All required data for the next move. This includes the updated delta
value and offset.
:return: The calculated offset from cross correlation.
"""
# Take image before move
before_img = rom_deps.cam.grab_as_array()

View file

@ -219,3 +219,53 @@ def test_move_back_until_motion_detected(rom_thing, mock_rom_deps, mocker):
for i, call_args in enumerate(mock_move_n_meas.call_args_list):
call_args.kwargs["movement"] = {"x": -(2**i), "y": 0}
call_args.kwargs["perform_autofocus"] = False
@pytest.mark.parametrize(
("good_moves", "expected_to_detect_motion", "offset_calls"),
[
([0, 1, 2], True, 3), # First 3 pass all good
([1, 2, 3], True, 4), # First is bad, will refocus, still complete
([2, 3, 4], True, 5), # First 2 are bad, will refocus twice, still complete
([3, 4, 5], True, 6), # First 3 are bad, will refocus 3 times, still complete
([4, 5, 6], False, 4), # First 4 are bad, fails
# Check second and 3rd measurement can fail after first fails 3 times
([3, 5, 7], True, 8),
([3, 6, 9], True, 10),
([3, 7, 11], True, 12),
# But they can't fail 4 times
([3, 8, 9], False, 8),
([3, 7, 12], False, 12),
],
)
def test_stage_still_moves(
good_moves,
expected_to_detect_motion,
offset_calls,
rom_thing,
mock_rom_deps,
mocker,
):
"""Test _stage_still_moves correctly detects stage movement."""
rom_thing._stream_resolution = [800, 600]
min_offset = 800 * stage_measure.SMALL_STEP / 100 * stage_measure.DETECT_MOTION_TOL
def gen_offsets(*_args, **_kwargs):
"""Generate offset dictionaries with small moves unless count matches ``good_moves``."""
i = 0
while True:
x = min_offset * 1.2 if i in good_moves else 0.1
yield {"x": x, "y": 0}
i += 1
mock_offset_from = mocker.patch.object(
rom_thing, "_offset_from", side_effect=gen_offsets()
)
still_moves = rom_thing._stage_still_moves(
axis="x",
direction=1,
rom_deps=mock_rom_deps,
)
assert still_moves is expected_to_detect_motion
assert mock_offset_from.call_count == offset_calls