mcpField
O
opentrons-protocol-api

opentrons-protocol-api

github.com/jaechang-hits其他38468 次安装6 天前更新
代码仓库

关于 opentrons-protocol-api

opentrons-protocol-api 是用于为 OT-2 和 Flex 机器人编写 Python 液体处理流程的技能。它提供移液器、实验室器皿和硬件模块操作,并支持在机器人运行前进行本地模拟。

主要功能

  1. 01以 Python 文件编写流程
  2. 02控制移液转移和吸头使用
  3. 03加载实验室器皿并访问孔位
  4. 04操作温控和磁力模块
  5. 05在本地模拟流程

适用场景

  1. 01设置 PCR 反应并运行热循环
  2. 02在微孔板上制作系列稀释
  3. 03自动执行磁珠纯化
  4. 04协调液体处理与模块控制

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill opentrons-protocol-api

安装后在 Claude Code 中输入/opentrons-protocol-api确认已加载。

详细介绍

Opentrons Python Protocol API

概述

Opentrons Protocol API v2 可让你将液体处理流程编写为纯 Python 文件,并在 OT-2 或 Flex 机器人上运行。每个流程都定义一个 metadata 字典、一个可选的 requirements 字典,以及一个 run(protocol) 函数。传递给 run() 的 ProtocolContext 对象提供所有甲板设置、移液器操作、模块控制和实用方法。上传到机器人之前,可以在任何计算机上使用 opentrons_simulate 模拟流程,也可以通过 Opentrons App 或 HTTP API 上传。

适用场景

  • 设置 PCR 反应:将主混合液从试管架分配到热循环仪板中,从单个试管中加入模板 DNA,然后自动执行 PCR 程序。
  • 执行系列稀释:以编程方式让多通道移液器在 96 孔板上逐步操作,使用指定的稀释液体积创建 2 倍或自定义稀释曲线。
  • 进行 ELISA 板布局:向指定孔中加入封闭缓冲液、一抗、二抗和底物,并在每种试剂之间更换吸头。
  • 自动执行磁珠纯化:启用/停用磁力模块,吸取上清液,用乙醇清洗并洗脱,全程通过自动化循环完成。
  • 板型转换和转印:使用一条命令将整个 96 孔板转移到目标板;也可以将试管中的样品重新排布到板中。
  • 集成硬件模块:在单个流程中协调温控、振荡和液体处理步骤,并精确计时。
  • 如果要编写必须在 Hamilton STAR、Tecan Freedom EVO 或其他厂商的设备上运行的流程,请改用 PyLabRobot;对于仅使用 Opentrons 的工作流,原生 Protocol API 的集成更紧密,模块支持也更完善。
  • 若要在自动化前检索和解析已发布的流程,请同时使用 protocolsio-integration 搜索 protocols.io。

前置条件

  • Python 包:opentrons
  • 机器人类型:OT-2(插槽 1-11,Gen2 移液器)或 Flex(插槽 A1-D3,Flex 移液器)
  • 环境:Python 3.10+;使用 Opentrons App 上传到实体机器人
  • CLI 工具:软件包自带 opentrons_simulate,用于本地测试
pip install opentrons
# Verify installation and simulate a protocol locally
opentrons_simulate my_protocol.py

快速入门

展示所有必需元素的最简流程——元数据、实验室耗材、仪器和转移操作:

from opentrons import protocol_api

metadata = {
    "protocolName": "Simple Reagent Distribution",
    "author": "Lab Automation Team",
    "apiLevel": "2.19",
}

def run(protocol: protocol_api.ProtocolContext):
    # Load labware onto deck slots
    tips    = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    source  = protocol.load_labware("nest_12_reservoir_15ml", "2")
    plate   = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")

    # Load pipette and attach tip rack
    pipette = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])

    # Distribute 50 µL from reservoir A1 to first 12 wells using one tip
    pipette.distribute(50, source["A1"], plate.wells()[:12], new_tip="once")
    protocol.comment("Distribution complete")
# Simulate locally — no robot needed
opentrons_simulate simple_reagent_distribution.py

核心 API

模块 1:流程元数据和甲板设置

每个流程都必须包含一个 metadata 字典,至少指定 apiLevel。可选的 requirements 字典用于设置目标机器人类型。所有实验室耗材和仪器都通过 ProtocolContext 加载。

from opentrons import protocol_api

