Skip to content

Lid inheritance fix #583

New issue

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

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

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
287 changes: 273 additions & 14 deletions docs/resources/resource-stack/resource-stack.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 29,
"id": "2ebfc327",
"metadata": {},
"outputs": [],
Expand All @@ -42,7 +42,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 30,
"id": "1737611f",
"metadata": {},
"outputs": [
Expand All @@ -52,7 +52,7 @@
"([], [], [])"
]
},
"execution_count": 2,
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -75,7 +75,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 31,
"id": "255c656a",
"metadata": {},
"outputs": [
Expand All @@ -85,7 +85,7 @@
"(['A', 'B'], 20)"
]
},
"execution_count": 3,
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -112,7 +112,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 32,
"id": "c6479d0b",
"metadata": {},
"outputs": [
Expand All @@ -122,7 +122,7 @@
"20"
]
},
"execution_count": 4,
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -152,7 +152,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 33,
"id": "e35e3a75",
"metadata": {},
"outputs": [
Expand All @@ -162,7 +162,7 @@
"'L2'"
]
},
"execution_count": 5,
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -177,7 +177,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 34,
"id": "7c7c11d5",
"metadata": {},
"outputs": [
Expand All @@ -187,7 +187,7 @@
"'L1'"
]
},
"execution_count": 6,
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -218,7 +218,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 35,
"id": "7b92cac5",
"metadata": {},
"outputs": [
Expand All @@ -228,7 +228,7 @@
"True"
]
},
"execution_count": 7,
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
Expand Down Expand Up @@ -256,6 +256,265 @@
"\n",
"This allows temporary storage of plates or lids during automated workflows."
]
},
{
"cell_type": "markdown",
"id": "d3d4b23b",
"metadata": {},
"source": [
"## Moving plates and lids to the stacking area\n",
"The functions `move_lid()` and `move_plate()` can be used to move plates and lids to a ResourceStack during robot runtime.\n",
"\n",
"Below is an example on the STARBackend:"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "f421a8be",
"metadata": {},
"outputs": [],
"source": [
"from pylabrobot.liquid_handling import LiquidHandler\n",
"from pylabrobot.liquid_handling.backends import LiquidHandlerChatterboxBackend, STARBackend\n",
"from pylabrobot.resources.hamilton import STARLetDeck\n",
"\n",
"from pylabrobot.resources import (\n",
" TIP_CAR_480_A00, \n",
" STF,\n",
" PLT_CAR_L5AC_A00,\n",
" Cor_96_wellplate_360ul_Fb,\n",
" Cor_96_wellplate_2mL_Vb,\n",
" ResourceStack,\n",
")"
]
},
{
"cell_type": "markdown",
"id": "2c24b77d",
"metadata": {},
"source": [
"Setup liquid handler and deck"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "0dda3ff5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"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 waste_block was assigned to the liquid handler.\n"
]
}
],
"source": [
"lh = LiquidHandler(backend=LiquidHandlerChatterboxBackend(), deck=STARLetDeck())\n",
"await lh.setup()"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "1ee5adf5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Resource tip_carrier was assigned to the liquid handler.\n"
]
}
],
"source": [
"tip_car = TIP_CAR_480_A00(name=\"tip_carrier\")\n",
"tip_rack = STF(name=\"tip_rack\")\n",
"tip_car[0] = tip_rack\n",
"lh.deck.assign_child_resource(tip_car, rails=1)"
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "7e139df0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Resource plate_carrier was assigned to the liquid handler.\n"
]
}
],
"source": [
"plate_stack = ResourceStack(\"plate_stack\", \"z\", [\n",
" Cor_96_wellplate_2mL_Vb(name='stack_plate_1')\n",
"])\n",
"\n",
"plt_car = PLT_CAR_L5AC_A00(name=\"plate_carrier\")\n",
"plt_car[0] = plate_stack\n",
"plt_car[1] = plate_1 = Cor_96_wellplate_360ul_Fb(name=\"plate_1\", with_lid=True)\n",
"plt_car[2] = plate_2 = Cor_96_wellplate_360ul_Fb(name=\"plate_2\", with_lid=True)\n",
"lh.deck.assign_child_resource(plt_car, rails=8)\n",
"\n",
"plate_1_lid = plate_1.lid\n",
"plate_2_lid = plate_2.lid"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "c0811184",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Rail Resource Type Coordinates (mm)\n",
"=================================================================================\n",
"(-6) ├── trash_core96 Trash (-58.200, 106.000, 229.000)\n",
" │\n",
"(1) ├── tip_carrier TipCarrier (100.000, 063.000, 100.000)\n",
" │ ├── tip_rack TipRack (106.200, 073.000, 214.950)\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │\n",
"(8) ├── plate_carrier PlateCarrier (257.500, 063.000, 100.000)\n",
" │ ├── plate_stack ResourceStack (261.500, 071.500, 184.950)\n",
" │ │ ├── stack_plate_1 Plate (261.500, 071.500, 184.950)\n",
" │ ├── plate_1 Plate (261.500, 167.500, 183.120)\n",
" │ │ ├── plate_1_lid Lid (261.500, 167.500, 189.720)\n",
" │ ├── plate_2 Plate (261.500, 263.500, 183.120)\n",
" │ │ ├── plate_2_lid Lid (261.500, 263.500, 189.720)\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │\n",
"(31) ├── waste_block Resource (775.000, 115.000, 100.000)\n",
" │ ├── teaching_tip_rack TipRack (780.900, 461.100, 100.000)\n",
" │\n",
"(32) ├── trash Trash (800.000, 190.600, 137.100)\n",
"\n"
]
}
],
"source": [
"lh.summary()"
]
},
{
"cell_type": "markdown",
"id": "a34006a6",
"metadata": {},
"source": [
"If the top of the stack is a plate without a lid, a lid moved with `move_lid()` to the stack will automatically become a child of the top plate.\n",
"\n",
"Moving a plate with a lid with `move_plate()` will move both the plate and lid to the top of the stack."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a5ac7d15",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Picking up resource: ResourcePickup(resource=Lid(name=plate_1_lid, location=Coordinate(000.000, 000.000, 006.600), size_x=127.76, size_y=85.48, size_z=8.9, category=lid), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=2.37, direction=<GripDirection.FRONT: 1>)\n",
"Dropping resource: ResourceDrop(resource=Lid(name=plate_1_lid, location=Coordinate(000.000, 000.000, 006.600), size_x=127.76, size_y=85.48, size_z=8.9, category=lid), destination=Coordinate(x=261.5, y=71.5, z=220.85), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=2.37, pickup_direction=<GripDirection.FRONT: 1>, drop_direction=<GripDirection.FRONT: 1>, rotation=0)\n",
"Resource plate_1_lid was unassigned from the liquid handler.\n",
"Resource plate_1_lid was assigned to the liquid handler.\n",
"Picking up resource: ResourcePickup(resource=Plate(name=plate_2, size_x=127.76, size_y=85.48, size_z=14.2, location=Coordinate(000.000, 000.000, -03.030)), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=9.87, direction=<GripDirection.FRONT: 1>)\n",
"Dropping resource: ResourceDrop(resource=Plate(name=plate_2, size_x=127.76, size_y=85.48, size_z=14.2, location=Coordinate(000.000, 000.000, -03.030)), destination=Coordinate(x=261.5, y=71.5, z=229.75), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=9.87, pickup_direction=<GripDirection.FRONT: 1>, drop_direction=<GripDirection.FRONT: 1>, rotation=0)\n",
"Resource plate_2 was unassigned from the liquid handler.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Resource 'plate_2_lid' is very high on the deck: 245.25 mm. Be careful when traversing the deck.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Resource plate_2 was assigned to the liquid handler.\n"
]
}
],
"source": [
"await lh.move_lid(plate_1_lid, plate_stack)\n",
"await lh.move_plate(plate_2, plate_stack)"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "38f8e056",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Rail Resource Type Coordinates (mm)\n",
"==================================================================================\n",
"(-6) ├── trash_core96 Trash (-58.200, 106.000, 229.000)\n",
" │\n",
"(1) ├── tip_carrier TipCarrier (100.000, 063.000, 100.000)\n",
" │ ├── tip_rack TipRack (106.200, 073.000, 214.950)\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │\n",
"(8) ├── plate_carrier PlateCarrier (257.500, 063.000, 100.000)\n",
" │ ├── plate_stack ResourceStack (261.500, 071.500, 184.950)\n",
" │ │ ├── stack_plate_1 Plate (261.500, 071.500, 184.950)\n",
" │ │ │ ├── plate_1_lid Lid (261.500, 071.500, 220.850)\n",
" │ │ ├── plate_2 Plate (261.500, 071.500, 229.750)\n",
" │ │ │ ├── plate_2_lid Lid (261.500, 071.500, 236.350)\n",
" │ ├── plate_1 Plate (261.500, 167.500, 183.120)\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │ ├── <empty>\n",
" │\n",
"(31) ├── waste_block Resource (775.000, 115.000, 100.000)\n",
" │ ├── teaching_tip_rack TipRack (780.900, 461.100, 100.000)\n",
" │\n",
"(32) ├── trash Trash (800.000, 190.600, 137.100)\n",
"\n"
]
}
],
"source": [
"lh.summary()"
]
},
{
"cell_type": "markdown",
"id": "7f41abdb",
"metadata": {},
"source": [
"**Warning:** Currently there are no checks in PyLabRobot for plate and lid compatibility when moving a lid to a ResourceStack. It is possible that the lid from one plate could be added to a plate of a different type on the ResourceStack with `move_lid()`. Users are responsible for making sure the lids and plates are compatible and will stack correctly.\n",
"\n",
"TODO: Create a more permanent and robust fix: https://github.com/PyLabRobot/pylabrobot/pull/546#issuecomment-2945105532"
]
}
],
"metadata": {
Expand All @@ -279,7 +538,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.15"
"version": "3.10.12"
}
},
"nbformat": 4,
Expand Down
Loading