Week 3: Protocol Skeleton (Colab/OT-2)

Prelude to this lab

What this is
A minimal, well-commented Opentrons Python API v2 protocol that mixes five dye “channels” (Red/Yellow/Green/Cyan/Blue) and logs the total consumables.

It will report: tips used and µL per color. It uses OT-2 GEN2 p300, 300 µL tips, a 96-well Corning 360 µL flat plate, and an Eppendorf 1.5 mL 24-tube rack. The log messages appear via protocol.comment().


Opentrons protocol (copy into a single Colab cell or .py)

# metadata / requirements — declare API level (>=2.15 recommended)
# You can put apiLevel here or in `metadata["apiLevel"]`.
requirements = {"apiLevel": "2.15"}  # see docs on versioning
metadata = {
    "protocolName": "HTGAA W3 — Gel Art Mix (5 colors) — Skeleton",
    "author": "Alireza Hekmati",
    "description": "Distribute 5 color channels to a 96-well plate; log tip count and per-color volumes."
}

from opentrons import protocol_api

def run(protocol: protocol_api.ProtocolContext):
    # --- Deck / labware -------------------------------------------------------
    # Tip rack: 300 µL filtered/unfiltered (OT-2 standard)
    tips300 = protocol.load_labware("opentrons_96_tiprack_300ul", "8")
    # Plate: Corning 96-well, 360 µL flat bottom
    plate   = protocol.load_labware("corning_96_wellplate_360ul_flat", "2")
    # Tube rack: Eppendorf 1.5 mL Safe-Lock (24 position)
    tuberack = protocol.load_labware("opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap", "5")

    # Pipette: P300 Single-Channel GEN2 on left
    p300 = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips300])

    # --- Parameters you may tweak ---------------------------------------------
    VOLUME_PER_WELL = 30   # µL to dispense per destination well
    N_WELLS_PER_COLOR = 6  # how many wells to fill for each color
    MIX_BEFORE_ASPIRATE = (3, 150)  # (reps, µL) on source tube

    # Map dye sources in tube rack (prepare physical dyes in these tubes)
    # A1..A5 will be the 5 color sources.
    sources = {
        "Red":   tuberack["A1"],
        "Yellow":tuberack["A2"],
        "Green": tuberack["A3"],
        "Cyan":  tuberack["A4"],
        "Blue":  tuberack["A5"],
    }

    # Choose simple destination pattern: first 5 rows (A-E), left to right
    row_index = {"A":0, "B":1, "C":2, "D":3, "E":4}
    dest_rows = {
        "Red":    "A",
        "Yellow": "B",
        "Green":  "C",
        "Cyan":   "D",
        "Blue":   "E",
    }

    # --- Accounting: tip count & per-color volumes ----------------------------
    tips_used = 0
    per_color_uL = {k: 0 for k in sources.keys()}

    # Helper to pick up a tip and track it
    def get_tip():
        nonlocal tips_used
        p300.pick_up_tip()
        tips_used += 1

    # --- Work loop -------------------------------------------------------------
    for color, src in sources.items():
        # Decide the row and the first N destinations in that row
        row = dest_rows[color]
        dests = plate.rows()[row_index[row]][:N_WELLS_PER_COLOR]

        # Mix the source (optional, helps with homogeneity)
        get_tip()
        p300.mix(MIX_BEFORE_ASPIRATE[0], MIX_BEFORE_ASPIRATE[1], src)

        # Use one tip per color; distribute to N wells
        for d in dests:
            p300.aspirate(VOLUME_PER_WELL, src)   # atomic commands: aspirate/dispense
            p300.dispense(VOLUME_PER_WELL, d)
            # (optional) touch_tip to minimize droplets
            # p300.touch_tip(d)

            per_color_uL[color] += VOLUME_PER_WELL

        # Final blowout back into source top to clear residual
        p300.blow_out(src.top())
        p300.drop_tip()

    # --- Log summary to run log -----------------------------------------------
    protocol.comment("=== HTGAA W3 — RUN SUMMARY ===")
    protocol.comment(f"Tips used (P300): {tips_used}")
    for c, uL in per_color_uL.items():
        protocol.comment(f"{c}: {uL} µL total")

    protocol.comment("Per-color wells filled: " + str(N_WELLS_PER_COLOR))
    protocol.comment(f"Volume per well: {VOLUME_PER_WELL} µL")
    protocol.comment("Plate: corning_96_wellplate_360ul_flat | Tips: opentrons_96_tiprack_300ul")