# Minimum required metadata
metadata = {
    "protocolName": "My Assay Protocol",
    "author": "Jane Smith <[email protected]>",
    "description": "96-well assay setup with temperature control",
    "apiLevel": "2.19",
}

# Optional: target a specific robot type (Flex or OT-2)
requirements = {"robotType": "OT-2", "apiLevel": "2.19"}

def run(protocol: protocol_api.ProtocolContext):
    # OT-2: slots numbered 1-11 in a 3×4 grid
    tips_300 = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    tips_20  = protocol.load_labware("opentrons_96_tiprack_20ul",  "4")
    source   = protocol.load_labware("nest_12_reservoir_15ml",     "2", label="Buffer Reservoir")
    plate    = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
    tube_rack = protocol.load_labware("opentrons_24_tuberack_nest_1.5ml_snapcap", "5")

    # Load both pipettes (optional: one or two mounts)
    p300 = protocol.load_instrument("p300_single_gen2", "left",  tip_racks=[tips_300])
    p20  = protocol.load_instrument("p20_single_gen2",  "right", tip_racks=[tips_20])

    print(f"Deck has {len(protocol.deck)} slots; pipettes: {[p300.name, p20.name]}")

OT-2 甲板布局(3 列 × 4 行,按从左到右、从下到上的顺序编号):

Slot map (OT-2):         Slot map (Flex, A-D rows, 1-3 cols):
 10 | 11 | Trash          D1 | D2 | D3
  7 |  8 |  9             C1 | C2 | C3
  4 |  5 |  6             B1 | B2 | B3
  1 |  2 |  3             A1 | A2 | A3

常见 OT-2 移液器名称:p20_single_gen2、p300_single_gen2、p1000_single_gen2、p20_multi_gen2、p300_multi_gen2。 常见 Flex 移液器名称:p50_single_flex、p1000_single_flex、p50_multi_flex、p1000_multi_flex、flex_96channel_1000。

模块 2:移液器操作

用于精确逐步控制的底层吸液/分液/吹出操作。

def run(protocol: protocol_api.ProtocolContext):
    tips   = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    source = protocol.load_labware("nest_12_reservoir_15ml", "2")
    dest   = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
    p300   = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])

    p300.pick_up_tip()

    # Aspirate and dispense — basic liquid movement
    p300.aspirate(100, source["A1"])         # draw 100 µL from reservoir
    p300.dispense(100, dest["A1"])           # expel into plate well

    # Air gap to prevent dripping during transport
    p300.aspirate(80, source["A2"])
    p300.air_gap(20)                         # draw 20 µL air to cap the tip
    p300.dispense(100, dest["A2"])           # dispenses liquid + air

    # Mix in place (repetitions, volume)
    p300.mix(3, 60, dest["A1"])             # mix 60 µL × 3 times

    # Remove exterior droplets / expel residual
    p300.touch_tip(dest["A1"])              # wipe tip on well rim
    p300.blow_out(dest["A1"].top())         # expel last drop at top

    p300.drop_tip()
    protocol.comment("Low-level operations complete")
def run(protocol: protocol_api.ProtocolContext):
    tips = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    p300 = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])

    # Adjust flow rates (µL/s) for viscous or sensitive samples
    p300.flow_rate.aspirate = 50    # slow down for viscous liquids (default ~150)
    p300.flow_rate.dispense = 150   # default dispense speed
    p300.flow_rate.blow_out = 300   # fast blow-out for complete expulsion
    print(f"Aspirate rate: {p300.flow_rate.aspirate} µL/s")
模块 3:transfer() 快捷方法

transfer()、distribute() 和 consolidate() 会自动管理吸头,并支持混匀、吹出和空气间隙选项。

def run(protocol: protocol_api.ProtocolContext):
    tips   = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    source = protocol.load_labware("corning_96_wellplate_360ul_flat", "2")
    dest   = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
    p300   = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])

    # transfer(): one source → one destination, with optional per-well tip changes
    p300.transfer(
        100,
        source["A1"],
        dest["A1"],
        new_tip="always",       # options: "always", "once", "never"
        mix_after=(3, 50),      # mix 50 µL × 3 reps after each dispense
        blow_out=True,
        touch_tip=True,
    )

    # transfer() with lists: pairwise source-destination mapping
    sources = source.wells()[:8]
    dests   = dest.wells()[:8]
    p300.transfer(75, sources, dests, new_tip="always")

    # distribute(): one source → many destinations (single tip, multi-dispense)
    p300.distribute(
        50,
        source["A1"],
        dest.wells()[:12],
        new_tip="once",         # use one tip for all destinations
        disposal_volume=10,     # extra volume drawn to ensure accuracy
    )

    # consolidate(): many sources → one destination (collect, then dispense)
    p300.consolidate(
        50,
        source.wells()[:8],
        dest["A1"],
        mix_after=(3, 100),
    )
    print("Compound transfer operations complete")
