diff --git a/api/src/opentrons/protocols/api_support/instrument.py b/api/src/opentrons/protocols/api_support/instrument.py index 0137b43a4c8..3299b8512f9 100644 --- a/api/src/opentrons/protocols/api_support/instrument.py +++ b/api/src/opentrons/protocols/api_support/instrument.py @@ -73,7 +73,7 @@ def tip_length_for( VALID_PIP_TIPRACK_VOL = { - "FLEX": {"p50": [50], "p1000": [50, 200, 1000]}, + "FLEX": {"p50": [50], "p200": [50, 200], "p1000": [50, 200, 1000]}, "OT2": { "p10": [10, 20], "p20": [10, 20], diff --git a/hardware-testing/Makefile b/hardware-testing/Makefile index 1249243415e..8119a69b965 100755 --- a/hardware-testing/Makefile +++ b/hardware-testing/Makefile @@ -99,6 +99,7 @@ test-photometric-multi: test-photometric: $(python) -m hardware_testing.gravimetric --photometric --simulate --pipette 1000 --channels 96 --tip 50 --trials 1 $(python) -m hardware_testing.gravimetric --photometric --simulate --pipette 1000 --channels 96 --tip 200 --trials 1 + $(python) -m hardware_testing.gravimetric --photometric --simulate --pipette 200 --channels 96 --tip 50 --trials 1 .PHONY: test-gravimetric-single test-gravimetric-single: @@ -121,6 +122,7 @@ test-gravimetric-multi: .PHONY: test-gravimetric-96 test-gravimetric-96: $(python) -m hardware_testing.gravimetric --simulate --pipette 1000 --channels 96 --trials 2 --no-blank + $(python) -m hardware_testing.gravimetric --simulate --pipette 200 --channels 96 --trials 2 --no-blank .PHONY: test-gravimetric test-gravimetric: diff --git a/hardware-testing/hardware_testing/gravimetric/__main__.py b/hardware-testing/hardware_testing/gravimetric/__main__.py index 4b08596ebf5..f297f0e7e3a 100644 --- a/hardware-testing/hardware_testing/gravimetric/__main__.py +++ b/hardware-testing/hardware_testing/gravimetric/__main__.py @@ -12,6 +12,7 @@ from hardware_testing.data import create_run_id_and_start_time, ui, get_git_description from hardware_testing.protocols.gravimetric_lpc.gravimetric import ( gravimetric_ot3_p1000_96, + gravimetric_ot3_p200_96, gravimetric_ot3_p1000_multi, gravimetric_ot3_p1000_single, gravimetric_ot3_p50_single, @@ -26,6 +27,7 @@ photometric_ot3_p1000_single, photometric_ot3_p50_multi, photometric_ot3_p1000_96, + photometric_ot3_p200_96, photometric_ot3_p50_single, ) @@ -56,6 +58,9 @@ 1: gravimetric_ot3_p50_single, 8: gravimetric_ot3_p50_multi, }, + 200: { + 96: gravimetric_ot3_p200_96, + }, 1000: { 1: gravimetric_ot3_p1000_single, 8: gravimetric_ot3_p1000_multi, @@ -68,6 +73,12 @@ 1: {50: gravimetric_ot3_p50_single}, 8: {50: gravimetric_ot3_p50_multi_50ul_tip_increment}, }, + 200: { + 96: { + 50: gravimetric_ot3_p200_96, + 200: gravimetric_ot3_p200_96, + }, + }, 1000: { 1: { 50: gravimetric_ot3_p1000_single, @@ -92,6 +103,9 @@ 1: "p50_single_flex", 8: "p50_multi_flex", }, + 200: { + 96: "p200_96_flex", + }, 1000: { 1: "p1000_single_flex", 8: "p1000_multi_flex", @@ -109,6 +123,9 @@ 50: photometric_ot3_p50_multi, }, }, + 200: { + 96: {50: photometric_ot3_p200_96, 200: photometric_ot3_p200_96}, + }, 1000: { 1: { 50: photometric_ot3_p1000_single, @@ -553,7 +570,7 @@ def _main( if __name__ == "__main__": parser = argparse.ArgumentParser("Pipette Testing") parser.add_argument("--simulate", action="store_true") - parser.add_argument("--pipette", type=int, choices=[50, 1000], required=True) + parser.add_argument("--pipette", type=int, choices=[50, 200, 1000], required=True) parser.add_argument("--channels", type=int, choices=[1, 8, 96], default=1) parser.add_argument("--tip", type=int, choices=[0, 50, 200, 1000], default=0) parser.add_argument("--trials", type=int, default=0) diff --git a/hardware-testing/hardware_testing/gravimetric/config.py b/hardware-testing/hardware_testing/gravimetric/config.py index 304087748d1..968de3ecca7 100644 --- a/hardware-testing/hardware_testing/gravimetric/config.py +++ b/hardware-testing/hardware_testing/gravimetric/config.py @@ -102,6 +102,20 @@ class PhotometricConfig(VolumetricConfig): }, }, }, + 200: { + 96: { + 50: { + "mount_speed": 5, + "plunger_speed": 20, + "sensor_threshold_pascals": 15, + }, + 200: { + "mount_speed": 5, + "plunger_speed": 20, + "sensor_threshold_pascals": 15, + }, + } + }, 1000: { 1: { 50: { @@ -199,6 +213,10 @@ def _get_liquid_probe_settings( ], }, 96: { + 200: [ + (50, [1.0, 50.0]), # T50 + (200, [200.0]), # T200 + ], 1000: [ # P1000 (50, [5.0]), # T50 (200, [200.0]), # T200 @@ -260,6 +278,10 @@ def _get_liquid_probe_settings( ], }, 96: { + 200: [ + (50, [1.0, 5.0]), # T50 + (200, [200.0]), # T200 + ], 1000: [ # P1000 (50, [5.0]), # T50 (200, [200.0]), # T200 @@ -340,6 +362,21 @@ def _get_liquid_probe_settings( }, }, 96: { + 200: { + 50: { # T50 + 1.0: (2.5, 2.0), + 2.0: (2.5, 2.0), + 3.0: (2.5, 2.0), + 5.0: (2.5, 2.0), + 10.0: (3.1, 1.7), + 50.0: (1.5, 0.75), + }, + 200: { # T200 + 5.0: (2.5, 4.0), + 50.0: (1.5, 2.0), + 200.0: (1.4, 0.9), + }, + }, 1000: { # P1000 50: { # T50 1.0: (2.5, 2.0), diff --git a/hardware-testing/hardware_testing/gravimetric/increments.py b/hardware-testing/hardware_testing/gravimetric/increments.py index bbe79d0785f..76c90a45b44 100644 --- a/hardware-testing/hardware_testing/gravimetric/increments.py +++ b/hardware-testing/hardware_testing/gravimetric/increments.py @@ -266,6 +266,62 @@ }, }, 96: { + 200: { + 50: { + "default": [ + 2.000, + 3.000, + 4.000, + 5.000, + 6.000, + 7.000, + 8.000, + 9.000, + 10.000, + 15.000, + 25.000, + 40.000, + 60.000, + ], + "lowVolumeDefault": [ + 1.100, + 1.200, + 1.370, + 1.700, + 2.040, + 2.660, + 3.470, + 3.960, + 4.350, + 4.800, + 5.160, + 5.890, + 6.730, + 8.200, + 10.020, + 11.100, + 14.910, + 28.940, + 48.27, + ], + }, + 200: { + "default": [ + 2.000, + 3.000, + 4.000, + 5.000, + 6.000, + 7.000, + 8.000, + 9.000, + 10.000, + 50.000, + 100.000, + 220.000, + ], + }, + }, 1000: { # FIXME: need to update based on DVT data 50: { "default": [ @@ -322,7 +378,7 @@ 1075.00, ], }, - } + }, }, } diff --git a/hardware-testing/hardware_testing/gravimetric/liquid_class/defaults.py b/hardware-testing/hardware_testing/gravimetric/liquid_class/defaults.py index a37f21b1b36..c7021e60585 100644 --- a/hardware-testing/hardware_testing/gravimetric/liquid_class/defaults.py +++ b/hardware-testing/hardware_testing/gravimetric/liquid_class/defaults.py @@ -357,6 +357,66 @@ ), }, }, + 200: { # P200 + 50: { # T50 + 5: DispenseSettings( # 5uL + z_submerge_depth=_default_submerge_dispense_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_dispense_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + blow_out_submerged=5, + ), + 10: DispenseSettings( # 10uL + z_submerge_depth=_default_submerge_dispense_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_dispense_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + blow_out_submerged=5, + ), + 50: DispenseSettings( # 50uL + z_submerge_depth=_default_submerge_dispense_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_dispense_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + blow_out_submerged=5, + ), + }, + 200: { # T200 + 5: DispenseSettings( # 5uL + z_submerge_depth=_default_submerge_dispense_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_dispense_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + blow_out_submerged=5, + ), + 50: DispenseSettings( # 50uL + z_submerge_depth=_default_submerge_dispense_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_dispense_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + blow_out_submerged=5, + ), + 200: DispenseSettings( # 200uL + z_submerge_depth=_default_submerge_dispense_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_dispense_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + blow_out_submerged=5, + ), + }, + }, }, } @@ -728,6 +788,72 @@ ), }, }, + 200: { # P200 + 50: { # T50 + 5: AspirateSettings( # 5uL + z_submerge_depth=_default_submerge_aspirate_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=6.5, # ul/sec + delay=_default_aspirate_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + leading_air_gap=0, + trailing_air_gap=0.1, + ), + 10: AspirateSettings( # 10uL + z_submerge_depth=_default_submerge_aspirate_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=6.5, # ul/sec + delay=_default_aspirate_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + leading_air_gap=0, + trailing_air_gap=0.1, + ), + 50: AspirateSettings( # 50uL + z_submerge_depth=_default_submerge_aspirate_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=6.5, # ul/sec + delay=_default_aspirate_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + leading_air_gap=0, + trailing_air_gap=0.1, + ), + }, + 200: { # T200 + 5: AspirateSettings( # 5uL + z_submerge_depth=_default_submerge_aspirate_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_aspirate_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + leading_air_gap=0, + trailing_air_gap=2, + ), + 50: AspirateSettings( # 50uL + z_submerge_depth=_default_submerge_aspirate_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_aspirate_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + leading_air_gap=0, + trailing_air_gap=3.5, + ), + 200: AspirateSettings( # 200uL + z_submerge_depth=_default_submerge_aspirate_mm, + plunger_acceleration=_default_accel_96ch_ul_sec_sec, + plunger_flow_rate=80, # ul/sec + delay=_default_aspirate_delay_seconds, + z_retract_discontinuity=_default_retract_discontinuity, + z_retract_height=_default_retract_mm, + leading_air_gap=0, + trailing_air_gap=2, + ), + }, + }, }, } diff --git a/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py b/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py index 6c4e05f1ba8..cf49ae8feff 100644 --- a/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py +++ b/hardware-testing/hardware_testing/opentrons_api/helpers_ot3.py @@ -109,9 +109,17 @@ def _create_fake_pipette_id(mount: OT3Mount, model: Optional[str]) -> Optional[s return None items = model.split("_") assert len(items) == 3 - size = "P1K" if items[0] == "p1000" else "P50" + match items[0]: + case "p1000": + size = "P1K" + version = 35 + case "p50": + size = "P50" + version = 35 + case "p200": + size = "P2H" + version = 30 channels = "S" if items[1] == "single" else "M" - version = 35 # model names don't have a version so just fake a 3.5 version date = datetime.now().strftime("%y%m%d") unique_number = 1 if mount == OT3Mount.LEFT else 2 return f"{size}{channels}{version}{date}A0{unique_number}" diff --git a/hardware-testing/hardware_testing/protocols/gravimetric_lpc/gravimetric/gravimetric_ot3_p200_96.py b/hardware-testing/hardware_testing/protocols/gravimetric_lpc/gravimetric/gravimetric_ot3_p200_96.py new file mode 100644 index 00000000000..726f5b72533 --- /dev/null +++ b/hardware-testing/hardware_testing/protocols/gravimetric_lpc/gravimetric/gravimetric_ot3_p200_96.py @@ -0,0 +1,41 @@ +"""Gravimetric OT3 P200.""" +from opentrons.protocol_api import ProtocolContext +from opentrons.protocol_api._types import OffDeckType + +metadata = {"protocolName": "gravimetric-ot3-p200-96"} +requirements = {"robotType": "Flex", "apiLevel": "2.21"} + +SLOT_SCALE = 4 +SLOTS_TIPRACK = { + # TODO: add slot 12 when tipracks are disposable + 50: [2, 3, 5, 6, 7, 8, 9, 10, 11], + 200: [2, 3, 5, 6, 7, 8, 9, 10, 11], +} +LABWARE_ON_SCALE = "nest_1_reservoir_195ml" + + +def run(ctx: ProtocolContext) -> None: + """Run.""" + scale_labware = ctx.load_labware(LABWARE_ON_SCALE, SLOT_SCALE) + pipette = ctx.load_instrument("flex_96channel_200", "left") + adapters = [ + ctx.load_adapter("opentrons_flex_96_tiprack_adapter", slot) + for slot in SLOTS_TIPRACK[50] + ] + for tip_size in SLOTS_TIPRACK.keys(): + tipracks = [ + adapter.load_labware(f"opentrons_flex_96_tiprack_{tip_size}uL") + for adapter in adapters + ] + for rack in tipracks: + pipette.pick_up_tip(rack) + pipette.aspirate(10, scale_labware["A1"].top()) + pipette.dispense(10, scale_labware["A1"].top()) + pipette.drop_tip(home_after=False) + + for rack in tipracks: + ctx.move_labware( + rack, + new_location=OffDeckType.OFF_DECK, + use_gripper=False, + ) diff --git a/hardware-testing/hardware_testing/protocols/gravimetric_lpc/photometric/photometric_ot3_p200_96.py b/hardware-testing/hardware_testing/protocols/gravimetric_lpc/photometric/photometric_ot3_p200_96.py new file mode 100644 index 00000000000..092c00e5878 --- /dev/null +++ b/hardware-testing/hardware_testing/protocols/gravimetric_lpc/photometric/photometric_ot3_p200_96.py @@ -0,0 +1,44 @@ +"""Gravimetric OT3 P200.""" +from opentrons.protocol_api import ProtocolContext +from opentrons.protocol_api._types import OffDeckType + +metadata = {"protocolName": "photometric-ot3-p200-96"} +requirements = {"robotType": "Flex", "apiLevel": "2.15"} + +SLOTS_TIPRACK = { + 50: [5, 6, 8, 9, 11], + 200: [5, 6, 8, 9, 11], +} +SLOT_PLATE = 3 +SLOT_RESERVOIR = 2 + +RESERVOIR_LABWARE = "nest_1_reservoir_195ml" +PHOTOPLATE_LABWARE = "corning_96_wellplate_360ul_flat" + + +def run(ctx: ProtocolContext) -> None: + """Run.""" + reservoir = ctx.load_labware(RESERVOIR_LABWARE, SLOT_RESERVOIR) + plate = ctx.load_labware(PHOTOPLATE_LABWARE, SLOT_PLATE) + pipette = ctx.load_instrument("flex_96channel_200", "left") + adapters = [ + ctx.load_adapter("opentrons_flex_96_tiprack_adapter", slot) + for slot in SLOTS_TIPRACK[50] + ] + for tip_size in SLOTS_TIPRACK.keys(): + tipracks = [ + adapter.load_labware(f"opentrons_flex_96_tiprack_{tip_size}uL") + for adapter in adapters + ] + for rack in tipracks: + pipette.pick_up_tip(rack) + pipette.aspirate(10, reservoir["A1"].top()) + pipette.dispense(10, plate["A1"].top()) + pipette.drop_tip(home_after=False) + + for rack in tipracks: + ctx.move_labware( + rack, + new_location=OffDeckType.OFF_DECK, + use_gripper=False, + )