Skip to content

Commit

Permalink
first pass: add fluid handling
Browse files Browse the repository at this point in the history
  • Loading branch information
sfoster1 committed Oct 30, 2024
1 parent 633e0d0 commit cd8ae17
Show file tree
Hide file tree
Showing 19 changed files with 548 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from ..errors.error_occurrence import ErrorOccurrence
from ..errors.exceptions import PipetteNotReadyToAspirateError
from ..state.update_types import StateUpdate
from ..types import AspiratedFluid, FluidKind

if TYPE_CHECKING:
from ..execution import PipettingHandler, GantryMover
Expand All @@ -48,7 +49,7 @@ class AirGapInPlaceResult(BaseLiquidHandlingResult):


_ExecuteReturn = Union[
SuccessData[AirGapInPlaceResult, None],
SuccessData[AirGapInPlaceResult],
DefinedErrorData[OverpressureError],
]

Expand Down Expand Up @@ -128,9 +129,12 @@ async def execute(self, params: AirGapInPlaceParams) -> _ExecuteReturn:
state_update=state_update,
)
else:
state_update.set_fluid_aspirated(
pipette_id=params.pipetteId,
fluid=AspiratedFluid(kind=FluidKind.AIR, volume=volume),
)
return SuccessData(
public=AirGapInPlaceResult(volume=volume),
private=None,
state_update=state_update,
)

Expand Down
14 changes: 13 additions & 1 deletion api/src/opentrons/protocol_engine/commands/aspirate.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@
from opentrons.hardware_control import HardwareControlAPI

from ..state.update_types import StateUpdate, CLEAR
from ..types import WellLocation, WellOrigin, CurrentWell, DeckPoint
from ..types import (
WellLocation,
WellOrigin,
CurrentWell,
DeckPoint,
AspiratedFluid,
FluidKind,
)

if TYPE_CHECKING:
from ..execution import MovementHandler, PipettingHandler
Expand Down Expand Up @@ -141,6 +148,7 @@ async def execute(self, params: AspirateParams) -> _ExecuteReturn:
well_name=well_name,
volume_added=CLEAR,
)
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
Expand All @@ -162,6 +170,10 @@ async def execute(self, params: AspirateParams) -> _ExecuteReturn:
well_name=well_name,
volume_added=-volume_aspirated,
)
state_update.set_fluid_aspirated(
pipette_id=params.pipetteId,
fluid=AspiratedFluid(kind=FluidKind.LIQUID, volume=volume_aspirated),
)
return SuccessData(
public=AspirateResult(
volume=volume_aspirated,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from ..errors.error_occurrence import ErrorOccurrence
from ..errors.exceptions import PipetteNotReadyToAspirateError
from ..state.update_types import StateUpdate, CLEAR
from ..types import CurrentWell
from ..types import CurrentWell, AspiratedFluid, FluidKind

if TYPE_CHECKING:
from ..execution import PipettingHandler, GantryMover
Expand Down Expand Up @@ -115,6 +115,7 @@ async def execute(self, params: AspirateInPlaceParams) -> _ExecuteReturn:
well_name=current_location.well_name,
volume_added=CLEAR,
)
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
Expand All @@ -139,6 +140,10 @@ async def execute(self, params: AspirateInPlaceParams) -> _ExecuteReturn:
state_update=state_update,
)
else:
state_update.set_fluid_aspirated(
pipette_id=params.pipetteId,
fluid=AspiratedFluid(kind=FluidKind.LIQUID, volume=volume),
)
if (
isinstance(current_location, CurrentWell)
and current_location.pipette_id == params.pipetteId
Expand All @@ -148,6 +153,7 @@ async def execute(self, params: AspirateInPlaceParams) -> _ExecuteReturn:
well_name=current_location.well_name,
volume_added=-volume,
)

return SuccessData(
public=AspirateInPlaceResult(volume=volume),
state_update=state_update,
Expand Down
3 changes: 3 additions & 0 deletions api/src/opentrons/protocol_engine/commands/blow_out.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ async def execute(self, params: BlowOutParams) -> _ExecuteReturn:
pipette_id=params.pipetteId, flow_rate=params.flowRate
)
except PipetteOverpressureError as e:
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
Expand All @@ -112,8 +113,10 @@ async def execute(self, params: BlowOutParams) -> _ExecuteReturn:
)
},
),
state_update=state_update,
)
else:
state_update.set_fluid_empty(pipette_id=params.pipetteId)
return SuccessData(
public=BlowOutResult(position=deck_point),
state_update=state_update,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
SuccessData,
)
from ..errors.error_occurrence import ErrorOccurrence
from ..state import update_types

from opentrons.hardware_control import HardwareControlAPI

