I have been using the Hamilton Star to make dilutions and load a 96 well plate for Gator BLI. Unfortunately, I have run into an issue with dispensing different volumes in different pipettes. I created a function to aspirate enough volume for all the wells in a row from a 50ml conical tube and then dispense various amounts across the plate.
This is a simplified version of my code
async def multi_channel_transfer_from_tube(tube_resource, target_plate, column_transfers, tip_resources):
await lh.pick_up_tips(tip_resources)
tip_volumes = [0] * 8
for volumes, column in column_transfers:
# add volumes to tip_volumes for each channel
for i, volume in enumerate(volumes):
tip_volumes[i] += volume
for i, volume in enumerate(tip_volumes):
await lh.aspirate(tube_resource, vols=[volume], use_channels=[i])
for volumes, column in column_transfers:
await lh.dispense(target_plate[f"A{column}:H{column}"], vols=volumes)
await lh.discard_tips()
Unfortunately, after calling the function multiple times, channel 7 throws an error that there is too little volume and the pipette cannot âmoveâ to that position.
I tried troubleshooting by using the command STAR.request_volume_in_tip after aspirating and dispensing. What is request_volume_in_tip? Is that motor steps? It doesnât match the actual volume requested. Also, request_volume_in_tip seems non-linear to the aspirated/dispensed volume in tip. That seems odd if it is geared
Should I be calling a different function for multi dispensing from a tip?
I am not sure how to upload an excel file so I uploaded a table of my troubleshooting. Actual is the response from request_volume_in_tip. Ratio shows the non-linear relationship between volumes expected and actual.
The 3rd and 5th time I called the function the volumes were the same just different plates/columns but the request_volume_in_tip changes for the same volumes. Error happens at the end of the 5th time when trying to dispense 200 ul.
you are running into the problem of the dispensed volume not being the plunger volume on Hamiltons. and unfortunately the mapping is not linear as you point outâŠ
there is a correction happening (in venus, and copied that into PLR) for âspecified volume â firmware/plunger volumeâ. unfortunately f(v1+v2+...) â f(v1) + f(v2) + ..., often f(v1+v2+...) < f(v1) + f(v2) + ...
STAR.request_volume_in_tip is the plunger volume
the way to solve this is to add more volume s to the aspiration f(v1+v2+... + s) â„ f(v1) + f(v2) + ...
the function being used depends on the tip type. this loads a âhamilton liquid classâ, that includes a correction function.
letâs say you are using HighVolumeFilter_Water_DispenseSurface_Part (name matching venus. meaning: 1000ul filter tips, water, no blowout/jet mode):
from pylabrobot.liquid_handling.liquid_classes.hamilton.star import HighVolumeFilter_Water_DispenseSurface_Part
print(HighVolumeFilter_Water_DispenseSurface_Part.compute_corrected_volume(1000))
#1028.5
print(sum(HighVolumeFilter_Water_DispenseSurface_Part.compute_corrected_volume(200) for _ in range(5)))
#1055.0
also, people pointed out to me in the past that in a serial dispense the first and last dispense are often cursed and should be done into the aspiration-container or trash.
this is done on the backend to provide good parameters
âsmartâ code like this leads to annoying cases like this, so should generally be avoided. in this case I think itâs the lesser evil compared to having less accurate aspirations/dispenses when making a simple lh.aspirate call
Liquid classes also perform differently at different altitudes and humidity, air is a spring and its the plunger for an air displacement system. Most liquid classes were developed in Reno at elevation where its dry as hell. First thing I did was modify that liquid class for our robots.
The results above are really really terrible though, I would not expect that bad from vanilla liquid classes. Begs the question, how are you measuring?
agree that the hamilton liquid classes are not perfect and almost always require fine tuning by the end user (we use a scale for this). but entirely no parameters /volume correction would be even worse.
@cwehrhan how can you tell Davidâs results are bad? he is only showing target volume and plunger volume, no external metric to compare against
Thank you so much for your reply. I understand overall idea that air is a spring and the environment plays a role, but shouldnât the correction happen for both the aspiration and dispension? Maybe I donât quite understand. I could add volume to the aspiration, but I am concerned about building up liquid overtime. Is there a way to reset the plunger with a firmware command? Does this happen when dropping tips? Can you aspirate an air gap between each volume and then dispense so that the plunger ends up within the air gap for each dispense?
My current plan is to buy a trough holder and just take advantage of multi-channel instead of a 50ml tube and multi-dispension. Should take about the same time.
Also, sorry about misleading labeling actual volume and plunger value.
Thanks again! I was going crazy thinking my code was not pipetting the correct amounts.
it does, and it happens correctly when you aspirate and dispense the exact same volume in matching operation. For example, aspirate 200 and dispense 200 or aspirate 200 five times in a row then dispense 200 five times. The problem occurs because the correction function is non-linear (f(v1+v2+...) â f(v1) + f(v2) + ... lis is aspiration, rhs is dispense)
Yes, there is a " Move dispensing drive into Init. position (empty tip)" firmware command for this. This command exists on the PX boards/computers per channel, as opposed to the robot master computer (called C0). For example P1 for the backmost channel (0 in PLR).
We donât have this wrapped in PLR, but I can add it if you like. The firmware command is this:
Happens just before pickup actually. So you donât need to do it manually or worry about moving the plunger up over the protocol.
But again the cleanest way to do it is to compute the corrected volume for the aspiration and dispenses using compute_corrected_volume (see my post above) and ideally to waste the first and last dispense into a waste/the original container.
I see. I now understand. Out of curiosity, why is it non-linear?
Would it be helpful to develop a function that creates an air gap between each volume? If the plunger movements are non-linear would each volume become inaccurate after the first volume aspirated? How would the volumes be corrected after the first aspirated volume? Would the air gap mess with the volume correction?
I think the air gap would mess with it, but itâs an interesting idea and I do not know for sure. You can use a scale or a plate reader to easily test these hypotheses