When using the robot today, I encountered an error after sending the command to pick up the tips, but before it had successfully picked them up.
Attempts to pick up tips resulted in this error:
HasTipError Traceback (most recent call last)
Cell In[13], line 3
1 for tips, source_wells, target_wells in zip(fprimer_tips.traverse(8, direction="down")
2 , primer_f_plate.traverse(8, direction='down'), pcr_plate.traverse(8, direction="down")):
----> 3 await lh.pick_up_tips(tips)
4 await lh.aspirate(
5 resources=source_wells,
6 vols=[2.5] * 8
7 )
8 await lh.dispense(
9 resources=target_wells,
10 vols=[2.5] * 8
11 )
File ~/pylabrobot/pylabrobot/machines/machine.py:23, in need_setup_finished.<locals>.wrapper(self, *args, **kwargs)
21 if not self.setup_finished:
22 raise RuntimeError("The setup has not finished. See `setup`.")
---> 23 return await func(self, *args, **kwargs)
File ~/pylabrobot/pylabrobot/liquid_handling/liquid_handler.py:419, in LiquidHandler.pick_up_tips(self, tip_spots, use_channels, offsets, **backend_kwargs)
417 for channel, op in zip(use_channels, pickups):
418 if self.head[channel].has_tip:
--> 419 raise HasTipError("Channel has tip")
420 if does_tip_tracking() and not op.resource.tracker.is_disabled:
421 op.resource.tracker.remove_tip()
HasTipError: Channel has tip
However, attempting to return tips results in this error.
---------------------------------------------------------------------------
NoTipError Traceback (most recent call last)
Cell In[14], line 1
----> 1 await lh.return_tips()
File ~/pylabrobot/pylabrobot/liquid_handling/liquid_handler.py:628, in LiquidHandler.return_tips(self, use_channels, **backend_kwargs)
625 if len(tip_spots) == 0:
626 raise RuntimeError("No tips have been picked up.")
--> 628 return await self.drop_tips(tip_spots=tip_spots, use_channels=channels, **backend_kwargs)
File ~/pylabrobot/pylabrobot/machines/machine.py:23, in need_setup_finished.<locals>.wrapper(self, *args, **kwargs)
21 if not self.setup_finished:
22 raise RuntimeError("The setup has not finished. See `setup`.")
---> 23 return await func(self, *args, **kwargs)
File ~/pylabrobot/pylabrobot/liquid_handling/liquid_handler.py:524, in LiquidHandler.drop_tips(self, tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs)
522 tips = []
523 for channel in use_channels:
--> 524 tip = self.head[channel].get_tip()
525 if tip.tracker.get_used_volume() > 0 and not allow_nonzero_volume:
526 raise RuntimeError(f"Cannot drop tip with volume {tip.tracker.get_used_volume()}")
File ~/pylabrobot/pylabrobot/resources/tip_tracker.py:66, in TipTracker.get_tip(self)
59 """Get the tip. Note that does includes pending operations.
60
61 Raises:
62 NoTipError: If the tip spot does not have a tip.
63 """
65 if self._tip is None:
---> 66 raise NoTipError(f"{self.thing} does not have a tip.")
67 return self._tip
By running the command lh.head[channel_index].remove_tip(tip, origin) or lh.head[channel_index].add_tip(tip, origin) I can manually reset the state to reflect reality, but given that HasTipError and NoTipError are contradictory, it feels like this behavior should be handled differently. I think if there is an error during a tip pickup there are a few possible outcomes:
The command completes, tips are picked up, and the error only comes after in which case you want the state to reflect that there are tips.
The error occurs prior to the tips being picked up
Partial success
I am not sure of the best, safest approach to handle this overall. My initial thoughts are that if there is uncertainty over the state of the tip, that should actually be a separate state in tip tracking that leads to its own error on any actions involving the head in question. Ideally, the message displayed with this error should always contain all the information necessary to resolve the problem and reflect the reality of the tip state. But I would love to hear any additional thoughts on the best approach to resolve this issue.
Hello,
When using the robot today, I encountered an error after sending the command to pick up the tips, but before it had successfully picked them up.
Attempts to pick up tips resulted in this error:
However, attempting to return tips results in this error.
By running the command
lh.head[channel_index].remove_tip(tip, origin)
orlh.head[channel_index].add_tip(tip, origin)
I can manually reset the state to reflect reality, but given that HasTipError and NoTipError are contradictory, it feels like this behavior should be handled differently. I think if there is an error during a tip pickup there are a few possible outcomes:I am not sure of the best, safest approach to handle this overall. My initial thoughts are that if there is uncertainty over the state of the tip, that should actually be a separate state in tip tracking that leads to its own error on any actions involving the head in question. Ideally, the message displayed with this error should always contain all the information necessary to resolve the problem and reflect the reality of the tip state. But I would love to hear any additional thoughts on the best approach to resolve this issue.