diff --git a/api/src/opentrons/hardware_control/dev_types.py b/api/src/opentrons/hardware_control/dev_types.py index 5a4a991c5e8..e6c475b405c 100644 --- a/api/src/opentrons/hardware_control/dev_types.py +++ b/api/src/opentrons/hardware_control/dev_types.py @@ -15,7 +15,11 @@ PipetteName, ChannelCount, ) -from opentrons_shared_data.pipette.pipette_definition import PipetteConfigurations +from opentrons_shared_data.pipette.types import PipetteTipType +from opentrons_shared_data.pipette.pipette_definition import ( + PipetteConfigurations, + SupportedTipsDefinition, +) from opentrons_shared_data.gripper import ( GripperModel, GripperDefinition, @@ -89,6 +93,7 @@ class PipetteDict(InstrumentDict): ready_to_aspirate: bool has_tip: bool default_blow_out_volume: float + supported_tips: Dict[PipetteTipType, SupportedTipsDefinition] class GripperDict(InstrumentDict): diff --git a/api/src/opentrons/hardware_control/instruments/ot2/pipette.py b/api/src/opentrons/hardware_control/instruments/ot2/pipette.py index c861cc82de2..f0f724ded66 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/pipette.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/pipette.py @@ -537,6 +537,7 @@ def as_dict(self) -> "Pipette.DictType": "return_tip_height": self.active_tip_settings.default_return_tip_height, "tip_overlap": self.tip_overlap, "back_compat_names": self._config.pipette_backcompat_names, + "supported_tips": self._config.supported_tips, } ) return self._config_as_dict diff --git a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py index d7fa5f10acb..64615b97880 100644 --- a/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py +++ b/api/src/opentrons/hardware_control/instruments/ot2/pipette_handler.py @@ -218,6 +218,7 @@ def get_attached_instrument(self, mount: MountType) -> PipetteDict: "default_blow_out_flow_rates", "default_dispense_flow_rates", "back_compat_names", + "supported_tips", ] instr_dict = instr.as_dict() diff --git a/api/src/opentrons/hardware_control/instruments/ot3/pipette.py b/api/src/opentrons/hardware_control/instruments/ot3/pipette.py index b468e38cc77..61404361f95 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/pipette.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/pipette.py @@ -532,6 +532,7 @@ def as_dict(self) -> "Pipette.DictType": "return_tip_height": self.active_tip_settings.default_return_tip_height, "tip_overlap": self.tip_overlap, "back_compat_names": self._config.pipette_backcompat_names, + "supported_tips": self._config.supported_tips, } ) return self._config_as_dict diff --git a/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py b/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py index 8c805c0e466..a36fcda9ff2 100644 --- a/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py +++ b/api/src/opentrons/hardware_control/instruments/ot3/pipette_handler.py @@ -229,6 +229,7 @@ def get_attached_instrument(self, mount: OT3Mount) -> PipetteDict: "default_blow_out_flow_rates", "default_dispense_flow_rates", "back_compat_names", + "supported_tips", ] instr_dict = instr.as_dict() diff --git a/api/src/opentrons/protocol_engine/execution/tip_handler.py b/api/src/opentrons/protocol_engine/execution/tip_handler.py index 7ea24d7442b..64215d1f498 100644 --- a/api/src/opentrons/protocol_engine/execution/tip_handler.py +++ b/api/src/opentrons/protocol_engine/execution/tip_handler.py @@ -60,9 +60,7 @@ async def pick_up_tip( hw_mount = self._state_view.pipettes.get_mount(pipette_id).to_hw_mount() nominal_tip_geometry = self._state_view.geometry.get_nominal_tip_geometry( - pipette_id=pipette_id, - labware_id=labware_id, - well_name=well_name, + pipette_id=pipette_id, labware_id=labware_id, well_name=well_name ) actual_tip_length = await self._labware_data_provider.get_calibrated_tip_length( diff --git a/api/src/opentrons/protocol_engine/resources/pipette_data_provider.py b/api/src/opentrons/protocol_engine/resources/pipette_data_provider.py index cf1b3c91ba5..5fc99a7c61a 100644 --- a/api/src/opentrons/protocol_engine/resources/pipette_data_provider.py +++ b/api/src/opentrons/protocol_engine/resources/pipette_data_provider.py @@ -7,6 +7,7 @@ pipette_load_name_conversions as pipette_load_name, load_data as load_pipette_data, types as pip_types, + pipette_definition, ) from opentrons.hardware_control.dev_types import PipetteDict @@ -26,7 +27,9 @@ class LoadedStaticPipetteData: home_position: float nozzle_offset_z: float flow_rates: FlowRates - return_tip_scale: float + tip_configuration_lookup_table: Dict[ + float, pipette_definition.SupportedTipsDefinition + ] nominal_tip_overlap: Dict[str, float] @@ -52,12 +55,14 @@ def get_virtual_pipette_static_config( channels=config.channels, home_position=config.mount_configurations.homePosition, nozzle_offset_z=config.nozzle_offset[2], + tip_configuration_lookup_table={ + k.value: v for k, v in config.supported_tips.items() + }, flow_rates=FlowRates( default_blow_out=tip_configuration.default_blowout_flowrate.values_by_api_level, default_aspirate=tip_configuration.default_aspirate_flowrate.values_by_api_level, default_dispense=tip_configuration.default_dispense_flowrate.values_by_api_level, ), - return_tip_scale=tip_configuration.default_return_tip_height, nominal_tip_overlap=config.tip_overlap_dictionary, ) @@ -75,7 +80,9 @@ def get_pipette_static_config(pipette_dict: PipetteDict) -> LoadedStaticPipetteD default_aspirate=pipette_dict["default_aspirate_flow_rates"], default_dispense=pipette_dict["default_dispense_flow_rates"], ), - return_tip_scale=pipette_dict["return_tip_height"], + tip_configuration_lookup_table={ + k.value: v for k, v in pipette_dict["supported_tips"].items() + }, nominal_tip_overlap=pipette_dict["tip_overlap"], # TODO(mc, 2023-02-28): these two values are not present in PipetteDict # https://opentrons.atlassian.net/browse/RCORE-655 diff --git a/api/src/opentrons/protocol_engine/state/pipettes.py b/api/src/opentrons/protocol_engine/state/pipettes.py index 4a1dd19b86a..c3093fc0855 100644 --- a/api/src/opentrons/protocol_engine/state/pipettes.py +++ b/api/src/opentrons/protocol_engine/state/pipettes.py @@ -3,6 +3,7 @@ from dataclasses import dataclass from typing import Dict, List, Mapping, Optional, Tuple +from opentrons_shared_data.pipette import pipette_definition from opentrons.config.defaults_ot2 import Z_RETRACT_DISTANCE from opentrons.hardware_control.dev_types import PipetteDict from opentrons.types import MountType, Mount as HwMount @@ -71,7 +72,9 @@ class StaticPipetteConfig: min_volume: float max_volume: float channels: int - return_tip_scale: float + tip_configuration_lookup_table: Dict[ + float, pipette_definition.SupportedTipsDefinition + ] nominal_tip_overlap: Dict[str, float] home_position: float nozzle_offset_z: float @@ -124,7 +127,7 @@ def handle_action(self, action: Action) -> None: min_volume=config.min_volume, max_volume=config.max_volume, channels=config.channels, - return_tip_scale=config.return_tip_scale, + tip_configuration_lookup_table=config.tip_configuration_lookup_table, nominal_tip_overlap=config.nominal_tip_overlap, home_position=config.home_position, nozzle_offset_z=config.nozzle_offset_z, @@ -171,11 +174,32 @@ def _handle_command(self, command: Command) -> None: self._state.attached_tip_by_id[pipette_id] = attached_tip self._state.aspirated_volume_by_id[pipette_id] = 0 + static_config = self._state.static_config_by_id.get(pipette_id) + if static_config: + tip_configuration = static_config.tip_configuration_lookup_table[ + attached_tip.volume + ] + self._state.flow_rates_by_id[pipette_id] = FlowRates( + default_blow_out=tip_configuration.default_blowout_flowrate.values_by_api_level, + default_aspirate=tip_configuration.default_aspirate_flowrate.values_by_api_level, + default_dispense=tip_configuration.default_dispense_flowrate.values_by_api_level, + ) + elif isinstance(command.result, (DropTipResult, DropTipInPlaceResult)): pipette_id = command.params.pipetteId self._state.aspirated_volume_by_id[pipette_id] = None self._state.attached_tip_by_id[pipette_id] = None + static_config = self._state.static_config_by_id.get(pipette_id) + if static_config: + tip_configuration = static_config.tip_configuration_lookup_table[ + static_config.max_volume + ] + self._state.flow_rates_by_id[pipette_id] = FlowRates( + default_blow_out=tip_configuration.default_blowout_flowrate.values_by_api_level, + default_aspirate=tip_configuration.default_aspirate_flowrate.values_by_api_level, + default_dispense=tip_configuration.default_dispense_flowrate.values_by_api_level, + ) elif isinstance(command.result, BlowOutResult): pipette_id = command.params.pipetteId self._state.aspirated_volume_by_id[pipette_id] = None @@ -504,7 +528,20 @@ def get_instrument_max_height_ot2(self, pipette_id: str) -> float: def get_return_tip_scale(self, pipette_id: str) -> float: """Return the given pipette's return tip height scale.""" - return self.get_config(pipette_id).return_tip_scale + max_volume = self.get_maximum_volume(pipette_id) + working_volume = max_volume + if self.get_attached_tip(pipette_id): + working_volume = self.get_working_volume(pipette_id) + + if working_volume in self.get_config(pipette_id).tip_configuration_lookup_table: + tip_lookup = self.get_config(pipette_id).tip_configuration_lookup_table[ + working_volume + ] + else: + tip_lookup = self.get_config(pipette_id).tip_configuration_lookup_table[ + working_volume + ] + return tip_lookup.default_return_tip_height def get_flow_rates(self, pipette_id: str) -> FlowRates: """Get the default flow rates for the pipette.""" diff --git a/api/tests/opentrons/protocol_engine/conftest.py b/api/tests/opentrons/protocol_engine/conftest.py index 1065ed5c2d9..cd7d57cb1b8 100644 --- a/api/tests/opentrons/protocol_engine/conftest.py +++ b/api/tests/opentrons/protocol_engine/conftest.py @@ -9,6 +9,7 @@ from opentrons_shared_data.deck import load as load_deck from opentrons_shared_data.deck.dev_types import DeckDefinitionV3 from opentrons_shared_data.labware import load_definition +from opentrons_shared_data.pipette import pipette_definition from opentrons.protocols.models import LabwareDefinition from opentrons.protocols.api_support.deck_type import ( STANDARD_OT2_DECK, @@ -187,3 +188,24 @@ def mag_block_v1_def() -> ModuleDefinition: """Get the definition of a V1 Mag Block.""" definition = load_shared_data("module/definitions/3/magneticBlockV1.json") return ModuleDefinition.parse_raw(definition) + + +@pytest.fixture(scope="session") +def supported_tip_fixture() -> pipette_definition.SupportedTipsDefinition: + """Get a mock supported tip definition.""" + return pipette_definition.SupportedTipsDefinition( + defaultAspirateFlowRate=pipette_definition.FlowRateDefinition( + default=10, valuesByApiLevel={} + ), + defaultDispenseFlowRate=pipette_definition.FlowRateDefinition( + default=10, valuesByApiLevel={} + ), + defaultBlowOutFlowRate=pipette_definition.FlowRateDefinition( + default=10, valuesByApiLevel={} + ), + defaultTipLength=40, + defaultReturnTipHeight=0.5, + aspirate=pipette_definition.ulPerMMDefinition(default={"1": [(0, 0, 0)]}), + dispense=pipette_definition.ulPerMMDefinition(default={"1": [(0, 0, 0)]}), + defaultBlowoutVolume=5, + ) diff --git a/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py b/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py index 45444e037b9..836108ca8ef 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py +++ b/api/tests/opentrons/protocol_engine/execution/test_equipment_handler.py @@ -6,6 +6,7 @@ from typing import Any, Optional, cast from opentrons_shared_data.pipette.dev_types import PipetteNameType +from opentrons_shared_data.pipette import pipette_definition from opentrons_shared_data.labware.dev_types import LabwareUri from opentrons.calibration_storage.helpers import uri_from_details @@ -126,7 +127,9 @@ async def temp_module_v2(decoy: Decoy) -> TempDeck: @pytest.fixture -def loaded_static_pipette_data() -> LoadedStaticPipetteData: +def loaded_static_pipette_data( + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> LoadedStaticPipetteData: """Get a pipette config data value object.""" return LoadedStaticPipetteData( model="pipette_model", @@ -139,7 +142,7 @@ def loaded_static_pipette_data() -> LoadedStaticPipetteData: default_aspirate={"b": 4.56}, default_dispense={"c": 7.89}, ), - return_tip_scale=0.5, + tip_configuration_lookup_table={4.56: supported_tip_fixture}, nominal_tip_overlap={"default": 9.87}, home_position=10.11, nozzle_offset_z=12.13, diff --git a/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py b/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py index 10faba4655e..280bdbcc321 100644 --- a/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py +++ b/api/tests/opentrons/protocol_engine/resources/test_pipette_data_provider.py @@ -1,5 +1,6 @@ """Test pipette data provider.""" from opentrons_shared_data.pipette.dev_types import PipetteNameType, PipetteModel +from opentrons_shared_data.pipette import pipette_definition, types as pip_types from opentrons.hardware_control.dev_types import PipetteDict from opentrons.protocol_engine.types import FlowRates @@ -29,7 +30,7 @@ def test_get_virtual_pipette_static_config() -> None: default_dispense={"2.0": 3.78, "2.6": 7.56}, default_blow_out={"2.0": 3.78, "2.6": 7.56}, ), - return_tip_scale=0.5, + tip_configuration_lookup_table=result.tip_configuration_lookup_table, nominal_tip_overlap={ "default": 8.25, "opentrons/eppendorf_96_tiprack_10ul_eptips/1": 8.4, @@ -42,7 +43,9 @@ def test_get_virtual_pipette_static_config() -> None: ) -def test_get_pipette_static_config() -> None: +def test_get_pipette_static_config( + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> None: """It should return config data given a PipetteDict.""" pipette_dict: PipetteDict = { "name": "p300_single_gen2", @@ -78,6 +81,7 @@ def test_get_pipette_static_config() -> None: "default_dispense_speeds": {"2.0": 5.021202, "2.6": 10.042404}, "default_aspirate_speeds": {"2.0": 5.021202, "2.6": 10.042404}, "default_blow_out_volume": 10, + "supported_tips": {pip_types.PipetteTipType.t300: supported_tip_fixture}, } result = subject.get_pipette_static_config(pipette_dict) @@ -93,7 +97,7 @@ def test_get_pipette_static_config() -> None: default_dispense={"2.0": 46.43, "2.3": 92.86}, default_blow_out={"2.0": 46.43, "2.2": 92.86}, ), - return_tip_scale=0.5, + tip_configuration_lookup_table={300: supported_tip_fixture}, nominal_tip_overlap={ "default": 8.2, "opentrons/opentrons_96_tiprack_300ul/1": 8.2, diff --git a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py index 1f50c5c89f4..037ec8e9855 100644 --- a/api/tests/opentrons/protocol_engine/state/test_geometry_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_geometry_view.py @@ -7,6 +7,7 @@ from opentrons_shared_data.deck.dev_types import DeckDefinitionV3 from opentrons_shared_data.labware.dev_types import LabwareUri +from opentrons_shared_data.pipette import pipette_definition from opentrons.calibration_storage.helpers import uri_from_details from opentrons.protocols.models import LabwareDefinition from opentrons.types import Point, DeckSlotName, MountType @@ -1354,6 +1355,7 @@ def test_get_next_drop_tip_location( pipette_channels: int, pipette_mount: MountType, expected_locations: List[DropTipWellLocation], + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should provide the next location to drop tips into within a labware.""" decoy.when(labware_view.is_fixed_trash(labware_id="abc")).then_return(True) @@ -1368,7 +1370,7 @@ def test_get_next_drop_tip_location( model="blah", display_name="bleh", serial_number="", - return_tip_scale=0, + tip_configuration_lookup_table={9001: supported_tip_fixture}, nominal_tip_overlap={}, home_position=0, nozzle_offset_z=0, diff --git a/api/tests/opentrons/protocol_engine/state/test_pipette_store.py b/api/tests/opentrons/protocol_engine/state/test_pipette_store.py index 1b9cfac207d..a8b3bc17d18 100644 --- a/api/tests/opentrons/protocol_engine/state/test_pipette_store.py +++ b/api/tests/opentrons/protocol_engine/state/test_pipette_store.py @@ -4,6 +4,7 @@ from typing import Optional from opentrons_shared_data.pipette.dev_types import PipetteNameType +from opentrons_shared_data.pipette import pipette_definition from opentrons.types import DeckSlotName, MountType from opentrons.protocol_engine import commands as cmd @@ -589,7 +590,10 @@ def test_set_movement_speed(subject: PipetteStore) -> None: assert subject.state.movement_speed_by_id[pipette_id] == 123.456 -def test_add_pipette_config(subject: PipetteStore) -> None: +def test_add_pipette_config( + subject: PipetteStore, + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> None: """It should issue an action to add a pipette config.""" subject.handle_action( AddPipetteConfigAction( @@ -606,7 +610,7 @@ def test_add_pipette_config(subject: PipetteStore) -> None: default_dispense={"b": 2}, default_blow_out={"c": 3}, ), - return_tip_scale=4, + tip_configuration_lookup_table={4: supported_tip_fixture}, nominal_tip_overlap={"default": 5}, home_position=8.9, nozzle_offset_z=10.11, @@ -621,7 +625,7 @@ def test_add_pipette_config(subject: PipetteStore) -> None: min_volume=1.23, max_volume=4.56, channels=7, - return_tip_scale=4, + tip_configuration_lookup_table={4: supported_tip_fixture}, nominal_tip_overlap={"default": 5}, home_position=8.9, nozzle_offset_z=10.11, diff --git a/api/tests/opentrons/protocol_engine/state/test_pipette_view.py b/api/tests/opentrons/protocol_engine/state/test_pipette_view.py index 6ae2b896095..b76ba20303f 100644 --- a/api/tests/opentrons/protocol_engine/state/test_pipette_view.py +++ b/api/tests/opentrons/protocol_engine/state/test_pipette_view.py @@ -3,6 +3,7 @@ from typing import cast, Dict, List, Optional from opentrons_shared_data.pipette.dev_types import PipetteNameType +from opentrons_shared_data.pipette import pipette_definition from opentrons.config.defaults_ot2 import Z_RETRACT_DISTANCE from opentrons.types import MountType, Mount as HwMount @@ -227,7 +228,9 @@ def test_get_aspirated_volume() -> None: subject.get_aspirated_volume("pipette-id-no-tip") -def test_get_pipette_working_volume() -> None: +def test_get_pipette_working_volume( + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> None: """It should get the minimum value of tip volume and max volume.""" subject = get_pipette_view( attached_tip_by_id={ @@ -241,7 +244,7 @@ def test_get_pipette_working_volume() -> None: model="blah", display_name="bleh", serial_number="", - return_tip_scale=0, + tip_configuration_lookup_table={9001: supported_tip_fixture}, nominal_tip_overlap={}, home_position=0, nozzle_offset_z=0, @@ -252,7 +255,9 @@ def test_get_pipette_working_volume() -> None: assert subject.get_working_volume("pipette-id") == 1337 -def test_get_pipette_working_volume_raises_if_tip_volume_is_none() -> None: +def test_get_pipette_working_volume_raises_if_tip_volume_is_none( + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> None: """Should raise an exception that no tip is attached.""" subject = get_pipette_view( attached_tip_by_id={ @@ -266,7 +271,7 @@ def test_get_pipette_working_volume_raises_if_tip_volume_is_none() -> None: model="blah", display_name="bleh", serial_number="", - return_tip_scale=0, + tip_configuration_lookup_table={9001: supported_tip_fixture}, nominal_tip_overlap={}, home_position=0, nozzle_offset_z=0, @@ -281,7 +286,9 @@ def test_get_pipette_working_volume_raises_if_tip_volume_is_none() -> None: subject.get_working_volume("wrong-id") -def test_get_pipette_available_volume() -> None: +def test_get_pipette_available_volume( + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> None: """It should get the available volume for a pipette.""" subject = get_pipette_view( attached_tip_by_id={ @@ -300,7 +307,7 @@ def test_get_pipette_available_volume() -> None: model="blah", display_name="bleh", serial_number="", - return_tip_scale=0, + tip_configuration_lookup_table={123: supported_tip_fixture}, nominal_tip_overlap={}, home_position=0, nozzle_offset_z=0, @@ -312,7 +319,7 @@ def test_get_pipette_available_volume() -> None: model="blah", display_name="bleh", serial_number="", - return_tip_scale=0, + tip_configuration_lookup_table={123: supported_tip_fixture}, nominal_tip_overlap={}, home_position=0, nozzle_offset_z=0, @@ -409,7 +416,9 @@ def test_get_deck_point( assert subject.get_deck_point(pipette_id="pipette-id") == DeckPoint(x=1, y=2, z=3) -def test_get_static_config() -> None: +def test_get_static_config( + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> None: """It should return the static pipette configuration that was set for the given pipette.""" config = StaticPipetteConfig( model="pipette-model", @@ -418,13 +427,25 @@ def test_get_static_config() -> None: min_volume=1.23, max_volume=4.56, channels=9, - return_tip_scale=7.89, + tip_configuration_lookup_table={4.56: supported_tip_fixture}, nominal_tip_overlap={}, home_position=10.12, nozzle_offset_z=12.13, ) - subject = get_pipette_view(static_config_by_id={"pipette-id": config}) + subject = get_pipette_view( + pipettes_by_id={ + "pipette-id": LoadedPipette( + id="pipette-id", + mount=MountType.LEFT, + pipetteName=PipetteNameType.P300_SINGLE, + ) + }, + attached_tip_by_id={ + "pipette-id": TipGeometry(length=1, volume=4.56, diameter=3), + }, + static_config_by_id={"pipette-id": config}, + ) assert subject.get_config("pipette-id") == config assert subject.get_model_name("pipette-id") == "pipette-model" @@ -432,14 +453,16 @@ def test_get_static_config() -> None: assert subject.get_serial_number("pipette-id") == "serial-number" assert subject.get_minimum_volume("pipette-id") == 1.23 assert subject.get_maximum_volume("pipette-id") == 4.56 - assert subject.get_return_tip_scale("pipette-id") == 7.89 + assert subject.get_return_tip_scale("pipette-id") == 0.5 assert ( subject.get_instrument_max_height_ot2("pipette-id") == 22.25 - Z_RETRACT_DISTANCE ) -def test_get_nominal_tip_overlap() -> None: +def test_get_nominal_tip_overlap( + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, +) -> None: """It should return the static pipette configuration that was set for the given pipette.""" config = StaticPipetteConfig( model="", @@ -448,7 +471,7 @@ def test_get_nominal_tip_overlap() -> None: min_volume=0, max_volume=0, channels=10, - return_tip_scale=0, + tip_configuration_lookup_table={0: supported_tip_fixture}, nominal_tip_overlap={ "some-uri": 100, "default": 10, diff --git a/api/tests/opentrons/protocol_engine/state/test_tip_state.py b/api/tests/opentrons/protocol_engine/state/test_tip_state.py index d59a783cd55..33573daff83 100644 --- a/api/tests/opentrons/protocol_engine/state/test_tip_state.py +++ b/api/tests/opentrons/protocol_engine/state/test_tip_state.py @@ -7,6 +7,7 @@ LabwareDefinition, Parameters as LabwareParameters, ) +from opentrons_shared_data.pipette import pipette_definition from opentrons.protocol_engine import actions, commands from opentrons.protocol_engine.state.tips import TipStore, TipView @@ -174,6 +175,7 @@ def test_get_next_tip_skips_picked_up_tip( get_next_tip_tips: int, input_starting_tip: Optional[str], result_well_name: Optional[str], + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should get the next tip in the column if one has been picked up.""" subject.handle_action(actions.UpdateCommandAction(command=load_labware_command)) @@ -192,7 +194,7 @@ def test_get_next_tip_skips_picked_up_tip( default_dispense={}, default_blow_out={}, ), - return_tip_scale=0, + tip_configuration_lookup_table={15: supported_tip_fixture}, nominal_tip_overlap={}, nozzle_offset_z=1.23, home_position=4.56, @@ -230,6 +232,7 @@ def test_reset_tips( subject: TipStore, load_labware_command: commands.LoadLabware, pick_up_tip_command: commands.PickUpTip, + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should be able to reset tip tracking state.""" subject.handle_action(actions.UpdateCommandAction(command=load_labware_command)) @@ -248,7 +251,7 @@ def test_reset_tips( default_dispense={}, default_blow_out={}, ), - return_tip_scale=0, + tip_configuration_lookup_table={15: supported_tip_fixture}, nominal_tip_overlap={}, nozzle_offset_z=1.23, home_position=4.56, @@ -267,7 +270,9 @@ def test_reset_tips( assert result == "A1" -def test_handle_pipette_config_action(subject: TipStore) -> None: +def test_handle_pipette_config_action( + subject: TipStore, supported_tip_fixture: pipette_definition.SupportedTipsDefinition +) -> None: """Should add pipette channel to state.""" subject.handle_action( actions.AddPipetteConfigAction( @@ -284,7 +289,7 @@ def test_handle_pipette_config_action(subject: TipStore) -> None: default_dispense={}, default_blow_out={}, ), - return_tip_scale=0, + tip_configuration_lookup_table={15: supported_tip_fixture}, nominal_tip_overlap={}, nozzle_offset_z=1.23, home_position=4.56, @@ -332,6 +337,7 @@ def test_drop_tip( pick_up_tip_command: commands.PickUpTip, drop_tip_command: commands.DropTip, drop_tip_in_place_command: commands.DropTipInPlace, + supported_tip_fixture: pipette_definition.SupportedTipsDefinition, ) -> None: """It should be clear tip length when a tip is dropped.""" subject.handle_action(actions.UpdateCommandAction(command=load_labware_command)) @@ -350,7 +356,7 @@ def test_drop_tip( default_dispense={}, default_blow_out={}, ), - return_tip_scale=0, + tip_configuration_lookup_table={15: supported_tip_fixture}, nominal_tip_overlap={}, nozzle_offset_z=1.23, home_position=4.56, diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_0.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_0.json index 87fe840de4e..b24e1d5f9d1 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_0.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_0.json @@ -1,6 +1,43 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [12.29687531, -0.0049, 3.134703694], + [50.0, -0.0002, 3.077116024] + ], + "2": [ + [5.5768667, 0.076142366, 2.363797525], + [7.0999333, 0.0338396036, 2.599714392], + [11.5943825, 0.0130432679, 2.747366988], + [17.6461325, 0.007010609879, 2.817311933], + [50, 0.002620115513, 2.894787178] + ] + } + }, + "dispense": { + "default": { + "1": [[50.0, 0.0, 3.06368702]], + "2": [[50, 0, 3.06368702]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25, diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_3.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_3.json index 87fe840de4e..b24e1d5f9d1 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_3.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_3.json @@ -1,6 +1,43 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [12.29687531, -0.0049, 3.134703694], + [50.0, -0.0002, 3.077116024] + ], + "2": [ + [5.5768667, 0.076142366, 2.363797525], + [7.0999333, 0.0338396036, 2.599714392], + [11.5943825, 0.0130432679, 2.747366988], + [17.6461325, 0.007010609879, 2.817311933], + [50, 0.002620115513, 2.894787178] + ] + } + }, + "dispense": { + "default": { + "1": [[50.0, 0.0, 3.06368702]], + "2": [[50, 0, 3.06368702]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25, diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_4.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_4.json index 561eda019d0..5554187f45c 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_4.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_4.json @@ -1,6 +1,43 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [12.29687531, -0.0049, 3.134703694], + [50, -0.0002, 3.077116024] + ], + "2": [ + [5.5768667, 0.076142366, 2.363797525], + [7.0999333, 0.0338396036, 2.599714392], + [11.5943825, 0.0130432679, 2.747366988], + [17.6461325, 0.007010609879, 2.817311933], + [50, 0.002620115513, 2.894787178] + ] + } + }, + "dispense": { + "default": { + "1": [[50.0, 0.0, 3.06368702]], + "2": [[50, 0, 3.06368702]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25, diff --git a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_5.json b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_5.json index 8dec0c063ce..d1037751e6f 100644 --- a/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_5.json +++ b/shared-data/pipette/definitions/2/liquid/eight_channel/p50/1_5.json @@ -1,6 +1,43 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [12.29687531, -0.0049, 3.134703694], + [50, -0.0002, 3.077116024] + ], + "2": [ + [5.5768667, 0.076142366, 2.363797525], + [7.0999333, 0.0338396036, 2.599714392], + [11.5943825, 0.0130432679, 2.747366988], + [17.6461325, 0.007010609879, 2.817311933], + [50, 0.002620115513, 2.894787178] + ] + } + }, + "dispense": { + "default": { + "1": [[50.0, 0.0, 3.06368702]], + "2": [[50, 0, 3.06368702]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25, diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_0.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_0.json index e5c82c6aa13..c40edfdc1fe 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_0.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_0.json @@ -1,6 +1,43 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [11.79687499, -0.0098, 3.064988953], + [50.0, -0.0004, 2.954068131] + ], + "2": [ + [5.538952382, 0.04994568474, 2.492829422], + [7.050333334, 0.0335171238, 2.583826438], + [11.5397619, 0.01443549911, 2.718358253], + [17.55071427, 0.006684226987, 2.807806088], + [50, 0.001789563193, 2.893710933] + ] + } + }, + "dispense": { + "default": { + "1": [[50, 0, 2.931601299]], + "2": [[50, 0, 2.931601299]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25, diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_3.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_3.json index 70a615339a0..0252b304dd5 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_3.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_3.json @@ -1,6 +1,43 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [11.79687499, -0.0098, 3.064988953], + [50.0, -0.0004, 2.954068131] + ], + "2": [ + [5.538952382, 0.04994568474, 2.492829422], + [7.050333334, 0.0335171238, 2.583826438], + [11.5397619, 0.01443549911, 2.718358253], + [17.55071427, 0.006684226987, 2.807806088], + [50, 0.001789563193, 2.893710933] + ] + } + }, + "dispense": { + "default": { + "1": [[50.0, 0.0, 2.931601299]], + "2": [[50, 0, 2.931601299]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25, diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_4.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_4.json index 70a615339a0..0252b304dd5 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_4.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_4.json @@ -1,6 +1,43 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [11.79687499, -0.0098, 3.064988953], + [50.0, -0.0004, 2.954068131] + ], + "2": [ + [5.538952382, 0.04994568474, 2.492829422], + [7.050333334, 0.0335171238, 2.583826438], + [11.5397619, 0.01443549911, 2.718358253], + [17.55071427, 0.006684226987, 2.807806088], + [50, 0.001789563193, 2.893710933] + ] + } + }, + "dispense": { + "default": { + "1": [[50.0, 0.0, 2.931601299]], + "2": [[50, 0, 2.931601299]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25, diff --git a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_5.json b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_5.json index fbbc0bc2398..479aa28b1e5 100644 --- a/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_5.json +++ b/shared-data/pipette/definitions/2/liquid/single_channel/p50/1_5.json @@ -1,6 +1,39 @@ { "$otSharedSchema": "#/pipette/schemas/2/pipetteLiquidPropertiesSchema.json", "supportedTips": { + "t50": { + "defaultAspirateFlowRate": { + "default": 25, + "valuesByApiLevel": { "2.0": 25 } + }, + "defaultDispenseFlowRate": { + "default": 50, + "valuesByApiLevel": { "2.0": 50 } + }, + "defaultBlowOutFlowRate": { + "default": 1000, + "valuesByApiLevel": { "2.0": 1000 } + }, + "defaultTipLength": 51.7, + "aspirate": { + "default": { + "1": [ + [5.762111167, 0.02912395377, 2.7132], + [7.208999967, 0.001758534127, 2.8709], + [10.18300033, 0.008684827443, 2.821], + [35.954444, 0.003367098915, 2.8751], + [42.075889, 0.001505686352, 2.9421], + [50.0, 0.001091358226, 2.9595] + ] + } + }, + "dispense": { + "default": { + "1": [[50.0, 0.0, 2.931601299]] + } + }, + "defaultBlowoutVolume": 4.712 + }, "t200": { "defaultAspirateFlowRate": { "default": 25,