模块 4:实验室耗材、液体和孔位访问

从库中加载实验室耗材,按名称/行/列定位孔位,并定义液体,以便在 Opentrons App 中进行可视化追踪。

def run(protocol: protocol_api.ProtocolContext):
    plate  = protocol.load_labware("corning_96_wellplate_360ul_flat", "1")
    p300   = protocol.load_instrument("p300_single_gen2", "left",
                                      tip_racks=[protocol.load_labware("opentrons_96_tiprack_300ul", "2")])

    # Access wells by alphanumeric name
    well_a1 = plate["A1"]

    # Access all wells (column-major order: A1, B1, C1, ..., H1, A2, ...)
    all_wells = plate.wells()
    print(f"Total wells: {len(all_wells)}")   # 96

    # Access by row (8 rows, A-H; each row has 12 wells)
    row_a = plate.rows()[0]    # [A1, A2, ..., A12]
    row_b = plate.rows()[1]    # [B1, B2, ..., B12]

    # Access by column (12 columns, 1-12; each column has 8 wells)
    col_1 = plate.columns()[0]   # [A1, B1, C1, D1, E1, F1, G1, H1]

    # Vertical position control within a well
    p300.pick_up_tip()
    p300.aspirate(80, well_a1.bottom(z=1))   # 1 mm above well bottom
    p300.dispense(80, well_a1.top(z=-2))     # 2 mm below well top
    p300.aspirate(80, well_a1.center())      # geometric center
    p300.drop_tip()
def run(protocol: protocol_api.ProtocolContext):
    reservoir = protocol.load_labware("nest_12_reservoir_15ml", "1")
    plate     = protocol.load_labware("corning_96_wellplate_360ul_flat", "2")

    # Define liquids for visual tracking in Opentrons App
    pbs     = protocol.define_liquid(name="1× PBS",    description="Phosphate buffered saline",    display_color="#0077BB")
    sample  = protocol.define_liquid(name="Sample",    description="Cell lysate, 1 mg/mL protein", display_color="#EE7733")

    # Assign liquids to wells with known starting volumes (µL)
    reservoir["A1"].load_liquid(liquid=pbs,    volume=10000)
    reservoir["A2"].load_liquid(liquid=sample, volume=5000)

    # Mark destination wells as empty
    for well in plate.wells():
        well.load_empty()

    print("Liquids defined and assigned")
模块 5:硬件模块

控制温控、磁力、热循环仪和加热振荡模块。每个模块都通过其型号名称字符串加载,并占用特定的甲板插槽。

def run(protocol: protocol_api.ProtocolContext):
    # --- Temperature Module (Gen2) ---
    temp_mod = protocol.load_module("temperature module gen2", "3")
    temp_plate = temp_mod.load_labware("corning_96_wellplate_360ul_flat")
    temp_mod.set_temperature(celsius=4)       # blocks until target reached
    print(f"Temp module: {temp_mod.temperature}°C")
    # temp_mod.deactivate()                   # turn off at end

    # --- Magnetic Module (Gen2) ---
    mag_mod  = protocol.load_module("magnetic module gen2", "6")
    mag_plate = mag_mod.load_labware("nest_96_wellplate_100ul_pcr_full_skirt")
    mag_mod.engage(height_from_base=10)       # raise magnets 10 mm from plate base
    protocol.delay(seconds=300)               # hold beads for 5 min
    mag_mod.disengage()

    # --- Heater-Shaker Module ---
    hs_mod = protocol.load_module("heaterShakerModuleV1", "1")
    hs_plate = hs_mod.load_labware("corning_96_wellplate_360ul_flat")
    hs_mod.close_labware_latch()
    hs_mod.set_target_temperature(celsius=37)
    hs_mod.wait_for_temperature()
    hs_mod.set_and_wait_for_shake_speed(rpm=500)
    protocol.delay(minutes=30)
    hs_mod.deactivate_shaker()
    hs_mod.deactivate_heater()
    hs_mod.open_labware_latch()
    print("Heater-shaker cycle complete")
