Skip to content

Commit

Permalink
Paper Freeze (#39)
Browse files Browse the repository at this point in the history
* Refactor: Cleanup for Digital Discovery Paper

* testing resetting with errors

* Fix: reset state on reconnect

---------

Co-authored-by: Dozgulbas <[email protected]>
  • Loading branch information
LuckierDodge and Dozgulbas authored Oct 11, 2023
1 parent 33bb20a commit 893f1e3
Show file tree
Hide file tree
Showing 20 changed files with 614 additions and 586 deletions.
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.DEFAULT_GOAL := all
isort = isort ot2_driver
black = black --target-version py39 ot2_driver
isort = python -m isort .
black = python -m black --target-version py39 .

.PHONY: format
format:
Expand All @@ -10,15 +10,15 @@ format:
.PHONY: lint
lint:
$(black) --check --diff
flake8 ot2_driver/
pydocstyle ot2_driver/ --count
python -m flake8 .
python -m pydocstyle . --count



.PHONY: mypy
mypy:
mypy --config-file setup.cfg --package ot2_driver/
mypy --config-file setup.cfg ot2_driver/
mypy --config-file setup.cfg --package .
mypy --config-file setup.cfg .

.PHONY: all
all: format lint
52 changes: 27 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
### Installation
1. `git clone https://github.com/KPHippe/ot2_driver.git`
2. Switch to my dev branch `git checkout dev-kyle`
3. I would recommend a conda/venv environment. The following assusumes conda.
1. `conda create -n ot2-driver python=3.9`
1. `conda activate ot2-driver`
1. `pip install -r requirements.txt`
1. `pip install -e .`
### Installation

```
git clone https://github.com/AD-SDL/ot2_module.git
cd ot2_module
pip install -r requirements.txt
pip install -e .
```

*This installs ot2_driver as a package*

Note: This module was developed using Python 3.9

### Getting the OT2 setup for ssh
*This is not required (or used) for the HTTP driver*
*This is not required (or used) for the HTTP driver*
When setting up an ssh key to connect to the opentrons, it is helpful to make a new one without a passphrase. For more information on setting up an ssh connection see:

*Note, you have to have the Opentrons App installed*

- https://support.opentrons.com/en/articles/3203681-setting-up-ssh-access-to-your-ot-2
- https://support.opentrons.com/en/articles/3287453-connecting-to-your-ot-2-with-ssh

For prototyping in the RPL, connect via the wire and wait for the robot to become visible on the application. Click `settings` then `network settings` and if you intend on running via the wire, use the `wired-ip` in the robot configuration file. If you intend to use the wireless IP, you must connect to the `snowcrash` network, but this does not have internet access.
For prototyping in the RPL, connect via the wire and wait for the robot to become visible on the application. Click `settings` then `network settings` and if you intend on running via the wire, use the `wired-ip` in the robot configuration file. If you intend to use the wireless IP, you must connect to the `snowcrash` network, but this does not have internet access.

### Robot config
### Robot config

Below is an example of what I refer to as the `robot_config`
Below is an example of what I refer to as the `robot_config`
```
# OT2 in lab
- ip: IP.ADDRESS
Expand All @@ -32,7 +34,7 @@ Below is an example of what I refer to as the `robot_config`
```

### Running the driver
### Running the driver

If you would like to use the script as I have made it, I have provided command line descriptions and example commands below

Expand All @@ -57,27 +59,27 @@ optional arguments:
```

To run the `protopiler/example_configs/basic_config.yaml` with verbose settings and default outs, run the following
To run the `protopiler/example_configs/basic_config.yaml` with verbose settings and default outs, run the following
```
python ot2_driver_ssh.py -rc [insert/robot/config/path] -pc protopiler/example_configs/basic_config.yaml -v
```
To run the `protopiler/example_configs/basic_config.yaml` with verbose settings and specify the output files, run the following
To run the `protopiler/example_configs/basic_config.yaml` with verbose settings and specify the output files, run the following

```
python ot2_driver_ssh.py -rc [insert/robot/config/path] -pc protopiler/example_configs/basic_config.yaml -po ./test_protocol.py -ro ./test_resources.json -v
python ot2_driver_ssh.py -rc [insert/robot/config/path] -pc protopiler/example_configs/basic_config.yaml -po ./test_protocol.py -ro ./test_resources.json -v
```

To run your own protocol.py file, replace data in the `-pc` option with the path to your protocol.py file
```
python ot2_driver_ssh.py -rc [insert/robot/config/path] -pc ./test_protocol.py
```

*The process is the same for the HTTP driver*
*The process is the same for the HTTP driver*

If you would like to write your own code using the ot2 driver you can start with something like this
```python
# would have to specify path to ot2_driver_ssh.py if not in directory
from ot2_driver_ssh import OT2_Driver
from ot2_driver_ssh import OT2_Driver

# Load one ot2
for ot2_raw_cfg in yaml.safe_load(open(`robot_config_path`)):
Expand All @@ -92,22 +94,22 @@ if "py" not in str(`protocol_config`):
protocol_out=`protocol_out`,
resource_out=`resource_out`,
)


