def touch_right(cur_position: Location): if touch_tip == "right": p10_multi.move_to(cur_position.move(Point(x=2.7, z=-0.75))) p10_multi.move_to(cur_position.move(Point(x=-1, z=0.75))) else: p10_multi.move_to(cur_position.move(Point(x=-2.7, z=-0.75))) p10_multi.move_to(cur_position.move(Point(x=1, z=0.75)))
def run(ctx): [transfer_csv] = get_values( # noqa: F821 "transfer_csv") tiprack20 = [ ctx.load_labware('opentrons_96_tiprack_20ul', '3', '20µl tiprack') ] pipettes = [ ctx.load_instrument('p20_single_gen2', mount, tip_racks=tiprack20) for mount in ['right', 'left'] ] # load labware transfer_info = [[val.strip().lower() for val in line.split(',')[1:]] for line in transfer_csv.splitlines() if line.split(',')[0].strip()][1:] src_a = Location( Point(float(transfer_info[0][0]), float(transfer_info[0][1]), float(transfer_info[0][2])), None) src_b = Location( Point(float(transfer_info[1][0]), float(transfer_info[1][1]), float(transfer_info[1][2])), None) for line in transfer_info[2:]: dest = Location(Point(float(line[0]), float(line[1]), float(line[2])), None) vol = float(line[3]) [p.pick_up_tip() for p in pipettes] [pip.home() for pip in pipettes] for src, p in zip([src_a, src_b], pipettes): p.aspirate(vol, src) p.home() p.dispense(vol, dest) p.home() [p.drop_tip() for p in pipettes]
def test_move_to_slot(): slot_position = Location(Point(1, 2, 3), 'deck') mock_context = mock.Mock() mock_deck = mock.MagicMock(spec=Deck) mock_deck.__contains__.return_value = True mock_deck.position_for.return_value = slot_position mock_context.deck = mock_deck pipette_mock = mock.create_autospec(InstrumentContext) instruments = {'somePipetteId': pipette_mock} params = { 'pipette': 'somePipetteId', 'slot': '4', 'offset': { 'x': 10, 'y': 11, 'z': 12 }, 'forceDirect': mock.sentinel.force_direct, 'minimumZHeight': mock.sentinel.minimum_z_height } _move_to_slot(mock_context, instruments, params) assert pipette_mock.mock_calls == [ mock.call.move_to(Location(Point(11, 13, 15), 'deck'), force_direct=mock.sentinel.force_direct, minimum_z_height=mock.sentinel.minimum_z_height) ]
async def test_max_speeds(loop, monkeypatch, hardware): ctx = papi.ProtocolContext(loop) ctx.connect(hardware) ctx.home() mock_move = mock.Mock() monkeypatch.setattr(ctx._hw_manager.hardware, 'move_to', mock_move) instr = ctx.load_instrument('p10_single', Mount.RIGHT) instr.move_to(Location(Point(0, 0, 0), None)) assert all( kwargs['max_speeds'] == {} for args, kwargs in mock_move.call_args_list) mock_move.reset_mock() ctx.max_speeds['x'] = 10 instr.move_to(Location(Point(0, 0, 1), None)) assert all( kwargs['max_speeds'] == {Axis.X: 10} for args, kwargs in mock_move.call_args_list) mock_move.reset_mock() ctx.max_speeds['x'] = None instr.move_to(Location(Point(1, 0, 1), None)) assert all( kwargs['max_speeds'] == {} for args, kwargs in mock_move.call_args_list)
def test_tiprack_list(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) tiprack_2 = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) assert labware.select_tiprack_from_list( [tiprack], 1) == (tiprack, tiprack['A1']) assert labware.select_tiprack_from_list( [tiprack], 1, tiprack.wells()[1]) == (tiprack, tiprack['B1']) tiprack['C1'].has_tip = False assert labware.select_tiprack_from_list( [tiprack], 1, tiprack.wells()[2]) == (tiprack, tiprack['D1']) tiprack['H12'].has_tip = False tiprack_2['A1'].has_tip = False assert labware.select_tiprack_from_list( [tiprack, tiprack_2], 1, tiprack.wells()[95]) == ( tiprack_2, tiprack_2['B1']) with pytest.raises(labware.OutOfTipsError): labware.select_tiprack_from_list( [tiprack], 1, tiprack.wells()[95])
def _get_move_to_point_loc_by_state(self) -> Location: assert self._z_height_reference is not None, \ "saveOffset has not been called yet" pt_id = MOVE_POINT_STATE_MAP[self._current_state] coords = self._deck.get_calibration_position(pt_id).position loc = Location(Point(*coords), None) return loc.move(point=Point(0, 0, self._z_height_reference))
def test_air_gap(): m = mock.MagicMock() m.pipette_mock = mock.create_autospec(InstrumentContext) m.mock_set_flow_rate = mock.MagicMock() deck = Location(Point(0, 0, 0), 'deck') well_name = 'A2' some_labware = labware.Labware(minimalLabwareDef2, deck) loaded_labware = {'someLabwareId': some_labware} params = {'labware': 'someLabwareId', 'well': well_name} params = {'pipette': 'somePipetteId', 'volume': 42, 'labware': 'someLabwareId', 'well': well_name, 'offsetFromBottomMm': 12} instruments = {'somePipetteId': m.pipette_mock} loaded_labware = {'someLabwareId': some_labware} with mock.patch( 'opentrons.protocols.execution.execute_json_v3._set_flow_rate', new=m.mock_set_flow_rate): _air_gap(instruments, loaded_labware, params) # NOTE: air_gap `height` arg is mm from well top, # so we expect it to equal offsetFromBottomMm - well depth. assert m.mock_calls == [ mock.call.mock_set_flow_rate(m.pipette_mock, params), mock.call.pipette_mock.move_to( Location(point=Point(x=19, y=28, z=17.0), labware=some_labware[well_name])), mock.call.pipette_mock.air_gap(42, 12 - 40) ]
def test_direct_cp(): deck = Deck() trough = labware.load(trough_name, deck.position_for(1)) lw1 = labware.load(labware_name, deck.position_for(2)) # when moving from no origin location to a centered labware we should # start in default cp from_nothing = plan_moves(Location(Point(50, 50, 50), None), trough.wells()[0].top(), deck) check_arc_basic(from_nothing, Location(Point(50, 50, 50), None), trough.wells()[0].top()) assert from_nothing[0][1] is None assert from_nothing[1][1] == CriticalPoint.XY_CENTER assert from_nothing[2][1] == CriticalPoint.XY_CENTER # when moving from an origin with a centered labware to a dest with a # centered labware we should stay in centered the entire time, whether # arc from_centered_arc = plan_moves(trough.wells()[0].top(), trough.wells()[1].top(), deck) check_arc_basic(from_centered_arc, trough.wells()[0].top(), trough.wells()[1].top()) assert from_centered_arc[0][1] == CriticalPoint.XY_CENTER assert from_centered_arc[1][1] == CriticalPoint.XY_CENTER assert from_centered_arc[2][1] == CriticalPoint.XY_CENTER # or direct from_centered_direct = plan_moves(trough.wells()[0].top(), trough.wells()[1].bottom(), deck) assert from_centered_direct[0][1] == CriticalPoint.XY_CENTER # when moving from centered to normal, only the first move should be # centered to_normal = plan_moves(trough.wells()[0].top(), lw1.wells()[0].top(), deck) check_arc_basic(to_normal, trough.wells()[0].top(), lw1.wells()[0].top()) assert to_normal[0][1] == CriticalPoint.XY_CENTER assert to_normal[1][1] is None assert to_normal[2][1] is None
def test_select_next_tip(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) well_list = tiprack.wells() next_one = tiprack.next_tip() assert next_one == well_list[0] next_five = tiprack.next_tip(5) assert next_five == well_list[0] next_eight = tiprack.next_tip(8) assert next_eight == well_list[0] next_nine = tiprack.next_tip(9) assert next_nine is None # A1 tip only has been used tiprack.use_tips(well_list[0]) next_one = tiprack.next_tip() assert next_one == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[1] next_eight = tiprack.next_tip(8) assert next_eight == well_list[8] # 2nd column has also been used tiprack.use_tips(well_list[8], num_channels=8) next_one = tiprack.next_tip() assert next_one == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[1] next_eight = tiprack.next_tip(8) assert next_eight == well_list[16] # Bottom 4 tips of 1rd column are also used tiprack.use_tips(well_list[4], num_channels=4) next_one = tiprack.next_tip() assert next_one == well_list[1] next_three = tiprack.next_tip(3) assert next_three == well_list[1] next_five = tiprack.next_tip(5) assert next_five == well_list[16] next_eight = tiprack.next_tip(8) assert next_eight == well_list[16] # you can reuse tips infinitely on api level 2.2 tiprack.use_tips(well_list[0]) tiprack.use_tips(well_list[0]) # you can't on api level 2.1 or previous early_tr = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot'), api_level=APIVersion(2, 1)) early_tr.use_tips(well_list[0]) with pytest.raises(AssertionError): early_tr.use_tips(well_list[0])
def test_get_location_with_offset(): deck = Location(Point(0, 0, 0), 'deck') some_labware = labware.Labware(minimalLabwareDef2, deck) loaded_labware = {'someLabwareId': some_labware} params = {'offsetFromBottomMm': 3, 'labware': 'someLabwareId', 'well': 'A2'} result = _get_location_with_offset(loaded_labware, params) assert result == Location(Point(19, 28, 8), some_labware['A2'])
def test_bottom(): slot = Location(Point(7, 8, 9), 1) well_name = 'rectangular_well_json' has_tip = False well = labware.Well(test_data[well_name], slot, well_name, has_tip) well_data = test_data[well_name] expected_x = well_data['x'] + slot.point.x expected_y = well_data['y'] + slot.point.y expected_z = well_data['z'] + slot.point.z assert well.bottom() == Location(Point(expected_x, expected_y, expected_z), well)
def test_top(): slot = Location(Point(4, 5, 6), 1) well_name = 'circular_well_json' has_tip = False well = labware.Well(test_data[well_name], slot, well_name, has_tip) well_data = test_data[well_name] expected_x = well_data['x'] + slot.point.x expected_y = well_data['y'] + slot.point.y expected_z = well_data['z'] + well_data['depth'] + slot.point.z assert well.top() == Location(Point(expected_x, expected_y, expected_z), well)
async def move_to_tip_rack(self): # point safely above target tip well in tip rack pt_above_well = self._tip_rack.wells()[0].top().point + \ MOVE_TO_TIP_RACK_SAFETY_BUFFER if self._tip_origin_pt is not None: # use jogged to x and y offsets only if returning tip to rack await self._move(Location(Point(self._tip_origin_pt.x, self._tip_origin_pt.y, pt_above_well.z), None)) else: await self._move(Location(pt_above_well, None))
def test_get_location_with_offset_fixed_trash(): deck = Location(Point(0, 0, 0), 'deck') trash_labware_def = deepcopy(minimalLabwareDef2) trash_labware_def['parameters']['quirks'] = ["fixedTrash"] trash_labware = labware.Labware(trash_labware_def, deck) loaded_labware = {'someLabwareId': trash_labware} params = {'offsetFromBottomMm': 3, 'labware': 'someLabwareId', 'well': 'A1'} result = _get_location_with_offset(loaded_labware, params) assert result == Location(Point(10, 28, 45), trash_labware['A1'])
def test_get_parent_identifier(): labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) lw = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) # slots have no parent identifier assert labware._get_parent_identifier(lw) == '' # modules do mmg = ModuleGeometry('my magdeck', MagneticModuleModel.MAGNETIC_V1, ModuleType.MAGNETIC, Point(0, 0, 0), 10, 10, Location(Point(1, 2, 3), '3'), APIVersion(2, 4)) lw = labware.Labware(labware_def, mmg.location) assert labware._get_parent_identifier(lw)\ == MagneticModuleModel.MAGNETIC_V1.value
def test_tip_tracking_init(): labware_name = 'opentrons_96_tiprack_300ul' labware_def = labware.get_labware_definition(labware_name) tiprack = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) assert tiprack.is_tiprack for well in tiprack.wells(): assert well.has_tip labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) lw = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) assert not lw.is_tiprack for well in lw.wells(): assert not well.has_tip
def test_well_parent(): labware_name = 'corning_96_wellplate_360ul_flat' labware_def = labware.get_labware_definition(labware_name) lw = labware.Labware(labware_def, Location(Point(0, 0, 0), 'Test Slot')) parent = Location(Point(7, 8, 9), lw) well_name = 'circular_well_json' has_tip = True well = labware.Well(test_data[well_name], parent, well_name, has_tip) assert well.parent is lw assert well.top().labware is well assert well.top().labware.parent is lw assert well.bottom().labware is well assert well.bottom().labware.parent is lw assert well.center().labware is well assert well.center().labware.parent is lw
def test_labware_init(): deck = Location(Point(0, 0, 0), 'deck') fake_labware = labware.Labware(minimalLabwareDef, deck) ordering = [well for col in minimalLabwareDef['ordering'] for well in col] assert fake_labware._ordering == ordering assert fake_labware._well_definition == minimalLabwareDef['wells'] assert fake_labware._offset == Point(x=10, y=10, z=5)
def test_load_calibration(monkeypatch, clear_calibration): calibration_point = None def mock_set_calibration(self, delta): nonlocal calibration_point calibration_point = delta monkeypatch.setattr(labware.Labware, 'set_calibration', mock_set_calibration) monkeypatch.setattr(labware, '_hash_labware_def', mock_hash_labware) test_labware = labware.Labware(minimalLabwareDef, Location(Point(0, 0, 0), 'deck')) test_offset = Point(1, 1, 1) test_tip_length = 31.7 labware.save_calibration(test_labware, test_offset) labware.save_tip_length(test_labware, test_tip_length) # Set without saving to show that load will update with previously saved # data test_labware.set_calibration(Point(0, 0, 0)) test_labware.tip_length = 46.8 labware.load_calibration(test_labware) assert calibration_point == test_offset assert test_labware.tip_length == test_tip_length
def test_build_edges(): lw_def = get_labware_definition('corning_96_wellplate_360ul_flat') test_lw = Labware(lw_def, Location(Point(0, 0, 0), None)) off = Point(0, 0, 1.0) deck = Deck() old_correct_edges = [ test_lw['A1']._from_center_cartesian(x=1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=-1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=1.0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=-1.0, z=1) + off, ] res = build_edges( test_lw['A1'], 1.0, Mount.RIGHT, deck, version=APIVersion(2, 2)) assert res == old_correct_edges new_correct_edges = [ test_lw['A1']._from_center_cartesian(x=1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=-1.0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=1.0, z=1) + off, test_lw['A1']._from_center_cartesian(x=0, y=-1.0, z=1) + off, ] res2 = build_edges( test_lw['A1'], 1.0, Mount.RIGHT, deck, version=APIVersion(2, 4)) assert res2 == new_correct_edges
def test_module_load_v2(module_model): mod = module_geometry.load_module( module_model, Location(Point(0, 0, 0), '3')) mod_def = module_geometry._load_module_definition(MAX_SUPPORTED_VERSION, module_model) high_z = mod_def['dimensions']['bareOverallHeight'] assert mod.highest_z == high_z
def __init__(self, definition: dict, parent: Location) -> None: """ Create a Module for tracking the position of a module. Note that modules do not currently have a concept of calibration apart from calibration of labware on top of the module. The practical result of this is that if the module parent :py:class:`.Location` is incorrect, then acorrect calibration of one labware on the deck would be incorrect on the module, and vice-versa. Currently, the way around this would be to correct the :py:class:`.Location` so that the calibrated labware is targeted accurately in both positions. :param definition: A dict containing all the data required to define the geometry of the module. :type definition: dict :param parent: A location representing location of the front left of the outside of the module (usually the front-left corner of a slot on the deck). :type parent: :py:class:`.Location` """ self._parent = parent self._display_name = "{} on {}".format(definition["displayName"], str(parent.labware)) self._load_name = definition["loadName"] self._offset = Point(definition["labwareOffset"]["x"], definition["labwareOffset"]["y"], definition["labwareOffset"]["z"]) self._height = definition["dimensions"]["bareOverallHeight"]\ + self._parent.point.z self._over_labware = definition["dimensions"]["overLabwareHeight"] self._labware: Optional[Labware] = None self._location = Location(point=self._offset + self._parent.point, labware=self)
def test_touch_tip(): location = Location(Point(1, 2, 3), 'deck') well = labware.Well( { 'shape': 'circular', 'depth': 40, 'totalLiquidVolume': 100, 'diameter': 30, 'x': 40, 'y': 50, 'z': 3 }, parent=Location(Point(10, 20, 30), 1), has_tip=False, display_name='some well', api_level=MAX_SUPPORTED_VERSION) pipette_mock = mock.create_autospec(InstrumentContext, name='pipette_mock') mock_get_location_with_offset = mock.MagicMock( return_value=location, name='mock_get_location_with_offset') mock_get_well = mock.MagicMock(return_value=well, name='mock_get_well') mock_set_flow_rate = mock.MagicMock(name='mock_set_flow_rate') params = { 'pipette': 'somePipetteId', 'labware': 'someLabwareId', 'well': 'someWell' } instruments = {'somePipetteId': pipette_mock} with mock.patch( 'opentrons.protocol_api.execute_v3._get_location_with_offset', new=mock_get_location_with_offset): with mock.patch('opentrons.protocol_api.execute_v3._get_well', new=mock_get_well): with mock.patch('opentrons.protocol_api.execute_v3._set_flow_rate', new=mock_set_flow_rate): _touch_tip(instruments, mock.sentinel.loaded_labware, params) # note: for this fn, order of calls doesn't matter b/c # we don't have stateful stuff like flow_rate mock_get_location_with_offset.assert_called_once_with( mock.sentinel.loaded_labware, params) mock_get_well.assert_called_once_with(mock.sentinel.loaded_labware, params) assert pipette_mock.mock_calls == [ mock.call.touch_tip(well, v_offset=-70.0) ]
def test_uris(): details = ('opentrons', 'opentrons_96_tiprack_300ul', '1') uri = 'opentrons/opentrons_96_tiprack_300ul/1' assert labware.uri_from_details(*details) == uri defn = labware.get_labware_definition(details[1], details[0], details[2]) assert labware.uri_from_definition(defn) == uri lw = labware.Labware(defn, Location(Point(0, 0, 0), 'Test Slot')) assert lw.uri == uri
async def _return_first_tip(self): first_pip = self._get_pipette_by_rank(PipetteRank.first) assert first_pip, \ 'cannot drop tip on first mount, pipette not present' state_name = CalibrationCheckState.preparingFirstPipette loc = Location(getattr(self._moves, state_name).position, None) await self._move(first_pip.mount, loc) await self._drop_tip(first_pip.mount)
async def _return_second_tip(self): second_pip = self._get_pipette_by_rank(PipetteRank.second) assert second_pip, \ 'cannot drop tip on second mount, pipette not present' state_name = CalibrationCheckState.preparingSecondPipette loc = Location(getattr(self._moves, state_name).position, None) await self._move(second_pip.mount, loc) await self._drop_tip(second_pip.mount)
async def _move_second_pipette(self): second_pip = self._get_pipette_by_rank(PipetteRank.second) assert second_pip, \ 'cannot move pipette on second mount, pipette not present' loc_to_move = Location( getattr(self._moves, self.current_state_name).position, None) if self.current_state_name ==\ CalibrationCheckState.joggingSecondPipetteToPointOne: saved_height =\ self._saved_points[getattr(CalibrationCheckState, 'comparingSecondPipetteHeight')] z_point = \ saved_height + self._initial_z_offset - HEIGHT_SAFETY_BUFFER updated_point = loc_to_move.point + z_point._replace(x=0.0, y=0.0) loc_to_move = Location(updated_point, None) await self._move(second_pip.mount, loc_to_move) await self._register_point_second_pipette()
def test_get_well(): deck = Location(Point(0, 0, 0), 'deck') well_name = 'A2' some_labware = labware.Labware(minimalLabwareDef2, deck) loaded_labware = {'someLabwareId': some_labware} params = {'labware': 'someLabwareId', 'well': well_name} result = _get_well(loaded_labware, params) assert result == some_labware[well_name]
async def move_to_deck(self): deck_pt = self._deck.get_slot_center(JOG_TO_DECK_SLOT) ydim = self._deck.get_slot_definition( JOG_TO_DECK_SLOT)['boundingBox']['yDimension'] new_pt = deck_pt - Point(0, (ydim/2), deck_pt.z) + \ MOVE_TO_DECK_SAFETY_BUFFER to_loc = Location(new_pt, None) await self._move(to_loc)
def center(self) -> Location: """ :return: a Point corresponding to the absolute position of the center of the well relative to the deck (with the front-left corner of slot 1 as (0,0,0)) """ top = self.top() center_z = top.point.z - (self._depth / 2.0) return Location(Point(x=top.point.x, y=top.point.y, z=center_z), self)