def run(protocol: protocol_api.ProtocolContext):
    # --- Thermocycler Module (Gen2) ---
    # Auto-occupies slots 7-11 on OT-2; no slot argument needed
    tc_mod  = protocol.load_module("thermocyclerModuleV2")
    tc_plate = tc_mod.load_labware("nest_96_wellplate_100ul_pcr_full_skirt")

    tc_mod.open_lid()
    tc_mod.set_lid_temperature(celsius=105)   # pre-heat lid to prevent condensation

    # Initial denaturation
    tc_mod.set_block_temperature(95, hold_time_seconds=180)

    # PCR cycling profile
    profile = [
        {"temperature": 95, "hold_time_seconds": 15},   # denaturation
        {"temperature": 60, "hold_time_seconds": 30},   # annealing
        {"temperature": 72, "hold_time_seconds": 30},   # extension
    ]
    tc_mod.execute_profile(steps=profile, repetitions=35, block_max_volume=25)

    # Final extension and hold
    tc_mod.set_block_temperature(72, hold_time_minutes=5)
    tc_mod.set_block_temperature(4)           # hold at 4°C indefinitely
    tc_mod.deactivate_lid()
    tc_mod.open_lid()
    print("PCR complete; plate held at 4°C")
模块 6:高级流程功能

暂停以等待用户交互、记录可在应用中查看的注释、控制导轨灯,并检测模拟模式。

def run(protocol: protocol_api.ProtocolContext):
    # Pause and prompt the user (robot stops, app shows message)
    protocol.pause(msg="Add 10 µL of enzyme to tube A1, then resume")

    # Timed delay (robot waits without user action)
    protocol.delay(seconds=30, msg="Waiting 30s for reaction incubation")
    protocol.delay(minutes=5)

    # Log a comment visible in Opentrons App run log
    protocol.comment("Starting serial dilution — columns 1 to 11")

    # Rail lights for visual status indication
    protocol.set_rail_lights(True)    # lights on
    protocol.set_rail_lights(False)   # lights off

    # Home all axes (useful after an error or before finishing)
    protocol.home()

    # Detect simulation vs. physical run — skip slow waits in simulation
    if protocol.is_simulating():
        protocol.comment("Running in simulation mode — skipping 10-min incubation")
    else:
        protocol.delay(minutes=10)

    # Load waste bin (Flex only — OT-2 uses fixed trash)
    # trash = protocol.load_trash_bin("A3")

    print("Protocol control features demonstrated")

常见工作流

工作流 1:使用热循环仪进行 PCR 设置

目标:将预混液从试管架转移到热循环仪上的 PCR 板中,从单独的样本中加入模板 DNA,然后运行完整的 PCR 循环程序。

from opentrons import protocol_api

metadata = {
    "protocolName": "PCR Setup and Run",
    "author": "Lab Automation",
    "apiLevel": "2.19",
}

def run(protocol: protocol_api.ProtocolContext):
    # Hardware setup
    tc_mod    = protocol.load_module("thermocyclerModuleV2")
    tc_plate  = tc_mod.load_labware("nest_96_wellplate_100ul_pcr_full_skirt")
    tips_300  = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    tips_20   = protocol.load_labware("opentrons_96_tiprack_20ul",  "4")
    reagents  = protocol.load_labware("opentrons_24_tuberack_nest_1.5ml_snapcap", "2")
    p300      = protocol.load_instrument("p300_single_gen2", "left",  tip_racks=[tips_300])
    p20       = protocol.load_instrument("p20_single_gen2",  "right", tip_racks=[tips_20])

    # Define liquids
    master_mix = protocol.define_liquid("Master Mix", "2× PCR master mix", "#33BBEE")
    template   = protocol.define_liquid("Template",   "gDNA 10 ng/µL",     "#EE3377")
    reagents["A1"].load_liquid(master_mix, volume=500)
    for i in range(8):
        reagents.wells()[i + 1].load_liquid(template, volume=50)

    # Step 1: Open lid and distribute master mix (20 µL per well, 8 wells)
    tc_mod.open_lid()
    protocol.comment("Distributing master mix")
    p300.distribute(
        20,
        reagents["A1"],
        tc_plate.wells()[:8],
        new_tip="once",
        blow_out=True,
        blowout_location="source well",
    )

    # Step 2: Add template DNA (5 µL per well, fresh tip each time)
    protocol.comment("Adding template DNA")
    for i in range(8):
        p20.transfer(
            5,
            reagents.wells()[i + 1],
            tc_plate.wells()[i],
            new_tip="always",
            mix_after=(2, 10),
        )

    # Step 3: Run PCR
    tc_mod.close_lid()
    tc_mod.set_lid_temperature(105)
    tc_mod.set_block_temperature(95, hold_time_seconds=180)  # initial denaturation

    profile = [
        {"temperature": 95, "hold_time_seconds": 15},
        {"temperature": 60, "hold_time_seconds": 30},
        {"temperature": 72, "hold_time_seconds": 30},
    ]
    tc_mod.execute_profile(steps=profile, repetitions=35, block_max_volume=25)
    tc_mod.set_block_temperature(72, hold_time_minutes=5)    # final extension
    tc_mod.set_block_temperature(4)                          # hold
    tc_mod.deactivate_lid()
    tc_mod.open_lid()
    protocol.comment("PCR complete — 8 reactions in wells A1:H1")
