计划执行与检查节点
executing-plans
按既定实施计划完成工作,保持过程检查和反馈。
opentrons-gripper【效率与协作】Opentrons Flex Gripper - automated labware movement between deck locations, modules, waste chute, and off-deck storage with precise positioning and offset control for hands-free plate transfers
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
The Opentrons Flex Gripper enables fully automated labware movement without manual intervention. It moves plates, reservoirs, and tip racks between deck slots, hardware modules, trash/waste chute, and off-deck storage with precise positioning and optional offset adjustments.
Core value: Eliminate manual plate transfers during protocols. Automatically move labware between modules, enabling complex multi-step workflows without pausing for user intervention.
Platform: Opentrons Flex only (not available on OT-2)
Use the Gripper skill when:
Don't use when:
| Operation | Method | Key Parameters |
|---|---|---|
| Move labware | protocol.move_labware() | labware, new_location, use_gripper=True |
| Move with offsets | protocol.move_labware() | pick_up_offset, drop_offset |
| Move to module | protocol.move_labware() | labware, module_object, use_gripper=True |
| Dispose in waste | protocol.move_labware() | labware, waste_chute, use_gripper=True |
| Move off-deck | protocol.move_labware() | labware, OFF_DECK, use_gripper=True |
| Manual movement | protocol.move_labware() | use_gripper=False (pauses for user) |
Opentrons Flex only
"robotType": "Flex"from opentrons import protocol_api
metadata = {'apiLevel': '2.19'}
requirements = {"robotType": "Flex", "apiLevel": "2.19"}
def run(protocol: protocol_api.ProtocolContext):
# Load labware
source_plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "C1")
# Move labware to new deck slot
protocol.move_labware(
labware=source_plate,
new_location="D2",
use_gripper=True
)
Deck slot formats (both work):
# Load module and labware
temp_mod = protocol.load_module("temperature module gen2", "D1")
plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "C2")
# Move plate to temperature module
protocol.move_labware(
labware=plate,
new_location=temp_mod,
use_gripper=True
)
# Load waste chute
waste_chute = protocol.load_waste_chute()
# Dispose of used plate
protocol.move_labware(
labware=used_plate,
new_location=waste_chute,
use_gripper=True
)
from opentrons.protocol_api import OFF_DECK
# Move labware off the deck (to storage)
protocol.move_labware(
labware=archive_plate,
new_location=OFF_DECK,
use_gripper=True
)
# Later: bring back from off-deck storage
protocol.move_labware(
labware=archive_plate,
new_location="B3",
use_gripper=True
)
Use case: Free up deck space by temporarily storing labware off-deck
Fine-tune pickup and drop positions with offset vectors:
protocol.move_labware(
labware=plate,
new_location="D2",
use_gripper=True,
pick_up_offset={"x": 0, "y": 0, "z": 2}, # Lift 2mm higher when picking up
drop_offset={"x": 0, "y": 0, "z": 1} # Place 1mm higher when dropping
)
Offset units: Millimeters Coordinates:
Pick-up offset:
Drop-off offset:
# Custom deep-well plate requires higher pickup
custom_plate = protocol.load_labware("custom_deepwell_96", "C1")
protocol.move_labware(
labware=custom_plate,
new_location="D1",
use_gripper=True,
pick_up_offset={"x": 0, "y": 0, "z": 3}, # Pickup 3mm higher
drop_offset={"x": 0, "y": 0, "z": 0} # Standard drop
)
Set use_gripper=False to pause protocol for user to manually move labware:
# Pause for manual movement
protocol.move_labware(
labware=delicate_plate,
new_location="D3",
use_gripper=False # Protocol pauses, user moves plate manually
)
Use case: Delicate labware, non-grippable items, or troubleshooting
temp_mod = protocol.load_module("temperature module gen2", "D1")
plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "C2")
# Move to temperature module
protocol.move_labware(plate, temp_mod, use_gripper=True)
# Set temperature
temp_mod.set_temperature(4)
protocol.delay(minutes=5)
# Move off module
protocol.move_labware(plate, "C2", use_gripper=True)
temp_mod.deactivate()
Critical: Open labware latch before gripper operations
hs_mod = protocol.load_module("heaterShakerModuleV1", "D1")
adapter = hs_mod.load_adapter("opentrons_96_flat_bottom_adapter")
plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "C2")
# Open latch BEFORE moving plate to module
hs_mod.open_labware_latch()
# Move plate to heater-shaker
protocol.move_labware(plate, hs_mod, use_gripper=True)
# Close latch for shaking
hs_mod.close_labware_latch()
hs_mod.set_and_wait_for_temperature(37)
hs_mod.set_and_wait_for_shake_speed(500)
protocol.delay(minutes=10)
hs_mod.deactivate_shaker()
hs_mod.deactivate_heater()
# Open latch BEFORE removing plate
hs_mod.open_labware_latch()
# Move plate off module
protocol.move_labware(plate, "C2", use_gripper=True)
Critical: Open lid before gripper operations
tc_mod = protocol.load_module("thermocyclerModuleV2")
plate = protocol.load_labware("opentrons_96_wellplate_200ul_pcr_full_skirt", "C2")
# Open lid BEFORE moving plate to thermocycler
tc_mod.open_lid()
# Move plate to thermocycler
protocol.move_labware(plate, tc_mod, use_gripper=True)
# Close lid and run PCR
tc_mod.close_lid()
tc_mod.set_lid_temperature(105)
# ... PCR cycling ...
# Open lid BEFORE removing plate
tc_mod.open_lid()
# Move plate off thermocycler
protocol.move_labware(plate, "C2", use_gripper=True)
mag_block = protocol.load_module("magneticBlockV1", "D1")
mag_plate = protocol.load_labware("biorad_96_wellplate_200ul_pcr", "C2")
# Move plate to magnetic block for bead separation
protocol.move_labware(mag_plate, mag_block, use_gripper=True)
# Wait for beads to collect
protocol.delay(minutes=3)
# Pipette supernatant (beads held by magnets)
pipette.transfer(150, mag_plate.wells(), waste.wells())
# Move plate off magnets for resuspension
protocol.move_labware(mag_plate, "C2", use_gripper=True)
Critical: Reader lid must be open before gripper operations
reader = protocol.load_module("absorbanceReaderV1", "D3")
assay_plate = protocol.load_labware("corning_96_wellplate_360ul_flat", "C2")
# Initialize reader
reader.close_lid()
reader.initialize(mode="single", wavelengths=[450])
# Open lid BEFORE moving plate to reader
reader.open_lid()
# Move plate to reader
protocol.move_labware(assay_plate, reader, use_gripper=True)
# Close lid and read
reader.close_lid()
data = reader.read()
# Open lid BEFORE removing plate
reader.open_lid()
# Move plate off reader
protocol.move_labware(assay_plate, "C2", use_gripper=True)
# DNA extraction with module transfers
sample_plate = protocol.load_labware("biorad_96_wellplate_200ul_pcr", "C1")
hs_mod = protocol.load_module("heaterShakerModuleV1", "D1")
mag_block = protocol.load_module("magneticBlockV1", "D2")
temp_mod = protocol.load_module("temperature module gen2", "D3")
# 1. Lysis on heater-shaker
hs_mod.open_labware_latch()
protocol.move_labware(sample_plate, hs_mod, use_gripper=True)
hs_mod.close_labware_latch()
hs_mod.set_and_wait_for_temperature(56)
hs_mod.set_and_wait_for_shake_speed(1000)
protocol.delay(minutes=15)
hs_mod.deactivate_shaker()
hs_mod.deactivate_heater()
hs_mod.open_labware_latch()
# 2. Bead binding on magnetic block
protocol.move_labware(sample_plate, mag_block, use_gripper=True)
protocol.delay(minutes=3)
pipette.transfer(150, sample_plate.wells(), waste.wells())
# 3. Elution on temperature module (cold)
protocol.move_labware(sample_plate, temp_mod, use_gripper=True)
temp_mod.set_temperature(4)
pipette.transfer(50, elution_buffer, sample_plate.wells())
# 4. Return to deck
protocol.move_labware(sample_plate, "C1", use_gripper=True)
temp_mod.deactivate()
# Process multiple plates sequentially
plates = [
protocol.load_labware("corning_96_wellplate_360ul_flat", "C1"),
protocol.load_labware("corning_96_wellplate_360ul_flat", "C2"),
protocol.load_labware("corning_96_wellplate_360ul_flat", "C3")
]
reader = protocol.load_module("absorbanceReaderV1", "D3")
reader.close_lid()
reader.initialize(mode="single", wavelengths=[600])
reader.open_lid()
for i, plate in enumerate(plates):
# Read each plate
protocol.move_labware(plate, reader, use_gripper=True)
reader.close_lid()
data = reader.read(export_filename=f"plate_{i+1}_od600")
reader.open_lid()
# Move to off-deck storage
protocol.move_labware(plate, OFF_DECK, use_gripper=True)
# Dispose of used consumables
waste_chute = protocol.load_waste_chute()
# After using tip rack
protocol.move_labware(empty_tips, waste_chute, use_gripper=True)
# After processing sample plate
protocol.move_labware(used_plate, waste_chute, use_gripper=True)
# Free up deck space by moving inactive labware off-deck
storage = OFF_DECK
# Initial setup - plates start on deck
plate_1 = protocol.load_labware("corning_96_wellplate_360ul_flat", "B1")
plate_2 = protocol.load_labware("corning_96_wellplate_360ul_flat", "B2")
plate_3 = protocol.load_labware("corning_96_wellplate_360ul_flat", "B3")
# Process plate 1
# ... operations on plate_1 ...
# Move plate 1 off-deck to free space
protocol.move_labware(plate_1, storage, use_gripper=True)
# Process plate 2
# ... operations on plate_2 ...
# Retrieve plate 1 when needed again
protocol.move_labware(plate_1, "B1", use_gripper=True)
The gripper can only move labware with compatible geometry.
Labware must have one of:
Most Opentrons labware and major brands (Corning, NEST, Axygen, Bio-Rad) are gripper-compatible. Check labware definition or test before protocol deployment.
Examples of labware that may NOT be grippable:
Solution: Use use_gripper=False to prompt manual movement, or use adapters.
use_gripper=False backup for troubleshooting❌ Moving to Heater-Shaker with closed latch:
protocol.move_labware(plate, hs_mod, use_gripper=True) # Error: latch closed
✅ Correct:
hs_mod.open_labware_latch()
protocol.move_labware(plate, hs_mod, use_gripper=True)
❌ Moving to Thermocycler with closed lid:
protocol.move_labware(plate, tc_mod, use_gripper=True) # Error: lid closed
✅ Correct:
tc_mod.open_lid()
protocol.move_labware(plate, tc_mod, use_gripper=True)
❌ Moving non-grippable labware:
# Custom labware without gripper features
protocol.move_labware(custom_tubes, "D2", use_gripper=True) # Error: cannot grip
✅ Correct:
# Use manual movement for non-grippable labware
protocol.move_labware(custom_tubes, "D2", use_gripper=False)
❌ Forgetting to specify use_gripper:
protocol.move_labware(plate, "D2") # Defaults to use_gripper=False, pauses protocol
✅ Correct:
protocol.move_labware(plate, "D2", use_gripper=True) # Explicit gripper use
❌ Moving to occupied location:
plate_1 = protocol.load_labware("corning_96_wellplate_360ul_flat", "C1")
plate_2 = protocol.load_labware("corning_96_wellplate_360ul_flat", "C2")
protocol.move_labware(plate_1, "C2", use_gripper=True) # Error: C2 occupied by plate_2
✅ Correct:
# Move plate_2 first, then plate_1
protocol.move_labware(plate_2, OFF_DECK, use_gripper=True)
protocol.move_labware(plate_1, "C2", use_gripper=True)
Gripper cannot grip labware:
use_gripper=False for non-compatible labwareGripper collision errors:
Labware not properly seated after movement:
Protocol pauses unexpectedly:
use_gripper=True is specifiedOFF_DECK movement errors:
from opentrons.protocol_api import OFF_DECK# Use gripper for standard labware, manual for custom
def move_smart(protocol, labware, destination, is_grippable=True):
if is_grippable:
protocol.move_labware(labware, destination, use_gripper=True)
else:
protocol.comment(f"Please manually move {labware} to {destination}")
protocol.move_labware(labware, destination, use_gripper=False)
move_smart(protocol, standard_plate, "D2", is_grippable=True)
move_smart(protocol, custom_tubes, "D3", is_grippable=False)
# Test offsets to find optimal values
def test_gripper_offset(protocol, labware, destination, z_offset_range):
for z in z_offset_range:
protocol.comment(f"Testing pickup offset z={z}")
protocol.move_labware(
labware,
destination,
use_gripper=True,
pick_up_offset={"x": 0, "y": 0, "z": z}
)
protocol.pause("Check if pickup was successful. Resume to continue.")
# Move back
protocol.move_labware(labware, "C1", use_gripper=True)
# Run test
test_gripper_offset(protocol, test_plate, "D2", z_offset_range=[0, 1, 2, 3])
# Rotate plates through processing stations
def process_plate_carousel(protocol, plates, processing_station):
"""Process multiple plates through single module."""
for i, plate in enumerate(plates):
protocol.comment(f"Processing plate {i+1}/{len(plates)}")
# Move to processing station
protocol.move_labware(plate, processing_station, use_gripper=True)
# Process (example: read absorbance)
# ... processing steps ...
# Move to archive
protocol.move_labware(plate, OFF_DECK, use_gripper=True)
process_plate_carousel(protocol, [plate1, plate2, plate3], reader_module)
Tips for efficient gripper workflows:
Example efficient layout:
1 2 3 4
A [Plates] [Module1] [Reader] [Reserved]
B [Plates] [Module2] [Reader] [Reserved]
C [Tips] [Reagent] [Reader] [Reserved]
D [Tips] [Waste] [Reader] [Reserved]
Flex staging area slots (column 4: A4, B4, C4, D4) are used for:
Important: When Absorbance Reader is loaded, column 4 cannot be used for labware.
opentrons - Main Opentrons Python API skillopentrons-heater-shaker - Heater-Shaker Module (requires gripper integration)opentrons-absorbance-reader - Absorbance Plate Reader (requires gripper)opentrons-magnetic-block - Magnetic Block (designed for gripper workflow)opentrons-thermocycler - Thermocycler Module (gripper-compatible)opentrons-temperature-module - Temperature Module (gripper-compatible)