Moving plate onto Alpaqua magnet using CORE grippers#
tags: #resourcemovement #plateadapter #hamiltonstar
Last updated: 2025-10-27
Prerequisites#
Machines used:
Hamilton STAR
Non-PLR dependencies: None
Preview of Machine Behvaiour#
Protocol Mode#
protocol_mode = "simulation" # "execution" or "simulation"
Import Statements#
Non-PLR Dependencies#
None
Machine & Visualizer#
%load_ext autoreload
%autoreload 2
       
import random 
import time
from pylabrobot.liquid_handling import LiquidHandler
from pylabrobot.resources.hamilton import STARLetDeck
from pylabrobot.visualizer.visualizer import Visualizer
if protocol_mode == "execution":
  from pylabrobot.liquid_handling.backends import STARBackend
  backend = STARBackend()
elif protocol_mode == "simulation":
  from pylabrobot.liquid_handling.backends.hamilton.STAR_chatterbox import STARChatterboxBackend
    
  backend = STARChatterboxBackend()
Required Resources#
from pylabrobot.resources import (
  hamilton_mfx_carrier_L5_base,
  hamilton_mfx_plateholder_DWP_metal_tapped,
  hamilton_mfx_plateholder_DWP_flat,
  alpaqua_96_plateadapter_magnum_flx,
  Azenta4titudeFrameStar_96_wellplate_200ul_Vb,
)
Note: if you’re unsure whether you have the resources mentioned in a PLR automated Protocol, use Python’s inbuild help function to check out the resource definition’s docstring - they always contain the manufacturer’s catalogue/part number (and if available a direct link to the product page):
help(hamilton_mfx_plateholder_DWP_metal_tapped) # for more information visit the docs 'Resource Management' section
Help on function hamilton_mfx_plateholder_DWP_metal_tapped in module pylabrobot.resources.hamilton.mfx_modules:
hamilton_mfx_plateholder_DWP_metal_tapped(name: str) -> pylabrobot.resources.carrier.PlateHolder
    Hamilton MFX DWP Module (cat.-no. 188042 / 188042-00).
    Hamilton name: 'MFX_DWP_rackbased_module'
    It also contains metal clamps at the corners.
    https://www.hamiltoncompany.com/other-robotics/188042
Instantiate Frontend & Connect to Machine#
deck = STARLetDeck()
lh = LiquidHandler(backend=backend, deck=deck)
await lh.setup()
vis = Visualizer(resource=lh)
await vis.setup()
await backend.disable_cover_control() # 😈
Websocket server started at http://127.0.0.1:2121
File server started at http://127.0.0.1:1337 . Open this URL in your browser.
C0CDid0001
Configure Deck Layout#
# Setup MFX Carrier for Magnetic Bead Resuspension
mfx_plateholder_dwp_0 = hamilton_mfx_plateholder_DWP_metal_tapped(
    name=f"mfx_plateholder_dwp_tapped_dwp_0"
)
mfx_carrier_tapped_plate_holder_example = hamilton_mfx_carrier_L5_base(
  name="mfx_carrier_tapped_plate_holder_example",
  modules={
    0: mfx_plateholder_dwp_0,
  }
)
mfx_carrier_tapped_plate_holder_example[0] = Azenta4titudeFrameStar_96_wellplate_200ul_Vb(
  name="wash_plate_0"
)
deck.assign_child_resource(mfx_carrier_tapped_plate_holder_example, rails=1)
# Setup Magnet-carrying MFX Carrier
plateholder_flat_0 = hamilton_mfx_plateholder_DWP_flat(name=f"plateholder_flat_0")
magnet_0 = alpaqua_96_plateadapter_magnum_flx(name=f"alpaqua_magnet_0")
plateholder_flat_0.assign_child_resource(magnet_0)
mfx_carrier_magnet_example = hamilton_mfx_carrier_L5_base(
  name="mfx_carrier_magnet_example",
  modules={
    0: plateholder_flat_0,
  }
)
magnet_0.plate_z_offset = 0.62  # <===== PLATE-SPECIFIC !
# empirical: distance between Alpaqua magnet hole bottom to
# cavity_bottom of the well that is placed on top of it
# use ztouch_probing to measure both 
deck.assign_child_resource(mfx_carrier_magnet_example, rails=8)
Execution#
Move Plate Onto Magnet PlateAdapter#
plate_index = 0 # always design for throughput adaptivness ;)
plate_to_move = lh.deck.get_resource(f"wash_plate_{plate_index}")
move_target = lh.deck.get_resource(f"alpaqua_magnet_{plate_index}")
back_channel_idx = random.randint(1, 6)  # Reduce wear & tear on any single channel
if protocol_mode == "simulation":
  time.sleep(2)
    
await lh.move_plate(
  plate=plate_to_move,
  to=move_target,
  use_arm="core",
  channel_1=back_channel_idx,
  channel_2=back_channel_idx + 1,
  pickup_distance_from_top=6,
  core_grip_strength=40,
  return_core_gripper=False,
)
if protocol_mode == "execution":
  # "smart" command, will ask operator for input if it cannot find plate in move_target location
  # place into condition for simulation mode
  # (1) check transfer success, (2) push plate flush
  await backend.core_check_resource_exists_at_location_center(
    location=plate_to_move.get_absolute_location(),
    resource=plate_to_move,
    gripper_y_margin=9,
    enable_recovery=True,
    audio_feedback=False,
  )
print(backend.core_parked)
# >>> False # save time - keep CORE grippers on channels during magnetisation time
if protocol_mode == "simulation":
  time.sleep(2)
C0ZPid0002xs01679xd0yj1147yv0050zj1932zy0500yo0885yg0825yw40th2800te2800
C0ZRid0003xs03254xd0yj1138zj2162zi000zy0500yo0885th2800te2800
False
Move Plate back onto tapped PlateHolder#
move_target = lh.deck.get_resource(f"mfx_plateholder_dwp_tapped_dwp_{plate_index}")
await lh.move_plate(
  plate=plate_to_move,
  to=move_target,
  use_arm="core",
  channel_1=back_channel_idx,
  channel_2=back_channel_idx + 1,
  pickup_distance_from_top=6,
  core_grip_strength=40,
  return_core_gripper=False,
)
if protocol_mode == "execution":
  await backend.core_check_resource_exists_at_location_center(
    location=plate_to_move.get_absolute_location(),
    resource=plate_to_move,
    gripper_y_margin=9,
    enable_recovery=True,
    audio_feedback=False,
  )
   
await backend.return_core_gripper_tools()
print(backend.core_parked)
# >>> True
C0ZPid0004xs03254xd0yj1138yv0050zj2162zy0500yo0885yg0825yw40th2800te2800
C0ZRid0005xs01679xd0yj1147zj1932zi000zy0500yo0885th2800te2800
C0ZSid0006xs07975xd0ya1250yb1070tp2150tz2050th2800te2800
True