Expand Down Expand Up @@ -72,12 +73,14 @@ def __init__(

async def execute(self, params: BlowOutInPlaceParams) -> _ExecuteReturn:
"""Blow-out without moving the pipette."""
state_update = update_types.StateUpdate()
try:
current_position = await self._gantry_mover.get_position(params.pipetteId)
await self._pipetting.blow_out_in_place(
pipette_id=params.pipetteId, flow_rate=params.flowRate
)
except PipetteOverpressureError as e:
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
Expand All @@ -97,8 +100,10 @@ async def execute(self, params: BlowOutInPlaceParams) -> _ExecuteReturn:
)
},
),
state_update=state_update,
)
else:
state_update.set_fluid_empty(pipette_id=params.pipetteId)
return SuccessData(
public=BlowOutInPlaceResult(),
)
Expand Down
9 changes: 8 additions & 1 deletion api/src/opentrons/protocol_engine/commands/dispense.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ async def execute(self, params: DispenseParams) -> _ExecuteReturn:
well_name=well_name,
volume_added=CLEAR,
)
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
Expand All @@ -128,11 +129,17 @@ async def execute(self, params: DispenseParams) -> _ExecuteReturn:
state_update=state_update,
)
else:
volume_added = (
self._state_view.pipettes.get_liquid_dispensed_by_ejecting_volume(
pipette_id=params.pipetteId, volume=volume
)
)
state_update.set_liquid_operated(
labware_id=labware_id,
well_name=well_name,
volume_added=volume,
volume_added=volume_added if volume_added is not None else CLEAR,
)
state_update.set_fluid_ejected(pipette_id=params.pipetteId, volume=volume)
return SuccessData(
public=DispenseResult(volume=volume, position=deck_point),
state_update=state_update,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ async def execute(self, params: DispenseInPlaceParams) -> _ExecuteReturn:
well_name=current_location.well_name,
volume_added=CLEAR,
)
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
Expand All @@ -118,14 +119,20 @@ async def execute(self, params: DispenseInPlaceParams) -> _ExecuteReturn:
state_update=state_update,
)
else:
state_update.set_fluid_ejected(pipette_id=params.pipetteId, volume=volume)
if (
isinstance(current_location, CurrentWell)
and current_location.pipette_id == params.pipetteId
):
volume_added = (
self._state_view.pipettes.get_liquid_dispensed_by_ejecting_volume(
pipette_id=params.pipetteId, volume=volume
)
)
state_update.set_liquid_operated(
labware_id=current_location.labware_id,
well_name=current_location.well_name,
volume_added=volume,
volume_added=volume_added if volume_added is not None else CLEAR,
)
return SuccessData(
public=DispenseInPlaceResult(volume=volume),
Expand Down
3 changes: 3 additions & 0 deletions api/src/opentrons/protocol_engine/commands/drop_tip.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,15 @@ async def execute(self, params: DropTipParams) -> _ExecuteReturn:
state_update_if_false_positive.update_pipette_tip_state(
pipette_id=params.pipetteId, tip_geometry=None
)
state_update.set_fluid_unknown(pipette_id=pipette_id)
state_update_if_false_positive.set_fluid_unknown(pipette_id=pipette_id)
return DefinedErrorData(
public=error,
state_update=state_update,
state_update_if_false_positive=state_update_if_false_positive,
)
else:
state_update.set_fluid_unknown(pipette_id=pipette_id)
state_update.update_pipette_tip_state(
pipette_id=params.pipetteId, tip_geometry=None
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ def __init__(
async def execute(self, params: DropTipInPlaceParams) -> _ExecuteReturn:
"""Drop a tip using the requested pipette."""
state_update = update_types.StateUpdate()

try:
await self._tip_handler.drop_tip(
pipette_id=params.pipetteId, home_after=params.homeAfter
Expand All @@ -75,6 +74,10 @@ async def execute(self, params: DropTipInPlaceParams) -> _ExecuteReturn:
state_update_if_false_positive.update_pipette_tip_state(
pipette_id=params.pipetteId, tip_geometry=None
)
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
state_update_if_false_positive.set_fluid_unknown(
pipette_id=params.pipetteId
)
error = TipPhysicallyAttachedError(
id=self._model_utils.generate_id(),
createdAt=self._model_utils.get_timestamp(),
Expand All @@ -92,6 +95,7 @@ async def execute(self, params: DropTipInPlaceParams) -> _ExecuteReturn:
state_update_if_false_positive=state_update_if_false_positive,
)
else:
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
state_update.update_pipette_tip_state(
pipette_id=params.pipetteId, tip_geometry=None
)
Expand Down
1 change: 1 addition & 0 deletions api/src/opentrons/protocol_engine/commands/load_pipette.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ async def execute(
serial_number=loaded_pipette.serial_number,
config=loaded_pipette.static_config,
)
state_update.set_fluid_unknown(pipette_id=loaded_pipette.pipette_id)

return SuccessData(
public=LoadPipetteResult(pipetteId=loaded_pipette.pipette_id),
Expand Down
1 change: 1 addition & 0 deletions api/src/opentrons/protocol_engine/commands/pick_up_tip.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ async def execute(
state_update.mark_tips_as_used(
pipette_id=pipette_id, labware_id=labware_id, well_name=well_name
)
state_update.set_fluid_empty(pipette_id=pipette_id)
return SuccessData(
public=PickUpTipResult(
tipVolume=tip_geometry.volume,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
SuccessData,
)
from ..errors.error_occurrence import ErrorOccurrence
from ..state import update_types

if TYPE_CHECKING:
from ..execution import PipettingHandler, GantryMover
Expand Down Expand Up @@ -64,11 +65,13 @@ def __init__(
async def execute(self, params: PrepareToAspirateParams) -> _ExecuteReturn:
"""Prepare the pipette to aspirate."""
current_position = await self._gantry_mover.get_position(params.pipetteId)
state_update = update_types.StateUpdate()
try:
await self._pipetting_handler.prepare_for_aspirate(
pipette_id=params.pipetteId,
)
except PipetteOverpressureError as e:
state_update.set_fluid_unknown(pipette_id=params.pipetteId)
return DefinedErrorData(
public=OverpressureError(
id=self._model_utils.generate_id(),
Expand All @@ -90,10 +93,12 @@ async def execute(self, params: PrepareToAspirateParams) -> _ExecuteReturn:
}
),
),
state_update=state_update,
)
else:
state_update.set_fluid_empty(pipette_id=params.pipetteId)
return SuccessData(
public=PrepareToAspirateResult(),
public=PrepareToAspirateResult(), state_update=state_update
)


Expand Down
Loading

0 comments on commit cd8ae17

Please sign in to comment.