Skip to content

Commit

Permalink
Catch all cases where the z height of the bottom of attached tips wou…
Browse files Browse the repository at this point in the history
…ld be lower than the top of gripped labware
  • Loading branch information
CaseyBatten committed Jan 18, 2024
1 parent 6a0e3fe commit fca8865
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
3 changes: 2 additions & 1 deletion api/src/opentrons/protocol_engine/commands/move_labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations
from pydantic import BaseModel, Field
from typing import TYPE_CHECKING, Optional, Type
from typing import TYPE_CHECKING, Optional, Type, List
from typing_extensions import Literal

from opentrons.types import Point
Expand Down Expand Up @@ -199,6 +199,7 @@ async def execute( # noqa: C901
pickUpOffset=params.pickUpOffset or LabwareOffsetVector(x=0, y=0, z=0),
dropOffset=params.dropOffset or LabwareOffsetVector(x=0, y=0, z=0),
)

# Skips gripper moves when using virtual gripper
await self._labware_movement.move_labware_with_gripper(
labware_id=params.labwareId,
Expand Down
36 changes: 35 additions & 1 deletion api/src/opentrons/protocol_engine/execution/labware_movement.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def __init__(
)
)

async def move_labware_with_gripper(
async def move_labware_with_gripper( # noqa: C901
self,
labware_id: str,
current_location: OnDeckLabwareLocation,
Expand All @@ -89,8 +89,25 @@ async def move_labware_with_gripper(
) -> None:
"""Move a loaded labware from one location to another using gripper."""
use_virtual_gripper = self._state_store.config.use_virtual_gripper

if use_virtual_gripper:
# During Analysis we will pass in hard coded estimates for certain positions on accessible during execution
# Estimated gripper homed position Z: 253.575 + 93.85 - 94.825 - 86.475 = 166.125 mm
attached_tips = self._state_store.pipettes.get_all_attached_tips()
if attached_tips:
for pipette_id, tip in attached_tips:
if not self._state_store.geometry.validate_gripper_labware_tip_collision(
gripper_homed_position_z=166.125,
pipettes_homed_position_z=248.0,
tip=tip,
labware_id=labware_id,
current_location=current_location,
):
raise LabwareMovementNotAllowedError(
f"Cannot move labware '{self._state_store.labware.get(labware_id).loadName}' when {int(tip.volume)} ul tips are attached."
)
return

ot3api = ensure_ot3_hardware(
hardware_api=self._hardware_api,
error_msg="Gripper is only available on Opentrons Flex",
Expand All @@ -111,6 +128,23 @@ async def move_labware_with_gripper(
await ot3api.home(axes=[Axis.Z_L, Axis.Z_R, Axis.Z_G])
gripper_homed_position = await ot3api.gantry_position(mount=gripper_mount)

# Verify that no tip collisions will occur during the move
attached_tips = self._state_store.pipettes.get_all_attached_tips()
if attached_tips:
for pipette_id, tip in attached_tips:
pipetted_homed_position = await ot3api.gantry_position(mount=self._state_store.pipettes.get_mount(pipette_id))

if not self._state_store.geometry.validate_gripper_labware_tip_collision(
gripper_homed_position_z=gripper_homed_position.z,
pipettes_homed_position_z=pipetted_homed_position.z,
tip=tip,
labware_id=labware_id,
current_location=current_location,
):
raise LabwareMovementNotAllowedError(
f"Cannot move labware '{self._state_store.labware.get(labware_id).loadName}' when {int(tip.volume)} ul tips are attached."
)

async with self._thermocycler_plate_lifter.lift_plate_for_labware_movement(
labware_location=current_location
):
Expand Down
23 changes: 23 additions & 0 deletions api/src/opentrons/protocol_engine/state/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from opentrons.types import Point, DeckSlotName, StagingSlotName, MountType
from opentrons_shared_data.labware.constants import WELL_NAME_PATTERN


from .. import errors
from ..errors import LabwareNotLoadedOnLabwareError, LabwareNotLoadedOnModuleError
from ..resources import fixture_validation
Expand Down Expand Up @@ -977,6 +978,28 @@ def get_total_nominal_gripper_offset_for_move_type(
).dropOffset
)

def validate_gripper_labware_tip_collision(
self,
gripper_homed_position_z: float,
pipettes_homed_position_z: float,
tip: TipGeometry,
labware_id: str,
current_location: OnDeckLabwareLocation,
) -> bool:
"""Check for potential collision of tips against labware to be lifted."""
labware_top_z_when_gripped = gripper_homed_position_z + (
self.get_labware_highest_z(labware_id=labware_id)
- self.get_labware_grip_point(
labware_id=labware_id, location=current_location
).z
)
# TODO(mm, 2024-01-18): Utilizing the nozzle map and labware X coordinates verify if collisions will occur on the X axis (analysis will use hard coded data to measure from the gripper critical point to the pipette mount)

tip_bottom_z = pipettes_homed_position_z - tip.length
if tip_bottom_z < labware_top_z_when_gripped:
return False
return True

def _nominal_gripper_offsets_for_location(
self, location: OnDeckLabwareLocation
) -> LabwareMovementOffsetData:
Expand Down

0 comments on commit fca8865

Please sign in to comment.