Aspirating All/Most Liquid from 96 Well Plate Wells (Opentrons Flex)

Just wanted to share her in case it’s helpful. I was having trouble with residual liquid left behind in the corner of my 96 well plate wells. I was doing z=1 and also tried going down to z=0.5.

On the advice of @Stanjak and @MeghanFerzoco, I tried lower (z=0, z=1) and it seems to help greatly.

From left to right, all with a 1000 uL tip with y=-2 offset unless specified:

  • Aspirating at z=0.5 (ring of liquid remaining)
  • z=0.25 (didn’t help that much)
  • z=0.1 (less liquid remaining)
  • z=0 (even less liquid remaining)
  • Aspirating at z=1 from each “corner” of the well
  • Aspirating 50% of the liquid at z=1, then 35% at z=0.5, then 15% at z=0.1. Then finally 15 uL extra aspiration at z=0
  • Aspirating 50% of the liquid at z=1, then 35% at z=0.5, then 15% at z=0.1. Then finally 5 uL extra aspiration from each corner, at z=0

I’m moving forward with the decreasing Z position .aspirate() actions (I’m pipetting cells so I want to save the potentially higher shear force z=1 and z=0 aspirations for just the residual liquid/cells that are left in the well.

Example (non-professional) code:

well_vol = TRYPLE_WASH_VOL + TRYPLE_VOL
aspirate_1 = well.bottom(z=1).move(Y_OFFSET_96_WELL)
aspirate_2 = well.bottom(z=0.5).move(Y_OFFSET_96_WELL)
aspirate_3 = well.bottom(z=0.1).move(Y_OFFSET_96_WELL)
aspirate_4 = well.bottom(z=0).move(Y_OFFSET_96_WELL)
                
p1000_multi.mix(2, well_vol / 2, aspirate_1, aspirate_flow_rate=150, dispense_flow_rate=150)
p1000_multi.flow_rate.aspirate = 150
p1000_multi.aspirate((well_vol-40)/2, aspirate_1)
p1000_multi.aspirate((well_vol-40)/2, aspirate_2)
p1000_multi.flow_rate.aspirate = 50
p1000_multi.aspirate(30, aspirate_3)
p1000_multi.aspirate(10, aspirate_4)
3 Likes

I seem to not be able to edit, but the 5th well from the left is actually z=0.1 eith aspiration from each corner, not 1 mm!

1 Like

Thank you for sharing! this is very helpful. I assume this is about a 96-well PCR plate (200 µL). I am trying to reach something similar with the NEST 96-well deepwell plate on the magnetic block. My problem is that despite very slow aspirations at optimal z there is still 2-3 µL liquid left in the edges of the well. Maybe I should just consider it dead volume, but this is guaranteed reproducible 10% loss of my sample, which I usually can recover with manual pipette. So I am going to try your approach of aspirating at each edge and test different z’s for this. [I am not limited to 1000 µL tips, I can use 50 µL.]. I wonder if anybody has tested this already

1 Like

2-3ul dead volume for a deepwell plate is pretty good imo, for greater recovery i’d recommend trying your protocol on a 96 well skirted PCR plate. The thinner bottom-well diameter might help the volume retain surface tension as the liquid level decreases.

Outside of that, there’s deepwell plates with hydrophobic coating which could help reduce side of well residual volume.

Thanks for reminding me about the topic. I also thought of doing this in a PCR plate, but it has its own problems, e.g. a bubble trapped at the bottom or need to pipette mix instead of using heater-shaker for bead resuspension.
But in the end for this protocol I was too nerdy to accept this loss and too lazy to switch to PCR plates, so I came up with this corner sweep approach, which almost always allows to recover the full volume, even those 2-3 µL. The key was to do it at two different Z’s, so you’re not that dependent on the slight movement of the plate when it gets transferred by the gripper.

    _eluate_corner_xy = ((2.9, 2.9), (2.9, -2.9), (-2.9, -2.9), (-2.9, 2.9))




def _eluate_corner_sweeps(pipette, well, corner_ul):

        pipette.move_to(well.bottom().move(types.Point(x=0, y=0, z=1)))

        pipette.default_speed = 0.5

        pipette.move_to(well.bottom().move(types.Point(x=0, y=0, z=0.5)))

        pipette.aspirate(corner_ul/2, rate=0.1)

        pipette.default_speed = 0.1

        pipette.move_to(well.bottom().move(types.Point(x=0, y=0, z=0.2)))

        pipette.aspirate(corner_ul/2, rate=0.1)

        pipette.default_speed = 400

        pipette.move_to(well.bottom(z=10))

        pipette.default_speed = 0.5

for dx, dy in _eluate_corner_xy:

            pipette.move_to(well.bottom().move(types.Point(x=dx, y=dy, z=2.9)))

            pipette.aspirate(corner_ul/2, rate=0.1)

            pipette.default_speed = 1

            pipette.move_to(well.bottom().move(types.Point(x=dx, y=dy, z=2.4)))

            pipette.aspirate(corner_ul/2, rate=0.1)

            pipette.default_speed = 400

        pipette.move_to(well.bottom(z=10))
1 Like