Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APIv2 Docs #4120

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 19 additions & 21 deletions api/docs/source/v2/apiv2index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ Overview
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 instructions to transfer from well ``'A1'`` to well ``'B1'`` that even a computer could understand:
The design goal of the Opentrons API is to make code readable and easy to understand. For example, below is example code and instructions to transfer from well ``'A1'`` to well ``'B1'`` :

.. code-block:: none

This protocol is by me; it’s called Opentrons Protocol Tutorial and is used for demonstrating the Opentrons API
This protocol is called Opentrons Protocol Tutorial and is used for demonstrating the Opentrons API

Begin the protocol

Add a 96 well plate, and place it in slot '2' of the robot deck
Add a 300 µL tip rack, and place it in slot '1' of the robot deck

Add a single-channel 300 µL pipette to the left mount, and tell it to use that tip rack
Add a single-channel 300 µL pipette to the left mount, and tell it to use the left tip rack

Transfer 100 µL from the plate's 'A1' well to its 'B2' well

Expand All @@ -49,7 +49,7 @@ If we were to rewrite this with the Opentrons API, it would look like the follow
# metadata
metadata = {
'protocolName': 'My Protocol',
'author': 'Name <[email protected]>',
'author': 'your email address <your-[email protected]>',
wheresaddie marked this conversation as resolved.
Show resolved Hide resolved
'description': 'Simple protocol to get started using OT2'
}

Expand Down Expand Up @@ -88,14 +88,14 @@ When writing protocols using the Opentrons API, there are generally five section
Metadata
^^^^^^^^

Metadata is a dictionary of data that is read by the server and returned to client applications (such as the Opentrons Run App). It is not needed to run a protocol (and is entirely optional), but if present can help the client application display additional data about the protocol currently being executed.
Metadata describes other data. It provides information about a certain item's content. It is not needed to run a protocol (and is entirely optional), but if present can help the client application display additional data about the protocol currently being executed.

The fields above (``"protocolName"``, ``"author"``, and ``"description"``) are the recommended fields, but the metadata dictionary can contain fewer fields, or additional fields as desired (though non-standard fields are not displayed by the Opentrons app).
The fields above (``"protocolName"``, ``"author"``, and ``"description"``) are the recommended fields, but the metadata can contain fewer fields, or additional fields as desired (though non-standard fields are not displayed by the Opentrons app).

The Run Function and the Protocol Context
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Opentrons API version 2 protocols are structured around a function called ``run(protocol)``, defined in code like this:
Opentrons API version 2 protocols are structured around a function called ``run(protocol)``, written in code as:

.. code-block:: python

