def move_to(self, location, instrument=None, strategy='arc', **kwargs): """ Move an instrument to a coordinate, container or a coordinate within a container. Parameters ---------- location : one of the following: 1. :class:`Placeable` (i.e. Container, Deck, Slot, Well) — will move to the origin of a container. 2. :class:`Vector` move to the given coordinate in Deck coordinate system. 3. (:class:`Placeable`, :class:`Vector`) move to a given coordinate within object's coordinate system. instrument : Instrument to move relative to. If ``None``, move relative to the center of a gantry. strategy : {'arc', 'direct'} ``arc`` : move to the point using arc trajectory avoiding obstacles. ``direct`` : move to the point in a straight line. Examples -------- >>> from opentrons import Robot >>> robot.reset() # doctest: +ELLIPSIS <opentrons.robot.robot.Robot object at ...> >>> robot.connect('Virtual Smoothie') >>> robot.home() >>> plate = robot.add_container('96-flat', 'A1', 'plate') >>> robot.move_to(plate[0]) >>> robot.move_to(plate[0].top()) """ placeable, coordinates = containers.unpack_location(location) if instrument: coordinates = instrument.calibrator.convert(placeable, coordinates) else: coordinates += placeable.coordinates(placeable.get_deck()) if strategy == 'arc': arc_coords = self._create_arc(coordinates, placeable, instrument) for coord in arc_coords: self._driver.move_head(**coord) elif strategy == 'direct': self._driver.move_head(x=coordinates[0], y=coordinates[1], z=coordinates[2]) else: raise RuntimeError('Unknown move strategy: {}'.format(strategy))
def _associate_placeable(self, location): """ Saves a reference to a placeable """ if not location: return placeable, _ = unpack_location(location) self.previous_placeable = placeable if not self.placeables or (placeable != self.placeables[-1]): self.placeables.append(placeable)
def _associate_placeable(self, location): """ Saves a reference to a placeable """ if not location: return placeable, _ = containers.unpack_location(location) self.previous_placeable = placeable if not self.placeables or (placeable != self.placeables[-1]): self.placeables.append(placeable)
def _dispense_during_transfer(self, vol, loc, **kwargs): """ Performs a :any:`dispense` when running a :any:`transfer`, and optionally a :any:`mix`, :any:`touch_tip`, and/or :any:`blow_out` afterwards. """ mix_after = kwargs.get('mix_after', (0, 0)) rate = kwargs.get('rate', 1) air_gap = kwargs.get('air_gap', 0) well, _ = unpack_location(loc) if air_gap: self.dispense(air_gap, well.top(5), rate=rate) self.dispense(vol, loc, rate=rate) self._mix_during_transfer(mix_after, well, **kwargs)
def _aspirate_during_transfer(self, vol, loc, **kwargs): """ Performs an :any:`aspirate` when running a :any:`transfer`, and optionally a :any:`touch_tip` afterwards. """ rate = kwargs.get('rate', 1) mix_before = kwargs.get('mix', kwargs.get('mix_before', (0, 0))) air_gap = kwargs.get('air_gap', 0) touch_tip = kwargs.get('touch_tip', False) well, _ = unpack_location(loc) if self.current_volume == 0: self._mix_during_transfer(mix_before, well, **kwargs) self.aspirate(vol, loc, rate=rate) if air_gap: self.air_gap(air_gap) if touch_tip or touch_tip is 0: self.touch_tip(touch_tip)
def _position_for_aspirate(self, location=None): """ Position this :any:`Pipette` for an aspiration, given it's current state """ # first go to the destination if location: placeable, _ = unpack_location(location) self.move_to(placeable.top(), strategy='arc') # setup the plunger above the liquid if self.current_volume == 0: self.motor.move(self._get_plunger_position('bottom')) # then go inside the location if location: if isinstance(location, Placeable): location = location.bottom(min(location.z_size(), 1)) self.move_to(location, strategy='direct')
def _position_for_aspirate(self, location=None, plunger_empty=False): """ Position this :any:`Pipette` for an aspiration, given it's current state """ # first go to the destination if location: placeable, _ = containers.unpack_location(location) self.move_to(placeable.top(), strategy='arc', enqueue=False) # setup the plunger above the liquid if plunger_empty: self.motor.move(self._get_plunger_position('bottom')) # then go inside the location if location: if isinstance(location, Placeable): location = location.bottom(1) self.move_to(location, strategy='direct', enqueue=False)
def _setup(): nonlocal location if not location: if self.has_tip_rack(): # TODO: raise warning/exception if looped back to first tip location = next(self.tip_rack_iter) else: self.robot.add_warning( 'pick_up_tip called with no reference to a tip') self.current_tip_home_well = None if location: placeable, _ = containers.unpack_location(location) self.current_tip_home_well = placeable if isinstance(location, Placeable): location = location.bottom() self._associate_placeable(location) self.current_volume = 0
def pick_up_tip(self, location=None, presses=3): """ Pick up a tip for the Pipette to run liquid-handling commands with Notes ----- A tip can be manually set by passing a `location`. If no location is passed, the Pipette will pick up the next available tip in it's `tip_racks` list (see :any:`Pipette`) Parameters ---------- location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the pick_up_tip. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> robot.reset() # doctest: +ELLIPSIS <opentrons.robot.robot.Robot object at ...> >>> tiprack = containers.load('tiprack-200ul', 'A1') >>> p200 = instruments.Pipette(axis='a', tip_racks=[tiprack]) >>> p200.pick_up_tip(tiprack[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> p200.return_tip() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # `pick_up_tip` will automatically go to tiprack[1] >>> p200.pick_up_tip() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> p200.return_tip() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ if not location: location = self.get_next_tip() self.current_tip(None) if location: placeable, _ = unpack_location(location) self.current_tip(placeable) if isinstance(location, Placeable): location = location.bottom() _description = "Picking up tip {0}".format( ('from ' + humanize_location(location) if location else '')) # NOQA self.robot.add_command(_description) presses = (1 if not helpers.is_number(presses) else presses) self.motor.move(self._get_plunger_position('bottom')) self.current_volume = 0 if location: self.move_to(location, strategy='arc') tip_plunge = 6 for i in range(int(presses) - 1): self.robot.move_head(z=tip_plunge, mode='relative') self.robot.move_head(z=-tip_plunge, mode='relative') return self
def move_to(self, location, instrument=None, strategy="arc", **kwargs): """ Move an instrument to a coordinate, container or a coordinate within a container. Parameters ---------- location : one of the following: 1. :class:`Placeable` (i.e. Container, Deck, Slot, Well) — will move to the origin of a container. 2. :class:`Vector` move to the given coordinate in Deck coordinate system. 3. (:class:`Placeable`, :class:`Vector`) move to a given coordinate within object's coordinate system. instrument : Instrument to move relative to. If ``None``, move relative to the center of a gantry. strategy : {'arc', 'direct'} ``arc`` : move to the point using arc trajectory avoiding obstacles. ``direct`` : move to the point in a straight line. Examples -------- >>> from opentrons import Robot >>> robot.reset() # doctest: +ELLIPSIS <opentrons.robot.robot.Robot object at ...> >>> robot.connect('Virtual Smoothie') True >>> robot.home() True >>> plate = robot.add_container('96-flat', 'A1', 'plate') >>> robot.move_to(plate[0]) >>> robot.move_to(plate[0].top()) """ enqueue = kwargs.get("enqueue", False) # Adding this for backwards compatibility with old move_to(now=False) # convention. if "now" in kwargs: enqueue = not kwargs.get("now") placeable, coordinates = containers.unpack_location(location) if instrument: coordinates = instrument.calibrator.convert(placeable, coordinates) else: coordinates += placeable.coordinates(placeable.get_deck()) def _do(): if strategy == "arc": arc_coords = self._create_arc(coordinates, placeable) for coord in arc_coords: self._driver.move_head(**coord) elif strategy == "direct": self._driver.move_head(x=coordinates[0], y=coordinates[1], z=coordinates[2]) else: raise RuntimeError("Unknown move strategy: {}".format(strategy)) if enqueue: self.add_command(Command(do=_do)) else: _do()
def move_to(self, location, instrument, strategy='arc', **kwargs): """ Move an instrument to a coordinate, container or a coordinate within a container. Parameters ---------- location : one of the following: 1. :class:`Placeable` (i.e. Container, Deck, Slot, Well) — will move to the origin of a container. 2. :class:`Vector` move to the given coordinate in Deck coordinate system. 3. (:class:`Placeable`, :class:`Vector`) move to a given coordinate within object's coordinate system. instrument : Instrument to move relative to. If ``None``, move relative to the center of a gantry. strategy : {'arc', 'direct'} ``arc`` : move to the point using arc trajectory avoiding obstacles. ``direct`` : move to the point in a straight line. """ placeable, coordinates = containers.unpack_location(location) # because the top position is what is tracked, # this checks if coordinates doesn't equal top offset = subtract(coordinates, placeable.top()[1]) if 'trough' in repr(placeable): # Move the pipette so that a multi-channel pipette is centered in # the trough well to prevent crashing into the side, which would # happen if you send the "A1" tip to the center of the well. See # `robot.calibrate_container_with_instrument` for corresponding # offset and comment. offset = offset + (0, Y_OFFSET_MULTI, 0) if isinstance(placeable, containers.WellSeries): placeable = placeable[0] target = add(pose_tracker.absolute(self.poses, placeable), offset.coordinates) if self._previous_instrument: if self._previous_instrument != instrument: self._previous_instrument.retract() # because we're switching pipettes, this ensures a large (safe) # Z arc height will be used for the new pipette self._prev_container = None self._previous_instrument = instrument if strategy == 'arc': arc_coords = self._create_arc(instrument, target, placeable) for coord in arc_coords: self.poses = instrument._move(self.poses, **coord) elif strategy == 'direct': position = {'x': target[0], 'y': target[1], 'z': target[2]} self.poses = instrument._move(self.poses, **position) else: raise RuntimeError('Unknown move strategy: {}'.format(strategy))