Loading Pipettes

When writing a protocol, you must inform the Protocol API about the pipettes you will be using on your robot. The ProtocolContext.load_instrument() function provides this information and returns an InstrumentContext object.

As noted above, you call the load_instrument() method to load a pipette. This method also requires the pipette’s API load name, its left or right mount position, and (optionally) a list of associated tip racks. Even if you don’t use the pipette anywhere else in your protocol, the Opentrons App and the robot won’t let you start the protocol run until all pipettes loaded by load_instrument() are attached properly.

API Load Names

The pipette’s API load name (instrument_name) is the first parameter of the load_instrument() method. It tells your robot which attached pipette you’re going to use in a protocol. The tables below list the API load names for the currently available Flex and OT-2 pipettes.

Pipette Model

Volume (µL)

API Load Name

Flex 1-Channel Pipette

1–50

flex_1channel_50

5–1000

flex_1channel_1000

Flex 8-Channel Pipette

1–50

flex_8channel_50

5–1000

flex_8channel_1000

Flex 96-Channel Pipette

5–1000

flex_96channel_1000

Loading Flex 1- and 8-Channel Pipettes

This code sample loads a Flex 1-Channel Pipette in the left mount and a Flex 8-Channel Pipette in the right mount. Both pipettes are 1000 µL. Each pipette uses its own 1000 µL tip rack.

from opentrons import protocol_api

requirements = {"robotType": "Flex", "apiLevel":"2.17"}

def run(protocol: protocol_api.ProtocolContext):
    tiprack1 = protocol.load_labware(
        load_name="opentrons_flex_96_tiprack_1000ul", location="D1")
    tiprack2 = protocol.load_labware(
        load_name="opentrons_flex_96_tiprack_1000ul", location="C1")
    left = protocol.load_instrument(
        instrument_name="flex_1channel_1000",
        mount="left",
        tip_racks=[tiprack1])
    right = protocol.load_instrument(
        instrument_name="flex_8channel_1000",
        mount="right",
        tip_racks=[tiprack2])

If you’re writing a protocol that uses the Flex Gripper, you might think that this would be the place in your protocol to declare that. However, the gripper doesn’t require load_instrument! Whether your gripper requires a protocol is determined by the presence of ProtocolContext.move_labware() commands. See Moving Labware for more details.

Loading a Flex 96-Channel Pipette

This code sample loads the Flex 96-Channel Pipette. Because of its size, the Flex 96-Channel Pipette requires the left and right pipette mounts. You cannot use this pipette with 1- or 8-Channel Pipette in the same protocol or when these instruments are attached to the robot. Load the 96-channel pipette as follows:

def run(protocol: protocol_api.ProtocolContext):
    pipette = protocol.load_instrument(
        instrument_name="flex_96channel_1000"
    )

In protocols specifying API version 2.15, also include mount="left" as a parameter of load_instrument().

New in version 2.15.

Changed in version 2.16: The mount parameter is optional.

Loading OT-2 Pipettes

This code sample loads a P1000 Single-Channel GEN2 pipette in the left mount and a P300 Single-Channel GEN2 pipette in the right mount. Each pipette uses its own 1000 µL tip rack.

from opentrons import protocol_api

metadata = {"apiLevel": "2.17"}

def run(protocol: protocol_api.ProtocolContext):
    tiprack1 = protocol.load_labware(
        load_name="opentrons_96_tiprack_1000ul", location=1)
    tiprack2 = protocol.load_labware(
        load_name="opentrons_96_tiprack_1000ul", location=2)
    left = protocol.load_instrument(
        instrument_name="p1000_single_gen2",
        mount="left",
        tip_racks=[tiprack1])
    right = protocol.load_instrument(
        instrument_name="p300_multi_gen2",
        mount="right",
        tip_racks=[tiprack1])

New in version 2.0.

Adding Tip Racks

The load_instrument() method includes the optional argument tip_racks. This parameter accepts a list of tip rack labware objects, which lets you to specify as many tip racks as you want. You can also edit a pipette’s tip racks after loading it by setting its InstrumentContext.tip_racks property.

Note

Some methods, like configure_nozzle_layout(), reset a pipette’s tip racks. See Partial Tip Pickup for more information.

The advantage of using tip_racks is twofold. First, associating tip racks with your pipette allows for automatic tip tracking throughout your protocol. Second, it removes the need to specify tip locations in the InstrumentContext.pick_up_tip() method. For example, let’s start by loading loading some labware and instruments like this:

def run(protocol: protocol_api.ProtocolContext):
    tiprack_left = protocol.load_labware(
        load_name="opentrons_flex_96_tiprack_200ul", location="D1")
    tiprack_right = protocol.load_labware(
        load_name="opentrons_flex_96_tiprack_200ul", location="D2")
    left_pipette = protocol.load_instrument(
        instrument_name="flex_8channel_1000", mount="left")
    right_pipette = protocol.load_instrument(
        instrument_name="flex_8channel_1000",
        mount="right",
        tip_racks=[tiprack_right])

Let’s pick up a tip with the left pipette. We need to specify the location as an argument of pick_up_tip(), since we loaded the left pipette without a tip_racks argument.

left_pipette.pick_up_tip(tiprack_left["A1"])
left_pipette.drop_tip()

But now you have to specify tiprack_left every time you call pick_up_tip, which means you’re doing all your own tip tracking:

left_pipette.pick_up_tip(tiprack_left["A2"])
left_pipette.drop_tip()
left_pipette.pick_up_tip(tiprack_left["A3"])
left_pipette.drop_tip()

However, because you specified a tip rack location for the right pipette, the robot will automatically pick up from location A1 of its associated tiprack:

right_pipette.pick_up_tip()
right_pipette.drop_tip()

Additional calls to pick_up_tip will automatically progress through the tips in the right rack:

right_pipette.pick_up_tip()  # picks up from A2
right_pipette.drop_tip()
right_pipette.pick_up_tip()  # picks up from A3
right_pipette.drop_tip()

New in version 2.0.

See also Building Block Commands and Complex Commands.

Adding Trash Containers

The API automatically assigns a trash_container to pipettes, if one is available in your protocol. The trash_container is where the pipette will dispose tips when you call drop_tip() with no arguments. You can change the trash container, if you don’t want to use the default.

One example of when you might want to change the trash container is a Flex protocol that goes through a lot of tips. In a case where the protocol uses two pipettes, you could load two trash bins and assign one to each pipette:

left_pipette = protocol.load_instrument(
    instrument_name="flex_8channel_1000", mount="left"
)
right_pipette = protocol.load_instrument(
    instrument_name="flex_8channel_50", mount="right"
)
left_trash = load_trash_bin("A3")
right_trash = load_trash_bin("B3")
left_pipette.trash_container = left_trash
right_pipette.trash_container = right_trash

Another example is a Flex protocol that uses a waste chute. Say you want to only dispose labware in the chute, and you want the pipette to drop tips in a trash bin. You can implicitly get the trash bin to be the pipette’s trash_container based on load order, or you can ensure it by setting it after all the load commands:

pipette = protocol.load_instrument(
    instrument_name="flex_1channel_1000",
    mount="left"
)
chute = protocol.load_waste_chute()  # default because loaded first
trash = protocol.load_trash_bin("A3")
pipette.trash_container = trash  # overrides default

New in version 2.0.

Changed in version 2.16: Added support for TrashBin and WasteChute objects.