Skip to content

Commit

Permalink
use pipette bounding box offsets to find pipette bounds at target pos…
Browse files Browse the repository at this point in the history
…ition
  • Loading branch information
sanni-t committed Feb 23, 2024
1 parent 81cd790 commit 8b9b8af
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 34 deletions.
5 changes: 2 additions & 3 deletions api/src/opentrons/protocol_api/core/engine/deck_conflict.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,8 @@ def check_safe_for_pipette_movement(

labware_slot = engine_state.geometry.get_ancestor_slot_name(labware_id)
pipette_bounds_at_well_location = (
engine_state.pipettes.get_nozzle_bounds_at_specified_move_to_position(
pipette_id=pipette_id,
destination_position=well_location_point,
engine_state.pipettes.get_pipette_bounds_at_specified_move_to_position(
pipette_id=pipette_id, destination_position=well_location_point
)
)
surrounding_slots = adjacent_slots_getters.get_surrounding_slots(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class LoadedStaticPipetteData:
float, pipette_definition.SupportedTipsDefinition
]
nominal_tip_overlap: Dict[str, float]
back_left_corner_offset: Point
front_right_corner_offset: Point
back_left_nozzle_offset: Point
front_right_nozzle_offset: Point

Expand Down Expand Up @@ -151,6 +153,8 @@ def _get_virtual_pipette_static_config_by_model(
]

nozzle_manager = NozzleConfigurationManager.build_from_config(config)
pip_back_left = config.pipette_bounding_box_offsets.back_left_corner
pip_front_right = config.pipette_bounding_box_offsets.front_right_corner
return LoadedStaticPipetteData(
model=str(pipette_model),
display_name=config.display_name,
Expand All @@ -173,6 +177,12 @@ def _get_virtual_pipette_static_config_by_model(
nominal_tip_overlap=config.liquid_properties[
liquid_class
].tip_overlap_dictionary,
back_left_corner_offset=Point(
pip_back_left[0], pip_back_left[1], pip_back_left[2]
),
front_right_corner_offset=Point(
pip_front_right[0], pip_front_right[1], pip_front_right[2]
),
back_left_nozzle_offset=nozzle_manager.current_configuration.back_left_nozzle_offset,
front_right_nozzle_offset=nozzle_manager.current_configuration.front_right_nozzle_offset,
)
Expand All @@ -189,6 +199,8 @@ def get_virtual_pipette_static_config(

def get_pipette_static_config(pipette_dict: PipetteDict) -> LoadedStaticPipetteData:
"""Get the config for a pipette, given the state/config object from the HW API."""
back_left_offset = pipette_dict["pipette_bounding_box_offsets"].back_left_corner
front_right_offset = pipette_dict["pipette_bounding_box_offsets"].front_right_corner
return LoadedStaticPipetteData(
model=pipette_dict["model"],
display_name=pipette_dict["display_name"],
Expand All @@ -215,4 +227,10 @@ def get_pipette_static_config(pipette_dict: PipetteDict) -> LoadedStaticPipetteD
front_right_nozzle_offset=pipette_dict[
"current_nozzle_map"
].front_right_nozzle_offset,
back_left_corner_offset=Point(
back_left_offset[0], back_left_offset[1], back_left_offset[2]
),
front_right_corner_offset=Point(
front_right_offset[0], front_right_offset[1], front_right_offset[2]
),
)
24 changes: 19 additions & 5 deletions api/src/opentrons/protocol_engine/state/pipettes.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ class BoundingNozzlesOffsets:
front_right_offset: Point


@dataclass(frozen=True)
class PipetteBoundingBoxOffsets:
"""Offsets of the bounding nozzles of the pipette."""

back_left_corner: Point
front_right_corner: Point


@dataclass(frozen=True)
class StaticPipetteConfig:
"""Static config for a pipette."""
Expand All @@ -101,6 +109,7 @@ class StaticPipetteConfig:
nominal_tip_overlap: Dict[str, float]
home_position: float
nozzle_offset_z: float
pipette_bounding_box_offsets: PipetteBoundingBoxOffsets
bounding_nozzle_offsets: BoundingNozzlesOffsets


Expand Down Expand Up @@ -166,6 +175,10 @@ def _handle_command( # noqa: C901
nominal_tip_overlap=config.nominal_tip_overlap,
home_position=config.home_position,
nozzle_offset_z=config.nozzle_offset_z,
pipette_bounding_box_offsets=PipetteBoundingBoxOffsets(
back_left_corner=config.back_left_corner_offset,
front_right_corner=config.front_right_corner_offset,
),
bounding_nozzle_offsets=BoundingNozzlesOffsets(
back_left_offset=config.back_left_nozzle_offset,
front_right_offset=config.front_right_nozzle_offset,
Expand Down Expand Up @@ -685,7 +698,7 @@ def get_pipette_bounding_nozzle_offsets(
"""Get the nozzle offsets of the pipette's bounding nozzles."""
return self.get_config(pipette_id).bounding_nozzle_offsets

def get_nozzle_bounds_at_specified_move_to_position(
def get_pipette_bounds_at_specified_move_to_position(
self,
pipette_id: str,
destination_position: Point,
Expand All @@ -699,18 +712,19 @@ def get_nozzle_bounds_at_specified_move_to_position(
)

# Get the pipette bounding box based on total nozzles
bounding_nozzles_offsets = self.get_pipette_bounding_nozzle_offsets(pipette_id)

pipette_bounds_offsets = self.get_config(
pipette_id
).pipette_bounding_box_offsets
# TODO (spp): add a margin to these bounds
pip_back_left_bound = (
primary_nozzle_position
- primary_nozzle_offset
+ bounding_nozzles_offsets.back_left_offset
+ pipette_bounds_offsets.back_left_corner
)
pip_front_right_bound = (
primary_nozzle_position
- primary_nozzle_offset
+ bounding_nozzles_offsets.front_right_offset
+ pipette_bounds_offsets.front_right_corner
)
pip_back_right_bound = Point(
pip_front_right_bound.x, pip_back_left_bound.y, pip_front_right_bound.z
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def test_deck_conflict_raises_for_bad_pipette_move(
)
).then_return(destination_well_point)
decoy.when(
mock_state_view.pipettes.get_nozzle_bounds_at_specified_move_to_position(
mock_state_view.pipettes.get_pipette_bounds_at_specified_move_to_position(
pipette_id="pipette-id", destination_position=destination_well_point
)
).then_return(nozzle_bounds)
Expand Down Expand Up @@ -571,7 +571,7 @@ def test_deck_conflict_raises_for_collision_with_tc_lid(
)
).then_return(destination_well_point)
decoy.when(
mock_state_view.pipettes.get_nozzle_bounds_at_specified_move_to_position(
mock_state_view.pipettes.get_pipette_bounds_at_specified_move_to_position(
pipette_id="pipette-id", destination_position=destination_well_point
)
).then_return(nozzle_bounds_at_destination)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ async def test_configure_for_volume_implementation(
nominal_tip_overlap={},
back_left_nozzle_offset=Point(x=1, y=2, z=3),
front_right_nozzle_offset=Point(x=4, y=5, z=6),
back_left_corner_offset=Point(10, 20, 30),
front_right_corner_offset=Point(40, 50, 60),
)

decoy.when(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ async def test_load_pipette_implementation(
nominal_tip_overlap={},
back_left_nozzle_offset=Point(x=1, y=2, z=3),
front_right_nozzle_offset=Point(x=4, y=5, z=6),
back_left_corner_offset=Point(x=1, y=2, z=3),
front_right_corner_offset=Point(x=4, y=5, z=6),
)
data = LoadPipetteParams(
pipetteName=PipetteNameType.P300_SINGLE,
Expand Down Expand Up @@ -100,6 +102,8 @@ async def test_load_pipette_implementation_96_channel(
nominal_tip_overlap={},
back_left_nozzle_offset=Point(x=1, y=2, z=3),
front_right_nozzle_offset=Point(x=4, y=5, z=6),
back_left_corner_offset=Point(x=1, y=2, z=3),
front_right_corner_offset=Point(x=4, y=5, z=6),
)

decoy.when(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ def loaded_static_pipette_data(
nozzle_offset_z=12.13,
back_left_nozzle_offset=Point(x=1, y=2, z=3),
front_right_nozzle_offset=Point(x=4, y=5, z=6),
back_left_corner_offset=Point(x=1, y=2, z=3),
front_right_corner_offset=Point(x=4, y=5, z=6),
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ def test_get_virtual_pipette_static_config(
},
back_left_nozzle_offset=Point(x=0.0, y=0.0, z=10.45),
front_right_nozzle_offset=Point(x=0.0, y=0.0, z=10.45),
back_left_corner_offset=Point(0, 0, 10.45),
front_right_corner_offset=Point(0, 0, 10.45),
)


Expand Down Expand Up @@ -86,6 +88,8 @@ def test_configure_virtual_pipette_for_volume(
nominal_tip_overlap=result1.nominal_tip_overlap,
back_left_nozzle_offset=Point(x=-8.0, y=-22.0, z=-259.15),
front_right_nozzle_offset=Point(x=-8.0, y=-22.0, z=-259.15),
back_left_corner_offset=Point(-8.0, -22.0, -259.15),
front_right_corner_offset=Point(-8.0, -22.0, -259.15),
)
subject_instance.configure_virtual_pipette_for_volume(
"my-pipette", 1, result1.model
Expand All @@ -110,6 +114,8 @@ def test_configure_virtual_pipette_for_volume(
nominal_tip_overlap=result2.nominal_tip_overlap,
back_left_nozzle_offset=Point(x=-8.0, y=-22.0, z=-259.15),
front_right_nozzle_offset=Point(x=-8.0, y=-22.0, z=-259.15),
back_left_corner_offset=Point(-8.0, -22.0, -259.15),
front_right_corner_offset=Point(-8.0, -22.0, -259.15),
)


Expand Down Expand Up @@ -137,6 +143,8 @@ def test_load_virtual_pipette_by_model_string(
nominal_tip_overlap=result.nominal_tip_overlap,
back_left_nozzle_offset=Point(x=0.0, y=31.5, z=35.52),
front_right_nozzle_offset=Point(x=0.0, y=-31.5, z=35.52),
back_left_corner_offset=Point(-16.0, 43.15, 35.52),
front_right_corner_offset=Point(16.0, -43.15, 35.52),
)


Expand Down Expand Up @@ -256,4 +264,6 @@ def test_get_pipette_static_config(
home_position=0,
back_left_nozzle_offset=Point(x=1, y=2, z=3),
front_right_nozzle_offset=Point(x=4, y=5, z=6),
back_left_corner_offset=Point(10, 20, 30),
front_right_corner_offset=Point(40, 50, 60),
)
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
PipetteView,
StaticPipetteConfig,
BoundingNozzlesOffsets,
PipetteBoundingBoxOffsets,
)
from opentrons.protocol_engine.state.addressable_areas import AddressableAreaView
from opentrons.protocol_engine.state.geometry import GeometryView, _GripperMoveType
Expand Down Expand Up @@ -1857,6 +1858,10 @@ def test_get_next_drop_tip_location(
back_left_offset=Point(x=10, y=20, z=30),
front_right_offset=Point(x=40, y=50, z=60),
),
pipette_bounding_box_offsets=PipetteBoundingBoxOffsets(
back_left_corner=Point(x=10, y=20, z=30),
front_right_corner=Point(x=40, y=50, z=60),
),
)
)
decoy.when(mock_pipette_view.get_mount("pip-123")).then_return(pipette_mount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
CurrentDeckPoint,
StaticPipetteConfig,
BoundingNozzlesOffsets,
PipetteBoundingBoxOffsets,
)
from opentrons.protocol_engine.resources.pipette_data_provider import (
LoadedStaticPipetteData,
Expand Down Expand Up @@ -684,6 +685,8 @@ def test_add_pipette_config(
nozzle_offset_z=10.11,
back_left_nozzle_offset=Point(x=1, y=2, z=3),
front_right_nozzle_offset=Point(x=4, y=5, z=6),
back_left_corner_offset=Point(x=1, y=2, z=3),
front_right_corner_offset=Point(x=4, y=5, z=6),
),
)
subject.handle_action(
Expand All @@ -705,6 +708,10 @@ def test_add_pipette_config(
back_left_offset=Point(x=1, y=2, z=3),
front_right_offset=Point(x=4, y=5, z=6),
),
pipette_bounding_box_offsets=PipetteBoundingBoxOffsets(
back_left_corner=Point(x=1, y=2, z=3),
front_right_corner=Point(x=4, y=5, z=6),
),
)
assert subject.state.flow_rates_by_id["pipette-id"].default_aspirate == {"a": 1.0}
assert subject.state.flow_rates_by_id["pipette-id"].default_dispense == {"b": 2.0}
Expand Down
Loading

0 comments on commit 8b9b8af

Please sign in to comment.