Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions pylabrobot/hamilton/prep/driver/features/head8.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@
PipetteChannel,
Pipettes,
_absolute_z_from_well,
_build_container_segments,
_effective_radius,
_get_container_segments,
)
from .pipettes import (
default_lld_params as _default_lld_params_fn,
Expand Down Expand Up @@ -1115,9 +1115,6 @@ def __init__(self, tip: Tip, volume: float):
loc = container.get_location_wrt(self._require_deck(), "c", "c", "cavity_bottom")
ref_x, ref_y = loc.x, loc.y + 3.5 * PROBE_PITCH_MM
wg = _absolute_z_from_well(container, self._require_deck(), liquid_height)
ref_segments = container_segments or (
_build_container_segments(container) if auto_container_geometry else []
)
ref_resource = container
else:
wells_list = list(wells) # type: ignore[arg-type]
Expand All @@ -1131,14 +1128,20 @@ def __init__(self, tip: Tip, volume: float):
ref_loc = wells_list[0].get_location_wrt(self._require_deck(), "c", "c", "cavity_bottom")
ref_x, ref_y = ref_loc.x, ref_loc.y
wg = _absolute_z_from_well(wells_list[0], self._require_deck(), liquid_height)
ref_segments = container_segments or (
_build_container_segments(wells_list[0]) if auto_container_geometry else []
)
ref_resource = wells_list[0]

resolved_z_fluid = z_fluid if z_fluid is not None else wg.liquid_surface
resolved_z_air = z_air if z_air is not None else wg.z_air
resolved_z_minimum = z_minimum if z_minimum is not None else wg.well_bottom
# the firmware counts segment 0 from z_minimum
cavity_bottom_z = ref_resource.get_location_wrt(
self._require_deck(), "c", "c", "cavity_bottom"
).z
ref_segments = container_segments or (
_get_container_segments(ref_resource, profile_start=resolved_z_minimum - cavity_bottom_z)
if auto_container_geometry
else []
)
resolved_z_bottom_search_offset = (
z_bottom_search_offset if z_bottom_search_offset is not None else 2.0
)
Expand Down Expand Up @@ -1337,9 +1340,6 @@ def __init__(self, tip: Tip, volume: float):
loc = container.get_location_wrt(self._require_deck(), "c", "c", "cavity_bottom")
ref_x, ref_y = loc.x, loc.y + 3.5 * PROBE_PITCH_MM
wg = _absolute_z_from_well(container, self._require_deck(), liquid_height)
ref_segments = container_segments or (
_build_container_segments(container) if auto_container_geometry else []
)
ref_resource = container
else:
wells_list = list(wells) # type: ignore[arg-type]
Expand All @@ -1353,14 +1353,20 @@ def __init__(self, tip: Tip, volume: float):
ref_loc = wells_list[0].get_location_wrt(self._require_deck(), "c", "c", "cavity_bottom")
ref_x, ref_y = ref_loc.x, ref_loc.y
wg = _absolute_z_from_well(wells_list[0], self._require_deck(), liquid_height)
ref_segments = container_segments or (
_build_container_segments(wells_list[0]) if auto_container_geometry else []
)
ref_resource = wells_list[0]

resolved_z_fluid = z_fluid if z_fluid is not None else wg.liquid_surface
resolved_z_air = z_air if z_air is not None else wg.z_air
resolved_z_minimum = z_minimum if z_minimum is not None else wg.well_bottom
# the firmware counts segment 0 from z_minimum
cavity_bottom_z = ref_resource.get_location_wrt(
self._require_deck(), "c", "c", "cavity_bottom"
).z
ref_segments = container_segments or (
_get_container_segments(ref_resource, profile_start=resolved_z_minimum - cavity_bottom_z)
if auto_container_geometry
else []
)
resolved_z_bottom_search_offset = (
z_bottom_search_offset if z_bottom_search_offset is not None else 2.0
)
Expand Down
31 changes: 31 additions & 0 deletions pylabrobot/hamilton/prep/driver/features/head8_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from pylabrobot.hamilton.prep.driver.features.pipettes import (
Pipettes,
_build_pipettor_gantry_move_parameters,
_get_container_segments,
)
from pylabrobot.hamilton.prep.driver.simulator import RECORDING_PREP_HEAD8
from pylabrobot.resources import Coordinate, Resource
Expand Down Expand Up @@ -301,6 +302,36 @@ async def _run() -> None:
asyncio.run(_run())


def test_head8_aspirate_container_segments_start_at_z_minimum():
"""With auto_container_geometry, segment 0 begins at the z_minimum the command sends."""

async def _run() -> None:
deck, tip_rack, src_plate, _ = _make_deck()
p = PrepSimulationDriver(deck=deck, declared_configuration_json=RECORDING_PREP_HEAD8)
await p.setup()
assert p.head8 is not None

captured, _ = _record_send(p)

await p.head8.pick_up_tips(tip_rack.column(0))
wells = src_plate.column(0)
cavity_bottom_z = wells[0].get_location_wrt(deck, "c", "c", "cavity_bottom").z
profile_top = sum(s.height for s in _get_container_segments(wells[0]))
await p.head8.aspirate(
wells=wells, volume=10, z_minimum=cavity_bottom_z + 1.5, auto_container_geometry=True
)

asp = [c for c in captured if isinstance(c, PrepCmd.MphAspirateNoLldMonitoring2)]
params = asp[0].aspirate_parameters[0]
assert params.common.z_minimum == pytest.approx(cavity_bottom_z + 1.5)
sent_height = sum(s.height for s in params.container_description)
assert sent_height == pytest.approx(profile_top - 1.5)

await p.stop()

asyncio.run(_run())


def test_head8_v2_dispense_sends_mphdispensetnolld2():
"""Simulator default (use_v1=False) → V2 dispense command class is sent."""

Expand Down
Loading
Loading