Skip to content

Commit

Permalink
fix(api): Flex 2 15 api fixed trash auto tipdrop support (#14225)
Browse files Browse the repository at this point in the history
ensures that all OT2 protocols auto drop tips regardless of version, and that only Flex protocols 2.15 and prior auto drop tips
  • Loading branch information
CaseyBatten authored Dec 15, 2023
1 parent 3135a08 commit 9a05d1f
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 21 deletions.
41 changes: 24 additions & 17 deletions api/src/opentrons/protocol_engine/execution/hardware_stopper.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,23 @@ async def _drop_tip(self) -> None:

await self._home_everything_except_plungers()

# OT-2 Will only ever use the Fixed Trash Addressable Area
if self._state_store.config.robot_type == "OT-2 Standard":
for pipette_id, tip in attached_tips:
try:
for pipette_id, tip in attached_tips:
try:
if self._state_store.labware.get_fixed_trash_id() == FIXED_TRASH_ID:
# OT-2 and Flex 2.15 protocols will default to the Fixed Trash Labware
await self._tip_handler.add_tip(pipette_id=pipette_id, tip=tip)
await self._movement_handler.move_to_well(
pipette_id=pipette_id,
labware_id=FIXED_TRASH_ID,
well_name="A1",
)
await self._tip_handler.drop_tip(
pipette_id=pipette_id,
home_after=False,
)
elif self._state_store.config.robot_type == "OT-2 Standard":
# API 2.16 and above OT2 protocols use addressable areas
await self._tip_handler.add_tip(pipette_id=pipette_id, tip=tip)
# TODO: Add ability to drop tip onto custom trash as well.
# if API is 2.15 and below aka is should_have_fixed_trash

await self._movement_handler.move_to_addressable_area(
pipette_id=pipette_id,
addressable_area_name="fixedTrash",
Expand All @@ -90,21 +99,19 @@ async def _drop_tip(self) -> None:
speed=None,
minimum_z_height=None,
)

await self._tip_handler.drop_tip(
pipette_id=pipette_id,
home_after=False,
)
else:
log.debug(
"Flex Protocols API Version 2.16 and beyond do not support automatic tip dropping at this time."
)

except HwPipetteNotAttachedError:
# this will happen normally during protocol analysis, but
# should not happen during an actual run
log.debug(f"Pipette ID {pipette_id} no longer attached.")

else:
log.debug(
"Flex protocols do not support automatic tip dropping at this time."
)
except HwPipetteNotAttachedError:
# this will happen normally during protocol analysis, but
# should not happen during an actual run
log.debug(f"Pipette ID {pipette_id} no longer attached.")

async def do_halt(self, disengage_before_stopping: bool = False) -> None:
"""Issue a halt signal to the hardware API.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
TipHandler,
HardwareStopper,
)
from opentrons.protocol_engine.types import MotorAxis, TipGeometry, PostRunHardwareState
from opentrons.protocol_engine.types import (
MotorAxis,
TipGeometry,
PostRunHardwareState,
AddressableOffsetVector,
)

if TYPE_CHECKING:
from opentrons.hardware_control.ot3api import OT3API
Expand Down Expand Up @@ -229,3 +234,107 @@ async def test_hardware_stopping_sequence_with_gripper(
),
await ot3_hardware_api.stop(home_after=True),
)


@pytest.mark.ot3_only
async def test_hardware_stopping_sequence_with_fixed_trash(
decoy: Decoy,
state_store: StateStore,
ot3_hardware_api: OT3API,
movement: MovementHandler,
mock_tip_handler: TipHandler,
) -> None:
"""It should stop the hardware, and home the robot. Flex no longer performs automatic drop tip."""
subject = HardwareStopper(
hardware_api=ot3_hardware_api,
state_store=state_store,
movement=movement,
tip_handler=mock_tip_handler,
)
decoy.when(state_store.pipettes.get_all_attached_tips()).then_return(
[
("pipette-id", TipGeometry(length=1.0, volume=2.0, diameter=3.0)),
]
)
decoy.when(state_store.labware.get_fixed_trash_id()).then_return("fixedTrash")
decoy.when(state_store.config.use_virtual_gripper).then_return(False)
decoy.when(ot3_hardware_api.has_gripper()).then_return(True)

await subject.do_stop_and_recover(
drop_tips_after_run=True,
post_run_hardware_state=PostRunHardwareState.HOME_AND_STAY_ENGAGED,
)

decoy.verify(
await ot3_hardware_api.stop(home_after=False),
await ot3_hardware_api.home_z(mount=OT3Mount.GRIPPER),
await movement.home(
axes=[MotorAxis.X, MotorAxis.Y, MotorAxis.LEFT_Z, MotorAxis.RIGHT_Z]
),
await mock_tip_handler.add_tip(
pipette_id="pipette-id",
tip=TipGeometry(length=1.0, volume=2.0, diameter=3.0),
),
await movement.move_to_well(
pipette_id="pipette-id",
labware_id="fixedTrash",
well_name="A1",
),
await mock_tip_handler.drop_tip(
pipette_id="pipette-id",
home_after=False,
),
await ot3_hardware_api.stop(home_after=True),
)


async def test_hardware_stopping_sequence_with_OT2_addressable_area(
decoy: Decoy,
state_store: StateStore,
hardware_api: HardwareAPI,
movement: MovementHandler,
mock_tip_handler: TipHandler,
) -> None:
"""It should stop the hardware, and home the robot. Flex no longer performs automatic drop tip."""
subject = HardwareStopper(
hardware_api=hardware_api,
state_store=state_store,
movement=movement,
tip_handler=mock_tip_handler,
)
decoy.when(state_store.pipettes.get_all_attached_tips()).then_return(
[
("pipette-id", TipGeometry(length=1.0, volume=2.0, diameter=3.0)),
]
)
decoy.when(state_store.config.robot_type).then_return("OT-2 Standard")
decoy.when(state_store.config.use_virtual_gripper).then_return(False)

await subject.do_stop_and_recover(
drop_tips_after_run=True,
post_run_hardware_state=PostRunHardwareState.HOME_AND_STAY_ENGAGED,
)

decoy.verify(
await hardware_api.stop(home_after=False),
await movement.home(
axes=[MotorAxis.X, MotorAxis.Y, MotorAxis.LEFT_Z, MotorAxis.RIGHT_Z]
),
await mock_tip_handler.add_tip(
pipette_id="pipette-id",
tip=TipGeometry(length=1.0, volume=2.0, diameter=3.0),
),
await movement.move_to_addressable_area(
pipette_id="pipette-id",
addressable_area_name="fixedTrash",
offset=AddressableOffsetVector(x=0, y=0, z=0),
force_direct=False,
speed=None,
minimum_z_height=None,
),
await mock_tip_handler.drop_tip(
pipette_id="pipette-id",
home_after=False,
),
await hardware_api.stop(home_after=True),
)
3 changes: 0 additions & 3 deletions robot-server/robot_server/runs/engine_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,6 @@ async def create(

post_run_hardware_state = PostRunHardwareState.HOME_AND_STAY_ENGAGED
drop_tips_after_run = True
if self._robot_type == "OT-3 Standard":
post_run_hardware_state = PostRunHardwareState.HOME_AND_STAY_ENGAGED
drop_tips_after_run = False

runner = create_protocol_runner(
protocol_engine=engine,
Expand Down

0 comments on commit 9a05d1f

Please sign in to comment.