At the end of this command the tip_ends will be left 20 mm above the destination_wells due to the min_z_endpos attribute.
However, when adding a second lh.dispense() command after this using lld_mode=cLLD the channels first move back up, and then to theminimum_traverse_height_at_beginning_of_a_command (if declared). minimum_traverse_height_at_beginning_of_a_command appears to dictate from where the cLLD search begins, but the channels always move back up before then.
In this situation, the channels with the droplet attached to them should not bounce up and down but should only move downwards.
One way to get around this problem is to use STAR.probe_z_height_using_channel because this command does not send the channel back up before starting the cLLD search.
However, this command only operates on one channel at a time, i.e. does not fulfill requirement no. 3.
VENUS software has things like virtual shift of labware that might be a way to enable this. Is there a similar function within PyLab, or possibly superimposing labware on the same position/redefining the labware location midway through pipetting?
Alternatively, might you be able to manipulate the traveling airgap and blowout settings such that your droplet is considered part of the “airgap”? This is probably how I’d consider solving this issue in VENUS, but I am no PyLab expert.
I have added this to the command I show above. This defines the post-dispense_1 behaviour, i.e. how far to move above where the droplet has been dispensed. When set to 0 this together with min_z_endpos ensures the tip stays where it generated the droplet (dispense_1).
I tried adding this to lh.dispense() but it simply returns a warning:
\pylabrobot\pylabrobot\liquid_handling\liquid_handler.py:293: UserWarning: Extra arguments to backend.dispense: {'liquid_surface_no_lld'}
warnings.warn(f"Extra arguments to backend.{method.__name__}: {extra}")
…which seems odd given that it is an argument of STAR.dispense_pip().
That solved it:
In STAR.dispense()lld_search_height is amended via:
if lld_search_height is None:
lld_search_height = [
int((wb + op.resource.get_size_z() + (2.7 if isinstance(op.resource, Well) else 5)) * 10) #?
for wb, op in zip(well_bottoms, ops)
]
else:
lld_search_height = [int((wb + sh) * 10) for wb, sh in zip(well_bottoms, lld_search_height)]
This meant that at the beginning of the command “dispense_2” it was going to the well_bottom+well_size_z+5.0 mm in order to start its cLLD search.
Simply changing this to the z_offset at which dispense_1 created the droplet, in my case 20 mm, meant that the dispense_2 command did not “bounce” up and down at the beginning but continued dispense_2 straight from where it left dispense_1
Thank you for the support and helping me figure this out so quickly!
Yes, you can update the location of any resource dynamically by setting its location attribute (note that this relative to the parent resource).
(This rest is not particularly relevant in this thread, but wanted to say it anyway. The deck model in PLR is supposed to be a physically accurate representation of reality. While “hacks” like superimposing labware would work, we would aim to provide more natural tools for doing that. As with venus, ultimately firmware commands are sent to the machine that just specify some locations, very much independent of how these locations are generated from a deck layout. Changing the deck layout (“hack”) in venus may the only way, and in plr it’s one way, to change which parameters are sent, but it’s still a hack for which we can provide a better API.)
That is because it was not an argument of STAR.dispense (the STAR-implementation of LiquidHandlerBackend.dispense). Fixed with expose STAR.dispense liquid_surface_no_lld param · PyLabRobot/pylabrobot@d6c713a · GitHub. (inconsistent with lld_search_height, which is relative, whereas liquid_surface_no_lld is absolute, will fix when I fix the 0.1mm vs 1mm discrepancy.)