{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Plate Carriers\n", "\n", "Plate carriers slide into rails on railed-decks like Hamilton STAR(let) and Tecan EVO, and are used to hold Plates." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using a plate carrier\n", "\n", "The PyLabRobot Resource Library (PLR-RL) has a big number of predefined carriers. You can find these in the [PLR-RL docs](https://docs.pylabrobot.org/resources/index.html). [Hamilton Plate Carriers](https://docs.pylabrobot.org/resources/library/ml_star.html#plate-carriers) may be of particular interest." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pylabrobot.resources.ml_star import PLT_CAR_L5AC_A00" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_plate_carrier = PLT_CAR_L5AC_A00(name=\"my_plate_carrier\")\n", "my_plate_carrier.capacity" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To assign a plate at a specific location in the plate carrier, simply set it at a specific index. In PLR, carriers are 0-indexed where the site at the front of the robot (nearest to the door) is 0." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from pylabrobot.resources import Cor_96_wellplate_360ul_Fb\n", "\n", "my_plate = Cor_96_wellplate_360ul_Fb(name=\"my_plate\")\n", "my_plate_carrier[0] = my_plate" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can assign plates to a variable and to the carrier in a single line." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "my_plate_carrier[1] = my_other_plate = Cor_96_wellplate_360ul_Fb(name=\"my_other_plate\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The children (in the arborescence) of a plate carrier are {class}`pylabrobot.resources.carrier.PlateHolder` objects. These model the sites for plates on the carrier. A `PlateHolder` may or may not have a `Plate` as a child, depending on whether the spot is occupied." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "PlateHolder(name=carrier-my_plate_carrier-spot-0, location=(004.000, 008.500, 086.150), size_x=127.0, size_y=86.0, size_z=0, category=plate_holder)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_plate_carrier[0]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "PlateHolder(name=carrier-my_plate_carrier-spot-0, location=(004.000, 008.500, 086.150), size_x=127.0, size_y=86.0, size_z=0, category=plate_holder)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_plate.parent" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use the `PlateHolder.resource` attribute to access the `Plate` object, if it exists." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Plate(name=my_plate, size_x=127.76, size_y=85.48, size_z=14.2, location=(000.000, 000.000, -03.030))" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_plate_carrier[0].resource" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_plate_carrier[2].resource is None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Moving plates onto carrier sites\n", "\n", "If your liquid handling robot has a robotic arm, or if you are using an external robot arm that can interface with carriers, you can move plates out of or onto carriers using the `move_plate` method. For this, you can specify the destination by indexing into the carrier. This will return a `PlateHolder` object.\n", "\n", "As an example, we will use the LiquidHandlerChatterboxBackend, but this code will work on any robot that supports moving plates." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Resource my_plate_carrier was assigned to the liquid handler.\n", "Setting up the liquid handler.\n", "Resource deck was assigned to the liquid handler.\n", "Resource trash was assigned to the liquid handler.\n", "Resource trash_core96 was assigned to the liquid handler.\n", "Resource my_plate_carrier was assigned to the liquid handler.\n" ] } ], "source": [ "from pylabrobot.liquid_handling import LiquidHandler, LiquidHandlerChatterboxBackend\n", "from pylabrobot.resources import STARDeck\n", "lh = LiquidHandler(backend=LiquidHandlerChatterboxBackend(), deck=STARDeck())\n", "lh.deck.assign_child_resource(my_plate_carrier, rails=1)\n", "await lh.setup()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Moving Move(resource=Plate(name=my_plate, size_x=127.76, size_y=85.48, size_z=14.2, location=(000.000, 000.000, -03.030)), destination=PlateHolder(name=carrier-my_plate_carrier-spot-2, location=(004.000, 200.500, 086.150), size_x=127.0, size_y=86.0, size_z=0, category=plate_holder), intermediate_locations=[], resource_offset=Coordinate(x=0, y=0, z=0), destination_offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=0, get_direction=, put_direction=).\n" ] } ], "source": [ "await lh.move_resource(my_plate, my_plate_carrier[2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pedestal z height\n", "\n", "> ValueError(\"pedestal_size_z must be provided. See https://docs.pylabrobot.org/resources/plate_carriers.html#pedestal_size_z for more information.\")\n", "\n", "Many plate carriers feature a \"pedestal\" or \"platform\" on the sites. Plates can sit on this pedestal, or directly on the bottom of the site. This depends on the pedestal _and_ plate geometry, so it is important that we know the height of the pedestal.\n", "\n", "The pedestal information is not typically available in labware databases (like the VENUS or EVOware databases), and so we rely on users to measure and contribute this information.\n", "\n", "Here's how you measure the pedestal height:\n", "\n", "![Pedestal height measurement](/resources/img/pedestal/measure.jpeg)\n", "\n", "Once you have measured the pedestal height, you can contribute this information to the PyLabRobot Labware database. Here's a guide on contributing to the open-source project: [\"How to Open Source\"](/contributor_guide/how-to-open-source.md).\n", "\n", "For background, see PR 143: [https://github.com/PyLabRobot/pylabrobot/pull/143](https://github.com/PyLabRobot/pylabrobot/pull/143)." ] } ], "metadata": { "kernelspec": { "display_name": "env", "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.9.19" } }, "nbformat": 4, "nbformat_minor": 2 }