Skip to content

Commit

Permalink
Merge branch 'edge' into local-code-snapshots
Browse files Browse the repository at this point in the history
  • Loading branch information
y3rsh committed Oct 21, 2024
2 parents 5b27837 + d2829dd commit 0af4c1b
Show file tree
Hide file tree
Showing 196 changed files with 1,771 additions and 793 deletions.
1 change: 1 addition & 0 deletions api/src/opentrons/cli/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ async def _do_analyze(
liquids=[],
wells=[],
hasEverEnteredErrorRecovery=False,
files=[],
),
parameters=[],
)
Expand Down
1 change: 1 addition & 0 deletions api/src/opentrons/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ def _create_live_context_pe(
hardware_api=hardware_api_wrapped,
config=_get_protocol_engine_config(),
deck_configuration=entrypoint_util.get_deck_configuration(),
file_provider=None,
error_recovery_policy=error_recovery_policy.never_recover,
drop_tips_after_run=False,
post_run_hardware_state=PostRunHardwareState.STAY_ENGAGED_IN_PLACE,
Expand Down
23 changes: 18 additions & 5 deletions api/src/opentrons/hardware_control/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1241,10 +1241,10 @@ async def pick_up_tip(
if prep_after:
await self.prepare_for_aspirate(mount)

async def drop_tip(self, mount: top_types.Mount, home_after: bool = True) -> None:
"""Drop tip at the current location."""

spec, _remove = self.plan_check_drop_tip(mount, home_after)
async def tip_drop_moves(
self, mount: top_types.Mount, home_after: bool = True
) -> None:
spec, _ = self.plan_check_drop_tip(mount, home_after)

for move in spec.drop_moves:
self._backend.set_active_current(move.current)
Expand Down Expand Up @@ -1272,7 +1272,20 @@ async def drop_tip(self, mount: top_types.Mount, home_after: bool = True) -> Non
await self.move_rel(mount, shake[0], speed=shake[1])

self._backend.set_active_current(spec.ending_current)
_remove()

async def drop_tip(self, mount: top_types.Mount, home_after: bool = True) -> None:
"""Drop tip at the current location."""
await self.tip_drop_moves(mount, home_after)

# todo(mm, 2024-10-17): Ideally, callers would be able to replicate the behavior
# of this method via self.drop_tip_moves() plus other public methods. This
# currently prevents that: there is no public equivalent for
# instrument.set_current_volume().
instrument = self.get_pipette(mount)
instrument.set_current_volume(0)

self.set_current_tiprack_diameter(mount, 0.0)
self.remove_tip(mount)

async def create_simulating_module(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ async def reset_nozzle_configuration(self, mount: MountType) -> None:
if instr:
instr.reset_nozzle_configuration()

async def add_tip(self, mount: MountType, tip_length: float) -> None:
def add_tip(self, mount: MountType, tip_length: float) -> None:
instr = self._attached_instruments[mount]
attached = self.attached_instruments
instr_dict = attached[mount]
Expand All @@ -430,7 +430,7 @@ async def add_tip(self, mount: MountType, tip_length: float) -> None:
f"attach tip called while tip already attached to {instr}"
)

async def remove_tip(self, mount: MountType) -> None:
def remove_tip(self, mount: MountType) -> None:
instr = self._attached_instruments[mount]
attached = self.attached_instruments
instr_dict = attached[mount]
Expand Down Expand Up @@ -929,6 +929,8 @@ def plan_check_drop_tip(
) -> Tuple[DropTipSpec, Callable[[], None]]:
...

# todo(mm, 2024-10-17): The returned _remove_tips() callable is not used by anything
# anymore. Delete it.
def plan_check_drop_tip( # type: ignore[no-untyped-def]
self,
mount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ async def reset_nozzle_configuration(self, mount: OT3Mount) -> None:
if instr:
instr.reset_nozzle_configuration()

async def add_tip(self, mount: OT3Mount, tip_length: float) -> None:
def add_tip(self, mount: OT3Mount, tip_length: float) -> None:
instr = self._attached_instruments[mount]
attached = self.attached_instruments
instr_dict = attached[mount]
Expand All @@ -440,7 +440,7 @@ async def add_tip(self, mount: OT3Mount, tip_length: float) -> None:
"attach tip called while tip already attached to {instr}"
)

async def remove_tip(self, mount: OT3Mount) -> None:
def remove_tip(self, mount: OT3Mount) -> None:
instr = self._attached_instruments[mount]
attached = self.attached_instruments
instr_dict = attached[mount]
Expand Down
12 changes: 6 additions & 6 deletions api/src/opentrons/hardware_control/ot3_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,13 +819,13 @@ async def find_pipette_offset(
try:
if reset_instrument_offset:
await hcapi.reset_instrument_offset(mount)
await hcapi.add_tip(mount, hcapi.config.calibration.probe_length)
hcapi.add_tip(mount, hcapi.config.calibration.probe_length)
offset = await _calibrate_mount(
hcapi, mount, slot, method, raise_verify_error, probe=probe
)
return offset
finally:
await hcapi.remove_tip(mount)
hcapi.remove_tip(mount)


async def calibrate_pipette(
Expand Down Expand Up @@ -877,7 +877,7 @@ async def calibrate_module(
if mount == OT3Mount.GRIPPER:
hcapi.add_gripper_probe(GripperProbe.FRONT)
else:
await hcapi.add_tip(mount, hcapi.config.calibration.probe_length)
hcapi.add_tip(mount, hcapi.config.calibration.probe_length)

LOG.info(
f"Starting module calibration for {module_id} at {nominal_position} using {mount}"
Expand All @@ -903,7 +903,7 @@ async def calibrate_module(
hcapi.remove_gripper_probe()
await hcapi.ungrip()
else:
await hcapi.remove_tip(mount)
hcapi.remove_tip(mount)


async def calibrate_belts(
Expand All @@ -927,15 +927,15 @@ async def calibrate_belts(
raise RuntimeError("Must use pipette mount, not gripper")
try:
hcapi.reset_deck_calibration()
await hcapi.add_tip(mount, hcapi.config.calibration.probe_length)
hcapi.add_tip(mount, hcapi.config.calibration.probe_length)
belt_attitude, alignment_details = await _determine_transform_matrix(
hcapi, mount
)
save_robot_belt_attitude(belt_attitude, pipette_id)
return belt_attitude, alignment_details
finally:
hcapi.load_deck_calibration()
await hcapi.remove_tip(mount)
hcapi.remove_tip(mount)


def apply_machine_transform(
Expand Down
37 changes: 23 additions & 14 deletions api/src/opentrons/hardware_control/ot3api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2289,17 +2289,10 @@ def set_working_volume(
)
instrument.working_volume = tip_volume

async def drop_tip(
async def tip_drop_moves(
self, mount: Union[top_types.Mount, OT3Mount], home_after: bool = False
) -> None:
"""Drop tip at the current location."""
realmount = OT3Mount.from_mount(mount)
instrument = self._pipette_handler.get_pipette(realmount)

def _remove_tips() -> None:
instrument.set_current_volume(0)
instrument.current_tiprack_diameter = 0.0
instrument.remove_tip()

await self._move_to_plunger_bottom(realmount, rate=1.0, check_current_vol=False)

Expand All @@ -2326,11 +2319,27 @@ def _remove_tips() -> None:
if home_after:
await self._home([Axis.by_mount(mount)])

_remove_tips()
# call this in case we're simulating
# call this in case we're simulating:
if isinstance(self._backend, OT3Simulator):
self._backend._update_tip_state(realmount, False)

async def drop_tip(
self, mount: Union[top_types.Mount, OT3Mount], home_after: bool = False
) -> None:
"""Drop tip at the current location."""
await self.tip_drop_moves(mount=mount, home_after=home_after)

# todo(mm, 2024-10-17): Ideally, callers would be able to replicate the behavior
# of this method via self.drop_tip_moves() plus other public methods. This
# currently prevents that: there is no public equivalent for
# instrument.set_current_volume().
realmount = OT3Mount.from_mount(mount)
instrument = self._pipette_handler.get_pipette(realmount)
instrument.set_current_volume(0)

self.set_current_tiprack_diameter(mount, 0.0)
self.remove_tip(mount)

async def clean_up(self) -> None:
"""Get the API ready to stop cleanly."""
await self._backend.clean_up()
Expand Down Expand Up @@ -2598,13 +2607,13 @@ async def update_nozzle_configuration_for_mount(
starting_nozzle,
)

async def add_tip(
def add_tip(
self, mount: Union[top_types.Mount, OT3Mount], tip_length: float
) -> None:
await self._pipette_handler.add_tip(OT3Mount.from_mount(mount), tip_length)
self._pipette_handler.add_tip(OT3Mount.from_mount(mount), tip_length)

async def remove_tip(self, mount: Union[top_types.Mount, OT3Mount]) -> None:
await self._pipette_handler.remove_tip(OT3Mount.from_mount(mount))
def remove_tip(self, mount: Union[top_types.Mount, OT3Mount]) -> None:
self._pipette_handler.remove_tip(OT3Mount.from_mount(mount))

def add_gripper_probe(self, probe: GripperProbe) -> None:
self._gripper_handler.add_probe(probe)
Expand Down
8 changes: 1 addition & 7 deletions api/src/opentrons/hardware_control/protocols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ class HardwareControlInterface(
def get_robot_type(self) -> Type[OT2RobotType]:
return OT2RobotType

def cache_tip(self, mount: MountArgType, tip_length: float) -> None:
...


class FlexHardwareControlInterface(
PositionEstimator,
Expand All @@ -87,12 +84,9 @@ class FlexHardwareControlInterface(
def get_robot_type(self) -> Type[FlexRobotType]:
return FlexRobotType

def cache_tip(self, mount: MountArgType, tip_length: float) -> None:
...


__all__ = [
"HardwareControlAPI",
"HardwareControlInterface",
"FlexHardwareControlInterface",
"Simulatable",
"Stoppable",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,20 @@ def get_instrument_max_height(
"""
...

async def add_tip(self, mount: MountArgType, tip_length: float) -> None:
# todo(mm, 2024-10-17): Consider deleting this in favor of cache_tip(), which is
# the same except for `assert`s, if we can do so without breaking anything.
def add_tip(self, mount: MountArgType, tip_length: float) -> None:
"""Inform the hardware that a tip is now attached to a pipette.
This changes the critical point of the pipette to make sure that
the end of the tip is what moves around, and allows liquid handling.
"""
...

async def remove_tip(self, mount: MountArgType) -> None:
def cache_tip(self, mount: MountArgType, tip_length: float) -> None:
...

def remove_tip(self, mount: MountArgType) -> None:
"""Inform the hardware that a tip is no longer attached to a pipette.
This changes the critical point of the system to the end of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ async def pick_up_tip(
"""
...

async def tip_drop_moves(
self, mount: MountArgType, home_after: bool = True
) -> None:
...

async def drop_tip(
self,
mount: MountArgType,
Expand Down
27 changes: 23 additions & 4 deletions api/src/opentrons/protocol_api/core/engine/module_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,11 +586,20 @@ def initialize(
)
self._initialized_value = wavelengths

def read(self) -> Optional[Dict[int, Dict[str, float]]]:
"""Initiate a read on the Absorbance Reader, and return the results. During Analysis, this will return None."""
def read(self, filename: Optional[str]) -> Dict[int, Dict[str, float]]:
"""Initiate a read on the Absorbance Reader, and return the results. During Analysis, this will return a measurement of zero for all wells."""
wavelengths = self._engine_client.state.modules.get_absorbance_reader_substate(
self.module_id
).configured_wavelengths
if wavelengths is None:
raise CannotPerformModuleAction(
"Cannot perform Read action on Absorbance Reader without calling `.initialize(...)` first."
)
if self._initialized_value:
self._engine_client.execute_command(
cmd.absorbance_reader.ReadAbsorbanceParams(moduleId=self.module_id)
cmd.absorbance_reader.ReadAbsorbanceParams(
moduleId=self.module_id, fileName=filename
)
)
if not self._engine_client.state.config.use_virtual_modules:
read_result = (
Expand All @@ -603,7 +612,17 @@ def read(self) -> Optional[Dict[int, Dict[str, float]]]:
raise CannotPerformModuleAction(
"Absorbance Reader failed to return expected read result."
)
return None

# When using virtual modules, return all zeroes
virtual_asbsorbance_result: Dict[int, Dict[str, float]] = {}
for wavelength in wavelengths:
converted_values = (
self._engine_client.state.modules.convert_absorbance_reader_data_points(
data=[0] * 96
)
)
virtual_asbsorbance_result[wavelength] = converted_values
return virtual_asbsorbance_result

def close_lid(
self,
Expand Down
2 changes: 1 addition & 1 deletion api/src/opentrons/protocol_api/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ def initialize(
"""Initialize the Absorbance Reader by taking zero reading."""

@abstractmethod
def read(self) -> Optional[Dict[int, Dict[str, float]]]:
def read(self, filename: Optional[str]) -> Dict[int, Dict[str, float]]:
"""Get an absorbance reading from the Absorbance Reader."""

@abstractmethod
Expand Down
17 changes: 14 additions & 3 deletions api/src/opentrons/protocol_api/module_contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,17 @@ def initialize(
)

@requires_version(2, 21)
def read(self) -> Optional[Dict[int, Dict[str, float]]]:
"""Initiate read on the Absorbance Reader. Returns a dictionary of wavelengths to dictionary of values ordered by well name."""
return self._core.read()
def read(self, export_filename: Optional[str]) -> Dict[int, Dict[str, float]]:
"""Initiate read on the Absorbance Reader.
Returns a dictionary of wavelengths to dictionary of values ordered by well name.
:param export_filename: Optional, if a filename is provided a CSV file will be saved
as a result of the read action containing measurement data. The filename will
be modified to include the wavelength used during measurement. If multiple
measurements are taken, then a file will be generated for each wavelength provided.
Example: If `export_filename="my_data"` and wavelengths 450 and 531 are used during
measurement, the output files will be "my_data_450.csv" and "my_data_531.csv".
"""
return self._core.read(filename=export_filename)
Loading

0 comments on commit 0af4c1b

Please sign in to comment.