Automatic incrementation and repetition of basic liquid handling tasks

Opentrons API has a feature that allows a user to attach tip racks to pipettes, and then it will automatically increment through tips any time pick_up_tip() is called. More info here.

Additionally, when moving more liquid than can fit in a pipette tip at once, Opentrons will automatically use multiple aspirate and dispense commands when a transfer, consolidate, or distribute method is called. More here.

I was wondering if PLR has similar features, or if that is something that could be added in the future. I know there is a transfer method, but I have not had much time to play around with it yet.

Thanks!

1 Like

Hi Jaren,

The short answer is “no, PLR does not have such a feature out of the box”.

But you can make it in a couple of seconds:

# Generate TIP carrier instances
tip_carrier_1 = TIP_CAR_480_A00(name='tip_carrier_1')
# Assign tipracks
tip_carrier_1[0] = HTF_L(name=f'tip_1000ul_00')
tip_carrier_1[1] = HTF_L(name=f'tip_1000ul_01')

# Create the iterator
tip_1000ul_iterator = iter(flatten([lh.deck.get_resource(f"tip_1000ul_0{x}").get_all_items() for x in range(2)]))

# Definition of flatten
def flatten(nested_list):
    return [item for sublist in nested_list for item in sublist]

What you are referring to is called an iterator in programming.
An iterator is an object that enables a programmer to traverse through all the elements in a collection, such as lists, tuples, dictionaries, and sets. It provides a way to access elements of a container sequentially without needing to know the underlying structure of the container.
It is an almost universal concept across different programming languages.

In Python, you can make any list into an iterator by simply stating new_iterator = iter(list_example) - which is what I show above.

For some reason Hamilton is calling this programming concept “sequence” (I guess there weren’t enough meanings associated with the term sequence :man_shrugging: ).

Now you can call

# Tip Pickup
positions = [next(tip_1000ul_iterator) for x in range(no_channels)]
await lh.pick_up_tips(positions)

And it will incrementally pick up tips, not just from the first but across both tip racks defined.

While this isn’t too big of a deal on a simple liquid handler like the OT-2, it is a massive help when dealing with multi-channel systems :slight_smile:

PS.: You could get the same functionality in a couple of other ways (e.g. a generator implementation) but I find that this iterator implementation is the most readable and easy to understand.

edit: I will answer your liquid distribution question in a bit but in short, you can do that too by quickly writing the required loop

1 Like

That’s very helpful, thank you. I did not know you could make a list into an iterator like that.

positions = [next(tip_1000ul_iterator) for x in range(no_channels)]

Is no_channels the total number of tips, as in the size of the iterator list?

No, no_channels is how many channels/pipettes you want to pick up a tip.

For an OT-2 that would be 1 with the single-channel pipettes (I don’t know how PLR and the Opentrons API handle usage of a fixed multichannel though).

For a Hamilton machine you might have anywhere between 4-16 channels which can move independently from each other in their y-dimension.
Say you have an 8-channel Vantage but you only process 5 samples in the next step. Then your no_channels would be 5.

Oh got it, thank you.

1 Like

not yet supported

2 Likes