From a84f00bf0036481752f33369604ca0e23ecd0847 Mon Sep 17 00:00:00 2001 From: Laura Cox Date: Wed, 1 Nov 2023 21:40:38 +0200 Subject: [PATCH] fix logic problem when starting nozzle isn't A1 --- api/src/opentrons/hardware_control/api.py | 5 +- .../hardware_control/nozzle_manager.py | 14 +- api/src/opentrons/hardware_control/ot3api.py | 1 + .../protocols/liquid_handler.py | 4 +- .../instruments/test_nozzle_manager.py | 205 +++++++++--------- 5 files changed, 126 insertions(+), 103 deletions(-) diff --git a/api/src/opentrons/hardware_control/api.py b/api/src/opentrons/hardware_control/api.py index 85538e80c47..4630c634f56 100644 --- a/api/src/opentrons/hardware_control/api.py +++ b/api/src/opentrons/hardware_control/api.py @@ -1052,8 +1052,8 @@ async def blow_out( async def update_nozzle_configuration_for_mount( self, mount: top_types.Mount, - back_left_nozzle: Optional[str] = None, - front_right_nozzle: Optional[str] = None, + back_left_nozzle: Optional[str], + front_right_nozzle: Optional[str], starting_nozzle: Optional[str] = None, ) -> None: """ @@ -1076,6 +1076,7 @@ async def update_nozzle_configuration_for_mount( if not back_left_nozzle and not front_right_nozzle and not starting_nozzle: await self.reset_nozzle_configuration(mount) else: + # assert back_left_nozzle and front_right_nozzle await self.update_nozzle_configuration( mount, back_left_nozzle, front_right_nozzle, starting_nozzle ) diff --git a/api/src/opentrons/hardware_control/nozzle_manager.py b/api/src/opentrons/hardware_control/nozzle_manager.py index 42eaae96ac3..781d2c55bc8 100644 --- a/api/src/opentrons/hardware_control/nozzle_manager.py +++ b/api/src/opentrons/hardware_control/nozzle_manager.py @@ -115,6 +115,7 @@ def build( starting_nozzle: str, back_left_nozzle: str, front_right_nozzle: str, + origin_nozzle: Optional[str] = None, ) -> "NozzleMap": difference = ( physical_nozzle_map[front_right_nozzle] @@ -125,11 +126,21 @@ def build( map_store_list = list(physical_nozzle_map.items()) + if origin_nozzle: + origin_difference = ( + physical_nozzle_map[back_left_nozzle] + - physical_nozzle_map[origin_nozzle] + ) + starting_col = int(abs(origin_difference[0] // INTERNOZZLE_SPACING)) + else: + starting_col = 0 map_store = OrderedDict( { k: v for i in range(x_columns_length) - for k, v in map_store_list[i * 8 : y_rows_length * (i + 1)] + for k, v in map_store_list[ + (i + starting_col) * 8 : y_rows_length * ((i + starting_col) + 1) + ] } ) return cls( @@ -267,6 +278,7 @@ def update_nozzle_configuration( starting_nozzle=starting_nozzle or back_left_nozzle, back_left_nozzle=back_left_nozzle, front_right_nozzle=front_right_nozzle, + origin_nozzle=self._physical_nozzle_map.starting_nozzle, ) def get_tip_configuration_current(self) -> float: diff --git a/api/src/opentrons/hardware_control/ot3api.py b/api/src/opentrons/hardware_control/ot3api.py index 45bd5e9d779..efed30f50de 100644 --- a/api/src/opentrons/hardware_control/ot3api.py +++ b/api/src/opentrons/hardware_control/ot3api.py @@ -2291,6 +2291,7 @@ async def update_nozzle_configuration_for_mount( OT3Mount.from_mount(mount) ) else: + assert back_left_nozzle and front_right_nozzle await self._pipette_handler.update_nozzle_configuration( OT3Mount.from_mount(mount), back_left_nozzle, diff --git a/api/src/opentrons/hardware_control/protocols/liquid_handler.py b/api/src/opentrons/hardware_control/protocols/liquid_handler.py index a8eebe496bd..e46cea2fdc2 100644 --- a/api/src/opentrons/hardware_control/protocols/liquid_handler.py +++ b/api/src/opentrons/hardware_control/protocols/liquid_handler.py @@ -19,8 +19,8 @@ class LiquidHandler( async def update_nozzle_configuration_for_mount( self, mount: Mount, - back_left_nozzle: Optional[str] = None, - front_right_nozzle: Optional[str] = None, + back_left_nozzle: Optional[str], + front_right_nozzle: Optional[str], starting_nozzle: Optional[str] = None, ) -> None: """ diff --git a/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py b/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py index 77ae709bc8e..1761e59a6ec 100644 --- a/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py +++ b/api/tests/opentrons/hardware_control/instruments/test_nozzle_manager.py @@ -16,6 +16,106 @@ def build_nozzle_manger( ) +NINETY_SIX_CHANNEL_MAP = { + "A1": [-36.0, -25.5, -259.15], + "A2": [-27.0, -25.5, -259.15], + "A3": [-18.0, -25.5, -259.15], + "A4": [-9.0, -25.5, -259.15], + "A5": [0.0, -25.5, -259.15], + "A6": [9.0, -25.5, -259.15], + "A7": [18.0, -25.5, -259.15], + "A8": [27.0, -25.5, -259.15], + "A9": [36.0, -25.5, -259.15], + "A10": [45.0, -25.5, -259.15], + "A11": [54.0, -25.5, -259.15], + "A12": [63.0, -25.5, -259.15], + "B1": [-36.0, -34.5, -259.15], + "B2": [-27.0, -34.5, -259.15], + "B3": [-18.0, -34.5, -259.15], + "B4": [-9.0, -34.5, -259.15], + "B5": [0.0, -34.5, -259.15], + "B6": [9.0, -34.5, -259.15], + "B7": [18.0, -34.5, -259.15], + "B8": [27.0, -34.5, -259.15], + "B9": [36.0, -34.5, -259.15], + "B10": [45.0, -34.5, -259.15], + "B11": [54.0, -34.5, -259.15], + "B12": [63.0, -34.5, -259.15], + "C1": [-36.0, -43.5, -259.15], + "C2": [-27.0, -43.5, -259.15], + "C3": [-18.0, -43.5, -259.15], + "C4": [-9.0, -43.5, -259.15], + "C5": [0.0, -43.5, -259.15], + "C6": [9.0, -43.5, -259.15], + "C7": [18.0, -43.5, -259.15], + "C8": [27.0, -43.5, -259.15], + "C9": [36.0, -43.5, -259.15], + "C10": [45.0, -43.5, -259.15], + "C11": [54.0, -43.5, -259.15], + "C12": [63.0, -43.5, -259.15], + "D1": [-36.0, -52.5, -259.15], + "D2": [-27.0, -52.5, -259.15], + "D3": [-18.0, -52.5, -259.15], + "D4": [-9.0, -52.5, -259.15], + "D5": [0.0, -52.5, -259.15], + "D6": [9.0, -52.5, -259.15], + "D7": [18.0, -52.5, -259.15], + "D8": [27.0, -52.5, -259.15], + "D9": [36.0, -52.5, -259.15], + "D10": [45.0, -52.5, -259.15], + "D11": [54.0, -52.5, -259.15], + "D12": [63.0, -52.5, -259.15], + "E1": [-36.0, -61.5, -259.15], + "E2": [-27.0, -61.5, -259.15], + "E3": [-18.0, -61.5, -259.15], + "E4": [-9.0, -61.5, -259.15], + "E5": [0.0, -61.5, -259.15], + "E6": [9.0, -61.5, -259.15], + "E7": [18.0, -61.5, -259.15], + "E8": [27.0, -61.5, -259.15], + "E9": [36.0, -61.5, -259.15], + "E10": [45.0, -61.5, -259.15], + "E11": [54.0, -61.5, -259.15], + "E12": [63.0, -61.5, -259.15], + "F1": [-36.0, -70.5, -259.15], + "F2": [-27.0, -70.5, -259.15], + "F3": [-18.0, -70.5, -259.15], + "F4": [-9.0, -70.5, -259.15], + "F5": [0.0, -70.5, -259.15], + "F6": [9.0, -70.5, -259.15], + "F7": [18.0, -70.5, -259.15], + "F8": [27.0, -70.5, -259.15], + "F9": [36.0, -70.5, -259.15], + "F10": [45.0, -70.5, -259.15], + "F11": [54.0, -70.5, -259.15], + "F12": [63.0, -70.5, -259.15], + "G1": [-36.0, -79.5, -259.15], + "G2": [-27.0, -79.5, -259.15], + "G3": [-18.0, -79.5, -259.15], + "G4": [-9.0, -79.5, -259.15], + "G5": [0.0, -79.5, -259.15], + "G6": [9.0, -79.5, -259.15], + "G7": [18.0, -79.5, -259.15], + "G8": [27.0, -79.5, -259.15], + "G9": [36.0, -79.5, -259.15], + "G10": [45.0, -79.5, -259.15], + "G11": [54.0, -79.5, -259.15], + "G12": [63.0, -79.5, -259.15], + "H1": [-36.0, -88.5, -259.15], + "H2": [-27.0, -88.5, -259.15], + "H3": [-18.0, -88.5, -259.15], + "H4": [-9.0, -88.5, -259.15], + "H5": [0.0, -88.5, -259.15], + "H6": [9.0, -88.5, -259.15], + "H7": [18.0, -88.5, -259.15], + "H8": [27.0, -88.5, -259.15], + "H9": [36.0, -88.5, -259.15], + "H10": [45.0, -88.5, -259.15], + "H11": [54.0, -88.5, -259.15], + "H12": [63.0, -88.5, -259.15], +} + + @pytest.mark.parametrize( argnames=["nozzle_map", "critical_point_configuration", "expected"], argvalues=[ @@ -34,104 +134,7 @@ def build_nozzle_manger( Point(-8.0, -47.5, -259.15), ], [ - { - "A1": [-36.0, -25.5, -259.15], - "A2": [-27.0, -25.5, -259.15], - "A3": [-18.0, -25.5, -259.15], - "A4": [-9.0, -25.5, -259.15], - "A5": [0.0, -25.5, -259.15], - "A6": [9.0, -25.5, -259.15], - "A7": [18.0, -25.5, -259.15], - "A8": [27.0, -25.5, -259.15], - "A9": [36.0, -25.5, -259.15], - "A10": [45.0, -25.5, -259.15], - "A11": [54.0, -25.5, -259.15], - "A12": [63.0, -25.5, -259.15], - "B1": [-36.0, -34.5, -259.15], - "B2": [-27.0, -34.5, -259.15], - "B3": [-18.0, -34.5, -259.15], - "B4": [-9.0, -34.5, -259.15], - "B5": [0.0, -34.5, -259.15], - "B6": [9.0, -34.5, -259.15], - "B7": [18.0, -34.5, -259.15], - "B8": [27.0, -34.5, -259.15], - "B9": [36.0, -34.5, -259.15], - "B10": [45.0, -34.5, -259.15], - "B11": [54.0, -34.5, -259.15], - "B12": [63.0, -34.5, -259.15], - "C1": [-36.0, -43.5, -259.15], - "C2": [-27.0, -43.5, -259.15], - "C3": [-18.0, -43.5, -259.15], - "C4": [-9.0, -43.5, -259.15], - "C5": [0.0, -43.5, -259.15], - "C6": [9.0, -43.5, -259.15], - "C7": [18.0, -43.5, -259.15], - "C8": [27.0, -43.5, -259.15], - "C9": [36.0, -43.5, -259.15], - "C10": [45.0, -43.5, -259.15], - "C11": [54.0, -43.5, -259.15], - "C12": [63.0, -43.5, -259.15], - "D1": [-36.0, -52.5, -259.15], - "D2": [-27.0, -52.5, -259.15], - "D3": [-18.0, -52.5, -259.15], - "D4": [-9.0, -52.5, -259.15], - "D5": [0.0, -52.5, -259.15], - "D6": [9.0, -52.5, -259.15], - "D7": [18.0, -52.5, -259.15], - "D8": [27.0, -52.5, -259.15], - "D9": [36.0, -52.5, -259.15], - "D10": [45.0, -52.5, -259.15], - "D11": [54.0, -52.5, -259.15], - "D12": [63.0, -52.5, -259.15], - "E1": [-36.0, -61.5, -259.15], - "E2": [-27.0, -61.5, -259.15], - "E3": [-18.0, -61.5, -259.15], - "E4": [-9.0, -61.5, -259.15], - "E5": [0.0, -61.5, -259.15], - "E6": [9.0, -61.5, -259.15], - "E7": [18.0, -61.5, -259.15], - "E8": [27.0, -61.5, -259.15], - "E9": [36.0, -61.5, -259.15], - "E10": [45.0, -61.5, -259.15], - "E11": [54.0, -61.5, -259.15], - "E12": [63.0, -61.5, -259.15], - "F1": [-36.0, -70.5, -259.15], - "F2": [-27.0, -70.5, -259.15], - "F3": [-18.0, -70.5, -259.15], - "F4": [-9.0, -70.5, -259.15], - "F5": [0.0, -70.5, -259.15], - "F6": [9.0, -70.5, -259.15], - "F7": [18.0, -70.5, -259.15], - "F8": [27.0, -70.5, -259.15], - "F9": [36.0, -70.5, -259.15], - "F10": [45.0, -70.5, -259.15], - "F11": [54.0, -70.5, -259.15], - "F12": [63.0, -70.5, -259.15], - "G1": [-36.0, -79.5, -259.15], - "G2": [-27.0, -79.5, -259.15], - "G3": [-18.0, -79.5, -259.15], - "G4": [-9.0, -79.5, -259.15], - "G5": [0.0, -79.5, -259.15], - "G6": [9.0, -79.5, -259.15], - "G7": [18.0, -79.5, -259.15], - "G8": [27.0, -79.5, -259.15], - "G9": [36.0, -79.5, -259.15], - "G10": [45.0, -79.5, -259.15], - "G11": [54.0, -79.5, -259.15], - "G12": [63.0, -79.5, -259.15], - "H1": [-36.0, -88.5, -259.15], - "H2": [-27.0, -88.5, -259.15], - "H3": [-18.0, -88.5, -259.15], - "H4": [-9.0, -88.5, -259.15], - "H5": [0.0, -88.5, -259.15], - "H6": [9.0, -88.5, -259.15], - "H7": [18.0, -88.5, -259.15], - "H8": [27.0, -88.5, -259.15], - "H9": [36.0, -88.5, -259.15], - "H10": [45.0, -88.5, -259.15], - "H11": [54.0, -88.5, -259.15], - "H12": [63.0, -88.5, -259.15], - }, + NINETY_SIX_CHANNEL_MAP, CriticalPoint.XY_CENTER, Point(13.5, -57.0, -259.15), ], @@ -176,6 +179,12 @@ def test_update_nozzles_with_critical_points( pytest.raises(nozzle_manager.IncompatibleNozzleConfiguration), Point(1, 1, 1), ], + [ + NINETY_SIX_CHANNEL_MAP, + ("A12", "H12"), + does_not_raise(), + Point(x=63.0, y=-25.5, z=-259.15), + ], ], ) def test_update_nozzle_configuration(