def blow_out(self, location=None, enqueue=True): """ Force any remaining liquid to dispense, by moving this pipette's plunger to the calibrated `blow_out` position Notes ----- If no `location` is passed, the pipette will blow_out from it's current position. Parameters ---------- location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the blow_out. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(axis='a', max_volume=200) >>> p200.aspirate(50).dispense().blow_out() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ def _setup(): nonlocal location self.current_volume = 0 self._associate_placeable(location) def _do(): nonlocal location self.move_to(location, strategy='arc', enqueue=False) self.motor.move(self._get_plunger_position('blow_out')) _description = "Blow_out at {}".format( humanize_location(location) if location else '<In Place>' ) self.create_command( do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def blow_out(self, location=None, enqueue=True): """ Force any remaining liquid to dispense, by moving this pipette's plunger to the calibrated `blow_out` position Notes ----- If no `location` is passed, the pipette will blow_out from it's current position. Parameters ---------- location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the blow_out. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(axis='a', max_volume=200) >>> p200.aspirate(50).dispense().blow_out() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ def _setup(): nonlocal location self.current_volume = 0 self._associate_placeable(location) def _do(): nonlocal location self.move_to(location, strategy='arc', enqueue=False) self.motor.move(self._get_plunger_position('blow_out')) _description = "Blow_out at {}".format( humanize_location(location) if location else '<In Place>') self.create_command(do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def blow_out(self, location=None): """ Force any remaining liquid to dispense, by moving this pipette's plunger to the calibrated `blow_out` position Notes ----- If no `location` is passed, the pipette will blow_out from it's current position. Parameters ---------- location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the blow_out. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(name='p200', axis='a', max_volume=200) >>> p200.aspirate(50).dispense().blow_out() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ _description = "Blowing out {}".format( 'at ' + humanize_location(location) if location else '') self.robot.add_command(_description) self.move_to(location, strategy='arc') self.motor.move(self._get_plunger_position('blow_out')) self.current_volume = 0 return self
def drop_tip(self, location=None, home_after=True): """ Drop the pipette's current tip Notes ----- If no location is passed, the pipette defaults to its `trash_container` (see :any:`Pipette`) Parameters ---------- location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the drop_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') >>> trash = containers.load('point', 'A1') >>> p200 = instruments.Pipette(axis='a', trash_container=trash) >>> p200.pick_up_tip(tiprack[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # drops the tip in the trash >>> p200.drop_tip() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> p200.pick_up_tip(tiprack[1]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # drops the tip back at its tip rack >>> p200.drop_tip(tiprack[1]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ if not location and self.trash_container: location = self.trash_container if isinstance(location, Placeable): # give space for the drop-tip mechanism location = location.bottom(self._drop_tip_offset) _description = "Drop_tip {}".format( ('at ' + humanize_location(location) if location else '')) self.robot.add_command(_description) if location: self.move_to(location, strategy='arc') self.motor.move(self._get_plunger_position('drop_tip')) if home_after: self.motor.home() self.motor.move(self._get_plunger_position('bottom')) self.current_volume = 0 self.current_tip(None) return self
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 dispense(self, volume=None, location=None, rate=1.0): """ Dispense a volume of liquid (in microliters/uL) using this pipette Notes ----- If no `location` is passed, the pipette will dispense from it's current position. If no `volume` is passed, `dispense` will default to it's `current_volume` Parameters ---------- volume : int or float The number of microliters to dispense (Default: self.current_volume) location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the dispense. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` rate : float Set plunger speed for this dispense, where speed = rate * dispense_speed (see :meth:`set_speed`) Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(name='p200', axis='a', max_volume=200) >>> # fill the pipette with liquid (200uL) >>> p200.aspirate(plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 50uL to a Well >>> p200.dispense(50, plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 50uL to the center of a well >>> relative_vector = plate[1].center() >>> p200.dispense(50, (plate[1], relative_vector)) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 20uL in place, at half the speed >>> p200.dispense(20, rate=0.5) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense the pipette's remaining volume (80uL) to a Well >>> p200.dispense(plate[2]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ if not helpers.is_number(volume): if volume and not location: location = volume volume = self.current_volume # Ensure we don't dispense more than the current volume volume = min(self.current_volume, volume) # if volume is specified as 0uL, then do nothing if volume == 0: return self _description = "Dispensing {0} {1}".format( volume, ('at ' + humanize_location(location) if location else '')) # NOQA self.robot.add_command(_description) self.move_to(location, strategy='arc') # position robot above location # TODO(ahmed): revisit this distance = self._plunge_distance(self.current_volume - volume) bottom = self._get_plunger_position('bottom') destination = bottom - distance speed = self.speeds['dispense'] * rate self.motor.speed(speed) self.motor.move(destination) self.current_volume -= volume # update after actual dispense return self
def aspirate(self, volume=None, location=None, rate=1.0): """ Aspirate a volume of liquid (in microliters/uL) using this pipette Notes ----- If no `location` is passed, the pipette will aspirate from it's current position. If no `volume` is passed, `aspirate` will default to it's `max_volume` Parameters ---------- volume : int or float The number of microliters to aspirate (Default: self.max_volume) location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the aspirate. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` rate : float Set plunger speed for this aspirate, where speed = rate * aspirate_speed (see :meth:`set_speed`) Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette( ... name='p200', axis='a', max_volume=200) >>> # aspirate 50uL from a Well >>> p200.aspirate(50, plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate 50uL from the center of a well >>> p200.aspirate(50, plate[1].bottom()) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate 20uL in place, twice as fast >>> p200.aspirate(20, rate=2.0) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate the pipette's remaining volume (80uL) from a Well >>> p200.aspirate(plate[2]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ # Note: volume positional argument may not be passed. if it isn't then # assume the first positional argument is the location if not helpers.is_number(volume): if volume and not location: location = volume volume = self.max_volume - self.current_volume # if volume is specified as 0uL, then do nothing if volume == 0: return self if self.current_volume + volume > self.max_volume: raise RuntimeWarning( 'Pipette with max volume of {0} cannot hold volume {1}'.format( self.max_volume, self.current_volume + volume)) distance = self._plunge_distance(self.current_volume + volume) bottom = self._get_plunger_position('bottom') destination = bottom - distance speed = self.speeds['aspirate'] * rate _description = "Aspirating {0} {1}".format( volume, ('at ' + humanize_location(location) if location else '')) # NOQA self.robot.add_command(_description) self._position_for_aspirate(location) self.motor.speed(speed) self.motor.move(destination) self.current_volume += volume # update after actual aspirate return self
def drop_tip(self, location=None, enqueue=True): """ Drop the pipette's current tip Notes ----- If no location is passed, the pipette defaults to its `trash_container` (see :any:`Pipette`) Parameters ---------- location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the drop_tip. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> robot.reset() # doctest: +ELLIPSIS <opentrons.robot.robot.Robot object at ...> >>> tiprack = containers.load('tiprack-200ul', 'A1') >>> trash = containers.load('point', 'A1') >>> p200 = instruments.Pipette(axis='a', trash_container=trash) >>> p200.pick_up_tip(tiprack[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # drops the tip in the trash >>> p200.drop_tip() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> p200.pick_up_tip(tiprack[1]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # drops the tip back at its tip rack >>> p200.drop_tip(tiprack[1]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ def _setup(): nonlocal location if not location and self.trash_container: location = self.trash_container if isinstance(location, Placeable): # give space for the drop-tip mechanism location = location.bottom(self._drop_tip_offset) self._associate_placeable(location) self.current_tip_home_well = None self.current_volume = 0 def _do(): nonlocal location if location: self.move_to(location, strategy='arc', enqueue=False) self.motor.move(self._get_plunger_position('drop_tip')) self.motor.home() self.motor.move(self._get_plunger_position('bottom')) _description = "Drop_tip at {}".format( (humanize_location(location) if location else '<In Place>') ) self.create_command( do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def pick_up_tip(self, location=None, enqueue=True): """ 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` enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately 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 ...> """ 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 _do(): nonlocal location if location: self.move_to(location, strategy='arc', enqueue=False) tip_plunge = 6 self.robot.move_head(z=tip_plunge, mode='relative') self.robot.move_head(z=-tip_plunge - 1, mode='relative') self.robot.move_head(z=tip_plunge + 1, mode='relative') self.robot.move_head(z=-tip_plunge, mode='relative') _description = "Picking up tip from {0}".format( (humanize_location(location) if location else '<In Place>') ) self.create_command( do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def dispense(self, volume=None, location=None, rate=1.0, enqueue=True): """ Dispense a volume of liquid (in microliters/uL) using this pipette Notes ----- If no `location` is passed, the pipette will dispense from it's current position. If no `volume` is passed, `dispense` will default to it's `current_volume` Parameters ---------- volume : int or float The number of microliters to dispense (Default: self.current_volume) location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the dispense. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` rate : float Set plunger speed for this dispense, where speed = rate * dispense_speed (see :meth:`set_speed`) enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(axis='a', max_volume=200) >>> # fill the pipette with liquid (200uL) >>> p200.aspirate(plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 50uL to a Well >>> p200.dispense(50, plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 50uL to the center of a well >>> relative_vector = plate[1].center() >>> p200.dispense(50, (plate[1], relative_vector)) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 20uL in place, at half the speed >>> p200.dispense(20, rate=0.5) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense the pipette's remaining volume (80uL) to a Well >>> p200.dispense(plate[2]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ def _setup(): nonlocal location nonlocal volume nonlocal rate if not isinstance(volume, (int, float, complex)): if volume and not location: location = volume volume = self.current_volume if not volume or (self.current_volume - volume < 0): volume = self.current_volume if isinstance(location, Placeable): location = location.bottom(1) self.current_volume -= volume self._associate_placeable(location) def _do(): nonlocal location nonlocal volume nonlocal rate self.move_to(location, strategy='arc', enqueue=False) distance = self._plunge_distance(self.current_volume) bottom = self._get_plunger_position('bottom') destination = bottom - distance speed = self.speeds['dispense'] * rate self.motor.speed(speed) self.motor.move(destination) _description = "Dispensing {0}uL at {1}".format( volume, (humanize_location(location) if location else '<In Place>') ) self.create_command( do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def aspirate(self, volume=None, location=None, rate=1.0, enqueue=True): """ Aspirate a volume of liquid (in microliters/uL) using this pipette Notes ----- If no `location` is passed, the pipette will aspirate from it's current position. If no `volume` is passed, `aspirate` will default to it's `max_volume` Parameters ---------- volume : int or float The number of microliters to aspirate (Default: self.max_volume) location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the aspirate. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` rate : float Set plunger speed for this aspirate, where speed = rate * aspirate_speed (see :meth:`set_speed`) enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(axis='a', max_volume=200) >>> # aspirate 50uL from a Well >>> p200.aspirate(50, plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate 50uL from the center of a well >>> relative_vector = plate[1].center() >>> p200.aspirate(50, (plate[1], relative_vector)) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate 20uL in place, twice as fast >>> p200.aspirate(20, rate=2.0) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate the pipette's remaining volume (80uL) from a Well >>> p200.aspirate(plate[2]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ # set True if volume before this aspirate was 0uL plunger_empty = False def _setup(): nonlocal volume nonlocal location nonlocal rate nonlocal plunger_empty if not isinstance(volume, (int, float, complex)): if volume and not location: location = volume volume = self.max_volume - self.current_volume if self.current_volume + volume > self.max_volume: raise RuntimeWarning( 'Pipette ({0}) cannot hold volume {1}' .format( self.max_volume, self.current_volume + volume) ) if self.current_volume == 0: plunger_empty = True self.current_volume += volume self._associate_placeable(location) def _do(): nonlocal volume nonlocal location nonlocal rate nonlocal plunger_empty distance = self._plunge_distance(self.current_volume) bottom = self._get_plunger_position('bottom') destination = bottom - distance speed = self.speeds['aspirate'] * rate self._position_for_aspirate(location, plunger_empty) self.motor.speed(speed) self.motor.move(destination) _description = "Aspirating {0}uL at {1}".format( volume, (humanize_location(location) if location else '<In Place>') ) self.create_command( do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def drop_tip(self, location=None, enqueue=True): """ Drop the pipette's current tip Notes ----- If no location is passed, the pipette defaults to its `trash_container` (see :any:`Pipette`) Parameters ---------- location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the drop_tip. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> robot.reset() # doctest: +ELLIPSIS <opentrons.robot.robot.Robot object at ...> >>> tiprack = containers.load('tiprack-200ul', 'A1') >>> trash = containers.load('point', 'A1') >>> p200 = instruments.Pipette(axis='a', trash_container=trash) >>> p200.pick_up_tip(tiprack[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # drops the tip in the trash >>> p200.drop_tip() # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> p200.pick_up_tip(tiprack[1]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # drops the tip back at its tip rack >>> p200.drop_tip(tiprack[1]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ def _setup(): nonlocal location if not location and self.trash_container: location = self.trash_container if isinstance(location, Placeable): # give space for the drop-tip mechanism location = location.bottom(self._drop_tip_offset) self._associate_placeable(location) self.current_tip_home_well = None self.current_volume = 0 def _do(): nonlocal location if location: self.move_to(location, strategy='arc', enqueue=False) self.motor.move(self._get_plunger_position('drop_tip')) self.motor.home() self.motor.move(self._get_plunger_position('bottom')) _description = "Drop_tip at {}".format( (humanize_location(location) if location else '<In Place>')) self.create_command(do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def pick_up_tip(self, location=None, enqueue=True): """ 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` enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately 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 ...> """ 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 _do(): nonlocal location if location: self.move_to(location, strategy='arc', enqueue=False) tip_plunge = 6 self.robot.move_head(z=tip_plunge, mode='relative') self.robot.move_head(z=-tip_plunge - 1, mode='relative') self.robot.move_head(z=tip_plunge + 1, mode='relative') self.robot.move_head(z=-tip_plunge, mode='relative') _description = "Picking up tip from {0}".format( (humanize_location(location) if location else '<In Place>')) self.create_command(do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def dispense(self, volume=None, location=None, rate=1.0, enqueue=True): """ Dispense a volume of liquid (in microliters/uL) using this pipette Notes ----- If no `location` is passed, the pipette will dispense from it's current position. If no `volume` is passed, `dispense` will default to it's `current_volume` Parameters ---------- volume : int or float The number of microliters to dispense (Default: self.current_volume) location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the dispense. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` rate : float Set plunger speed for this dispense, where speed = rate * dispense_speed (see :meth:`set_speed`) enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(axis='a', max_volume=200) >>> # fill the pipette with liquid (200uL) >>> p200.aspirate(plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 50uL to a Well >>> p200.dispense(50, plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 50uL to the center of a well >>> relative_vector = plate[1].center() >>> p200.dispense(50, (plate[1], relative_vector)) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense 20uL in place, at half the speed >>> p200.dispense(20, rate=0.5) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # dispense the pipette's remaining volume (80uL) to a Well >>> p200.dispense(plate[2]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ def _setup(): nonlocal location nonlocal volume nonlocal rate if not isinstance(volume, (int, float, complex)): if volume and not location: location = volume volume = self.current_volume if not volume or (self.current_volume - volume < 0): volume = self.current_volume if isinstance(location, Placeable): location = location.bottom(1) self.current_volume -= volume self._associate_placeable(location) def _do(): nonlocal location nonlocal volume nonlocal rate self.move_to(location, strategy='arc', enqueue=False) distance = self._plunge_distance(self.current_volume) bottom = self._get_plunger_position('bottom') destination = bottom - distance speed = self.speeds['dispense'] * rate self.motor.speed(speed) self.motor.move(destination) _description = "Dispensing {0}uL at {1}".format( volume, (humanize_location(location) if location else '<In Place>')) self.create_command(do=_do, setup=_setup, description=_description, enqueue=enqueue) return self
def aspirate(self, volume=None, location=None, rate=1.0, enqueue=True): """ Aspirate a volume of liquid (in microliters/uL) using this pipette Notes ----- If no `location` is passed, the pipette will aspirate from it's current position. If no `volume` is passed, `aspirate` will default to it's `max_volume` Parameters ---------- volume : int or float The number of microliters to aspirate (Default: self.max_volume) location : :any:`Placeable` or tuple(:any:`Placeable`, :any:`Vector`) The :any:`Placeable` (:any:`Well`) to perform the aspirate. Can also be a tuple with first item :any:`Placeable`, second item relative :any:`Vector` rate : float Set plunger speed for this aspirate, where speed = rate * aspirate_speed (see :meth:`set_speed`) enqueue : bool If set to `True` (default), the method will be appended to the robots list of commands for executing during :any:`run` or :any:`simulate`. If set to `False`, the method will skip the command queue and execute immediately Returns ------- This instance of :class:`Pipette`. Examples -------- .. >>> p200 = instruments.Pipette(axis='a', max_volume=200) >>> # aspirate 50uL from a Well >>> p200.aspirate(50, plate[0]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate 50uL from the center of a well >>> relative_vector = plate[1].center() >>> p200.aspirate(50, (plate[1], relative_vector)) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate 20uL in place, twice as fast >>> p200.aspirate(20, rate=2.0) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> >>> # aspirate the pipette's remaining volume (80uL) from a Well >>> p200.aspirate(plate[2]) # doctest: +ELLIPSIS <opentrons.instruments.pipette.Pipette object at ...> """ # set True if volume before this aspirate was 0uL plunger_empty = False def _setup(): nonlocal volume nonlocal location nonlocal rate nonlocal plunger_empty if not isinstance(volume, (int, float, complex)): if volume and not location: location = volume volume = self.max_volume - self.current_volume if self.current_volume + volume > self.max_volume: raise RuntimeWarning( 'Pipette ({0}) cannot hold volume {1}'.format( self.max_volume, self.current_volume + volume)) if self.current_volume == 0: plunger_empty = True self.current_volume += volume self._associate_placeable(location) def _do(): nonlocal volume nonlocal location nonlocal rate nonlocal plunger_empty distance = self._plunge_distance(self.current_volume) bottom = self._get_plunger_position('bottom') destination = bottom - distance speed = self.speeds['aspirate'] * rate self._position_for_aspirate(location, plunger_empty) self.motor.speed(speed) self.motor.move(destination) _description = "Aspirating {0}uL at {1}".format( volume, (humanize_location(location) if location else '<In Place>')) self.create_command(do=_do, setup=_setup, description=_description, enqueue=enqueue) return self