OT-2 HTTP Driver End-to-End Example#
This tutorial walks through a complete OT-2 workflow using the AFL-automation Opentrons driver stack. It is based on the repository notebook for preparing samples with OT2Prepare and demonstrates how to set up the robot, define stocks and targets, and execute a preparation protocol that includes both shaking and temperature control.
By the end, you will have connected to a robot, loaded pipettes and labware, prepared a sample from stock solutions, mixed it on a heater-shaker, moved it to a temperature module, and shut the system down cleanly.
This page is meant to be read as a full worked example rather than a task-specific reference.
What You Will Do#
In this tutorial, you will:
connect to an OT-2 over its HTTP interface
reset the driver state before starting a run
load pipettes, tip racks, custom labware, and modules
define stock solutions and a target sample
prepare the sample automatically
shake the sample and move it to a temperature-controlled location
deactivate modules and reset the robot at the end
Connection and Robot Requirements#
This tutorial requires a direct Ethernet connection between the OT-2 and the control computer running the notebook or script. That connection may be provided through USB-B Ethernet or through a LAN connection, but the control computer must be able to reach the OT-2 over the network.
Before you begin, confirm that your robot meets at least these requirements:
firmware version
v1.1.0-25e5ceaor newersupported Protocol API versions from
v2.0throughv2.28
You will also need the OT-2 IP address. You can find it in the Opentrons app under the network settings for the robot. Update the robot_ip field in the driver initialization below with that address. The port should remain 31950 unless you have changed it on your system.
Prerequisites#
Before you begin, make sure you have:
installed AFL-automation with Opentrons support
an Ethernet connection between the OT-2 and the control computer running this tutorial
the OT-2 IP address from the Opentrons app network settings
local copies of any custom labware JSON files used in the workflow
a physical deck layout that matches the slots and modules used below
Install the Opentrons extra if needed:
pip install AFL-automation[opentrons]
Step 1: Create the Driver#
Start by creating an OT2Prepare instance and pointing it at the robot. This tutorial uses the preparation-oriented wrapper because it combines deck control with stock and sample preparation logic.
Replace the example robot_ip value below with the IP address of your own OT-2.
from AFL.automation.prepare.OT2Prepare import OT2Prepare
import json
import time
driver = OT2Prepare(
overrides={
"robot_ip": "169.254.59.185",
"robot_port": "31950",
}
)
If you are repeating the tutorial, clear any previous state before continuing.
driver.reset_stocks()
driver.reset_deck()
driver.reset()
Step 2: Load Tip Racks and Pipettes#
Next, load the tip racks and attach the pipettes that will be used for transfers. The left mount carries a p20_single_gen2 and the right mount carries a p300_single_gen2.
driver.load_labware(name="opentrons_96_tiprack_20ul", slot="10")
driver.load_instrument(
name="p20_single_gen2",
mount="left",
tip_rack_slots=["10"],
)
driver.load_labware(name="opentrons_96_tiprack_300ul", slot="11")
driver.load_instrument(
name="p300_single_gen2",
mount="right",
tip_rack_slots=["11"],
)
At this point the driver can choose between the loaded pipettes when it plans transfers.
Step 3: Load Custom Source Labware#
The stock solutions in this example live in a custom vial holder. Load the labware definition from JSON and send it to the robot as part of the labware load call.
with open("./labware/ice_slurry_holder_20ml_3x2.json", "r") as f:
custom_labware_def = json.load(f)
driver.load_labware(
name="ice_slurry_holder",
slot="2",
labware_json=custom_labware_def,
)
When labware_json is provided, the driver uploads the definition and can reuse it in later runs.
Step 4: Load the Heater-Shaker Assembly#
Now load a heater-shaker module in slot 4 and place the destination plate on top of it. In this example, the adapter and plate are loaded as separate steps.
heater_shaker_id = driver.load_module("heaterShakerModuleV1", slot="4")
driver.unlatch_shaker(module_id=heater_shaker_id)
driver.load_labware(
name="opentrons_96_deep_well_adapter_nest_wellplate_2ml_deep",
slot="4",
module=heater_shaker_id,
)
driver.load_labware(
name="nest_96_wellplate_2ml_deep",
slot="4",
module=heater_shaker_id,
)
driver.latch_shaker(module_id=heater_shaker_id)
This is the destination where the prepared sample will initially be mixed.
Step 5: Load the Temperature Module#
The final sample is transferred to a vial holder mounted on a temperature module.
temp_module_id = driver.load_module("temperatureModuleV1", slot="3")
with open("./labware/5ml_vial_holder_1x1_hightemp.json", "r") as f:
vial_holder_def = json.load(f)
driver.load_labware(
name="vial_holder",
slot="3",
labware_json=vial_holder_def,
module=temp_module_id,
)
Notice that module-backed labware is associated with the module identifier rather than treated as a plain deck slot load.
Step 6: Define Components and Stock Solutions#
With the deck configured, define the components and stock solutions that the preparation layer will use to plan the sample.
driver.reset_stocks()
driver.add_component(name="H2O", formula="H2O", density="1.0 g/ml")
driver.add_component(name="YCl3", formula="YCl3")
driver.add_component(name="BSA")
driver.add_stock({
"name": "stock_BSA",
"location": "2A1",
"concentrations": {"BSA": "200 mg/ml"},
"volumes": {"H2O": "20 ml"},
"total_volume": "20 ml",
"solutes": ["BSA"],
})
driver.add_stock({
"name": "stock_YCl3",
"location": "2A2",
"molarities": {"YCl3": "1 mol/L"},
"volumes": {"H2O": "10 ml"},
"total_volume": "10 ml",
"solutes": ["YCl3"],
})
driver.add_stock({
"name": "stock_H2O",
"location": "2A3",
"volumes": {"H2O": "20 ml"},
"total_volume": "20 ml",
})
The stock metadata is what allows the driver to compute a feasible preparation plan.
Step 7: Define and Prepare the Target Sample#
Now describe the sample you want to make and ask the driver whether it can be prepared from the stocks currently on deck.
target = {
"name": "bsa_ycl3_sample",
"concentrations": {"BSA": "175 mg/ml"},
"molarities": {"YCl3": "43 mmol/L"},
"volumes": {"H2O": "1 ml"},
"total_volume": "1 ml",
"solutes": ["BSA", "YCl3"],
"location": "4A1",
}
feasible = driver.is_feasible(target)[0]
print("Feasible solution:", feasible)
If the target is feasible, execute the preparation into the destination well.
result, dest = driver.prepare(target, dest=target["location"])
During this step, the driver selects an appropriate loaded pipette and breaks transfers into smaller operations when necessary.
Step 8: Mix the Sample and Move It#
After the sample is prepared, briefly mix it on the heater-shaker and then transfer it to the vial holder on the temperature module.
driver.set_shake(400, module_id=heater_shaker_id)
time.sleep(5)
driver.stop_shake(module_id=heater_shaker_id)
driver.transfer(
source=result["destination"],
dest="3A1",
volume=float(result["total_volume"].replace("ul", "").strip()),
source_z_offset=1.0,
)
The source_z_offset helps keep the tip slightly above the bottom of the well during aspiration.
Step 9: Control the Temperature Module#
With the sample in its final location, step through a few temperatures and inspect the module status after each change.
for temp_c in [10.0, 30.0, 50.0]:
print(f"Setting sample temperature to {temp_c} C")
driver.set_tempmodule_temperature(temp_module_id, temp_c)
time.sleep(10)
driver.get_tempmodule_status()
driver.deactivate_tempmodule(temp_module_id)
This demonstrates both active temperature control and clean module shutdown.
Step 10: Finish the Run#
When the example is complete, home the robot and reset the driver state.
driver.home()
driver.reset()
What This Tutorial Demonstrated#
You have now walked through a full OT-2 HTTP driver example that combines:
deck setup
custom labware loading
module control
stock-aware sample preparation
direct liquid transfer
temperature control
end-of-run cleanup
From here, you can adapt the same pattern to your own deck layouts, stock definitions, and sample recipes.