工作流 2:使用多通道移液器进行 ELISA 系列稀释

目标:使用多通道移液器向第 2 至第 12 列加入稀释液,在整块板上进行 2 倍系列稀释,并一次性向所有孔中加入检测试剂。

from opentrons import protocol_api

metadata = {
    "protocolName": "ELISA Serial Dilution",
    "author": "Lab Automation",
    "apiLevel": "2.19",
}

def run(protocol: protocol_api.ProtocolContext):
    # Deck layout
    tips_300  = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    tips_300b = protocol.load_labware("opentrons_96_tiprack_300ul", "4")  # extra rack
    reservoir = protocol.load_labware("nest_12_reservoir_15ml", "2")
    plate     = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
    multi     = protocol.load_instrument("p300_multi_gen2", "left",
                                          tip_racks=[tips_300, tips_300b])

    # Define liquids
    diluent = protocol.define_liquid("Diluent", "PBS + 1% BSA", "#0077BB")
    sample  = protocol.define_liquid("Sample",  "Serum 1:10",   "#EE7733")
    reservoir["A1"].load_liquid(diluent, volume=50000)
    reservoir["A2"].load_liquid(sample,  volume=5000)

    # Step 1: Load column 1 with undiluted sample (all 8 rows at once)
    protocol.comment("Loading undiluted sample into column 1")
    multi.transfer(100, reservoir["A2"], plate.columns()[0], new_tip="once")

    # Step 2: Add diluent to columns 2-12
    protocol.comment("Adding diluent to columns 2-12")
    multi.distribute(
        100,
        reservoir["A1"],
        [col[0] for col in plate.columns()[1:]],  # A2 through A12 (multi-channel reads full column)
        new_tip="once",
        disposal_volume=10,
    )

    # Step 3: Serial dilution — transfer 100 µL from each column to the next, mix
    protocol.comment("Performing 2-fold serial dilution across columns 1→11")
    multi.transfer(
        100,
        [col[0] for col in plate.columns()[:11]],   # cols 1-11 as source
        [col[0] for col in plate.columns()[1:]],    # cols 2-12 as destination
        mix_after=(5, 80),                           # mix 80 µL × 5 reps after each dispense
        new_tip="always",                            # fresh tip per column to avoid carry-over
    )

    # Step 4: Remove 100 µL from column 12 to equalize volumes
    multi.pick_up_tip()
    multi.aspirate(100, plate.columns()[11][0])
    multi.drop_tip()

    protocol.comment("ELISA serial dilution complete — 11 dilution steps, 12 columns")
    print("Protocol complete: 2-fold dilution series across 96-well plate")

关键参数