# Transfer the protocol to the ot2

# Transfer the protocol to the ot2
transfer_returncode = ot2.transfer(protocol_file)
if returncode:
print("Exception raised when transferring...")

# Execute the protocol
# Execute the protocol
ot2.execute(protocol_file)

```
### Updating the Code on node computer
1. `cd ~/wei_ws/src/ot2_driver`
1. `cd ~/wei_ws/src/ot2_module`
2. `git pull`
3. `pip install -e .`
### Running Dev Tools
### Running Dev Tools

1. Install `pip install -r requirements/dev.txt`
2. Run `make` in project root
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@

# -- Path setup --------------------------------------------------------------

import datetime

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
import datetime

sys.path.insert(0, os.path.abspath("../.."))
import ot2_driver

# -- Project information -----------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion ot2_driver/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Test descriptions, I am in the `ot2_driver.__init__`"""

__version__ = "0.0.1a1"
__version__ = "0.2.0"
8 changes: 4 additions & 4 deletions ot2_driver/config.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""Stores dataclasses/args/config for the ot2 drivers"""
import yaml
import json
from argparse import ArgumentParser, Namespace
from pathlib import Path
from typing import Union, Optional, Type, TypeVar
from typing import Optional, Type, TypeVar, Union

import yaml
from pydantic import BaseModel as _BaseModel

_T = TypeVar("_T")
Expand All @@ -13,7 +13,7 @@


class BaseModel(_BaseModel):
"""Allows any sub-class to inherit methods allowing for programatic description of protocols
"""Allows any sub-class to inherit methods allowing for programmatic description of protocols
Can load a yaml into a class and write a class into a yaml file.
"""

Expand Down Expand Up @@ -48,7 +48,7 @@ def json(self, **kwargs) -> str:
return super().json(**kwargs)

def write_yaml(self, cfg_path: PathLike) -> None:
"""Allows programatic creation of ot2util objects and saving them into yaml.
"""Allows programmatic creation of ot2util objects and saving them into yaml.
Parameters
----------
cfg_path : PathLike
Expand Down
27 changes: 19 additions & 8 deletions ot2_driver/ot2_driver_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import time
from enum import Enum
from pathlib import Path
from typing import Dict, List, Optional, Tuple, Any
from typing import Any, Dict, List, Optional, Tuple

import requests
import yaml
from urllib3 import Retry

from ot2_driver.config import PathLike, parse_ot2_args, OT2_Config
from ot2_driver.config import OT2_Config, PathLike, parse_ot2_args
from ot2_driver.protopiler.protopiler import ProtoPiler


Expand Down Expand Up @@ -77,7 +77,12 @@ def __init__(
self.change_lights_status(status=True)

def compile_protocol(
self, config_path, resource_file=None, resource_path=None, payload: Optional[Dict[str, Any]] = None, protocol_out_path=None
self,
config_path,
resource_file=None,
resource_path=None,
payload: Optional[Dict[str, Any]] = None,
protocol_out_path=None,
) -> Tuple[str, str]:
"""Compile the protocols via protopiler
Expand All @@ -97,14 +102,20 @@ def compile_protocol(
"""
if ".py" not in str(config_path):
self.protopiler.load_config(
config_path=config_path, resource_file=resource_file, resource_path=resource_path, protocol_out_path=protocol_out_path
config_path=config_path,
resource_file=resource_file,
resource_path=resource_path,
protocol_out_path=protocol_out_path,
)
print("resource_file = {}".format(str(resource_file)))
(
protocol_out_path,
protocol_resource_file,
) = self.protopiler.yaml_to_protocol(
config_path, resource_file=resource_file, resource_file_out=resource_path, payload=payload
config_path,
resource_file=resource_file,
resource_file_out=resource_path,
payload=payload,
)

return protocol_out_path, protocol_resource_file
Expand Down Expand Up @@ -258,10 +269,10 @@ def get_robot_status(self) -> RobotStatus:
Status
Either IDLE or RUNNING
"""
runs = self.get_runs()
if runs is None:
runs = self.get_runs()
if runs is None:
return RobotStatus.OFFLINE.value

for run in runs:
run_status = run["status"]
if (
Expand Down
15 changes: 8 additions & 7 deletions ot2_driver/protocol_20230221-123810.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from opentrons import protocol_api


metadata = {
"protocolName": "Color Mixing all",
"author": "Kyle [email protected]",
"description": "Mixing red colors",
"apiLevel": "2.12"
"apiLevel": "2.12",
}

def run(protocol: protocol_api.ProtocolContext):

def run(protocol: protocol_api.ProtocolContext):
deck = {}
pipettes = {}

Expand All @@ -20,8 +19,12 @@ def run(protocol: protocol_api.ProtocolContext):
deck["7"] = protocol.load_labware("opentrons_6_tuberack_nest_50ml_conical", "7")
deck["10"] = protocol.load_labware("opentrons_96_tiprack_300ul", "10")
deck["11"] = protocol.load_labware("opentrons_96_tiprack_20ul", "11")
pipettes["left"] = protocol.load_instrument("p300_single_gen2", "left", tip_racks=[deck["10"]])
pipettes["right"] = protocol.load_instrument("p20_single_gen2", "right", tip_racks=[deck["11"]])
pipettes["left"] = protocol.load_instrument(
"p300_single_gen2", "left", tip_racks=[deck["10"]]
)
pipettes["right"] = protocol.load_instrument(
"p20_single_gen2", "right", tip_racks=[deck["11"]]
)

####################
# execute commands #
Expand Down Expand Up @@ -60,7 +63,6 @@ def run(protocol: protocol_api.ProtocolContext):
pipettes["left"].blow_out()
pipettes["left"].drop_tip()


# Mix color 2
pipettes["left"].pick_up_tip(deck["10"].wells()[3])
pipettes["left"].well_bottom_clearance.aspirate = 1.0
Expand Down Expand Up @@ -94,7 +96,6 @@ def run(protocol: protocol_api.ProtocolContext):
pipettes["right"].blow_out()
pipettes["right"].drop_tip()


# Mix color 3
pipettes["right"].pick_up_tip(deck["11"].wells()[2])
pipettes["right"].well_bottom_clearance.aspirate = 1.0
Expand Down
26 changes: 23 additions & 3 deletions ot2_driver/protopiler/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ class Transfer(CommandBase):
"""blow out from tip into current location"""
drop_tip: Union[bool, List[bool]] = True
"""Drop the tip once a transfer is done"""
return_tip:Union[bool, List[bool]] = False
return_tip: Union[bool, List[bool]] = False
"""puts tip back into tip box"""


class Multi_Transfer(CommandBase):
multi_source: Union[str, List[List[str]]]
"""List of sources to be aspirated, each list within matrix presumed to be in single column"""
Expand All @@ -133,6 +134,7 @@ class Multi_Transfer(CommandBase):
multi_drop_tip: Union[bool, List[bool]] = True
"""Drop the tip once a transfer is done"""


class Mix(CommandBase):
reps: Union[int, List[int]]
"""how many mix cycles"""
Expand All @@ -141,26 +143,32 @@ class Mix(CommandBase):
location: Union[List[str], str]
"""mixing destination"""


class Deactivate(CommandBase):
deactivate: bool
"""Deactivates current module"""


class Temperature_Set(CommandBase):
change_temp: int
"""Temperature to set temperature module to"""


class Replace_Tip(CommandBase):
replace_tip: bool
"""Place tip back into tip rack"""


class Clear_Pipette(CommandBase):
clear: bool
"""Blowout and remove any tip on pipette over trash"""


class Move_Pipette(CommandBase):
move_to: int
"""Moves pipette to given deck position"""


# metadata container
class Metadata(BaseSettings):
"""Container for the run metadata"""
Expand All @@ -182,7 +190,19 @@ class ProtocolConfig(BaseSettings):
"""The additional resources (currently xls, xlsx files) to be used when compiling a protocol"""
equipment: List[Union[Labware, Pipette]]
"""A list of the equipment you want to use on the OT2"""
commands: List[Union[Transfer, Multi_Transfer, Mix, Deactivate, Temperature_Set, Replace_Tip, Clear_Pipette, Move_Pipette, CommandBase]]
commands: List[
Union[
Transfer,
Multi_Transfer,
Mix,
Deactivate,
Temperature_Set,
Replace_Tip,
Clear_Pipette,
Move_Pipette,
CommandBase,
]
]
"""Commands to execute during run"""
metadata: Metadata
"""Information about the run"""
"""Information about the run"""
Loading

0 comments on commit 893f1e3

Please sign in to comment.