{ "cells": [ { "cell_type": "markdown", "id": "63d8a7a6-1107-4334-8b73-598aa1ca97c4", "metadata": {}, "source": "# Byonoy Absorbance 96 Automate\n\n- [OEM Link](https://byonoy.com/absorbance-automate/)\n- **Communication Protocol / Hardware:** HID / USB-A/C\n- **Communication Level:** Firmware\n- VID:PID `16d0:1199`\n- Takes a single SLAS-format 96-wellplate on the detection unit, enables movement of the cap/illumination unit over it, and reads all 96 wells simultaneously.\n- Up to 6 configurable absorbance wavelengths (dependent on specifications during purchase)." }, { "cell_type": "markdown", "id": "840adda3-0ea1-4e7c-b0cb-34dd2244de69", "metadata": {}, "source": [ "---\n", "## Setup Instructions (Physical)\n", "\n", "The Byonoy Absorbance 96 Automate (A96A) is a an absorbance plate reader consisting of...\n", "1. a `detection_unit` containing the liqht sensors,\n", "2. a `illumination_unit` containing the light source,\n", "3. a `parking_unit` representing a simple resource_holder for the `illumination_unit`, and\n", "4. an `sbs_adapter` which is an optional holder for the `detection_unit` or `parking_unit`, enabling placement of this machine onto a standard SLAS/SBS-format plate holder.\n", "\n", "### Communication\n", "It requires only one cable connections to be operational:\n", "1. USB cable (USB-C at `base` end; USB-A at control PC end)" ] }, { "cell_type": "markdown", "id": "e4aa8066-9eb5-4f8a-8d69-372712bdb3b5", "metadata": {}, "source": [ "---\n", "## Setup Instructions (Programmatic)\n", "\n", "If used with a liquid handler, first setup the liquid handler:" ] }, { "cell_type": "raw", "id": "fe2cca99-8ff6-431f-97c4-ed32211578af", "metadata": {}, "source": [ "import logging\n", "from pylabrobot.io import LOG_LEVEL_IO\n", "from datetime import datetime\n", "\n", "current_date = datetime.today().strftime('%Y-%m-%d')\n", "protocol_mode = \"execution\"\n", "\n", "# Create the shared file handler once\n", "fh = logging.FileHandler(f\"{current_date}_testing_{protocol_mode}.log\", mode=\"a\")\n", "fh.setLevel(LOG_LEVEL_IO)\n", "formatter = logging.Formatter(\n", " \"%(asctime)s [%(levelname)s] %(name)s - %(message)s\"\n", ")\n", "fh.setFormatter(formatter)\n", "\n", "# Configure the main pylabrobot logger\n", "logger_plr = logging.getLogger(\"pylabrobot\")\n", "logger_plr.setLevel(LOG_LEVEL_IO)\n", "if not any(isinstance(h, logging.FileHandler) and h.baseFilename == fh.baseFilename\n", " for h in logger_plr.handlers):\n", " logger_plr.addHandler(fh)\n", "\n", "# Other loggers can reuse the same file handler\n", "logger_manager = logging.getLogger(\"manager\")\n", "logger_device = logging.getLogger(\"device\")\n", "\n", "for logger in [logger_manager, logger_device]:\n", " logger.setLevel(logging.DEBUG) # or logging.INFO\n", " if not any(isinstance(h, logging.FileHandler) and h.baseFilename == fh.baseFilename\n", " for h in logger.handlers):\n", " logger.addHandler(fh)\n", "\n", "# START LOGGING\n", "logger_manager.info(\"START AUTOMATED PROTOCOL\")\n" ] }, { "cell_type": "code", "execution_count": null, "id": "2477b684-443f-4a2f-b16c-99649f443de4", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 1, "id": "1fd4d917", "metadata": {}, "outputs": [], "source": [ "from pylabrobot.liquid_handling import LiquidHandler, LiquidHandlerChatterboxBackend\n", "from pylabrobot.resources import STARDeck\n", "\n", "lh = LiquidHandler(deck=STARDeck(), backend=LiquidHandlerChatterboxBackend())" ] }, { "cell_type": "code", "execution_count": 2, "id": "7355585a-e751-46b6-897b-d09c8be38852", "metadata": {}, "outputs": [], "source": [ "from pylabrobot.resources import (\n", " hamilton_mfx_carrier_L5_base, MFX_CAR_L4_SHAKER , # MFX CARRIERS\n", " MFX_DWP_rackbased_module, hamilton_mfx_plateholder_DWP_metal_tapped,\n", ")" ] }, { "cell_type": "code", "execution_count": 3, "id": "20dbb226-5cc3-49f6-ac62-0c4f4e11eff9", "metadata": {}, "outputs": [], "source": [ "# \n", "\n", "mfx_carrier_2_plateholders = hamilton_mfx_carrier_L5_base(\n", " name=\"mfx_carrier_2_plateholders\",\n", " modules={\n", " 4: hamilton_mfx_plateholder_DWP_metal_tapped(name=f\"mfx_plateholder_1\"),\n", " 2: hamilton_mfx_plateholder_DWP_metal_tapped(name=f\"mfx_plateholder_parking_unit\"),\n", " 0: hamilton_mfx_plateholder_DWP_metal_tapped(name=f\"mfx_plateholder_detection_unit\")\n", " }\n", ")\n", "\n", "lh.deck.assign_child_resource(mfx_carrier_2_plateholders, rails=12)\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "abde0e65", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Setting up the liquid handler.\n" ] } ], "source": [ "await lh.setup()" ] }, { "cell_type": "markdown", "id": "165bd434-5899-4623-ac67-91d2aad55e7c", "metadata": {}, "source": [ "Then generate a plate definition for the plate you want to read:" ] }, { "cell_type": "code", "execution_count": 5, "id": "5be9a197", "metadata": {}, "outputs": [], "source": [ "from pylabrobot.resources.coordinate import Coordinate\n", "from pylabrobot.resources.cellvis.plates import CellVis_96_wellplate_350uL_Fb\n", "\n", "\n", "demo_plate = CellVis_96_wellplate_350uL_Fb(name='demo_plate')\n", "\n", "mfx_carrier_2_plateholders[4] = demo_plate" ] }, { "cell_type": "code", "execution_count": 6, "id": "38a9cf2d-840c-49ce-a886-da29c67fb124", "metadata": {}, "outputs": [], "source": [ "from pylabrobot.plate_reading.byonoy import (\n", " byonoy_sbs_adapter,\n", " byonoy_a96a_detection_unit, \n", " byonoy_a96a_illumination_unit,\n", " byonoy_a96a_parking_unit\n", ")" ] }, { "cell_type": "code", "execution_count": 7, "id": "beb292d0-cc18-439f-b8c4-ae3013aa35d9", "metadata": {}, "outputs": [], "source": [ "# Detection Unit\n", "a96a_sbs_adapter_DU = byonoy_sbs_adapter(name=\"a96a_sbs_adapter_DU\")\n", "a96a_detection_unit = byonoy_a96a_detection_unit(name=\"a96a_detection_unit\")\n", "a96a_sbs_adapter_DU.assign_child_resource(a96a_detection_unit)\n", "\n", "mfx_carrier_2_plateholders[0] = a96a_sbs_adapter_DU\n", "\n", "# Parking Unit\n", "a96a_sbs_adapter_PU = byonoy_sbs_adapter(name=\"a96a_sbs_adapter_PU\")\n", "a96a_parking_unit = byonoy_a96a_parking_unit(name=\"a96a_parking_unit\")\n", "a96a_sbs_adapter_PU.assign_child_resource(a96a_parking_unit)\n", "\n", "mfx_carrier_2_plateholders[2] = a96a_sbs_adapter_PU\n", "\n", "\n", "a96a_illumination_unit = byonoy_a96a_illumination_unit(name=\"a96a_illumination_unit\")\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "642ba0d5-f66a-48a6-a0b5-3ae609c39a0f", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Resource 'a96a_illumination_unit' is very high on the deck: 257.948 mm. Be careful when traversing the deck.\n" ] } ], "source": [ "a96a_detection_unit.assign_child_resource(a96a_illumination_unit)" ] }, { "cell_type": "code", "execution_count": 8, "id": "7ee80f6a-02dd-4f10-8708-121f1ac9423b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Coordinate(x=337.75, y=67.0, z=200.95)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a96a_detection_unit.get_location_wrt(lh.deck)" ] }, { "cell_type": "code", "execution_count": 9, "id": "2a473088-4d8e-43fd-ad20-d90f31f77741", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rail Resource Type Coordinates (mm)\n", "===========================================================================================\n", "(-6) ├── trash_core96 Trash (-58.200, 106.000, 216.400)\n", " │\n", "(12) ├── mfx_carrier_2_plateholders MFXCarrier (347.500, 063.000, 100.000)\n", " │ ├── demo_plate Plate (351.500, 456.000, 182.050)\n", " │ ├── a96a_sbs_adapter_PU ResourceHolder (351.500, 264.000, 183.950)\n", " │ │ ├── a96a_parking_unit ByonoyBaseUnit (337.750, 259.000, 200.950)\n", " │ ├── a96a_sbs_adapter_DU ResourceHolder (351.500, 072.000, 183.950)\n", " │ │ ├── a96a_detection_unit ByonoyBaseUnit (337.750, 067.000, 200.950)\n", " │\n", "(55) ├── waste_block Resource (1315.000, 115.000, 100.000)\n", " │ ├── teaching_tip_rack TipRack (1320.900, 461.100, 100.000)\n", " │ ├── core_grippers HamiltonCoreGrippers (1337.500, 125.000, 205.000)\n", " │\n", "(56) ├── trash Trash (1340.000, 190.600, 137.100)\n", "\n" ] } ], "source": [ "lh.summary()" ] }, { "cell_type": "code", "execution_count": 11, "id": "81c0ef1a-a2cc-4094-b194-ee1781f782b3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rail Resource Type Coordinates (mm)\n", "===============================================================================================\n", "(-6) ├── trash_core96 Trash (-58.200, 106.000, 216.400)\n", " │\n", "(12) ├── mfx_carrier_2_plateholders MFXCarrier (347.500, 063.000, 100.000)\n", " │ ├── demo_plate Plate (351.500, 456.000, 182.050)\n", " │ ├── a96a_sbs_adapter_PU ResourceHolder (351.500, 264.000, 183.950)\n", " │ │ ├── a96a_parking_unit ByonoyBaseUnit (337.750, 259.000, 200.950)\n", " │ ├── a96a_sbs_adapter_DU ResourceHolder (351.500, 072.000, 183.950)\n", " │ │ ├── a96a_detection_unit ByonoyBaseUnit (337.750, 067.000, 200.950)\n", " │ │ │ ├── a96a_illumination_unitResource (337.750, 067.000, 215.050)\n", " │\n", "(55) ├── waste_block Resource (1315.000, 115.000, 100.000)\n", " │ ├── teaching_tip_rack TipRack (1320.900, 461.100, 100.000)\n", " │ ├── core_grippers HamiltonCoreGrippers (1337.500, 125.000, 205.000)\n", " │\n", "(56) ├── trash Trash (1340.000, 190.600, 137.100)\n", "\n" ] } ], "source": [ "lh.summary()" ] }, { "cell_type": "code", "execution_count": 17, "id": "5da9d7e2-fada-41b9-ab68-aff1e995b7d2", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Resource 'a96a_illumination_unit' is very high on the deck: 257.948 mm. Be careful when traversing the deck.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Picking up resource: ResourcePickup(resource=Resource(name='a96a_illumination_unit', location=Coordinate(000.000, 000.000, 014.100), size_x=155.26, size_y=95.48, size_z=42.898, category=None), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=13.5, direction=)\n", "Dropping resource: ResourceDrop(resource=Resource(name='a96a_illumination_unit', location=Coordinate(000.000, 000.000, 014.100), size_x=155.26, size_y=95.48, size_z=42.898, category=None), destination=Coordinate(x=337.75, y=259.0, z=200.95), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=13.5, pickup_direction=, direction=, rotation=0)\n" ] } ], "source": [ "await lh.move_resource(a96a_illumination_unit, a96a_parking_unit, pickup_distance_from_top=13.5)" ] }, { "cell_type": "code", "execution_count": 18, "id": "0cf647e4-1190-458d-a377-21fc31076419", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rail Resource Type Coordinates (mm)\n", "===============================================================================================\n", "(-6) ├── trash_core96 Trash (-58.200, 106.000, 216.400)\n", " │\n", "(12) ├── mfx_carrier_2_plateholders MFXCarrier (347.500, 063.000, 100.000)\n", " │ ├── \n", " │ ├── a96a_sbs_adapter_PU ResourceHolder (351.500, 264.000, 183.950)\n", " │ │ ├── a96a_parking_unit ByonoyBaseUnit (337.750, 259.000, 200.950)\n", " │ │ │ ├── a96a_illumination_unitResource (337.750, 259.000, 215.050)\n", " │ ├── a96a_sbs_adapter_DU ResourceHolder (351.500, 072.000, 183.950)\n", " │ │ ├── a96a_detection_unit ByonoyBaseUnit (337.750, 067.000, 200.950)\n", " │\n", "(55) ├── waste_block Resource (1315.000, 115.000, 100.000)\n", " │ ├── teaching_tip_rack TipRack (1320.900, 461.100, 100.000)\n", " │ ├── core_grippers HamiltonCoreGrippers (1337.500, 125.000, 205.000)\n", " │\n", "(56) ├── trash Trash (1340.000, 190.600, 137.100)\n", "\n" ] } ], "source": [ "lh.summary()" ] }, { "cell_type": "code", "execution_count": null, "id": "e11fc4d6-39fa-47cb-bec7-862a1ac85c9c", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "54f6e3d0-d477-4acf-b6f0-80378c937181", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "raw", "id": "f72c8d26-136d-4b40-9c7e-2876ced1aa01", "metadata": {}, "source": [ "a96a_detection_unit.assign_child_resource(demo_plate)" ] }, { "cell_type": "code", "execution_count": 19, "id": "3668cae5-23c0-4004-a601-cc83ab89615d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Picking up resource: ResourcePickup(resource=Plate(name='demo_plate', size_x=127.6, size_y=85.75, size_z=13.83, location=None), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=9.87, direction=)\n", "Dropping resource: ResourceDrop(resource=Plate(name='demo_plate', size_x=127.6, size_y=85.75, size_z=13.83, location=None), destination=Coordinate(x=337.75, y=67.0, z=200.95), 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=, direction=, rotation=0)\n" ] } ], "source": [ "await lh.move_plate(demo_plate, a96a_detection_unit)" ] }, { "cell_type": "code", "execution_count": 20, "id": "400d6f72-2c5f-4ec7-90fd-42aa7cd83a0f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rail Resource Type Coordinates (mm)\n", "===============================================================================================\n", "(-6) ├── trash_core96 Trash (-58.200, 106.000, 216.400)\n", " │\n", "(12) ├── mfx_carrier_2_plateholders MFXCarrier (347.500, 063.000, 100.000)\n", " │ ├── \n", " │ ├── a96a_sbs_adapter_PU ResourceHolder (351.500, 264.000, 183.950)\n", " │ │ ├── a96a_parking_unit ByonoyBaseUnit (337.750, 259.000, 200.950)\n", " │ │ │ ├── a96a_illumination_unitResource (337.750, 259.000, 215.050)\n", " │ ├── a96a_sbs_adapter_DU ResourceHolder (351.500, 072.000, 183.950)\n", " │ │ ├── a96a_detection_unit ByonoyBaseUnit (337.750, 067.000, 200.950)\n", " │ │ │ ├── demo_plate Plate (360.250, 072.000, 216.950)\n", " │\n", "(55) ├── waste_block Resource (1315.000, 115.000, 100.000)\n", " │ ├── teaching_tip_rack TipRack (1320.900, 461.100, 100.000)\n", " │ ├── core_grippers HamiltonCoreGrippers (1337.500, 125.000, 205.000)\n", " │\n", "(56) ├── trash Trash (1340.000, 190.600, 137.100)\n", "\n" ] } ], "source": [ "lh.summary()" ] }, { "cell_type": "code", "execution_count": null, "id": "e503fceb-092f-4687-b07b-ef4cc4146944", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 21, "id": "f9e0ddc2-bd3f-4802-b2da-021b89eadaa6", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Resource 'a96a_illumination_unit' is very high on the deck: 257.948 mm. Be careful when traversing the deck.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Picking up resource: ResourcePickup(resource=Resource(name='a96a_illumination_unit', location=Coordinate(000.000, 000.000, 014.100), size_x=155.26, size_y=95.48, size_z=42.898, category=None), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=13.5, direction=)\n", "Dropping resource: ResourceDrop(resource=Resource(name='a96a_illumination_unit', location=Coordinate(000.000, 000.000, 014.100), size_x=155.26, size_y=95.48, size_z=42.898, category=None), destination=Coordinate(x=337.75, y=67.0, z=200.95), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=13.5, pickup_direction=, direction=, rotation=0)\n" ] } ], "source": [ "await lh.move_resource(a96a_illumination_unit, a96a_detection_unit, pickup_distance_from_top=13.5)" ] }, { "cell_type": "code", "execution_count": null, "id": "55efae40-199e-4e3d-8070-d153fd1734c2", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "1aaf6867-9254-4f41-9e63-e45bcea26fb6", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 22, "id": "b176939a-8e24-4c21-bd2b-f79799473a83", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rail Resource Type Coordinates (mm)\n", "===============================================================================================\n", "(-6) ├── trash_core96 Trash (-58.200, 106.000, 216.400)\n", " │\n", "(12) ├── mfx_carrier_2_plateholders MFXCarrier (347.500, 063.000, 100.000)\n", " │ ├── \n", " │ ├── a96a_sbs_adapter_PU ResourceHolder (351.500, 264.000, 183.950)\n", " │ │ ├── a96a_parking_unit ByonoyBaseUnit (337.750, 259.000, 200.950)\n", " │ ├── a96a_sbs_adapter_DU ResourceHolder (351.500, 072.000, 183.950)\n", " │ │ ├── a96a_detection_unit ByonoyBaseUnit (337.750, 067.000, 200.950)\n", " │ │ │ ├── demo_plate Plate (360.250, 072.000, 216.950)\n", " │ │ │ ├── a96a_illumination_unitResource (337.750, 067.000, 215.050)\n", " │\n", "(55) ├── waste_block Resource (1315.000, 115.000, 100.000)\n", " │ ├── teaching_tip_rack TipRack (1320.900, 461.100, 100.000)\n", " │ ├── core_grippers HamiltonCoreGrippers (1337.500, 125.000, 205.000)\n", " │\n", "(56) ├── trash Trash (1340.000, 190.600, 137.100)\n", "\n" ] } ], "source": [ "lh.summary()" ] }, { "cell_type": "code", "execution_count": null, "id": "2dab4931-8203-4697-a56c-175b41ace6c2", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 23, "id": "1ead86de-3288-4fe6-9e9d-7bcbcfb7ad8a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Picking up resource: ResourcePickup(resource=Plate(name='demo_plate', size_x=127.6, size_y=85.75, size_z=13.83, location=Coordinate(022.500, 005.000, 016.000)), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=13.5, direction=)\n", "Dropping resource: ResourceDrop(resource=Plate(name='demo_plate', size_x=127.6, size_y=85.75, size_z=13.83, location=Coordinate(022.500, 005.000, 016.000)), destination=Coordinate(x=351.5, y=456.0, z=182.05), destination_absolute_rotation=Rotation(x=0, y=0, z=0), offset=Coordinate(x=0, y=0, z=0), pickup_distance_from_top=13.5, pickup_direction=, direction=, rotation=0)\n" ] } ], "source": [ "await lh.move_resource(demo_plate, mfx_carrier_2_plateholders[4], pickup_distance_from_top=13.5)" ] }, { "cell_type": "code", "execution_count": null, "id": "30d3b220-0ac3-4f5d-a414-a241c4cead5e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 14, "id": "0837df63-1ec6-4c53-9eef-826a57fecf95", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Coordinate(x=360.25, y=72.0, z=216.95)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "demo_plate.get_location_wrt(lh.deck)" ] }, { "cell_type": "code", "execution_count": 15, "id": "4e8af209-b3b0-4969-b107-4bf3f8394985", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Coordinate(x=337.75, y=67.0, z=200.95)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a96a_detection_unit.get_location_wrt(lh.deck)" ] }, { "cell_type": "code", "execution_count": 16, "id": "c720d02c-0a7b-47be-a79c-dde06e6213ce", "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'ByonoyBaseUnit' object has no attribute 'child_location'", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[16]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m a96a_detection_unit.get_location_wrt(lh.deck)+ \u001b[43ma96a_detection_unit\u001b[49m\u001b[43m.\u001b[49m\u001b[43mchild_location\u001b[49m\n", "\u001b[31mAttributeError\u001b[39m: 'ByonoyBaseUnit' object has no attribute 'child_location'" ] } ], "source": [ "a96a_detection_unit.get_location_wrt(lh.deck)+ a96a_detection_unit.child_location" ] }, { "cell_type": "code", "execution_count": null, "id": "40458d1a-a723-4f2d-a15d-ad50b736d6e6", "metadata": {}, "outputs": [], "source": [ "a96a_detection_unit.assign_child_resource(a96a_illumination_unit)" ] }, { "cell_type": "code", "execution_count": null, "id": "7ede3638-c73f-4a34-a33a-b44cafde96df", "metadata": {}, "outputs": [], "source": [ "lh.summary()" ] }, { "cell_type": "code", "execution_count": 21, "id": "3308a6e2-f31b-4a27-94ba-bf8adc56953b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ByonoyA96ABaseUnit(name='a96a_detection_unit', location=Coordinate(-13.750, -05.000, 017.000), size_x=155.26, size_y=95.48, size_z=18.5, category=resource_holder)\n" ] }, { "data": { "text/plain": [ "[None]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[print(x) for x in a96a_sbs_adapter.children]" ] }, { "cell_type": "code", "execution_count": 22, "id": "09deefed-475e-4a1a-a897-94d90ab3a98b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Plate(name='demo_plate', size_x=127.6, size_y=85.75, size_z=13.83, location=Coordinate(022.500, 005.000, 016.000))\n", "Resource(name='a96a_illumination_unit', location=Coordinate(000.000, 000.000, 014.100), size_x=155.26, size_y=95.48, size_z=42.898, category=None)\n" ] }, { "data": { "text/plain": [ "[None, None]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[print(x) for x in a96a_detection_unit.children]" ] }, { "cell_type": "markdown", "id": "bee933e6-b6df-4de7-aad1-40a2f0ba6721", "metadata": {}, "source": [ "Now instantiate the Byonoy absorbance plate reader:" ] }, { "cell_type": "code", "execution_count": 5, "id": "6aa99372", "metadata": {}, "outputs": [], "source": [ "from pylabrobot.plate_reading.byonoy import (\n", " byonoy_absorbance_adapter,\n", " byonoy_absorbance96_base_and_reader\n", ")\n", "\n", "cap_adapter = byonoy_absorbance_adapter(name='cap_adapter')\n", "\n", "base, reader_cap = byonoy_absorbance96_base_and_reader(name='base', assign=True)\n", "\n", "lh.deck.assign_child_resource(cap_adapter, location=Coordinate(400, 0, 0))" ] }, { "cell_type": "code", "execution_count": 6, "id": "a10f9bb9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Connected to Bynoy Absorbance 96 Automate (via HID with VID=5840:PID=4505) on b'DevSrvsID:4308410804'\n", "Identified available wavelengths: [420, 600] nm\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "await reader_cap.setup(verbose=True)\n", "\n", "reader_cap.setup_finished" ] }, { "cell_type": "code", "execution_count": 7, "id": "7089dbcd-4c88-434a-8e71-bdbe05130908", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'path': b'DevSrvsID:4308410804',\n", " 'vendor_id': 5840,\n", " 'product_id': 4505,\n", " 'serial_number': 'BYOMAA00058',\n", " 'release_number': 512,\n", " 'manufacturer_string': 'Byonoy GmbH',\n", " 'product_string': 'Absorbance 96 Automate',\n", " 'usage_page': 65280,\n", " 'usage': 1,\n", " 'interface_number': 0,\n", " 'bus_type': }" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "reader_cap.backend.io.device_info" ] }, { "cell_type": "code", "execution_count": 8, "id": "49ecf2d4-f8ec-4ed1-8ed0-a8eecc04e584", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[420, 600]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "reader_cap.backend.available_wavelengths" ] }, { "cell_type": "markdown", "id": "29947461-c095-4c5c-a98f-dd434eea7472", "metadata": {}, "source": [ "## Test Movement for Plate Reading" ] }, { "cell_type": "raw", "id": "32de1568-625b-4114-ae55-df1c03ea9230", "metadata": {}, "source": [ "# move the reader off the base\n", "await lh.move_resource(reader_cap, Coordinate(200, 0, 0))" ] }, { "cell_type": "raw", "id": "4199936d-efd1-423c-9714-20b0ae581e10", "metadata": { "scrolled": true }, "source": [ "await lh.move_resource(plate, base.plate_holder)" ] }, { "cell_type": "raw", "id": "b11f154e-2025-4092-9a52-fb14af1a1520", "metadata": {}, "source": [ "await lh.move_resource(reader_cap, base.reader_holder)" ] }, { "cell_type": "raw", "id": "0b975857-6b26-49c9-947d-db25763e332d", "metadata": {}, "source": [ "adapter.assign_child_resource(base)" ] }, { "cell_type": "code", "execution_count": 9, "id": "b2e6e986", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(ResourceHolder(name='cap_adapter', location=Coordinate(400.000, 000.000, 000.000), size_x=127.76, size_y=85.59, size_z=14.07, category=resource_holder),\n", " ByonoyBase(name='base_base', location=None, size_x=138, size_y=95.7, size_z=27.7, category=None),\n", " PlateReader(name='base_reader', location=Coordinate(000.000, 000.000, 010.660), size_x=138, size_y=95.7, size_z=0, category=None))" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cap_adapter, base, reader_cap" ] }, { "cell_type": "markdown", "id": "1ccafe3d-56c1-405f-b79e-6d4f8930e49d", "metadata": {}, "source": [ "---\n", "\n", "## Usage / Machine Features" ] }, { "cell_type": "markdown", "id": "30619f34-af58-4a74-b4fd-e2d53033c2de", "metadata": {}, "source": [ "### Query Machine Configuration" ] }, { "cell_type": "code", "execution_count": 10, "id": "2254228f-2864-4174-a615-9d1aed119ad5", "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "[420, 600]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "await reader_cap.backend.get_available_absorbance_wavelengths()" ] }, { "cell_type": "markdown", "id": "fc15c1b4-be77-4180-a5ce-d8a31480d0d4", "metadata": {}, "source": [ "### Measure Absorbance" ] }, { "cell_type": "code", "execution_count": 11, "id": "e5a1d2e2-7b2c-4077-bde6-338f257b1993", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
01234567891011
00.000002-0.0000020.0000830.0000380.0000482.975314e-050.000075NoneNoneNoneNoneNone
10.0000620.0000510.0000400.0000180.0000643.082320e-050.000044NoneNoneNoneNoneNone
20.0000880.0000550.0000690.0000090.0000797.937726e-050.000078NoneNoneNoneNoneNone
30.0000800.0000500.0000090.0000690.0000673.182423e-050.000070NoneNoneNoneNoneNone
40.0000420.0000030.0001100.000005-0.000005-1.815412e-050.000070NoneNoneNoneNoneNone
50.0000550.000054-0.0000230.0000410.0000369.664112e-070.000039NoneNoneNoneNoneNone
60.0000460.0000250.0000190.0000170.0000393.658781e-050.000066NoneNoneNoneNoneNone
70.0000380.0000180.0000550.0000410.000034-3.216584e-05NaNNoneNoneNoneNoneNone
\n", "
" ], "text/plain": [ " 0 1 2 3 4 5 6 \\\n", "0 0.000002 -0.000002 0.000083 0.000038 0.000048 2.975314e-05 0.000075 \n", "1 0.000062 0.000051 0.000040 0.000018 0.000064 3.082320e-05 0.000044 \n", "2 0.000088 0.000055 0.000069 0.000009 0.000079 7.937726e-05 0.000078 \n", "3 0.000080 0.000050 0.000009 0.000069 0.000067 3.182423e-05 0.000070 \n", "4 0.000042 0.000003 0.000110 0.000005 -0.000005 -1.815412e-05 0.000070 \n", "5 0.000055 0.000054 -0.000023 0.000041 0.000036 9.664112e-07 0.000039 \n", "6 0.000046 0.000025 0.000019 0.000017 0.000039 3.658781e-05 0.000066 \n", "7 0.000038 0.000018 0.000055 0.000041 0.000034 -3.216584e-05 NaN \n", "\n", " 7 8 9 10 11 \n", "0 None None None None None \n", "1 None None None None None \n", "2 None None None None None \n", "3 None None None None None \n", "4 None None None None None \n", "5 None None None None None \n", "6 None None None None None \n", "7 None None None None None " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "readings_420_nested_list = await reader_cap.backend.read_absorbance(\n", " wells=plate.children[:55],\n", " wavelength = 420, # units: nm\n", " output_nested_list=True\n", ")\n", "\n", "import pandas as pd\n", "\n", "pd.DataFrame(readings_420_nested_list)" ] }, { "cell_type": "code", "execution_count": 12, "id": "9fccbccb-d569-4883-be04-290c639b99f0", "metadata": {}, "outputs": [], "source": [ "import time" ] }, { "cell_type": "code", "execution_count": 13, "id": "fbf13573-8754-4a8d-8d26-93dff422ab22", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
01234567891011
00.0000970.0000790.0000870.0000920.0000850.0000970.0000860.0000880.0000740.0001110.0000660.000076
10.0000500.0000740.0000630.0000540.0000730.0000660.0000500.0000610.0000820.0000950.0000510.000059
20.0000930.0000490.0000310.0000810.0000670.0000830.0000660.0001040.0000740.0000640.0000400.000069
30.0000960.0000740.0000230.0000750.0001000.0000530.0000640.0000870.0000700.0000730.0000500.000054
40.0000870.0000740.0001610.0000700.0000800.0000690.0001010.0001060.0001120.0001030.0000590.000062
50.0000580.0000670.0000230.0000680.0000360.0000530.0000350.0000440.0000450.0000970.0000390.000033
60.0000800.0000360.0000120.0000790.0000620.0000610.0000460.0000840.0000430.0000500.0000260.000064
70.0000870.0000530.0000720.0000600.0000760.0000310.0000340.0000840.0000860.0000540.0000320.000079
\n", "
" ], "text/plain": [ " 0 1 2 3 4 5 6 \\\n", "0 0.000097 0.000079 0.000087 0.000092 0.000085 0.000097 0.000086 \n", "1 0.000050 0.000074 0.000063 0.000054 0.000073 0.000066 0.000050 \n", "2 0.000093 0.000049 0.000031 0.000081 0.000067 0.000083 0.000066 \n", "3 0.000096 0.000074 0.000023 0.000075 0.000100 0.000053 0.000064 \n", "4 0.000087 0.000074 0.000161 0.000070 0.000080 0.000069 0.000101 \n", "5 0.000058 0.000067 0.000023 0.000068 0.000036 0.000053 0.000035 \n", "6 0.000080 0.000036 0.000012 0.000079 0.000062 0.000061 0.000046 \n", "7 0.000087 0.000053 0.000072 0.000060 0.000076 0.000031 0.000034 \n", "\n", " 7 8 9 10 11 \n", "0 0.000088 0.000074 0.000111 0.000066 0.000076 \n", "1 0.000061 0.000082 0.000095 0.000051 0.000059 \n", "2 0.000104 0.000074 0.000064 0.000040 0.000069 \n", "3 0.000087 0.000070 0.000073 0.000050 0.000054 \n", "4 0.000106 0.000112 0.000103 0.000059 0.000062 \n", "5 0.000044 0.000045 0.000097 0.000039 0.000033 \n", "6 0.000084 0.000043 0.000050 0.000026 0.000064 \n", "7 0.000084 0.000086 0.000054 0.000032 0.000079 " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "1.5100939273834229" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "start_time = time.time()\n", "\n", "readings_600_nested_list = await reader_cap.backend.read_absorbance(\n", " wells=plate.children[:],\n", " wavelength = 600, # units: nm\n", " output_nested_list=True\n", ")\n", "display(pd.DataFrame(readings_600_nested_list))\n", "\n", "\n", "time.time() - start_time" ] }, { "cell_type": "code", "execution_count": null, "id": "a6f77438-147e-4e3d-bcf8-dbfa0f443a46", "metadata": {}, "outputs": [], "source": "start_time = time.time()\n\nreadings_600_nested_list = await reader_cap.backend.read_absorbance(\n wells=plate.children[:],\n wavelength = 600, # units: nm\n output_nested_list=True\n)\ndisplay(pd.DataFrame(readings_600_nested_list))\n\ntime.time() - start_time" }, { "cell_type": "code", "execution_count": null, "id": "60719244-d75d-4e34-bb89-266608837ff0", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 15, "id": "1749dc00-c760-4993-b374-fb2ee09d2175", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
420nm600nm
A10.0000640.000100
B10.0000970.000033
C10.0001650.000086
D10.0001050.000082
E10.0001060.000132
.........
D80.0000730.000117
E80.0000850.000107
F80.0000570.000053
G80.0001240.000102
H80.0000790.000128
\n", "

64 rows × 2 columns

\n", "
" ], "text/plain": [ " 420nm 600nm\n", "A1 0.000064 0.000100\n", "B1 0.000097 0.000033\n", "C1 0.000165 0.000086\n", "D1 0.000105 0.000082\n", "E1 0.000106 0.000132\n", ".. ... ...\n", "D8 0.000073 0.000117\n", "E8 0.000085 0.000107\n", "F8 0.000057 0.000053\n", "G8 0.000124 0.000102\n", "H8 0.000079 0.000128\n", "\n", "[64 rows x 2 columns]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "first_n_columns = 8\n", "\n", "readings_420 = await reader_cap.backend.read_absorbance(\n", " wells=plate.children[:8*first_n_columns],\n", " wavelength = 420 # units: nm\n", ")\n", "readings_600 = await reader_cap.backend.read_absorbance(\n", " wells=plate.children[:8*first_n_columns],\n", " wavelength = 600 # units: nm\n", ")\n", "\n", "well_indexed_df = pd.DataFrame([readings_420, readings_600], index=[\"420nm\", \"600nm\"]).T\n", "well_indexed_df" ] }, { "cell_type": "markdown", "id": "1a33230d-8243-4d21-88e1-4a4eb6cba7c8", "metadata": {}, "source": [ "## Disconnect from Reader" ] }, { "cell_type": "code", "execution_count": 16, "id": "21a72488", "metadata": {}, "outputs": [], "source": [ "await reader_cap.stop()" ] }, { "cell_type": "code", "execution_count": null, "id": "62b8732a-8bd7-427d-85c3-ab900f2a48b6", "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.12.11" } }, "nbformat": 4, "nbformat_minor": 5 }