参数模块 / 函数默认值范围 / 选项作用
new_tiptransfer、distribute、consolidate"always""always"、"once"、"never"控制更换吸头的策略;使用 "always" 可防止交叉污染
mix_aftertransferNone(重复次数, 体积) 元组每次分液后,在目标孔中吸液 / 排液,以使液体均匀
mix_beforetransferNone(重复次数, 体积) 元组每次吸液前,在源孔中吸液 / 排液
blow_outtransferFalseTrue、False分液后排出残余体积;设置 blowout_location 可控制排出位置
air_gaptransfer00–移液器最大值 µL吸液后加入空气间隙,防止机器人移动时滴漏
disposal_volumedistribute00–移液器最大值 µL开始时额外吸取的体积,可提高分液精度;随后弃入废液槽
flow_rate.aspirate移液器属性因型号而异1–1000 µL/s吸液速度;对黏稠样本(甘油、蛋白质 > 5 mg/mL)应调低
flow_rate.dispense移液器属性因型号而异1–1000 µL/s分液速度;对于易起泡或脆弱的细胞悬液应调低
height_from_basemag_mod.engage()—0–20 mm磁铁尖端高于板底的高度;取决于磁珠 / 板的几何结构
repetitionstc_mod.execute_profile()—1–99PCR 热循环次数

最佳实践

  1. 在硬件上运行前务必先进行模拟:使用 opentrons_simulate protocol.py 检查实验室耗材名称错误、吸头不足、体积溢出和槽位冲突,避免消耗耗材或占用机器人运行时间。

    opentrons_simulate my_pcr_setup.py
    # Output shows all commands; errors printed with line numbers
    
  2. 优先使用复合操作,而非手动执行取吸头 / 吸液 / 排液 / 弃吸头序列:transfer()、distribute() 和 consolidate() 会自动处理吸头管理、空气间隙和吹出。仅在复合方法不支持的操作中使用底层调用。

  3. 运行前清点吸头:计算吸头总消耗量(每次 new_tip="always" 转移会为每对孔消耗一个吸头)。如果吸头数量超过吸头架容量,请在 tip_racks=[] 中添加更多吸头架。

    n_transfers = len(source_wells)   # one tip per transfer
    tips_per_rack = 96
    racks_needed = -(-n_transfers // tips_per_rack)   # ceiling division
    print(f"Need {racks_needed} tip rack(s) for {n_transfers} transfers")
    
  4. 使用 define_liquid() 和 load_liquid() 验证设置:Opentrons App 中的液体追踪会以颜色标记孔及其体积,便于在按下 Run 前确认试剂放置正确。

  5. 在协议文件中区分 OT-2 槽位与 Flex 槽位:OT-2 使用数字字符串("1" 至 "11"),而 Flex 使用网格坐标("A1" 至 "D3")。设置 requirements = {"robotType": "Flex"} 或 "OT-2",以便在模拟期间检测槽位不匹配。

  6. 针对难处理的液体调整流速:黏稠溶液(≥20% 甘油、PEG、蛋白质 > 5 mg/mL)需要较低的吸液速度(25-50 µL/s)。对于易起泡的样本,应降低分液速度以避免产生气泡。

  7. 手动步骤使用 protocol.pause(),不要使用 protocol.delay():pause() 会停止机器人并通知操作员;运行会按需恢复。delay() 用于定时等待(孵育、模块平衡),此时不需要人工操作。

常用操作配方

配方:板复制(96 孔板到 96 孔板)

适用情况:使用每孔更换新吸头的方式,将整块源板复制到目标板。

from opentrons import protocol_api

metadata = {"protocolName": "Plate Replication", "apiLevel": "2.19"}

def run(protocol: protocol_api.ProtocolContext):
    tips   = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    source = protocol.load_labware("corning_96_wellplate_360ul_flat", "2")
    dest   = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
    p300   = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])

    # Transfer all 96 wells in one call — pairwise source[i] → dest[i]
    p300.transfer(100, source.wells(), dest.wells(), new_tip="always")
    protocol.comment("Plate replicated: 96 wells transferred")
配方:使用多通道移液器逐列加液

适用场景:使用多通道移液器和一个吸头,将单一试剂逐列加入 96 孔板。

from opentrons import protocol_api

metadata = {"protocolName": "Multi-Channel Fill", "apiLevel": "2.19"}

def run(protocol: protocol_api.ProtocolContext):
    tips      = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    reservoir = protocol.load_labware("nest_12_reservoir_15ml", "2")
    plate     = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
    multi     = protocol.load_instrument("p300_multi_gen2", "left", tip_racks=[tips])

    # distribute() with multi-channel: one pick-up, 12 dispenses across all columns
    multi.distribute(
        100,
        reservoir["A1"],
        [plate.columns()[i][0] for i in range(12)],
        new_tip="once",
        disposal_volume=10,
    )
    protocol.comment("96-well plate filled: 100 µL per well, single tip")
