{ "cells": [ { "cell_type": "markdown", "id": "866f6f49", "metadata": {}, "source": [ "# Hello World, \"Hamilton Heater Shaker\"!\n", "\n", "The Hamilton Heater Shaker is a `HeaterShaker` machine that enables:\n", "- heating, \n", "- locking & unlocking, and\n", "- (orbital) shaking\n", "\n", "...of plates (active cooling is not possible with this machine)." ] }, { "cell_type": "markdown", "id": "b235295c-ed0f-4bcc-9542-3ebb13b47181", "metadata": {}, "source": [ "- [manufacturer_link](https://www.hamiltoncompany.com/automated-liquid-handling/small-devices/hamilton-heater-shaker?srsltid=AfmBOooBVzRaBrPj4UYumvbcbECIxj4lk_0jpJDjMrLksnFJPOgNURm6)\n", "- Temperature control = RT+5°C to 105°C (all variants)\n", "- Variants:\n", " - Cat. no.: 199027 \n", " - shaking orbit = 1.5 mm \n", " - shaking speed = 100 - 1800 rpm\n", " - Cat. no.: 199033 \n", " - shaking orbit = 2.0 mm \n", " - shaking speed = 100 - 2500 rpm\n", " - Cat. no.: 199034 \n", " - shaking orbit = 3.0 mm \n", " - shaking speed = 100 - 2400 rpm \n", " - max. loading = 500 grams \n", "\n", "- Footprint: size_x = 146.2, size_y = 103.8, size_z=74.11" ] }, { "cell_type": "markdown", "id": "1e836e11-90eb-4c4a-888e-1f7d0ac54798", "metadata": {}, "source": [ "---\n", "## Setup Instructions (Physical)" ] }, { "cell_type": "markdown", "id": "d2087a07", "metadata": {}, "source": [ "A Hamilton Heater Shaker (hhs) can be used through two different **control interfaces**:\n", "- a **control box**, called the `HamiltonHeaterShakerBox`: this supports connection of up to **8 heater shakers** per control box, OR\n", "- **directly plugging** the hhs **into a Hamilton STAR liquid handler**: STAR liquid handlers have 2 RS232 ports on their left side, and can therefore support up to **2 heater shakers** simultaneously.\n", "\n", "When using the **heater shaker box control interface** a USB-B cable is plugged into one of the heater shakers and connected to the host computer.\n", "This heater shaker is connected via a serial port to the control box. Other heater shakers are also plugged into the control box using serial cables, but not plugged into the computer.\n", "The first heater shakers serves as a gateway.\n", "\n", "When using the **Hamilton STAR interface**, the Heater Shaker is connected via a serial interface:\n", "- Connection: STAR (RS232) ⇄ Host computer (USB-A)\n", "\n", "The heater shaker is then controlled through the STAR Liquid Handler." ] }, { "cell_type": "markdown", "id": "eb905396-ef6d-4f45-b0f0-933e6b689418", "metadata": {}, "source": [ "---\n", "## Setup Instructions (Programmatic)\n", "\n", "In either case, `HamiltonHeaterShakerBackend` will be the backend and `HeaterShaker` will be the frontend.\n", "Depending on the interface you use, pass a different argument to `HamiltonHeaterShakerBackend`.\n", "\n", "**hs_box_control**:\n", "As multiple heater shakers can be controlled through one USB connection to the computer (a cable to HHS 1 when using the control box), the `index` of a specific heater shaker needs to be specified.\n", "Note that this also requires turing a DIP switch on the bottom of the HHS module.\n", "\n", "**star_control**:\n", "Each heater shaker is connected via a separate cable to the STAR liquid handler.\n", "The back RS232 port corresponds to `index=1` and the front RS232 port corresponds to `index=2`." ] }, { "cell_type": "code", "execution_count": 1, "id": "12fa20e6-5708-4581-93e2-f342cf74c062", "metadata": {}, "outputs": [], "source": [ "interface_choice = \"star_control\" # hs_box_control VS star_control" ] }, { "cell_type": "code", "execution_count": null, "id": "000202e0", "metadata": {}, "outputs": [], "source": [ "if interface_choice == \"hs_box_control\":\n", " \n", " # Setting up a backend with the HamiltonHeaterShakerBox\n", " from pylabrobot.heating_shaking import HamiltonHeaterShakerBackend, HamiltonHeaterShakerBox\n", " \n", " control_interface = hhs_box = HamiltonHeaterShakerBox()\n", "\n", "elif interface_choice == \"star_control\":\n", " \n", " # Alternative: setting up a backend with a STAR\n", " from pylabrobot.liquid_handling import LiquidHandler, STARBackend\n", " from pylabrobot.resources import STARDeck\n", " from pylabrobot.heating_shaking import HamiltonHeaterShakerBackend\n", " \n", " control_interface = star_backend = STARBackend()\n", "\n", " # Control via a STAR requires instantiation of the STAR liquid handler\n", " lh = LiquidHandler(backend=star_backend, deck=STARDeck())\n", "\n", "else:\n", " raise ValueError(f\"Interface choice invalid: {interface_choice}\")\n", "\n", "backend = HamiltonHeaterShakerBackend(\n", " index=1,\n", " interface=control_interface\n", ")" ] }, { "cell_type": "code", "execution_count": 3, "id": "819863d9", "metadata": {}, "outputs": [], "source": [ "from pylabrobot.heating_shaking import HeaterShaker\n", "from pylabrobot.resources.coordinate import Coordinate\n", "\n", "hs = HeaterShaker(\n", " name=\"Hamilton HeaterShaker\",\n", " backend=backend,\n", " size_x=146.2,\n", " size_y=103.8,\n", " size_z=74.11,\n", " child_location=Coordinate(x=9.66, y=9.22, z=74.11),\n", ")" ] }, { "cell_type": "markdown", "id": "29806703", "metadata": {}, "source": [ "Note that you will need to call `hhs_box.setup()` before calling `HeaterShaker.setup()`.\n", "When using a `STAR`, just use `star.setup()` or, more likely, `lh.setup()`.\n", "This is opening the USB connection to the device you are using as an interface.\n", "\n", "Note that setup should only be called ONCE:\n", "- when using a STAR as a liquid handler, just call `lh.setup()`.\n", "(Do not call it again when using the heater shaker.)\n", "- when using multiple heater shakers with the control box, call `.setup()` once for the control box, and then call `HeaterShaker.setup()` for each heater shaker.\n", "(Do not call `setup` again for the control box.)" ] }, { "cell_type": "code", "execution_count": 4, "id": "76173726", "metadata": {}, "outputs": [], "source": [ "if interface_choice == \"hs_box_control\":\n", " \n", " # When using the HamiltonHeaterShakerBox, you need to call setup() on the box\n", " await hhs_box.setup()\n", "\n", "elif interface_choice == \"star_control\":\n", "\n", " # Alternative: when using the STAR, you need to call setup() on lh\n", " await lh.setup()" ] }, { "cell_type": "markdown", "id": "70115dff", "metadata": {}, "source": [ "After calling `setup` on your interface, call `HeaterShaker.setup()` for each heater shaker machine.\n", "This will initialize the `HeaterShaker` machine itself." ] }, { "cell_type": "code", "execution_count": 6, "id": "c6d38f82", "metadata": {}, "outputs": [], "source": [ "await hs.setup()" ] }, { "cell_type": "markdown", "id": "599b7d31-27b1-44f9-a720-cd2ef55e122f", "metadata": {}, "source": [ "---\n", "## Usage" ] }, { "cell_type": "markdown", "id": "5e201ecb", "metadata": {}, "source": [ "### Heating Control" ] }, { "cell_type": "code", "execution_count": 7, "id": "2f544e4a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "25.6" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "await hs.get_temperature() # Temperature of sensor in the middle of the heater shaker in C" ] }, { "cell_type": "markdown", "id": "6cadda38", "metadata": {}, "source": [ "The HHS also supports reading the temperature at the edge of the heater shaker:" ] }, { "cell_type": "code", "execution_count": 8, "id": "81e0743c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "25.7" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "await hs.backend.get_edge_temperature()" ] }, { "cell_type": "code", "execution_count": 6, "id": "f076c7bd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'T1TAid0004er00'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "await hs.set_temperature(37) # Temperature in degrees C" ] }, { "cell_type": "code", "execution_count": 7, "id": "cf85de20", "metadata": {}, "outputs": [], "source": [ "await hs.wait_for_temperature() # Wait for the temperature to stabilize" ] }, { "cell_type": "markdown", "id": "d1b72d26", "metadata": {}, "source": [ "### Shaking Control" ] }, { "cell_type": "code", "execution_count": 9, "id": "17646f3d", "metadata": {}, "outputs": [], "source": [ "await hs.lock_plate()" ] }, { "cell_type": "code", "execution_count": 10, "id": "49b330b7", "metadata": {}, "outputs": [], "source": [ "await hs.shake(\n", " speed=100, # rpm\n", " direction=0, # seconds\n", " acceleration=1000, # rpm/sec\n", ") " ] }, { "cell_type": "code", "execution_count": 12, "id": "71d8a964", "metadata": {}, "outputs": [], "source": [ "await hs.stop_shaking()" ] }, { "cell_type": "code", "execution_count": 11, "id": "a0d8ab2d", "metadata": {}, "outputs": [], "source": [ "await hs.unlock_plate()" ] }, { "cell_type": "markdown", "id": "c9176b41-c939-45f0-aa6a-a5599188f38c", "metadata": {}, "source": [ "### Closing Connection to Machine" ] }, { "cell_type": "code", "execution_count": 9, "id": "94577ff3-7add-4f3c-815c-c0301ca58adf", "metadata": {}, "outputs": [], "source": [ "await hs.stop()" ] }, { "cell_type": "markdown", "id": "a6ee0951", "metadata": {}, "source": [ "---\n", "## Using Multiple Hamilton Heater Shakers\n", "\n", "### 1x hs_box - Multiple HHS\n", "\n", "When using multiple heater shakers, you can use the `HamiltonHeaterShakerBackend` class to control them. This class will automatically handle the communication with the control box and the individual heater shakers.\n", "\n", "As above, initialize the `HamiltonHeaterShakerBox` class. Then, initialize as many `HamiltonHeaterShakerBackend` classes as you want to control, specifying the index for each. Note that each `HamiltonHeaterShakerBackend` gets the same instance of the `HamiltonHeaterShakerBox`: this is because there is a single USB connection, managed by that instance." ] }, { "cell_type": "code", "execution_count": null, "id": "9745da8f", "metadata": {}, "outputs": [], "source": [ "control_interface = hhs_box = HamiltonHeaterShakerBox()\n", "\n", "# HS1\n", "backend1 = HamiltonHeaterShakerBackend(index=1, interface=control_interface)\n", "hs1 = HeaterShaker(\n", " name=\"Hamilton HeaterShaker\",\n", " backend=backend1,\n", " size_x=146.2,\n", " size_y=103.8,\n", " size_z=74.11,\n", " child_location=Coordinate(x=9.66, y=9.22, z=74.11),\n", ")\n", "\n", "# HS2\n", "backend2 = HamiltonHeaterShakerBackend(index=2, interface=control_interface)\n", "hs2 = HeaterShaker(\n", " name=\"Hamilton HeaterShaker\",\n", " backend=backend2,\n", " size_x=146.2,\n", " size_y=103.8,\n", " size_z=74.11,\n", " child_location=Coordinate(x=9.66, y=9.22, z=74.11),\n", ")" ] }, { "cell_type": "markdown", "id": "e26cc8dc", "metadata": {}, "source": [ "For setup, call `setup` on the `HamiltonHeaterShakerBox` instance. This will setup the USB connection to the control box. Then, call `setup` on each `HamiltonHeaterShakerBackend` instance. This will setup the individual heater shakers." ] }, { "cell_type": "code", "execution_count": null, "id": "7ff193b0", "metadata": {}, "outputs": [], "source": [ "await hhs_box.setup()\n", "\n", "for hs in [hs1, hs2]:\n", " await hs.setup()" ] }, { "cell_type": "markdown", "id": "d955b4d4-edf8-46b9-a70b-9e75ea7aa4a2", "metadata": {}, "source": [ "### 1x STAR - 2x hhs\n" ] }, { "cell_type": "code", "execution_count": null, "id": "4d753a1a-97ce-4625-adce-e59c37851207", "metadata": {}, "outputs": [], "source": [ "control_interface = star_backend = STARBackend()\n", "\n", "# Control via a STAR requires instantiation of the STAR liquid handler\n", "lh = LiquidHandler(backend=star_backend, deck=STARDeck())\n", "\n", "# HS1\n", "backend1 = HamiltonHeaterShakerBackend(index=1, interface=control_interface)\n", "\n", "hs1 = HeaterShaker(\n", " name=\"Hamilton HeaterShaker\",\n", " backend=backend1,\n", " size_x=146.2,\n", " size_y=103.8,\n", " size_z=74.11,\n", " child_location=Coordinate(x=9.66, y=9.22, z=74.11),\n", ")\n", "\n", "# HS2\n", "backend2 = HamiltonHeaterShakerBackend(index=2, interface=control_interface)\n", "\n", "hs2 = HeaterShaker(\n", " name=\"Hamilton HeaterShaker\",\n", " backend=backend2,\n", " size_x=146.2,\n", " size_y=103.8,\n", " size_z=74.11,\n", " child_location=Coordinate(x=9.66, y=9.22, z=74.11),\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "f359e8f2-60c6-45cc-aa01-bc59bb77599d", "metadata": {}, "outputs": [], "source": [ "await lh.setup()\n", "\n", "for hs in [hs1, hs2]:\n", " await hs.setup()" ] } ], "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.7" } }, "nbformat": 4, "nbformat_minor": 5 }