Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -1473,8 +1473,7 @@ async def pick_up_tips(

x_positions, y_positions, channels_involved = self._ops_to_fw_positions(ops, use_channels)

tip_spots = [op.resource for op in ops]
tips = set(cast(HamiltonTip, tip_spot.get_tip()) for tip_spot in tip_spots)
tips = set(cast(HamiltonTip, op.tip) for op in ops)
if len(tips) > 1:
raise ValueError("Cannot mix tips with different tip types.")
ttti = await self.get_or_assign_tip_type_index(tips.pop())
Expand All @@ -1484,9 +1483,9 @@ async def pick_up_tips(
max_tip_length = max((op.tip.total_tip_length - op.tip.fitting_depth) for op in ops)

# not sure why this is necessary, but it is according to log files and experiments
if self._get_hamilton_tip([op.resource for op in ops]).tip_size == TipSize.LOW_VOLUME:
if self._get_hamilton_tip([op.tip for op in ops]).tip_size == TipSize.LOW_VOLUME:
max_tip_length += 2
elif self._get_hamilton_tip([op.resource for op in ops]).tip_size != TipSize.STANDARD_VOLUME:
elif self._get_hamilton_tip([op.tip for op in ops]).tip_size != TipSize.STANDARD_VOLUME:
max_tip_length -= 2

tip = ops[0].tip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,13 @@ async def test_core_96_tip_pickup(self):
]
)

async def test_tip_tracking_pick_up(self):
set_tip_tracking(enabled=True)
try:
await self.lh.pick_up_tips(self.tip_rack["A1", "B1"])
finally:
set_tip_tracking(enabled=False)

async def test_tip_tracking_pick_up96(self):
set_tip_tracking(enabled=True)
await self.lh.pick_up_tips96(self.tip_rack)
Expand Down
15 changes: 7 additions & 8 deletions pylabrobot/legacy/liquid_handling/backends/hamilton/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
LiquidHandlerBackend,
)
from pylabrobot.legacy.liquid_handling.standard import PipettingOp
from pylabrobot.resources import TipSpot
from pylabrobot.resources import Tip
from pylabrobot.resources.hamilton import (
HamiltonTip,
TipPickupMethod,
Expand Down Expand Up @@ -454,15 +454,14 @@ async def get_or_assign_tip_type_index(self, tip: HamiltonTip) -> int:

return self._tth2tti[tip_type_hash]

def _get_hamilton_tip(self, tip_spots: List[TipSpot]) -> HamiltonTip:
"""Get the single tip type for all tip spots. If it does not exist or is not a HamiltonTip,
raise an error."""
tips = set(tip_spot.get_tip() for tip_spot in tip_spots)
if len(tips) > 1:
def _get_hamilton_tip(self, tips: Sequence[Tip]) -> HamiltonTip:
"""Get the single Hamilton tip type. If mixed or not a HamiltonTip, raise an error."""
unique = set(tips)
if len(unique) > 1:
raise ValueError("Cannot mix tips with different tip types.")
if len(tips) == 0:
if len(unique) == 0:
raise ValueError("No tips specified.")
tip = tips.pop()
tip = unique.pop()
if not isinstance(tip, HamiltonTip):
raise ValueError(f"Tip {tip} is not a HamiltonTip.")
return tip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,17 +484,17 @@ async def pick_up_tips(
):
x_positions, y_positions, tip_pattern = self._ops_to_fw_positions(ops, use_channels)

tips = [cast(HamiltonTip, op.resource.get_tip()) for op in ops]
tips = [cast(HamiltonTip, op.tip) for op in ops]
ttti = [await self.get_or_assign_tip_type_index(tip) for tip in tips]

max_z = max(op.resource.get_location_wrt(self.deck).z + op.offset.z for op in ops)
max_total_tip_length = max(op.tip.total_tip_length for op in ops)
max_tip_length = max((op.tip.total_tip_length - op.tip.fitting_depth) for op in ops)

# not sure why this is necessary, but it is according to log files and experiments
if self._get_hamilton_tip([op.resource for op in ops]).tip_size == TipSize.LOW_VOLUME:
if self._get_hamilton_tip([op.tip for op in ops]).tip_size == TipSize.LOW_VOLUME:
max_tip_length += 2
elif self._get_hamilton_tip([op.resource for op in ops]).tip_size != TipSize.STANDARD_VOLUME:
elif self._get_hamilton_tip([op.tip for op in ops]).tip_size != TipSize.STANDARD_VOLUME:
max_tip_length -= 2

try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,13 @@ async def test_tip_pickup_01(self):
PICKUP_TIP_FORMAT,
)

async def test_tip_tracking_pick_up(self):
set_tip_tracking(enabled=True)
try:
await self.lh.pick_up_tips(self.tip_rack["A1", "B1"])
finally:
set_tip_tracking(enabled=False)

async def test_tip_drop_01(self):
await self.test_tip_pickup_01() # pick up tips first
await self.lh.drop_tips(self.tip_rack["A1", "B1"])
Expand Down
6 changes: 3 additions & 3 deletions pylabrobot/resources/tip_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ def has_tip(self) -> bool:
return self._pending_tip is not None

def get_tip(self) -> "Tip":
"""Get the tip. Note that does includes pending operations.
"""Get the tip. Note that this includes pending operations.

Raises:
NoTipError: If the tip spot does not have a tip.
"""

if self._tip is None:
if self._pending_tip is None:
raise NoTipError(f"{self.thing} does not have a tip.")
return self._tip
return self._pending_tip

def disable(self) -> None:
"""Disable the tip tracker."""
Expand Down
14 changes: 14 additions & 0 deletions pylabrobot/resources/tip_tracker_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,17 @@ def test_remove_tip(self):

with self.assertRaises(NoTipError):
tracker.get_tip()

def test_get_tip_includes_pending_add(self):
tracker = TipTracker(thing="tester")
tracker.add_tip(self.tip, commit=False)
self.assertEqual(tracker.has_tip, True)
self.assertEqual(tracker.get_tip(), self.tip)

def test_get_tip_includes_pending_remove(self):
tracker = TipTracker(thing="tester")
tracker.add_tip(self.tip)
tracker.remove_tip(commit=False)
self.assertEqual(tracker.has_tip, False)
with self.assertRaises(NoTipError):
tracker.get_tip()
Loading