Hi everyone,
Has something changed about the PLR backend commands for aspirate and dispense for STAR machines?
await lh.aspirate(
tube_list,
use_channels = use_channels[:no_channels],
vols=[20]*no_channels,
hamilton_liquid_classes = [HTF_water_LC]*no_channels,
aspiration_speed=[20]*no_channels,
blow_out=[True]*no_channels,
blow_out_air_volume=[4]*no_channels,
minimum_height=mm2dmm(tube_list[0].get_absolute_location(z="bottom").z+1)
)
returns a warning:
c:\users\cmoschner\desktop\pylabrobot\pylabrobot\liquid_handling\liquid_handler.py:292: UserWarning: Extra arguments to backend.aspirate: {'aspiration_speed'}
warnings.warn(f"Extra arguments to backend.{method.__name__}: {extra}")
→ Looking into STAR.py
and its def aspirate()
method (the “abstract” backend command) , it is clear that this method does not have an aspiration_speed
argument but aspirate_pip
(the “true”/direct backend command to the STAR) does.
Explanation tangent:
To iterate for clarity purposes, the command generation stack is:
lh.aspirate()
- what users are likely to use (across different devices), sends information to…lh.backend.aspirate()
/STAR.aspirate()
(in this case) - what gives this specific liquid handler (i.e. STAR) higher level information, acts as an intermediate #TODO: need to convert all arguments given to this method toul
andmm
units (currently a mess of ul. deci-ul, mm, deci–mm for different arguments), sends information to…lh.backend.aspirate_pip()
/STAR.aspirate_pip()
(in this case) - what converts the information into the final firmware command, cumbersome to use because it has to be given positional information, hence the layer above to deal with this. #TODO: need to convert all arguments given to this method todeci-ul
anddeci-mm
units as integers or strings with the appropriate length padding.
So I dived into the STAR.aspirate()
code and found that even though one cannot give it an aspiration_speed
argument, it has to generate one itself and hand it to STAR.aspirate_pip()
.
It does so via
aspiration_speed = [int(fr * 10) for fr in flow_rates]
flow_rates
in turn is specified just above this assignment via
flow_rates = [
op.flow_rate or (hlc.aspiration_flow_rate if hlc is not None else 100)
for op, hlc in zip(ops, hamilton_liquid_classes)]
But importantly, flow_rates
is not an argument of STAR.aspirate()
either.
→ This means that PLR users can only change aspiration speed, i.e. “flow rate during aspiration”, by using hamilton_liquid_classes
if I am not mistaken?
If we don’t, then the aspiration speed is always 100 (ul/s).
I have definitely used aspiration_speed
as an argument before which makes me wonder what might have happened, or whether I have overlooked an important piece of code somewhere.
→ This has actually just broken a previously functional automation protocol I created that depends on aspiration_speed
being different from 100 (ul/s).
Please let me know whether you can spot my mistake.
Also, everything above also applies to dispense()
.