From 133922d45831585d7dbc37be26824f878b5a8650 Mon Sep 17 00:00:00 2001 From: Joe Laforet Date: Wed, 15 May 2024 11:29:44 -0400 Subject: [PATCH 1/3] Added OT2 Deck Intro --- DataSimulations/Introduction_to_Decks.ipynb | 288 +++---- .../Introduction_to_Decks-checkpoint.ipynb | 288 +++---- .../OT2_Deck_Intro-checkpoint.ipynb | 619 ++++++++++++++ Decks/Introduction_to_Decks.ipynb | 2 +- Decks/OT2_Deck_Intro.ipynb | 618 ++++++++++++++ Decks/pylabrobot-20240514.log | 0 Decks/pylabrobot-20240515.log | 0 Equipment/Introduction_to_Equipment.ipynb | 288 +++---- Introduction_to_PyLabRobot.ipynb | 776 ++++++++++++++++-- Notes from Stefan | 9 + Protocols/Introduction_to_Protocols.ipynb | 288 +++---- README.md | 74 +- .../Introduction_to_SystemsIntegrations.ipynb | 288 +++---- Worklists/Introduction_to_Worklists.ipynb | 288 +++---- pylabrobot-20240513.log | 0 pylabrobot-20240514.log | 0 16 files changed, 2867 insertions(+), 959 deletions(-) create mode 100644 Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb create mode 100644 Decks/OT2_Deck_Intro.ipynb create mode 100644 Decks/pylabrobot-20240514.log create mode 100644 Decks/pylabrobot-20240515.log create mode 100644 Notes from Stefan create mode 100644 pylabrobot-20240513.log create mode 100644 pylabrobot-20240514.log diff --git a/DataSimulations/Introduction_to_Decks.ipynb b/DataSimulations/Introduction_to_Decks.ipynb index 61a4782..1c6ae91 100644 --- a/DataSimulations/Introduction_to_Decks.ipynb +++ b/DataSimulations/Introduction_to_Decks.ipynb @@ -1,144 +1,144 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", - "metadata": {}, - "source": [ - "**Welcome to PyLabRobot!**\n", - "\n", - "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", - "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", - "\n", - "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", - "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", - "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", - "be translatable across many different machines.\n", - "\n", - "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", - "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", - "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", - "the most widely used liquid handling robots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.liquid_handling import LiquidHandler\n", - "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", - "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b372972-d6dc-454b-95eb-d9941405621b", - "metadata": {}, - "outputs": [], - "source": [ - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", - "await lh.setup()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0324171c-101d-4b3d-9103-a0137c620174", - "metadata": {}, - "outputs": [], - "source": [ - "vis = Visualizer(resource=lh)\n", - "await vis.setup()" - ] - }, - { - "cell_type": "markdown", - "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", - "metadata": {}, - "source": [ - "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.resources import (\n", - " TIP_CAR_480_A00,\n", - " PLT_CAR_L5AC_A00,\n", - " Cos_96_DW_1mL,\n", - " HTF_L\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", - "metadata": {}, - "outputs": [], - "source": [ - "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", - "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", - "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", - "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", - "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", - "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", - "lh.deck.assign_child_resource(tip_car, rails=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": {}, - "outputs": [], - "source": [ - "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", - "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", - "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", - "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", - "lh.deck.assign_child_resource(plt_car, rails=8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", - "metadata": {}, - "outputs": [], - "source": [ - "await vis.stop()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", + "metadata": {}, + "source": [ + "**Welcome to PyLabRobot!**\n", + "\n", + "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", + "\n", + "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", + "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", + "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", + "be translatable across many different machines.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", + "the most widely used liquid handling robots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.hamilton import STARLetDeck\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b372972-d6dc-454b-95eb-d9941405621b", + "metadata": {}, + "outputs": [], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "await lh.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0324171c-101d-4b3d-9103-a0137c620174", + "metadata": {}, + "outputs": [], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", + "metadata": {}, + "source": [ + "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " TIP_CAR_480_A00,\n", + " PLT_CAR_L5AC_A00,\n", + " Cos_96_DW_1mL,\n", + " HTF_L\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", + "metadata": {}, + "outputs": [], + "source": [ + "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", + "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", + "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", + "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", + "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", + "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", + "lh.deck.assign_child_resource(tip_car, rails=15)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", + "metadata": {}, + "outputs": [], + "source": [ + "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", + "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", + "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", + "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", + "lh.deck.assign_child_resource(plt_car, rails=8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", + "metadata": {}, + "outputs": [], + "source": [ + "await vis.stop()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Decks/.ipynb_checkpoints/Introduction_to_Decks-checkpoint.ipynb b/Decks/.ipynb_checkpoints/Introduction_to_Decks-checkpoint.ipynb index 61a4782..1c6ae91 100644 --- a/Decks/.ipynb_checkpoints/Introduction_to_Decks-checkpoint.ipynb +++ b/Decks/.ipynb_checkpoints/Introduction_to_Decks-checkpoint.ipynb @@ -1,144 +1,144 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", - "metadata": {}, - "source": [ - "**Welcome to PyLabRobot!**\n", - "\n", - "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", - "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", - "\n", - "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", - "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", - "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", - "be translatable across many different machines.\n", - "\n", - "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", - "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", - "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", - "the most widely used liquid handling robots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.liquid_handling import LiquidHandler\n", - "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", - "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b372972-d6dc-454b-95eb-d9941405621b", - "metadata": {}, - "outputs": [], - "source": [ - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", - "await lh.setup()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0324171c-101d-4b3d-9103-a0137c620174", - "metadata": {}, - "outputs": [], - "source": [ - "vis = Visualizer(resource=lh)\n", - "await vis.setup()" - ] - }, - { - "cell_type": "markdown", - "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", - "metadata": {}, - "source": [ - "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.resources import (\n", - " TIP_CAR_480_A00,\n", - " PLT_CAR_L5AC_A00,\n", - " Cos_96_DW_1mL,\n", - " HTF_L\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", - "metadata": {}, - "outputs": [], - "source": [ - "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", - "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", - "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", - "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", - "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", - "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", - "lh.deck.assign_child_resource(tip_car, rails=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": {}, - "outputs": [], - "source": [ - "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", - "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", - "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", - "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", - "lh.deck.assign_child_resource(plt_car, rails=8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", - "metadata": {}, - "outputs": [], - "source": [ - "await vis.stop()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", + "metadata": {}, + "source": [ + "**Welcome to PyLabRobot!**\n", + "\n", + "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", + "\n", + "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", + "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", + "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", + "be translatable across many different machines.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", + "the most widely used liquid handling robots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.hamilton import STARLetDeck\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b372972-d6dc-454b-95eb-d9941405621b", + "metadata": {}, + "outputs": [], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "await lh.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0324171c-101d-4b3d-9103-a0137c620174", + "metadata": {}, + "outputs": [], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", + "metadata": {}, + "source": [ + "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " TIP_CAR_480_A00,\n", + " PLT_CAR_L5AC_A00,\n", + " Cos_96_DW_1mL,\n", + " HTF_L\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", + "metadata": {}, + "outputs": [], + "source": [ + "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", + "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", + "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", + "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", + "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", + "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", + "lh.deck.assign_child_resource(tip_car, rails=15)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", + "metadata": {}, + "outputs": [], + "source": [ + "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", + "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", + "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", + "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", + "lh.deck.assign_child_resource(plt_car, rails=8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", + "metadata": {}, + "outputs": [], + "source": [ + "await vis.stop()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb b/Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb new file mode 100644 index 0000000..c06336f --- /dev/null +++ b/Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb @@ -0,0 +1,619 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8dbbadf0-ac05-44a6-a303-e7e71691ed9a", + "metadata": {}, + "source": [ + "# Intro to Decks: OT2\n", + "### In this tutorial, you will see how to instantiate an OT2 Deck, how to add labware, and how to move liquids around.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `OTDeck` that will represent the deck of an OpenTrons OT2, one of\n", + "the most widely used liquid handling robots. \n", + "\n", + "Make sure to also `import opentrons` !" + ] + }, + { + "cell_type": "markdown", + "id": "0b6ee87a-a089-4a5b-9b60-852d1e1f8874", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "63636707-3e3c-4aba-b8eb-1e702875d391", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.opentrons import OTDeck\n", + "\n", + "from pylabrobot.resources.opentrons.load import *\n", + "from pylabrobot.resources.opentrons.plates import *\n", + "\n", + "import opentrons" + ] + }, + { + "cell_type": "markdown", + "id": "10bcab3e-f908-479a-8e63-1fecfbe9ecf7", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "### Setting up the Deck and Visualizer" + ] + }, + { + "cell_type": "markdown", + "id": "7a612e7b-d246-4c75-874c-1b053ab2aeda", + "metadata": {}, + "source": [ + "First, we will create an instance of the `LiquidHandler` class. This may take some time to set up, so we run the `setup()` function with the `await` keyword." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cb5eb1ee-a1ae-4fd3-afff-78967d6e9f95", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting up the robot.\n", + "Resource deck was assigned to the robot.\n", + "Resource trash_container was assigned to the robot.\n" + ] + } + ], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=OTDeck())\n", + "\n", + "await lh.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "c044f917-ae75-4e17-80e1-7ad0f13b64cc", + "metadata": {}, + "source": [ + "After initializing our `LiquidHandler`, we want to create an instance of a `Visualizer`. This will allow you to see the Deck and follow your protocol in real time. You can see how tips and liquids move as you run commands. Make sure to open the `Visualizer` in another window." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9ce8270d-91ed-4836-a742-ab5375c4fdaa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Websocket server started at http://127.0.0.1:2122\n", + "File server started at http://127.0.0.1:1338 . Open this URL in your browser.\n" + ] + } + ], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "70c070bd-f7fd-47c4-9c98-65674fa776fc", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "### Adding Labware to the Deck" + ] + }, + { + "cell_type": "markdown", + "id": "4d0024ee-4722-4b99-afad-3bba67388855", + "metadata": {}, + "source": [ + "Now, we are ready to add some labware to the deck. PyLabRobot has many different labware items already defined. Only import the ones that you need for your protocol. A full list of labware can be found in `PyLabRobot\\Resources\\opentrons`. You can also create custom labware, but that is out of scope for this tutorial.\n", + "\n", + "Let's begin by importing a `TubeRack`, a `TipRack`, and a `Plate`.\n", + "
\n", + " Definitions of Labware:\n", + " \n", + "* **TubeRack** = Used to hold various tubes, commonly the 2mL Eppendorfs.\n", + "\n", + "* **TipRack** = Labware that holds pipette tips.\n", + "\n", + "* **Plate** = Well-Plate that one can add liquids to.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "71889711-e068-4e7e-b158-128a9491a1a0", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap,\n", + " opentrons_96_tiprack_300ul,\n", + " corning_96_wellplate_360ul_flat\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fae79fcb-7dbb-4145-a03a-eef0da7d6e38", + "metadata": {}, + "source": [ + "**Note:** The OT2 has **11 spots** for labware. It also has a built in trash can for discarding tips.\n", + "\n", + "One thing to keep in mind when designing a protocol is `layout efficiency`. The more separated labware is on the deck, the longer your protocol will be because the pipette has to travel farther.\n", + "\n", + "In general, you want to keep your tip racks in the back, your stocks in the middle, and then finally your plates in the front. This allows for `linear movement`.\n", + "\n", + "For example, the arm grabs a **tip from slot 7**, aspirates **stock from slot 4**, and then finally **dispenses in slot 1**. Reducing the travel time of the pipette will decrease the runtime of your protocol.\n", + "\n", + "To place labware on the Deck, call `assign_child_at_slot()`. Pass in the labware you want to place along with the slot you want to place it in." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c4c43470-21ff-4b3f-9a36-cdc3c0d97403", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource tip_rack was assigned to the robot.\n" + ] + } + ], + "source": [ + "# When you instantiate a labware, give it a name that will show when you\n", + "# mouse over it in the visualizer.\n", + "tip_rack = opentrons_96_tiprack_300ul(\"tip_rack\")\n", + "\n", + "lh.deck.assign_child_at_slot(tip_rack, 7)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3740eb57-80bd-498b-95d5-725b9487c196", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource tube_rack was assigned to the robot.\n" + ] + } + ], + "source": [ + "# Stock Solution Tube Rack\n", + "tube_rack = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap(\"tube_rack\")\n", + "\n", + "lh.deck.assign_child_at_slot(tube_rack, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "fd6a17ea-b41e-4033-a914-81b2d87635b9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource prep_plate was assigned to the robot.\n" + ] + } + ], + "source": [ + "# Plate for Sample Preparation\n", + "plate = corning_96_wellplate_360ul_flat(\"prep_plate\")\n", + "\n", + "lh.deck.assign_child_at_slot(plate, 1)" + ] + }, + { + "cell_type": "markdown", + "id": "b7c49e37-543c-49b5-86f0-5c9df9bdd5a1", + "metadata": {}, + "source": [ + "### Adding Liquids to the Deck" + ] + }, + { + "cell_type": "markdown", + "id": "b757ebe8-be14-48af-bda6-f377a8769d0b", + "metadata": {}, + "source": [ + "Let's add some liquids to our `tube_rack`. We can add up to the `max_volume` of the tube. If you go over this number, PyLabRobot will throw an error. We shall add 1000µL of 4 different dyes to the first column of our `tube_rack`. This corresponds to wells *A1, B1, C1, and D1*.\n", + "\n", + "To iterate over locations on labware, we use the `traverse()` function. This produces a generator object that we use the `next` keyword on to yield our desired wells.\n", + "\n", + "`traverse()` takes in two arguments: **batch_size** is the amount of wells to return, and **direction** is how to iterate over the wells. In our case, we use `\"down\"` to return the wells column wise.\n", + "\n", + "
\n", + " More info on direction:\n", + "\n", + "* `\"down\"`, `\"snake_down\"`, `\"right\"`, and `\"snake_right\"` start at the top left item **(A1)**.\n", + " \n", + "* `\"up\"` and `\"snake_up\"` start at the bottom left **(H1)**.\n", + " \n", + "* `\"left\"` and `\"snake_left\"` start at the top right **(A12)**.\n", + "\n", + "* The `snake` directions alternate between going in the given direction and going in the opposite direction. For example, `\"snake_down\"` will go from A1 to H1, then H2 to A2, then A3 to H3, etc.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "aca186f8-922b-4226-89ef-e6cfe886b512", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=tube_rack_B1, location=(018.210, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=tube_rack_C1, location=(018.210, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=tube_rack_D1, location=(018.210, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "first_col_tubes = next(tube_rack.traverse(batch_size=4, direction='down'))\n", + "first_col_tubes" + ] + }, + { + "cell_type": "markdown", + "id": "88f4e079-81e1-441c-923c-63e2a8b1cfb7", + "metadata": {}, + "source": [ + "Use the `tracker.add_liquid()` function to put liquid in a `tube`. The `tracker` class contains all of the methods associated with keeping record of how much/what kind of liquid is in a given container.\n", + "\n", + "Pass in a string for **\"Liquid_Type\"** and a number for **Volume** to this function.\n", + "\n", + "Let's add our dyes to the tubes in `first_col_tubes`." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "876af18c-fdde-4a78-8261-b9a61c580988", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(len(first_col_tubes)):\n", + " \n", + " first_col_tubes[i].tracker.add_liquid(f\"Dye_{i}\", 1000)\n", + " \n", + " #Commit the change\n", + " first_col_tubes[i].tracker.commit()" + ] + }, + { + "cell_type": "markdown", + "id": "1e0137ea-bd0f-4a8f-9785-3b7aafe5c7dd", + "metadata": {}, + "source": [ + "Here's a Utility function for printing all of the filled spots of a `TubeRack`." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ee999023-9b95-41b0-90c4-4e05bc65d629", + "metadata": {}, + "outputs": [], + "source": [ + "def print_filled_spots_of_tubeRack(tube_rack):\n", + "\n", + " all_tubes = tube_rack.get_all_children()\n", + "\n", + " all_empty = True\n", + " \n", + " for tube in all_tubes:\n", + " \n", + " liquid = tube.tracker.liquids\n", + "\n", + " if liquid != []:\n", + " print(f\"Spot {tube.name.split('_')[-1]} contains:\")\n", + "\n", + " name = liquid[0][0]\n", + " vol = liquid[0][1]\n", + " \n", + " print(f\"{vol}uL of {name}\")\n", + "\n", + " all_empty = False\n", + "\n", + " if all_empty:\n", + " print(\"Entire rack is empty!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1832d167-395f-44fe-911b-1584b9a71281", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Spot A1 contains:\n", + "1000uL of Dye_0\n", + "Spot B1 contains:\n", + "1000uL of Dye_1\n", + "Spot C1 contains:\n", + "1000uL of Dye_2\n", + "Spot D1 contains:\n", + "1000uL of Dye_3\n" + ] + } + ], + "source": [ + "print_filled_spots_of_tubeRack(tube_rack)" + ] + }, + { + "cell_type": "markdown", + "id": "ffceed8a-b9c4-4824-85e4-2676957811f6", + "metadata": {}, + "source": [ + "### Moving Liquids from Point A to Point B" + ] + }, + { + "cell_type": "markdown", + "id": "622baa5b-0e60-47cb-aa03-aeb3982d3519", + "metadata": {}, + "source": [ + "Why is it not updating the contents of the tubes correctly?? The animations are also broken now." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "d93e6576-a5d8-43fe-b8aa-3c48b4514a0d", + "metadata": {}, + "outputs": [], + "source": [ + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "0e85d828-b3f5-4ad2-9e87-56ccd985720f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "5f55c2d7-6e9c-4190-a1d7-ef65e7a93915", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Aspirating [Aspiration(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", + "Dispensing [Dispense(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack[\"A1\"])\n", + "time.sleep(2)\n", + "\n", + "await lh.aspirate(tube_rack[\"A1\"], vols=[100])\n", + "tube_rack[\"A1\"][0].tracker.commit()\n", + "time.sleep(2)\n", + "\n", + "await lh.dispense(plate[\"A1\"], vols=[100])\n", + "plate[\"A1\"][0].tracker.commit()\n", + "time.sleep(2)\n", + "\n", + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "e402336b-ff23-4205-81ee-d16e967ad017", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tube_rack[\"A1\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "e51ed207-74e3-4ad1-9aa4-7a79ece40016", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Spot A1 contains:\n", + "1000uL of Dye_0\n", + "Spot B1 contains:\n", + "1000uL of Dye_1\n", + "Spot C1 contains:\n", + "1000uL of Dye_2\n", + "Spot D1 contains:\n", + "1000uL of Dye_3\n" + ] + } + ], + "source": [ + "print_filled_spots_of_tubeRack(tube_rack)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "f64ffbc0-7d55-4f43-9083-4ecd147c5193", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('Dye_0', 1000)]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tube_rack[0][0].tracker.liquids" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ac2d2e3-dfb0-4d5f-8aee-8769cfd804f1", + "metadata": {}, + "outputs": [], + "source": [ + "await lh.pick_up_tips(tip_rack[\"A1\"])\n", + "time.sleep(1)\n", + "\n", + "await lh.aspirate(plate[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.dispense(tube_rack[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.return_tips()" + ] + }, + { + "cell_type": "markdown", + "id": "29adc390-9c6f-49c5-9112-5cdb7ce7b7a1", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "### For future reference, how to export states of labware as .json files" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "22fab8bb-af21-4f79-982e-ca46a11df867", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "' Save the state of this resource and all children to a JSON file.\\n\\n Args:\\n fn: File name. Caution: file will be overwritten.\\n indent: Same as `json.dump`\\'s `indent` argument (for json pretty printing).\\n\\n Examples:\\n Saving to a json file:\\n\\n >>> deck.save_state_to_file(\"my_state.json\")\\n'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\" Save the state of this resource and all children to a JSON file.\n", + "\n", + " Args:\n", + " fn: File name. Caution: file will be overwritten.\n", + " indent: Same as `json.dump`'s `indent` argument (for json pretty printing).\n", + "\n", + " Examples:\n", + " Saving to a json file:\n", + "\n", + " >>> deck.save_state_to_file(\"my_state.json\")\n", + "\"\"\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9d2169c-1e13-4abd-8095-6844b856d84e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Decks/Introduction_to_Decks.ipynb b/Decks/Introduction_to_Decks.ipynb index 61a4782..fbade5d 100644 --- a/Decks/Introduction_to_Decks.ipynb +++ b/Decks/Introduction_to_Decks.ipynb @@ -136,7 +136,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.10.4" } }, "nbformat": 4, diff --git a/Decks/OT2_Deck_Intro.ipynb b/Decks/OT2_Deck_Intro.ipynb new file mode 100644 index 0000000..8223e02 --- /dev/null +++ b/Decks/OT2_Deck_Intro.ipynb @@ -0,0 +1,618 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8dbbadf0-ac05-44a6-a303-e7e71691ed9a", + "metadata": {}, + "source": [ + "# Intro to Decks: OT2\n", + "### In this tutorial, you will see how to instantiate an OT2 Deck, how to add labware, and how to move liquids around.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `OTDeck` that will represent the deck of an OpenTrons OT2, one of\n", + "the most widely used liquid handling robots. \n", + "\n", + "Make sure to also `import opentrons` !" + ] + }, + { + "cell_type": "markdown", + "id": "0b6ee87a-a089-4a5b-9b60-852d1e1f8874", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "63636707-3e3c-4aba-b8eb-1e702875d391", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.opentrons import OTDeck\n", + "\n", + "from pylabrobot.resources.opentrons.load import *\n", + "from pylabrobot.resources.opentrons.plates import *\n", + "\n", + "import opentrons" + ] + }, + { + "cell_type": "markdown", + "id": "10bcab3e-f908-479a-8e63-1fecfbe9ecf7", + "metadata": {}, + "source": [ + "### Setting up the Deck and Visualizer" + ] + }, + { + "cell_type": "markdown", + "id": "7a612e7b-d246-4c75-874c-1b053ab2aeda", + "metadata": {}, + "source": [ + "First, we will create an instance of the `LiquidHandler` class. This may take some time to set up, so we run the `setup()` function with the `await` keyword." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cb5eb1ee-a1ae-4fd3-afff-78967d6e9f95", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting up the robot.\n", + "Resource deck was assigned to the robot.\n", + "Resource trash_container was assigned to the robot.\n" + ] + } + ], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=OTDeck())\n", + "\n", + "await lh.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "c044f917-ae75-4e17-80e1-7ad0f13b64cc", + "metadata": {}, + "source": [ + "After initializing our `LiquidHandler`, we want to create an instance of a `Visualizer`. This will allow you to see the Deck and follow your protocol in real time. You can see how tips and liquids move as you run commands. Make sure to open the `Visualizer` in another window." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9ce8270d-91ed-4836-a742-ab5375c4fdaa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Websocket server started at http://127.0.0.1:2122\n", + "File server started at http://127.0.0.1:1338 . Open this URL in your browser.\n" + ] + } + ], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "70c070bd-f7fd-47c4-9c98-65674fa776fc", + "metadata": {}, + "source": [ + "### Adding Labware to the Deck" + ] + }, + { + "cell_type": "markdown", + "id": "4d0024ee-4722-4b99-afad-3bba67388855", + "metadata": {}, + "source": [ + "Now, we are ready to add some labware to the deck. PyLabRobot has many different labware items already defined. Only import the ones that you need for your protocol. A full list of labware can be found in `PyLabRobot\\Resources\\opentrons`. You can also create custom labware, but that is out of scope for this tutorial.\n", + "\n", + "Let's begin by importing a `TubeRack`, a `TipRack`, and a `Plate`.\n", + "
\n", + " Definitions of Labware:\n", + " \n", + "* **TubeRack** = Used to hold various tubes, commonly the 2mL Eppendorfs.\n", + "\n", + "* **TipRack** = Labware that holds pipette tips.\n", + "\n", + "* **Plate** = Well-Plate that one can add liquids to.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "71889711-e068-4e7e-b158-128a9491a1a0", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap,\n", + " opentrons_96_tiprack_300ul,\n", + " corning_96_wellplate_360ul_flat\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fae79fcb-7dbb-4145-a03a-eef0da7d6e38", + "metadata": {}, + "source": [ + "**Note:** The OT2 has **11 spots** for labware. It also has a built in trash can for discarding tips.\n", + "\n", + "One thing to keep in mind when designing a protocol is `layout efficiency`. The more separated labware is on the deck, the longer your protocol will be because the pipette has to travel farther.\n", + "\n", + "In general, you want to keep your tip racks in the back, your stocks in the middle, and then finally your plates in the front. This allows for `linear movement`.\n", + "\n", + "For example, the arm grabs a **tip from slot 7**, aspirates **stock from slot 4**, and then finally **dispenses in slot 1**. Reducing the travel time of the pipette will decrease the runtime of your protocol.\n", + "\n", + "To place labware on the Deck, call `assign_child_at_slot()`. Pass in the labware you want to place along with the slot you want to place it in." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c4c43470-21ff-4b3f-9a36-cdc3c0d97403", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource tip_rack was assigned to the robot.\n" + ] + } + ], + "source": [ + "# When you instantiate a labware, give it a name that will show when you\n", + "# mouse over it in the visualizer.\n", + "tip_rack = opentrons_96_tiprack_300ul(\"tip_rack\")\n", + "\n", + "lh.deck.assign_child_at_slot(tip_rack, 7)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3740eb57-80bd-498b-95d5-725b9487c196", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource tube_rack was assigned to the robot.\n" + ] + } + ], + "source": [ + "# Stock Solution Tube Rack\n", + "tube_rack = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap(\"tube_rack\")\n", + "\n", + "lh.deck.assign_child_at_slot(tube_rack, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "fd6a17ea-b41e-4033-a914-81b2d87635b9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource prep_plate was assigned to the robot.\n" + ] + } + ], + "source": [ + "# Plate for Sample Preparation\n", + "plate = corning_96_wellplate_360ul_flat(\"prep_plate\")\n", + "\n", + "lh.deck.assign_child_at_slot(plate, 1)" + ] + }, + { + "cell_type": "markdown", + "id": "b7c49e37-543c-49b5-86f0-5c9df9bdd5a1", + "metadata": {}, + "source": [ + "### Adding Liquids to the Deck" + ] + }, + { + "cell_type": "markdown", + "id": "b757ebe8-be14-48af-bda6-f377a8769d0b", + "metadata": {}, + "source": [ + "Let's add some liquids to our `tube_rack`. We can add up to the `max_volume` of the tube. If you go over this number, PyLabRobot will throw an error. We shall add 1000µL of 4 different dyes to the first column of our `tube_rack`. This corresponds to wells *A1, B1, C1, and D1*.\n", + "\n", + "To iterate over locations on labware, we use the `traverse()` function. This produces a generator object that we use the `next` keyword on to yield our desired wells.\n", + "\n", + "`traverse()` takes in two arguments: **batch_size** is the amount of wells to return, and **direction** is how to iterate over the wells. In our case, we use `\"down\"` to return the wells column wise.\n", + "\n", + "
\n", + " More info on direction:\n", + "\n", + "* `\"down\"`, `\"snake_down\"`, `\"right\"`, and `\"snake_right\"` start at the top left item **(A1)**.\n", + " \n", + "* `\"up\"` and `\"snake_up\"` start at the bottom left **(H1)**.\n", + " \n", + "* `\"left\"` and `\"snake_left\"` start at the top right **(A12)**.\n", + "\n", + "* The `snake` directions alternate between going in the given direction and going in the opposite direction. For example, `\"snake_down\"` will go from A1 to H1, then H2 to A2, then A3 to H3, etc.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "aca186f8-922b-4226-89ef-e6cfe886b512", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=tube_rack_B1, location=(018.210, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=tube_rack_C1, location=(018.210, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=tube_rack_D1, location=(018.210, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "first_col_tubes = next(tube_rack.traverse(batch_size=4, direction='down'))\n", + "first_col_tubes" + ] + }, + { + "cell_type": "markdown", + "id": "88f4e079-81e1-441c-923c-63e2a8b1cfb7", + "metadata": {}, + "source": [ + "Use the `tracker.add_liquid()` function to put liquid in a `tube`. The `tracker` class contains all of the methods associated with keeping record of how much/what kind of liquid is in a given container.\n", + "\n", + "Pass in a string for **\"Liquid_Type\"** and a number for **Volume** to this function.\n", + "\n", + "Let's add our dyes to the tubes in `first_col_tubes`." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "876af18c-fdde-4a78-8261-b9a61c580988", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(len(first_col_tubes)):\n", + " \n", + " first_col_tubes[i].tracker.add_liquid(f\"Dye_{i}\", 1000)\n", + " \n", + " #Commit the change\n", + " first_col_tubes[i].tracker.commit()" + ] + }, + { + "cell_type": "markdown", + "id": "1e0137ea-bd0f-4a8f-9785-3b7aafe5c7dd", + "metadata": {}, + "source": [ + "Here's a Utility function for printing all of the filled spots of a `TubeRack`." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "ee999023-9b95-41b0-90c4-4e05bc65d629", + "metadata": {}, + "outputs": [], + "source": [ + "def print_filled_spots_of_tubeRack(tube_rack):\n", + "\n", + " all_tubes = tube_rack.get_all_children()\n", + "\n", + " all_empty = True\n", + " \n", + " for tube in all_tubes:\n", + " \n", + " liquid = tube.tracker.liquids\n", + "\n", + " if liquid != []:\n", + " print(f\"Spot {tube.name.split('_')[-1]} contains:\")\n", + "\n", + " name = liquid[0][0]\n", + " vol = liquid[0][1]\n", + " \n", + " print(f\"{vol}uL of {name}\")\n", + "\n", + " all_empty = False\n", + "\n", + " if all_empty:\n", + " print(\"Entire rack is empty!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "1832d167-395f-44fe-911b-1584b9a71281", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Spot A1 contains:\n", + "1000uL of Dye_0\n", + "Spot B1 contains:\n", + "1000uL of Dye_1\n", + "Spot C1 contains:\n", + "1000uL of Dye_2\n", + "Spot D1 contains:\n", + "1000uL of Dye_3\n" + ] + } + ], + "source": [ + "print_filled_spots_of_tubeRack(tube_rack)" + ] + }, + { + "cell_type": "markdown", + "id": "ffceed8a-b9c4-4824-85e4-2676957811f6", + "metadata": {}, + "source": [ + "### Moving Liquids from Point A to Point B" + ] + }, + { + "cell_type": "markdown", + "id": "622baa5b-0e60-47cb-aa03-aeb3982d3519", + "metadata": {}, + "source": [ + "Why is it not updating the contents of the tubes correctly?? The animations are also broken now." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "d93e6576-a5d8-43fe-b8aa-3c48b4514a0d", + "metadata": {}, + "outputs": [], + "source": [ + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "0e85d828-b3f5-4ad2-9e87-56ccd985720f", + "metadata": {}, + "outputs": [ + { + "ename": "RuntimeError", + "evalue": "No tips have been picked up.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_6667/2886996634.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mawait\u001b[0m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreturn_tips\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/liquid_handling/liquid_handler.py\u001b[0m in \u001b[0;36mreturn_tips\u001b[0;34m(self, use_channels, **backend_kwargs)\u001b[0m\n\u001b[1;32m 557\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 558\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 559\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"No tips have been picked up.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 560\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 561\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdrop_tips\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0muse_channels\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mchannels\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mbackend_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mRuntimeError\u001b[0m: No tips have been picked up." + ] + } + ], + "source": [ + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "5f55c2d7-6e9c-4190-a1d7-ef65e7a93915", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Aspirating [Aspiration(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", + "Dispensing [Dispense(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack[\"A1\"])\n", + "time.sleep(2)\n", + "\n", + "await lh.aspirate(tube_rack[\"A1\"], vols=[100])\n", + "tube_rack[\"A1\"][0].tracker.commit()\n", + "time.sleep(2)\n", + "\n", + "await lh.dispense(plate[\"A1\"], vols=[100])\n", + "plate[\"A1\"][0].tracker.commit()\n", + "time.sleep(2)\n", + "\n", + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "e402336b-ff23-4205-81ee-d16e967ad017", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tube_rack[\"A1\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "e51ed207-74e3-4ad1-9aa4-7a79ece40016", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Spot A1 contains:\n", + "1000uL of Dye_0\n", + "Spot B1 contains:\n", + "1000uL of Dye_1\n", + "Spot C1 contains:\n", + "1000uL of Dye_2\n", + "Spot D1 contains:\n", + "1000uL of Dye_3\n" + ] + } + ], + "source": [ + "print_filled_spots_of_tubeRack(tube_rack)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "f64ffbc0-7d55-4f43-9083-4ecd147c5193", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('Dye_0', 1000)]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tube_rack[0][0].tracker.liquids" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ac2d2e3-dfb0-4d5f-8aee-8769cfd804f1", + "metadata": {}, + "outputs": [], + "source": [ + "await lh.pick_up_tips(tip_rack[\"A1\"])\n", + "time.sleep(1)\n", + "\n", + "await lh.aspirate(plate[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.dispense(tube_rack[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.return_tips()" + ] + }, + { + "cell_type": "markdown", + "id": "29adc390-9c6f-49c5-9112-5cdb7ce7b7a1", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "### For future reference, how to export states of labware as .json files" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "22fab8bb-af21-4f79-982e-ca46a11df867", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "' Save the state of this resource and all children to a JSON file.\\n\\n Args:\\n fn: File name. Caution: file will be overwritten.\\n indent: Same as `json.dump`\\'s `indent` argument (for json pretty printing).\\n\\n Examples:\\n Saving to a json file:\\n\\n >>> deck.save_state_to_file(\"my_state.json\")\\n'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\" Save the state of this resource and all children to a JSON file.\n", + "\n", + " Args:\n", + " fn: File name. Caution: file will be overwritten.\n", + " indent: Same as `json.dump`'s `indent` argument (for json pretty printing).\n", + "\n", + " Examples:\n", + " Saving to a json file:\n", + "\n", + " >>> deck.save_state_to_file(\"my_state.json\")\n", + "\"\"\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9d2169c-1e13-4abd-8095-6844b856d84e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Decks/pylabrobot-20240514.log b/Decks/pylabrobot-20240514.log new file mode 100644 index 0000000..e69de29 diff --git a/Decks/pylabrobot-20240515.log b/Decks/pylabrobot-20240515.log new file mode 100644 index 0000000..e69de29 diff --git a/Equipment/Introduction_to_Equipment.ipynb b/Equipment/Introduction_to_Equipment.ipynb index 61a4782..1c6ae91 100644 --- a/Equipment/Introduction_to_Equipment.ipynb +++ b/Equipment/Introduction_to_Equipment.ipynb @@ -1,144 +1,144 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", - "metadata": {}, - "source": [ - "**Welcome to PyLabRobot!**\n", - "\n", - "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", - "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", - "\n", - "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", - "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", - "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", - "be translatable across many different machines.\n", - "\n", - "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", - "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", - "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", - "the most widely used liquid handling robots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.liquid_handling import LiquidHandler\n", - "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", - "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b372972-d6dc-454b-95eb-d9941405621b", - "metadata": {}, - "outputs": [], - "source": [ - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", - "await lh.setup()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0324171c-101d-4b3d-9103-a0137c620174", - "metadata": {}, - "outputs": [], - "source": [ - "vis = Visualizer(resource=lh)\n", - "await vis.setup()" - ] - }, - { - "cell_type": "markdown", - "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", - "metadata": {}, - "source": [ - "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.resources import (\n", - " TIP_CAR_480_A00,\n", - " PLT_CAR_L5AC_A00,\n", - " Cos_96_DW_1mL,\n", - " HTF_L\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", - "metadata": {}, - "outputs": [], - "source": [ - "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", - "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", - "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", - "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", - "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", - "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", - "lh.deck.assign_child_resource(tip_car, rails=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": {}, - "outputs": [], - "source": [ - "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", - "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", - "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", - "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", - "lh.deck.assign_child_resource(plt_car, rails=8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", - "metadata": {}, - "outputs": [], - "source": [ - "await vis.stop()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", + "metadata": {}, + "source": [ + "**Welcome to PyLabRobot!**\n", + "\n", + "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", + "\n", + "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", + "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", + "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", + "be translatable across many different machines.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", + "the most widely used liquid handling robots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.hamilton import STARLetDeck\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b372972-d6dc-454b-95eb-d9941405621b", + "metadata": {}, + "outputs": [], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "await lh.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0324171c-101d-4b3d-9103-a0137c620174", + "metadata": {}, + "outputs": [], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", + "metadata": {}, + "source": [ + "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " TIP_CAR_480_A00,\n", + " PLT_CAR_L5AC_A00,\n", + " Cos_96_DW_1mL,\n", + " HTF_L\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", + "metadata": {}, + "outputs": [], + "source": [ + "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", + "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", + "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", + "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", + "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", + "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", + "lh.deck.assign_child_resource(tip_car, rails=15)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", + "metadata": {}, + "outputs": [], + "source": [ + "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", + "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", + "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", + "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", + "lh.deck.assign_child_resource(plt_car, rails=8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", + "metadata": {}, + "outputs": [], + "source": [ + "await vis.stop()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Introduction_to_PyLabRobot.ipynb b/Introduction_to_PyLabRobot.ipynb index 53e920e..2aecb70 100644 --- a/Introduction_to_PyLabRobot.ipynb +++ b/Introduction_to_PyLabRobot.ipynb @@ -5,12 +5,12 @@ "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", "metadata": {}, "source": [ - "**Welcome to PyLabRobot!**\n", + "# **Welcome to PyLabRobot!**\n", "\n", - "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "PyLabRobot *(PLR)* is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", "\n", - "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", + "PLR defines a universal interface class called **LiquidHandler** that provides generic methods for controlling robots\n", "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", "be translatable across many different machines.\n", @@ -21,9 +21,17 @@ "the most widely used liquid handling robots." ] }, + { + "cell_type": "markdown", + "id": "9268a564-0e57-4ace-9b22-68fcffbfcc2f", + "metadata": {}, + "source": [ + "### Imports" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", "metadata": {}, "outputs": [], @@ -31,31 +39,126 @@ "from pylabrobot.liquid_handling import LiquidHandler\n", "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n" + "from pylabrobot.resources.hamilton import STARLetDeck\n", + "from pylabrobot.resources.opentrons import OTDeck\n", + "\n", + "from pylabrobot.resources.opentrons.load import *\n", + "from pylabrobot.resources.opentrons.plates import *\n", + "\n", + "import opentrons" + ] + }, + { + "cell_type": "markdown", + "id": "3c611cf0-ac3f-4e4d-8f48-b9d2241f5670", + "metadata": {}, + "source": [ + "### Liquid Handler: High level abstraction, thing that takes in aspirate and dispense commands, abstract wrapper for all robot backends\n", + "Give input backend, what robot you are planning to use, PLR is hardware agnostic, you use the abstract liquid handler scaffold and then pass in \n", + "the details of your specific robot\n", + "### Deck: What deck is your robot using, again it is hardware agnostic.\n", + "\n", + "* Restart kernel is your friend when working with PLR" + ] + }, + { + "cell_type": "markdown", + "id": "213a4b8c-098e-4e0e-bb9f-446ba5b1709a", + "metadata": {}, + "source": [ + "## Deck Set-Up" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "8b372972-d6dc-454b-95eb-d9941405621b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting up the robot.\n", + "Resource deck was assigned to the robot.\n", + "Resource trash_container was assigned to the robot.\n" + ] + } + ], "source": [ - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "# Call setup to instantiate your specific instance of the robot\n", + "\n", + "# Hamilton\n", + "#lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "\n", + "# OpenTrons\n", + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=OTDeck())\n", + "\n", + "# Use await because setup can take many minutes. Use await when you have a long function call that you\n", + "# want to be able to do other things while its happening\n", "await lh.setup()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "0324171c-101d-4b3d-9103-a0137c620174", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Websocket server started at http://127.0.0.1:2121\n", + "File server started at http://127.0.0.1:1337 . Open this URL in your browser.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "----------------------------------------\n", + "Exception occurred during processing of request from ('127.0.0.1', 40734)\n", + "Traceback (most recent call last):\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 316, in _handle_request_noblock\n", + " self.process_request(request, client_address)\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 347, in process_request\n", + " self.finish_request(request, client_address)\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 360, in finish_request\n", + " self.RequestHandlerClass(request, client_address, self)\n", + " File \"/mnt/d/Chory Lab/PyLabRobot/pylabrobot/visualizer/visualizer.py\", line 322, in __init__\n", + " super().__init__(*args, directory=path, **kwargs)\n", + " File \"/usr/lib/python3.10/http/server.py\", line 651, in __init__\n", + " super().__init__(*args, **kwargs)\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 747, in __init__\n", + " self.handle()\n", + " File \"/usr/lib/python3.10/http/server.py\", line 425, in handle\n", + " self.handle_one_request()\n", + " File \"/usr/lib/python3.10/http/server.py\", line 413, in handle_one_request\n", + " method()\n", + " File \"/mnt/d/Chory Lab/PyLabRobot/pylabrobot/visualizer/visualizer.py\", line 343, in do_GET\n", + " self.wfile.write(content.encode(\"utf-8\"))\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 826, in write\n", + " self._sock.sendall(b)\n", + "BrokenPipeError: [Errno 32] Broken pipe\n", + "----------------------------------------\n" + ] + } + ], "source": [ + "# If you want to follow along in real time, instantiate the protocol visualizer\n", "vis = Visualizer(resource=lh)\n", "await vis.setup()" ] }, + { + "cell_type": "markdown", + "id": "42bf486e-b8cb-4918-a2e6-a9955e71c46b", + "metadata": {}, + "source": [ + "### Put some labware on the deck!" + ] + }, { "cell_type": "markdown", "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", @@ -66,7 +169,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", "metadata": {}, "outputs": [], @@ -75,17 +178,40 @@ " TIP_CAR_480_A00,\n", " PLT_CAR_L5AC_A00,\n", " Cos_96_DW_1mL,\n", - " HTF_L\n", + " HTF_L,\n", + " opentrons_96_tiprack_300ul,\n", + " opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap\n", ")\n" ] }, + { + "cell_type": "markdown", + "id": "8cf826da-7d57-49ce-8303-d40501f50e2b", + "metadata": {}, + "source": [ + "### Hamilton Tip Racks" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "TypeError", + "evalue": "OTDeck.assign_child_resource() got an unexpected keyword argument 'rails'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_582/3930452725.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mtip_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtip_rack4\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHTF_L\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'tips_04'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwith_tips\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mtip_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtip_rack5\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHTF_L\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'tips_05'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwith_tips\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeck\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massign_child_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_car\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrails\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m15\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: OTDeck.assign_child_resource() got an unexpected keyword argument 'rails'" + ] + } + ], "source": [ + "# Hamilton Tips\n", "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", @@ -97,10 +223,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": {}, - "outputs": [], + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Resource with name 'plate carrier' already defined.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_200/3931165138.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mplt_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplate_2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCos_96_DW_1mL\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'plate_02'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mplt_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplate_3\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCos_96_DW_1mL\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'plate_03'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeck\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massign_child_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplt_car\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrails\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m8\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/resources/hamilton/hamilton_decks.py\u001b[0m in \u001b[0;36massign_child_resource\u001b[0;34m(self, resource, location, reassign, rails, replace)\u001b[0m\n\u001b[1;32m 113\u001b[0m \u001b[0mcast\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mResource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresource\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munassign\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 115\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Resource with name '{resource.name}' already defined.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 116\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mrails\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Resource with name 'plate carrier' already defined." + ] + } + ], "source": [ "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", @@ -111,17 +252,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "4421b04c-d894-4aaa-a9f4-7f51a16dc773", "metadata": {}, "outputs": [], "source": [ - "tip_rack1.fill()\n" + "tip_rack_1.fill()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "74928e32-3910-434c-b0af-5bdc9c03a51e", "metadata": {}, "outputs": [], @@ -132,130 +273,651 @@ "tip_rack2.set_tip_state([[True, True, False, False]*3]*8)\n" ] }, + { + "cell_type": "markdown", + "id": "2d2fba32-6be8-4248-88b2-ab74fb2047af", + "metadata": {}, + "source": [ + "### OpenTrons Tip Racks" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, + "id": "28b14d77-7cc3-4721-9f10-0867d9137a38", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource tip_rack_1 was assigned to the robot.\n", + "Resource tip_rack_2 was assigned to the robot.\n" + ] + } + ], + "source": [ + "# OT2 Tips\n", + "\n", + "tip_rack_1 = opentrons_96_tiprack_300ul(\"tip_rack_1\")\n", + "tip_rack_2 = opentrons_96_tiprack_300ul(\"tip_rack_2\")\n", + "\n", + "lh.deck.assign_child_at_slot(tip_rack_1, 7)\n", + "lh.deck.assign_child_at_slot(tip_rack_2, 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7d16498c-5b03-4454-a197-dc1faf8a3a6f", + "metadata": {}, + "outputs": [], + "source": [ + "tip_rack2 = lh.deck.get_resource(\"tip_rack_2\")\n", + "tip_rack2.set_tip_state([[True]*6 + [False]*6]*8)" + ] + }, + { + "cell_type": "markdown", + "id": "a06b3c22-5498-43dd-8e1e-ae0203c24f23", + "metadata": {}, + "source": [ + "### OpenTrons Plates" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "16547556-5fd6-4af8-a37b-dd6a1d209981", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource plate_1 was assigned to the robot.\n", + "Resource plate_2 was assigned to the robot.\n" + ] + } + ], + "source": [ + "plate_1 = corning_96_wellplate_360ul_flat('plate_1')\n", + "plate_2 = corning_96_wellplate_360ul_flat('plate_2')\n", + "\n", + "lh.deck.assign_child_at_slot(plate_1, 1)\n", + "lh.deck.assign_child_at_slot(plate_2, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 101, "id": "534179d6-96aa-419f-832e-dbf6b19de0fa", "metadata": {}, "outputs": [], "source": [ - "plate_1_liquids = [[(None, 500)]]*96\n", + "plate_1_liquids = [[('water', 200)]]*96\n", "plate_1.set_well_liquids(plate_1_liquids)\n", - "plate_2_liquids = [[(None, 100)], [(None, 500)]]*(96//2)\n", + "plate_2_liquids = [[(None, 100)], [(None, 100)]]*(96//2)\n", "plate_2.set_well_liquids(plate_2_liquids)\n" ] }, + { + "cell_type": "markdown", + "id": "fa620baf-955e-4671-b86c-8288545c599b", + "metadata": {}, + "source": [ + "### OpenTrons Tube Racks" + ] + }, { "cell_type": "code", - "execution_count": null, - "id": "21e6aa85-cbe1-4c8e-bbe7-1e33eaccdc20", + "execution_count": 17, + "id": "aa3468cd-f660-4c2b-8568-ed3160172174", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource rack_1 was assigned to the robot.\n", + "Resource rack_2 was assigned to the robot.\n" + ] + } + ], + "source": [ + "rack_1 = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap('rack_1')\n", + "rack_2 = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap('rack_2')\n", + "\n", + "lh.deck.assign_child_at_slot(rack_1, 4)\n", + "lh.deck.assign_child_at_slot(rack_2, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b65570bc-1589-43ec-9aa1-ece9c50187cd", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'TubeRack' object has no attribute 'set_liquids'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_962/3721324440.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mrack_1_liquids\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'water'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m200\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mrack_1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_liquids\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplate_1_liquids\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'TubeRack' object has no attribute 'set_liquids'" + ] + } + ], + "source": [ + "rack_1_liquids = [[('water', 200)]]*6\n", + "rack_1.set_liquids(plate_1_liquids)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 144, + "id": "02e18147-5337-4c75-9fd4-4243499d3108", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[Tube(name=rack_1_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B1, location=(018.210, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C1, location=(018.210, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D1, location=(018.210, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A2, location=(038.100, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B2, location=(038.100, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C2, location=(038.100, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D2, location=(038.100, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A3, location=(057.990, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B3, location=(057.990, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C3, location=(057.990, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D3, location=(057.990, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A4, location=(077.880, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B4, location=(077.880, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C4, location=(077.880, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D4, location=(077.880, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A5, location=(097.770, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B5, location=(097.770, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C5, location=(097.770, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D5, location=(097.770, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A6, location=(117.660, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B6, location=(117.660, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C6, location=(117.660, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D6, location=(117.660, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" + ] + }, + "execution_count": 144, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rack_1.get_all_children()" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "id": "23cb1bc9-cb4f-4d70-b0f7-7727a2586561", "metadata": {}, "outputs": [], "source": [ - "from pylabrobot.resources import set_tip_tracking, set_volume_tracking\n", - "set_tip_tracking(True), set_volume_tracking(True)\n" + "rack_1.enable_volume_trackers()" ] }, { "cell_type": "code", - "execution_count": null, - "id": "7eda3c13-e750-4823-8327-5e5baba6ac2d", + "execution_count": 125, + "id": "a467ab96-e1cb-4932-9e47-731831f29148", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['__class__',\n", + " '__delattr__',\n", + " '__dict__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__init_subclass__',\n", + " '__le__',\n", + " '__lt__',\n", + " '__module__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " '__weakref__',\n", + " '_call_did_assign_resource_callbacks',\n", + " '_call_did_unassign_resource_callbacks',\n", + " '_call_will_assign_resource_callbacks',\n", + " '_call_will_unassign_resource_callbacks',\n", + " '_check_assignment',\n", + " '_did_assign_resource_callbacks',\n", + " '_did_unassign_resource_callbacks',\n", + " '_name',\n", + " '_resource_state_updated_callbacks',\n", + " '_size_x',\n", + " '_size_y',\n", + " '_size_z',\n", + " '_state_updated',\n", + " '_will_assign_resource_callbacks',\n", + " '_will_unassign_resource_callbacks',\n", + " 'assign_child_resource',\n", + " 'category',\n", + " 'center',\n", + " 'centers',\n", + " 'children',\n", + " 'copy',\n", + " 'deregister_did_assign_resource_callback',\n", + " 'deregister_did_unassign_resource_callback',\n", + " 'deregister_state_update_callback',\n", + " 'deregister_will_assign_resource_callback',\n", + " 'deregister_will_unassign_resource_callback',\n", + " 'deserialize',\n", + " 'get_absolute_location',\n", + " 'get_all_children',\n", + " 'get_resource',\n", + " 'get_size_x',\n", + " 'get_size_y',\n", + " 'get_size_z',\n", + " 'load_all_state',\n", + " 'load_from_json_file',\n", + " 'load_state',\n", + " 'load_state_from_file',\n", + " 'location',\n", + " 'max_volume',\n", + " 'model',\n", + " 'name',\n", + " 'parent',\n", + " 'register_did_assign_resource_callback',\n", + " 'register_did_unassign_resource_callback',\n", + " 'register_state_update_callback',\n", + " 'register_will_assign_resource_callback',\n", + " 'register_will_unassign_resource_callback',\n", + " 'rotate',\n", + " 'rotated',\n", + " 'rotation',\n", + " 'save',\n", + " 'save_state_to_file',\n", + " 'serialize',\n", + " 'serialize_all_state',\n", + " 'serialize_state',\n", + " 'tracker',\n", + " 'unassign',\n", + " 'unassign_child_resource']" + ] + }, + "execution_count": 125, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dir(rack_1['A1'][0])" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "4354a042-96d4-4e93-916e-1cc2a25f2c1e", "metadata": {}, "outputs": [], "source": [ - "await lh.pick_up_tips(tip_rack1[\"A1\", \"B2\", \"C3\", \"D4\"])\n", - "await lh.drop_tips(tip_rack1[\"A1\", \"B2\", \"C3\", \"D4\"])\n" + "tube1 = rack_1[0][0]" ] }, { "cell_type": "code", - "execution_count": null, - "id": "8ca125a2-0fbd-4b1d-850b-29078dc48d9a", + "execution_count": 138, + "id": "8e5166dd-23a4-4d5b-b869-5fd4ca167f77", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "tube1.tracker.set_liquids([(None, 0)])" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "id": "0a1fd4b0-7089-43be-bfde-de3b43d2b44b", "metadata": {}, "outputs": [], "source": [ - "await lh.pick_up_tips96(tip_rack1)\n" + "tube1.tracker.add_liquid(None, 2000)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "464f5dd7-8d85-407b-b4d6-693340f90c5e", + "execution_count": 141, + "id": "cdbb78b9-39d4-4036-924a-a358d8c8c9a8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(None, 2000)]" + ] + }, + "execution_count": 141, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tube1.tracker.liquids" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "bebe9703-f00c-4975-9620-5eb3d0416001", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Aspirating [Aspiration(resource=Tube(name=rack_1_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Water', 100)])].\n", + "Dispensing [Dispense(resource=Well(name=plate_2_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Water', 100)])].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack_1[\"A1\"])\n", + "time.sleep(1)\n", + "\n", + "await lh.aspirate(rack_1[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.dispense(plate_2[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "62fe14fa-2c25-413a-a982-db510f6d8c0b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "ace711fd-1823-4056-b408-7f2f24be5338", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'list' object has no attribute 'add_liquid'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_962/68121547.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrack_1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_liquid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'water'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m200\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'list' object has no attribute 'add_liquid'" + ] + } + ], + "source": [ + "rack_1.get[0].add_liquid([('water', 200)])" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "21e6aa85-cbe1-4c8e-bbe7-1e33eaccdc20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(None, None)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pylabrobot.resources import set_tip_tracking, set_volume_tracking\n", + "set_tip_tracking(True), set_volume_tracking(True)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8055306d-042d-4d83-a685-139a221d8665", "metadata": {}, "outputs": [], "source": [ - "await lh.pick_up_tips(tip_rack1[\"A1\"])\n" + "import time" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, + "id": "7eda3c13-e750-4823-8327-5e5baba6ac2d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack_1[\"A1\", \"B2\", \"C3\", \"D4\"])\n", + "time.sleep(2)\n", + "await lh.drop_tips(tip_rack_1[\"A1\", \"B2\", \"C3\", \"D4\"])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "464f5dd7-8d85-407b-b4d6-693340f90c5e", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack_1[\"A1\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 14, "id": "1e4c9bb2-58e9-4c4d-a9d4-fa65db824f20", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aspirating [Aspiration(resource=Well(name=plate_1_A2, location=(023.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('water', 100)])].\n" + ] + } + ], "source": [ - "await lh.aspirate(plate_1[\"A2\"], vols=[300])\n" + "await lh.aspirate(plate_1[\"A2\"], vols=[100])" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "ce90182d-607b-4e93-bc9a-1d7dfef80e66", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dispensing [Dispense(resource=Well(name=plate_2_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('water', 100)])].\n" + ] + } + ], "source": [ - "await lh.dispense(plate_2[\"A1\"], vols=[300])\n" + "await lh.dispense(plate_2[\"A1\"], vols=[100])" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "711f3290-e36d-4ae9-88a3-80374709cc36", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], "source": [ - "await lh.return_tips()\n" + "await lh.return_tips()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "eb52fd76-d92a-43b3-8550-e688eed4c587", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips from tip_rack_1.\n" + ] + } + ], "source": [ - "await lh.pick_up_tips96(tip_rack1)\n" + "await lh.pick_up_tips96(tip_rack_1)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, + "id": "c9cbce02-0f7e-4e51-94e7-2635002d757b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aspirating 100 from Plate(name=plate_1, size_x=127.76, size_y=85.47, size_z=14.22, location=(000.000, 000.000, 000.000)).\n" + ] + } + ], + "source": [ + "await lh.aspirate96(plate_1, volume=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, "id": "ca18de2b-92f4-43c8-a0e7-dab9aa51ec38", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dispensing 100 to Plate(name=plate_2, size_x=127.76, size_y=85.47, size_z=14.22, location=(132.500, 000.000, 000.000)).\n" + ] + } + ], "source": [ - "await lh.dispense96(plate_3, volume=100)\n" + "await lh.dispense96(plate_2, volume=100)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "12ef3847-c203-4332-84bd-6631dd90aea5", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips to tip_rack_1.\n" + ] + } + ], "source": [ - "await lh.drop_tips96(tip_rack1)\n" + "await lh.drop_tips96(tip_rack_1)\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", "metadata": {}, "outputs": [], "source": [ "await vis.stop()\n" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8525dc3-7866-4b4d-b870-8c64313bba28", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -274,7 +936,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.10.4" } }, "nbformat": 4, diff --git a/Notes from Stefan b/Notes from Stefan new file mode 100644 index 0000000..f33716c --- /dev/null +++ b/Notes from Stefan @@ -0,0 +1,9 @@ +# Notes from Stefan + +This file serves as a journal/ written log of the different topics discussed as we construct the BME 590 class. + +Joe Laforet Jr. + +## 5/13/24 Day 1: Rough Outline + +* Stefan already made a github repo and a basic tutorial where students can get PyLabRobot set up on their machines. The exercise involves setting up a deck layout, adding in some liquids to the deck, and moving liquids from one place to another. I am going to reproduce this protocol using the OpenTrons platform, and then pretty up the tutorial. This will be either lab 1 or lab 0. diff --git a/Protocols/Introduction_to_Protocols.ipynb b/Protocols/Introduction_to_Protocols.ipynb index 61a4782..1c6ae91 100644 --- a/Protocols/Introduction_to_Protocols.ipynb +++ b/Protocols/Introduction_to_Protocols.ipynb @@ -1,144 +1,144 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", - "metadata": {}, - "source": [ - "**Welcome to PyLabRobot!**\n", - "\n", - "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", - "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", - "\n", - "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", - "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", - "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", - "be translatable across many different machines.\n", - "\n", - "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", - "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", - "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", - "the most widely used liquid handling robots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.liquid_handling import LiquidHandler\n", - "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", - "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b372972-d6dc-454b-95eb-d9941405621b", - "metadata": {}, - "outputs": [], - "source": [ - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", - "await lh.setup()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0324171c-101d-4b3d-9103-a0137c620174", - "metadata": {}, - "outputs": [], - "source": [ - "vis = Visualizer(resource=lh)\n", - "await vis.setup()" - ] - }, - { - "cell_type": "markdown", - "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", - "metadata": {}, - "source": [ - "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.resources import (\n", - " TIP_CAR_480_A00,\n", - " PLT_CAR_L5AC_A00,\n", - " Cos_96_DW_1mL,\n", - " HTF_L\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", - "metadata": {}, - "outputs": [], - "source": [ - "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", - "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", - "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", - "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", - "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", - "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", - "lh.deck.assign_child_resource(tip_car, rails=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": {}, - "outputs": [], - "source": [ - "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", - "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", - "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", - "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", - "lh.deck.assign_child_resource(plt_car, rails=8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", - "metadata": {}, - "outputs": [], - "source": [ - "await vis.stop()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", + "metadata": {}, + "source": [ + "**Welcome to PyLabRobot!**\n", + "\n", + "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", + "\n", + "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", + "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", + "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", + "be translatable across many different machines.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", + "the most widely used liquid handling robots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.hamilton import STARLetDeck\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b372972-d6dc-454b-95eb-d9941405621b", + "metadata": {}, + "outputs": [], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "await lh.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0324171c-101d-4b3d-9103-a0137c620174", + "metadata": {}, + "outputs": [], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", + "metadata": {}, + "source": [ + "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " TIP_CAR_480_A00,\n", + " PLT_CAR_L5AC_A00,\n", + " Cos_96_DW_1mL,\n", + " HTF_L\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", + "metadata": {}, + "outputs": [], + "source": [ + "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", + "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", + "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", + "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", + "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", + "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", + "lh.deck.assign_child_resource(tip_car, rails=15)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", + "metadata": {}, + "outputs": [], + "source": [ + "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", + "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", + "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", + "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", + "lh.deck.assign_child_resource(plt_car, rails=8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", + "metadata": {}, + "outputs": [], + "source": [ + "await vis.stop()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/README.md b/README.md index 083a66a..de1b2f8 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,37 @@ -# PyLabRobot Tutorials BME590 - -## Installation - -[Install Python](https://www.python.org/downloads/release/python-3110/)
-[Install Git](https://git-scm.com/downloads)
- - -From the terminal:
-`pip install pylabrobot[extras_visualizer]`
-`pip install websockets`
-`pip install jupyterlab`
-`git clone https://github.com/stefangolas/PyLabRobot_Tutorials_BME590.git`
-`cd PyLabRobot_Tutorials_BME590`
-`jupyter lab`
- -### Installation notes - -* It's possible you already have a version of some of the dependencies that get installed alongside. If you are worried about conflicts with existing packages, you can use a virtual environment. [How to Use Python Virtual Environments](https://realpython.com/python-virtual-environments-a-primer/). - -* You can use standard Jupyter Notebooks, but Jupyter Lab has a file system feature that is very convenient for navigating the repository. - -* If you get an error that says `pip not recognized` on Windows, you just have to add your Python installation path to your environment variables. [Stack Overflow: pip is not recognized as an internal or external command](https://stackoverflow.com/questions/23708898/pip-is-not-recognized-as-an-internal-or-external-command). - -* If you want to try changing the PLR source code, you can run the following from the terminal:
-`git clone https://github.com/PyLabRobot/pylabrobot.git`
-`cd pylabrobot`
-`pip install -e .[extras_visualizer]`
- -This will install PyLabRobot in such a way that if you change the source code you just cloned, those changes will be reflected in your working version of the library when you import it into Python. This means that you can break your own installation of PLR, but you can always re-clone from the main repo to start over. - -## Notebook - The last command should have opened the Jupyter Lab notebook shown below. This is an example script that gives an overview of PyLabRobot's capabilities. - There are other scripts that delve into specific topics such as `DataSimulations` that you can access from the same directory. Feel free to change the scripts - to get a sense of what PyLabRobot can do. - - ![image](Readme_Images/screenshot.png) +# PyLabRobot Tutorials BME590 + +## Installation + +[Install Python](https://www.python.org/downloads/release/python-3110/)
+[Install Git](https://git-scm.com/downloads)
+ + +From the terminal:
+`pip install pylabrobot[extras_visualizer]`
+`pip install websockets`
+`pip install jupyterlab`
+`git clone https://github.com/stefangolas/PyLabRobot_Tutorials_BME590.git`
+`cd PyLabRobot_Tutorials_BME590`
+`jupyter lab`
+ +### Installation notes + +* It's possible you already have a version of some of the dependencies that get installed alongside. If you are worried about conflicts with existing packages, you can use a virtual environment. [How to Use Python Virtual Environments](https://realpython.com/python-virtual-environments-a-primer/). + +* You can use standard Jupyter Notebooks, but Jupyter Lab has a file system feature that is very convenient for navigating the repository. + +* If you get an error that says `pip not recognized` on Windows, you just have to add your Python installation path to your environment variables. [Stack Overflow: pip is not recognized as an internal or external command](https://stackoverflow.com/questions/23708898/pip-is-not-recognized-as-an-internal-or-external-command). + +* If you want to try changing the PLR source code, you can run the following from the terminal:
+`git clone https://github.com/PyLabRobot/pylabrobot.git`
+`cd pylabrobot`
+`pip install -e .[extras_visualizer]`
+ +This will install PyLabRobot in such a way that if you change the source code you just cloned, those changes will be reflected in your working version of the library when you import it into Python. This means that you can break your own installation of PLR, but you can always re-clone from the main repo to start over. + +## Notebook + The last command should have opened the Jupyter Lab notebook shown below. This is an example script that gives an overview of PyLabRobot's capabilities. + There are other scripts that delve into specific topics such as `DataSimulations` that you can access from the same directory. Feel free to change the scripts + to get a sense of what PyLabRobot can do. + + ![image](Readme_Images/screenshot.png) diff --git a/SystemsIntegrations/Introduction_to_SystemsIntegrations.ipynb b/SystemsIntegrations/Introduction_to_SystemsIntegrations.ipynb index 61a4782..1c6ae91 100644 --- a/SystemsIntegrations/Introduction_to_SystemsIntegrations.ipynb +++ b/SystemsIntegrations/Introduction_to_SystemsIntegrations.ipynb @@ -1,144 +1,144 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", - "metadata": {}, - "source": [ - "**Welcome to PyLabRobot!**\n", - "\n", - "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", - "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", - "\n", - "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", - "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", - "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", - "be translatable across many different machines.\n", - "\n", - "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", - "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", - "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", - "the most widely used liquid handling robots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.liquid_handling import LiquidHandler\n", - "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", - "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b372972-d6dc-454b-95eb-d9941405621b", - "metadata": {}, - "outputs": [], - "source": [ - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", - "await lh.setup()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0324171c-101d-4b3d-9103-a0137c620174", - "metadata": {}, - "outputs": [], - "source": [ - "vis = Visualizer(resource=lh)\n", - "await vis.setup()" - ] - }, - { - "cell_type": "markdown", - "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", - "metadata": {}, - "source": [ - "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.resources import (\n", - " TIP_CAR_480_A00,\n", - " PLT_CAR_L5AC_A00,\n", - " Cos_96_DW_1mL,\n", - " HTF_L\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", - "metadata": {}, - "outputs": [], - "source": [ - "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", - "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", - "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", - "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", - "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", - "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", - "lh.deck.assign_child_resource(tip_car, rails=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": {}, - "outputs": [], - "source": [ - "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", - "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", - "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", - "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", - "lh.deck.assign_child_resource(plt_car, rails=8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", - "metadata": {}, - "outputs": [], - "source": [ - "await vis.stop()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", + "metadata": {}, + "source": [ + "**Welcome to PyLabRobot!**\n", + "\n", + "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", + "\n", + "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", + "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", + "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", + "be translatable across many different machines.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", + "the most widely used liquid handling robots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.hamilton import STARLetDeck\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b372972-d6dc-454b-95eb-d9941405621b", + "metadata": {}, + "outputs": [], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "await lh.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0324171c-101d-4b3d-9103-a0137c620174", + "metadata": {}, + "outputs": [], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", + "metadata": {}, + "source": [ + "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " TIP_CAR_480_A00,\n", + " PLT_CAR_L5AC_A00,\n", + " Cos_96_DW_1mL,\n", + " HTF_L\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", + "metadata": {}, + "outputs": [], + "source": [ + "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", + "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", + "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", + "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", + "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", + "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", + "lh.deck.assign_child_resource(tip_car, rails=15)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", + "metadata": {}, + "outputs": [], + "source": [ + "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", + "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", + "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", + "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", + "lh.deck.assign_child_resource(plt_car, rails=8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", + "metadata": {}, + "outputs": [], + "source": [ + "await vis.stop()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Worklists/Introduction_to_Worklists.ipynb b/Worklists/Introduction_to_Worklists.ipynb index 61a4782..1c6ae91 100644 --- a/Worklists/Introduction_to_Worklists.ipynb +++ b/Worklists/Introduction_to_Worklists.ipynb @@ -1,144 +1,144 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", - "metadata": {}, - "source": [ - "**Welcome to PyLabRobot!**\n", - "\n", - "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", - "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", - "\n", - "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", - "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", - "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", - "be translatable across many different machines.\n", - "\n", - "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", - "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", - "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", - "the most widely used liquid handling robots." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.liquid_handling import LiquidHandler\n", - "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", - "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b372972-d6dc-454b-95eb-d9941405621b", - "metadata": {}, - "outputs": [], - "source": [ - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", - "await lh.setup()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0324171c-101d-4b3d-9103-a0137c620174", - "metadata": {}, - "outputs": [], - "source": [ - "vis = Visualizer(resource=lh)\n", - "await vis.setup()" - ] - }, - { - "cell_type": "markdown", - "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", - "metadata": {}, - "source": [ - "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.resources import (\n", - " TIP_CAR_480_A00,\n", - " PLT_CAR_L5AC_A00,\n", - " Cos_96_DW_1mL,\n", - " HTF_L\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", - "metadata": {}, - "outputs": [], - "source": [ - "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", - "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", - "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", - "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", - "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", - "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", - "lh.deck.assign_child_resource(tip_car, rails=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": {}, - "outputs": [], - "source": [ - "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", - "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", - "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", - "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", - "lh.deck.assign_child_resource(plt_car, rails=8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", - "metadata": {}, - "outputs": [], - "source": [ - "await vis.stop()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", + "metadata": {}, + "source": [ + "**Welcome to PyLabRobot!**\n", + "\n", + "PyLabRobot is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", + "\n", + "PLR defines a universal interface class called LiquidHandler that provides generic methods for controlling robots\n", + "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", + "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", + "be translatable across many different machines.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", + "the most widely used liquid handling robots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.hamilton import STARLetDeck\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b372972-d6dc-454b-95eb-d9941405621b", + "metadata": {}, + "outputs": [], + "source": [ + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "await lh.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0324171c-101d-4b3d-9103-a0137c620174", + "metadata": {}, + "outputs": [], + "source": [ + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", + "metadata": {}, + "source": [ + "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " TIP_CAR_480_A00,\n", + " PLT_CAR_L5AC_A00,\n", + " Cos_96_DW_1mL,\n", + " HTF_L\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", + "metadata": {}, + "outputs": [], + "source": [ + "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", + "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", + "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", + "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", + "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", + "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", + "lh.deck.assign_child_resource(tip_car, rails=15)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", + "metadata": {}, + "outputs": [], + "source": [ + "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", + "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", + "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", + "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", + "lh.deck.assign_child_resource(plt_car, rails=8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", + "metadata": {}, + "outputs": [], + "source": [ + "await vis.stop()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pylabrobot-20240513.log b/pylabrobot-20240513.log new file mode 100644 index 0000000..e69de29 diff --git a/pylabrobot-20240514.log b/pylabrobot-20240514.log new file mode 100644 index 0000000..e69de29 From 13d1a222d2116bb4bd6d6deacf6ae59dbd56f747 Mon Sep 17 00:00:00 2001 From: Joe Laforet Date: Wed, 15 May 2024 12:43:43 -0400 Subject: [PATCH 2/3] removed scratch --- Introduction_to_PyLabRobot.ipynb | 944 ------------------------------- Notes from Stefan | 9 - 2 files changed, 953 deletions(-) delete mode 100644 Introduction_to_PyLabRobot.ipynb delete mode 100644 Notes from Stefan diff --git a/Introduction_to_PyLabRobot.ipynb b/Introduction_to_PyLabRobot.ipynb deleted file mode 100644 index 2aecb70..0000000 --- a/Introduction_to_PyLabRobot.ipynb +++ /dev/null @@ -1,944 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", - "metadata": {}, - "source": [ - "# **Welcome to PyLabRobot!**\n", - "\n", - "PyLabRobot *(PLR)* is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", - "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", - "\n", - "PLR defines a universal interface class called **LiquidHandler** that provides generic methods for controlling robots\n", - "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", - "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", - "be translatable across many different machines.\n", - "\n", - "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", - "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", - "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", - "the most widely used liquid handling robots." - ] - }, - { - "cell_type": "markdown", - "id": "9268a564-0e57-4ace-9b22-68fcffbfcc2f", - "metadata": {}, - "source": [ - "### Imports" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.liquid_handling import LiquidHandler\n", - "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", - "from pylabrobot.visualizer.visualizer import Visualizer\n", - "from pylabrobot.resources.hamilton import STARLetDeck\n", - "from pylabrobot.resources.opentrons import OTDeck\n", - "\n", - "from pylabrobot.resources.opentrons.load import *\n", - "from pylabrobot.resources.opentrons.plates import *\n", - "\n", - "import opentrons" - ] - }, - { - "cell_type": "markdown", - "id": "3c611cf0-ac3f-4e4d-8f48-b9d2241f5670", - "metadata": {}, - "source": [ - "### Liquid Handler: High level abstraction, thing that takes in aspirate and dispense commands, abstract wrapper for all robot backends\n", - "Give input backend, what robot you are planning to use, PLR is hardware agnostic, you use the abstract liquid handler scaffold and then pass in \n", - "the details of your specific robot\n", - "### Deck: What deck is your robot using, again it is hardware agnostic.\n", - "\n", - "* Restart kernel is your friend when working with PLR" - ] - }, - { - "cell_type": "markdown", - "id": "213a4b8c-098e-4e0e-bb9f-446ba5b1709a", - "metadata": {}, - "source": [ - "## Deck Set-Up" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "8b372972-d6dc-454b-95eb-d9941405621b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Setting up the robot.\n", - "Resource deck was assigned to the robot.\n", - "Resource trash_container was assigned to the robot.\n" - ] - } - ], - "source": [ - "# Call setup to instantiate your specific instance of the robot\n", - "\n", - "# Hamilton\n", - "#lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", - "\n", - "# OpenTrons\n", - "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=OTDeck())\n", - "\n", - "# Use await because setup can take many minutes. Use await when you have a long function call that you\n", - "# want to be able to do other things while its happening\n", - "await lh.setup()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "0324171c-101d-4b3d-9103-a0137c620174", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Websocket server started at http://127.0.0.1:2121\n", - "File server started at http://127.0.0.1:1337 . Open this URL in your browser.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "----------------------------------------\n", - "Exception occurred during processing of request from ('127.0.0.1', 40734)\n", - "Traceback (most recent call last):\n", - " File \"/usr/lib/python3.10/socketserver.py\", line 316, in _handle_request_noblock\n", - " self.process_request(request, client_address)\n", - " File \"/usr/lib/python3.10/socketserver.py\", line 347, in process_request\n", - " self.finish_request(request, client_address)\n", - " File \"/usr/lib/python3.10/socketserver.py\", line 360, in finish_request\n", - " self.RequestHandlerClass(request, client_address, self)\n", - " File \"/mnt/d/Chory Lab/PyLabRobot/pylabrobot/visualizer/visualizer.py\", line 322, in __init__\n", - " super().__init__(*args, directory=path, **kwargs)\n", - " File \"/usr/lib/python3.10/http/server.py\", line 651, in __init__\n", - " super().__init__(*args, **kwargs)\n", - " File \"/usr/lib/python3.10/socketserver.py\", line 747, in __init__\n", - " self.handle()\n", - " File \"/usr/lib/python3.10/http/server.py\", line 425, in handle\n", - " self.handle_one_request()\n", - " File \"/usr/lib/python3.10/http/server.py\", line 413, in handle_one_request\n", - " method()\n", - " File \"/mnt/d/Chory Lab/PyLabRobot/pylabrobot/visualizer/visualizer.py\", line 343, in do_GET\n", - " self.wfile.write(content.encode(\"utf-8\"))\n", - " File \"/usr/lib/python3.10/socketserver.py\", line 826, in write\n", - " self._sock.sendall(b)\n", - "BrokenPipeError: [Errno 32] Broken pipe\n", - "----------------------------------------\n" - ] - } - ], - "source": [ - "# If you want to follow along in real time, instantiate the protocol visualizer\n", - "vis = Visualizer(resource=lh)\n", - "await vis.setup()" - ] - }, - { - "cell_type": "markdown", - "id": "42bf486e-b8cb-4918-a2e6-a9955e71c46b", - "metadata": {}, - "source": [ - "### Put some labware on the deck!" - ] - }, - { - "cell_type": "markdown", - "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", - "metadata": {}, - "source": [ - "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", - "metadata": {}, - "outputs": [], - "source": [ - "from pylabrobot.resources import (\n", - " TIP_CAR_480_A00,\n", - " PLT_CAR_L5AC_A00,\n", - " Cos_96_DW_1mL,\n", - " HTF_L,\n", - " opentrons_96_tiprack_300ul,\n", - " opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap\n", - ")\n" - ] - }, - { - "cell_type": "markdown", - "id": "8cf826da-7d57-49ce-8303-d40501f50e2b", - "metadata": {}, - "source": [ - "### Hamilton Tip Racks" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "OTDeck.assign_child_resource() got an unexpected keyword argument 'rails'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_582/3930452725.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mtip_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtip_rack4\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHTF_L\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'tips_04'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwith_tips\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mtip_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtip_rack5\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHTF_L\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'tips_05'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwith_tips\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeck\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massign_child_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_car\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrails\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m15\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m: OTDeck.assign_child_resource() got an unexpected keyword argument 'rails'" - ] - } - ], - "source": [ - "# Hamilton Tips\n", - "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", - "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", - "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", - "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", - "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", - "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", - "lh.deck.assign_child_resource(tip_car, rails=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "ename": "ValueError", - "evalue": "Resource with name 'plate carrier' already defined.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_200/3931165138.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mplt_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplate_2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCos_96_DW_1mL\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'plate_02'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mplt_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplate_3\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCos_96_DW_1mL\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'plate_03'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeck\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massign_child_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplt_car\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrails\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m8\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/resources/hamilton/hamilton_decks.py\u001b[0m in \u001b[0;36massign_child_resource\u001b[0;34m(self, resource, location, reassign, rails, replace)\u001b[0m\n\u001b[1;32m 113\u001b[0m \u001b[0mcast\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mResource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresource\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munassign\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 115\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Resource with name '{resource.name}' already defined.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 116\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mrails\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: Resource with name 'plate carrier' already defined." - ] - } - ], - "source": [ - "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", - "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", - "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", - "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", - "lh.deck.assign_child_resource(plt_car, rails=8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "4421b04c-d894-4aaa-a9f4-7f51a16dc773", - "metadata": {}, - "outputs": [], - "source": [ - "tip_rack_1.fill()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "74928e32-3910-434c-b0af-5bdc9c03a51e", - "metadata": {}, - "outputs": [], - "source": [ - "tip_rack4 = lh.deck.get_resource(\"tips_04\")\n", - "tip_rack4.set_tip_state([[True]*6 + [False]*6]*8)\n", - "tip_rack3.set_tip_state([[True, False]*6]*8)\n", - "tip_rack2.set_tip_state([[True, True, False, False]*3]*8)\n" - ] - }, - { - "cell_type": "markdown", - "id": "2d2fba32-6be8-4248-88b2-ab74fb2047af", - "metadata": {}, - "source": [ - "### OpenTrons Tip Racks" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "28b14d77-7cc3-4721-9f10-0867d9137a38", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Resource tip_rack_1 was assigned to the robot.\n", - "Resource tip_rack_2 was assigned to the robot.\n" - ] - } - ], - "source": [ - "# OT2 Tips\n", - "\n", - "tip_rack_1 = opentrons_96_tiprack_300ul(\"tip_rack_1\")\n", - "tip_rack_2 = opentrons_96_tiprack_300ul(\"tip_rack_2\")\n", - "\n", - "lh.deck.assign_child_at_slot(tip_rack_1, 7)\n", - "lh.deck.assign_child_at_slot(tip_rack_2, 8)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "7d16498c-5b03-4454-a197-dc1faf8a3a6f", - "metadata": {}, - "outputs": [], - "source": [ - "tip_rack2 = lh.deck.get_resource(\"tip_rack_2\")\n", - "tip_rack2.set_tip_state([[True]*6 + [False]*6]*8)" - ] - }, - { - "cell_type": "markdown", - "id": "a06b3c22-5498-43dd-8e1e-ae0203c24f23", - "metadata": {}, - "source": [ - "### OpenTrons Plates" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "16547556-5fd6-4af8-a37b-dd6a1d209981", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Resource plate_1 was assigned to the robot.\n", - "Resource plate_2 was assigned to the robot.\n" - ] - } - ], - "source": [ - "plate_1 = corning_96_wellplate_360ul_flat('plate_1')\n", - "plate_2 = corning_96_wellplate_360ul_flat('plate_2')\n", - "\n", - "lh.deck.assign_child_at_slot(plate_1, 1)\n", - "lh.deck.assign_child_at_slot(plate_2, 2)" - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "id": "534179d6-96aa-419f-832e-dbf6b19de0fa", - "metadata": {}, - "outputs": [], - "source": [ - "plate_1_liquids = [[('water', 200)]]*96\n", - "plate_1.set_well_liquids(plate_1_liquids)\n", - "plate_2_liquids = [[(None, 100)], [(None, 100)]]*(96//2)\n", - "plate_2.set_well_liquids(plate_2_liquids)\n" - ] - }, - { - "cell_type": "markdown", - "id": "fa620baf-955e-4671-b86c-8288545c599b", - "metadata": {}, - "source": [ - "### OpenTrons Tube Racks" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "aa3468cd-f660-4c2b-8568-ed3160172174", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Resource rack_1 was assigned to the robot.\n", - "Resource rack_2 was assigned to the robot.\n" - ] - } - ], - "source": [ - "rack_1 = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap('rack_1')\n", - "rack_2 = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap('rack_2')\n", - "\n", - "lh.deck.assign_child_at_slot(rack_1, 4)\n", - "lh.deck.assign_child_at_slot(rack_2, 5)" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "b65570bc-1589-43ec-9aa1-ece9c50187cd", - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'TubeRack' object has no attribute 'set_liquids'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_962/3721324440.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mrack_1_liquids\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'water'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m200\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mrack_1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_liquids\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplate_1_liquids\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m: 'TubeRack' object has no attribute 'set_liquids'" - ] - } - ], - "source": [ - "rack_1_liquids = [[('water', 200)]]*6\n", - "rack_1.set_liquids(plate_1_liquids)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 144, - "id": "02e18147-5337-4c75-9fd4-4243499d3108", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[Tube(name=rack_1_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_B1, location=(018.210, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_C1, location=(018.210, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_D1, location=(018.210, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_A2, location=(038.100, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_B2, location=(038.100, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_C2, location=(038.100, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_D2, location=(038.100, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_A3, location=(057.990, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_B3, location=(057.990, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_C3, location=(057.990, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_D3, location=(057.990, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_A4, location=(077.880, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_B4, location=(077.880, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_C4, location=(077.880, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_D4, location=(077.880, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_A5, location=(097.770, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_B5, location=(097.770, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_C5, location=(097.770, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_D5, location=(097.770, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_A6, location=(117.660, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_B6, location=(117.660, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_C6, location=(117.660, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", - " Tube(name=rack_1_D6, location=(117.660, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" - ] - }, - "execution_count": 144, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rack_1.get_all_children()" - ] - }, - { - "cell_type": "code", - "execution_count": 109, - "id": "23cb1bc9-cb4f-4d70-b0f7-7727a2586561", - "metadata": {}, - "outputs": [], - "source": [ - "rack_1.enable_volume_trackers()" - ] - }, - { - "cell_type": "code", - "execution_count": 125, - "id": "a467ab96-e1cb-4932-9e47-731831f29148", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['__class__',\n", - " '__delattr__',\n", - " '__dict__',\n", - " '__dir__',\n", - " '__doc__',\n", - " '__eq__',\n", - " '__format__',\n", - " '__ge__',\n", - " '__getattribute__',\n", - " '__gt__',\n", - " '__hash__',\n", - " '__init__',\n", - " '__init_subclass__',\n", - " '__le__',\n", - " '__lt__',\n", - " '__module__',\n", - " '__ne__',\n", - " '__new__',\n", - " '__reduce__',\n", - " '__reduce_ex__',\n", - " '__repr__',\n", - " '__setattr__',\n", - " '__sizeof__',\n", - " '__str__',\n", - " '__subclasshook__',\n", - " '__weakref__',\n", - " '_call_did_assign_resource_callbacks',\n", - " '_call_did_unassign_resource_callbacks',\n", - " '_call_will_assign_resource_callbacks',\n", - " '_call_will_unassign_resource_callbacks',\n", - " '_check_assignment',\n", - " '_did_assign_resource_callbacks',\n", - " '_did_unassign_resource_callbacks',\n", - " '_name',\n", - " '_resource_state_updated_callbacks',\n", - " '_size_x',\n", - " '_size_y',\n", - " '_size_z',\n", - " '_state_updated',\n", - " '_will_assign_resource_callbacks',\n", - " '_will_unassign_resource_callbacks',\n", - " 'assign_child_resource',\n", - " 'category',\n", - " 'center',\n", - " 'centers',\n", - " 'children',\n", - " 'copy',\n", - " 'deregister_did_assign_resource_callback',\n", - " 'deregister_did_unassign_resource_callback',\n", - " 'deregister_state_update_callback',\n", - " 'deregister_will_assign_resource_callback',\n", - " 'deregister_will_unassign_resource_callback',\n", - " 'deserialize',\n", - " 'get_absolute_location',\n", - " 'get_all_children',\n", - " 'get_resource',\n", - " 'get_size_x',\n", - " 'get_size_y',\n", - " 'get_size_z',\n", - " 'load_all_state',\n", - " 'load_from_json_file',\n", - " 'load_state',\n", - " 'load_state_from_file',\n", - " 'location',\n", - " 'max_volume',\n", - " 'model',\n", - " 'name',\n", - " 'parent',\n", - " 'register_did_assign_resource_callback',\n", - " 'register_did_unassign_resource_callback',\n", - " 'register_state_update_callback',\n", - " 'register_will_assign_resource_callback',\n", - " 'register_will_unassign_resource_callback',\n", - " 'rotate',\n", - " 'rotated',\n", - " 'rotation',\n", - " 'save',\n", - " 'save_state_to_file',\n", - " 'serialize',\n", - " 'serialize_all_state',\n", - " 'serialize_state',\n", - " 'tracker',\n", - " 'unassign',\n", - " 'unassign_child_resource']" - ] - }, - "execution_count": 125, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dir(rack_1['A1'][0])" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "id": "4354a042-96d4-4e93-916e-1cc2a25f2c1e", - "metadata": {}, - "outputs": [], - "source": [ - "tube1 = rack_1[0][0]" - ] - }, - { - "cell_type": "code", - "execution_count": 138, - "id": "8e5166dd-23a4-4d5b-b869-5fd4ca167f77", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "tube1.tracker.set_liquids([(None, 0)])" - ] - }, - { - "cell_type": "code", - "execution_count": 140, - "id": "0a1fd4b0-7089-43be-bfde-de3b43d2b44b", - "metadata": {}, - "outputs": [], - "source": [ - "tube1.tracker.add_liquid(None, 2000)" - ] - }, - { - "cell_type": "code", - "execution_count": 141, - "id": "cdbb78b9-39d4-4036-924a-a358d8c8c9a8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[(None, 2000)]" - ] - }, - "execution_count": 141, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tube1.tracker.liquids" - ] - }, - { - "cell_type": "code", - "execution_count": 91, - "id": "bebe9703-f00c-4975-9620-5eb3d0416001", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", - "Aspirating [Aspiration(resource=Tube(name=rack_1_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Water', 100)])].\n", - "Dispensing [Dispense(resource=Well(name=plate_2_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Water', 100)])].\n", - "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" - ] - } - ], - "source": [ - "await lh.pick_up_tips(tip_rack_1[\"A1\"])\n", - "time.sleep(1)\n", - "\n", - "await lh.aspirate(rack_1[\"A1\"], vols=[100])\n", - "time.sleep(1)\n", - "\n", - "await lh.dispense(plate_2[\"A1\"], vols=[100])\n", - "time.sleep(1)\n", - "\n", - "await lh.return_tips()" - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "id": "62fe14fa-2c25-413a-a982-db510f6d8c0b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" - ] - } - ], - "source": [ - "await lh.return_tips()" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "ace711fd-1823-4056-b408-7f2f24be5338", - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'list' object has no attribute 'add_liquid'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_962/68121547.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrack_1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_liquid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'water'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m200\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m: 'list' object has no attribute 'add_liquid'" - ] - } - ], - "source": [ - "rack_1.get[0].add_liquid([('water', 200)])" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "21e6aa85-cbe1-4c8e-bbe7-1e33eaccdc20", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(None, None)" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from pylabrobot.resources import set_tip_tracking, set_volume_tracking\n", - "set_tip_tracking(True), set_volume_tracking(True)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "8055306d-042d-4d83-a685-139a221d8665", - "metadata": {}, - "outputs": [], - "source": [ - "import time" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "7eda3c13-e750-4823-8327-5e5baba6ac2d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", - "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" - ] - } - ], - "source": [ - "await lh.pick_up_tips(tip_rack_1[\"A1\", \"B2\", \"C3\", \"D4\"])\n", - "time.sleep(2)\n", - "await lh.drop_tips(tip_rack_1[\"A1\", \"B2\", \"C3\", \"D4\"])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "464f5dd7-8d85-407b-b4d6-693340f90c5e", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" - ] - } - ], - "source": [ - "await lh.pick_up_tips(tip_rack_1[\"A1\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "1e4c9bb2-58e9-4c4d-a9d4-fa65db824f20", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Aspirating [Aspiration(resource=Well(name=plate_1_A2, location=(023.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('water', 100)])].\n" - ] - } - ], - "source": [ - "await lh.aspirate(plate_1[\"A2\"], vols=[100])" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "ce90182d-607b-4e93-bc9a-1d7dfef80e66", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dispensing [Dispense(resource=Well(name=plate_2_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('water', 100)])].\n" - ] - } - ], - "source": [ - "await lh.dispense(plate_2[\"A1\"], vols=[100])" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "711f3290-e36d-4ae9-88a3-80374709cc36", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" - ] - } - ], - "source": [ - "await lh.return_tips()" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "eb52fd76-d92a-43b3-8550-e688eed4c587", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Picking up tips from tip_rack_1.\n" - ] - } - ], - "source": [ - "await lh.pick_up_tips96(tip_rack_1)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "c9cbce02-0f7e-4e51-94e7-2635002d757b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Aspirating 100 from Plate(name=plate_1, size_x=127.76, size_y=85.47, size_z=14.22, location=(000.000, 000.000, 000.000)).\n" - ] - } - ], - "source": [ - "await lh.aspirate96(plate_1, volume=100)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "ca18de2b-92f4-43c8-a0e7-dab9aa51ec38", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dispensing 100 to Plate(name=plate_2, size_x=127.76, size_y=85.47, size_z=14.22, location=(132.500, 000.000, 000.000)).\n" - ] - } - ], - "source": [ - "await lh.dispense96(plate_2, volume=100)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "12ef3847-c203-4332-84bd-6631dd90aea5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Dropping tips to tip_rack_1.\n" - ] - } - ], - "source": [ - "await lh.drop_tips96(tip_rack_1)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", - "metadata": {}, - "outputs": [], - "source": [ - "await vis.stop()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8525dc3-7866-4b4d-b870-8c64313bba28", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/Notes from Stefan b/Notes from Stefan deleted file mode 100644 index f33716c..0000000 --- a/Notes from Stefan +++ /dev/null @@ -1,9 +0,0 @@ -# Notes from Stefan - -This file serves as a journal/ written log of the different topics discussed as we construct the BME 590 class. - -Joe Laforet Jr. - -## 5/13/24 Day 1: Rough Outline - -* Stefan already made a github repo and a basic tutorial where students can get PyLabRobot set up on their machines. The exercise involves setting up a deck layout, adding in some liquids to the deck, and moving liquids from one place to another. I am going to reproduce this protocol using the OpenTrons platform, and then pretty up the tutorial. This will be either lab 1 or lab 0. From 6797a6cd871a8029e14a735ad8a0b07cc6e5fc81 Mon Sep 17 00:00:00 2001 From: Joe Laforet Date: Fri, 17 May 2024 17:15:40 -0400 Subject: [PATCH 3/3] finished draft 1 of OT2 notebook (Lab 0) --- .../OT2_Deck_Intro-checkpoint.ipynb | 293 ++++-- Decks/OT2_Deck_Intro.ipynb | 600 ++++++++--- Decks/pylabrobot-20240516.log | 0 Decks/pylabrobot-20240517.log | 0 Introduction_to_PyLabRobot.ipynb | 944 ++++++++++++++++++ 5 files changed, 1637 insertions(+), 200 deletions(-) create mode 100644 Decks/pylabrobot-20240516.log create mode 100644 Decks/pylabrobot-20240517.log create mode 100644 Introduction_to_PyLabRobot.ipynb diff --git a/Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb b/Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb index c06336f..e61bb9d 100644 --- a/Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb +++ b/Decks/.ipynb_checkpoints/OT2_Deck_Intro-checkpoint.ipynb @@ -19,9 +19,7 @@ { "cell_type": "markdown", "id": "0b6ee87a-a089-4a5b-9b60-852d1e1f8874", - "metadata": { - "jp-MarkdownHeadingCollapsed": true - }, + "metadata": {}, "source": [ "### Imports" ] @@ -29,6 +27,37 @@ { "cell_type": "code", "execution_count": 1, + "id": "9faf434a-2fc5-44cf-8dc9-7a68475d47bf", + "metadata": {}, + "outputs": [], + "source": [ + "import pylabrobot" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "069fb033-3ea2-4772-b55b-c800ed17dab5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/mnt/d/Chory Lab/PyLabRobot/pylabrobot/__init__.py'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pylabrobot.__file__" + ] + }, + { + "cell_type": "code", + "execution_count": 3, "id": "63636707-3e3c-4aba-b8eb-1e702875d391", "metadata": {}, "outputs": [], @@ -41,15 +70,17 @@ "from pylabrobot.resources.opentrons.load import *\n", "from pylabrobot.resources.opentrons.plates import *\n", "\n", - "import opentrons" + "from pylabrobot.resources import set_tip_tracking, set_volume_tracking\n", + "set_tip_tracking(True), set_volume_tracking(True)\n", + "\n", + "import opentrons\n", + "import time" ] }, { "cell_type": "markdown", "id": "10bcab3e-f908-479a-8e63-1fecfbe9ecf7", - "metadata": { - "jp-MarkdownHeadingCollapsed": true - }, + "metadata": {}, "source": [ "### Setting up the Deck and Visualizer" ] @@ -64,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "id": "cb5eb1ee-a1ae-4fd3-afff-78967d6e9f95", "metadata": {}, "outputs": [ @@ -94,7 +125,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "id": "9ce8270d-91ed-4836-a742-ab5375c4fdaa", "metadata": {}, "outputs": [ @@ -115,9 +146,7 @@ { "cell_type": "markdown", "id": "70c070bd-f7fd-47c4-9c98-65674fa776fc", - "metadata": { - "jp-MarkdownHeadingCollapsed": true - }, + "metadata": {}, "source": [ "### Adding Labware to the Deck" ] @@ -143,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "id": "71889711-e068-4e7e-b158-128a9491a1a0", "metadata": {}, "outputs": [], @@ -173,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "id": "c4c43470-21ff-4b3f-9a36-cdc3c0d97403", "metadata": {}, "outputs": [ @@ -195,7 +224,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 8, "id": "3740eb57-80bd-498b-95d5-725b9487c196", "metadata": {}, "outputs": [ @@ -216,7 +245,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "fd6a17ea-b41e-4033-a914-81b2d87635b9", "metadata": {}, "outputs": [ @@ -235,6 +264,44 @@ "lh.deck.assign_child_at_slot(plate, 1)" ] }, + { + "cell_type": "code", + "execution_count": 10, + "id": "8f58b38f-d40b-4a07-8162-b31d87fdcb12", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Deck: 624.3mm x 565.2mm\n", + "\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 10: Empty | 11: Empty | 12: trash_co... |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 7: tip_rack | 8: Empty | 9: Empty |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 4: tube_rack | 5: Empty | 6: Empty |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 1: prep_plate | 2: Empty | 3: Empty |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "\n" + ] + } + ], + "source": [ + "print(lh.deck.summary())" + ] + }, { "cell_type": "markdown", "id": "b7c49e37-543c-49b5-86f0-5c9df9bdd5a1", @@ -269,7 +336,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "id": "aca186f8-922b-4226-89ef-e6cfe886b512", "metadata": {}, "outputs": [ @@ -282,7 +349,7 @@ " Tube(name=tube_rack_D1, location=(018.210, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" ] }, - "execution_count": 8, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -306,17 +373,17 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "id": "876af18c-fdde-4a78-8261-b9a61c580988", "metadata": {}, "outputs": [], "source": [ "for i in range(len(first_col_tubes)):\n", - " \n", - " first_col_tubes[i].tracker.add_liquid(f\"Dye_{i}\", 1000)\n", + " # [(liquid, volume)]\n", + " first_col_tubes[i].tracker.set_liquids([(f\"Dye_{i}\", 1000)])\n", " \n", " #Commit the change\n", - " first_col_tubes[i].tracker.commit()" + " #first_col_tubes[i].tracker.commit()" ] }, { @@ -329,7 +396,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 13, "id": "ee999023-9b95-41b0-90c4-4e05bc65d629", "metadata": {}, "outputs": [], @@ -360,9 +427,11 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 14, "id": "1832d167-395f-44fe-911b-1584b9a71281", - "metadata": {}, + "metadata": { + "scrolled": true + }, "outputs": [ { "name": "stdout", @@ -383,6 +452,24 @@ "print_filled_spots_of_tubeRack(tube_rack)" ] }, + { + "cell_type": "code", + "execution_count": 15, + "id": "c1e08eec-4b28-498b-8374-09a62b4cefa0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Entire rack is empty!\n" + ] + } + ], + "source": [ + "print_filled_spots_of_tubeRack(plate)" + ] + }, { "cell_type": "markdown", "id": "ffceed8a-b9c4-4824-85e4-2676957811f6", @@ -392,106 +479,160 @@ ] }, { - "cell_type": "markdown", - "id": "622baa5b-0e60-47cb-aa03-aeb3982d3519", + "cell_type": "code", + "execution_count": 19, + "id": "0e85d828-b3f5-4ad2-9e87-56ccd985720f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "5f277deb-be20-4ce6-b888-1e5811e6e137", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], "source": [ - "Why is it not updating the contents of the tubes correctly?? The animations are also broken now." + "await lh.pick_up_tips(tip_rack[\"A1\"])" ] }, { "cell_type": "code", "execution_count": 18, - "id": "d93e6576-a5d8-43fe-b8aa-3c48b4514a0d", + "id": "8101f459-a1ce-4f1e-a482-2998da60e2d8", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], "source": [ - "import time" + "await lh.pick_up_tips(tip_rack[\"A1\", \"B2\", \"C3\", \"D4\"])" ] }, { "cell_type": "code", - "execution_count": 36, - "id": "0e85d828-b3f5-4ad2-9e87-56ccd985720f", + "execution_count": 20, + "id": "f1d968f1-1889-474e-8106-a55369d6e412", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" ] } ], "source": [ - "await lh.return_tips()" + "await lh.pick_up_tips(tip_rack[\"A1\", \"B2\", \"C3\", \"D4\"])\n", + "time.sleep(2)\n", + "await lh.drop_tips(tip_rack[\"A1\", \"B2\", \"C3\", \"D4\"])" ] }, { "cell_type": "code", - "execution_count": 37, - "id": "5f55c2d7-6e9c-4190-a1d7-ef65e7a93915", + "execution_count": 21, + "id": "52ae208a-cff3-419d-91e4-0293b437871b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", - "Aspirating [Aspiration(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", - "Dispensing [Dispense(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", - "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" ] } ], "source": [ - "await lh.pick_up_tips(tip_rack[\"A1\"])\n", - "time.sleep(2)\n", - "\n", - "await lh.aspirate(tube_rack[\"A1\"], vols=[100])\n", - "tube_rack[\"A1\"][0].tracker.commit()\n", - "time.sleep(2)\n", - "\n", - "await lh.dispense(plate[\"A1\"], vols=[100])\n", - "plate[\"A1\"][0].tracker.commit()\n", - "time.sleep(2)\n", - "\n", - "await lh.return_tips()" + "await lh.pick_up_tips(tip_rack[\"A1\"])" ] }, { "cell_type": "code", - "execution_count": 34, - "id": "e402336b-ff23-4205-81ee-d16e967ad017", + "execution_count": 22, + "id": "0b9a66e5-ac0c-456f-aad0-7c3597925da7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" + "False" ] }, - "execution_count": 34, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "tube_rack[\"A1\"]" + "tip_rack[\"A1\"][0].has_tip()" ] }, { "cell_type": "code", - "execution_count": 38, - "id": "e51ed207-74e3-4ad1-9aa4-7a79ece40016", + "execution_count": 23, + "id": "5f55c2d7-6e9c-4190-a1d7-ef65e7a93915", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aspirating [Aspiration(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=200, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 200)])].\n", + "Dispensing [Dispense(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=200, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 200)])].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.aspirate(tube_rack[\"A1\"], vols=[200])\n", + "time.sleep(2)\n", + "\n", + "await lh.dispense(plate[\"A1\"], vols=[200])\n", + "#plate[\"A1\"][0].tracker.commit()\n", + "time.sleep(2)\n", + "\n", + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "e51ed207-74e3-4ad1-9aa4-7a79ece40016", + "metadata": { + "scrolled": true + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Spot A1 contains:\n", - "1000uL of Dye_0\n", + "800.0uL of Dye_0\n", "Spot B1 contains:\n", "1000uL of Dye_1\n", "Spot C1 contains:\n", @@ -507,31 +648,21 @@ }, { "cell_type": "code", - "execution_count": 32, - "id": "f64ffbc0-7d55-4f43-9083-4ecd147c5193", + "execution_count": 27, + "id": "7ac2d2e3-dfb0-4d5f-8aee-8769cfd804f1", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "[('Dye_0', 1000)]" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Aspirating [Aspiration(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 100)])].\n", + "Dispensing [Dispense(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 100)])].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] } ], - "source": [ - "tube_rack[0][0].tracker.liquids" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7ac2d2e3-dfb0-4d5f-8aee-8769cfd804f1", - "metadata": {}, - "outputs": [], "source": [ "await lh.pick_up_tips(tip_rack[\"A1\"])\n", "time.sleep(1)\n", diff --git a/Decks/OT2_Deck_Intro.ipynb b/Decks/OT2_Deck_Intro.ipynb index 8223e02..8c3dc2d 100644 --- a/Decks/OT2_Deck_Intro.ipynb +++ b/Decks/OT2_Deck_Intro.ipynb @@ -27,6 +27,37 @@ { "cell_type": "code", "execution_count": 1, + "id": "9faf434a-2fc5-44cf-8dc9-7a68475d47bf", + "metadata": {}, + "outputs": [], + "source": [ + "import pylabrobot" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "069fb033-3ea2-4772-b55b-c800ed17dab5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/mnt/d/Chory Lab/PyLabRobot/pylabrobot/__init__.py'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pylabrobot.__file__" + ] + }, + { + "cell_type": "code", + "execution_count": 4, "id": "63636707-3e3c-4aba-b8eb-1e702875d391", "metadata": {}, "outputs": [], @@ -39,7 +70,11 @@ "from pylabrobot.resources.opentrons.load import *\n", "from pylabrobot.resources.opentrons.plates import *\n", "\n", - "import opentrons" + "from pylabrobot.resources import set_tip_tracking, set_volume_tracking\n", + "set_tip_tracking(True), set_volume_tracking(True)\n", + "\n", + "import opentrons\n", + "import time" ] }, { @@ -60,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "id": "cb5eb1ee-a1ae-4fd3-afff-78967d6e9f95", "metadata": {}, "outputs": [ @@ -90,7 +125,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "id": "9ce8270d-91ed-4836-a742-ab5375c4fdaa", "metadata": {}, "outputs": [ @@ -98,8 +133,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Websocket server started at http://127.0.0.1:2122\n", - "File server started at http://127.0.0.1:1338 . Open this URL in your browser.\n" + "Websocket server started at http://127.0.0.1:2121\n", + "File server started at http://127.0.0.1:1337 . Open this URL in your browser.\n" ] } ], @@ -121,7 +156,7 @@ "id": "4d0024ee-4722-4b99-afad-3bba67388855", "metadata": {}, "source": [ - "Now, we are ready to add some labware to the deck. PyLabRobot has many different labware items already defined. Only import the ones that you need for your protocol. A full list of labware can be found in `PyLabRobot\\Resources\\opentrons`. You can also create custom labware, but that is out of scope for this tutorial.\n", + "Now, we are ready to add some labware to the deck. **PyLabRobot** has many different labware items already defined. Only import the ones that you need for your protocol. A full list of labware can be found in `PyLabRobot\\Resources\\opentrons`. You can also create custom labware, but that is out of scope for this tutorial.\n", "\n", "Let's begin by importing a `TubeRack`, a `TipRack`, and a `Plate`.\n", "
\n", @@ -137,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "id": "71889711-e068-4e7e-b158-128a9491a1a0", "metadata": {}, "outputs": [], @@ -167,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "id": "c4c43470-21ff-4b3f-9a36-cdc3c0d97403", "metadata": {}, "outputs": [ @@ -189,7 +224,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "id": "3740eb57-80bd-498b-95d5-725b9487c196", "metadata": {}, "outputs": [ @@ -210,7 +245,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "id": "fd6a17ea-b41e-4033-a914-81b2d87635b9", "metadata": {}, "outputs": [ @@ -229,6 +264,44 @@ "lh.deck.assign_child_at_slot(plate, 1)" ] }, + { + "cell_type": "code", + "execution_count": 11, + "id": "8f58b38f-d40b-4a07-8162-b31d87fdcb12", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Deck: 624.3mm x 565.2mm\n", + "\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 10: Empty | 11: Empty | 12: trash_co... |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 7: tip_rack | 8: Empty | 9: Empty |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 4: tube_rack | 5: Empty | 6: Empty |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "| | | |\n", + "| 1: prep_plate | 2: Empty | 3: Empty |\n", + "| | | |\n", + "+-----------------+-----------------+-----------------+\n", + "\n" + ] + } + ], + "source": [ + "print(lh.deck.summary())" + ] + }, { "cell_type": "markdown", "id": "b7c49e37-543c-49b5-86f0-5c9df9bdd5a1", @@ -242,7 +315,7 @@ "id": "b757ebe8-be14-48af-bda6-f377a8769d0b", "metadata": {}, "source": [ - "Let's add some liquids to our `tube_rack`. We can add up to the `max_volume` of the tube. If you go over this number, PyLabRobot will throw an error. We shall add 1000µL of 4 different dyes to the first column of our `tube_rack`. This corresponds to wells *A1, B1, C1, and D1*.\n", + "Let's add some liquids to our `tube_rack`. We can add up to the `max_volume` of the tube. If you go over this number, **PyLabRobot** will throw an error. We shall add 1000µL of 4 different dyes to the first column of our `tube_rack`. This corresponds to wells *A1, B1, C1, and D1*.\n", "\n", "To iterate over locations on labware, we use the `traverse()` function. This produces a generator object that we use the `next` keyword on to yield our desired wells.\n", "\n", @@ -263,7 +336,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 12, "id": "aca186f8-922b-4226-89ef-e6cfe886b512", "metadata": {}, "outputs": [ @@ -276,7 +349,7 @@ " Tube(name=tube_rack_D1, location=(018.210, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" ] }, - "execution_count": 8, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -291,7 +364,7 @@ "id": "88f4e079-81e1-441c-923c-63e2a8b1cfb7", "metadata": {}, "source": [ - "Use the `tracker.add_liquid()` function to put liquid in a `tube`. The `tracker` class contains all of the methods associated with keeping record of how much/what kind of liquid is in a given container.\n", + "Use the `tracker.set_liquids()` function to put liquid in a `tube`. The `tracker` class contains all of the methods associated with keeping record of how much/what kind of liquid is in a given container.\n", "\n", "Pass in a string for **\"Liquid_Type\"** and a number for **Volume** to this function.\n", "\n", @@ -300,17 +373,14 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 13, "id": "876af18c-fdde-4a78-8261-b9a61c580988", "metadata": {}, "outputs": [], "source": [ "for i in range(len(first_col_tubes)):\n", - " \n", - " first_col_tubes[i].tracker.add_liquid(f\"Dye_{i}\", 1000)\n", - " \n", - " #Commit the change\n", - " first_col_tubes[i].tracker.commit()" + " # [(liquid, volume)]\n", + " first_col_tubes[i].tracker.set_liquids([(f\"Dye_{i}\", 2000)])" ] }, { @@ -323,7 +393,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 14, "id": "ee999023-9b95-41b0-90c4-4e05bc65d629", "metadata": {}, "outputs": [], @@ -354,22 +424,24 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 15, "id": "1832d167-395f-44fe-911b-1584b9a71281", - "metadata": {}, + "metadata": { + "scrolled": true + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Spot A1 contains:\n", - "1000uL of Dye_0\n", + "2000uL of Dye_0\n", "Spot B1 contains:\n", - "1000uL of Dye_1\n", + "2000uL of Dye_1\n", "Spot C1 contains:\n", - "1000uL of Dye_2\n", + "2000uL of Dye_2\n", "Spot D1 contains:\n", - "1000uL of Dye_3\n" + "2000uL of Dye_3\n" ] } ], @@ -378,47 +450,56 @@ ] }, { - "cell_type": "markdown", - "id": "ffceed8a-b9c4-4824-85e4-2676957811f6", + "cell_type": "code", + "execution_count": 16, + "id": "c1e08eec-4b28-498b-8374-09a62b4cefa0", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Entire rack is empty!\n" + ] + } + ], "source": [ - "### Moving Liquids from Point A to Point B" + "print_filled_spots_of_tubeRack(plate)" ] }, { "cell_type": "markdown", - "id": "622baa5b-0e60-47cb-aa03-aeb3982d3519", + "id": "ffceed8a-b9c4-4824-85e4-2676957811f6", "metadata": {}, "source": [ - "Why is it not updating the contents of the tubes correctly?? The animations are also broken now." + "### Moving Liquids from Point A to Point B" ] }, { - "cell_type": "code", - "execution_count": 12, - "id": "d93e6576-a5d8-43fe-b8aa-3c48b4514a0d", + "cell_type": "markdown", + "id": "4d7e2781-aee6-45a3-82a0-09a56e8452aa", "metadata": {}, - "outputs": [], "source": [ - "import time" + "Now that we've added some dyes to our tube rack, let's use the robot to move some liquid to our `prep_plate`. The first step of a liquid transfer is acquiring a tip.\n", + "\n", + "You can acquire a tip by calling `lh.pick_up_tips()`, and passing in the `TipSpots` of the tips you want to retrieve. `TipSpots` are indexed the same way that wells are.\n", + "\n", + "When a tip is picked up from a `TipRack`, it's location will turn white on the visualizer. To see what tips are currently on the robot, call `lh.head`. This returns a dictionary where the keys are the indices of the different channels of the main pipettor, and where the values are instances of the `TipTracker` class, allowing you to get information about how tips move on and off of a given channel.\n", + "\n", + "If you want to reset the state of tips on a robot, call `lh.return_tips()`. This function will automatically return the tips to their original locations." ] }, { "cell_type": "code", - "execution_count": 13, - "id": "0e85d828-b3f5-4ad2-9e87-56ccd985720f", + "execution_count": 76, + "id": "be4dfa3a-4654-4b1e-917b-91fd163b0a04", "metadata": {}, "outputs": [ { - "ename": "RuntimeError", - "evalue": "No tips have been picked up.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/tmp/ipykernel_6667/2886996634.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mawait\u001b[0m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreturn_tips\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/liquid_handling/liquid_handler.py\u001b[0m in \u001b[0;36mreturn_tips\u001b[0;34m(self, use_channels, **backend_kwargs)\u001b[0m\n\u001b[1;32m 557\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 558\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 559\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"No tips have been picked up.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 560\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 561\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdrop_tips\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0muse_channels\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mchannels\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mbackend_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mRuntimeError\u001b[0m: No tips have been picked up." + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_E7, location=(068.380, 038.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_D3, location=(032.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" ] } ], @@ -426,94 +507,102 @@ "await lh.return_tips()" ] }, + { + "cell_type": "markdown", + "id": "3ad6d617-4927-4898-b3b0-5c6c896367c7", + "metadata": {}, + "source": [ + "Let's try picking up 8 tips along the diagonal." + ] + }, { "cell_type": "code", - "execution_count": 37, - "id": "5f55c2d7-6e9c-4190-a1d7-ef65e7a93915", + "execution_count": 17, + "id": "f1d968f1-1889-474e-8106-a55369d6e412", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", - "Aspirating [Aspiration(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", - "Dispensing [Dispense(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[(None, 100)])].\n", - "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_E5, location=(050.380, 038.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_F6, location=(059.380, 029.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_G7, location=(068.380, 020.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_H8, location=(077.380, 011.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" ] } ], "source": [ - "await lh.pick_up_tips(tip_rack[\"A1\"])\n", - "time.sleep(2)\n", - "\n", - "await lh.aspirate(tube_rack[\"A1\"], vols=[100])\n", - "tube_rack[\"A1\"][0].tracker.commit()\n", - "time.sleep(2)\n", - "\n", - "await lh.dispense(plate[\"A1\"], vols=[100])\n", - "plate[\"A1\"][0].tracker.commit()\n", - "time.sleep(2)\n", - "\n", - "await lh.return_tips()" + "await lh.pick_up_tips(tip_rack[\"A1\", \"B2\", \"C3\", \"D4\", \"E5\", \"F6\", \"G7\", \"H8\"])" + ] + }, + { + "cell_type": "markdown", + "id": "7e370bb6-b432-46dc-88ce-851bde0b7d84", + "metadata": {}, + "source": [ + "Rather than use `lh.return_tips()` all of the time, you can also call `lh.drop_tips()` and pass in specifically where to place the tip, and what channel's tip to drop." ] }, { "cell_type": "code", - "execution_count": 34, - "id": "e402336b-ff23-4205-81ee-d16e967ad017", + "execution_count": 18, + "id": "7abad4b7-d3e2-4d45-a33c-651f41b9a590", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "[Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_E5, location=(050.380, 038.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_F6, location=(059.380, 029.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_G7, location=(068.380, 020.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_H8, location=(077.380, 011.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] } ], "source": [ - "tube_rack[\"A1\"]" + "await lh.drop_tips(tip_spots = tip_rack[\"A1\", \"B2\", \"C3\", \"D4\", \"E5\", \"F6\", \"G7\", \"H8\"],\n", + " use_channels = [0,1,2,3,4,5,6,7])" + ] + }, + { + "cell_type": "markdown", + "id": "31159c96-4f4a-4abf-9a83-f93bef0da703", + "metadata": {}, + "source": [ + "The order in which you pass in the `tip_spots` and the `use_channels` lists will determine which channel gets which tip. Take a look!" ] }, { "cell_type": "code", - "execution_count": 38, - "id": "e51ed207-74e3-4ad1-9aa4-7a79ece40016", + "execution_count": 19, + "id": "52ae208a-cff3-419d-91e4-0293b437871b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Spot A1 contains:\n", - "1000uL of Dye_0\n", - "Spot B1 contains:\n", - "1000uL of Dye_1\n", - "Spot C1 contains:\n", - "1000uL of Dye_2\n", - "Spot D1 contains:\n", - "1000uL of Dye_3\n" + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_E7, location=(068.380, 038.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" ] } ], "source": [ - "print_filled_spots_of_tubeRack(tube_rack)" + "await lh.pick_up_tips(tip_spots = tip_rack[\"A1\", 'C3', \"E7\"], use_channels = [2,0,1])" ] }, { "cell_type": "code", "execution_count": 32, - "id": "f64ffbc0-7d55-4f43-9083-4ecd147c5193", + "id": "807b3ba9-57db-483e-aca2-419f439e8520", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[('Dye_0', 1000)]" + "{0: TipTracker(Channel 0, is_disabled=False, has_tip=False tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), pending_tip=None),\n", + " 1: TipTracker(Channel 1, is_disabled=False, has_tip=True tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), pending_tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)),\n", + " 2: TipTracker(Channel 2, is_disabled=False, has_tip=False tip=None, pending_tip=None),\n", + " 3: TipTracker(Channel 3, is_disabled=False, has_tip=False tip=None, pending_tip=None),\n", + " 4: TipTracker(Channel 4, is_disabled=False, has_tip=True tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), pending_tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)),\n", + " 5: TipTracker(Channel 5, is_disabled=False, has_tip=False tip=None, pending_tip=None),\n", + " 6: TipTracker(Channel 6, is_disabled=False, has_tip=False tip=None, pending_tip=None),\n", + " 7: TipTracker(Channel 7, is_disabled=False, has_tip=False tip=None, pending_tip=None)}" ] }, "execution_count": 32, @@ -522,76 +611,349 @@ } ], "source": [ - "tube_rack[0][0].tracker.liquids" + "lh.head" + ] + }, + { + "cell_type": "markdown", + "id": "e2931c39-74db-4426-9be9-0a702c677489", + "metadata": {}, + "source": [ + "Here's another utility function that will print the status of tips on the pipetter. If there is a tip on a channel, this function will output its origin." ] }, { "cell_type": "code", - "execution_count": null, - "id": "7ac2d2e3-dfb0-4d5f-8aee-8769cfd804f1", + "execution_count": 21, + "id": "d579d650-e172-4c58-b9e9-a96262609f60", "metadata": {}, "outputs": [], "source": [ - "await lh.pick_up_tips(tip_rack[\"A1\"])\n", - "time.sleep(1)\n", + "def print_channels_tip_origin(lh):\n", + " # Prints the origin location of all tips currently on the robot\n", + " cur_pipetter = lh.head\n", "\n", - "await lh.aspirate(plate[\"A1\"], vols=[100])\n", - "time.sleep(1)\n", + " for channel in cur_pipetter:\n", + " print(f\"Channel {channel}:\")\n", "\n", - "await lh.dispense(tube_rack[\"A1\"], vols=[100])\n", - "time.sleep(1)\n", + " tip_tracker = lh.head[channel]\n", + " \n", + " if tip_tracker.has_tip == True:\n", + " print(tip_tracker.get_tip_origin())\n", + " else:\n", + " print(\"No tip present.\")\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "35530ae2-b0ff-4554-9da3-1b714357b9d7", + "metadata": {}, + "outputs": [], + "source": [ + "def print_channel_status(lh):\n", + " # Prints the status of liquids, if present, in each channel\n", + " cur_pipetter = lh.head\n", "\n", - "await lh.return_tips()" + " for channel in cur_pipetter:\n", + " print(f\"Channel {channel}:\")\n", + "\n", + " tip_tracker = lh.head[channel]\n", + " \n", + " if tip_tracker.has_tip == True:\n", + " tip = tip_tracker.get_tip()\n", + " print(tip.tracker.liquids)\n", + " else:\n", + " print(\"No tip present.\")\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "f4019779-4c85-4d46-8c35-960d26b58618", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Channel 0:\n", + "No tip present.\n", + "\n", + "Channel 1:\n", + "TipSpot(name=tip_rack_E7, location=(068.380, 038.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot)\n", + "\n", + "Channel 2:\n", + "No tip present.\n", + "\n", + "Channel 3:\n", + "No tip present.\n", + "\n", + "Channel 4:\n", + "TipSpot(name=tip_rack_D3, location=(032.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot)\n", + "\n", + "Channel 5:\n", + "No tip present.\n", + "\n", + "Channel 6:\n", + "No tip present.\n", + "\n", + "Channel 7:\n", + "No tip present.\n", + "\n" + ] + } + ], + "source": [ + "print_channels_tip_origin(lh)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "8f041cd7-6e04-4156-b253-dc840beac2f0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Channel 0:\n", + "No tip present.\n", + "\n", + "Channel 1:\n", + "[]\n", + "\n", + "Channel 2:\n", + "No tip present.\n", + "\n", + "Channel 3:\n", + "No tip present.\n", + "\n", + "Channel 4:\n", + "[]\n", + "\n", + "Channel 5:\n", + "No tip present.\n", + "\n", + "Channel 6:\n", + "No tip present.\n", + "\n", + "Channel 7:\n", + "No tip present.\n", + "\n" + ] + } + ], + "source": [ + "print_channel_status(lh)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "9c35e2c8-f75a-47ab-a57a-b2f3a26bfa77", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lh.head[1].get_tip().tracker.pending_liquids" ] }, { "cell_type": "markdown", - "id": "29adc390-9c6f-49c5-9112-5cdb7ce7b7a1", + "id": "60eecc01-1226-4b5e-8a19-f4f55cbfb15c", "metadata": { "jp-MarkdownHeadingCollapsed": true }, "source": [ - "### For future reference, how to export states of labware as .json files" + "You also don't need to specify channels in order. If you wanted to skip channel 3, we can do so by just passing in the next channel index and skipping 3." ] }, { "cell_type": "code", - "execution_count": 16, - "id": "22fab8bb-af21-4f79-982e-ca46a11df867", + "execution_count": 23, + "id": "62947627-8930-4bc5-ad97-081f5e157ad7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_D3, location=(032.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack[\"D3\"], use_channels = [4])" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "a7b792f0-a30f-43dd-9c39-b230b4f3dd52", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_E7, location=(068.380, 038.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.drop_tips(tip_spots = tip_rack[\"E7\"], use_channels = [2])" + ] + }, + { + "cell_type": "markdown", + "id": "110cbad9-a473-4911-ace3-cdcae2bbbba3", + "metadata": {}, + "source": [ + "If you want to check if a spot in the tip rack has a tip, call `TipSpot.has_tip()`. This could be useful if you are writing a script with many operations and want to automatically calculate where you should grab your next tip from." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "0b9a66e5-ac0c-456f-aad0-7c3597925da7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "' Save the state of this resource and all children to a JSON file.\\n\\n Args:\\n fn: File name. Caution: file will be overwritten.\\n indent: Same as `json.dump`\\'s `indent` argument (for json pretty printing).\\n\\n Examples:\\n Saving to a json file:\\n\\n >>> deck.save_state_to_file(\"my_state.json\")\\n'" + "False" ] }, - "execution_count": 16, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "\"\"\" Save the state of this resource and all children to a JSON file.\n", - "\n", - " Args:\n", - " fn: File name. Caution: file will be overwritten.\n", - " indent: Same as `json.dump`'s `indent` argument (for json pretty printing).\n", + "tip_rack[\"A1\"][0].has_tip()" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "25ff6efc-bf4b-49b2-9b37-4386d2f080af", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aspirating [Aspiration(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=200, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 200)])].\n" + ] + } + ], + "source": [ + "await lh.aspirate(tube_rack[\"A1\"], vols=[200])" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "5f55c2d7-6e9c-4190-a1d7-ef65e7a93915", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aspirating [Aspiration(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=200, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 200)])].\n", + "Dispensing [Dispense(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=200, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 200)])].\n" + ] + }, + { + "ename": "HasTipError", + "evalue": "Tip spot already has a tip.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mHasTipError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_727/3932198594.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0;32mawait\u001b[0m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreturn_tips\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/liquid_handling/liquid_handler.py\u001b[0m in \u001b[0;36mreturn_tips\u001b[0;34m(self, use_channels, **backend_kwargs)\u001b[0m\n\u001b[1;32m 559\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"No tips have been picked up.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 560\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 561\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;32mawait\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdrop_tips\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtip_spots\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0muse_channels\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mchannels\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mbackend_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 562\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 563\u001b[0m async def discard_tips(\n", + "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/machines/machine.py\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 23\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetup_finished\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"The setup has not finished. See `setup`.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 25\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;32mawait\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 26\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/liquid_handling/liquid_handler.py\u001b[0m in \u001b[0;36mdrop_tips\u001b[0;34m(self, tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs)\u001b[0m\n\u001b[1;32m 489\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mdoes_tip_tracking\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mresource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTipSpot\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m\u001b[0;31m \u001b[0m\u001b[0;31m\\\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 490\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mresource\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtracker\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_disabled\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 491\u001b[0;31m \u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mresource\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtracker\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_tip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtip\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcommit\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 492\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhead\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mchannel\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove_tip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 493\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/resources/tip_tracker.py\u001b[0m in \u001b[0;36madd_tip\u001b[0;34m(self, tip, origin, commit)\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Tip tracker is disabled. Call `enable()`.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_pending_tip\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 84\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mHasTipError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"{self.thing} already has a tip.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 85\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_pending_tip\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtip\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 86\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mHasTipError\u001b[0m: Tip spot already has a tip." + ] + } + ], + "source": [ + "await lh.aspirate(tube_rack[\"A1\"], vols=[200])\n", + "time.sleep(2)\n", "\n", - " Examples:\n", - " Saving to a json file:\n", + "await lh.dispense(plate[\"A1\"], vols=[200])\n", + "#plate[\"A1\"][0].tracker.commit()\n", + "time.sleep(2)\n", "\n", - " >>> deck.save_state_to_file(\"my_state.json\")\n", - "\"\"\"\n" + "await lh.return_tips()" ] }, { "cell_type": "code", - "execution_count": null, - "id": "b9d2169c-1e13-4abd-8095-6844b856d84e", + "execution_count": 55, + "id": "e51ed207-74e3-4ad1-9aa4-7a79ece40016", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Spot A1 contains:\n", + "200uL of Dye_0\n" + ] + } + ], + "source": [ + "print_filled_spots_of_tubeRack(plate)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "7ac2d2e3-dfb0-4d5f-8aee-8769cfd804f1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Aspirating [Aspiration(resource=Well(name=prep_plate_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 100)])].\n", + "Dispensing [Dispense(resource=Tube(name=tube_rack_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Dye_0', 100)])].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack[\"A1\"])\n", + "time.sleep(1)\n", + "\n", + "await lh.aspirate(plate[\"A1\"], vols=[200])\n", + "time.sleep(1)\n", + "\n", + "await lh.dispense(tube_rack[\"A1\"], vols=[200])\n", + "time.sleep(1)\n", + "\n", + "await lh.return_tips()" + ] } ], "metadata": { diff --git a/Decks/pylabrobot-20240516.log b/Decks/pylabrobot-20240516.log new file mode 100644 index 0000000..e69de29 diff --git a/Decks/pylabrobot-20240517.log b/Decks/pylabrobot-20240517.log new file mode 100644 index 0000000..e69de29 diff --git a/Introduction_to_PyLabRobot.ipynb b/Introduction_to_PyLabRobot.ipynb new file mode 100644 index 0000000..2aecb70 --- /dev/null +++ b/Introduction_to_PyLabRobot.ipynb @@ -0,0 +1,944 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "baf9fb61-2fc5-446c-9c4a-18801c7d7afa", + "metadata": {}, + "source": [ + "# **Welcome to PyLabRobot!**\n", + "\n", + "PyLabRobot *(PLR)* is a universal Python interface to liquid-handling robots. Liquid-handling robots aspirate and dispense precise volumes\n", + "of liquid in a Cartesian coordinate system, essentially the same as hand pipetting.\n", + "\n", + "PLR defines a universal interface class called **LiquidHandler** that provides generic methods for controlling robots\n", + "such as aspirate and dispense. This class can be instantiated with one of several backends (or drivers)\n", + "that convert generic commands to machine-specific commands. This makes it easy to write code that will\n", + "be translatable across many different machines.\n", + "\n", + "First we will import `LiquidHandler`, a backend called `ChatterBoxBackend` that prints the text\n", + "output of our commands, a class `Visualizer` that provides a visualization of the robot deck as we\n", + "run commands, and a class `STARLetDeck` that will represent the deck of a Hamilton Microlab STARLet, one of\n", + "the most widely used liquid handling robots." + ] + }, + { + "cell_type": "markdown", + "id": "9268a564-0e57-4ace-9b22-68fcffbfcc2f", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "f8bcf094-3c3a-41c4-b0e8-5d2caeee9ca9", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.liquid_handling import LiquidHandler\n", + "from pylabrobot.liquid_handling.backends import ChatterBoxBackend\n", + "from pylabrobot.visualizer.visualizer import Visualizer\n", + "from pylabrobot.resources.hamilton import STARLetDeck\n", + "from pylabrobot.resources.opentrons import OTDeck\n", + "\n", + "from pylabrobot.resources.opentrons.load import *\n", + "from pylabrobot.resources.opentrons.plates import *\n", + "\n", + "import opentrons" + ] + }, + { + "cell_type": "markdown", + "id": "3c611cf0-ac3f-4e4d-8f48-b9d2241f5670", + "metadata": {}, + "source": [ + "### Liquid Handler: High level abstraction, thing that takes in aspirate and dispense commands, abstract wrapper for all robot backends\n", + "Give input backend, what robot you are planning to use, PLR is hardware agnostic, you use the abstract liquid handler scaffold and then pass in \n", + "the details of your specific robot\n", + "### Deck: What deck is your robot using, again it is hardware agnostic.\n", + "\n", + "* Restart kernel is your friend when working with PLR" + ] + }, + { + "cell_type": "markdown", + "id": "213a4b8c-098e-4e0e-bb9f-446ba5b1709a", + "metadata": {}, + "source": [ + "## Deck Set-Up" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "8b372972-d6dc-454b-95eb-d9941405621b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting up the robot.\n", + "Resource deck was assigned to the robot.\n", + "Resource trash_container was assigned to the robot.\n" + ] + } + ], + "source": [ + "# Call setup to instantiate your specific instance of the robot\n", + "\n", + "# Hamilton\n", + "#lh = LiquidHandler(backend=ChatterBoxBackend(), deck=STARLetDeck())\n", + "\n", + "# OpenTrons\n", + "lh = LiquidHandler(backend=ChatterBoxBackend(), deck=OTDeck())\n", + "\n", + "# Use await because setup can take many minutes. Use await when you have a long function call that you\n", + "# want to be able to do other things while its happening\n", + "await lh.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0324171c-101d-4b3d-9103-a0137c620174", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Websocket server started at http://127.0.0.1:2121\n", + "File server started at http://127.0.0.1:1337 . Open this URL in your browser.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "----------------------------------------\n", + "Exception occurred during processing of request from ('127.0.0.1', 40734)\n", + "Traceback (most recent call last):\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 316, in _handle_request_noblock\n", + " self.process_request(request, client_address)\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 347, in process_request\n", + " self.finish_request(request, client_address)\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 360, in finish_request\n", + " self.RequestHandlerClass(request, client_address, self)\n", + " File \"/mnt/d/Chory Lab/PyLabRobot/pylabrobot/visualizer/visualizer.py\", line 322, in __init__\n", + " super().__init__(*args, directory=path, **kwargs)\n", + " File \"/usr/lib/python3.10/http/server.py\", line 651, in __init__\n", + " super().__init__(*args, **kwargs)\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 747, in __init__\n", + " self.handle()\n", + " File \"/usr/lib/python3.10/http/server.py\", line 425, in handle\n", + " self.handle_one_request()\n", + " File \"/usr/lib/python3.10/http/server.py\", line 413, in handle_one_request\n", + " method()\n", + " File \"/mnt/d/Chory Lab/PyLabRobot/pylabrobot/visualizer/visualizer.py\", line 343, in do_GET\n", + " self.wfile.write(content.encode(\"utf-8\"))\n", + " File \"/usr/lib/python3.10/socketserver.py\", line 826, in write\n", + " self._sock.sendall(b)\n", + "BrokenPipeError: [Errno 32] Broken pipe\n", + "----------------------------------------\n" + ] + } + ], + "source": [ + "# If you want to follow along in real time, instantiate the protocol visualizer\n", + "vis = Visualizer(resource=lh)\n", + "await vis.setup()" + ] + }, + { + "cell_type": "markdown", + "id": "42bf486e-b8cb-4918-a2e6-a9955e71c46b", + "metadata": {}, + "source": [ + "### Put some labware on the deck!" + ] + }, + { + "cell_type": "markdown", + "id": "59b03cfb-8e42-441e-9887-e7a87453d7f7", + "metadata": {}, + "source": [ + "Now we will import a tip carrier, a plate carrier, a plate, and a tip rack." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "7bb36402-2303-4d2e-bd3e-4e10a29e891c", + "metadata": {}, + "outputs": [], + "source": [ + "from pylabrobot.resources import (\n", + " TIP_CAR_480_A00,\n", + " PLT_CAR_L5AC_A00,\n", + " Cos_96_DW_1mL,\n", + " HTF_L,\n", + " opentrons_96_tiprack_300ul,\n", + " opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "8cf826da-7d57-49ce-8303-d40501f50e2b", + "metadata": {}, + "source": [ + "### Hamilton Tip Racks" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "25faa001-8f09-43af-ac2a-5b6b6b21d47a", + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "OTDeck.assign_child_resource() got an unexpected keyword argument 'rails'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_582/3930452725.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mtip_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtip_rack4\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHTF_L\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'tips_04'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwith_tips\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mtip_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtip_rack5\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHTF_L\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'tips_05'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwith_tips\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeck\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massign_child_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtip_car\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrails\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m15\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: OTDeck.assign_child_resource() got an unexpected keyword argument 'rails'" + ] + } + ], + "source": [ + "# Hamilton Tips\n", + "tip_car = TIP_CAR_480_A00(name='tip carrier')\n", + "tip_car[0] = tip_rack1 = HTF_L(name='tips_01', with_tips=False)\n", + "tip_car[1] = tip_rack2 = HTF_L(name='tips_02', with_tips=False)\n", + "tip_car[2] = tip_rack3 = HTF_L(name='tips_03', with_tips=False)\n", + "tip_car[3] = tip_rack4 = HTF_L(name='tips_04', with_tips=False)\n", + "tip_car[4] = tip_rack5 = HTF_L(name='tips_05', with_tips=False)\n", + "lh.deck.assign_child_resource(tip_car, rails=15)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5e7c1218-70e9-4905-b15a-16af3259c79f", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Resource with name 'plate carrier' already defined.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_200/3931165138.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mplt_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplate_2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCos_96_DW_1mL\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'plate_02'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mplt_car\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplate_3\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCos_96_DW_1mL\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'plate_03'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mlh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdeck\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massign_child_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplt_car\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrails\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m8\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/mnt/d/Chory Lab/PyLabRobot/pylabrobot/resources/hamilton/hamilton_decks.py\u001b[0m in \u001b[0;36massign_child_resource\u001b[0;34m(self, resource, location, reassign, rails, replace)\u001b[0m\n\u001b[1;32m 113\u001b[0m \u001b[0mcast\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mResource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_resource\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mresource\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munassign\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 115\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"Resource with name '{resource.name}' already defined.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 116\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mrails\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Resource with name 'plate carrier' already defined." + ] + } + ], + "source": [ + "plt_car = PLT_CAR_L5AC_A00(name='plate carrier')\n", + "plt_car[0] = plate_1 = Cos_96_DW_1mL(name='plate_01')\n", + "plt_car[1] = plate_2 = Cos_96_DW_1mL(name='plate_02')\n", + "plt_car[2] = plate_3 = Cos_96_DW_1mL(name='plate_03')\n", + "lh.deck.assign_child_resource(plt_car, rails=8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "4421b04c-d894-4aaa-a9f4-7f51a16dc773", + "metadata": {}, + "outputs": [], + "source": [ + "tip_rack_1.fill()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "74928e32-3910-434c-b0af-5bdc9c03a51e", + "metadata": {}, + "outputs": [], + "source": [ + "tip_rack4 = lh.deck.get_resource(\"tips_04\")\n", + "tip_rack4.set_tip_state([[True]*6 + [False]*6]*8)\n", + "tip_rack3.set_tip_state([[True, False]*6]*8)\n", + "tip_rack2.set_tip_state([[True, True, False, False]*3]*8)\n" + ] + }, + { + "cell_type": "markdown", + "id": "2d2fba32-6be8-4248-88b2-ab74fb2047af", + "metadata": {}, + "source": [ + "### OpenTrons Tip Racks" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "28b14d77-7cc3-4721-9f10-0867d9137a38", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource tip_rack_1 was assigned to the robot.\n", + "Resource tip_rack_2 was assigned to the robot.\n" + ] + } + ], + "source": [ + "# OT2 Tips\n", + "\n", + "tip_rack_1 = opentrons_96_tiprack_300ul(\"tip_rack_1\")\n", + "tip_rack_2 = opentrons_96_tiprack_300ul(\"tip_rack_2\")\n", + "\n", + "lh.deck.assign_child_at_slot(tip_rack_1, 7)\n", + "lh.deck.assign_child_at_slot(tip_rack_2, 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7d16498c-5b03-4454-a197-dc1faf8a3a6f", + "metadata": {}, + "outputs": [], + "source": [ + "tip_rack2 = lh.deck.get_resource(\"tip_rack_2\")\n", + "tip_rack2.set_tip_state([[True]*6 + [False]*6]*8)" + ] + }, + { + "cell_type": "markdown", + "id": "a06b3c22-5498-43dd-8e1e-ae0203c24f23", + "metadata": {}, + "source": [ + "### OpenTrons Plates" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "16547556-5fd6-4af8-a37b-dd6a1d209981", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource plate_1 was assigned to the robot.\n", + "Resource plate_2 was assigned to the robot.\n" + ] + } + ], + "source": [ + "plate_1 = corning_96_wellplate_360ul_flat('plate_1')\n", + "plate_2 = corning_96_wellplate_360ul_flat('plate_2')\n", + "\n", + "lh.deck.assign_child_at_slot(plate_1, 1)\n", + "lh.deck.assign_child_at_slot(plate_2, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "id": "534179d6-96aa-419f-832e-dbf6b19de0fa", + "metadata": {}, + "outputs": [], + "source": [ + "plate_1_liquids = [[('water', 200)]]*96\n", + "plate_1.set_well_liquids(plate_1_liquids)\n", + "plate_2_liquids = [[(None, 100)], [(None, 100)]]*(96//2)\n", + "plate_2.set_well_liquids(plate_2_liquids)\n" + ] + }, + { + "cell_type": "markdown", + "id": "fa620baf-955e-4671-b86c-8288545c599b", + "metadata": {}, + "source": [ + "### OpenTrons Tube Racks" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "aa3468cd-f660-4c2b-8568-ed3160172174", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resource rack_1 was assigned to the robot.\n", + "Resource rack_2 was assigned to the robot.\n" + ] + } + ], + "source": [ + "rack_1 = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap('rack_1')\n", + "rack_2 = opentrons_24_tuberack_eppendorf_2ml_safelock_snapcap('rack_2')\n", + "\n", + "lh.deck.assign_child_at_slot(rack_1, 4)\n", + "lh.deck.assign_child_at_slot(rack_2, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b65570bc-1589-43ec-9aa1-ece9c50187cd", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'TubeRack' object has no attribute 'set_liquids'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_962/3721324440.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mrack_1_liquids\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'water'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m200\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mrack_1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_liquids\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplate_1_liquids\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'TubeRack' object has no attribute 'set_liquids'" + ] + } + ], + "source": [ + "rack_1_liquids = [[('water', 200)]]*6\n", + "rack_1.set_liquids(plate_1_liquids)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 144, + "id": "02e18147-5337-4c75-9fd4-4243499d3108", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[Tube(name=rack_1_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B1, location=(018.210, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C1, location=(018.210, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D1, location=(018.210, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A2, location=(038.100, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B2, location=(038.100, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C2, location=(038.100, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D2, location=(038.100, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A3, location=(057.990, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B3, location=(057.990, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C3, location=(057.990, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D3, location=(057.990, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A4, location=(077.880, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B4, location=(077.880, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C4, location=(077.880, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D4, location=(077.880, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A5, location=(097.770, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B5, location=(097.770, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C5, location=(097.770, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D5, location=(097.770, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_A6, location=(117.660, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_B6, location=(117.660, 056.150, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_C6, location=(117.660, 036.870, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube),\n", + " Tube(name=rack_1_D6, location=(117.660, 017.590, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube)]" + ] + }, + "execution_count": 144, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rack_1.get_all_children()" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "id": "23cb1bc9-cb4f-4d70-b0f7-7727a2586561", + "metadata": {}, + "outputs": [], + "source": [ + "rack_1.enable_volume_trackers()" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "id": "a467ab96-e1cb-4932-9e47-731831f29148", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['__class__',\n", + " '__delattr__',\n", + " '__dict__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__init_subclass__',\n", + " '__le__',\n", + " '__lt__',\n", + " '__module__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " '__weakref__',\n", + " '_call_did_assign_resource_callbacks',\n", + " '_call_did_unassign_resource_callbacks',\n", + " '_call_will_assign_resource_callbacks',\n", + " '_call_will_unassign_resource_callbacks',\n", + " '_check_assignment',\n", + " '_did_assign_resource_callbacks',\n", + " '_did_unassign_resource_callbacks',\n", + " '_name',\n", + " '_resource_state_updated_callbacks',\n", + " '_size_x',\n", + " '_size_y',\n", + " '_size_z',\n", + " '_state_updated',\n", + " '_will_assign_resource_callbacks',\n", + " '_will_unassign_resource_callbacks',\n", + " 'assign_child_resource',\n", + " 'category',\n", + " 'center',\n", + " 'centers',\n", + " 'children',\n", + " 'copy',\n", + " 'deregister_did_assign_resource_callback',\n", + " 'deregister_did_unassign_resource_callback',\n", + " 'deregister_state_update_callback',\n", + " 'deregister_will_assign_resource_callback',\n", + " 'deregister_will_unassign_resource_callback',\n", + " 'deserialize',\n", + " 'get_absolute_location',\n", + " 'get_all_children',\n", + " 'get_resource',\n", + " 'get_size_x',\n", + " 'get_size_y',\n", + " 'get_size_z',\n", + " 'load_all_state',\n", + " 'load_from_json_file',\n", + " 'load_state',\n", + " 'load_state_from_file',\n", + " 'location',\n", + " 'max_volume',\n", + " 'model',\n", + " 'name',\n", + " 'parent',\n", + " 'register_did_assign_resource_callback',\n", + " 'register_did_unassign_resource_callback',\n", + " 'register_state_update_callback',\n", + " 'register_will_assign_resource_callback',\n", + " 'register_will_unassign_resource_callback',\n", + " 'rotate',\n", + " 'rotated',\n", + " 'rotation',\n", + " 'save',\n", + " 'save_state_to_file',\n", + " 'serialize',\n", + " 'serialize_all_state',\n", + " 'serialize_state',\n", + " 'tracker',\n", + " 'unassign',\n", + " 'unassign_child_resource']" + ] + }, + "execution_count": 125, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dir(rack_1['A1'][0])" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "4354a042-96d4-4e93-916e-1cc2a25f2c1e", + "metadata": {}, + "outputs": [], + "source": [ + "tube1 = rack_1[0][0]" + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "id": "8e5166dd-23a4-4d5b-b869-5fd4ca167f77", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "tube1.tracker.set_liquids([(None, 0)])" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "id": "0a1fd4b0-7089-43be-bfde-de3b43d2b44b", + "metadata": {}, + "outputs": [], + "source": [ + "tube1.tracker.add_liquid(None, 2000)" + ] + }, + { + "cell_type": "code", + "execution_count": 141, + "id": "cdbb78b9-39d4-4036-924a-a358d8c8c9a8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(None, 2000)]" + ] + }, + "execution_count": 141, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tube1.tracker.liquids" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "bebe9703-f00c-4975-9620-5eb3d0416001", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Aspirating [Aspiration(resource=Tube(name=rack_1_A1, location=(018.210, 075.430, 041.270), size_x=6.223, size_y=6.223, size_z=39.1, category=tube), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Water', 100)])].\n", + "Dispensing [Dispense(resource=Well(name=plate_2_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('Water', 100)])].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack_1[\"A1\"])\n", + "time.sleep(1)\n", + "\n", + "await lh.aspirate(rack_1[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.dispense(plate_2[\"A1\"], vols=[100])\n", + "time.sleep(1)\n", + "\n", + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "62fe14fa-2c25-413a-a982-db510f6d8c0b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "ace711fd-1823-4056-b408-7f2f24be5338", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'list' object has no attribute 'add_liquid'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_962/68121547.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrack_1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_liquid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'water'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m200\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'list' object has no attribute 'add_liquid'" + ] + } + ], + "source": [ + "rack_1.get[0].add_liquid([('water', 200)])" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "21e6aa85-cbe1-4c8e-bbe7-1e33eaccdc20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(None, None)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pylabrobot.resources import set_tip_tracking, set_volume_tracking\n", + "set_tip_tracking(True), set_volume_tracking(True)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8055306d-042d-4d83-a685-139a221d8665", + "metadata": {}, + "outputs": [], + "source": [ + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "7eda3c13-e750-4823-8327-5e5baba6ac2d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Pickup(resource=TipSpot(name=tip_rack_1_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n", + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_B2, location=(023.380, 065.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_C3, location=(032.380, 056.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47)), Drop(resource=TipSpot(name=tip_rack_1_D4, location=(041.380, 047.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack_1[\"A1\", \"B2\", \"C3\", \"D4\"])\n", + "time.sleep(2)\n", + "await lh.drop_tips(tip_rack_1[\"A1\", \"B2\", \"C3\", \"D4\"])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "464f5dd7-8d85-407b-b4d6-693340f90c5e", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips [Pickup(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips(tip_rack_1[\"A1\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "1e4c9bb2-58e9-4c4d-a9d4-fa65db824f20", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aspirating [Aspiration(resource=Well(name=plate_1_A2, location=(023.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('water', 100)])].\n" + ] + } + ], + "source": [ + "await lh.aspirate(plate_1[\"A2\"], vols=[100])" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "ce90182d-607b-4e93-bc9a-1d7dfef80e66", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dispensing [Dispense(resource=Well(name=plate_2_A1, location=(014.380, 074.240, 003.550), size_x=4.851, size_y=4.851, size_z=10.67, category=well), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47), volume=100, flow_rate=None, liquid_height=None, blow_out_air_volume=None, liquids=[('water', 100)])].\n" + ] + } + ], + "source": [ + "await lh.dispense(plate_2[\"A1\"], vols=[100])" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "711f3290-e36d-4ae9-88a3-80374709cc36", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips [Drop(resource=TipSpot(name=tip_rack_1_A1, location=(014.380, 074.240, 005.390), size_x=3.698, size_y=3.698, size_z=0, category=tip_spot), offset=None, tip=Tip(has_filter=False, total_tip_length=59.3, maximal_volume=300.0, fitting_depth=7.47))].\n" + ] + } + ], + "source": [ + "await lh.return_tips()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "eb52fd76-d92a-43b3-8550-e688eed4c587", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Picking up tips from tip_rack_1.\n" + ] + } + ], + "source": [ + "await lh.pick_up_tips96(tip_rack_1)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c9cbce02-0f7e-4e51-94e7-2635002d757b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Aspirating 100 from Plate(name=plate_1, size_x=127.76, size_y=85.47, size_z=14.22, location=(000.000, 000.000, 000.000)).\n" + ] + } + ], + "source": [ + "await lh.aspirate96(plate_1, volume=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "ca18de2b-92f4-43c8-a0e7-dab9aa51ec38", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dispensing 100 to Plate(name=plate_2, size_x=127.76, size_y=85.47, size_z=14.22, location=(132.500, 000.000, 000.000)).\n" + ] + } + ], + "source": [ + "await lh.dispense96(plate_2, volume=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "12ef3847-c203-4332-84bd-6631dd90aea5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropping tips to tip_rack_1.\n" + ] + } + ], + "source": [ + "await lh.drop_tips96(tip_rack_1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "08fb2161-4fc7-4312-9864-e85a46f02bcc", + "metadata": {}, + "outputs": [], + "source": [ + "await vis.stop()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8525dc3-7866-4b4d-b870-8c64313bba28", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}