配方:磁珠清洗循环

适用场景:进行基于磁珠的自动化纯化(DNA 提取、IP 检测),并重复执行清洗步骤。

from opentrons import protocol_api

metadata = {"protocolName": "Magnetic Bead Wash", "apiLevel": "2.19"}

def run(protocol: protocol_api.ProtocolContext):
    mag_mod   = protocol.load_module("magnetic module gen2", "4")
    bead_plate = mag_mod.load_labware("nest_96_wellplate_100ul_pcr_full_skirt")
    tips      = protocol.load_labware("opentrons_96_tiprack_300ul", "1")
    reservoir = protocol.load_labware("nest_12_reservoir_15ml", "2")
    waste     = protocol.load_labware("nest_12_reservoir_15ml", "5")
    p300      = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[tips])

    # Engage magnets and remove supernatant
    mag_mod.engage(height_from_base=6)
    protocol.delay(seconds=120, msg="Beads pelleting on magnet")
    p300.transfer(90, bead_plate["A1"].bottom(z=0.5), waste["A1"], new_tip="once")

    # Wash loop (2 washes)
    for wash_num in range(2):
        mag_mod.disengage()
        protocol.comment(f"Wash {wash_num + 1} of 2")
        p300.transfer(100, reservoir["A1"], bead_plate["A1"],
                      mix_after=(5, 80), new_tip="always")
        mag_mod.engage(height_from_base=6)
        protocol.delay(seconds=90)
        p300.transfer(100, bead_plate["A1"].bottom(z=0.5), waste["A2"], new_tip="always")

    # Elute
    mag_mod.disengage()
    elution_plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "3")
    p300.transfer(50, reservoir["A2"], bead_plate["A1"],
                  mix_after=(10, 40), new_tip="always")
    mag_mod.engage(height_from_base=6)
    protocol.delay(seconds=120)
    p300.transfer(45, bead_plate["A1"].bottom(z=0.5), elution_plate["A1"], new_tip="always")
    mag_mod.disengage()
    protocol.comment("Bead cleanup complete: eluate in elution_plate A1")

故障排除

问题原因解决方案
LabwareNotFoundError: [labware name]培养器皿 API 名称字符串不正确在 labware.opentrons.com 查找确切名称;名称区分大小写(例如,"corning_96_wellplate_360ul_flat")
运行期间出现 OutOfTipsError协议所需吸头数量超出吸头盒提供的数量在 tip_racks=[] 中添加额外的吸头盒;或者在重新装入吸头盒后调用 pipette.reset_tipracks()
体积超过移液器的最大容量尝试吸取或分液的体积超过移液器容量使用 distribute() 自动拆分大体积;大体积(最高 1000 µL)可换用 p1000_single_gen2
DeckConflictError培养器皿放置在相互重叠的槽位中热循环仪会自动占用槽位 7-11;运行前检查模拟输出中的 protocol.deck
模拟通过,但机器人因 ModuleNotAttachedError 而失败模块未实际连接,或型号字符串错误检查 USB 连接;使用确切的型号字符串:"temperature module gen2"、"magnetic module gen2"、"thermocyclerModuleV2"、"heaterShakerModuleV1"
体积不准确,尤其是接近移液器最小量程时移液器处于校准量程边缘,或液体黏稠选择最佳量程覆盖所需体积的移液器;关键转移前使用 mix() 预润洗吸头;降低流速
transfer() 的孔列表长度不匹配时出现 TypeError源孔列表和目标孔列表长度不同成对转移时确保源孔列表和目标孔列表长度相同;或者使用单一源孔搭配目标孔列表进行一对多转移
在 Flex 上使用槽位名称时出现 OT-2 协议错误机器人类型不匹配(数字槽位与网格槽位)设置 requirements = {"robotType": "Flex"} 或 "OT-2",以强制指定槽位命名;Flex 槽位是 "A1" 这类字符串,OT-2 槽位是 "1"-"11"

相关技能

  • pylabrobot — 面向 Hamilton、Tecan、Beckman 等供应商的硬件无关 Python API;当协议必须在非 Opentrons 硬件上运行时使用
  • protocolsio-integration — 搜索并检索 protocols.io 上发布的湿实验室协议,以便改编为 Opentrons Python 协议
  • benchling-integration — 将协议执行与 Benchling ELN 条目和样本登记库连接起来

参考资料

评论

支持 Markdown