Expand All @@ -104,11 +104,11 @@ Opentrons API version 2 protocols are structured around a function called ``run(
def run(protocol: protocol_api.ProtocolContext):
pass

This function must be named exactly ``run`` and must take exactly one mandatory argument (its name doesn’t matter, but we recommend ``protocol`` since this argument represents the protocol that the robot will execute).
The function must be named exactly ``run`` and must take exactly one mandatory argument (we recommend ``protocol`` since this argument represents the protocol that the robot will execute and is easy to parse if another editor needs to implement or reuse your code).

The function ``run`` is the container for the code that defines your protocol.
The function ``run`` is the container for the code that defines your protocol. Protocols are similar to interfaces, in that they define a collection of methods an object must support.

The object ``protocol`` is the *protocol context*, which represents the robot and its capabilities. It is always an instance of the :py:class:`opentrons.protocol_api.contexts.ProtocolContext` class (though you'll never have to instantiate one yourself - it is always passed in to ``run()``), and it is tagged as such in the example protocol to allow most editors to give you autocomplete.
In this example, object ``protocol`` is the *protocol context*, which represents the robot and its capabilities. It is always an instance of the :py:class:`opentrons.protocol_api.contexts.ProtocolContext` class (though you'll never have to instantiate one yourself - it is always passed in to ``run()``), and it is tagged as such in the example protocol to allow most editors to give you autocomplete.

The protocol context has two responsibilities:

Expand All @@ -117,39 +117,37 @@ The protocol context has two responsibilities:

The protocol context plays the same role as the ``robot``, ``labware``, ``instruments``, and ``modules`` objects in past versions of the API, with one important difference: it is only one object; and because it is passed in to your protocol rather than imported, it is possible for the API to be much more rigorous about separating simulation from reality.

The key point is that there is no longer any need to ``import opentrons`` at the top of every protocol, since the *robot* now *runs the protocol*, rather than the *protocol running the robot*. The example protocol imports the definition of the protocol context to provide editors with autocomplete sources.
Since the *robot* now *runs the protocol*, rather than the *protocol running the robot*, the key point to note is that there is no longer any need to ``import opentrons`` at the top of every protocol.


Labware
^^^^^^^
Refer to `the python docs <https://docs.python.org/3/index.html>`_ for clarification on using variables and additional information about handling labware in the :ref:`new-labware` section.

The next step is defining the labware required for your protocol. You must tell the protocol context about what should be present on the deck, and where. You tell the protocol context about labware by calling the method ``protocol.load_labware(name, slot)`` and saving the result.
The next step is defining the labware required for your protocol. You tell the protocol context about labware by calling the method ``protocol.load_labware(name, slot)``. By implementing this, the protocol receives context about what should be present on the deck, and where.

The name of a labware is a string that is different for each kind of labware. You can look up labware to add to your protocol on the Opentrons `Labware Library <https://labware.opentrons.com>`_.
The name of a labware is a string that is different for each kind of labware. You can reference all available labware by using the Opentrons `Labware Library <https://labware.opentrons.com>`_.

The slot is the labelled location on the deck in which you've placed the labware. The available slots are numbered from 1-11.
Note: the slot is the labelled location on the deck in which you've placed the labware. The available slots are numbered from 1-11.

Our example protocol above loads a `Corning 96 Well Plate <https://labware.opentrons.com/corning_96_wellplate_360ul_flat>`_ in slot 2 (``plate = protocol.load_labware('corning_96_wellplate_360ul_flat', 2)``) and an `Opentrons 300ul Tiprack <https://labware.opentrons.com/opentrons_96_tiprack_300ul>`_ in slot 1 (``tiprack = protocol.load_labware('opentrons_96_tiprack_300ul', 1)``). These can be referenced later in the protocol as ``plate`` and ``tiprack`` respectively. Check out `the python docs <https://docs.python.org/3/index.html>`_ for further clarification on using variables effectively in your code.

You can find more information about handling labware in the :ref:`new-labware` section.
Our example protocol above loads a `Corning 96 Well Plate <https://labware.opentrons.com/corning_96_wellplate_360ul_flat>`_ in slot 2 (``plate = protocol.load_labware('corning_96_wellplate_360ul_flat', 2)``) and an `Opentrons 300ul Tiprack <https://labware.opentrons.com/opentrons_96_tiprack_300ul>`_ in slot 1 (``tiprack = protocol.load_labware('opentrons_96_tiprack_300ul', 1)``). These can be referenced later in the protocol as ``plate`` and ``tiprack``.


Pipettes
^^^^^^^^
See :ref:`new-pipette` for more information on creating and working with pipettes.

After defining labware, you define the instruments required for your protocol. You tell the protocol context about which pipettes should be attached, and which slot they should be attached to, by calling the method ``protocol.load_instrument(model, mount, tip_racks)`` and saving the result.

The ``model`` of the pipette is the kind of pipette that should be attached; the ``mount`` is either ``"left"`` or ``"right"``; and ``tip_racks`` is a list of the objects representing tip racks that this instrument should use. Specifying ``tip_racks`` is optional, but if you don't then you'll have to manually specify where the instrument should pick up tips from every time you try and pick up a tip.

See :ref:`new-pipette` for more information on creating and working with pipettes.

Our example protocol above loads a P300 Single-channel pipette (``'p300_single'``) in the left mount (``'left'``), and uses the Opentrons 300ul tiprack we loaded previously as a source of tips (``tip_racks=[tiprack]``).
The example protocol above loads a P300 Single-channel pipette (``'p300_single'``) in the left mount (``'left'``), and uses the Opentrons 300ul tiprack loaded previously as a source of tips (``tip_racks=[tiprack]``).


Commands
^^^^^^^^

Once the instruments and labware required for the protocol are defined, the next step is to define the commands that make up the protocol. The most common commands are ``aspirate()``, ``dispense()``, ``pick_up_tip()``, and ``drop_tip()``. These and many others are described in the :ref:`v2-atomic-commands` and :ref:`v2-complex-commands` sections, which go into more detail about the commands and how they work. These commands typically specify which wells of which labware to interact with, using the labware you defined earlier, and are methods of the instruments you created in the pipette section. For instance, in our example protocol, you use the pipette you defined to:
Once the instruments and labware required for the protocol are defined, the next step is to define the commands that make up the protocol. The most common commands are ``aspirate()``, ``dispense()``, ``pick_up_tip()``, and ``drop_tip()``. These and many others are described in the :ref:`v2-atomic-commands` and :ref:`v2-complex-commands` sections, which go into more detail about the commands and how they work. These commands typically specify which wells of which labware to interact with, using the labware you defined earlier, and are methods of the instruments you created in the pipette section. In our example protocol, use the pipette you defined to:

1) Pick up a tip (implicitly from the tiprack you specified in slot 1 and assigned to the pipette): ``pipette.pick_up_tip()``
2) Aspirate 100ul from well A1 of the 96 well plate you specified in slot 2: ``pipette.aspirate(100, plate['A1'])``
Expand Down
32 changes: 17 additions & 15 deletions api/docs/source/v2/new_advanced_running.rst
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
Running Protocols Directly On The Robot
=======================================

Sometimes, you may write a protocol that is not suitable for execution through the Opentrons App. Perhaps it requires user input; perhaps it needs to do a lot of things it cannot do when being simulated. There are two ways to run a protocol on the robot without using the Opentrons app.
There are two ways to run a protocol on the robot without using the Opentrons app. These are typically protocols that require input or physical stimulations and cannot be emulated.

Jupyter Notebook
----------------

The robot runs a Jupyter notebook server that you can connect to with your web browser. This is a convenient environment in which to write and debug protocols, since you can define different parts of your protocol in different notebook cells and run only part of the protocol at a given time.
Using your web browers (the latest Chrome, Firefox, and Safari are known to work; the latest Edge and Opera probably will), you can access the robots Jupyter notebook server. This is a convenient environment to execute and debug protocols and define different parts of your protocol in different notebook cells. By doing such you can specify which parts of the protocol at a given time should run.

You can access the robot’s Jupyter notebook by following these steps:
To access the robot’s Jupyter notebook:

1. Open your Opentrons App and look for the IP address of your robot on the robot information page.
2. Type in ``(Your Robot's IP Address):48888`` into any browser on your computer.
1. Find the IP address of your robot on the robot information page.
2. Open your Opentrons App
3. Enter ``(Your Robot's IP Address):48888`` into any browser on your computer.

Here, you can select a notebook and develop protocols that will be saved on the robot itself. Note that these protocols will only be on the robot unless specifically downloaded to your computer using the ``File / Download As`` buttons in the notebook.
Here, you can select a notebook and develop protocols.

Note: Protocols will stored ONLY on the robot only unless specifically downloaded to your computer via ``File / Download As`` buttons in the notebook.

Protocol Structure
++++++++++++++++++

To take advantage of Jupyter's ability to run only parts of your protocol, you have to restructure it slightly - turn it inside out. Rather than writing a single ``run`` function that contains all your protocol logic, you can use the function :py:meth:`opentrons.execute.get_protocol_api`:
To take advantage of Jupyter's ability to run only parts of your protocol use the function :py:meth:`opentrons.execute.get_protocol_api`:

.. code-block:: python

Expand All @@ -28,21 +31,20 @@ To take advantage of Jupyter's ability to run only parts of your protocol, you h

This returns the same kind of object - a :py:class:`.ProtocolContext` - that is passed into your protocol's ``run`` function when you upload your protocol in the Opentrons App. Full documentation on the capabilities and use of the :py:class:`.ProtocolContext` object is available in the other sections of this guide - :ref:`protocol-api-robot`, :ref:`new-pipette`, :ref:`v2-atomic-commands`, :ref:`v2-complex-commands`, :ref:`new-labware`, and :ref:`new_modules`; a full list of all available attributes and methods is available in :ref:`protocol-api-reference`.

Whenever you call `get_protocol_api`, the robot will update its cache of attached instruments and modules. You can call `get_protocol_api` repeatedly; it will return an entirely new :py:class:`.ProtocolContext` each time, without any labware loaded or any instruments established. This can be a good way to reset the state of the system, if you accidentally loaded in the wrong labware.

Now that you have a :py:class:`.ProtocolContext`, you call all its methods just as you would in a protocol, without the encompassing ``run`` function, just like if you were prototyping a plotting or pandas script for later use.
Whenever you call `get_protocol_api`, the robot will update its cache of attached instruments and modules. By calling `get_protocol_api` repeatedly; it will return an entirely new :py:class:`.ProtocolContext` without any labware loaded or any instruments established.
Using :py:class:`.ProtocolContext`, you call all its methods just as you would in a protocol, without the encompassing ``run`` function, just like if you were prototyping a plotting or pandas script for later use.

Running A Previously-Written Protocol
How To Run A Previously-Written Protocol
+++++++++++++++++++++++++++++++++++++

If you have a protocol that you have already written, that is defined in a ``run`` function, and that you don't want to modify, you can run it directly in Jupyter. Copy the protocol into a cell and execute it - this won't cause the robot to move, it just makes the function available. Then, call the ``run`` function you just defined, and give it a :py:class:`.ProtocolContext`:
Any protocol written that is defined in a ``run`` function, you implement directly in Jupyter. Copy the protocol into a cell and execute it. This won't cause the robot to move, it just makes the function available. Call the ``run`` function you just defined, and give it a :py:class:`.ProtocolContext`:

.. code-block:: python

>>> import opentrons.execute
>>> from opentrons import protocol_api
>>> def run(protocol: protocol_api.ProtocolContext):
... # the contents of your protocol are here...
... # the contents of your protocol are here
...
>>> protocol = opentrons.execute.get_protocol_api()
>>> run(protocol) # your protocol will now run
Expand All @@ -52,11 +54,11 @@ If you have a protocol that you have already written, that is defined in a ``run
Command Line
------------

The robot's command line is accessible either by creating a new terminal in Jupyter or by using SSH to access its terminal. Sometimes, you may want to run a protocol on the robot terminal directly, without using the Opentrons App or the robot's Jupyter notebook. To do this, use the command line program ``opentrons_execute``:
The robot's command line is accessible either by creating a new terminal in Jupyter or by using SSH to access its terminal. This allows you to run the protocol directly. To do this, use the command line program ``opentrons_execute``:

.. code-block:: shell

# opentrons_execute /data/my_protocol.py


You can access help on the usage of ``opentrons_execute`` by calling ``opentrons_execute --help``. This script has a couple options to let you customize what it prints out when you run it. By default, it will print out the same runlog you see in the Opentrons App when running a protocol, as it executes; it will also print out internal logs at level ``warning`` or above. Both of these behaviors can be changed.
You can access help on the usage of ``opentrons_execute`` by calling ``opentrons_execute --help``.
Loading