diff --git a/.gitignore b/.gitignore
index 2d8b2ff20cb5..9e3f45a218ee 100755
--- a/.gitignore
+++ b/.gitignore
@@ -164,4 +164,9 @@ mock_dir
.npm-cache/
.eslintcache
+# include archived API docs
+!api/docs/dist/
+api/docs/dist/hardware/
+api/docs/dist/v2/
+
package-testing/results
diff --git a/api/Makefile b/api/Makefile
index 28f7c7ff79ef..90e3282b01f9 100755
--- a/api/Makefile
+++ b/api/Makefile
@@ -155,11 +155,11 @@ docs/dist/%: docs/root/%
$(SHX) cp -R docs/root/* docs/dist/
.PHONY: docs
-docs: docs/dist/index.html docs/dist/v1 docs/dist/v2 docs/dist/ot1 docs/dist/hardware
+docs: docs/dist/v2 docs/dist/hardware
.PHONY: docs-clean
docs-clean:
- $(SHX) rm -rf docs/dist docs/build
+ $(SHX) rm -rf docs/dist/v2 docs/dist/hardware docs/build
.PHONY: dev
dev:
diff --git a/api/docs/dist/index.html b/api/docs/dist/index.html
new file mode 100644
index 000000000000..29b14356e39e
--- /dev/null
+++ b/api/docs/dist/index.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+ Welcome to the OT-2 Python Protocol API Docs — Opentrons OT-2 Python Protocol API Documentation
+
+
+
+
+
+ Your browser should automatically redirect you from this page.
+ But if it does not, click one of the following links to go to the docs:
+
+
+
diff --git a/api/docs/dist/ot1/.nojekyll b/api/docs/dist/ot1/.nojekyll
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/api/docs/dist/ot1/_images/384-plate.png b/api/docs/dist/ot1/_images/384-plate.png
new file mode 100644
index 000000000000..8c4bf2130467
Binary files /dev/null and b/api/docs/dist/ot1/_images/384-plate.png differ
diff --git a/api/docs/dist/ot1/_images/96-Deep-Well.png b/api/docs/dist/ot1/_images/96-Deep-Well.png
new file mode 100644
index 000000000000..84e8343bec5f
Binary files /dev/null and b/api/docs/dist/ot1/_images/96-Deep-Well.png differ
diff --git a/api/docs/dist/ot1/_images/96-PCR-Flatt.png b/api/docs/dist/ot1/_images/96-PCR-Flatt.png
new file mode 100644
index 000000000000..b90e7ab6f08f
Binary files /dev/null and b/api/docs/dist/ot1/_images/96-PCR-Flatt.png differ
diff --git a/api/docs/dist/ot1/_images/96-PCR-Strip.png b/api/docs/dist/ot1/_images/96-PCR-Strip.png
new file mode 100644
index 000000000000..5657b407cb5d
Binary files /dev/null and b/api/docs/dist/ot1/_images/96-PCR-Strip.png differ
diff --git a/api/docs/dist/ot1/_images/96-PCR-Tall.png b/api/docs/dist/ot1/_images/96-PCR-Tall.png
new file mode 100644
index 000000000000..687f28988ba4
Binary files /dev/null and b/api/docs/dist/ot1/_images/96-PCR-Tall.png differ
diff --git a/api/docs/dist/ot1/_images/SelectConfigFile.png b/api/docs/dist/ot1/_images/SelectConfigFile.png
new file mode 100644
index 000000000000..ed8341945474
Binary files /dev/null and b/api/docs/dist/ot1/_images/SelectConfigFile.png differ
diff --git a/api/docs/dist/ot1/_images/Tiprack-1000.png b/api/docs/dist/ot1/_images/Tiprack-1000.png
new file mode 100644
index 000000000000..f82c49211332
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tiprack-1000.png differ
diff --git a/api/docs/dist/ot1/_images/Tiprack-1000ul-chem.png b/api/docs/dist/ot1/_images/Tiprack-1000ul-chem.png
new file mode 100644
index 000000000000..72c666afdc93
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tiprack-1000ul-chem.png differ
diff --git a/api/docs/dist/ot1/_images/Tiprack-10ul-H.png b/api/docs/dist/ot1/_images/Tiprack-10ul-H.png
new file mode 100644
index 000000000000..cb013f0449dc
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tiprack-10ul-H.png differ
diff --git a/api/docs/dist/ot1/_images/Tiprack-10ul.png b/api/docs/dist/ot1/_images/Tiprack-10ul.png
new file mode 100644
index 000000000000..757a207f8f7c
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tiprack-10ul.png differ
diff --git a/api/docs/dist/ot1/_images/Tiprack-200ul.png b/api/docs/dist/ot1/_images/Tiprack-200ul.png
new file mode 100644
index 000000000000..c0f73d1026dc
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tiprack-200ul.png differ
diff --git a/api/docs/dist/ot1/_images/Trough-12row.png b/api/docs/dist/ot1/_images/Trough-12row.png
new file mode 100644
index 000000000000..e4d8fe13ae7a
Binary files /dev/null and b/api/docs/dist/ot1/_images/Trough-12row.png differ
diff --git a/api/docs/dist/ot1/_images/Tuberack-075ml.png b/api/docs/dist/ot1/_images/Tuberack-075ml.png
new file mode 100644
index 000000000000..3db2083ac9e9
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tuberack-075ml.png differ
diff --git a/api/docs/dist/ot1/_images/Tuberack-15-50ml.png b/api/docs/dist/ot1/_images/Tuberack-15-50ml.png
new file mode 100644
index 000000000000..6406fb7a8cb4
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tuberack-15-50ml.png differ
diff --git a/api/docs/dist/ot1/_images/Tuberack-2ml.png b/api/docs/dist/ot1/_images/Tuberack-2ml.png
new file mode 100644
index 000000000000..cd5b3903f47e
Binary files /dev/null and b/api/docs/dist/ot1/_images/Tuberack-2ml.png differ
diff --git a/api/docs/dist/ot1/_images/Well_Iteration.png b/api/docs/dist/ot1/_images/Well_Iteration.png
new file mode 100644
index 000000000000..90bba0f10a99
Binary files /dev/null and b/api/docs/dist/ot1/_images/Well_Iteration.png differ
diff --git a/api/docs/dist/ot1/_images/connected.png b/api/docs/dist/ot1/_images/connected.png
new file mode 100644
index 000000000000..feb0dd059303
Binary files /dev/null and b/api/docs/dist/ot1/_images/connected.png differ
diff --git a/api/docs/dist/ot1/_images/container-calibration.png b/api/docs/dist/ot1/_images/container-calibration.png
new file mode 100644
index 000000000000..a393bca7f432
Binary files /dev/null and b/api/docs/dist/ot1/_images/container-calibration.png differ
diff --git a/api/docs/dist/ot1/_images/container-list.png b/api/docs/dist/ot1/_images/container-list.png
new file mode 100644
index 000000000000..f0c1bbe1da32
Binary files /dev/null and b/api/docs/dist/ot1/_images/container-list.png differ
diff --git a/api/docs/dist/ot1/_images/dragFirmwareBin.png b/api/docs/dist/ot1/_images/dragFirmwareBin.png
new file mode 100644
index 000000000000..d9be9ca892fa
Binary files /dev/null and b/api/docs/dist/ot1/_images/dragFirmwareBin.png differ
diff --git a/api/docs/dist/ot1/_images/firmware_files.png b/api/docs/dist/ot1/_images/firmware_files.png
new file mode 100644
index 000000000000..6e75b2033d3a
Binary files /dev/null and b/api/docs/dist/ot1/_images/firmware_files.png differ
diff --git a/api/docs/dist/ot1/_images/move-to-slot.png b/api/docs/dist/ot1/_images/move-to-slot.png
new file mode 100644
index 000000000000..13fcee51952d
Binary files /dev/null and b/api/docs/dist/ot1/_images/move-to-slot.png differ
diff --git a/api/docs/dist/ot1/_images/pipette-calibration.png b/api/docs/dist/ot1/_images/pipette-calibration.png
new file mode 100644
index 000000000000..713e8ff4895d
Binary files /dev/null and b/api/docs/dist/ot1/_images/pipette-calibration.png differ
diff --git a/api/docs/dist/ot1/_images/pipette-jog.png b/api/docs/dist/ot1/_images/pipette-jog.png
new file mode 100644
index 000000000000..a65b0f6e0bd4
Binary files /dev/null and b/api/docs/dist/ot1/_images/pipette-jog.png differ
diff --git a/api/docs/dist/ot1/_images/ports.png b/api/docs/dist/ot1/_images/ports.png
new file mode 100644
index 000000000000..4b0f0af4b441
Binary files /dev/null and b/api/docs/dist/ot1/_images/ports.png differ
diff --git a/api/docs/dist/ot1/_images/replaceConfig.png b/api/docs/dist/ot1/_images/replaceConfig.png
new file mode 100644
index 000000000000..4b1dca9b5230
Binary files /dev/null and b/api/docs/dist/ot1/_images/replaceConfig.png differ
diff --git a/api/docs/dist/ot1/_images/running-protocol.png b/api/docs/dist/ot1/_images/running-protocol.png
new file mode 100644
index 000000000000..7c20b5aafa85
Binary files /dev/null and b/api/docs/dist/ot1/_images/running-protocol.png differ
diff --git a/api/docs/dist/ot1/_sources/api.txt b/api/docs/dist/ot1/_sources/api.txt
new file mode 100644
index 000000000000..3329624f3086
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/api.txt
@@ -0,0 +1,24 @@
+.. _api:
+
+API Reference
+===============
+
+.. module:: opentrons
+
+If you are reading this, you are probably looking for an in-depth explanation of API classes and methods to fully master your protocol development skills.
+
+Robot
+-----
+
+All protocols are set up, simulated and executed using a Robot class.
+
+.. autoclass:: Robot
+ :members: connect, home, reset, commands, move_to, containers, actions, disconnect, head_speed, pause, resume, stop, diagnostics, get_warnings, add_instrument, get_mosfet, get_motor
+
+Pipette
+-----------------
+
+.. module:: opentrons.instruments
+
+.. autoclass:: Pipette
+ :members: aspirate, dispense, mix, delay, drop_tip, blow_out, touch_tip, pick_up_tip, return_tip, calibrate, calibrate_position, move_to, home, set_speed
diff --git a/api/docs/dist/ot1/_sources/calibration.txt b/api/docs/dist/ot1/_sources/calibration.txt
new file mode 100644
index 000000000000..c3b0c4e17ca8
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/calibration.txt
@@ -0,0 +1,127 @@
+.. _calibration:
+
+================
+How to Calibrate
+================
+
+Download App
+--------------------
+
+You can download the latest version of the app from `our website`_.
+
+.. _our website: https://opentrons.com/getting-started/download-app
+
+
+Connect to Robot
+--------------------
+
+Make sure your robot is turned on, and your laptop is connected via USB cable.
+
+Go to the select port drop down, and refresh if no ports are shown. Once the port shows up, click it and the robot will jog up and down.
+
+.. screenshot button with port drop down
+
+.. image:: img/app/ports.png
+.. image:: img/app/connected.png
+
+.. important::
+
+ Every time you connect to the robot, you need to home all axes before doing anything else.
+
+.. note::
+
+ Linux users will need to get permission to open the robot's serial port. This requires `sudo` privileges.
+ In a terminal window, run the following command
+
+ .. code-block:: bash
+
+ sudo usermod -a -G dialout USER_NAME_HERE
+
+ Where USER_NAME_HERE is the name of account that will be running the App.
+
+ Finally, logout and log back in as the user to activate the change.
+
+Upload Protocol
+--------------------
+
+Your ``.py`` protocol file can load into the App, through either clicking the "Upload" button, or drag-and-drop the ``.py`` file over that same button.
+
+.. note::
+
+ Make sure that when saving a protocol file, it ends with the ``.py`` file extension. This will ensure the App and other programs are able to properly read it.
+
+ For example, ``my_protocol_file.py``
+
+If successfully loaded, your Python protocol will be simulated in the background to detect any errors. While this is happening, you will see the word "Upload" replaced by the word "Processing". Once finished, the App will fill the calibration section of the App with your containers and pipettes.
+
+
+Jogging
+--------------------
+
+XYZ
+^^^^^^^^^^^^^^^^^^^^
+
+Move in the X, Y and Z by selecting your desired increment, and then clicking an arrow button.
+
+.. image:: img/app/pipette-jog.png
+
+Slot Button
+^^^^^^^^^^^^^^^^^^^^
+
+The slot button moves exactly one slot over in either X or Y, depending on which arrow you choose. This is particularly useful when calibrating multiple containers of the same type (eg an entire deck of 96 well plates). There is no slot Z, the robot will just move 1 mm.
+
+AB Plungers
+^^^^^^^^^^^^^^^^^^^^
+
+Use the plunger jog to move the plunger up and down. If you have selected a container or the pipette for the B axis, then the B axis will move, and if you have selected a container or the pipette for the A axis, it will move.
+
+.. screenshot plunger jog
+
+The app automatically toggles between pipettes (unlike 1.2)
+
+Move to Slot
+^^^^^^^^^^^^^^^^^^^^
+
+Jump to any slot on the deck with the Move to Slot buttons. The deck will automatically react and change between a 3x5 layout and a 2x5 layout based on which robot you are connected to (Hood vs. Pro/Standard)
+
+.. image:: img/app/move-to-slot.png
+
+
+Calibrate
+--------------------
+
+Once each container or pipette is calibrated, a check mark will appear next to it in the container list.
+
+.. image:: img/app/container-list.png
+
+Tipracks
+^^^^^^^^^^^^^^^^^^^^
+
+Jog the pipette down into the first tip in the tip rack. It should be firmly pushed into the tip, and the pick up tip button can be used to test its seating.
+
+Calling the pick up tip button from anywhere on the deck will direct the robot back to the tiprack to pick up a tip. Drop tip will send the tip to the trash.
+
+.. image:: img/app/container-calibration.png
+
+Containers
+^^^^^^^^^^^^^^^^^^^^
+
+With a tip on the pipette, calibrate to the bottom of the first well or tube in the container. Use the diagrams in the app to guide calibration.
+
+Pipettes
+^^^^^^^^^^^^^^^^^^^^
+
+Four calibrations positions need to be set for each pipette: Top, Bottom, Blow Out and Drop Tip. Make sure your pipette is manually set to its highest volume (or ~5 uL higher) for accurate calibration.
+
+.. image:: img/app/pipette-calibration.png
+
+Once these positions are all saved, you can test your calibrations. This is most easily done gravimetrically using a small scale. Use the aspirate and dispense buttons to pick up liquid and eject it onto the scale. If this volume isn't exactly what you expect, maybe 203 uL instead of 200, no big deal! You can go input the value into the max volume box. The robot will adjust its calculations accordingly and will then be able to dispense the correct volumes during experiments.
+
+The drop tip screw may need to be adjusted up or down if you cannot accurately calibrate Bottom.
+
+Run Protocol
+--------------------
+
+Once all your positions are saved, you can run your protocol. A progress will keep track of what percentage of your protocol has been done. Protocols can be paused, or they can be stopped entirely. We recommend homing after all protocols have been completed or stopped.
+
+.. image:: img/app/running-protocol.png
diff --git a/api/docs/dist/ot1/_sources/containers.txt b/api/docs/dist/ot1/_sources/containers.txt
new file mode 100644
index 000000000000..3f7e52d3d5be
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/containers.txt
@@ -0,0 +1,722 @@
+.. _containers:
+
+######################
+Containers
+######################
+
+We spend a fair amount of time organizing and counting wells when writing Python protocols. This section describes the different ways we can access wells and groups of wells.
+
+************************************
+
+******************
+Labware Library
+******************
+
+The Opentrons API comes with many common labware containers built in. These containers can be loaded into you Python protocol using the ``containers.load()`` method, and the specific name of the labware you need.
+
+`Check out this webpage`__ to see a visualization of all the API's current built-in containers.
+
+__ https://andysigler.github.io/ot-api-containerviz/
+
+Below are a list of some of the most commonly used containers in the API, as well as images for how they look.
+
+If you are interested in using your own container that is not included in the API, please take a look at how to create custom containers using ``containers.create()``, or contact Opentrons Support.
+
+.. note::
+
+ All names are case-sensitive, copying and pasting from this list into the protocol editor will ensure no errors are made.
+
+**********************
+
+Point
+=====
+
+Use ``point`` when there is only one position per container, such as the trash or a scale.
+
+.. code-block:: python
+
+ container.load('point', slot)
+
+You can access the point position as ``container.wells('A1')`` or ``container.wells(0)``.
+
+**********************
+
+Tipracks
+==========
+
+tiprack-10ul
+-------------
+
+Tip rack for a 10 uL pipette (single or 8-channel)
+
+.. code-block:: python
+
+ container.load('tiprack-10ul', slot)
+
+**Accessing Tips:** *single channel* ``['A1']-['H12']``, *8-channel* ``['A1']-['A12']``
+
+.. image:: img/labware_lib/Tiprack-10ul.png
+
+tiprack-10ul-H
+--------------
+
+Tip rack for a single channel 10 uL pipette when the pipette is in the center position. Set initial position to H1, and the pipette will use all the tips on the right hand side (E-H, 1-12)
+
+.. code-block:: python
+
+ container.load('tiprack-10ul-H', slot)
+
+**Accessing Tips:** *single channel* ``['E-H, 1-12']``
+
+.. image:: img/labware_lib/Tiprack-10ul-H.png
+
+tiprack-200ul
+-------------
+
+Tip rack for a 200 or 300 uL pipette (single or 8-channel)
+
+.. code-block:: python
+
+ container.load('tiprack-200ul', slot)
+
+**Accessing Tips:** *single channel* ``['A1']-['H12']``, *8-channel* ``['A1']-['A12']``
+
+.. image:: img/labware_lib/Tiprack-200ul.png
+
+tiprack-1000ul
+--------------
+
+Tip rack for a 1000 uL pipette (single or 8-channel)
+
+.. code-block:: python
+
+ container.load('tiprack-1000ul', slot)
+
+**Accessing Tips:** *single channel* ``['A1']-['H12']``, *8-channel* ``['A1']-['A12']``
+
+.. image:: img/labware_lib/Tiprack-1000.png
+
+tiprack-1000ul-chem
+-------------------
+
+Tip rack for 1000ul chem (10x10)
+
+.. code-block:: python
+
+ container.load('tiprack-1000ul-chem', slot)
+
+**Accessing Tips:** *single channel* ``[0]-[99]``
+
+.. image:: img/labware_lib/Tiprack-1000ul-chem.png
+
+**********************
+
+Troughs
+========
+
+trough-12row
+-------------
+
+12 row reservoir
+
+.. code-block:: python
+
+ container.load('trough-12row', slot)
+
+**Accessing Rows:** *single channel* ``['A1']-['A12']``, *8-channel* ``['A1']-['A12']``
+
+.. image:: img/labware_lib/Trough-12row.png
+
+**********************
+
+Tube Racks
+==========
+
+tube-rack-.75ml
+-------------
+
+4x6 rack that holds .75 mL microcentrifuge tubes
+(A1, A1-D6)
+
+.. code-block:: python
+
+ container.load('tube-rack-.75ml', slot)
+
+**Accessing Tubes:** *single channel* ``['A1']-['D6']``
+
+.. image:: img/labware_lib/Tuberack-075ml.png
+
+tube-rack-2ml
+-------------
+
+4x6 rack that holds 1.5 mL microcentrifuge tubes and 2 mL microcentrifuge tubes
+
+.. code-block:: python
+
+ container.load('tube-rack-2ml', slot)
+
+**Accessing Tubes:** *single channel* ``['A1']-['D6']``
+
+.. image:: img/labware_lib/Tuberack-2ml.png
+
+tube-rack-15_50ml
+------------------
+
+rack that holds 6 15 mL tubes and 4 50 mL tubes
+
+.. code-block:: python
+
+ container.load('tube-rack-15_50ml', slot)
+
+**Accessing Tubes:** *single channel* ``['A1']-['A3'], ['B1']-['B3'], ['C1']-['C2'], ['D1']-['D2']``
+
+.. image:: img/labware_lib/Tuberack-15-50ml.png
+
+
+Plates
+=======
+
+96-deep-well
+-------------
+
+See dimensions in diagram below.
+
+.. code-block:: python
+
+ container.load('96-deep-well', slot)
+
+**Accessing Wells:** *single channel* ``['A1']-['H12']``, *8-channel* ``['A1']-['A12']``
+
+.. image:: img/labware_lib/96-Deep-Well.png
+
+96-PCR-tall
+-------------
+
+See dimensions in diagram below.
+
+.. code-block:: python
+
+ container.load('96-PCR-tall', slot)
+
+**Accessing Wells:** *single channel* ``['A1']-['H12']``, *8-channel* ``['A1']-['A12']``
+
+.. image:: img/labware_lib/96-PCR-Tall.png
+
+96-PCR-flat
+-------------
+
+See dimensions in diagram below.
+
+.. code-block:: python
+
+ container.load('96-PCR-flat', slot)
+
+**Accessing Wells:** *single channel* ``['A1']-['H12']``, *8-channel* ``['A1']-['A12']``
+
+.. image:: img/labware_lib/96-PCR-Flatt.png
+
+PCR-strip-tall
+----------------
+
+See dimensions in diagram below.
+
+.. code-block:: python
+
+ container.load('PCR-strip-tall', slot)
+
+**Accessing Wells:** *single channel* ``['A1']-['A8']``, *8-channel* ``['A1']``
+
+.. image:: img/labware_lib/96-PCR-Strip.png
+
+384-plate
+----------
+
+See dimensions in diagram below.
+
+.. code-block:: python
+
+ container.load('384-plate', slot)
+
+**Accessing Wells:** *single channel* ``['A1']-['P24']``, *multi-channel* ``['A1']-['A24]``
+
+.. image:: img/labware_lib/384-plate.png
+
+
+**********************
+
+.. testsetup:: containers
+
+ from opentrons import containers, robot
+ robot.reset()
+
+**************
+Containers
+**************
+
+The containers module allows you to load common labware into your protocol. `Go here`__ to see a visualization of all built-in containers.
+
+__ https://andysigler.github.io/ot-api-containerviz/
+
+.. testcode:: containers
+
+ '''
+ Examples in this section require the following
+ '''
+ from opentrons import containers
+
+List
+====
+
+Once the container module is loaded, you can see a list of all containers currently inside the API by calling ``containers.list()``
+
+.. testcode:: containers
+
+ containers.list()
+
+Load
+====
+
+Labware is loaded with two arguments: 1) the container type, and 2) the deck slot it will be placed in on the robot.
+
+.. testcode:: containers
+
+ p = containers.load('96-flat', 'B1')
+
+A third optional argument can be used to give a container a unique name.
+
+.. testcode:: containers
+
+ p = containers.load('96-flat', 'B1', 'any-name-you-want')
+
+Unique names are useful in a few scenarios. First, they allow the container to have independant calibration data from other containers in the same slot. In the example above, the container named 'any-name-you-want' will assume different calibration data from the unnamed plate, even though they are the same type and in the same slot.
+
+.. note::
+
+ Calibration data refers to the saved positions for each container on deck, and is a part of the `Opentrons App calibration procedure`__.
+
+__ https://opentrons.com/getting-started/calibrate-deck
+
+Names can also be used to place multiple containers in the same slot all at once. For example, the flasks below are all placed in slot D1. So in order for the Opentrons API to tell them apart, we have given them each a unique name.
+
+.. testcode:: containers
+
+ fa = containers.load('T25-flask', 'D1', 'flask_a')
+ fb = containers.load('T25-flask', 'D1', 'flask_b')
+ fc = containers.load('T25-flask', 'D1', 'flask_c')
+
+Create
+======
+
+In addition to the default containers that come with the Opentrons API, you can create your own custom containers.
+
+Through the API's call containers.create(), you can create simple grid containers, which consist of circular wells arranged in columns and rows.
+
+.. testcode:: containers
+
+ containers.create(
+ '3x6_plate', # name of you container
+ grid=(3, 6), # specify amount of (columns, rows)
+ spacing=(12, 12), # distances (mm) between each (column, row)
+ diameter=5, # diameter (mm) of each well on the plate
+ depth=10) # depth (mm) of each well on the plate
+
+When you create your custom container, then it will be saved for later use under the name you've given it. This means you can use containers.load() to use the custom container you've created in this and any future protocol.
+
+.. testcode:: containers
+
+ custom_plate = containers.load('3x6_plate', 'D1')
+
+ for well in custom_plate.wells():
+ print(well)
+
+will print out...
+
+.. testoutput:: containers
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.. testsetup:: pipettes
+
+ from opentrons import instruments, robot
+ robot.reset()
+
+**********************
+
+.. testsetup:: individualwells
+
+ from opentrons import containers, robot
+
+ robot.reset()
+ plate = containers.load('96-flat', 'A1')
+
+******************
+Accessing Wells
+******************
+
+**********************
+
+Individual Wells
+================
+
+When writing a protocol using the API, you will be spending most of your time selecting which wells to transfer liquids to and from.
+
+The OT-One deck and containers are all set up with the same coordinate system - numbered rows and lettered columns.
+
+.. image:: img/well_iteration/Well_Iteration.png
+
+.. testcode:: individualwells
+
+ '''
+ Examples in this section expect the following
+ '''
+ from opentrons import containers
+
+ plate = containers.load('96-flat', 'A1')
+
+Wells by Name
+-------------
+
+Once a container is loaded into your protocol, you can easily access the many wells within it using ``wells()`` method. ``wells()`` takes the name of the well as an argument, and will return the well at that location.
+
+.. testcode:: individualwells
+
+ plate.wells('A1')
+ plate.wells('H12')
+
+Wells by Index
+--------------
+
+Wells can be referenced by their "string" name, as demonstrated above. However, they can also be referenced with zero-indexing, with the first well in a container being at position 0.
+
+.. testcode:: individualwells
+
+ plate.wells(0) # well A1
+ plate.wells(95) # well H12
+ plate.wells(-1) # well H12 (Python let's you do this)
+
+Columns and Rows
+----------------
+
+A container's wells are organized within a series of columns and rows, which are also labelled on standard labware. In the API, columns are given letter names (``'A'`` through ``'H'`` for example) and go left to right, while rows are given numbered names (``'1'`` through ``'8'`` for example) and go from front to back.
+You can access a specific row or column by using the ``rows()`` and ``cols()`` methods on a container. These will return all wells within that row or column.
+
+.. testcode:: individualwells
+
+ column = plate.cols('A')
+ row = plate.rows('1')
+
+ print('Column "A" has', len(column), 'wells')
+ print('Row "1" has', len(row), 'wells')
+
+will print out...
+
+.. testoutput:: individualwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ Column "A" has 12 wells
+ Row "1" has 8 wells
+
+The ``rows()`` or ``cols()`` methods can be used in combination with the ``wells()`` method to access wells within that row or column. In the example below, both lines refer to well ``'A1'``.
+
+.. testcode:: individualwells
+
+ plate.cols('A').wells('1')
+ plate.rows('1').wells('A')
+
+**********************
+
+.. testsetup:: multiwells
+
+ from opentrons import containers, robot
+
+ robot.reset()
+ plate = containers.load('96-flat', 'A1')
+
+
+Multiple Wells
+==============
+
+If we had to reference each well one at a time, our protocols could get very very long.
+
+When describing a liquid transfer, we can point to groups of wells for the liquid's source and/or destination. Or, we can get a group of wells that we want to loop through.
+
+.. testcode:: multiwells
+
+ '''
+ Examples in this section expect the following
+ '''
+ from opentrons import containers
+
+ plate = containers.load('96-flat', 'B1')
+
+Wells
+-----
+
+The ``wells()`` method can return a single well, or it can return a list of wells when multiple arguments are passed.
+
+Here is an example or accessing a list of wells, each specified by name:
+
+.. testcode:: multiwells
+
+ w = plate.wells('A1', 'B2', 'C3', 'H12')
+
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ >
+
+Multiple wells can be treated just like a normal Python list, and can be iterated through:
+
+.. testcode:: multiwells
+
+ for w in plate.wells('A1', 'B2', 'C3', 'H12'):
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+Wells To
+--------
+
+Instead of having to list the name of every well, we can also create a range of wells with a start and end point. The first argument is the starting well, and the ``to=`` argument is the last well.
+
+.. testcode:: multiwells
+
+ for w in plate.wells('A1', to='H1'):
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+
+
+
+
+Not only can we get every well between the start and end positions, but we can also set the ``step=`` size. The example below will access every 2nd well between ``'A1'`` and ``'H'``:
+
+.. testcode:: multiwells
+
+ for w in plate.wells('A1', to='H1', step=2):
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+These lists of wells can also move in the reverse direction along your container. For example, setting the ``to=`` argument to a well that comes before the starting position is allowed:
+
+.. testcode:: multiwells
+
+ for w in plate.wells('H1', to='A1', step=2):
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+Wells Length
+------------
+
+Another way you can create a list of wells is by specifying the length= of the well list you need, in addition to the starting point. The example below will return eight wells, starting at well ``'A1'``:
+
+.. testcode:: multiwells
+
+ for w in plate.wells('A1', length=8):
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+
+
+
+
+And just like before, we can also set the ``step=`` argument. Except this time the example will be accessing every 3rd well, until a total of eight wells have been found:
+
+.. testcode:: multiwells
+
+ for w in plate.wells('A1', length=8, step=3):
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+
+
+
+
+You can set the step= value to a negative number to move in the reverse direction along the container:
+
+.. testcode:: multiwells
+
+ for w in plate.wells('H11', length=8, step=-1):
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+
+
+
+
+Columns and Rows
+----------------
+
+Columns and Rows
+The same arguments described above can be used with ``rows()`` and ``cols()`` to create lists of rows or columns.
+
+Here is an example of iterating through rows:
+
+.. testcode:: multiwells
+
+ for r in plate.rows('2', length=3, step=-2):
+ print(r)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ >
+ >
+ >
+
+And here is an example of iterating through columns:
+
+.. testcode:: multiwells
+
+ for c in plate.cols('B', to='F', step=2):
+ print(c)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ >
+ >
+ >
+
+
+Slices
+------
+
+Containers can also be treating similarly to Python lists, and can therefore handle slices.
+
+.. testcode:: multiwells
+
+ for w in plate[0:8:2]:
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+The API's containers are also prepared to take string values for the slice's ``start`` and ``stop`` positions.
+
+.. testcode:: multiwells
+
+ for w in plate['A1':'A2':2]:
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+.. testcode:: multiwells
+
+ for w in plate.cols['B']['1'::2]:
+ print(w)
+
+will print out...
+
+.. testoutput:: multiwells
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+
+
+
+
+
+
diff --git a/api/docs/dist/ot1/_sources/examples.txt b/api/docs/dist/ot1/_sources/examples.txt
new file mode 100644
index 000000000000..48346fd0d10f
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/examples.txt
@@ -0,0 +1,222 @@
+.. _examples:
+
+########
+Examples
+########
+
+.. testsetup:: examples
+
+ from opentrons import robot, containers, instruments
+
+ plate = containers.load('96-flat', 'B1')
+ trough = containers.load('trough-12row', 'C1')
+
+ tiprack_1 = containers.load('tiprack-200ul', 'A1')
+ tiprack_2 = containers.load('tiprack-200ul', 'A2')
+
+ p200 = instruments.Pipette(
+ axis="b",
+ max_volume=200,
+ tip_racks=[tiprack_2])
+
+All examples on this page assume the following containers and pipette:
+
+.. testcode:: examples
+
+ from opentrons import robot, containers, instruments
+
+ plate = containers.load('96-flat', 'B1')
+ trough = containers.load('trough-12row', 'C1')
+
+ tiprack_1 = containers.load('tiprack-200ul', 'A1')
+ tiprack_2 = containers.load('tiprack-200ul', 'A2')
+
+ p200 = instruments.Pipette(
+ axis="b",
+ max_volume=200,
+ tip_racks=[tiprack_2])
+
+******************************
+
+***************
+Basic Transfer
+***************
+
+Moving 100uL from one well to another:
+
+.. testcode:: examples
+
+ p200.transfer(100, plate.wells('A1'), plate.wells('B1'))
+
+If you prefer to not use the ``.transfer()`` command, the following pipette commands will create the some results:
+
+.. testcode:: examples
+
+ p200.pick_up_tip()
+ p200.aspirate(100, plate.wells('A1'))
+ p200.dispense(100, plate.wells('A1'))
+ p200.return_tip()
+
+******************************
+
+*****
+Loops
+*****
+
+Loops in Python allows your protocol to perform many actions, or act upon many wells, all within just a few lines. The below example loops through the numbers ``0`` to ``11``, and uses that loop's current value to transfer from all wells in a trough to each row of a plate:
+
+.. testcode:: examples
+
+ # distribute 20uL from trough:A1 -> plate:row:1
+ # distribute 20uL from trough:A2 -> plate:row:2
+ # etc...
+
+ # ranges() starts at 0 and stops at 12, creating a range of 0-11
+ for i in range(12):
+ p200.distribute(20, trough.wells(i), plate.rows(i))
+
+******************************
+
+*******************
+Multiple Air Gaps
+*******************
+
+The Opentrons liquid handler can do some things that a human cannot do with a pipette, like accurately alternate between aspirating and creating air gaps within the same tip. The below example will aspirate from five wells in the trough, while creating a air gap between each sample.
+
+.. testcode:: examples
+
+ p200.pick_up_tip()
+
+ for well in trough.wells():
+ p200.aspirate(5, well).air_gap(10)
+
+ p200.dispense(plate.wells('A1'))
+
+ p200.return_tip()
+
+******************************
+
+***************
+Dilution
+***************
+
+This example first spreads a dilutent to all wells of a plate. It then dilutes 8 samples from the trough across the 8 columns of the plate.
+
+.. testcode:: examples
+
+ p200.distribute(50, trough.wells('A12'), plate.wells()) # dilutent
+
+ # loop through each column
+ for i in range(8):
+
+ # save the source well and destination column to variables
+ source = trough.wells(i)
+ column = plate.cols(i)
+
+ # transfer 10uL of source to first well in column
+ p200.transfer(10, source, column.wells('1'))
+
+ # dilute the sample down the column
+ p200.transfer(
+ 10, column.wells('1', to='11'), column.wells('2', to='12'),
+ mix_after=(3, 25))
+
+******************************
+
+***************
+Plate Mapping
+***************
+
+Deposit various volumes of liquids into the same plate of wells, and automatically refill the tip volume when it runs out.
+
+.. testcode:: examples
+
+ # these uL values were created randomly for this example
+ water_volumes = [
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96
+ ]
+
+ p200.distribute(water_volumes, trough.wells('A12'), plate)
+
+The final volumes can also be read from a CSV, and opened by your protocol.
+
+.. code-block:: python
+
+ '''
+ This example uses a CSV file saved on the same computer, formatted as follows,
+ where the columns in the file represent the 8 columns of the plate,
+ and the rows in the file represent the 12 rows of the plate,
+ and the values represent the uL that must end up at that location
+
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+
+ '''
+
+ # open file with absolute path (will be different depending on operating system)
+ # file paths on Windows look more like 'C:\\path\\to\\your\\csv_file.csv'
+ with open('/path/to/your/csv_file.csv') as my_file:
+
+ # save all volumes from CSV file into a list
+ volumes = []
+
+ # loop through each line (the plate's columns)
+ for l in my_file.read().splitlines():
+ # loop through each comma-separated value (the plate's rows)
+ for v in l.split(','):
+ volumes.append(float(v)) # save the volume
+
+ # distribute those volumes to the plate
+ p200.distribute(volumes, trough.wells('A1'), plate.wells())
+
+
+
+******************************
+
+*******************
+Precision Pipetting
+*******************
+
+This example shows how to deposit liquid around the edge of a well.
+
+.. testcode:: examples
+
+ p200.pick_up_tip()
+
+ # rotate around the edge of the well, dropping 10ul at a time
+ theta = 0.0
+ while p200.current_volume > 0:
+ # we can move around a circle with radius (r) and theta (degrees)
+ well_edge = plate.wells('B1').from_center(r=1.0, theta=theta, h=0.9)
+
+ # combine a Well with a Vector in a tuple
+ destination = (plate.wells('B1'), well_edge)
+ p200.move_to(destination, strategy='direct') # move straight there
+ p200.dispense(10)
+
+ theta += 0.314
+
+ p200.drop_tip()
+
+******************************
diff --git a/api/docs/dist/ot1/_sources/firmware.txt b/api/docs/dist/ot1/_sources/firmware.txt
new file mode 100644
index 000000000000..c614009d0580
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/firmware.txt
@@ -0,0 +1,54 @@
+.. _firmware:
+
+================
+Firmware Updates
+================
+
+The motorcontroller inside all Opentrons liquid handlers (called Smoothieboard or just Smoothie) will need it's firmware updated if you are planning to use the Opentrons API and accompanying 2.0 app. The process is simple, and can be done from your computer in under a minute.
+
+To summarize, there are two files on your Smoothie that must be replaced; ``FIRMWARE.CUR`` and ``config``.
+
+Download Files
+----------------------
+
+Download the zipped files from here:
+
+https://github.com/OpenTrons/smoothie-config/archive/2.0.0.zip
+
+After downloading, unpack the zip file to view its contents. The latest firmware files are found in folder "v2.0.0".
+
+Open the Smoothie's MicroSD Card
+---------------------------------
+
+Power OFF and unplug your Opentrons liquid handler's USB cable. Remove the microSD card from Smoothieboard (just above the USB connector on the robot), and connect it to your personal computer or laptop. It will show up as a storage device on your computer.
+
+.. image:: img/update-firmware/firmware_files.png
+
+Open the microSD storage device to see it's ``FIRMWARE.CUR`` and ``config`` files. There might be other files there, but the two you need to worry about are ``FIRMWARE.CUR`` and ``config``, because these are what we will be replacing.
+
+Select Your Model's Config
+----------------------------------
+
+Opentrons `come in three models`__, the Standard, Pro, and Hood. Each model requires a unique ``config`` and ``firmware.bin`` file to go along with it. Find the files that matches your robot (the folders are named after each model).
+
+__ https://opentrons.com/robots
+
+** Note: We have release a "Plus" version of our robots, which have faster motors. If you received a robot after April 2017, and if your robot's Z motor is all black (no silver on the outside) than you have a "Plus" model.
+
+.. image:: img/update-firmware/SelectConfigFile.png
+
+Copy Over Files
+---------------------------------
+
+Drag both the ``config`` file and ``firmware.bin`` from the correct folder onto the microSD card. You will be overwriting the old ``config`` file, so your computer may ask if you would like to proceed with replacing it.
+
+.. image:: img/update-firmware/replaceConfig.png
+
+The contents of the microSD card should now look like this:
+
+.. image:: img/update-firmware/dragFirmwareBin.png
+
+Restart
+---------------
+
+Unmount the Smoothie's microSD card from your computer, and connect it back to your powered OFF robot. When the robot powers on, it will read the ``firmware.bin`` file, then save it as ``FIRMWARE.CUR``. It will then read the new ``config`` file, and your liquid handler now has updated firmware.
diff --git a/api/docs/dist/ot1/_sources/index.txt b/api/docs/dist/ot1/_sources/index.txt
new file mode 100644
index 000000000000..ca2374983991
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/index.txt
@@ -0,0 +1,148 @@
+.. Opentrons API documentation master file, created by
+ sphinx-quickstart on Thu Oct 27 12:10:26 2016.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+===============
+Opentrons API
+===============
+
+The Opentrons API is a simple framework designed to make writing automated biology lab protocols easy.
+
+We’ve designed it in a way we hope is accessible to anyone with basic computer and wetlab skills. As a bench scientist, you should be able to code your automated protocols in a way that reads like a lab notebook.
+
+`View source code on GitHub`__
+
+__ https://github.com/opentrons/opentrons-api
+
+**********************
+
+.. testsetup:: helloworld
+
+ from opentrons import containers, instruments, robot
+
+ robot.reset()
+
+ tiprack = containers.load('tiprack-200ul', 'A1')
+ plate = containers.load('96-flat', 'B1')
+
+ pipette = instruments.Pipette(axis='b', max_volume=200)
+
+How it Looks
+---------------
+
+The design goal of the Opentrons API is to make code readable and easy to understand. For example, below is a short set of instruction to transfer from well ``'A1'`` to well ``'B1'`` that even a computer could understand:
+
+.. code-block:: none
+
+ Use the Opentrons API's containers and instruments
+
+ Add a 96 well plate, and place it in slot 'B1'
+ Add a 200uL tip rack, and place it in slot 'A1'
+
+ Add a 200uL pipette to axis 'b', and tell it to use that tip rack
+
+ Transfer 100uL from the plate's 'A1' well to its 'A2' well
+
+If we were to rewrite this with the Opentrons API, it would look like the following:
+
+.. testcode:: helloworld
+
+ # imports
+ from opentrons import containers, instruments
+
+ # containers
+ plate = containers.load('96-flat', 'B1')
+ tiprack = containers.load('tiprack-200ul', 'A1')
+
+ # pipettes
+ pipette = instruments.Pipette(axis='b', max_volume=200, tip_racks=[tiprack])
+
+ # commands
+ pipette.transfer(100, plate.wells('A1'), plate.wells('A2'))
+
+**********************
+
+How it's Organized
+------------------
+
+When writing protocols using the Opentrons API, there are generally three sections:
+
+1) Imports
+2) Containers
+3) Pipettes
+4) Commands
+
+Imports
+^^^^^^^
+
+When writing in Python, you must always include the Opentrons API within your file. We most commonly use the ``containers`` and ``instruments`` sections of the API.
+
+From the example above, the "imports" section looked like:
+
+.. code-block:: python
+
+ from opentrons import containers, instruments
+
+
+Containers
+^^^^^^^^^^
+
+While the imports section is usually the same across protocols, the containers section is different depending on the tip racks, well plates, troughs, or tubes you're using on the robot.
+
+Each container is given a type (ex: ``'96-flat'``), and the slot on the robot it will be placed (ex: ``'B1'``).
+
+From the example above, the "containers" section looked like:
+
+.. code-block:: python
+
+ plate = containers.load('96-flat', 'B1')
+ tiprack = containers.load('tiprack-200ul', 'A1')
+
+Pipettes
+^^^^^^^^
+
+Next, pipettes are created and attached to a specific axis on the OT-One (``'a'`` or ``'b'``). Axis ``'a'`` is on the center of the head, while axis ``'b'`` is on the left.
+
+There are other parameters for pipettes, but the most important are the ``max_volume`` to set it's size, and the tip rack(s) it will use during the protocol.
+
+From the example above, the "pipettes" section looked like:
+
+.. code-block:: python
+
+ pipette = instruments.Pipette(axis='b', max_volume=200, tip_racks=[tiprack])
+
+Commands
+^^^^^^^^
+
+And finally, the most fun section, the actual protocol commands! The most common commands are ``transfer()``, ``aspirate()``, ``dispense()``, ``pick_up_tip()``, ``drop_tip()``, and much more.
+
+This section can tend to get long, relative to the complexity of your protocol. However, with a better understanding of Python you can learn to compress and simplify even the most complex-seeming protocols.
+
+From the example above, the "commands" section looked like:
+
+.. code-block:: python
+
+ pipette.transfer(100, plate.wells('A1'), plate.wells('B1'))
+
+
+Table of Contents
+-----------------
+
+.. toctree::
+ :maxdepth: 3
+
+ writing
+ containers
+ pipettes
+ transfer
+ robot
+ modules
+ examples
+ api
+ calibration
+ firmware
+
+.. |br| raw:: html
+
+
diff --git a/api/docs/dist/ot1/_sources/modules.txt b/api/docs/dist/ot1/_sources/modules.txt
new file mode 100644
index 000000000000..d7141c156291
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/modules.txt
@@ -0,0 +1,94 @@
+.. _modules:
+
+################
+Hardware Modules
+################
+
+**********************
+
+**********
+Heat Deck
+**********
+
+The heat deck runs off the opensource platform Arduino, which is how you can control it's temperature. Our heat decks come automatically set to reach a temperature of 55 deg Celsius, but you can edit this value by editing the Arduino file.
+
+Find our Heat Deck source code `on GitHub here`__, and download.
+
+__ https://github.com/OpenTrons/opentrons-modules
+
+Also download and install the `Arduino IDE`__.
+
+__ https://www.arduino.cc/en/main/software
+
+Open the file, and you will see detailed instruction for how to update the temperature. The overiew is that you simply set the number for what temperature you want, then upload that code to the Heat Deck.
+
+**********************
+
+**********
+Magbead
+**********
+
+Setting up Hardware
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use your included DIY Mag Bead kit to configure the motor control board (see kit instructions).
+
+
+Initializing Module in API
+============================
+
+Just like a pipette, you need to set up and name your module.
+
+**instruments.Magbead** (*mofset, name*)
+
+ * **mosfet -** integer 0-5 (defaults to 0)
+ * **name -** the name you want to call your module
+
+.. testsetup:: main
+
+ from opentrons import instruments
+ from opentrons.instruments import Pipette
+ p200 = instruments.Pipette(axis="b", max_volume=200)
+
+.. testcode:: main
+
+ mag_deck = instruments.Magbead(name='mag_deck')
+
+Activate and Deactivate Magnets
+================================
+
+To activate the magnets and raise the module's platform, run ``.engage()``:
+
+**module.engage** ()
+
+.. testcode:: main
+
+ mag_deck.engage()
+
+To deactivate the magnets and lower the module's platform, run ``.disengage()``:
+
+**module.disengage** ()
+
+.. testcode:: main
+
+ mag_deck.disengage()
+
+Chain Other Commands
+============================
+
+Just like ``aspirate()`` and ``dispense()`` can be chained, you can chain ``engage()`` and ``disengage()``, as well as the ``delay()`` if you don't want to do anything between engaging and disengaging the magnets.
+
+.. testcode:: main
+
+ mag_deck.engage()
+ mag_deck.delay(60)
+ mag_deck.disengage()
+
+ mag_deck.engage().delay(60).disengage()
+
+You can call ``delay()`` with a ``Pipette`` or a ``Magbead`` module.
+
+.. testcode:: main
+
+ p200.delay(10)
+ mag_deck.delay(10)
diff --git a/api/docs/dist/ot1/_sources/pipettes.txt b/api/docs/dist/ot1/_sources/pipettes.txt
new file mode 100644
index 000000000000..35f23561aba5
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/pipettes.txt
@@ -0,0 +1,483 @@
+.. _pipettes:
+
+########################
+Liquid Handling
+########################
+
+The ``instruments`` module gives your protocol access to the ``Pipette``, which is what you will be primarily using to create protocol commands.
+
+************************
+
+******************
+Creating a Pipette
+******************
+
+.. testcode:: pipettes
+
+ '''
+ Examples in this section require the following
+ '''
+ from opentrons import instruments
+
+Axis and Max Volume
+===================
+
+To create a ``Pipette``, you must give it an axis and a max_volume. The axis can be either ``'a'`` or ``'b'``, and the volume is whatever your hand pipette is calibrated for. In this example, we are using a 200uL pipette.
+
+.. testcode:: pipettes
+
+ pipette = instruments.Pipette(
+ axis='b',
+ name='my-p200',
+ max_volume=200)
+
+Minimum Volume
+==============
+
+The minimum allowed volume can be set for each pipette. If your protocol attempts to aspirate or dispense a volume below this volume, the API will give you a warning.
+
+.. testcode:: pipettes
+
+ pipette = instruments.Pipette(
+ axis='b',
+ name='my-p200',
+ max_volume=200,
+ min_volume=20)
+
+Channels
+========
+
+Pipettes can also be assigned a number of channels, either ``channel=1`` or ``channel=8``. If you do not specify, it will default to ``channel=1`` channel.
+
+.. testcode:: pipettes
+
+ pipette = instruments.Pipette(
+ axis='b',
+ name='my-p200-multichannel',
+ max_volume=200,
+ min_volume=20,
+ channels=8)
+
+Plunger Speeds
+==============
+
+The speeds at which the pipette will aspirate and dispense can be set through ``aspirate_speed`` and ``dispense_speed``. The values are in millimeters/minute, and default to ``aspirate_speed=300`` and ``dispense_speed=500``.
+
+.. testcode:: pipettes
+
+ pipeipette = instruments.Pipette(
+ axis='b',
+ name='my-p200-multichannel',
+ max_volume=200,
+ min_volume=20,
+ channels=8,
+ aspirate_speed=200,
+ dispense_speed=600)
+
+.. testsetup:: robot
+
+ from opentrons import robot, containers, instruments
+
+ robot.reset()
+
+ plate = containers.load('96-flat', 'B1', 'my-plate')
+ tiprack = containers.load('tiprack-200ul', 'A1', 'my-rack')
+
+ pipette = instruments.Pipette(axis='b', max_volume=200, name='my-pipette')
+
+
+**********************
+
+**************
+Tip Handling
+**************
+
+When we handle liquids with a pipette, we are constantly exchanging old, used tips for new ones to prevent cross-contamination between our wells. To help with this constant need, we describe in this section a few methods for getting new tips, and removing tips from a pipette.
+
+**********************
+
+.. testsetup:: tips
+
+ from opentrons import containers, instruments, robot
+
+ robot.reset()
+
+ trash = containers.load('point', 'D2')
+ tiprack = containers.load('tiprack-200ul', 'B1')
+
+ pipette = instruments.Pipette(axis='a')
+
+This section demonstrates the options available for controlling tips
+
+.. testcode:: tips
+
+ '''
+ Examples in this section expect the following
+ '''
+ from opentrons import containers, instruments
+
+ trash = containers.load('point', 'D2')
+ tiprack = containers.load('tiprack-200ul', 'B1')
+
+ pipette = instruments.Pipette(axis='a')
+
+Pick Up Tip
+===========
+
+Before any liquid handling can be done, your pipette must have a tip on it. The command ``pick_up_tip()`` will move the pipette over to the specified tip, the press down into it to create a vacuum seal. The below example picks up the tip at location ``'A1'``.
+
+.. testcode:: tips
+
+ pipette.pick_up_tip(tiprack.wells('A1'))
+
+Drop Tip
+===========
+
+Once finished with a tip, the pipette will autonomously remove the tip when we call ``drop_tip()``. We can specify where to drop the tip by passing in a location. The below example drops the tip back at its originating location on the tip rack.
+
+.. testcode:: tips
+
+ pipette.drop_tip(tiprack.wells('A1'))
+
+Instead of returning a tip to the tip rack, we can also drop it in a trash container.
+
+.. testcode:: tips
+
+ pipette.pick_up_tip(tiprack.wells('A2'))
+ pipette.drop_tip(trash)
+
+Return Tip
+===========
+
+When we need to return the tip to its originating location on the tip rack, we can simply call ``return_tip()``. The example below will automatically return the tip to ``'A3'`` on the tip rack.
+
+.. testcode:: tips
+
+ pipette.pick_up_tip(tiprack.wells('A3'))
+ pipette.return_tip()
+
+**********************
+
+.. testsetup:: tipsiterating
+
+ from opentrons import containers, instruments, robot
+
+ robot.reset()
+
+ trash = containers.load('point', 'D2')
+ tip_rack_1 = containers.load('tiprack-200ul', 'B1')
+ tip_rack_2 = containers.load('tiprack-200ul', 'B2')
+
+ pipette = instruments.Pipette(
+ axis='b',
+ tip_racks=[tip_rack_1, tip_rack_2],
+ trash_container=trash
+ )
+
+Tips Iterating
+==============
+
+Automatically iterate through tips and drop tip in trash by attaching containers to a pipette
+
+.. testcode:: tipsiterating
+
+ '''
+ Examples in this section expect the following
+ '''
+ from opentrons import containers, instruments
+
+ trash = containers.load('point', 'D2')
+ tip_rack_1 = containers.load('tiprack-200ul', 'B1')
+ tip_rack_2 = containers.load('tiprack-200ul', 'B2')
+
+Attach Tip Rack to Pipette
+--------------------------
+
+Tip racks and trash containers can be "attached" to a pipette when the pipette is created. This give the pipette the ability to automatically iterate through tips, and to automatically send the tip to the trash container.
+
+Trash containers can be attached with the option ``trash_container=TRASH_CONTAINER``.
+
+Multiple tip racks are can be attached with the option ``tip_racks=[RACK_1, RACK_2, etc... ]``.
+
+.. testcode:: tipsiterating
+
+ pipette = instruments.Pipette(
+ axis='b',
+ tip_racks=[tip_rack_1, tip_rack_2],
+ trash_container=trash
+ )
+
+.. note::
+
+ The ``tip_racks=`` option expects us to give it a Python list, containing each tip rack we want to attach. If we are only attaching one tip rack, then the list will have a length of one, like the following:
+
+ ``tip_racks=[tiprack]``
+
+
+Iterating Through Tips
+----------------------
+
+Now that we have two tip racks attached to the pipette, we can automatically step through each tip whenever we call ``pick_up_tip()``. We then have the option to either ``return_tip()`` to the tip rack, or we can ``drop_tip()`` to remove the tip in the attached trash container.
+
+.. testcode:: tipsiterating
+
+ pipette.pick_up_tip() # picks up tip_rack_1:A1
+ pipette.return_tip()
+ pipette.pick_up_tip() # picks up tip_rack_1:A2
+ pipette.drop_tip() # automatically drops in trash
+
+ # use loop to pick up tips tip_rack_1:A3 through tip_rack_2:H12
+ for i in range(94 + 96):
+ pipette.pick_up_tip()
+ pipette.return_tip()
+
+If we try to ``pick_up_tip()`` again when all the tips have been used, the Opentrons API will show you an error.
+
+.. note::
+
+ If you run the cell above, and then uncomment and run the cell below, you will get an error because the pipette is out of tips.
+
+.. testcode:: tipsiterating
+
+ # this will raise an exception if run after the previous code block
+ # pipette.pick_up_tip()
+
+
+Select Starting Tip
+-------------------
+
+Calls to ``pick_up_tip()`` will by default start at the attached tip rack's ``'A1'`` location. If you however want to start automatic tip iterating at a different tip, you can use ``start_at_tip()``.
+
+.. testcode:: tipsiterating
+
+ pipette.reset()
+
+ pipette.start_at_tip(tip_rack_1['C3'])
+ pipette.pick_up_tip() # pick up C3 from "tip_rack_1"
+ pipette.return_tip()
+
+Get Current Tip
+---------------
+
+Get the source location of the pipette's current tip by calling ``current_tip()``. If the tip was from the ``'A1'`` position on our tip rack, ``current_tip()`` will return that position.
+
+.. testcode:: tipsiterating
+
+ print(pipette.current_tip()) # is holding no tip
+
+ pipette.pick_up_tip()
+ print(pipette.current_tip()) # is holding the next available tip
+
+ pipette.return_tip()
+ print(pipette.current_tip()) # is holding no tip
+
+will print out...
+
+.. testoutput:: tipsiterating
+
+ None
+
+ None
+
+**********************
+
+****************
+Liquid Control
+****************
+
+This is the fun section, where we get to move things around and pipette! This section describes the ``Pipette`` object's many liquid-handling commands, as well as how to move the ``robot``.
+
+**********************
+
+.. testsetup:: liquid
+
+ from opentrons import containers, instruments, robot
+
+ robot.reset()
+
+ plate = containers.load('96-flat', 'B1')
+ pipette = instruments.Pipette(axis='b', max_volume=200)
+
+.. testcode:: liquid
+
+ '''
+ Examples in this section expect the following
+ '''
+ from opentrons import containers, instruments
+
+ plate = containers.load('96-flat', 'B1')
+ pipette = instruments.Pipette(axis='b', max_volume=200)
+
+
+Aspirate
+========
+
+To aspirate is to pull liquid up into the pipette's tip. When calling aspirate on a pipette, we can specify how many micoliters, and at which location, to draw liquid from:
+
+.. testcode:: liquid
+
+ pipette.aspirate(50, plate.wells('A1')) # aspirate 50uL from plate:A1
+
+Now our pipette's tip is holding 50uL.
+
+We can also simply specify how many microliters to aspirate, and not mention a location. The pipette in this circumstance will aspirate from it's current location (which we previously set as ``plate.wells('A1'))``.
+
+.. testcode:: liquid
+
+ pipette.aspirate(50) # aspirate 50uL from current position
+
+Now our pipette's tip is holding 100uL.
+
+We can also specify only the location to aspirate from. If we do not tell the pipette how many micoliters to aspirate, it will by default fill up the remaining volume in it's tip. In this example, since we already have 100uL in the tip, the pipette will aspirate another 100uL
+
+.. testcode:: liquid
+
+ pipette.aspirate(plate.wells('A2')) # aspirate until pipette fills from plate:A2
+
+
+Dispense
+========
+
+To dispense is to push out liquid from the pipette's tip. It's usage in the Opentrons API is nearly identical to ``aspirate()``, in that you can specify microliters and location, only microliters, or only a location:
+
+.. testcode:: liquid
+
+ pipette.dispense(50, plate.wells('B1')) # dispense 50uL to plate:B1
+ pipette.dispense(50) # dispense 50uL to current position
+ pipette.dispense(plate.wells('B2')) # dispense until pipette empties to plate:B2
+
+That final dispense without specifying a micoliter amount will dispense all remaining liquids in the tip to ``plate.wells('B2')``, and now our pipette is empty.
+
+Blow Out
+========
+
+To blow out is to push an extra amount of air through the pipette's tip, so as to make sure that any remaining droplets are expelled.
+
+When calling ``blow_out()`` on a pipette, we have the option to specify a location to blow out the remaining liquid. If no location is specified, the pipette will blow out from it's current position.
+
+.. testcode:: liquid
+
+ pipette.blow_out() # blow out over current location
+ pipette.blow_out(plate.wells('B3')) # blow out over current plate:B3
+
+
+Touch Tip
+=========
+
+To touch tip is to move the pipette's currently attached tip to the edges of a well, for the purpose of knocking off any droplets that might be hanging from the tip.
+
+When calling ``touch_tip()`` on a pipette, we have the option to specify a location where the tip will touch the inner walls. If no location is specified, the pipette will touch tip inside it's current location.
+
+.. testcode:: liquid
+
+ pipette.touch_tip() # touch tip within current location
+ pipette.touch_tip(-2) # touch tip 2mm below the top of the current location
+ pipette.touch_tip(plate.wells('B1')) # touch tip within plate:B1
+
+
+Mix
+===
+
+Mixing is simply performing a series of ``aspirate()`` and ``dispense()`` commands in a row on a single location. However, instead of having to write those commands out every time, the Opentrons API allows you to simply say ``mix()``.
+
+The mix command takes three arguments: ``mix(repetitions, volume, location)``
+
+.. testcode:: liquid
+
+ pipette.mix(4, 100, plate.wells('A2')) # mix 4 times, 100uL, in plate:A2
+ pipette.mix(3, 50) # mix 3 times, 50uL, in current location
+ pipette.mix(2) # mix 2 times, pipette's max volume, in current location
+
+
+Air Gap
+=======
+
+Some liquids need an extra amount of air in the pipette's tip to prevent it from sliding out. A call to ``air_gap()`` with a microliter amount will aspirate that much air into the tip.
+
+.. testcode:: liquid
+
+ pipette.aspirate(100, plate.wells('B4'))
+ pipette.air_gap(20)
+
+**********************
+
+.. testsetup:: moving
+
+ from opentrons import robot, containers, instruments
+
+ robot.reset()
+
+ tiprack = containers.load('tiprack-200ul', 'A1')
+ plate = containers.load('96-flat', 'B1')
+
+ pipette = instruments.Pipette(axis='b')
+
+******
+Moving
+******
+
+Demonstrates the different ways to control the movement of the Opentrons liquid handler during a protocol run.
+
+.. testcode:: moving
+
+ '''
+ Examples in this section expect the following
+ '''
+ from opentrons import containers, instruments, robot
+
+ tiprack = containers.load('tiprack-200ul', 'A1')
+ plate = containers.load('96-flat', 'B1')
+
+ pipette = instruments.Pipette(axis='b')
+
+Move To
+=======
+
+Pipette's are able to ``move_to()`` any location on the deck.
+
+For example, we can move to the first tip in our tip rack:
+
+.. testcode:: moving
+
+ pipette.move_to(tiprack.wells('A1'))
+
+You can also specify at what height you would like the robot to move to inside of a location using ``top()`` and ``bottom()`` methods on that location.
+
+.. testcode:: moving
+
+ pipette.move_to(plate.wells('A1').bottom()) # move to the bottom of well A1
+ pipette.move_to(plate.wells('A1').top()) # move to the top of well A1
+ pipette.move_to(plate.wells('A1').bottom(2)) # move to 2mm above the bottom of well A1
+ pipette.move_to(plate.wells('A1').top(-2)) # move to 2mm below the top of well A1
+
+The above commands will cause the robot's head to first move upwards, then over to above the target location, then finally downwards until the target location is reached. If instead you would like the robot to mive in a straight line to the target location, you can set the movement strategy to ``'direct'``.
+
+.. testcode:: moving
+
+ pipette.move_to(plate.wells('A1'), strategy='direct')
+
+.. note::
+
+ Moving with ``strategy='direct'`` will run the risk of colliding with things on your deck. Be very careful when using the option.
+
+Usually the ``strategy='direct'`` option is useful when moving inside of a well. Take a look at the below sequence of movements, which first move the head to a well, and use 'direct' movements inside that well, then finally move on to a different well.
+
+.. testcode:: moving
+
+ pipette.move_to(plate.wells('A1'))
+ pipette.move_to(plate.wells('A1').bottom(1), strategy='direct')
+ pipette.move_to(plate.wells('A1').top(-2), strategy='direct')
+ pipette.move_to(plate.wells('A1'))
+
+Delay
+=====
+
+To have your protocol pause for any given number of minutes or seconds, simply call ``delay()`` on your pipette. The value passed into ``delay()`` is the number of minutes or seconds the robot will wait until moving on to the next commands.
+
+.. testcode:: moving
+
+ pipette.delay(seconds=2) # pause for 2 seconds
+ pipette.delay(minutes=5) # pause for 5 minutes
+ pipette.delay(minutes=5, seconds=2) # pause for 5 minutes and 2 seconds
+
+
diff --git a/api/docs/dist/ot1/_sources/robot.txt b/api/docs/dist/ot1/_sources/robot.txt
new file mode 100644
index 000000000000..53c9e4806100
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/robot.txt
@@ -0,0 +1,193 @@
+.. _robot:
+
+.. testsetup:: robot
+
+ from opentrons import containers, instruments, robot
+ from opentrons.instruments import pipette as _pipette
+
+ robot.reset()
+
+ plate = robot.add_container('96-flat', 'B1', 'my-plate')
+
+ tiprack = robot.add_container('tiprack-200ul', 'A1', 'my-rack')
+
+ pipette = _pipette.Pipette(robot, axis='b', max_volume=200, name='my-pipette')
+
+###################
+Advanced Control
+###################
+
+.. note::
+
+ The below features are designed for advanced users who wish to use the Opentrons API in their own Python environment (ie Jupyter). This page is not relevant for users only using the Opentrons App, because the features described below will not be accessible.
+
+The robot module can be thought of as the parent for all aspects of the Opentrons API. All containers, instruments, and protocol commands are added to and controlled by robot.
+
+.. testcode:: robot
+
+ '''
+ Examples in this section require the following
+ '''
+ from opentrons import robot, containers, instruments
+
+ plate = containers.load('96-flat', 'B1', 'my-plate')
+ tiprack = containers.load('tiprack-200ul', 'A1', 'my-rack')
+
+ pipette = instruments.Pipette(axis='b', max_volume=200, name='my-pipette')
+
+Head Speed
+==========
+
+The maximum speed of the robot's head can be set using ``robot.head_speed()``. The value we set the speed to is in millimeters-per-second (mm/sec).
+
+.. testcode:: robot
+
+ robot.head_speed(5000)
+
+.. note::
+
+ Setting the head speed to above ``6000 mm/sec`` may cause your robot to "skip", which means the motors will lose their grip and make a loud vibrating noise. We recommend you try out different speed values on your robot, and see what works and what doesn't.
+
+Homing
+======
+
+You can `home` the robot by calling ``home()``. You can also specify axes. The robot will home immdediately when this call is made.
+
+.. testcode:: robot
+
+ robot.home() # home the robot on all axis
+ robot.home('z') # home the Z axis only
+
+Commands
+========
+
+When commands are called on a pipette, they are recorded on the ``robot`` in the order they are called. You can see all past executed commands by calling ``robot.commands()``, which returns a `Python list`__.
+
+__ https://docs.python.org/3.5/tutorial/datastructures.html#more-on-lists
+
+.. testcode:: robot
+
+ pipette.pick_up_tip(tiprack.wells('A1'))
+ pipette.drop_tip(tiprack.wells('A1'))
+
+ for c in robot.commands():
+ print(c)
+
+will print out...
+
+.. testoutput:: robot
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ Picking up tip from
+ Drop_tip at
+
+Clear Commands
+==============
+
+We can erase the robot command history by calling ``robot.clear_commands()``. Any previously created instruments and containers will still be inside robot, but the commands history is erased.
+
+.. testcode:: robot
+
+ robot.clear_commands()
+ pipette.pick_up_tip(tiprack['A1'])
+ print('There is', len(robot.commands()), 'command')
+
+ robot.clear_commands()
+ print('There are now', len(robot.commands()), 'commands')
+
+will print out...
+
+.. testoutput:: robot
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ There is 1 command
+ There are now 0 commands
+
+Comment
+=======
+
+You can add a custom message to the list of command descriptions you see when running ``robot.commands()``. This command is ``robot.comment()``, and it allows you to print out any information you want at the point in your protocol
+
+.. testcode:: robot
+
+ robot.clear_commands()
+
+ pipette.pick_up_tip(tiprack['A1'])
+ robot.comment("Hello, just picked up tip A1")
+
+ pipette.pick_up_tip(tiprack['A1'])
+ robot.comment("Goodbye, just dropped tip A1")
+
+ for c in robot.commands():
+ print(c)
+
+will print out...
+
+.. testoutput:: robot
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ Picking up tip from
+ Hello, just picked up tip A1
+ Picking up tip from
+ Goodbye, just dropped tip A1
+
+Get Containers
+==============
+
+When containers are loaded, they are automatically added to the ``robot``. You can see all currently held containers by calling ``robot.get_containers()``, which returns a `Python list`__.
+
+__ https://docs.python.org/3.5/tutorial/datastructures.html#more-on-lists
+
+.. testcode:: robot
+
+ for name, container in robot.get_containers():
+ print(name, container.get_type())
+
+will print out...
+
+.. testoutput:: robot
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ my-plate 96-flat
+ my-rack tiprack-200ul
+
+Get Instruments
+===============
+
+When instruments are created, they are automatically added to the ``robot``. You can see all currently held instruments by calling ``robot.get_instruments()``, which returns a `Python list`__.
+
+__ https://docs.python.org/3.5/tutorial/datastructures.html#more-on-lists
+
+.. testcode:: robot
+
+ for axis, pipette in robot.get_instruments():
+ print(pipette.name, axis)
+
+will print out...
+
+.. testoutput:: robot
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ my-pipette B
+
+Reset
+=====
+
+Calling ``robot.reset()`` will remove everything from the robot. Any previously added containers, pipettes, or commands will be erased.
+
+.. testcode:: robot
+
+ robot.reset()
+ print(robot.get_containers())
+ print(robot.get_instruments())
+ print(robot.commands())
+
+will print out...
+
+.. testoutput:: robot
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ []
+ []
+ []
+
diff --git a/api/docs/dist/ot1/_sources/transfer.txt b/api/docs/dist/ot1/_sources/transfer.txt
new file mode 100644
index 000000000000..27522ff4eb25
--- /dev/null
+++ b/api/docs/dist/ot1/_sources/transfer.txt
@@ -0,0 +1,1137 @@
+.. _transfer:
+
+.. testsetup:: transfer
+
+ from opentrons import robot, Robot, containers, instruments
+ from opentrons.instruments import pipette as _pipette
+
+ robot.reset()
+ robot.clear_commands()
+
+ robot = Robot()
+
+ plate = robot.add_container('96-flat', 'B1')
+
+ tiprack = robot.add_container('tiprack-200ul', 'A1')
+ trash = robot.add_container('point', 'D2')
+
+ pipette = _pipette.Pipette(
+ robot,
+ axis='b',
+ max_volume=200,
+ tip_racks=[tiprack],
+ trash_container=trash)
+
+#######################
+Transfer Shortcuts
+#######################
+
+The Transfer command is a nice way to wrap up the most common liquid-handling actions we take. Instead of having to write ``loop`` and ``if`` statements, we can simply use the ``transfer()`` command, making Python protocol both easier to write and read!
+
+**********************
+
+Transfer
+========
+
+Most of time, a protocol is really just looping over some wells, aspirating, and then dispensing. Even though they are simple in nature, these loops take up a lot of space. The ``pipette.transfer()`` command takes care of those common loops. It will combine aspirates and dispenses automatically, making your protocol easier to read and edit.
+
+.. testcode:: transfer
+
+ '''
+ Examples in this section expect the following
+ '''
+ from opentrons import containers, instruments
+
+ plate = containers.load('96-flat', 'B1')
+
+ tiprack = containers.load('tiprack-200ul', 'A1')
+ trash = containers.load('point', 'D2')
+
+ pipette = instruments.Pipette(
+ axis='b',
+ max_volume=200,
+ tip_racks=[tiprack],
+ trash_container=trash)
+
+Basic
+-----
+
+The example below will transfer 100 uL from well ``'A1'`` to well ``'B1'``, automatically picking up a new tip and then dropping it when finished.
+
+.. testsetup:: transfer
+
+ from opentrons import robot, containers, instruments
+
+ robot.reset()
+ robot.clear_commands()
+
+ plate = containers.load('96-flat', 'B1')
+
+ tiprack = containers.load('tiprack-200ul', 'A1')
+ trash = containers.load('point', 'D2')
+
+ pipette = instruments.Pipette(
+ axis='b',
+ max_volume=200,
+ tip_racks=[tiprack],
+ trash_container=trash)
+
+.. testcode:: transfer
+
+ pipette.transfer(100, plate.wells('A1'), plate.wells('B1'))
+
+Transfer commands will automatically create entire series of ``aspirate()``, ``dispense()``, and other ``Pipette`` commands. We can print out all commands to see what it did in the previous example:
+
+.. testcode:: transfer
+
+ for c in robot.commands():
+ print(c)
+
+will print out...
+
+.. testoutput:: transfer
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ Picking up tip from
+ Aspirating 100.0 at
+ Dispensing 100.0 at
+ Drop_tip at
+
+Large Volumes
+-------------
+
+Volumes larger than the pipette's ``max_volume`` will automatically divide into smaller transfers.
+
+.. testsetup:: transfer_1
+
+ from opentrons import robot, containers, instruments
+
+ robot.reset()
+ robot.clear_commands()
+
+ plate = containers.load('96-flat', 'B1')
+
+ tiprack = containers.load('tiprack-200ul', 'A1')
+ trash = containers.load('point', 'D2')
+
+ pipette = instruments.Pipette(
+ axis='b',
+ max_volume=200,
+ tip_racks=[tiprack],
+ trash_container=trash)
+
+.. testcode:: transfer_1
+
+ pipette.transfer(700, plate.wells('A2'), plate.wells('B2'))
+
+ for c in robot.commands():
+ print(c)
+
+will print out...
+
+.. testoutput:: transfer_1
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ Picking up tip from
+ Aspirating 200.0 at
+ Dispensing 200.0 at
+ Aspirating 200.0 at
+ Dispensing 200.0 at
+ Aspirating 150.0 at
+ Dispensing 150.0 at
+ Aspirating 150.0 at
+ Dispensing 150.0 at
+ Drop_tip at
+
+Multiple Wells
+--------------
+
+Transfer commands are most useful when moving liquid between multiple wells.
+
+.. testsetup:: transfer_2
+
+ from opentrons import robot, containers, instruments
+
+ robot.reset()
+ robot.clear_commands()
+
+ plate = containers.load('96-flat', 'B1')
+
+ tiprack = containers.load('tiprack-200ul', 'A1')
+ trash = containers.load('point', 'D2')
+
+ pipette = instruments.Pipette(
+ axis='b',
+ max_volume=200,
+ tip_racks=[tiprack],
+ trash_container=trash)
+
+.. testcode:: transfer_2
+
+ pipette.transfer(100, plate.cols('A'), plate.cols('B'))
+
+ for c in robot.commands():
+ print(c)
+
+will print out...
+
+.. testoutput:: transfer_2
+ :options: -ELLIPSIS, +NORMALIZE_WHITESPACE
+
+ Picking up tip from
+ Aspirating 100.0 at
+ Dispensing 100.0 at
+ Aspirating 100.0 at
+ Dispensing 100.0 at
+ Aspirating 100.0 at
+ Dispensing 100.0 at
+ Aspirating 100.0 at
+ Dispensing 100.0 at
+ Aspirating 100.0 at
+ Dispensing 100.0 at