Skip to content

Commit

Permalink
added correction_volume arg/ param to engine and hardware control asp…
Browse files Browse the repository at this point in the history
…irate and dispense methods
  • Loading branch information
sanni-t committed Jan 21, 2025
1 parent 35686bc commit 6875002
Show file tree
Hide file tree
Showing 23 changed files with 194 additions and 21 deletions.
2 changes: 2 additions & 0 deletions api/src/opentrons/hardware_control/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ async def aspirate(
mount: top_types.Mount,
volume: Optional[float] = None,
rate: float = 1.0,
correction_volume: float = 0.0,
) -> None:
"""
Aspirate a volume of liquid (in microliters/uL) using this pipette.
Expand Down Expand Up @@ -1073,6 +1074,7 @@ async def dispense(
volume: Optional[float] = None,
rate: float = 1.0,
push_out: Optional[float] = None,
correction_volume: float = 0.0,
) -> None:
"""
Dispense a volume of liquid in microliters(uL) using this pipette.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,11 @@ def ready_for_tip_action(
self._ihp_log.debug(f"{action} on {target.name}")

def plunger_position(
self, instr: Pipette, ul: float, action: "UlPerMmAction"
self,
instr: Pipette,
ul: float,
action: "UlPerMmAction",
correction_volume: float = 0.0,
) -> float:
mm = ul / instr.ul_per_mm(ul, action)
position = instr.plunger_positions.bottom - mm
Expand Down Expand Up @@ -531,6 +535,7 @@ def plan_check_aspirate(
mount: OT3Mount,
volume: Optional[float],
rate: float,
correction_volume: float = 0.0,
) -> Optional[LiquidActionSpec]:
"""Check preconditions for aspirate, parse args, and calculate positions.
Expand Down Expand Up @@ -566,7 +571,10 @@ def plan_check_aspirate(
), "Cannot aspirate more than pipette max volume"

dist = self.plunger_position(
instrument, instrument.current_volume + asp_vol, "aspirate"
instr=instrument,
ul=instrument.current_volume + asp_vol,
action="aspirate",
correction_volume=correction_volume,
)
speed = self.plunger_speed(
instrument, instrument.aspirate_flow_rate * rate, "aspirate"
Expand All @@ -591,6 +599,7 @@ def plan_check_dispense(
volume: Optional[float],
rate: float,
push_out: Optional[float],
correction_volume: float = 0.0,
) -> Optional[LiquidActionSpec]:
"""Check preconditions for dispense, parse args, and calculate positions.
Expand Down Expand Up @@ -659,7 +668,10 @@ def plan_check_dispense(
)

dist = self.plunger_position(
instrument, instrument.current_volume - disp_vol, "dispense"
instr=instrument,
ul=instrument.current_volume - disp_vol,
action="dispense",
correction_volume=correction_volume,
)
speed = self.plunger_speed(
instrument, instrument.dispense_flow_rate * rate, "dispense"
Expand Down
13 changes: 11 additions & 2 deletions api/src/opentrons/hardware_control/ot3api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2046,12 +2046,16 @@ async def aspirate(
mount: Union[top_types.Mount, OT3Mount],
volume: Optional[float] = None,
rate: float = 1.0,
correction_volume: float = 0.0,
) -> None:
"""
Aspirate a volume of liquid (in microliters/uL) using this pipette."""
realmount = OT3Mount.from_mount(mount)
aspirate_spec = self._pipette_handler.plan_check_aspirate(
realmount, volume, rate
mount=realmount,
volume=volume,
rate=rate,
correction_volume=correction_volume,
)
if not aspirate_spec:
return
Expand Down Expand Up @@ -2088,12 +2092,17 @@ async def dispense(
volume: Optional[float] = None,
rate: float = 1.0,
push_out: Optional[float] = None,
correction_volume: float = 0.0,
) -> None:
"""
Dispense a volume of liquid in microliters(uL) using this pipette."""
realmount = OT3Mount.from_mount(mount)
dispense_spec = self._pipette_handler.plan_check_dispense(
realmount, volume, rate, push_out
mount=realmount,
volume=volume,
rate=rate,
push_out=push_out,
correction_volume=correction_volume,
)
if not dispense_spec:
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ async def aspirate(
mount: MountArgType,
volume: Optional[float] = None,
rate: float = 1.0,
correction_volume: float = 0.0,
) -> None:
"""
Aspirate a volume of liquid (in microliters/uL) using this pipette
Expand All @@ -117,6 +118,7 @@ async def aspirate(
volume : [float] The number of microliters to aspirate
rate : [float] Set plunger speed for this aspirate, where
speed = rate * aspirate_speed
correction_volume : Correction volume in uL for the specified aspirate volume
"""
...

Expand All @@ -126,6 +128,7 @@ async def dispense(
volume: Optional[float] = None,
rate: float = 1.0,
push_out: Optional[float] = None,
correction_volume: float = 0.0,
) -> None:
"""
Dispense a volume of liquid in microliters(uL) using this pipette
Expand All @@ -136,6 +139,7 @@ async def dispense(
volume : [float] The number of microliters to dispense
rate : [float] Set plunger speed for this dispense, where
speed = rate * dispense_speed
correction_volume : Correction volume in uL for the specified dispense volume
"""
...

Expand Down
10 changes: 9 additions & 1 deletion api/src/opentrons/protocol_api/core/engine/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def aspirate(
flow_rate: float,
in_place: bool,
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
"""Aspirate a given volume of liquid from the specified location.
Args:
Expand All @@ -174,7 +175,10 @@ def aspirate(

self._engine_client.execute_command(
cmd.AspirateInPlaceParams(
pipetteId=self._pipette_id, volume=volume, flowRate=flow_rate
pipetteId=self._pipette_id,
volume=volume,
flowRate=flow_rate,
correctionVolume=correction_volume,
)
)

Expand Down Expand Up @@ -205,6 +209,7 @@ def aspirate(
wellLocation=well_location,
volume=volume,
flowRate=flow_rate,
correctionVolume=correction_volume,
)
)

Expand All @@ -220,6 +225,7 @@ def dispense(
in_place: bool,
push_out: Optional[float],
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
"""Dispense a given volume of liquid into the specified location.
Args:
Expand Down Expand Up @@ -267,6 +273,7 @@ def dispense(
volume=volume,
flowRate=flow_rate,
pushOut=push_out,
correctionVolume=correction_volume,
)
)
else:
Expand Down Expand Up @@ -297,6 +304,7 @@ def dispense(
volume=volume,
flowRate=flow_rate,
pushOut=push_out,
correctionVolume=correction_volume,
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ def aspirate_and_wait(self, volume: float) -> None:
"""Aspirate according to aspirate properties and wait if enabled."""
# TODO: handle volume correction
aspirate_props = self._transfer_properties.aspirate
correction_volume = aspirate_props.correction_by_volume.get_for_volume(volume)
self._instrument.aspirate(
location=self._target_location,
well_core=None,
Expand All @@ -169,6 +170,7 @@ def aspirate_and_wait(self, volume: float) -> None:
flow_rate=aspirate_props.flow_rate_by_volume.get_for_volume(volume),
in_place=True,
is_meniscus=None, # TODO: update this once meniscus is implemented
correction_volume=correction_volume,
)
self._tip_state.append_liquid(volume)
delay_props = aspirate_props.delay
Expand All @@ -183,6 +185,7 @@ def dispense_and_wait(
"""Dispense according to dispense properties and wait if enabled."""
# TODO: handle volume correction
dispense_props = self._transfer_properties.dispense
correction_volume = dispense_props.correction_by_volume.get_for_volume(volume)
self._instrument.dispense(
location=self._target_location,
well_core=None,
Expand All @@ -192,6 +195,7 @@ def dispense_and_wait(
in_place=True,
push_out=push_out_override,
is_meniscus=None,
correction_volume=correction_volume,
)
if push_out_override:
# If a push out was performed, we need to reset the plunger before we can aspirate again
Expand Down Expand Up @@ -538,6 +542,7 @@ def _remove_air_gap(self, location: Location) -> None:
in_place=True,
is_meniscus=None,
push_out=0,
correction_volume=None,
)
self._tip_state.delete_air_gap(last_air_gap)
dispense_delay = dispense_props.delay
Expand Down
4 changes: 4 additions & 0 deletions api/src/opentrons/protocol_api/core/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def aspirate(
flow_rate: float,
in_place: bool,
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
"""Aspirate a given volume of liquid from the specified location.
Args:
Expand All @@ -52,6 +53,7 @@ def aspirate(
rate: The rate for how quickly to aspirate.
flow_rate: The flow rate in µL/s to aspirate at.
in_place: Whether this is in-place.
correction_volume: The correction volume in uL
"""
...

Expand All @@ -66,6 +68,7 @@ def dispense(
in_place: bool,
push_out: Optional[float],
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
"""Dispense a given volume of liquid into the specified location.
Args:
Expand All @@ -76,6 +79,7 @@ def dispense(
flow_rate: The flow rate in µL/s to dispense at.
in_place: Whether this is in-place.
push_out: The amount to push the plunger below bottom position.
correction_volume: The correction volume in uL
"""
...

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def aspirate(
flow_rate: float,
in_place: bool,
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
"""Aspirate a given volume of liquid from the specified location.
Args:
Expand All @@ -95,6 +96,7 @@ def aspirate(
rate: The rate in µL/s to aspirate at.
flow_rate: Not used in this core.
in_place: Whether we should move_to location.
correction_volume: Not used in this core
"""
if self.get_current_volume() == 0:
# Make sure we're at the top of the labware and clear of any
Expand Down Expand Up @@ -129,6 +131,7 @@ def dispense(
in_place: bool,
push_out: Optional[float],
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
"""Dispense a given volume of liquid into the specified location.
Args:
Expand All @@ -138,6 +141,7 @@ def dispense(
rate: The rate in µL/s to dispense at.
flow_rate: Not used in this core.
in_place: Whether we should move_to location.
correction_volume: Not used in this core.
push_out: The amount to push the plunger below bottom position.
"""
if isinstance(location, (TrashBin, WasteChute)):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def aspirate(
flow_rate: float,
in_place: bool,
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
if self.get_current_volume() == 0:
# Make sure we're at the top of the labware and clear of any
Expand Down Expand Up @@ -141,6 +142,7 @@ def dispense(
in_place: bool,
push_out: Optional[float],
is_meniscus: Optional[bool] = None,
correction_volume: Optional[float] = None,
) -> None:
if isinstance(location, (TrashBin, WasteChute)):
raise APIVersionError(
Expand Down
2 changes: 2 additions & 0 deletions api/src/opentrons/protocol_engine/commands/aspirate.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
BaseLiquidHandlingResult,
aspirate_in_place,
prepare_for_aspirate,
DEFAULT_CORRECTION_VOLUME,
)
from .movement_common import (
LiquidHandlingWellLocationMixin,
Expand Down Expand Up @@ -179,6 +180,7 @@ async def execute(self, params: AspirateParams) -> _ExecuteReturn:
command_note_adder=self._command_note_adder,
pipetting=self._pipetting,
model_utils=self._model_utils,
correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
)
state_update.append(aspirate_result.state_update)
if isinstance(aspirate_result, DefinedErrorData):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
BaseLiquidHandlingResult,
OverpressureError,
aspirate_in_place,
DEFAULT_CORRECTION_VOLUME,
)
from .command import (
AbstractCommandImpl,
Expand Down Expand Up @@ -108,6 +109,7 @@ async def execute(self, params: AspirateInPlaceParams) -> _ExecuteReturn:
command_note_adder=self._command_note_adder,
pipetting=self._pipetting,
model_utils=self._model_utils,
correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
)
if isinstance(result, DefinedErrorData):
if (
Expand Down
2 changes: 2 additions & 0 deletions api/src/opentrons/protocol_engine/commands/dispense.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
BaseLiquidHandlingResult,
OverpressureError,
dispense_in_place,
DEFAULT_CORRECTION_VOLUME,
)
from .movement_common import (
LiquidHandlingWellLocationMixin,
Expand Down Expand Up @@ -117,6 +118,7 @@ async def execute(self, params: DispenseParams) -> _ExecuteReturn:
},
pipetting=self._pipetting,
model_utils=self._model_utils,
correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
)

if isinstance(dispense_result, DefinedErrorData):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
BaseLiquidHandlingResult,
OverpressureError,
dispense_in_place,
DEFAULT_CORRECTION_VOLUME,
)
from .command import (
AbstractCommandImpl,
Expand Down Expand Up @@ -95,6 +96,7 @@ async def execute(self, params: DispenseInPlaceParams) -> _ExecuteReturn:
},
pipetting=self._pipetting,
model_utils=self._model_utils,
correction_volume=params.correctionVolume or DEFAULT_CORRECTION_VOLUME,
)
if isinstance(result, DefinedErrorData):
if (
Expand Down
Loading

0 comments on commit 6875002

Please sign in to comment.