diff --git a/test/experiments/prcxi_9300.json b/test/experiments/prcxi_9300.json index 65254e90..3b99a89d 100644 --- a/test/experiments/prcxi_9300.json +++ b/test/experiments/prcxi_9300.json @@ -21,9 +21,9 @@ "timeout": 10.0, "axis": "Left", "channel_num": 8, - "setup": false, - "debug": false, - "simulator": false, + "setup": true, + "debug": true, + "simulator": true, "matrix_id": "71593" }, "data": {}, diff --git a/unilabos/devices/liquid_handling/liquid_handler_abstract.py b/unilabos/devices/liquid_handling/liquid_handler_abstract.py index 8513053a..f5958129 100644 --- a/unilabos/devices/liquid_handling/liquid_handler_abstract.py +++ b/unilabos/devices/liquid_handling/liquid_handler_abstract.py @@ -1,11 +1,11 @@ from __future__ import annotations import traceback -from typing import List, Sequence, Optional, Literal, Union, Iterator, Dict, Any, Callable, Set - +from typing import List, Sequence, Optional, Literal, Union, Iterator, Dict, Any, Callable, Set, cast +from collections import Counter import asyncio import time - +import pprint as pp from pylabrobot.liquid_handling import LiquidHandler, LiquidHandlerBackend, LiquidHandlerChatterboxBackend, Strictness from pylabrobot.liquid_handling.liquid_handler import TipPresenceProbingMethod from pylabrobot.liquid_handling.standard import GripDirection @@ -29,6 +29,7 @@ from pylabrobot.resources import ( class LiquidHandlerMiddleware(LiquidHandler): def __init__(self, backend: LiquidHandlerBackend, deck: Deck, simulator: bool = False, channel_num: int = 8): self._simulator = simulator + self.channel_num = channel_num if simulator: self._simulate_backend = LiquidHandlerChatterboxBackend(channel_num) self._simulate_handler = LiquidHandlerAbstract(self._simulate_backend, deck, False) @@ -104,8 +105,7 @@ class LiquidHandlerMiddleware(LiquidHandler): offsets: Optional[List[Coordinate]] = None, **backend_kwargs, ): - print('222'*200) - print(tip_spots) + if self._simulator: return await self._simulate_handler.pick_up_tips(tip_spots, use_channels, offsets, **backend_kwargs) return await super().pick_up_tips(tip_spots, use_channels, offsets, **backend_kwargs) @@ -545,6 +545,7 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware): deck: Deck to use. """ self._simulator = simulator + self.group_info = dict() super().__init__(backend, deck, simulator, channel_num) @classmethod @@ -556,6 +557,51 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware): # REMOVE LIQUID -------------------------------------------------- # --------------------------------------------------------------- + def set_group(self, group_name: str, wells: List[Well], volumes: List[float]): + if len(wells) != 8: + raise RuntimeError(f"Expected 8 wells, got {len(wells)}") + self.group_info[group_name] = wells + self.set_liquid(wells, [group_name] * len(wells), volumes) + + async def transfer_group(self, source_group_name: str, target_group_name: str, unit_volume: float): + source_wells = self.group_info.get(source_group_name, []) + target_wells = self.group_info.get(target_group_name, []) + rack_info = dict() + for child in self.deck.children: + if issubclass(child.__class__, TipRack): + rack: TipRack = cast(TipRack, child) + if "plate" not in rack.name.lower(): + for tip in rack.get_all_tips(): + if unit_volume > tip.maximal_volume: + break + else: + rack_info[rack.name] = (rack, tip.maximal_volume - unit_volume) + if len(rack_info) == 0: + raise ValueError(f"No tip rack can support volume {unit_volume}.") + + rack_info = sorted(rack_info.items(), key=lambda x: x[1][1]) + for child in self.deck.children: + if child.name == rack_info[0][0]: + target_rack = child + + target_rack = cast(TipRack, target_rack) + + available_tips = {} + for (idx, name), tipSpot in zip(target_rack._ordering.items(), target_rack.get_all_items()): + if tipSpot.has_tip(): + available_tips[idx] = tipSpot + continue + + colnum_list = [int(holename[1:]) for holename in available_tips.keys()] + available_cols = [colnum for colnum, count in dict(Counter(colnum_list)).items() if count == 8] + available_cols.sort() # 这样就确定了列号 + tips_to_use = [available_tips[f"{chr(65 + i)}{available_cols[0]}"] for i in range(8)] + + await self.pick_up_tips(tips_to_use, use_channels=list(range(0, 8))) + await self.aspirate(source_wells, [10] * 8, use_channels=list(range(0, 8))) + await self.dispense(target_wells, [10] * 8, use_channels=list(range(0, 8))) + await self.discard_tips(use_channels=list(range(0, 8))) + async def create_protocol( self, protocol_name: str, @@ -569,6 +615,7 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware): """Create a new protocol with the given metadata.""" pass + async def remove_liquid( self, vols: List[float], @@ -987,8 +1034,8 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware): if delays is not None: await self.custom_delay(seconds=delays[1]) await self.touch_tip(current_targets) - await self.discard_tips() - + await self.discard_tips([0,1,2,3,4,5,6,7]) + # except Exception as e: # traceback.print_exc() # raise RuntimeError(f"Liquid addition failed: {e}") from e diff --git a/unilabos/devices/liquid_handling/prcxi/prcxi.py b/unilabos/devices/liquid_handling/prcxi/prcxi.py index 94a831d3..67309be2 100644 --- a/unilabos/devices/liquid_handling/prcxi/prcxi.py +++ b/unilabos/devices/liquid_handling/prcxi/prcxi.py @@ -431,14 +431,14 @@ class PRCXI9300Backend(LiquidHandlerBackend): async def pick_up_tips(self, ops: List[Pickup], use_channels: List[int] = None): """Pick up tips from the specified resource.""" - print('where?'*200) + plate_indexes = [] for op in ops: plate = op.resource.parent deck = plate.parent plate_index = deck.children.index(plate) - print(f"Plate index: {plate_index}, Plate name: {plate.name}") - print(f"Number of children in deck: {len(deck.children)}") + # print(f"Plate index: {plate_index}, Plate name: {plate.name}") + # print(f"Number of children in deck: {len(deck.children)}") plate_indexes.append(plate_index) @@ -452,8 +452,6 @@ class PRCXI9300Backend(LiquidHandlerBackend): tip_columns.append(tipspot_index // 8) if len(set(tip_columns)) != 1: raise ValueError("All pickups must be from the same tip column. Found different columns: " + str(tip_columns)) - # print('111'*99) - # print(plate_indexes[0]) PlateNo = plate_indexes[0] + 1 hole_col = tip_columns[0] + 1 hole_row = 1 @@ -977,153 +975,162 @@ if __name__ == "__main__": # 4. - # deck = PRCXI9300Deck(name="PRCXI_Deck_9300", size_x=100, size_y=100, size_z=100) + deck = PRCXI9300Deck(name="PRCXI_Deck_9300", size_x=100, size_y=100, size_z=100) - # from pylabrobot.resources.opentrons.tip_racks import opentrons_96_tiprack_300ul,opentrons_96_tiprack_10ul - # from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat, nest_96_wellplate_2ml_deep + from pylabrobot.resources.opentrons.tip_racks import opentrons_96_tiprack_300ul,opentrons_96_tiprack_10ul + from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat, nest_96_wellplate_2ml_deep - # def get_well_container(name: str) -> PRCXI9300Container: - # well_containers = corning_96_wellplate_360ul_flat(name).serialize() - # plate = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="plate", - # ordering=collections.OrderedDict()) - # plate_serialized = plate.serialize() - # plate_serialized["parent_name"] = deck.name - # well_containers.update({k: v for k, v in plate_serialized.items() if k not in ["children"]}) - # new_plate: PRCXI9300Container = PRCXI9300Container.deserialize(well_containers) - # return new_plate + def get_well_container(name: str) -> PRCXI9300Container: + well_containers = corning_96_wellplate_360ul_flat(name).serialize() + plate = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="plate", + ordering=well_containers["ordering"]) + plate_serialized = plate.serialize() + plate_serialized["parent_name"] = deck.name + well_containers.update({k: v for k, v in plate_serialized.items() if k not in ["children"]}) + new_plate: PRCXI9300Container = PRCXI9300Container.deserialize(well_containers) + return new_plate - # def get_tip_rack(name: str) -> PRCXI9300Container: - # tip_racks = opentrons_96_tiprack_300ul("name").serialize() - # tip_rack = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="tip_rack", - # ordering=collections.OrderedDict()) - # tip_rack_serialized = tip_rack.serialize() - # tip_rack_serialized["parent_name"] = deck.name - # tip_racks.update({k: v for k, v in tip_rack_serialized.items() if k not in ["children"]}) - # new_tip_rack: PRCXI9300Container = PRCXI9300Container.deserialize(tip_racks) - # return new_tip_rack + def get_tip_rack(name: str) -> PRCXI9300Container: + tip_racks = opentrons_96_tiprack_300ul("name").serialize() + tip_rack = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="tip_rack", + ordering=tip_racks["ordering"]) + tip_rack_serialized = tip_rack.serialize() + tip_rack_serialized["parent_name"] = deck.name + tip_racks.update({k: v for k, v in tip_rack_serialized.items() if k not in ["children"]}) + new_tip_rack: PRCXI9300Container = PRCXI9300Container.deserialize(tip_racks) + return new_tip_rack - # plate1 = get_tip_rack("RackT1") - # plate1.load_state({ - # "Material": { - # "uuid": "076250742950465b9d6ea29a225dfb00", - # "Code": "ZX-001-300", - # "Name": "300μL Tip头" - # } - # }) + plate1 = get_tip_rack("RackT1") + plate1.load_state({ + "Material": { + "uuid": "076250742950465b9d6ea29a225dfb00", + "Code": "ZX-001-300", + "Name": "300μL Tip头" + } + }) - # plate2 = get_well_container("PlateT2") - # plate2.load_state({ - # "Material": { - # "uuid": "57b1e4711e9e4a32b529f3132fc5931f", - # "Code": "ZX-019-2.2", - # "Name": "96深孔板" - # } - # }) + plate2 = get_well_container("PlateT2") + plate2.load_state({ + "Material": { + "uuid": "57b1e4711e9e4a32b529f3132fc5931f", + "Code": "ZX-019-2.2", + "Name": "96深孔板" + } + }) - # plate3 = PRCXI9300Trash("trash", size_x=50, size_y=100, size_z=10, category="trash") - # plate3.load_state({ - # "Material": { - # "uuid": "730067cf07ae43849ddf4034299030e9" - # } - # }) + plate3 = PRCXI9300Trash("trash", size_x=50, size_y=100, size_z=10, category="trash") + plate3.load_state({ + "Material": { + "uuid": "730067cf07ae43849ddf4034299030e9" + } + }) - # plate4 = get_well_container("PlateT4") - # plate4.load_state({ - # "Material": { - # "uuid": "57b1e4711e9e4a32b529f3132fc5931f", - # "Code": "ZX-019-2.2", - # "Name": "96深孔板" - # } - # }) + plate4 = get_well_container("PlateT4") + plate4.load_state({ + "Material": { + "uuid": "57b1e4711e9e4a32b529f3132fc5931f", + "Code": "ZX-019-2.2", + "Name": "96深孔板" + } + }) - # plate5 = get_well_container("PlateT5") - # plate5.load_state({ - # "Material": { - # "uuid": "57b1e4711e9e4a32b529f3132fc5931f", - # "Code": "ZX-019-2.2", - # "Name": "96深孔板" - # } - # }) - # plate6 = get_well_container("PlateT6") + plate5 = get_well_container("PlateT5") + plate5.load_state({ + "Material": { + "uuid": "57b1e4711e9e4a32b529f3132fc5931f", + "Code": "ZX-019-2.2", + "Name": "96深孔板" + } + }) + plate6 = get_well_container("PlateT6") - # plate6.load_state({ - # "Material": { - # "uuid": "57b1e4711e9e4a32b529f3132fc5931f", - # "Code": "ZX-019-2.2", - # "Name": "96深孔板" - # } - # }) + plate6.load_state({ + "Material": { + "uuid": "57b1e4711e9e4a32b529f3132fc5931f", + "Code": "ZX-019-2.2", + "Name": "96深孔板" + } + }) - # deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0)) - # deck.assign_child_resource(plate2, location=Coordinate(0, 0, 0)) - # deck.assign_child_resource(plate3, location=Coordinate(0, 0, 0)) - # deck.assign_child_resource(plate4, location=Coordinate(0, 0, 0)) - # deck.assign_child_resource(plate5, location=Coordinate(0, 0, 0)) - # deck.assign_child_resource(plate6, location=Coordinate(0, 0, 0)) + deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0)) + deck.assign_child_resource(plate2, location=Coordinate(0, 0, 0)) + deck.assign_child_resource(plate3, location=Coordinate(0, 0, 0)) + deck.assign_child_resource(plate4, location=Coordinate(0, 0, 0)) + deck.assign_child_resource(plate5, location=Coordinate(0, 0, 0)) + deck.assign_child_resource(plate6, location=Coordinate(0, 0, 0)) - # # print(plate2) # plate_2_liquids = [[('water', 500)]]*96 + # plate2.set_well_liquids(plate_2_liquids) - # handler = PRCXI9300Handler(deck=deck, host="10.181.214.132", port=9999, - # timeout=10.0, setup=False, debug=False, - # matrix_id="71593", - # channel_num=8, axis="Left") # Initialize the handler with the deck and host settings + - # handler.set_tiprack([plate1]) + handler = PRCXI9300Handler(deck=deck, host="10.181.214.132", port=9999, + timeout=10.0, setup=False, debug=False, + simulator=True, + matrix_id="71593", + channel_num=8, axis="Left") # Initialize the handler with the deck and host settings + - # asyncio.run(handler.setup()) # Initialize the handler and setup the connection - # from pylabrobot.resources import set_volume_tracking - # # from pylabrobot.resources import set_tip_tracking - # set_volume_tracking(enabled=True) + + + plate_2_liquids = handler.set_group("water", plate2.children[:8], [200]*8) + plate5_liquids = handler.set_group("master_mix", plate5.children[:8], [100]*8) + + handler.set_tiprack([plate1]) + asyncio.run(handler.setup()) # Initialize the handler and setup the connection + from pylabrobot.resources import set_volume_tracking + # from pylabrobot.resources import set_tip_tracking + set_volume_tracking(enabled=True) # from unilabos.resources.graphio import * - # A = tree_to_list([resource_plr_to_ulab(deck)]) - # with open("deck_9300_new.json", "w", encoding="utf-8") as f: - # json.dump(A, f, indent=4, ensure_ascii=False) - # asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection + # # A = tree_to_list([resource_plr_to_ulab(deck)]) + # # with open("deck_9300_new.json", "w", encoding="utf-8") as f: + # # json.dump(A, f, indent=4, ensure_ascii=False) + asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection + asyncio.run(handler.transfer_group("water", "master_mix", 100)) # Reset tip tracking - # # asyncio.run(handler.pick_up_tips(plate1.children[:8],[0,1,2,3,4,5,6,7])) - # # print(plate1.children[:8]) - # # asyncio.run(handler.aspirate(plate2.children[:8],[50]*8, [0,1,2,3,4,5,6,7])) - # # print(plate2.children[:8]) - # # asyncio.run(handler.dispense(plate5.children[:8],[50]*8,[0,1,2,3,4,5,6,7])) - # # print(plate5.children[:8]) + # asyncio.run(handler.pick_up_tips(plate1.children[:8],[0,1,2,3,4,5,6,7])) + # print(plate1.children[:8]) + # asyncio.run(handler.aspirate(plate2.children[:8],[50]*8, [0,1,2,3,4,5,6,7])) + # print(plate2.children[:8]) + # asyncio.run(handler.dispense(plate5.children[:8],[50]*8,[0,1,2,3,4,5,6,7])) + # print(plate5.children[:8]) - # # # # # asyncio.run(handler.drop_tips(tip_rack.children[8:16],[0,1,2,3,4,5,6,7])) - # # asyncio.run(handler.discard_tips()) + # #asyncio.run(handler.drop_tips(tip_rack.children[8:16],[0,1,2,3,4,5,6,7])) + # asyncio.run(handler.discard_tips([0,1,2,3,4,5,6,7])) - # # asyncio.run(handler.mix(well_containers.children[:8 - # # ], mix_time=3, mix_vol=50, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100)) - # # #print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info - # # asyncio.run(handler.add_liquid( - # # asp_vols=[100]*16, - # # dis_vols=[100]*16, - # # reagent_sources=plate2.children[:16], - # # targets=plate5.children[:16], - # # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], - # # flow_rates=[None] * 32, - # # offsets=[Coordinate(0, 0, 0)] * 32, - # # liquid_height=[None] * 16, - # # blow_out_air_volume=[None] * 16, - # # delays=None, - # # mix_time=3, - # # mix_vol=50, - # # spread="wide", - # # )) - # # asyncio.run(handler.run_protocol()) # Run the protocol - # # asyncio.run(handler.remove_liquid( - # # vols=[100]*16, - # # sources=plate2.children[-16:], - # # waste_liquid=plate5.children[:16], # 这个有些奇怪,但是好像也只能这么写 - # # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], - # # flow_rates=[None] * 32, - # # offsets=[Coordinate(0, 0, 0)] * 32, - # # liquid_height=[None] * 32, - # # blow_out_air_volume=[None] * 32, - # # spread="wide", - # # )) + # asyncio.run(handler.mix(well_containers.children[:8 + # ], mix_time=3, mix_vol=50, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100)) + # #print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info + # asyncio.run(handler.add_liquid( + # asp_vols=[100]*16, + # dis_vols=[100]*16, + # reagent_sources=plate2.children[:16], + # targets=plate5.children[:16], + # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], + # flow_rates=[None] * 32, + # offsets=[Coordinate(0, 0, 0)] * 32, + # liquid_height=[None] * 16, + # blow_out_air_volume=[None] * 16, + # delays=None, + # mix_time=3, + # mix_vol=50, + # spread="wide", + # )) + # asyncio.run(handler.run_protocol()) # Run the protocol + # asyncio.run(handler.remove_liquid( + # vols=[100]*16, + # sources=plate2.children[-16:], + # waste_liquid=plate5.children[:16], # 这个有些奇怪,但是好像也只能这么写 + # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], + # flow_rates=[None] * 32, + # offsets=[Coordinate(0, 0, 0)] * 32, + # liquid_height=[None] * 32, + # blow_out_air_volume=[None] * 32, + # spread="wide", + # )) # acid = [20]*8+[40]*8+[60]*8+[80]*8+[100]*8+[120]*8+[140]*8+[160]*8+[180]*8+[200]*8+[220]*8+[240]*8 # alkaline = acid[::-1] # Reverse the acid list for alkaline @@ -1144,258 +1151,264 @@ if __name__ == "__main__": # spread="wide", # )) # asyncio.run(handler.run_protocol()) # Run the protocol - # # # input("Running protocol...") - # # # input("Press Enter to continue...") # Wait for user input before proceeding - # # # print("PRCXI9300Handler initialized with deck and host settings.") - - # # Example usage - # # 1. 用导出的json,给每个T1 T2板子设定相应的物料,如果是孔板和枪头盒,要对应区分 - # # 2. 设计一个单点动作流程,可以跑 - # # 3. + # # input("Running protocol...") + # # input("Press Enter to continue...") # Wait for user input before proceeding + # # print("PRCXI9300Handler initialized with deck and host settings.") - deck = PRCXI9300Deck(name="PRCXI_Deck", size_x=100, size_y=100, size_z=100) - from pylabrobot.resources.opentrons.tip_racks import tipone_96_tiprack_200ul,opentrons_96_tiprack_10ul - from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat, nest_96_wellplate_2ml_deep +### 9320 ### - def get_well_container(name: str) -> PRCXI9300Container: - well_containers = corning_96_wellplate_360ul_flat(name).serialize() - plate = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="plate", - ordering=collections.OrderedDict()) - plate_serialized = plate.serialize() - plate_serialized["parent_name"] = deck.name - well_containers.update({k: v for k, v in plate_serialized.items() if k not in ["children"]}) - new_plate: PRCXI9300Container = PRCXI9300Container.deserialize(well_containers) - return new_plate - def get_tip_rack(name: str) -> PRCXI9300Container: - tip_racks = opentrons_96_tiprack_10ul("name").serialize() - tip_rack = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="tip_rack", - ordering=collections.OrderedDict()) - tip_rack_serialized = tip_rack.serialize() - tip_rack_serialized["parent_name"] = deck.name - tip_racks.update({k: v for k, v in tip_rack_serialized.items() if k not in ["children"]}) - new_tip_rack: PRCXI9300Container = PRCXI9300Container.deserialize(tip_racks) - return new_tip_rack +# deck = PRCXI9300Deck(name="PRCXI_Deck", size_x=100, size_y=100, size_z=100) + +# from pylabrobot.resources.opentrons.tip_racks import tipone_96_tiprack_200ul,opentrons_96_tiprack_10ul +# from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat, nest_96_wellplate_2ml_deep + +# def get_well_container(name: str) -> PRCXI9300Container: +# well_containers = corning_96_wellplate_360ul_flat(name).serialize() +# plate = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="plate", +# ordering=collections.OrderedDict()) +# plate_serialized = plate.serialize() +# plate_serialized["parent_name"] = deck.name +# well_containers.update({k: v for k, v in plate_serialized.items() if k not in ["children"]}) +# new_plate: PRCXI9300Container = PRCXI9300Container.deserialize(well_containers) +# return new_plate + +# def get_tip_rack(name: str) -> PRCXI9300Container: +# tip_racks = opentrons_96_tiprack_10ul("name").serialize() +# tip_rack = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="tip_rack", +# ordering=collections.OrderedDict()) +# tip_rack_serialized = tip_rack.serialize() +# tip_rack_serialized["parent_name"] = deck.name +# tip_racks.update({k: v for k, v in tip_rack_serialized.items() if k not in ["children"]}) +# new_tip_rack: PRCXI9300Container = PRCXI9300Container.deserialize(tip_racks) +# return new_tip_rack - plate1 = get_well_container("HPLCPlateT1") - plate1.load_state({ - "Material": { - "uuid": "548bbc3df0d4447586f2c19d2c0c0c55", - "Code": "HPLC01", - "Name": "HPLC料盘" - } - }) - plate2 = get_well_container("PlateT2") - plate2.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650", - } - }) - plate3 = get_well_container("PlateT3") - plate3.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650", - } - }) - trash = PRCXI9300Trash(name="trash", size_x=50, size_y=50, size_z=10, category="trash") - trash.load_state({ - "Material": { - "uuid": "730067cf07ae43849ddf4034299030e9" - } - }) - plate5 = get_well_container("PlateT5") - plate5.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650", - } - }) - plate6 = get_well_container("PlateT6") - plate6.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650" - } - }) - plate7 = PRCXI9300Container(name="plateT7", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()) - plate7.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650" - } - }) - plate8 = get_tip_rack("RackT8") - plate8.load_state({ - "Material": { - "uuid": "068b3815e36b4a72a59bae017011b29f", - "Code": "ZX-001-10+", - "Name": "10μL加长 Tip头" - } - }) - plate9 = get_well_container("PlateT9") - plate9.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650" - } - }) - plate10 = get_well_container("PlateT10") - plate10.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650" - } - }) - plate11 = get_well_container("PlateT11") - plate11.load_state({ - "Material": { - "uuid": "57b1e4711e9e4a32b529f3132fc5931f", - } - }) - plate12 = get_well_container("PlateT12") - plate12.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650" - } - }) - plate13 = get_well_container("PlateT13") - plate13.load_state({ - "Material": { - "uuid": "04211a2dc93547fe9bf6121eac533650" - } - }) +# plate1 = get_well_container("HPLCPlateT1") +# plate1.load_state({ +# "Material": { +# "uuid": "548bbc3df0d4447586f2c19d2c0c0c55", +# "Code": "HPLC01", +# "Name": "HPLC料盘" +# } +# }) +# plate2 = get_well_container("PlateT2") +# plate2.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650", +# } +# }) +# plate3 = get_well_container("PlateT3") +# plate3.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650", +# } +# }) +# trash = PRCXI9300Trash(name="trash", size_x=50, size_y=50, size_z=10, category="trash") +# trash.load_state({ +# "Material": { +# "uuid": "730067cf07ae43849ddf4034299030e9" +# } +# }) +# plate5 = get_well_container("PlateT5") +# plate5.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650", +# } +# }) +# plate6 = get_well_container("PlateT6") +# plate6.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650" +# } +# }) +# plate7 = PRCXI9300Container(name="plateT7", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()) +# plate7.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650" +# } +# }) +# plate8 = get_tip_rack("RackT8") +# plate8.load_state({ +# "Material": { +# "uuid": "068b3815e36b4a72a59bae017011b29f", +# "Code": "ZX-001-10+", +# "Name": "10μL加长 Tip头" +# } +# }) +# plate9 = get_well_container("PlateT9") +# plate9.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650" +# } +# }) +# plate10 = get_well_container("PlateT10") +# plate10.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650" +# } +# }) +# plate11 = get_well_container("PlateT11") +# plate11.load_state({ +# "Material": { +# "uuid": "57b1e4711e9e4a32b529f3132fc5931f", +# } +# }) +# plate12 = get_well_container("PlateT12") +# plate12.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650" +# } +# }) +# plate13 = get_well_container("PlateT13") +# plate13.load_state({ +# "Material": { +# "uuid": "04211a2dc93547fe9bf6121eac533650" +# } +# }) - # container_for_nothing = PRCXI9300Container(name="container_for_nothing", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()) +# # container_for_nothing = PRCXI9300Container(name="container_for_nothing", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()) - deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing1", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing2", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(trash, location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing3", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing4", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(plate8, location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing5", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing6", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(plate11, location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing7", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing8", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing1", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing2", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(trash, location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing3", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing4", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(plate8, location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing5", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing6", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(plate11, location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing7", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) +# deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing8", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0)) - handler = PRCXI9300Handler(deck=deck, host="10.181.102.13", port=9999, - timeout=10.0, setup=False, debug=False, - matrix_id="fd383e6d-2d0e-40b5-9c01-1b2870b1f1b1", - channel_num=1, axis="Right") # Initialize the handler with the deck and host settings +# handler = PRCXI9300Handler(deck=deck, host="10.181.102.13", port=9999, +# timeout=10.0, setup=False, debug=False, +# matrix_id="fd383e6d-2d0e-40b5-9c01-1b2870b1f1b1", +# channel_num=8, axis="Right") # Initialize the handler with the deck and host settings - handler.set_tiprack([plate8]) # Set the tip rack for the handler - asyncio.run(handler.setup()) # Initialize the handler and setup the connection - from pylabrobot.resources import set_volume_tracking - # from pylabrobot.resources import set_tip_tracking - set_volume_tracking(enabled=True) +# handler.set_tiprack([plate8]) # Set the tip rack for the handler +# asyncio.run(handler.setup()) # Initialize the handler and setup the connection +# from pylabrobot.resources import set_volume_tracking +# # from pylabrobot.resources import set_tip_tracking +# set_volume_tracking(enabled=True) - plate11.set_well_liquids([("Water", 100) if (i % 8 == 0 and i // 8 < 6) else (None, 100) for i in range(96)]) # Set liquids for every 8 wells in plate8 +# plate11.set_well_liquids([("Water", 100) if (i % 8 == 0 and i // 8 < 6) else (None, 100) for i in range(96)]) # Set liquids for every 8 wells in plate8 - from unilabos.resources.graphio import * +# from unilabos.resources.graphio import * - A = tree_to_list([resource_plr_to_ulab(deck)]) - # with open("deck.json", "w", encoding="utf-8") as f: - # json.dump(A, f, indent=4, ensure_ascii=False) +# A = tree_to_list([resource_plr_to_ulab(deck)]) +# # with open("deck.json", "w", encoding="utf-8") as f: +# # json.dump(A, f, indent=4, ensure_ascii=False) - print(plate11.get_well(0).tracker.get_used_volume()) - asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection - - # asyncio.run(handler.pick_up_tips([plate8.children[8]],[0])) - # print(plate8.children[8]) - # # asyncio.run(handler.run_protocol()) - # asyncio.run(handler.aspirate([plate11.children[0]],[10], [0])) - # print(plate11.children[0]) - # # asyncio.run(handler.run_protocol()) - # asyncio.run(handler.dispense([plate1.children[0]],[10],[0])) - # print(plate1.children[0]) - # # asyncio.run(handler.run_protocol()) - # asyncio.run(handler.mix([plate1.children[0]], mix_time=3, mix_vol=5, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100)) - # print(plate1.children[0]) - # asyncio.run(handler.discard_tips()) - - asyncio.run(handler.add_liquid( - asp_vols=[10]*7, - dis_vols=[10]*7, - reagent_sources=plate11.children[:7], - targets=plate1.children[2:9], - use_channels=[0], - flow_rates=[None] * 7, - offsets=[Coordinate(0, 0, 0)] * 7, - liquid_height=[None] * 7, - blow_out_air_volume=[None] * 2, - delays=None, - mix_time=3, - mix_vol=5, - spread="custom", -)) - - asyncio.run(handler.run_protocol()) # Run the protocol -# # asyncio.run(handler.transfer_liquid( -# # asp_vols=[10]*2, -# # dis_vols=[10]*2, -# # sources=plate11.children[:2], -# # targets=plate11.children[-2:], -# # use_channels=[0], -# # offsets=[Coordinate(0, 0, 0)] * 4, -# # liquid_height=[None] * 2, -# # blow_out_air_volume=[None] * 2, -# # delays=None, -# # mix_times=3, -# # mix_vol=5, -# # spread="wide", -# # tip_racks=[plate8] -# # )) - -# # asyncio.run(handler.remove_liquid( -# # vols=[10]*2, -# # sources=plate11.children[:2], -# # waste_liquid=plate11.children[43], -# # use_channels=[0], -# # offsets=[Coordinate(0, 0, 0)] * 4, -# # liquid_height=[None] * 2, -# # blow_out_air_volume=[None] * 2, -# # delays=None, -# # spread="wide" -# # )) -# asyncio.run(handler.run_protocol()) +# print(plate11.get_well(0).tracker.get_used_volume()) +# asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection +# # asyncio.run(handler.pick_up_tips([plate8.children[8]],[0])) +# # print(plate8.children[8]) +# # # asyncio.run(handler.run_protocol()) +# # asyncio.run(handler.aspirate([plate11.children[0]],[10], [0])) +# # print(plate11.children[0]) +# # # asyncio.run(handler.run_protocol()) +# # asyncio.run(handler.dispense([plate1.children[0]],[10],[0])) +# # print(plate1.children[0]) +# # # asyncio.run(handler.run_protocol()) +# # asyncio.run(handler.mix([plate1.children[0]], mix_time=3, mix_vol=5, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100)) +# # print(plate1.children[0]) # # asyncio.run(handler.discard_tips()) -# # asyncio.run(handler.mix(well_containers.children[:8 -# # ], mix_time=3, mix_vol=50, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100)) -# #print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info + +# asyncio.run(handler.add_liquid( +# asp_vols=[10]*7, +# dis_vols=[10]*7, +# reagent_sources=plate11.children[:7], +# targets=plate1.children[2:9], +# use_channels=[0], +# flow_rates=[None] * 7, +# offsets=[Coordinate(0, 0, 0)] * 7, +# liquid_height=[None] * 7, +# blow_out_air_volume=[None] * 2, +# delays=None, +# mix_time=3, +# mix_vol=5, +# spread="custom", +# )) + +# asyncio.run(handler.run_protocol()) # Run the protocol -# # asyncio.run(handler.remove_liquid( -# # vols=[100]*16, -# # sources=well_containers.children[-16:], -# # waste_liquid=well_containers.children[:16], # 这个有些奇怪,但是好像也只能这么写 -# # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], -# # flow_rates=[None] * 32, -# # offsets=[Coordinate(0, 0, 0)] * 32, -# # liquid_height=[None] * 32, -# # blow_out_air_volume=[None] * 32, -# # spread="wide", -# # )) -# # asyncio.run(handler.transfer_liquid( -# # asp_vols=[100]*16, -# # dis_vols=[100]*16, -# # tip_racks=[tip_rack], -# # sources=well_containers.children[-16:], -# # targets=well_containers.children[:16], -# # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], -# # offsets=[Coordinate(0, 0, 0)] * 32, -# # asp_flow_rates=[None] * 16, -# # dis_flow_rates=[None] * 16, -# # liquid_height=[None] * 32, -# # blow_out_air_volume=[None] * 32, -# # mix_times=3, -# # mix_vol=50, -# # spread="wide", -# # )) - print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info -# # input("pick_up_tips add step") -# #asyncio.run(handler.run_protocol()) # Run the protocol -# # input("Running protocol...") -# # input("Press Enter to continue...") # Wait for user input before proceeding -# # print("PRCXI9300Handler initialized with deck and host settings.") + + + + + +# # # asyncio.run(handler.transfer_liquid( +# # # asp_vols=[10]*2, +# # # dis_vols=[10]*2, +# # # sources=plate11.children[:2], +# # # targets=plate11.children[-2:], +# # # use_channels=[0], +# # # offsets=[Coordinate(0, 0, 0)] * 4, +# # # liquid_height=[None] * 2, +# # # blow_out_air_volume=[None] * 2, +# # # delays=None, +# # # mix_times=3, +# # # mix_vol=5, +# # # spread="wide", +# # # tip_racks=[plate8] +# # # )) + +# # # asyncio.run(handler.remove_liquid( +# # # vols=[10]*2, +# # # sources=plate11.children[:2], +# # # waste_liquid=plate11.children[43], +# # # use_channels=[0], +# # # offsets=[Coordinate(0, 0, 0)] * 4, +# # # liquid_height=[None] * 2, +# # # blow_out_air_volume=[None] * 2, +# # # delays=None, +# # # spread="wide" +# # # )) +# # asyncio.run(handler.run_protocol()) + +# # # asyncio.run(handler.discard_tips()) +# # # asyncio.run(handler.mix(well_containers.children[:8 +# # # ], mix_time=3, mix_vol=50, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100)) +# # #print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info + + +# # # asyncio.run(handler.remove_liquid( +# # # vols=[100]*16, +# # # sources=well_containers.children[-16:], +# # # waste_liquid=well_containers.children[:16], # 这个有些奇怪,但是好像也只能这么写 +# # # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], +# # # flow_rates=[None] * 32, +# # # offsets=[Coordinate(0, 0, 0)] * 32, +# # # liquid_height=[None] * 32, +# # # blow_out_air_volume=[None] * 32, +# # # spread="wide", +# # # )) +# # # asyncio.run(handler.transfer_liquid( +# # # asp_vols=[100]*16, +# # # dis_vols=[100]*16, +# # # tip_racks=[tip_rack], +# # # sources=well_containers.children[-16:], +# # # targets=well_containers.children[:16], +# # # use_channels=[0, 1, 2, 3, 4, 5, 6, 7], +# # # offsets=[Coordinate(0, 0, 0)] * 32, +# # # asp_flow_rates=[None] * 16, +# # # dis_flow_rates=[None] * 16, +# # # liquid_height=[None] * 32, +# # # blow_out_air_volume=[None] * 32, +# # # mix_times=3, +# # # mix_vol=50, +# # # spread="wide", +# # # )) +# # print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info +# # # input("pick_up_tips add step") +# # #asyncio.run(handler.run_protocol()) # Run the protocol +# # # input("Running protocol...") +# # # input("Press Enter to continue...") # Wait for user input before proceeding +# # # print("PRCXI9300Handler initialized with deck and host settings.") diff --git a/unilabos_msgs/action/LiquidHandlerSetGroup.action b/unilabos_msgs/action/LiquidHandlerSetGroup.action new file mode 100644 index 00000000..15a73719 --- /dev/null +++ b/unilabos_msgs/action/LiquidHandlerSetGroup.action @@ -0,0 +1,8 @@ +string group_name +Resource[] wells +float64[] volumes +--- +string return_info +bool success +--- +# 反馈 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerTransferGroup.action b/unilabos_msgs/action/LiquidHandlerTransferGroup.action new file mode 100644 index 00000000..d928bda7 --- /dev/null +++ b/unilabos_msgs/action/LiquidHandlerTransferGroup.action @@ -0,0 +1,8 @@ +string source_group_name +string target_group_name +float64 unit_volume +--- +string return_info +bool success +--- +# 反馈 \ No newline at end of file