From a948f09f60e960ab84b14903c73eaefa29c39b20 Mon Sep 17 00:00:00 2001 From: Junhan Chang Date: Fri, 30 May 2025 13:33:10 +0800 Subject: [PATCH 01/44] add biomek.py demo implementation --- unilabos/devices/liquid_handling/biomek.py | 167 ++++++++++++++++++ .../liquid_handler_abstract.py | 20 ++- 2 files changed, 182 insertions(+), 5 deletions(-) create mode 100644 unilabos/devices/liquid_handling/biomek.py diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py new file mode 100644 index 00000000..c9375e2a --- /dev/null +++ b/unilabos/devices/liquid_handling/biomek.py @@ -0,0 +1,167 @@ +import requests +from typing import List, Sequence, Optional, Union, Literal + +from .liquid_handler_abstract import LiquidHandlerAbstract + + +class LiquidHandlerBiomek(LiquidHandlerAbstract): + """ + Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 + 该类用于处理Biomek液体处理器的特定操作。 + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._status = "Idle" # 初始状态为 Idle + self._success = False # 初始成功状态为 False + self._status_queue = kwargs.get("status_queue", None) # 状态队列 + self.temp_protocol = {} + + def create_protocol(self, + protocol_name: str, + protocol_description: str, + protocol_version: str, + protocol_author: str, + protocol_date: str, + ): + """ + 创建一个新的协议。 + + Args: + protocol_name (str): 协议名称 + protocol_description (str): 协议描述 + protocol_version (str): 协议版本 + protocol_author (str): 协议作者 + protocol_date (str): 协议日期 + protocol_type (str): 协议类型 + none_keys (List[str]): 需要设置为None的键列表 + + Returns: + dict: 创建的协议字典 + """ + self.temp_protocol = { + "meta": { + "name": protocol_name, + "description": protocol_description, + "version": protocol_version, + "author": protocol_author, + "date": protocol_date, + }, + "labwares": [], + "steps": [], + } + return self.temp_protocol + + def run_protocol(self): + """ + 执行创建的实验流程。 + 工作站的完整执行流程是, + 从 create_protocol 开始,创建新的 method, + 随后执行 transfer_liquid 等操作向实验流程添加步骤, + 最后 run_protocol 执行整个方法。 + + Returns: + dict: 执行结果 + """ + if not self.temp_protocol: + raise ValueError("No protocol created. Please create a protocol first.") + + # 模拟执行协议 + self._status = "Running" + self._success = True + # 在这里可以添加实际执行协议的逻辑 + + response = requests.post("localhost:5000/api/protocols", json=self.temp_protocol) + + def create_resource( + self, + device_id: str, + res_id: str, + class_name: str, + parent: str, + bind_locations: Point, + liquid_input_slot: list[int], + liquid_type: list[str], + liquid_volume: list[int], + slot_on_deck: int, + ): + """ + 创建一个新的资源。 + + Args: + device_id (str): 设备ID + res_id (str): 资源ID + class_name (str): 资源类名 + parent (str): 父级ID + bind_locations (Point): 绑定位置 + liquid_input_slot (list[int]): 液体输入槽列表 + liquid_type (list[str]): 液体类型列表 + liquid_volume (list[int]): 液体体积列表 + slot_on_deck (int): 甲板上的槽位 + + Returns: + dict: 创建的资源字典 + """ + # TODO:需要对好接口,下面这个是临时的 + resource = { + "id": res_id, + "class": class_name, + "parent": parent, + "bind_locations": bind_locations.to_dict(), + "liquid_input_slot": liquid_input_slot, + "liquid_type": liquid_type, + "liquid_volume": liquid_volume, + "slot_on_deck": slot_on_deck, + } + self.temp_protocol["labwares"].append(resource) + return resource + + def transfer_liquid( + self, + sources: Sequence[Container], + targets: Sequence[Container], + tip_racks: Sequence[TipRack], + *, + use_channels: Optional[List[int]] = None, + asp_vols: Union[List[float], float], + dis_vols: Union[List[float], float], + asp_flow_rates: Optional[List[Optional[float]]] = None, + dis_flow_rates: Optional[List[Optional[float]]] = None, + offsets: Optional[List[Coordinate]] = None, + touch_tip: bool = False, + liquid_height: Optional[List[Optional[float]]] = None, + blow_out_air_volume: Optional[List[Optional[float]]] = None, + spread: Literal["wide", "tight", "custom"] = "wide", + is_96_well: bool = False, + mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none", + mix_times: Optional[List(int)] = None, + mix_vol: Optional[int] = None, + mix_rate: Optional[int] = None, + mix_liquid_height: Optional[float] = None, + delays: Optional[List[int]] = None, + none_keys: List[str] = [] + ): + # TODO:需要对好接口,下面这个是临时的 + self.temp_protocol["steps"].append({ + "type": "transfer", + "sources": [source.to_dict() for source in sources], + "targets": [target.to_dict() for target in targets], + "tip_racks": [tip_rack.to_dict() for tip_rack in tip_racks], + "use_channels": use_channels, + "asp_vols": asp_vols, + "dis_vols": dis_vols, + "asp_flow_rates": asp_flow_rates, + "dis_flow_rates": dis_flow_rates, + "offsets": offsets, + "touch_tip": touch_tip, + "liquid_height": liquid_height, + "blow_out_air_volume": blow_out_air_volume, + "spread": spread, + "is_96_well": is_96_well, + "mix_stage": mix_stage, + "mix_times": mix_times, + "mix_vol": mix_vol, + "mix_rate": mix_rate, + "mix_liquid_height": mix_liquid_height, + "delays": delays, + }) \ No newline at end of file diff --git a/unilabos/devices/liquid_handling/liquid_handler_abstract.py b/unilabos/devices/liquid_handling/liquid_handler_abstract.py index c349403e..2596e843 100644 --- a/unilabos/devices/liquid_handling/liquid_handler_abstract.py +++ b/unilabos/devices/liquid_handling/liquid_handler_abstract.py @@ -21,6 +21,18 @@ class LiquidHandlerAbstract(LiquidHandler): # REMOVE LIQUID -------------------------------------------------- # --------------------------------------------------------------- + async def create_protocol(self, + protocol_name: str, + protocol_description: str, + protocol_version: str, + protocol_author: str, + protocol_date: str, + protocol_type: str, + none_keys: List[str] = [] + ): + """Create a new protocol with the given metadata.""" + pass + async def remove_liquid( self, vols: List[float], @@ -158,13 +170,13 @@ class LiquidHandlerAbstract(LiquidHandler): # --------------------------------------------------------------- async def transfer_liquid( self, - asp_vols: Union[List[float], float], - dis_vols: Union[List[float], float], sources: Sequence[Container], targets: Sequence[Container], tip_racks: Sequence[TipRack], *, use_channels: Optional[List[int]] = None, + asp_vols: Union[List[float], float], + dis_vols: Union[List[float], float], asp_flow_rates: Optional[List[Optional[float]]] = None, dis_flow_rates: Optional[List[Optional[float]]] = None, offsets: Optional[List[Coordinate]] = None, @@ -266,9 +278,7 @@ class LiquidHandlerAbstract(LiquidHandler): print(f"Done: {msg}") print(f"Current time: {time.strftime('%H:%M:%S')}") - async def touch_tip(self, - targets: Sequence[Container], - ): + async def touch_tip(self, targets: Sequence[Container]): """Touch the tip to the side of the well.""" await self.aspirate( resources=[targets], From 055d120ba81f8a0a7022d2826e62c1ac2344e475 Mon Sep 17 00:00:00 2001 From: Junhan Chang Date: Fri, 30 May 2025 13:33:10 +0800 Subject: [PATCH 02/44] =?UTF-8?q?=E6=9B=B4=E6=96=B0LiquidHandlerBiomek?= =?UTF-8?q?=E7=B1=BB=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=B5=84=E6=BA=90=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E5=88=9B=E5=BB=BA=E6=96=B9=E6=B3=95=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E6=9B=B4=E6=96=B0YAML=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E4=BB=A5=E6=94=AF=E6=8C=81=E6=96=B0=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/devices/liquid_handling/biomek.py | 173 ++++++++++++++++++ .../liquid_handler_abstract.py | 99 +++++----- unilabos/registry/devices/liquid_handler.yaml | 79 +++++++- unilabos/ros/nodes/base_device_node.py | 14 ++ unilabos_msgs/CMakeLists.txt | 2 + .../LiquidHandlerProtocolCreation.action | 9 + 6 files changed, 320 insertions(+), 56 deletions(-) create mode 100644 unilabos/devices/liquid_handling/biomek.py create mode 100644 unilabos_msgs/action/LiquidHandlerProtocolCreation.action diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py new file mode 100644 index 00000000..40a90a41 --- /dev/null +++ b/unilabos/devices/liquid_handling/biomek.py @@ -0,0 +1,173 @@ +import requests +from typing import List, Sequence, Optional, Union, Literal +from geometry_msgs.msg import Point +from unilabos_msgs.msg import Resource + +from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker # type: ignore +from .liquid_handler_abstract import LiquidHandlerAbstract + + +class LiquidHandlerBiomek(LiquidHandlerAbstract): + """ + Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 + 该类用于处理Biomek液体处理器的特定操作。 + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._status = "Idle" # 初始状态为 Idle + self._success = False # 初始成功状态为 False + self._status_queue = kwargs.get("status_queue", None) # 状态队列 + self.temp_protocol = {} + + def create_protocol( + self, + protocol_name: str, + protocol_description: str, + protocol_version: str, + protocol_author: str, + protocol_date: str, + none_keys: List[str] = [], + ): + """ + 创建一个新的协议。 + + Args: + protocol_name (str): 协议名称 + protocol_description (str): 协议描述 + protocol_version (str): 协议版本 + protocol_author (str): 协议作者 + protocol_date (str): 协议日期 + protocol_type (str): 协议类型 + none_keys (List[str]): 需要设置为None的键列表 + + Returns: + dict: 创建的协议字典 + """ + self.temp_protocol = { + "meta": { + "name": protocol_name, + "description": protocol_description, + "version": protocol_version, + "author": protocol_author, + "date": protocol_date, + }, + "labwares": [], + "steps": [], + } + return self.temp_protocol + + def run_protocol(self): + """ + 执行创建的实验流程。 + 工作站的完整执行流程是, + 从 create_protocol 开始,创建新的 method, + 随后执行 transfer_liquid 等操作向实验流程添加步骤, + 最后 run_protocol 执行整个方法。 + + Returns: + dict: 执行结果 + """ + if not self.temp_protocol: + raise ValueError("No protocol created. Please create a protocol first.") + + # 模拟执行协议 + self._status = "Running" + self._success = True + # 在这里可以添加实际执行协议的逻辑 + + response = requests.post("localhost:5000/api/protocols", json=self.temp_protocol) + + def create_resource( + self, + resource_tracker: DeviceNodeResourceTracker, + resources: list[Resource], + bind_parent_id: str, + bind_location: dict[str, float], + liquid_input_slot: list[int], + liquid_type: list[str], + liquid_volume: list[int], + slot_on_deck: int, + ): + """ + 创建一个新的资源。 + + Args: + device_id (str): 设备ID + res_id (str): 资源ID + class_name (str): 资源类名 + parent (str): 父级ID + bind_locations (Point): 绑定位置 + liquid_input_slot (list[int]): 液体输入槽列表 + liquid_type (list[str]): 液体类型列表 + liquid_volume (list[int]): 液体体积列表 + slot_on_deck (int): 甲板上的槽位 + + Returns: + dict: 创建的资源字典 + """ + # TODO:需要对好接口,下面这个是临时的 + resource = { + "id": res_id, + "class": class_name, + "parent": parent, + "bind_locations": bind_locations.to_dict(), + "liquid_input_slot": liquid_input_slot, + "liquid_type": liquid_type, + "liquid_volume": liquid_volume, + "slot_on_deck": slot_on_deck, + } + self.temp_protocol["labwares"].append(resource) + return resource + + def transfer_liquid( + self, + sources: Sequence[Container], + targets: Sequence[Container], + tip_racks: Sequence[TipRack], + *, + use_channels: Optional[List[int]] = None, + asp_vols: Union[List[float], float], + dis_vols: Union[List[float], float], + asp_flow_rates: Optional[List[Optional[float]]] = None, + dis_flow_rates: Optional[List[Optional[float]]] = None, + offsets: Optional[List[Coordinate]] = None, + touch_tip: bool = False, + liquid_height: Optional[List[Optional[float]]] = None, + blow_out_air_volume: Optional[List[Optional[float]]] = None, + spread: Literal["wide", "tight", "custom"] = "wide", + is_96_well: bool = False, + mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none", + mix_times: Optional[List(int)] = None, + mix_vol: Optional[int] = None, + mix_rate: Optional[int] = None, + mix_liquid_height: Optional[float] = None, + delays: Optional[List[int]] = None, + none_keys: List[str] = [] + ): + # TODO:需要对好接口,下面这个是临时的 + self.temp_protocol["steps"].append( + { + "type": "transfer", + "sources": [source.to_dict() for source in sources], + "targets": [target.to_dict() for target in targets], + "tip_racks": [tip_rack.to_dict() for tip_rack in tip_racks], + "use_channels": use_channels, + "asp_vols": asp_vols, + "dis_vols": dis_vols, + "asp_flow_rates": asp_flow_rates, + "dis_flow_rates": dis_flow_rates, + "offsets": offsets, + "touch_tip": touch_tip, + "liquid_height": liquid_height, + "blow_out_air_volume": blow_out_air_volume, + "spread": spread, + "is_96_well": is_96_well, + "mix_stage": mix_stage, + "mix_times": mix_times, + "mix_vol": mix_vol, + "mix_rate": mix_rate, + "mix_liquid_height": mix_liquid_height, + "delays": delays, + } + ) diff --git a/unilabos/devices/liquid_handling/liquid_handler_abstract.py b/unilabos/devices/liquid_handling/liquid_handler_abstract.py index c349403e..4faa0427 100644 --- a/unilabos/devices/liquid_handling/liquid_handler_abstract.py +++ b/unilabos/devices/liquid_handling/liquid_handler_abstract.py @@ -6,13 +6,8 @@ import asyncio import time from pylabrobot.liquid_handling import LiquidHandler -from pylabrobot.resources import ( - Resource, - TipRack, - Container, - Coordinate, - Well -) +from pylabrobot.resources import Resource, TipRack, Container, Coordinate, Well + class LiquidHandlerAbstract(LiquidHandler): """Extended LiquidHandler with additional operations.""" @@ -21,6 +16,19 @@ class LiquidHandlerAbstract(LiquidHandler): # REMOVE LIQUID -------------------------------------------------- # --------------------------------------------------------------- + async def create_protocol( + self, + protocol_name: str, + protocol_description: str, + protocol_version: str, + protocol_author: str, + protocol_date: str, + protocol_type: str, + none_keys: List[str] = [], + ): + """Create a new protocol with the given metadata.""" + pass + async def remove_liquid( self, vols: List[float], @@ -35,26 +43,26 @@ class LiquidHandlerAbstract(LiquidHandler): spread: Optional[Literal["wide", "tight", "custom"]] = "wide", delays: Optional[List[int]] = None, is_96_well: Optional[bool] = False, - top: Optional[List(float)] = None, - none_keys: List[str] = [] + top: Optional[List[float]] = None, + none_keys: List[str] = [], ): """A complete *remove* (aspirate → waste) operation.""" trash = self.deck.get_trash_area() try: if is_96_well: - pass # This mode is not verified + pass # This mode is not verified else: if len(vols) != len(sources): raise ValueError("Length of `vols` must match `sources`.") for src, vol in zip(sources, vols): - self.move_to(src, dis_to_top=top[0] if top else 0) + await self.move_to(src, dis_to_top=top[0] if top else 0) tip = next(self.current_tip) await self.pick_up_tips(tip) await self.aspirate( resources=[src], vols=[vol], - use_channels=use_channels, # only aspirate96 used, default to None + use_channels=use_channels, # only aspirate96 used, default to None flow_rates=[flow_rates[0]] if flow_rates else None, offsets=[offsets[0]] if offsets else None, liquid_height=[liquid_height[0]] if liquid_height else None, @@ -64,15 +72,15 @@ class LiquidHandlerAbstract(LiquidHandler): await self.custom_delay(seconds=delays[0] if delays else 0) await self.dispense( resources=waste_liquid, - vols=[vol], - use_channels=use_channels, - flow_rates=[flow_rates[1]] if flow_rates else None, - offsets=[offsets[1]] if offsets else None, - liquid_height=[liquid_height[1]] if liquid_height else None, - blow_out_air_volume=blow_out_air_volume[1] if blow_out_air_volume else None, - spread=spread, - ) - await self.discard_tips() # For now, each of tips is discarded after use + vols=[vol], + use_channels=use_channels, + flow_rates=[flow_rates[1]] if flow_rates else None, + offsets=[offsets[1]] if offsets else None, + liquid_height=[liquid_height[1]] if liquid_height else None, + blow_out_air_volume=blow_out_air_volume[1] if blow_out_air_volume else None, + spread=spread, + ) + await self.discard_tips() # For now, each of tips is discarded after use except Exception as e: raise RuntimeError(f"Liquid removal failed: {e}") from e @@ -100,13 +108,13 @@ class LiquidHandlerAbstract(LiquidHandler): mix_vol: Optional[int] = None, mix_rate: Optional[int] = None, mix_liquid_height: Optional[float] = None, - none_keys: List[str] = [] + none_keys: List[str] = [], ): """A complete *add* (aspirate reagent → dispense into targets) operation.""" try: if is_96_well: - pass # This mode is not verified. + pass # This mode is not verified. else: if len(asp_vols) != len(targets): raise ValueError("Length of `vols` must match `targets`.") @@ -122,7 +130,7 @@ class LiquidHandlerAbstract(LiquidHandler): offsets=[offsets[0]] if offsets else None, liquid_height=[liquid_height[0]] if liquid_height else None, blow_out_air_volume=[blow_out_air_volume[0]] if blow_out_air_volume else None, - spread=spread + spread=spread, ) if delays is not None: await self.custom_delay(seconds=delays[0]) @@ -144,7 +152,8 @@ class LiquidHandlerAbstract(LiquidHandler): mix_vol=mix_vol, offsets=offsets if offsets else None, height_to_bottom=mix_liquid_height if mix_liquid_height else None, - mix_rate=mix_rate if mix_rate else None) + mix_rate=mix_rate if mix_rate else None, + ) if delays is not None: await self.custom_delay(seconds=delays[1]) await self.touch_tip(targets[_]) @@ -158,13 +167,13 @@ class LiquidHandlerAbstract(LiquidHandler): # --------------------------------------------------------------- async def transfer_liquid( self, - asp_vols: Union[List[float], float], - dis_vols: Union[List[float], float], sources: Sequence[Container], targets: Sequence[Container], tip_racks: Sequence[TipRack], *, use_channels: Optional[List[int]] = None, + asp_vols: Union[List[float], float], + dis_vols: Union[List[float], float], asp_flow_rates: Optional[List[Optional[float]]] = None, dis_flow_rates: Optional[List[Optional[float]]] = None, offsets: Optional[List[Coordinate]] = None, @@ -179,7 +188,7 @@ class LiquidHandlerAbstract(LiquidHandler): mix_rate: Optional[int] = None, mix_liquid_height: Optional[float] = None, delays: Optional[List[int]] = None, - none_keys: List[str] = [] + none_keys: List[str] = [], ): """Transfer liquid from each *source* well/plate to the corresponding *target*. @@ -201,14 +210,15 @@ class LiquidHandlerAbstract(LiquidHandler): # 96‑channel head mode # ------------------------------------------------------------------ if is_96_well: - pass # This mode is not verified + pass # This mode is not verified else: if not (len(asp_vols) == len(sources) and len(dis_vols) == len(targets)): raise ValueError("`sources`, `targets`, and `vols` must have the same length.") tip_iter = self.iter_tips(tip_racks) - for src, tgt, asp_vol, asp_flow_rate, dis_vol, dis_flow_rate in ( - zip(sources, targets, asp_vols, asp_flow_rates, dis_vols, dis_flow_rates)): + for src, tgt, asp_vol, asp_flow_rate, dis_vol, dis_flow_rate in zip( + sources, targets, asp_vols, asp_flow_rates, dis_vols, dis_flow_rates + ): tip = next(tip_iter) await self.pick_up_tips(tip) # Aspirate from source @@ -247,9 +257,9 @@ class LiquidHandlerAbstract(LiquidHandler): except Exception as exc: raise RuntimeError(f"Liquid transfer failed: {exc}") from exc -# --------------------------------------------------------------- -# Helper utilities -# --------------------------------------------------------------- + # --------------------------------------------------------------- + # Helper utilities + # --------------------------------------------------------------- async def custom_delay(self, seconds=0, msg=None): """ @@ -266,28 +276,26 @@ class LiquidHandlerAbstract(LiquidHandler): print(f"Done: {msg}") print(f"Current time: {time.strftime('%H:%M:%S')}") - async def touch_tip(self, - targets: Sequence[Container], - ): + async def touch_tip(self, targets: Sequence[Container]): """Touch the tip to the side of the well.""" await self.aspirate( resources=[targets], vols=[0], use_channels=None, flow_rates=None, - offsets=[Coordinate(x=-targets.get_size_x()/2,y=0,z=0)], + offsets=[Coordinate(x=-targets.get_size_x() / 2, y=0, z=0)], liquid_height=None, - blow_out_air_volume=None + blow_out_air_volume=None, ) - #await self.custom_delay(seconds=1) # In the simulation, we do not need to wait + # await self.custom_delay(seconds=1) # In the simulation, we do not need to wait await self.aspirate( resources=[targets], vols=[0], use_channels=None, flow_rates=None, - offsets=[Coordinate(x=targets.get_size_x()/2,y=0,z=0)], + offsets=[Coordinate(x=targets.get_size_x() / 2, y=0, z=0)], liquid_height=None, - blow_out_air_volume=None + blow_out_air_volume=None, ) async def mix( @@ -298,9 +306,9 @@ class LiquidHandlerAbstract(LiquidHandler): height_to_bottom: Optional[float] = None, offsets: Optional[Coordinate] = None, mix_rate: Optional[float] = None, - none_keys: List[str] = [] + none_keys: List[str] = [], ): - if mix_time is None: # No mixing required + if mix_time is None: # No mixing required return """Mix the liquid in the target wells.""" for _ in range(mix_time): @@ -333,7 +341,7 @@ class LiquidHandlerAbstract(LiquidHandler): tip_iter = self.iter_tips(tip_racks) self.current_tip = tip_iter - async def move_to(self, well: Well, dis_to_top: float = 0 , channel: int = 0): + async def move_to(self, well: Well, dis_to_top: float = 0, channel: int = 0): """ Move a single channel to a specific well with a given z-height. @@ -352,4 +360,3 @@ class LiquidHandlerAbstract(LiquidHandler): await self.move_channel_x(channel, abs_loc.x) await self.move_channel_y(channel, abs_loc.y) await self.move_channel_z(channel, abs_loc.z + well_height + dis_to_top) - diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index bcddae55..299db7fe 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -22,8 +22,8 @@ liquid_handler: is_96_well: is_96_well top: top none_keys: none_keys - feedback: { } - result: { } + feedback: {} + result: {} add_liquid: type: LiquidHandlerAdd goal: @@ -43,8 +43,8 @@ liquid_handler: mix_rate: mix_rate mix_liquid_height: mix_liquid_height none_keys: none_keys - feedback: { } - result: { } + feedback: {} + result: {} transfer_liquid: type: LiquidHandlerTransfer goal: @@ -69,8 +69,8 @@ liquid_handler: mix_liquid_height: mix_liquid_height delays: delays none_keys: none_keys - feedback: { } - result: { } + feedback: {} + result: {} mix: type: LiquidHandlerMix goal: @@ -81,16 +81,16 @@ liquid_handler: offsets: offsets mix_rate: mix_rate none_keys: none_keys - feedback: { } - result: { } + feedback: {} + result: {} move_to: type: LiquidHandlerMoveTo goal: well: well dis_to_top: dis_to_top channel: channel - feedback: { } - result: { } + feedback: {} + result: {} aspirate: type: LiquidHandlerAspirate goal: @@ -272,3 +272,62 @@ liquid_handler.revvity: status: status result: success: success + +liquid_handler.biomek: + description: Biomek液体处理器设备,基于pylabrobot控制 + icon: icon_yiyezhan.webp + class: + module: unilabos.devices.liquid_handling.biomek:LiquidHandlerBiomek + type: python + status_types: + status: String + success: Boolean + action_value_mappings: + create_protocol: + type: LiquidHandlerProtocolCreation + goal: + protocol_name: protocol_name + protocol_description: protocol_description + protocol_version: protocol_version + protocol_author: protocol_author + protocol_date: protocol_date + protocol_type: protocol_type + none_keys: none_keys + feedback: {} + result: {} + run_protocol: + type: EmptyIn + goal: {} + feedback: {} + result: {} + transfer_liquid: + type: LiquidHandlerTransfer + goal: + asp_vols: asp_vols + dis_vols: dis_vols + sources: sources + targets: targets + tip_racks: tip_racks + use_channels: use_channels + asp_flow_rates: asp_flow_rates + dis_flow_rates: dis_flow_rates + offsets: offsets + touch_tip: touch_tip + liquid_height: liquid_height + blow_out_air_volume: blow_out_air_volume + spread: spread + is_96_well: is_96_well + mix_stage: mix_stage + mix_times: mix_times + mix_vol: mix_vol + mix_rate: mix_rate + mix_liquid_height: mix_liquid_height + delays: delays + none_keys: none_keys + feedback: {} + result: {} + schema: + type: object + properties: {} + required: [] + additionalProperties: false diff --git a/unilabos/ros/nodes/base_device_node.py b/unilabos/ros/nodes/base_device_node.py index 28b67aa4..daf52300 100644 --- a/unilabos/ros/nodes/base_device_node.py +++ b/unilabos/ros/nodes/base_device_node.py @@ -349,6 +349,20 @@ class BaseROS2DeviceNode(Node, Generic[T]): response = rclient.call(request) # 应该先add_resource了 res.response = "OK" + # 如果driver自己就有assign的方法,那就使用driver自己的assign方法 + if hasattr(self.driver_instance, "create_resource"): + create_resource_func = getattr(self.driver_instance, "create_resource") + create_resource_func( + resource_tracker=self.resource_tracker, + resources=request.resources, + bind_parent_id=bind_parent_id, + bind_location=location, + liquid_input_slot=LIQUID_INPUT_SLOT, + liquid_type=ADD_LIQUID_TYPE, + liquid_volume=LIQUID_VOLUME, + slot_on_deck=slot, + ) + return res # 接下来该根据bind_parent_id进行assign了,目前只有plr可以进行assign,不然没有办法输入到物料系统中 resource = self.resource_tracker.figure_resource({"name": bind_parent_id}) # request.resources = [convert_to_ros_msg(Resource, resources)] diff --git a/unilabos_msgs/CMakeLists.txt b/unilabos_msgs/CMakeLists.txt index 0cd6a1e3..135e5738 100644 --- a/unilabos_msgs/CMakeLists.txt +++ b/unilabos_msgs/CMakeLists.txt @@ -29,6 +29,8 @@ set(action_files "action/HeatChillStart.action" "action/HeatChillStop.action" + "action/LiquidHandlerProtocolCreation.action" + "action/LiquidHandlerAspirate.action" "action/LiquidHandlerDiscardTips.action" "action/LiquidHandlerDispense.action" diff --git a/unilabos_msgs/action/LiquidHandlerProtocolCreation.action b/unilabos_msgs/action/LiquidHandlerProtocolCreation.action new file mode 100644 index 00000000..de8c605a --- /dev/null +++ b/unilabos_msgs/action/LiquidHandlerProtocolCreation.action @@ -0,0 +1,9 @@ +string protocol_name +string protocol_description +string protocol_version +string protocol_author +string protocol_date +string protocol_type +string[] none_keys +--- +--- From 0452a681806d39017774f8e34536e7de82b5f1fc Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Fri, 30 May 2025 16:03:49 +0800 Subject: [PATCH 03/44] Test --- unilabos/devices/liquid_handling/biomek.py | 10 +- .../devices/liquid_handling/convert_biomek.py | 158 ++++++++++++++++++ 2 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 unilabos/devices/liquid_handling/convert_biomek.py diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index c9375e2a..6dd6e288 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -1,7 +1,9 @@ -import requests -from typing import List, Sequence, Optional, Union, Literal +# import requests +# from typing import List, Sequence, Optional, Union, Literal + +# from .liquid_handler_abstract import LiquidHandlerAbstract + -from .liquid_handler_abstract import LiquidHandlerAbstract class LiquidHandlerBiomek(LiquidHandlerAbstract): @@ -16,6 +18,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): self._success = False # 初始成功状态为 False self._status_queue = kwargs.get("status_queue", None) # 状态队列 self.temp_protocol = {} + self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 def create_protocol(self, protocol_name: str, @@ -63,6 +66,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): Returns: dict: 执行结果 """ + #use popen or subprocess to create py32 process and communicate send the temp protocol to it if not self.temp_protocol: raise ValueError("No protocol created. Please create a protocol first.") diff --git a/unilabos/devices/liquid_handling/convert_biomek.py b/unilabos/devices/liquid_handling/convert_biomek.py new file mode 100644 index 00000000..3ed3bc1f --- /dev/null +++ b/unilabos/devices/liquid_handling/convert_biomek.py @@ -0,0 +1,158 @@ + +import json +from typing import Sequence, Optional, List, Union, Literal +json_path = "/Users/guangxinzhang/Documents/Deep Potential/opentrons/convert/protocols/enriched_steps/sci-lucif-assay4.json" + +with open(json_path, "r") as f: + data = json.load(f) + +transfer_example = data[0] +#print(transfer_example) + + +temp_protocol = [] + +sources = transfer_example["sources"] # Assuming sources is a list of Container objects +targets = transfer_example["targets"] # Assuming targets is a list of Container objects +tip_racks = transfer_example["tip_racks"] # Assuming tip_racks is a list of TipRack objects +asp_vols = transfer_example["asp_vols"] # Assuming asp_vols is a list of volumes + +def transfer_liquid( + #self, + sources,#: Sequence[Container], + targets,#: Sequence[Container], + tip_racks,#: Sequence[TipRack], + # *, + # use_channels: Optional[List[int]] = None, + asp_vols: Union[List[float], float], + # dis_vols: Union[List[float], float], + # asp_flow_rates: Optional[List[Optional[float]]] = None, + # dis_flow_rates: Optional[List[Optional[float]]] = None, + # offsets,#: Optional[List[]] = None, + # touch_tip: bool = False, + # liquid_height: Optional[List[Optional[float]]] = None, + # blow_out_air_volume: Optional[List[Optional[float]]] = None, + # spread: Literal["wide", "tight", "custom"] = "wide", + # is_96_well: bool = False, + # mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none", + # mix_times,#: Optional[list() = None, + # mix_vol: Optional[int] = None, + # mix_rate: Optional[int] = None, + # mix_liquid_height: Optional[float] = None, + # delays: Optional[List[int]] = None, + # none_keys: List[str] = [] + ): + # -------- Build Biomek transfer step -------- + # 1) Construct default parameter scaffold (values mirror Biomek “Transfer” block). + transfer_params = { + "Span8": False, + "Pod": "Pod1", + "items": {}, # to be filled below + "Wash": False, + "Dynamic?": True, + "AutoSelectActiveWashTechnique": False, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": True, + "ChangeTipsBetweenSources": False, + "DefaultCaption": "", # filled after we know first pair/vol + "UseExpression": False, + "LeaveTipsOn": False, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": False, + "Replicates": "1", + "ShowTipHandlingDetails": False, + "ShowTransferDetails": True, + "Solvent": "Water", + "Span8Wash": False, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": False, + "SplitVolumeCleaning": False, + "Stop": "Destinations", + "TipLocation": "BC1025F", + "UseCurrentTips": False, + "UseDisposableTips": False, + "UseFixedTips": False, + "UseJIT": True, + "UseMandrelSelection": True, + "UseProbes": [True, True, True, True, True, True, True, True], + "WashCycles": "3", + "WashVolume": "110%", + "Wizard": False + } + + # 2) Build the items mapping (source/dest/volume triplets). + # Priority: user‑provided sources, targets, dis_vols. + items: dict = {} + for idx, (src, dst) in enumerate(zip(sources, targets)): + items[str(idx)] = { + "Source": str(src), + "Destination": str(dst), + "Volume": asp_vols[idx] + } + transfer_params["items"] = items + + return transfer_params + + # # 3) Set a readable caption using the first source/target if available. + # if items: + # first_item = next(iter(items.values())) + # transfer_params["DefaultCaption"] = ( + # f"Transfer {first_item['Volume']} µL from " + # f"{first_item['Source']} to {first_item['Destination']}" + # ) + + # # 4) Append the fully‑formed step to the temp protocol. + # self.temp_protocol.setdefault("steps", []).append({"transfer": transfer_params}) + + + +action = transfer_liquid(sources=sources,targets=targets,tip_racks=tip_racks) +print(action) +# print(action) + + + + +""" + "transfer": { + + "items": {}, + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "Transfer 100 µL from P13 to P3", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC1025F", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [true, true, true, true, true, true, true, true], + "WashCycles": "3", + "WashVolume": "110%", + "Wizard": false +""" + + + + From ea2e9c3e3a7cae8fb95f6f2a79b8dfb9d9e0e6e6 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Fri, 30 May 2025 16:50:13 +0800 Subject: [PATCH 04/44] fix biomek success type --- unilabos/registry/devices/liquid_handler.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index 299db7fe..313a8b80 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -279,9 +279,7 @@ liquid_handler.biomek: class: module: unilabos.devices.liquid_handling.biomek:LiquidHandlerBiomek type: python - status_types: - status: String - success: Boolean + status_types: {} action_value_mappings: create_protocol: type: LiquidHandlerProtocolCreation From cb7c56a1d9a0958b3cb263f91cbcbe73424cdb16 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Fri, 30 May 2025 17:00:06 +0800 Subject: [PATCH 05/44] Convert LH action to biomek. --- unilabos/devices/liquid_handling/biomek.py | 91 +- .../convert_biomek.py | 42 +- .../test liquid handler/sci-lucif-assay4.json | 4033 +++++++++++++++++ 3 files changed, 4116 insertions(+), 50 deletions(-) rename unilabos/devices/liquid_handling/{ => test liquid handler}/convert_biomek.py (84%) create mode 100644 unilabos/devices/liquid_handling/test liquid handler/sci-lucif-assay4.json diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 6dd6e288..12cdf096 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -1,7 +1,7 @@ -# import requests -# from typing import List, Sequence, Optional, Union, Literal +import requests +from typing import List, Sequence, Optional, Union, Literal -# from .liquid_handler_abstract import LiquidHandlerAbstract +from .liquid_handler_abstract import LiquidHandlerAbstract @@ -125,6 +125,8 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): sources: Sequence[Container], targets: Sequence[Container], tip_racks: Sequence[TipRack], + solvent: Optional[str] = None, + TipLocation: Optional[str] = None, *, use_channels: Optional[List[int]] = None, asp_vols: Union[List[float], float], @@ -145,27 +147,62 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): delays: Optional[List[int]] = None, none_keys: List[str] = [] ): - # TODO:需要对好接口,下面这个是临时的 - self.temp_protocol["steps"].append({ - "type": "transfer", - "sources": [source.to_dict() for source in sources], - "targets": [target.to_dict() for target in targets], - "tip_racks": [tip_rack.to_dict() for tip_rack in tip_racks], - "use_channels": use_channels, - "asp_vols": asp_vols, - "dis_vols": dis_vols, - "asp_flow_rates": asp_flow_rates, - "dis_flow_rates": dis_flow_rates, - "offsets": offsets, - "touch_tip": touch_tip, - "liquid_height": liquid_height, - "blow_out_air_volume": blow_out_air_volume, - "spread": spread, - "is_96_well": is_96_well, - "mix_stage": mix_stage, - "mix_times": mix_times, - "mix_vol": mix_vol, - "mix_rate": mix_rate, - "mix_liquid_height": mix_liquid_height, - "delays": delays, - }) \ No newline at end of file + + transfer_params = { + "Span8": False, + "Pod": "Pod1", + "items": {}, + "Wash": False, + "Dynamic?": True, + "AutoSelectActiveWashTechnique": False, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": False, + "ChangeTipsBetweenSources": False, + "DefaultCaption": "", + "UseExpression": False, + "LeaveTipsOn": False, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": False, + "Replicates": "1", + "ShowTipHandlingDetails": False, + "ShowTransferDetails": True, + "Solvent": "Water", + "Span8Wash": False, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": False, + "SplitVolumeCleaning": False, + "Stop": "Destinations", + "TipLocation": "BC1025F", + "UseCurrentTips": False, + "UseDisposableTips": True, + "UseFixedTips": False, + "UseJIT": True, + "UseMandrelSelection": True, + "UseProbes": [True, True, True, True, True, True, True, True], + "WashCycles": "1", + "WashVolume": "110%", + "Wizard": False + } + + items: dict = {} + for idx, (src, dst) in enumerate(zip(sources, targets)): + items[str(idx)] = { + "Source": str(src), + "Destination": str(dst), + "Volume": asp_vols[idx] + } + transfer_params["items"] = items + transfer_params["Solvent"] = solvent if solvent else "Water" + transfer_params["TipLocation"] = TipLocation + + if len(tip_racks) == 1: + transfer_params['UseCurrentTips'] = True + elif len(tip_racks) > 1: + transfer_params["ChangeTipsBetweenDests"] = True + + self.temp_protocol["steps"].append(transfer_params) + + return + \ No newline at end of file diff --git a/unilabos/devices/liquid_handling/convert_biomek.py b/unilabos/devices/liquid_handling/test liquid handler/convert_biomek.py similarity index 84% rename from unilabos/devices/liquid_handling/convert_biomek.py rename to unilabos/devices/liquid_handling/test liquid handler/convert_biomek.py index 3ed3bc1f..712fdd9f 100644 --- a/unilabos/devices/liquid_handling/convert_biomek.py +++ b/unilabos/devices/liquid_handling/test liquid handler/convert_biomek.py @@ -11,20 +11,23 @@ transfer_example = data[0] temp_protocol = [] - +TipLocation = "BC1025F" # Assuming this is a fixed tip location for the transfer sources = transfer_example["sources"] # Assuming sources is a list of Container objects targets = transfer_example["targets"] # Assuming targets is a list of Container objects tip_racks = transfer_example["tip_racks"] # Assuming tip_racks is a list of TipRack objects asp_vols = transfer_example["asp_vols"] # Assuming asp_vols is a list of volumes +solvent = "PBS" def transfer_liquid( #self, sources,#: Sequence[Container], targets,#: Sequence[Container], tip_racks,#: Sequence[TipRack], + TipLocation, # *, # use_channels: Optional[List[int]] = None, asp_vols: Union[List[float], float], + solvent: Optional[str] = None, # dis_vols: Union[List[float], float], # asp_flow_rates: Optional[List[Optional[float]]] = None, # dis_flow_rates: Optional[List[Optional[float]]] = None, @@ -44,6 +47,7 @@ def transfer_liquid( ): # -------- Build Biomek transfer step -------- # 1) Construct default parameter scaffold (values mirror Biomek “Transfer” block). + transfer_params = { "Span8": False, "Pod": "Pod1", @@ -52,7 +56,7 @@ def transfer_liquid( "Dynamic?": True, "AutoSelectActiveWashTechnique": False, "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": True, + "ChangeTipsBetweenDests": False, "ChangeTipsBetweenSources": False, "DefaultCaption": "", # filled after we know first pair/vol "UseExpression": False, @@ -72,18 +76,16 @@ def transfer_liquid( "Stop": "Destinations", "TipLocation": "BC1025F", "UseCurrentTips": False, - "UseDisposableTips": False, + "UseDisposableTips": True, "UseFixedTips": False, "UseJIT": True, "UseMandrelSelection": True, "UseProbes": [True, True, True, True, True, True, True, True], - "WashCycles": "3", + "WashCycles": "1", "WashVolume": "110%", "Wizard": False } - # 2) Build the items mapping (source/dest/volume triplets). - # Priority: user‑provided sources, targets, dis_vols. items: dict = {} for idx, (src, dst) in enumerate(zip(sources, targets)): items[str(idx)] = { @@ -92,24 +94,18 @@ def transfer_liquid( "Volume": asp_vols[idx] } transfer_params["items"] = items + transfer_params["Solvent"] = solvent if solvent else "Water" + transfer_params["TipLocation"] = TipLocation + + if len(tip_racks) == 1: + transfer_params['UseCurrentTips'] = True + elif len(tip_racks) > 1: + transfer_params["ChangeTipsBetweenDests"] = True return transfer_params - # # 3) Set a readable caption using the first source/target if available. - # if items: - # first_item = next(iter(items.values())) - # transfer_params["DefaultCaption"] = ( - # f"Transfer {first_item['Volume']} µL from " - # f"{first_item['Source']} to {first_item['Destination']}" - # ) - - # # 4) Append the fully‑formed step to the temp protocol. - # self.temp_protocol.setdefault("steps", []).append({"transfer": transfer_params}) - - - -action = transfer_liquid(sources=sources,targets=targets,tip_racks=tip_racks) -print(action) +action = transfer_liquid(sources=sources,targets=targets,tip_racks=tip_racks, asp_vols=asp_vols,solvent = solvent, TipLocation=TipLocation) +print(json.dumps(action,indent=2)) # print(action) @@ -132,9 +128,9 @@ print(action) "Repeats": "1", "RepeatsByVolume": false, "Replicates": "1", - "ShowTipHandlingDetails": false, + "ShowTipHandlingDetails": true, "ShowTransferDetails": true, - "Solvent": "Water", + "Span8Wash": false, "Span8WashVolume": "2", "Span8WasteVolume": "1", diff --git a/unilabos/devices/liquid_handling/test liquid handler/sci-lucif-assay4.json b/unilabos/devices/liquid_handling/test liquid handler/sci-lucif-assay4.json new file mode 100644 index 00000000..012a1606 --- /dev/null +++ b/unilabos/devices/liquid_handling/test liquid handler/sci-lucif-assay4.json @@ -0,0 +1,4033 @@ +[ + { + "template": "transfer", + "sources": [ + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + } + ], + "targets": [ + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + } + ], + "tip_racks": [ + { + "well": "A1", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A2", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A3", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A4", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A5", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A6", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A7", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A8", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A9", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A10", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A11", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + }, + { + "well": "A12", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 8 + } + ], + "use_channels": null, + "asp_vols": [ + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0 + ], + "asp_flow_rates": [ + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8 + ], + "disp_vols": [ + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0, + 120.0 + ], + "dis_flow_rates": [ + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0 + ], + "offsets": null, + "touch_tip": false, + "liquid_height": null, + "blow_out_air_volume": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "is_96_well": false, + "mix_stage": "none", + "mix_times": 0, + "mix_vol": null, + "mix_rate": null, + "mix_liquid_height": null, + "delays": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "top": [ + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5 + ], + "bottom": [ + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null + ], + "move": [ + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null + ], + "center": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + "move_to": [ + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ], + "mix_detail": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ] + }, + { + "template": "transfer", + "sources": [ + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "reagent stock", + "slot": 3 + } + ], + "targets": [ + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + } + ], + "tip_racks": [ + { + "well": "A1", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + } + ], + "use_channels": null, + "asp_vols": [ + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0 + ], + "asp_flow_rates": [ + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0 + ], + "disp_vols": [ + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0, + 70.0 + ], + "dis_flow_rates": [ + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2 + ], + "offsets": null, + "touch_tip": true, + "liquid_height": null, + "blow_out_air_volume": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "is_96_well": false, + "mix_stage": "none", + "mix_times": 0, + "mix_vol": null, + "mix_rate": null, + "mix_liquid_height": null, + "delays": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "top": [ + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2, + null, + -2 + ], + "bottom": [ + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null + ], + "move": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "center": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + "move_to": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ], + "mix_detail": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ] + }, + { + "template": "transfer", + "sources": [ + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + } + ], + "targets": [ + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + }, + { + "well": "A1", + "labware": "waste", + "slot": 9 + } + ], + "tip_racks": [ + { + "well": "A2", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A3", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A4", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A5", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A6", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A7", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A8", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A9", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A10", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A11", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A12", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 11 + }, + { + "well": "A1", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + } + ], + "use_channels": null, + "asp_vols": [ + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0 + ], + "asp_flow_rates": [ + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8, + 18.8 + ], + "disp_vols": [ + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0 + ], + "dis_flow_rates": [ + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0 + ], + "offsets": null, + "touch_tip": false, + "liquid_height": null, + "blow_out_air_volume": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "is_96_well": false, + "mix_stage": "none", + "mix_times": 0, + "mix_vol": null, + "mix_rate": null, + "mix_liquid_height": null, + "delays": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "top": [ + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5, + null, + -5 + ], + "bottom": [ + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null, + 0.2, + null + ], + "move": [ + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null, + [ + -2.5, + 0.0, + 0.0 + ], + null + ], + "center": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + "move_to": [ + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + -0.2 + ], + "bottom": [ + null + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ], + "mix_detail": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ] + }, + { + "template": "transfer", + "sources": [ + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "reagent stock", + "slot": 3 + } + ], + "targets": [ + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + } + ], + "tip_racks": [ + { + "well": "A2", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + } + ], + "use_channels": null, + "asp_vols": [ + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0 + ], + "asp_flow_rates": [ + 47.0, + 47.0, + 47.0, + 47.0, + 47.0, + 47.0, + 47.0, + 47.0, + 47.0, + 47.0, + 47.0, + 47.0 + ], + "disp_vols": [ + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0, + 30.0 + ], + "dis_flow_rates": [ + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2, + 28.2 + ], + "offsets": null, + "touch_tip": true, + "liquid_height": null, + "blow_out_air_volume": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "is_96_well": false, + "mix_stage": "none", + "mix_times": 0, + "mix_vol": null, + "mix_rate": null, + "mix_liquid_height": null, + "delays": [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0 + ], + "top": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "bottom": [ + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5, + 0.5, + 5 + ], + "move": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "center": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + "move_to": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ], + "mix_detail": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ] + }, + { + "template": "transfer", + "sources": [ + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "reagent stock", + "slot": 3 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + } + ], + "targets": [ + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A1", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A2", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A3", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A4", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A5", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A6", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A7", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A8", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A9", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A10", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A11", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + }, + { + "well": "A12", + "labware": "working plate", + "slot": 6 + } + ], + "tip_racks": [ + { + "well": "A3", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A4", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A5", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A6", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A7", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A8", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A9", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A10", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A11", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A12", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 1 + }, + { + "well": "A1", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 4 + }, + { + "well": "A2", + "type": "Opentrons OT-2 96 Tip Rack 300 \u00b5L", + "slot": 4 + } + ], + "use_channels": null, + "asp_vols": [ + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0 + ], + "asp_flow_rates": [ + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0 + ], + "disp_vols": [ + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0, + 75.0 + ], + "dis_flow_rates": [ + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0, + 282.0 + ], + "offsets": null, + "touch_tip": true, + "liquid_height": null, + "blow_out_air_volume": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "is_96_well": false, + "mix_stage": "after", + "mix_times": [ + 3 + ], + "mix_vol": 75.0, + "mix_rate": null, + "mix_liquid_height": null, + "delays": [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ], + "top": [ + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5, + null, + -0.5 + ], + "bottom": [ + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null, + 0.5, + null + ], + "move": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "center": [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + "move_to": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + } + ], + "mix_detail": [ + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + }, + { + "top": [], + "bottom": [], + "move": [], + "center": [] + }, + { + "top": [ + null + ], + "bottom": [ + 0.5 + ], + "move": [ + null + ], + "center": [ + false + ] + } + ] + } +] \ No newline at end of file From 208540b307a38bfe27dc3f402d48d190e5ac1e39 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Fri, 30 May 2025 17:08:19 +0800 Subject: [PATCH 06/44] Update biomek.py --- unilabos/devices/liquid_handling/biomek.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 12cdf096..7692905e 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -175,7 +175,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): "SplitVolumeCleaning": False, "Stop": "Destinations", "TipLocation": "BC1025F", - "UseCurrentTips": False, + "UseCurrentTips": False, "UseDisposableTips": True, "UseFixedTips": False, "UseJIT": True, @@ -205,4 +205,4 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): self.temp_protocol["steps"].append(transfer_params) return - \ No newline at end of file + s \ No newline at end of file From 0f2555c90c8d7bce040ca934895c9d0ef4e0c7cc Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sat, 31 May 2025 00:00:39 +0800 Subject: [PATCH 07/44] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E8=A1=A8=E4=B8=8A?= =?UTF-8?q?=E6=8A=A5handle=E5=92=8Cschema=20(param=20input)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pump_and_valve/solenoid_valve_mock.py | 8 +-- .../pump_and_valve/vacuum_pump_mock.py | 6 +- unilabos/registry/devices/liquid_handler.yaml | 15 +++++ unilabos/registry/devices/pump_and_valve.yaml | 41 ++++++++++-- .../registry/devices/vacuum_and_purge.yaml | 67 +++++++++++++++++++ unilabos/registry/devices/work_station.yaml | 2 +- unilabos/registry/registry.py | 16 ++++- 7 files changed, 139 insertions(+), 16 deletions(-) diff --git a/unilabos/devices/pump_and_valve/solenoid_valve_mock.py b/unilabos/devices/pump_and_valve/solenoid_valve_mock.py index 08820ca0..b6735a3f 100644 --- a/unilabos/devices/pump_and_valve/solenoid_valve_mock.py +++ b/unilabos/devices/pump_and_valve/solenoid_valve_mock.py @@ -5,22 +5,22 @@ class SolenoidValveMock: def __init__(self, port: str = "COM6"): self._status = "Idle" self._valve_position = "OPEN" - + @property def status(self) -> str: return self._status - + @property def valve_position(self) -> str: return self._valve_position def get_valve_position(self) -> str: return self._valve_position - + def set_valve_position(self, position): self._status = "Busy" time.sleep(5) - + self._valve_position = position time.sleep(5) self._status = "Idle" diff --git a/unilabos/devices/pump_and_valve/vacuum_pump_mock.py b/unilabos/devices/pump_and_valve/vacuum_pump_mock.py index 3e330570..96a48426 100644 --- a/unilabos/devices/pump_and_valve/vacuum_pump_mock.py +++ b/unilabos/devices/pump_and_valve/vacuum_pump_mock.py @@ -4,17 +4,17 @@ import time class VacuumPumpMock: def __init__(self, port: str = "COM6"): self._status = "OPEN" - + @property def status(self) -> str: return self._status def get_status(self) -> str: return self._status - + def set_status(self, position): time.sleep(5) - + self._status = position time.sleep(5) diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index 313a8b80..95f06ca6 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -245,6 +245,21 @@ liquid_handler: target_vols: target_vols aspiration_flow_rate: aspiration_flow_rate dispense_flow_rates: dispense_flow_rates + handles: + input: + - handler_key: liquid-input + label: Liquid Input + data_type: resource + io_type: target + data_source: handle + data_key: liquid + output: + - handler_key: liquid-output + label: Liquid Output + data_type: resource + io_type: source + data_source: executor + data_key: liquid schema: type: object properties: diff --git a/unilabos/registry/devices/pump_and_valve.yaml b/unilabos/registry/devices/pump_and_valve.yaml index 5fdd8606..fd5dd98e 100644 --- a/unilabos/registry/devices/pump_and_valve.yaml +++ b/unilabos/registry/devices/pump_and_valve.yaml @@ -23,20 +23,51 @@ syringe_pump_with_valve.runze: type: string description: The position of the valve required: - - status - - position - - valve_position + - status + - position + - valve_position additionalProperties: false - solenoid_valve.mock: description: Mock solenoid valve class: module: unilabos.devices.pump_and_valve.solenoid_valve_mock:SolenoidValveMock type: python + status_types: + status: String + valve_position: String + action_value_mappings: + open: + type: EmptyIn + goal: {} + feedback: {} + result: {} + close: + type: EmptyIn + goal: {} + feedback: {} + result: {} + handles: + input: + - handler_key: fluid-input + label: Fluid Input + data_type: fluid + output: + - handler_key: fluid-output + label: Fluid Output + data_type: fluid + init_param_schema: + type: object + properties: + port: + type: string + description: "通信端口" + default: "COM6" + required: + - port solenoid_valve: description: Solenoid valve class: module: unilabos.devices.pump_and_valve.solenoid_valve:SolenoidValve - type: python \ No newline at end of file + type: python diff --git a/unilabos/registry/devices/vacuum_and_purge.yaml b/unilabos/registry/devices/vacuum_and_purge.yaml index 236ceddc..b6108203 100644 --- a/unilabos/registry/devices/vacuum_and_purge.yaml +++ b/unilabos/registry/devices/vacuum_and_purge.yaml @@ -22,9 +22,76 @@ vacuum_pump.mock: string: string feedback: {} result: {} + handles: + input: + - handler_key: fluid-input + label: Fluid Input + data_type: fluid + io_type: target + data_source: handle + data_key: fluid_in + output: + - handler_key: fluid-output + label: Fluid Output + data_type: fluid + io_type: source + data_source: executor + data_key: fluid_out + init_param_schema: + type: object + properties: + port: + type: string + description: "通信端口" + default: "COM6" + required: + - port gas_source.mock: description: Mock gas source class: module: unilabos.devices.pump_and_valve.vacuum_pump_mock:VacuumPumpMock type: python + status_types: + status: String + action_value_mappings: + open: + type: EmptyIn + goal: {} + feedback: {} + result: {} + close: + type: EmptyIn + goal: {} + feedback: {} + result: {} + set_status: + type: StrSingleInput + goal: + string: string + feedback: {} + result: {} + handles: + input: + - handler_key: fluid-input + label: Fluid Input + data_type: fluid + io_type: target + data_source: handle + data_key: fluid_in + output: + - handler_key: fluid-output + label: Fluid Output + data_type: fluid + io_type: source + data_source: executor + data_key: fluid_out + init_param_schema: + type: object + properties: + port: + type: string + description: "通信端口" + default: "COM6" + required: + - port diff --git a/unilabos/registry/devices/work_station.yaml b/unilabos/registry/devices/work_station.yaml index fadfd5ec..d3a37338 100644 --- a/unilabos/registry/devices/work_station.yaml +++ b/unilabos/registry/devices/work_station.yaml @@ -4,4 +4,4 @@ workstation: module: unilabos.ros.nodes.presets.protocol_node:ROS2ProtocolNode type: ros2 schema: - properties: {} \ No newline at end of file + properties: {} diff --git a/unilabos/registry/registry.py b/unilabos/registry/registry.py index c68e0d8d..4cfb7dab 100644 --- a/unilabos/registry/registry.py +++ b/unilabos/registry/registry.py @@ -25,9 +25,7 @@ class Registry: self.ResourceCreateFromOuterEasy = self._replace_type_with_class( "ResourceCreateFromOuterEasy", "host_node", f"动作 create_resource" ) - self.EmptyIn = self._replace_type_with_class( - "EmptyIn", "host_node", f"" - ) + self.EmptyIn = self._replace_type_with_class("EmptyIn", "host_node", f"") self.device_type_registry = {} self.resource_type_registry = {} self._setup_called = False # 跟踪setup是否已调用 @@ -99,6 +97,8 @@ class Registry: }, "icon": "icon_device.webp", "registry_type": "device", + "handles": [], + "init_param_schema": {}, "schema": {"properties": {}, "additionalProperties": False, "type": "object"}, "file_path": "/", } @@ -132,6 +132,12 @@ class Registry: resource_info["description"] = "" if "icon" not in resource_info: resource_info["icon"] = "" + if "icon" not in resource_info: + resource_info["icon"] = "" + if "handles" not in resource_info: + resource_info["handles"] = [] + if "init_param_schema" not in resource_info: + resource_info["init_param_schema"] = {} resource_info["registry_type"] = "resource" self.resource_type_registry.update(data) logger.debug( @@ -194,6 +200,10 @@ class Registry: device_config["description"] = "" if "icon" not in device_config: device_config["icon"] = "" + if "handles" not in device_config: + device_config["handles"] = [] + if "init_param_schema" not in device_config: + device_config["init_param_schema"] = {} device_config["registry_type"] = "device" if "class" in device_config: # 处理状态类型 From 478a85951c29221e926b4f62d50489b533cbbdf0 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sat, 31 May 2025 00:00:55 +0800 Subject: [PATCH 08/44] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbiomek=E7=BC=BA?= =?UTF-8?q?=E5=B0=91=E7=9A=84=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/devices/liquid_handling/biomek.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index ccca72d1..41812d15 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -30,6 +30,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): protocol_version: str, protocol_author: str, protocol_date: str, + protocol_type: str, none_keys: List[str] = [], ): """ @@ -54,6 +55,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): "version": protocol_version, "author": protocol_author, "date": protocol_date, + "type": protocol_type, }, "labwares": [], "steps": [], From 6f6c70ee57b439647e047ac6b11560010b345df3 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Wed, 4 Jun 2025 13:11:45 +0800 Subject: [PATCH 09/44] delete 's' --- unilabos/devices/liquid_handling/biomek.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index ccca72d1..dc24dd2f 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -209,4 +209,4 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): self.temp_protocol["steps"].append(transfer_params) return - s + From 8a29bc5597ae5ef33f5f15f91b625f700aa64a71 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Wed, 4 Jun 2025 13:20:12 +0800 Subject: [PATCH 10/44] Remove warnings --- unilabos/devices/liquid_handling/biomek.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index dc24dd2f..8d32cb2c 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -2,11 +2,19 @@ import requests from typing import List, Sequence, Optional, Union, Literal from geometry_msgs.msg import Point from unilabos_msgs.msg import Resource - +from pylabrobot.liquid_handling import LiquidHandler +from pylabrobot.resources import ( + Resource, + TipRack, + Container, + Coordinate, + Well +) from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker # type: ignore from .liquid_handler_abstract import LiquidHandlerAbstract - +import json +from typing import Sequence, Optional, List, Union, Literal class LiquidHandlerBiomek(LiquidHandlerAbstract): @@ -92,6 +100,10 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): liquid_type: list[str], liquid_volume: list[int], slot_on_deck: int, + res_id, + class_name, + bind_locations, + parent ): """ 创建一个新的资源。 From 807dcdd226b5b032e2d2b2bcf534a5f8949c0d08 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Wed, 4 Jun 2025 13:27:05 +0800 Subject: [PATCH 11/44] Update biomek.py --- unilabos/devices/liquid_handling/biomek.py | 1 - 1 file changed, 1 deletion(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 8d32cb2c..211d239b 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -2,7 +2,6 @@ import requests from typing import List, Sequence, Optional, Union, Literal from geometry_msgs.msg import Point from unilabos_msgs.msg import Resource -from pylabrobot.liquid_handling import LiquidHandler from pylabrobot.resources import ( Resource, TipRack, From 147b8f47c0c2f85580f2876522ac39bf55db5642 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Wed, 4 Jun 2025 16:38:18 +0800 Subject: [PATCH 12/44] Biomek test --- unilabos/devices/liquid_handling/biomek.py | 62 +- .../devices/liquid_handling/biomek_test.py | 568 ++++++++++++++++++ 2 files changed, 623 insertions(+), 7 deletions(-) create mode 100644 unilabos/devices/liquid_handling/biomek_test.py diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index edbecf88..3ba1f75e 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -15,8 +15,8 @@ from .liquid_handler_abstract import LiquidHandlerAbstract import json from typing import Sequence, Optional, List, Union, Literal - class LiquidHandlerBiomek(LiquidHandlerAbstract): + """ Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 该类用于处理Biomek液体处理器的特定操作。 @@ -29,6 +29,28 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): self._status_queue = kwargs.get("status_queue", None) # 状态队列 self.temp_protocol = {} self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 + self.technique = { + 'MC P300 high':{ + "use_channels": "Span8", + "asp_vols": [50], + "asp_flow_rates": 50, + "dis_flow_rates": 50, + "offsets": None, + "touch_tip": True, + "liquid_height": 20, + "blow_out_air_volume": 20, + "spread": "wide", + "is_96_well": True, + "mix_stage": "none", + "mix_times": None, + "mix_vol": None, + "mix_rate": None, + "mix_liquid_height": None, + "delays": None, + "none_keys": [] + } + } + def create_protocol( self, @@ -143,7 +165,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): targets: Sequence[Container], tip_racks: Sequence[TipRack], solvent: Optional[str] = None, - TipLocation: Optional[str] = None, + TipLocation :str = None, *, use_channels: Optional[List[int]] = None, asp_vols: Union[List[float], float], @@ -157,7 +179,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): spread: Literal["wide", "tight", "custom"] = "wide", is_96_well: bool = False, mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none", - mix_times: Optional[List(int)] = None, + mix_times: Optional[int] = None, mix_vol: Optional[int] = None, mix_rate: Optional[int] = None, mix_liquid_height: Optional[float] = None, @@ -208,18 +230,44 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): items[str(idx)] = { "Source": str(src), "Destination": str(dst), - "Volume": asp_vols[idx] + "Volume": dis_vols[idx] } transfer_params["items"] = items transfer_params["Solvent"] = solvent if solvent else "Water" transfer_params["TipLocation"] = TipLocation if len(tip_racks) == 1: - transfer_params['UseCurrentTips'] = True + transfer_params['UseCurrentTips'] = True elif len(tip_racks) > 1: transfer_params["ChangeTipsBetweenDests"] = True self.temp_protocol["steps"].append(transfer_params) - + + return + + def transfer_biomek( + self, + parameters: dict, + technique: str, + ): + """ + 处理Biomek的液体转移操作。 + + """ + sources = parameters.get("source") + targets = parameters.get("target") + tip_rack = parameters.get("tip_rack") + volume = parameters.get("volume") + liquid_type = parameters.get("liquid_type", "Well Content") + other_params = self.technique.get(technique, {}) + + self.transfer_liquid( + sources=[sources], + targets=[targets], + TipLocation=tip_rack, + tip_racks=[tip_rack], + solvent=liquid_type, + dis_vols=[volume], + **other_params + ) return - diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py new file mode 100644 index 00000000..1aa01cec --- /dev/null +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -0,0 +1,568 @@ +import requests +from typing import List, Sequence, Optional, Union, Literal +# from geometry_msgs.msg import Point +# from unilabos_msgs.msg import Resource +from pylabrobot.resources import ( + Resource, + TipRack, + Container, + Coordinate, + Well +) +# from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker # type: ignore +# from .liquid_handler_abstract import LiquidHandlerAbstract + +import json +from typing import Sequence, Optional, List, Union, Literal + +steps_info = ''' +{ + "steps": [ + { + "step_number": 1, + "operation": "transfer", + "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", + "parameters": { + "source": "P1", + "target": "P11", + "tip_rack": "BC230", + "volume": 50 + } + }, + { + "step_number": 2, + "operation": "transfer", + "description": "加入2倍体积Bind Beads BC至产物中", + "parameters": { + "source": "P2", + "target": "P11", + "tip_rack": "BC230", + "volume": 100 + } + }, + { + "step_number": 3, + "operation": "move_labware", + "description": "移动P11至Orbital1用于振荡混匀", + "parameters": { + "source": "P11", + "target": "Orbital1" + } + }, + { + "step_number": 4, + "operation": "oscillation", + "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", + "parameters": { + "rpm": 800, + "time": 300 + } + }, + { + "step_number": 5, + "operation": "move_labware", + "description": "移动混匀后的板回P11", + "parameters": { + "source": "Orbital1", + "target": "P11" + } + }, + { + "step_number": 6, + "operation": "move_labware", + "description": "将P11移动到磁力架(P12)吸附3分钟", + "parameters": { + "source": "P11", + "target": "P12" + } + }, + { + "step_number": 7, + "operation": "incubation", + "description": "磁力架上室温静置3分钟完成吸附", + "parameters": { + "time": 180 + } + }, + { + "step_number": 8, + "operation": "transfer", + "description": "去除上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 150 + } + }, + { + "step_number": 9, + "operation": "transfer", + "description": "加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 10, + "operation": "move_labware", + "description": "移动清洗板到Orbital1进行振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 11, + "operation": "oscillation", + "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 12, + "operation": "move_labware", + "description": "振荡后将板移回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 13, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 14, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 15, + "operation": "transfer", + "description": "第二次加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 16, + "operation": "move_labware", + "description": "再次移动清洗板到Orbital1振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 17, + "operation": "oscillation", + "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 18, + "operation": "move_labware", + "description": "振荡后板送回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 19, + "operation": "incubation", + "description": "再次吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 20, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 21, + "operation": "incubation", + "description": "空气干燥15分钟", + "parameters": { + "time": 900 + } + }, + { + "step_number": 22, + "operation": "transfer", + "description": "加30-50μl Elution Buffer洗脱", + "parameters": { + "source": "P4", + "target": "P12", + "tip_rack": "BC230", + "volume": 40 + } + }, + { + "step_number": 23, + "operation": "move_labware", + "description": "移动到Orbital1振荡混匀(60秒)", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 24, + "operation": "oscillation", + "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 25, + "operation": "move_labware", + "description": "振荡后送回磁力架P12", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 26, + "operation": "incubation", + "description": "室温静置3分钟(洗脱反应)", + "parameters": { + "time": 180 + } + }, + { + "step_number": 27, + "operation": "transfer", + "description": "将上清液(DNA)转移到新板(P13)", + "parameters": { + "source": "P12", + "target": "P13", + "tip_rack": "BC230", + "volume": 40 + } + } + ] +} +''' + + + +#class LiquidHandlerBiomek(LiquidHandlerAbstract): + + +class LiquidHandlerBiomek: + """ + Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 + 该类用于处理Biomek液体处理器的特定操作。 + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._status = "Idle" # 初始状态为 Idle + self._success = False # 初始成功状态为 False + self._status_queue = kwargs.get("status_queue", None) # 状态队列 + self.temp_protocol = {} + self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 + self.technique = { + 'MC P300 high':{ + "use_channels": "Span8", + "asp_vols": [50], + "asp_flow_rates": 50, + "dis_flow_rates": 50, + "offsets": None, + "touch_tip": True, + "liquid_height": 20, + "blow_out_air_volume": 20, + "spread": "wide", + "is_96_well": True, + "mix_stage": "none", + "mix_times": None, + "mix_vol": None, + "mix_rate": None, + "mix_liquid_height": None, + "delays": None, + "none_keys": [] + } + } + + + def create_protocol( + self, + protocol_name: str, + protocol_description: str, + protocol_version: str, + protocol_author: str, + protocol_date: str, + protocol_type: str, + none_keys: List[str] = [], + ): + """ + 创建一个新的协议。 + + Args: + protocol_name (str): 协议名称 + protocol_description (str): 协议描述 + protocol_version (str): 协议版本 + protocol_author (str): 协议作者 + protocol_date (str): 协议日期 + protocol_type (str): 协议类型 + none_keys (List[str]): 需要设置为None的键列表 + + Returns: + dict: 创建的协议字典 + """ + self.temp_protocol = { + "meta": { + "name": protocol_name, + "description": protocol_description, + "version": protocol_version, + "author": protocol_author, + "date": protocol_date, + "type": protocol_type, + }, + "labwares": [], + "steps": [], + } + return self.temp_protocol + +# def run_protocol(self): +# """ +# 执行创建的实验流程。 +# 工作站的完整执行流程是, +# 从 create_protocol 开始,创建新的 method, +# 随后执行 transfer_liquid 等操作向实验流程添加步骤, +# 最后 run_protocol 执行整个方法。 + +# Returns: +# dict: 执行结果 +# """ +# #use popen or subprocess to create py32 process and communicate send the temp protocol to it +# if not self.temp_protocol: +# raise ValueError("No protocol created. Please create a protocol first.") + +# # 模拟执行协议 +# self._status = "Running" +# self._success = True +# # 在这里可以添加实际执行协议的逻辑 + +# response = requests.post("localhost:5000/api/protocols", json=self.temp_protocol) + +# def create_resource( +# self, +# resource_tracker: DeviceNodeResourceTracker, +# resources: list[Resource], +# bind_parent_id: str, +# bind_location: dict[str, float], +# liquid_input_slot: list[int], +# liquid_type: list[str], +# liquid_volume: list[int], +# slot_on_deck: int, +# res_id, +# class_name, +# bind_locations, +# parent +# ): +# """ +# 创建一个新的资源。 + +# Args: +# device_id (str): 设备ID +# res_id (str): 资源ID +# class_name (str): 资源类名 +# parent (str): 父级ID +# bind_locations (Point): 绑定位置 +# liquid_input_slot (list[int]): 液体输入槽列表 +# liquid_type (list[str]): 液体类型列表 +# liquid_volume (list[int]): 液体体积列表 +# slot_on_deck (int): 甲板上的槽位 + +# Returns: +# dict: 创建的资源字典 +# """ +# # TODO:需要对好接口,下面这个是临时的 +# resource = { +# "id": res_id, +# "class": class_name, +# "parent": parent, +# "bind_locations": bind_locations.to_dict(), +# "liquid_input_slot": liquid_input_slot, +# "liquid_type": liquid_type, +# "liquid_volume": liquid_volume, +# "slot_on_deck": slot_on_deck, +# } +# self.temp_protocol["labwares"].append(resource) +# return resource + + def transfer_liquid( + self, + sources: Sequence[Container], + targets: Sequence[Container], + tip_racks: Sequence[TipRack], + solvent: Optional[str] = None, + TipLocation :str = None, + *, + use_channels: Optional[List[int]] = None, + asp_vols: Union[List[float], float], + dis_vols: Union[List[float], float], + asp_flow_rates: Optional[List[Optional[float]]] = None, + dis_flow_rates: Optional[List[Optional[float]]] = None, + offsets: Optional[List[Coordinate]] = None, + touch_tip: bool = False, + liquid_height: Optional[List[Optional[float]]] = None, + blow_out_air_volume: Optional[List[Optional[float]]] = None, + spread: Literal["wide", "tight", "custom"] = "wide", + is_96_well: bool = False, + mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none", + mix_times: Optional[int] = None, + mix_vol: Optional[int] = None, + mix_rate: Optional[int] = None, + mix_liquid_height: Optional[float] = None, + delays: Optional[List[int]] = None, + none_keys: List[str] = [] + ): + + transfer_params = { + "Span8": False, + "Pod": "Pod1", + "items": {}, + "Wash": False, + "Dynamic?": True, + "AutoSelectActiveWashTechnique": False, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": False, + "ChangeTipsBetweenSources": False, + "DefaultCaption": "", + "UseExpression": False, + "LeaveTipsOn": False, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": False, + "Replicates": "1", + "ShowTipHandlingDetails": False, + "ShowTransferDetails": True, + "Solvent": "Water", + "Span8Wash": False, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": False, + "SplitVolumeCleaning": False, + "Stop": "Destinations", + "TipLocation": "BC1025F", + "UseCurrentTips": False, + "UseDisposableTips": True, + "UseFixedTips": False, + "UseJIT": True, + "UseMandrelSelection": True, + "UseProbes": [True, True, True, True, True, True, True, True], + "WashCycles": "1", + "WashVolume": "110%", + "Wizard": False + } + + items: dict = {} + for idx, (src, dst) in enumerate(zip(sources, targets)): + items[str(idx)] = { + "Source": str(src), + "Destination": str(dst), + "Volume": dis_vols[idx] + } + transfer_params["items"] = items + transfer_params["Solvent"] = solvent if solvent else "Water" + transfer_params["TipLocation"] = TipLocation + + if len(tip_racks) == 1: + transfer_params['UseCurrentTips'] = True + elif len(tip_racks) > 1: + transfer_params["ChangeTipsBetweenDests"] = True + + self.temp_protocol["steps"].append(transfer_params) + + return + + def transfer_biomek( + self, + parameters: dict, + technique: str, + ): + """ + 创建一个Biomek液体处理器的转移步骤。 + + Args: + step_number (int): 步骤编号 + operation (str): 操作类型 + description (str): 步骤描述 + parameters (dict): 步骤参数 + + Returns: + dict: 创建的转移步骤字典 + """ + + sources = parameters.get("source") + targets = parameters.get("target") + tip_rack = parameters.get("tip_rack") + volume = parameters.get("volume") + liquid_type = parameters.get("liquid_type", "Well Content") + other_params = self.technique.get(technique, {}) + + self.transfer_liquid( + sources=[sources], + targets=[targets], + TipLocation=tip_rack, + tip_racks=[tip_rack], + solvent=liquid_type, + dis_vols=[volume], + **other_params + ) + + return + +handler = LiquidHandlerBiomek() + +handler.temp_protocol = { + "meta": {}, + "labwares": [], + "steps": [] +} +input_steps = json.loads(steps_info) + +for step in input_steps['steps']: + if step['operation'] != 'transfer': + continue + parameters = step['parameters'] + handler.transfer_biomek(parameters, technique='MC P300 high') + +print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) + From 5b240cb0ea70ff0d2b28b0ef31c0fc8f582510df Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Wed, 4 Jun 2025 17:30:53 +0800 Subject: [PATCH 13/44] Update biomek.py --- unilabos/devices/liquid_handling/biomek.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 3ba1f75e..c0bde755 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -2,13 +2,13 @@ import requests from typing import List, Sequence, Optional, Union, Literal from geometry_msgs.msg import Point from unilabos_msgs.msg import Resource + from pylabrobot.resources import ( - Resource, TipRack, Container, Coordinate, - Well ) + from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker # type: ignore from .liquid_handler_abstract import LiquidHandlerAbstract @@ -123,10 +123,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): liquid_type: list[str], liquid_volume: list[int], slot_on_deck: int, - res_id, - class_name, - bind_locations, - parent + ): """ 创建一个新的资源。 @@ -146,6 +143,16 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): dict: 创建的资源字典 """ # TODO:需要对好接口,下面这个是临时的 + for resource in resources: + res_id = resource.id + class_name = resource.class_name + parent = bind_parent_id + bind_locations = Coordinate.from_point(resource.bind_location) + liquid_input_slot = liquid_input_slot + liquid_type = liquid_type + liquid_volume = liquid_volume + slot_on_deck = slot_on_deck + resource = { "id": res_id, "class": class_name, From c5a495f4093c45c67f3e17ef34176049f4e5cfe1 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Wed, 4 Jun 2025 19:03:00 +0800 Subject: [PATCH 14/44] =?UTF-8?q?=E6=96=B0=E5=A2=9Etransfer=5Fbiomek?= =?UTF-8?q?=E7=9A=84msg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/registry/devices/liquid_handler.yaml | 1 + unilabos/registry/registry.py | 2 -- unilabos/ros/msgs/message_converter.py | 2 +- unilabos_msgs/CMakeLists.txt | 1 + unilabos_msgs/action/LiquidHandlerTransferBiomek.action | 9 +++++++++ 5 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 unilabos_msgs/action/LiquidHandlerTransferBiomek.action diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index 95f06ca6..b3b011e2 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -1,5 +1,6 @@ liquid_handler: description: Liquid handler device controlled by pylabrobot + icon: icon_yiyezhan.webp class: module: unilabos.devices.liquid_handling.liquid_handler_abstract:LiquidHandlerAbstract type: python diff --git a/unilabos/registry/registry.py b/unilabos/registry/registry.py index 4cfb7dab..e95d25aa 100644 --- a/unilabos/registry/registry.py +++ b/unilabos/registry/registry.py @@ -132,8 +132,6 @@ class Registry: resource_info["description"] = "" if "icon" not in resource_info: resource_info["icon"] = "" - if "icon" not in resource_info: - resource_info["icon"] = "" if "handles" not in resource_info: resource_info["handles"] = [] if "init_param_schema" not in resource_info: diff --git a/unilabos/ros/msgs/message_converter.py b/unilabos/ros/msgs/message_converter.py index 11c7afd5..94b12cfe 100644 --- a/unilabos/ros/msgs/message_converter.py +++ b/unilabos/ros/msgs/message_converter.py @@ -131,7 +131,7 @@ _msg_converter: Dict[Type, Any] = { Bool: lambda x: Bool(data=bool(x)), str: str, String: lambda x: String(data=str(x)), - Point: lambda x: Point(x=x.x, y=x.y, z=x.z), + Point: lambda x: Point(x=x.x, y=x.y, z=x.z) if not isinstance(x, dict) else Point(x=x.get("x", 0), y=x.get("y", 0), z=x.get("z", 0)), Resource: lambda x: Resource( id=x.get("id", ""), name=x.get("name", ""), diff --git a/unilabos_msgs/CMakeLists.txt b/unilabos_msgs/CMakeLists.txt index 135e5738..098bb35c 100644 --- a/unilabos_msgs/CMakeLists.txt +++ b/unilabos_msgs/CMakeLists.txt @@ -45,6 +45,7 @@ set(action_files "action/LiquidHandlerReturnTips96.action" "action/LiquidHandlerStamp.action" "action/LiquidHandlerTransfer.action" + "action/LiquidHandlerTransferBiomek.action" "action/LiquidHandlerAdd.action" "action/LiquidHandlerMix.action" diff --git a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action new file mode 100644 index 00000000..7d785d93 --- /dev/null +++ b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action @@ -0,0 +1,9 @@ +Resource source +Resource target +Resource tip_rack +string aspirate_technique +string dispense_technique + +--- + +--- From e63c15997c74875e334de3ce2979b5845e2768c4 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Wed, 4 Jun 2025 21:29:54 +0800 Subject: [PATCH 15/44] New transfer_biomek --- unilabos/devices/liquid_handling/biomek.py | 634 ++++++++++++++++-- .../devices/liquid_handling/biomek_test.py | 366 +++++++--- 2 files changed, 867 insertions(+), 133 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index c0bde755..4f0a3137 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -1,7 +1,7 @@ import requests from typing import List, Sequence, Optional, Union, Literal from geometry_msgs.msg import Point -from unilabos_msgs.msg import Resource +#from unilabos_msgs.msg import Resource from pylabrobot.resources import ( TipRack, @@ -29,25 +29,45 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): self._status_queue = kwargs.get("status_queue", None) # 状态队列 self.temp_protocol = {} self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 - self.technique = { + self.aspirate_techniques = { 'MC P300 high':{ - "use_channels": "Span8", - "asp_vols": [50], - "asp_flow_rates": 50, - "dis_flow_rates": 50, - "offsets": None, - "touch_tip": True, - "liquid_height": 20, - "blow_out_air_volume": 20, - "spread": "wide", - "is_96_well": True, - "mix_stage": "none", - "mix_times": None, - "mix_vol": None, - "mix_rate": None, - "mix_liquid_height": None, - "delays": None, - "none_keys": [] + "Solvent": "Water", + } + } + self.dispense_techniques = { + 'MC P300 high':{ + "Span8": False, + "Pod": "Pod1", + "Wash": False, + "Dynamic?": True, + "AutoSelectActiveWashTechnique": False, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": True, + "ChangeTipsBetweenSources": False, + "DefaultCaption": "", + "UseExpression": False, + "LeaveTipsOn": False, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": False, + "Replicates": "1", + "ShowTipHandlingDetails": False, + "ShowTransferDetails": True, + "Span8Wash": False, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": False, + "SplitVolumeCleaning": False, + "Stop": "Destinations", + "UseCurrentTips": False, + "UseDisposableTips": False, + "UseFixedTips": False, + "UseJIT": True, + "UseMandrelSelection": True, + "UseProbes": [True, True, True, True, True, True, True, True], + "WashCycles": "3", + "WashVolume": "110%", + "Wizard": False } } @@ -171,8 +191,6 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): sources: Sequence[Container], targets: Sequence[Container], tip_racks: Sequence[TipRack], - solvent: Optional[str] = None, - TipLocation :str = None, *, use_channels: Optional[List[int]] = None, asp_vols: Union[List[float], float], @@ -213,7 +231,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): "Replicates": "1", "ShowTipHandlingDetails": False, "ShowTransferDetails": True, - "Solvent": "Water", + "Solvent": "Well Content", "Span8Wash": False, "Span8WashVolume": "2", "Span8WasteVolume": "1", @@ -240,7 +258,9 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): "Volume": dis_vols[idx] } transfer_params["items"] = items + transfer_params["Solvent"] = solvent if solvent else "Water" + TipLocation = tip_racks[0].name transfer_params["TipLocation"] = TipLocation if len(tip_racks) == 1: @@ -251,30 +271,564 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): self.temp_protocol["steps"].append(transfer_params) return - + def transfer_biomek( self, - parameters: dict, - technique: str, + source: str, + target: str, + tip_rack: str, + volume: float, + aspirate_techniques: str, + dispense_techniques: str, ): """ 处理Biomek的液体转移操作。 """ - sources = parameters.get("source") - targets = parameters.get("target") - tip_rack = parameters.get("tip_rack") - volume = parameters.get("volume") - liquid_type = parameters.get("liquid_type", "Well Content") - other_params = self.technique.get(technique, {}) + + asp_params = self.aspirate_techniques.get(aspirate_techniques, {}) + dis_params = self.dispense_techniques.get(dispense_techniques, {}) - self.transfer_liquid( - sources=[sources], - targets=[targets], - TipLocation=tip_rack, - tip_racks=[tip_rack], - solvent=liquid_type, - dis_vols=[volume], - **other_params - ) + transfer_params = { + "Span8": False, + "Pod": "Pod1", + "items": {}, + "Wash": False, + "Dynamic?": True, + "AutoSelectActiveWashTechnique": False, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": False, + "ChangeTipsBetweenSources": True, + "DefaultCaption": "", + "UseExpression": False, + "LeaveTipsOn": False, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": False, + "Replicates": "1", + "ShowTipHandlingDetails": False, + "ShowTransferDetails": True, + "Solvent": "Water", + "Span8Wash": False, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": False, + "SplitVolumeCleaning": False, + "Stop": "Destinations", + "TipLocation": "BC1025F", + "UseCurrentTips": False, + "UseDisposableTips": True, + "UseFixedTips": False, + "UseJIT": True, + "UseMandrelSelection": True, + "UseProbes": [True, True, True, True, True, True, True, True], + "WashCycles": "1", + "WashVolume": "110%", + "Wizard": False + } + + items: dict = {} + items["Source"] = source + items["Destination"] = target + items["Volume"] = volume + transfer_params["items"] = items + transfer_params["Solvent"] = asp_params['Solvent'] + transfer_params["TipLocation"] = tip_rack + transfer_params.update(asp_params) + transfer_params.update(dis_params) + self.temp_protocol["steps"].append(transfer_params) + return + +steps_info = ''' +{ + "steps": [ + { + "step_number": 1, + "operation": "transfer", + "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", + "parameters": { + "source": "P1", + "target": "P11", + "tip_rack": "BC230", + "volume": 50 + } + }, + { + "step_number": 2, + "operation": "transfer", + "description": "加入2倍体积Bind Beads BC至产物中", + "parameters": { + "source": "P2", + "target": "P11", + "tip_rack": "BC230", + "volume": 100 + } + }, + { + "step_number": 3, + "operation": "move_labware", + "description": "移动P11至Orbital1用于振荡混匀", + "parameters": { + "source": "P11", + "target": "Orbital1" + } + }, + { + "step_number": 4, + "operation": "oscillation", + "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", + "parameters": { + "rpm": 800, + "time": 300 + } + }, + { + "step_number": 5, + "operation": "move_labware", + "description": "移动混匀后的板回P11", + "parameters": { + "source": "Orbital1", + "target": "P11" + } + }, + { + "step_number": 6, + "operation": "move_labware", + "description": "将P11移动到磁力架(P12)吸附3分钟", + "parameters": { + "source": "P11", + "target": "P12" + } + }, + { + "step_number": 7, + "operation": "incubation", + "description": "磁力架上室温静置3分钟完成吸附", + "parameters": { + "time": 180 + } + }, + { + "step_number": 8, + "operation": "transfer", + "description": "去除上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 150 + } + }, + { + "step_number": 9, + "operation": "transfer", + "description": "加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 10, + "operation": "move_labware", + "description": "移动清洗板到Orbital1进行振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 11, + "operation": "oscillation", + "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 12, + "operation": "move_labware", + "description": "振荡后将板移回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 13, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 14, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 15, + "operation": "transfer", + "description": "第二次加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 16, + "operation": "move_labware", + "description": "再次移动清洗板到Orbital1振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 17, + "operation": "oscillation", + "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 18, + "operation": "move_labware", + "description": "振荡后板送回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 19, + "operation": "incubation", + "description": "再次吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 20, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 21, + "operation": "incubation", + "description": "空气干燥15分钟", + "parameters": { + "time": 900 + } + }, + { + "step_number": 22, + "operation": "transfer", + "description": "加30-50μl Elution Buffer洗脱", + "parameters": { + "source": "P4", + "target": "P12", + "tip_rack": "BC230", + "volume": 40 + } + }, + { + "step_number": 23, + "operation": "move_labware", + "description": "移动到Orbital1振荡混匀(60秒)", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 24, + "operation": "oscillation", + "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 25, + "operation": "move_labware", + "description": "振荡后送回磁力架P12", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 26, + "operation": "incubation", + "description": "室温静置3分钟(洗脱反应)", + "parameters": { + "time": 180 + } + }, + { + "step_number": 27, + "operation": "transfer", + "description": "将上清液(DNA)转移到新板(P13)", + "parameters": { + "source": "P12", + "target": "P13", + "tip_rack": "BC230", + "volume": 40 + } + } + ] +} +''' + + +labware_with_liquid = ''' +[ { + "id": "stock plate on P1", + "parent": "deck", + "slot_on_deck": "P1", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "master_mix" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "Tip Rack BC230 TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P7", + "parent": "deck", + "slot_on_deck": "P7", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P8", + "parent": "deck", + "slot_on_deck": "P8", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "stock plate on 4", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "ethyl alcohol" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "magnetics module on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "magnetics module", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "nest_1_reservoir_195ml", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + } +] + +''' + +handler = LiquidHandlerBiomek() +handler.temp_protocol = { + "meta": {}, + "labwares": [], + "steps": [] +} + +input_steps = json.loads(steps_info) +labwares = json.loads(labware_with_liquid) + +for step in input_steps['steps']: + if step['operation'] != 'transfer': + continue + parameters = step['parameters'] + tip_rack=parameters['tip_rack'] + # 找到labwares中与tip_rack匹配的项的id + tip_rack_id = [lw['id'] for lw in labwares if lw['class_name'] == tip_rack][0] + + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=tip_rack_id, + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high' + ) +print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) + diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 1aa01cec..54db6dfc 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -296,25 +296,45 @@ class LiquidHandlerBiomek: self._status_queue = kwargs.get("status_queue", None) # 状态队列 self.temp_protocol = {} self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 - self.technique = { + self.aspirate_techniques = { 'MC P300 high':{ - "use_channels": "Span8", - "asp_vols": [50], - "asp_flow_rates": 50, - "dis_flow_rates": 50, - "offsets": None, - "touch_tip": True, - "liquid_height": 20, - "blow_out_air_volume": 20, - "spread": "wide", - "is_96_well": True, - "mix_stage": "none", - "mix_times": None, - "mix_vol": None, - "mix_rate": None, - "mix_liquid_height": None, - "delays": None, - "none_keys": [] + "Solvent": "Water", + } + } + self.dispense_techniques = { + 'MC P300 high':{ + "Span8": False, + "Pod": "Pod1", + "Wash": False, + "Dynamic?": True, + "AutoSelectActiveWashTechnique": False, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": True, + "ChangeTipsBetweenSources": False, + "DefaultCaption": "", + "UseExpression": False, + "LeaveTipsOn": False, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": False, + "Replicates": "1", + "ShowTipHandlingDetails": False, + "ShowTransferDetails": True, + "Span8Wash": False, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": False, + "SplitVolumeCleaning": False, + "Stop": "Destinations", + "UseCurrentTips": False, + "UseDisposableTips": False, + "UseFixedTips": False, + "UseJIT": True, + "UseMandrelSelection": True, + "UseProbes": [True, True, True, True, True, True, True, True], + "WashCycles": "3", + "WashVolume": "110%", + "Wizard": False } } @@ -425,34 +445,24 @@ class LiquidHandlerBiomek: # } # self.temp_protocol["labwares"].append(resource) # return resource + - def transfer_liquid( - self, - sources: Sequence[Container], - targets: Sequence[Container], - tip_racks: Sequence[TipRack], - solvent: Optional[str] = None, - TipLocation :str = None, - *, - use_channels: Optional[List[int]] = None, - asp_vols: Union[List[float], float], - dis_vols: Union[List[float], float], - asp_flow_rates: Optional[List[Optional[float]]] = None, - dis_flow_rates: Optional[List[Optional[float]]] = None, - offsets: Optional[List[Coordinate]] = None, - touch_tip: bool = False, - liquid_height: Optional[List[Optional[float]]] = None, - blow_out_air_volume: Optional[List[Optional[float]]] = None, - spread: Literal["wide", "tight", "custom"] = "wide", - is_96_well: bool = False, - mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none", - mix_times: Optional[int] = None, - mix_vol: Optional[int] = None, - mix_rate: Optional[int] = None, - mix_liquid_height: Optional[float] = None, - delays: Optional[List[int]] = None, - none_keys: List[str] = [] + def transfer_biomek( + self, + source: str, + target: str, + tip_rack: str, + volume: float, + aspirate_techniques: str, + dispense_techniques: str, ): + """ + 处理Biomek的液体转移操作。 + + """ + + asp_params = self.aspirate_techniques.get(aspirate_techniques, {}) + dis_params = self.dispense_techniques.get(dispense_techniques, {}) transfer_params = { "Span8": False, @@ -463,7 +473,7 @@ class LiquidHandlerBiomek: "AutoSelectActiveWashTechnique": False, "ActiveWashTechnique": "", "ChangeTipsBetweenDests": False, - "ChangeTipsBetweenSources": False, + "ChangeTipsBetweenSources": True, "DefaultCaption": "", "UseExpression": False, "LeaveTipsOn": False, @@ -493,61 +503,220 @@ class LiquidHandlerBiomek: } items: dict = {} - for idx, (src, dst) in enumerate(zip(sources, targets)): - items[str(idx)] = { - "Source": str(src), - "Destination": str(dst), - "Volume": dis_vols[idx] - } + items["Source"] = source + items["Destination"] = target + items["Volume"] = volume transfer_params["items"] = items - transfer_params["Solvent"] = solvent if solvent else "Water" - transfer_params["TipLocation"] = TipLocation - - if len(tip_racks) == 1: - transfer_params['UseCurrentTips'] = True - elif len(tip_racks) > 1: - transfer_params["ChangeTipsBetweenDests"] = True - + transfer_params["Solvent"] = asp_params['Solvent'] + transfer_params["TipLocation"] = tip_rack + transfer_params.update(asp_params) + transfer_params.update(dis_params) self.temp_protocol["steps"].append(transfer_params) return - - def transfer_biomek( - self, - parameters: dict, - technique: str, - ): - """ - 创建一个Biomek液体处理器的转移步骤。 - Args: - step_number (int): 步骤编号 - operation (str): 操作类型 - description (str): 步骤描述 - parameters (dict): 步骤参数 +labware_with_liquid = ''' +[ { + "id": "stock plate on P1", + "parent": "deck", + "slot_on_deck": "P1", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "master_mix" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "Tip Rack BC230 TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P7", + "parent": "deck", + "slot_on_deck": "P7", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P8", + "parent": "deck", + "slot_on_deck": "P8", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "stock plate on 4", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "ethyl alcohol" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, - Returns: - dict: 创建的转移步骤字典 - """ - - sources = parameters.get("source") - targets = parameters.get("target") - tip_rack = parameters.get("tip_rack") - volume = parameters.get("volume") - liquid_type = parameters.get("liquid_type", "Well Content") - other_params = self.technique.get(technique, {}) + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "magnetics module on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "magnetics module", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "nest_1_reservoir_195ml", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + } +] + +''' - self.transfer_liquid( - sources=[sources], - targets=[targets], - TipLocation=tip_rack, - tip_racks=[tip_rack], - solvent=liquid_type, - dis_vols=[volume], - **other_params - ) - return handler = LiquidHandlerBiomek() @@ -556,13 +725,24 @@ handler.temp_protocol = { "labwares": [], "steps": [] } + input_steps = json.loads(steps_info) +labwares = json.loads(labware_with_liquid) for step in input_steps['steps']: if step['operation'] != 'transfer': continue parameters = step['parameters'] - handler.transfer_biomek(parameters, technique='MC P300 high') + tip_rack=parameters['tip_rack'] + # 找到labwares中与tip_rack匹配的项的id + tip_rack_id = [lw['id'] for lw in labwares if lw['class_name'] == tip_rack][0] + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=tip_rack_id, + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high' + ) print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) From e1a7c3a1039caa2271a4e4e36c32c80954f2a8e5 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Wed, 4 Jun 2025 21:49:22 +0800 Subject: [PATCH 16/44] Updated transfer_biomek --- unilabos/devices/liquid_handling/biomek_test.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 54db6dfc..8096e8d6 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -733,16 +733,15 @@ for step in input_steps['steps']: if step['operation'] != 'transfer': continue parameters = step['parameters'] - tip_rack=parameters['tip_rack'] - # 找到labwares中与tip_rack匹配的项的id - tip_rack_id = [lw['id'] for lw in labwares if lw['class_name'] == tip_rack][0] + handler.transfer_biomek(source=parameters['source'], target=parameters['target'], volume=parameters['volume'], - tip_rack=tip_rack_id, + tip_rack=parameters['tip_rack'], aspirate_techniques='MC P300 high', dispense_techniques='MC P300 high' ) + print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) From b99969278c635e0778ea40cd25e665eda94197d0 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:30:51 +0800 Subject: [PATCH 17/44] =?UTF-8?q?=E6=9B=B4=E6=96=B0transfer=5Fbiomek?= =?UTF-8?q?=E7=9A=84msg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/registry/devices/liquid_handler.yaml | 11 +++++++++++ .../action/LiquidHandlerTransferBiomek.action | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index b3b011e2..64b35acb 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -340,6 +340,17 @@ liquid_handler.biomek: none_keys: none_keys feedback: {} result: {} + transfer_biomek: + type: LiquidHandlerTransferBiomek + goal: + source: source, + target: target, + tip_rack: tip_rack, + volume: volume, + aspirate_techniques: aspirate_techniques, + dispense_techniques: dispense_techniques, + feedback: {} + result: {} schema: type: object properties: {} diff --git a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action index 7d785d93..02beef64 100644 --- a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action @@ -1,6 +1,7 @@ -Resource source -Resource target -Resource tip_rack +string source +string target +string tip_rack +float volume string aspirate_technique string dispense_technique From 39de3ac58ea8749b3c8b95c125db8f78c3ddfc7f Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Thu, 5 Jun 2025 15:41:16 +0800 Subject: [PATCH 18/44] =?UTF-8?q?=E6=9B=B4=E6=96=B0transfer=5Fbiomek?= =?UTF-8?q?=E7=9A=84msg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos_msgs/action/LiquidHandlerTransferBiomek.action | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action index 02beef64..b52dec57 100644 --- a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action @@ -1,7 +1,7 @@ string source string target string tip_rack -float volume +float64 volume string aspirate_technique string dispense_technique From dd5a7cab75948443db64491876b03e211f221927 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Thu, 5 Jun 2025 16:04:44 +0800 Subject: [PATCH 19/44] =?UTF-8?q?=E6=94=AF=E6=8C=81Biomek=E5=88=9B?= =?UTF-8?q?=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/devices/liquid_handling/biomek.py | 968 +++++++++++---------- unilabos/ros/nodes/base_device_node.py | 4 +- 2 files changed, 491 insertions(+), 481 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 4f0a3137..35c5f6f7 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -1,7 +1,8 @@ import requests from typing import List, Sequence, Optional, Union, Literal from geometry_msgs.msg import Point -#from unilabos_msgs.msg import Resource +from pylabrobot.liquid_handling import LiquidHandler +from unilabos_msgs.msg import Resource from pylabrobot.resources import ( TipRack, @@ -22,8 +23,8 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): 该类用于处理Biomek液体处理器的特定操作。 """ - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, backend=None, deck=None, *args, **kwargs): + super().__init__(backend, deck, *args, **kwargs) self._status = "Idle" # 初始状态为 Idle self._success = False # 初始成功状态为 False self._status_queue = kwargs.get("status_queue", None) # 状态队列 @@ -71,6 +72,10 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): } } + @classmethod + def deserialize(cls, data: dict, allow_marshal: bool = False) -> LiquidHandler: + return LiquidHandler.deserialize(data, allow_marshal) + def create_protocol( self, @@ -259,7 +264,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): } transfer_params["items"] = items - transfer_params["Solvent"] = solvent if solvent else "Water" + transfer_params["Solvent"] = "Water" TipLocation = tip_racks[0].name transfer_params["TipLocation"] = TipLocation @@ -340,495 +345,498 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): return -steps_info = ''' -{ - "steps": [ + +if __name__ == "__main__": + + steps_info = ''' { - "step_number": 1, - "operation": "transfer", - "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", - "parameters": { - "source": "P1", - "target": "P11", - "tip_rack": "BC230", - "volume": 50 - } - }, - { - "step_number": 2, - "operation": "transfer", - "description": "加入2倍体积Bind Beads BC至产物中", - "parameters": { - "source": "P2", - "target": "P11", - "tip_rack": "BC230", - "volume": 100 - } - }, - { - "step_number": 3, - "operation": "move_labware", - "description": "移动P11至Orbital1用于振荡混匀", - "parameters": { - "source": "P11", - "target": "Orbital1" - } - }, - { - "step_number": 4, - "operation": "oscillation", - "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", - "parameters": { - "rpm": 800, - "time": 300 - } - }, - { - "step_number": 5, - "operation": "move_labware", - "description": "移动混匀后的板回P11", - "parameters": { - "source": "Orbital1", - "target": "P11" - } - }, - { - "step_number": 6, - "operation": "move_labware", - "description": "将P11移动到磁力架(P12)吸附3分钟", - "parameters": { - "source": "P11", - "target": "P12" - } - }, - { - "step_number": 7, - "operation": "incubation", - "description": "磁力架上室温静置3分钟完成吸附", - "parameters": { - "time": 180 - } - }, - { - "step_number": 8, - "operation": "transfer", - "description": "去除上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 150 - } - }, - { - "step_number": 9, - "operation": "transfer", - "description": "加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 10, - "operation": "move_labware", - "description": "移动清洗板到Orbital1进行振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 11, - "operation": "oscillation", - "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 12, - "operation": "move_labware", - "description": "振荡后将板移回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 13, - "operation": "incubation", - "description": "吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 14, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 15, - "operation": "transfer", - "description": "第二次加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 16, - "operation": "move_labware", - "description": "再次移动清洗板到Orbital1振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 17, - "operation": "oscillation", - "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 18, - "operation": "move_labware", - "description": "振荡后板送回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 19, - "operation": "incubation", - "description": "再次吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 20, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 21, - "operation": "incubation", - "description": "空气干燥15分钟", - "parameters": { - "time": 900 - } - }, - { - "step_number": 22, - "operation": "transfer", - "description": "加30-50μl Elution Buffer洗脱", - "parameters": { - "source": "P4", - "target": "P12", - "tip_rack": "BC230", - "volume": 40 - } - }, - { - "step_number": 23, - "operation": "move_labware", - "description": "移动到Orbital1振荡混匀(60秒)", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 24, - "operation": "oscillation", - "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", - "parameters": { - "rpm": 800, - "time": 60 - } - }, - { - "step_number": 25, - "operation": "move_labware", - "description": "振荡后送回磁力架P12", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 26, - "operation": "incubation", - "description": "室温静置3分钟(洗脱反应)", - "parameters": { - "time": 180 - } - }, - { - "step_number": 27, - "operation": "transfer", - "description": "将上清液(DNA)转移到新板(P13)", - "parameters": { - "source": "P12", - "target": "P13", - "tip_rack": "BC230", - "volume": 40 - } + "steps": [ + { + "step_number": 1, + "operation": "transfer", + "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", + "parameters": { + "source": "P1", + "target": "P11", + "tip_rack": "BC230", + "volume": 50 + } + }, + { + "step_number": 2, + "operation": "transfer", + "description": "加入2倍体积Bind Beads BC至产物中", + "parameters": { + "source": "P2", + "target": "P11", + "tip_rack": "BC230", + "volume": 100 + } + }, + { + "step_number": 3, + "operation": "move_labware", + "description": "移动P11至Orbital1用于振荡混匀", + "parameters": { + "source": "P11", + "target": "Orbital1" + } + }, + { + "step_number": 4, + "operation": "oscillation", + "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", + "parameters": { + "rpm": 800, + "time": 300 + } + }, + { + "step_number": 5, + "operation": "move_labware", + "description": "移动混匀后的板回P11", + "parameters": { + "source": "Orbital1", + "target": "P11" + } + }, + { + "step_number": 6, + "operation": "move_labware", + "description": "将P11移动到磁力架(P12)吸附3分钟", + "parameters": { + "source": "P11", + "target": "P12" + } + }, + { + "step_number": 7, + "operation": "incubation", + "description": "磁力架上室温静置3分钟完成吸附", + "parameters": { + "time": 180 + } + }, + { + "step_number": 8, + "operation": "transfer", + "description": "去除上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 150 + } + }, + { + "step_number": 9, + "operation": "transfer", + "description": "加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 10, + "operation": "move_labware", + "description": "移动清洗板到Orbital1进行振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 11, + "operation": "oscillation", + "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 12, + "operation": "move_labware", + "description": "振荡后将板移回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 13, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 14, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 15, + "operation": "transfer", + "description": "第二次加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 16, + "operation": "move_labware", + "description": "再次移动清洗板到Orbital1振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 17, + "operation": "oscillation", + "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 18, + "operation": "move_labware", + "description": "振荡后板送回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 19, + "operation": "incubation", + "description": "再次吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 20, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 21, + "operation": "incubation", + "description": "空气干燥15分钟", + "parameters": { + "time": 900 + } + }, + { + "step_number": 22, + "operation": "transfer", + "description": "加30-50μl Elution Buffer洗脱", + "parameters": { + "source": "P4", + "target": "P12", + "tip_rack": "BC230", + "volume": 40 + } + }, + { + "step_number": 23, + "operation": "move_labware", + "description": "移动到Orbital1振荡混匀(60秒)", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 24, + "operation": "oscillation", + "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 25, + "operation": "move_labware", + "description": "振荡后送回磁力架P12", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 26, + "operation": "incubation", + "description": "室温静置3分钟(洗脱反应)", + "parameters": { + "time": 180 + } + }, + { + "step_number": 27, + "operation": "transfer", + "description": "将上清液(DNA)转移到新板(P13)", + "parameters": { + "source": "P12", + "target": "P13", + "tip_rack": "BC230", + "volume": 40 + } + } + ] } - ] -} -''' + ''' -labware_with_liquid = ''' -[ { - "id": "stock plate on P1", - "parent": "deck", - "slot_on_deck": "P1", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "master_mix" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "Tip Rack BC230 TL2", - "parent": "deck", - "slot_on_deck": "TL2", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + labware_with_liquid = ''' + [ { + "id": "stock plate on P1", + "parent": "deck", + "slot_on_deck": "P1", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "master_mix" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, { - "id": "Tip Rack BC230 on TL3", - "parent": "deck", - "slot_on_deck": "TL3", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on TL4", - "parent": "deck", - "slot_on_deck": "TL4", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on TL5", - "parent": "deck", - "slot_on_deck": "TL5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P5", - "parent": "deck", - "slot_on_deck": "P5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P6", - "parent": "deck", - "slot_on_deck": "P6", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P7", - "parent": "deck", - "slot_on_deck": "P7", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on P8", - "parent": "deck", - "slot_on_deck": "P8", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P7", + "parent": "deck", + "slot_on_deck": "P7", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 P16", - "parent": "deck", - "slot_on_deck": "P16", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "stock plate on 4", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P2", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P3", - "parent": "deck", - "slot_on_deck": "P3", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "ethyl alcohol" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - - { - "id": "oscillation", - "parent": "deck", - "slot_on_deck": "Orbital1", - "class_name": "Orbital", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "working plate on P11", - "parent": "deck", - "slot_on_deck": "P11", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P8", + "parent": "deck", + "slot_on_deck": "P8", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "magnetics module on P12", - "parent": "deck", - "slot_on_deck": "P12", - "class_name": "magnetics module", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "working plate on P13", - "parent": "deck", - "slot_on_deck": "P13", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "waste on P22", - "parent": "deck", - "slot_on_deck": "P22", - "class_name": "nest_1_reservoir_195ml", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] + "id": "stock plate on 4", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "ethyl alcohol" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "magnetics module on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "magnetics module", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "nest_1_reservoir_195ml", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + } + ] + + ''' + + handler = LiquidHandlerBiomek() + handler.temp_protocol = { + "meta": {}, + "labwares": [], + "steps": [] } -] -''' + input_steps = json.loads(steps_info) + labwares = json.loads(labware_with_liquid) -handler = LiquidHandlerBiomek() -handler.temp_protocol = { - "meta": {}, - "labwares": [], - "steps": [] -} + for step in input_steps['steps']: + if step['operation'] != 'transfer': + continue + parameters = step['parameters'] + tip_rack=parameters['tip_rack'] + # 找到labwares中与tip_rack匹配的项的id + tip_rack_id = [lw['id'] for lw in labwares if lw['class_name'] == tip_rack][0] -input_steps = json.loads(steps_info) -labwares = json.loads(labware_with_liquid) - -for step in input_steps['steps']: - if step['operation'] != 'transfer': - continue - parameters = step['parameters'] - tip_rack=parameters['tip_rack'] - # 找到labwares中与tip_rack匹配的项的id - tip_rack_id = [lw['id'] for lw in labwares if lw['class_name'] == tip_rack][0] - - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=tip_rack_id, - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high' - ) -print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=tip_rack_id, + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high' + ) + print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) diff --git a/unilabos/ros/nodes/base_device_node.py b/unilabos/ros/nodes/base_device_node.py index daf52300..e7991303 100644 --- a/unilabos/ros/nodes/base_device_node.py +++ b/unilabos/ros/nodes/base_device_node.py @@ -805,7 +805,9 @@ class ROS2DeviceNode: self.resource_tracker = DeviceNodeResourceTracker() # use_pylabrobot_creator 使用 cls的包路径检测 - use_pylabrobot_creator = driver_class.__module__.startswith("pylabrobot") or driver_class.__name__ == "LiquidHandlerAbstract" + use_pylabrobot_creator = (driver_class.__module__.startswith("pylabrobot") + or driver_class.__name__ == "LiquidHandlerAbstract" + or driver_class.__name__ == "LiquidHandlerBiomek") # TODO: 要在创建之前预先请求服务器是否有当前id的物料,放到resource_tracker中,让pylabrobot进行创建 # 创建设备类实例 From a62112ae2676ce6d065892e03f950c72b996fd0e Mon Sep 17 00:00:00 2001 From: qxw138 Date: Thu, 5 Jun 2025 17:26:36 +0800 Subject: [PATCH 20/44] new action --- .../devices/liquid_handling/biomek_test.py | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 8096e8d6..e8f51388 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -513,7 +513,66 @@ class LiquidHandlerBiomek: transfer_params.update(dis_params) self.temp_protocol["steps"].append(transfer_params) - return + return + + def move_biomek( + self, + source: str, + target: str, + ): + """ + 处理Biomek移动板子的操作。 + + """ + + move_params = { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": source, + "Target": target, + "LeaveBottomLabware": False, + } + self.temp_protocol["steps"].append(move_params) + + return + + def incubation_biomek( + self, + time: int, + ): + """ + 处理Biomek的孵育操作。 + """ + incubation_params = { + "BarcodeInput?": False, + "DeckItems": {}, + "Layout": "Multichannel", + "Pause?": True, + "PodSetup": {}, + "SplitterPosition": 206, + "VerifyPodSetup?": True + } + self.temp_protocol["steps"].append(incubation_params) + + return + + def oscillation_biomek( + self, + rpm: int, + time: int, + ): + """ + 处理Biomek的振荡操作。 + """ + oscillation_params = { + 'Device': 'OrbitalShaker0', + 'Parameters': (str(rpm), '2', str(time), 'CounterClockwise'), + 'Command': 'Timed Shake' + } + self.temp_protocol["steps"].append(oscillation_params) + + return + labware_with_liquid = ''' [ { From 101c1bc3cc933db02b329fab9b15bd93b8d64c87 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Thu, 5 Jun 2025 22:15:57 +0800 Subject: [PATCH 21/44] fix key name typo --- unilabos/registry/devices/liquid_handler.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index 64b35acb..eba2e0bc 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -343,12 +343,12 @@ liquid_handler.biomek: transfer_biomek: type: LiquidHandlerTransferBiomek goal: - source: source, - target: target, - tip_rack: tip_rack, - volume: volume, - aspirate_techniques: aspirate_techniques, - dispense_techniques: dispense_techniques, + source: source + target: target + tip_rack: tip_rack + volume: volume + aspirate_techniques: aspirate_techniques + dispense_techniques: dispense_techniques feedback: {} result: {} schema: From 1e00a66a6575383d3e9c2c323fde7e49996de737 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Fri, 6 Jun 2025 11:05:36 +0800 Subject: [PATCH 22/44] New parameter for biomek to run. --- unilabos/devices/liquid_handling/biomek.py | 44 +- unilabos/devices/liquid_handling/biomek.txt | 642 ++++ .../biomek_temporary_protocol.json | 2697 +++++++++++++++++ .../devices/liquid_handling/biomek_test.py | 498 +-- 4 files changed, 3620 insertions(+), 261 deletions(-) create mode 100644 unilabos/devices/liquid_handling/biomek.txt create mode 100644 unilabos/devices/liquid_handling/biomek_temporary_protocol.json diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 4f0a3137..8fbeb40f 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -285,20 +285,29 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): 处理Biomek的液体转移操作。 """ - + items = [] + asp_params = self.aspirate_techniques.get(aspirate_techniques, {}) dis_params = self.dispense_techniques.get(dispense_techniques, {}) + asp_params['Position'] = source + dis_params['Position'] = target + asp_params['Volume'] = str(volume) + dis_params['Volume'] = str(volume) + + items.append(asp_params) + items.append(dis_params) + transfer_params = { "Span8": False, "Pod": "Pod1", - "items": {}, + "items": [], "Wash": False, "Dynamic?": True, "AutoSelectActiveWashTechnique": False, "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": False, - "ChangeTipsBetweenSources": True, + "ChangeTipsBetweenDests": True, + "ChangeTipsBetweenSources": False, "DefaultCaption": "", "UseExpression": False, "LeaveTipsOn": False, @@ -315,31 +324,25 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): "SplitVolume": False, "SplitVolumeCleaning": False, "Stop": "Destinations", - "TipLocation": "BC1025F", + "TipLocation": "BC230", "UseCurrentTips": False, - "UseDisposableTips": True, + "UseDisposableTips": False, "UseFixedTips": False, "UseJIT": True, "UseMandrelSelection": True, "UseProbes": [True, True, True, True, True, True, True, True], - "WashCycles": "1", + "WashCycles": "4", "WashVolume": "110%", "Wizard": False } - - items: dict = {} - items["Source"] = source - items["Destination"] = target - items["Volume"] = volume transfer_params["items"] = items - transfer_params["Solvent"] = asp_params['Solvent'] + transfer_params["Solvent"] = 'Water' transfer_params["TipLocation"] = tip_rack - transfer_params.update(asp_params) - transfer_params.update(dis_params) self.temp_protocol["steps"].append(transfer_params) - + return + steps_info = ''' { "steps": [ @@ -604,6 +607,7 @@ steps_info = ''' ''' + labware_with_liquid = ''' [ { "id": "stock plate on P1", @@ -806,6 +810,7 @@ labware_with_liquid = ''' ''' handler = LiquidHandlerBiomek() + handler.temp_protocol = { "meta": {}, "labwares": [], @@ -819,16 +824,13 @@ for step in input_steps['steps']: if step['operation'] != 'transfer': continue parameters = step['parameters'] - tip_rack=parameters['tip_rack'] - # 找到labwares中与tip_rack匹配的项的id - tip_rack_id = [lw['id'] for lw in labwares if lw['class_name'] == tip_rack][0] handler.transfer_biomek(source=parameters['source'], target=parameters['target'], volume=parameters['volume'], - tip_rack=tip_rack_id, + tip_rack=parameters['tip_rack'], aspirate_techniques='MC P300 high', dispense_techniques='MC P300 high' ) -print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) + diff --git a/unilabos/devices/liquid_handling/biomek.txt b/unilabos/devices/liquid_handling/biomek.txt new file mode 100644 index 00000000..2d830a6d --- /dev/null +++ b/unilabos/devices/liquid_handling/biomek.txt @@ -0,0 +1,642 @@ + + 当前方法 Method0530 包含 36 个步骤 + + 步骤 0: + Bitmap: OStepUI.ocx,START + Let: {} + Weak: {} + Prompt: {} + + 步骤 1: + BarcodeInput?: False + DeckItems: {'P1': [{'Properties': {'Name': '', 'Device': '', 'liquidtype': 'Water', 'BarCode': '', 'SenseEveryTime': False}, 'Known': True, 'Class': 'LabwareClasses\\Matrix96_750uL', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}, 'EvalAmounts': (500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0), 'Nominal': False, 'EvalLiquids': ('Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water')}], 'P10': [{'Tips': {'Class': 'TipClasses\\T50F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T50F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC50F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P8': [], 'P9': [{'Tips': {'Class': 'TipClasses\\T50F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T50F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC50F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P11': [{'Properties': {'Name': '', 'Device': '', 'liquidtype': 'Water', 'BarCode': '', 'SenseEveryTime': False}, 'Known': True, 'Class': 'LabwareClasses\\BCDeep96Round', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}, 'EvalAmounts': (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), 'Nominal': False, 'EvalLiquids': ('Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water')}], 'P12': [], 'P13': [{'Properties': {'Name': '', 'Device': '', 'liquidtype': 'Water', 'BarCode': '', 'SenseEveryTime': False}, 'Known': True, 'Class': 'LabwareClasses\\BCDeep96Round', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}, 'EvalAmounts': (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), 'Nominal': False, 'EvalLiquids': ('Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water')}], 'P14': [], 'P15': [], 'P16': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P17': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P18': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P19': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P20': [], 'P2': [{'Properties': {'Name': '', 'Device': '', 'liquidtype': 'Water', 'BarCode': '', 'SenseEveryTime': False}, 'Known': True, 'Class': 'LabwareClasses\\Matrix96_750uL', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}, 'EvalAmounts': (500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0), 'Nominal': False, 'EvalLiquids': ('Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water')}], 'P21': [], 'P22': [{'Properties': {'Name': '', 'Device': '', 'liquidtype': 'Water', 'BarCode': '', 'SenseEveryTime': False}, 'Known': True, 'Class': 'LabwareClasses\\AgilentReservoir', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}, 'EvalAmounts': (0.0,), 'Nominal': False, 'EvalLiquids': ('Water',)}], 'P23': [], 'P24': [], 'P25': [], 'P26': [], 'P27': [], 'P28': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P29': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'P30': [], 'P3': [{'Properties': {'Name': '', 'Device': '', 'liquidtype': 'Water', 'BarCode': '', 'SenseEveryTime': False}, 'Known': True, 'Class': 'LabwareClasses\\AgilentReservoir', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}, 'EvalAmounts': (300000.0,), 'Nominal': False, 'EvalLiquids': ('Water',)}], 'P4': [{'Properties': {'Name': '', 'Device': '', 'liquidtype': 'Water', 'BarCode': '', 'SenseEveryTime': False}, 'Known': True, 'Class': 'LabwareClasses\\Matrix96_750uL', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}, 'EvalAmounts': (500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0, 500.0), 'Nominal': False, 'EvalLiquids': ('Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water', 'Water')}], 'P5': [], 'P6': [], 'P7': [], 'TL1': [{'Tips': {'Class': 'TipClasses\\T230', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T230', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC230', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'TL2': [{'Tips': {'Class': 'TipClasses\\T230', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T230', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC230', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'TL3': [{'Tips': {'Class': 'TipClasses\\T230', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T230', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC230', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'TL4': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'TL5': [{'Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'RT_Tips': {'Class': 'TipClasses\\T1025F', 'Contents': [], '_RT_Contents': [], 'Used': False, 'RT_Used': False, 'Dirty': False, 'RT_Dirty': False, 'MaxVolumeUsed': 0.0, 'RT_MaxVolumeUsed': 0.0}, 'Properties': {}, 'Known': False, 'Class': 'LabwareClasses\\BC1025F', 'DataSets': {'Volume': {}}, 'RuntimeDataSets': {'Volume': {}}}], 'TR1': [], 'WS1': 'Water'} + Layout: Multichannel + Pause?: True + PodSetup: {'LeftHasTips': False, 'LeftTipType': '', 'RightHasTips': False, 'RightTipType': ''} + SplitterPosition: 206 + VerifyPodSetup?: True + + 步骤 2: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P1', 'Height': -2.0, 'Volume': '50', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'Matrix96_750uL', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P11', 'Height': -2.0, 'Volume': '50', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 50 µL from P1 to P11 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC230 + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 3: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P2', 'Height': -2.0, 'Volume': '100', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'Matrix96_750uL', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P11', 'Height': -2.0, 'Volume': '100', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 100 µL from P2 to P11 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC230 + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 4: + Pod: Pod1 + GripSide: A1 near + Source: P11 + Target: Orbital1 + LeaveBottomLabware: False + + 步骤 5: + Device: + Parameters: () + Command: + + 步骤 6: + Device: + Parameters: () + Command: + + 步骤 7: + Pod: Pod1 + GripSide: A1 near + Source: Orbital1 + Target: P11 + LeaveBottomLabware: False + + 步骤 8: + Pod: Pod1 + GripSide: A1 near + Source: P11 + Target: P12 + LeaveBottomLabware: False + + 步骤 9: + Message: Paused + Location: the whole system + Time: 180 + Mode: TimedResource + + 步骤 10: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P12', 'Height': -2.0, 'Volume': '150', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P22', 'Height': -2.0, 'Volume': '150', 'liquidtype': 'Tip Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 150 µL from P12 to P22 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC230 + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 11: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P3', 'Height': -2.0, 'Volume': '400', 'liquidtype': 'Well Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P3 to P12 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 12: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P3', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Well Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P3 to P12 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 13: + Pod: Pod1 + GripSide: A1 near + Source: P12 + Target: Orbital1 + LeaveBottomLabware: False + + 步骤 14: + Device: + Parameters: () + Command: + + 步骤 15: + Pod: Pod1 + GripSide: A1 near + Source: Orbital1 + Target: P12 + LeaveBottomLabware: False + + 步骤 16: + Message: Paused + Location: the whole system + Time: 180 + Mode: TimedResource + + 步骤 17: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P22', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P12 to P22 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 18: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P22', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P12 to P22 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 19: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P3', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Well Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P3 to P12 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 20: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P3', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Well Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P3 to P12 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 21: + Pod: Pod1 + GripSide: A1 near + Source: P12 + Target: Orbital1 + LeaveBottomLabware: False + + 步骤 22: + Device: OrbitalShaker0 + Parameters: ('800', '3', '45', 'CounterClockwise', None) + Command: Timed Shake + + 步骤 23: + Pod: Pod1 + GripSide: A1 near + Source: Orbital1 + Target: P12 + LeaveBottomLabware: False + + 步骤 24: + Message: Paused + Location: the whole system + Time: 180 + Mode: TimedResource + + 步骤 25: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P22', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P12 to P22 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 26: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P12', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P22', 'Height': -2.0, 'Volume': '200', 'liquidtype': 'Tip Contents', 'LabwareClass': 'AgilentReservoir', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True,), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 200 µL from P12 to P22 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC1025F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 27: + Message: Paused + Location: the whole system + Time: 900 + Mode: TimedResource + + 步骤 28: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P4', 'Height': -2.0, 'Volume': '40', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'Matrix96_750uL', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P12', 'Height': -2.0, 'Volume': '40', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 40 µL from P4 to P12 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC50F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 29: + Pod: Pod1 + GripSide: A1 near + Source: P12 + Target: Orbital1 + LeaveBottomLabware: False + + 步骤 30: + Device: OrbitalShaker0 + Parameters: ('800', '3', '60', 'CounterClockwise', None) + Command: Timed Shake + + 步骤 31: + Message: Paused + Location: the whole system + Time: 180 + Mode: TimedResource + + 步骤 32: + Pod: Pod1 + GripSide: A1 near + Source: Orbital1 + Target: P12 + LeaveBottomLabware: False + + 步骤 33: + Message: Paused + Location: the whole system + Time: 120 + Mode: TimedResource + + 步骤 34: + Span8: False + Pod: Pod1 + Wash: False + items: [{'Position': 'P12', 'Height': -2.0, 'Volume': '40', 'liquidtype': 'Well Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': True, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}, {'Position': 'P13', 'Height': -2.0, 'Volume': '40', 'liquidtype': 'Tip Contents', 'WellsX': 12, 'LabwareClass': 'BCDeep96Round', 'AutoSelectPrototype': True, 'ColsFirst': True, 'CustomHeight': False, 'DataSetPattern': False, 'HeightFrom': 0, 'LocalPattern': True, 'Operation': 'Dispense', 'OverrideHeight': False, 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC', 'ReferencedPattern': '', 'RowsFirst': False, 'SectionExpression': '', 'SelectionInfo': (1,), 'SetMark': True, 'Source': False, 'StartAtMark': False, 'StartAtSelection': True, 'UseExpression': False}] + Dynamic?: True + AutoSelectActiveWashTechnique: False + ActiveWashTechnique: + ChangeTipsBetweenDests: True + ChangeTipsBetweenSources: False + DefaultCaption: Transfer 40 µL from P12 to P13 + UseExpression: False + LeaveTipsOn: False + MandrelExpression: + Repeats: 1 + RepeatsByVolume: False + Replicates: 1 + ShowTipHandlingDetails: True + ShowTransferDetails: True + Solvent: Water + Span8Wash: False + Span8WashVolume: 2 + Span8WasteVolume: 1 + SplitVolume: False + SplitVolumeCleaning: False + Stop: Destinations + TipLocation: BC50F + UseCurrentTips: False + UseDisposableTips: False + UseFixedTips: False + UseJIT: True + UseMandrelSelection: True + UseProbes: (True, True, True, True, True, True, True, True) + WashCycles: 4 + WashVolume: 110% + Wizard: False + + 步骤 35: + Type: + Bitmap: OStepUI.ocx,FINISH + cleardeck: True + cleardevices: True + cleanuppods: True + PodsToMaxZ: True + ClearGlobals: True + ParkPods: True + Authent: False + Collapsed: True + ConnectionString: + Password: + Path: + Report: False + Server: + TableName: + UserName: + Catalog: diff --git a/unilabos/devices/liquid_handling/biomek_temporary_protocol.json b/unilabos/devices/liquid_handling/biomek_temporary_protocol.json new file mode 100644 index 00000000..129c3ba2 --- /dev/null +++ b/unilabos/devices/liquid_handling/biomek_temporary_protocol.json @@ -0,0 +1,2697 @@ +{ + "meta": {}, + "labwares": [], + "steps": [ + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + }, + { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + ] +} \ No newline at end of file diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 8096e8d6..c1f05f23 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -15,6 +15,262 @@ from pylabrobot.resources import ( import json from typing import Sequence, Optional, List, Union, Literal + + +#class LiquidHandlerBiomek(LiquidHandlerAbstract): + + +class LiquidHandlerBiomek: + """ + Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 + 该类用于处理Biomek液体处理器的特定操作。 + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._status = "Idle" # 初始状态为 Idle + self._success = False # 初始成功状态为 False + self._status_queue = kwargs.get("status_queue", None) # 状态队列 + self.temp_protocol = {} + self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 + self.aspirate_techniques = { + 'MC P300 high':{ + 'Position': 'P1', + 'Height': -2.0, + 'Volume': '50', + 'liquidtype': 'Well Contents', + 'WellsX': 12, + 'LabwareClass': 'Matrix96_750uL', + 'AutoSelectPrototype': True, + 'ColsFirst': True, + 'CustomHeight': False, + 'DataSetPattern': False, + 'HeightFrom': 0, + 'LocalPattern': True, + 'Operation': 'Aspirate', + 'OverrideHeight': False, + 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), + 'Prototype': 'MC P300 High', + 'ReferencedPattern': '', + 'RowsFirst': False, + 'SectionExpression': '', + 'SelectionInfo': (1,), + 'SetMark': True, + 'Source': True, + 'StartAtMark': False, + 'StartAtSelection': True, + 'UseExpression': False}, + } + + self.dispense_techniques = { + 'MC P300 high':{ + 'Position': 'P11', + 'Height': -2.0, + 'Volume': '50', + 'liquidtype': 'Tip Contents', + 'WellsX': 12, + 'LabwareClass': 'Matrix96_750uL', + 'AutoSelectPrototype': True, + 'ColsFirst': True, + 'CustomHeight': False, + 'DataSetPattern': False, + 'HeightFrom': 0, + 'LocalPattern': True, + 'Operation': 'Dispense', + 'OverrideHeight': False, + 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), + 'Prototype': 'MC P300 High', + 'ReferencedPattern': '', + 'RowsFirst': False, + 'SectionExpression': '', + 'SelectionInfo': (1,), + 'SetMark': True, + 'Source': False, + 'StartAtMark': False, + 'StartAtSelection': True, + 'UseExpression': False} + } + + + def create_protocol( + self, + protocol_name: str, + protocol_description: str, + protocol_version: str, + protocol_author: str, + protocol_date: str, + protocol_type: str, + none_keys: List[str] = [], + ): + """ + 创建一个新的协议。 + + Args: + protocol_name (str): 协议名称 + protocol_description (str): 协议描述 + protocol_version (str): 协议版本 + protocol_author (str): 协议作者 + protocol_date (str): 协议日期 + protocol_type (str): 协议类型 + none_keys (List[str]): 需要设置为None的键列表 + + Returns: + dict: 创建的协议字典 + """ + self.temp_protocol = { + "meta": { + "name": protocol_name, + "description": protocol_description, + "version": protocol_version, + "author": protocol_author, + "date": protocol_date, + "type": protocol_type, + }, + "labwares": [], + "steps": [], + } + return self.temp_protocol + +# def run_protocol(self): +# """ +# 执行创建的实验流程。 +# 工作站的完整执行流程是, +# 从 create_protocol 开始,创建新的 method, +# 随后执行 transfer_liquid 等操作向实验流程添加步骤, +# 最后 run_protocol 执行整个方法。 + +# Returns: +# dict: 执行结果 +# """ +# #use popen or subprocess to create py32 process and communicate send the temp protocol to it +# if not self.temp_protocol: +# raise ValueError("No protocol created. Please create a protocol first.") + +# # 模拟执行协议 +# self._status = "Running" +# self._success = True +# # 在这里可以添加实际执行协议的逻辑 + +# response = requests.post("localhost:5000/api/protocols", json=self.temp_protocol) + +# def create_resource( +# self, +# resource_tracker: DeviceNodeResourceTracker, +# resources: list[Resource], +# bind_parent_id: str, +# bind_location: dict[str, float], +# liquid_input_slot: list[int], +# liquid_type: list[str], +# liquid_volume: list[int], +# slot_on_deck: int, +# res_id, +# class_name, +# bind_locations, +# parent +# ): +# """ +# 创建一个新的资源。 + +# Args: +# device_id (str): 设备ID +# res_id (str): 资源ID +# class_name (str): 资源类名 +# parent (str): 父级ID +# bind_locations (Point): 绑定位置 +# liquid_input_slot (list[int]): 液体输入槽列表 +# liquid_type (list[str]): 液体类型列表 +# liquid_volume (list[int]): 液体体积列表 +# slot_on_deck (int): 甲板上的槽位 + +# Returns: +# dict: 创建的资源字典 +# """ +# # TODO:需要对好接口,下面这个是临时的 +# resource = { +# "id": res_id, +# "class": class_name, +# "parent": parent, +# "bind_locations": bind_locations.to_dict(), +# "liquid_input_slot": liquid_input_slot, +# "liquid_type": liquid_type, +# "liquid_volume": liquid_volume, +# "slot_on_deck": slot_on_deck, +# } +# self.temp_protocol["labwares"].append(resource) +# return resource + + + def transfer_biomek( + self, + source: str, + target: str, + tip_rack: str, + volume: float, + aspirate_techniques: str, + dispense_techniques: str, + ): + """ + 处理Biomek的液体转移操作。 + + """ + items = [] + + asp_params = self.aspirate_techniques.get(aspirate_techniques, {}) + dis_params = self.dispense_techniques.get(dispense_techniques, {}) + + asp_params['Position'] = source + dis_params['Position'] = target + asp_params['Volume'] = str(volume) + dis_params['Volume'] = str(volume) + + items.append(asp_params) + items.append(dis_params) + + transfer_params = { + "Span8": False, + "Pod": "Pod1", + "items": [], + "Wash": False, + "Dynamic?": True, + "AutoSelectActiveWashTechnique": False, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": True, + "ChangeTipsBetweenSources": False, + "DefaultCaption": "", + "UseExpression": False, + "LeaveTipsOn": False, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": False, + "Replicates": "1", + "ShowTipHandlingDetails": False, + "ShowTransferDetails": True, + "Solvent": "Water", + "Span8Wash": False, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": False, + "SplitVolumeCleaning": False, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": False, + "UseDisposableTips": False, + "UseFixedTips": False, + "UseJIT": True, + "UseMandrelSelection": True, + "UseProbes": [True, True, True, True, True, True, True, True], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": False + } + transfer_params["items"] = items + transfer_params["Solvent"] = 'Water' + transfer_params["TipLocation"] = tip_rack + self.temp_protocol["steps"].append(transfer_params) + + return + + steps_info = ''' { "steps": [ @@ -280,241 +536,6 @@ steps_info = ''' -#class LiquidHandlerBiomek(LiquidHandlerAbstract): - - -class LiquidHandlerBiomek: - """ - Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 - 该类用于处理Biomek液体处理器的特定操作。 - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._status = "Idle" # 初始状态为 Idle - self._success = False # 初始成功状态为 False - self._status_queue = kwargs.get("status_queue", None) # 状态队列 - self.temp_protocol = {} - self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 - self.aspirate_techniques = { - 'MC P300 high':{ - "Solvent": "Water", - } - } - self.dispense_techniques = { - 'MC P300 high':{ - "Span8": False, - "Pod": "Pod1", - "Wash": False, - "Dynamic?": True, - "AutoSelectActiveWashTechnique": False, - "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": True, - "ChangeTipsBetweenSources": False, - "DefaultCaption": "", - "UseExpression": False, - "LeaveTipsOn": False, - "MandrelExpression": "", - "Repeats": "1", - "RepeatsByVolume": False, - "Replicates": "1", - "ShowTipHandlingDetails": False, - "ShowTransferDetails": True, - "Span8Wash": False, - "Span8WashVolume": "2", - "Span8WasteVolume": "1", - "SplitVolume": False, - "SplitVolumeCleaning": False, - "Stop": "Destinations", - "UseCurrentTips": False, - "UseDisposableTips": False, - "UseFixedTips": False, - "UseJIT": True, - "UseMandrelSelection": True, - "UseProbes": [True, True, True, True, True, True, True, True], - "WashCycles": "3", - "WashVolume": "110%", - "Wizard": False - } - } - - - def create_protocol( - self, - protocol_name: str, - protocol_description: str, - protocol_version: str, - protocol_author: str, - protocol_date: str, - protocol_type: str, - none_keys: List[str] = [], - ): - """ - 创建一个新的协议。 - - Args: - protocol_name (str): 协议名称 - protocol_description (str): 协议描述 - protocol_version (str): 协议版本 - protocol_author (str): 协议作者 - protocol_date (str): 协议日期 - protocol_type (str): 协议类型 - none_keys (List[str]): 需要设置为None的键列表 - - Returns: - dict: 创建的协议字典 - """ - self.temp_protocol = { - "meta": { - "name": protocol_name, - "description": protocol_description, - "version": protocol_version, - "author": protocol_author, - "date": protocol_date, - "type": protocol_type, - }, - "labwares": [], - "steps": [], - } - return self.temp_protocol - -# def run_protocol(self): -# """ -# 执行创建的实验流程。 -# 工作站的完整执行流程是, -# 从 create_protocol 开始,创建新的 method, -# 随后执行 transfer_liquid 等操作向实验流程添加步骤, -# 最后 run_protocol 执行整个方法。 - -# Returns: -# dict: 执行结果 -# """ -# #use popen or subprocess to create py32 process and communicate send the temp protocol to it -# if not self.temp_protocol: -# raise ValueError("No protocol created. Please create a protocol first.") - -# # 模拟执行协议 -# self._status = "Running" -# self._success = True -# # 在这里可以添加实际执行协议的逻辑 - -# response = requests.post("localhost:5000/api/protocols", json=self.temp_protocol) - -# def create_resource( -# self, -# resource_tracker: DeviceNodeResourceTracker, -# resources: list[Resource], -# bind_parent_id: str, -# bind_location: dict[str, float], -# liquid_input_slot: list[int], -# liquid_type: list[str], -# liquid_volume: list[int], -# slot_on_deck: int, -# res_id, -# class_name, -# bind_locations, -# parent -# ): -# """ -# 创建一个新的资源。 - -# Args: -# device_id (str): 设备ID -# res_id (str): 资源ID -# class_name (str): 资源类名 -# parent (str): 父级ID -# bind_locations (Point): 绑定位置 -# liquid_input_slot (list[int]): 液体输入槽列表 -# liquid_type (list[str]): 液体类型列表 -# liquid_volume (list[int]): 液体体积列表 -# slot_on_deck (int): 甲板上的槽位 - -# Returns: -# dict: 创建的资源字典 -# """ -# # TODO:需要对好接口,下面这个是临时的 -# resource = { -# "id": res_id, -# "class": class_name, -# "parent": parent, -# "bind_locations": bind_locations.to_dict(), -# "liquid_input_slot": liquid_input_slot, -# "liquid_type": liquid_type, -# "liquid_volume": liquid_volume, -# "slot_on_deck": slot_on_deck, -# } -# self.temp_protocol["labwares"].append(resource) -# return resource - - - def transfer_biomek( - self, - source: str, - target: str, - tip_rack: str, - volume: float, - aspirate_techniques: str, - dispense_techniques: str, - ): - """ - 处理Biomek的液体转移操作。 - - """ - - asp_params = self.aspirate_techniques.get(aspirate_techniques, {}) - dis_params = self.dispense_techniques.get(dispense_techniques, {}) - - transfer_params = { - "Span8": False, - "Pod": "Pod1", - "items": {}, - "Wash": False, - "Dynamic?": True, - "AutoSelectActiveWashTechnique": False, - "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": False, - "ChangeTipsBetweenSources": True, - "DefaultCaption": "", - "UseExpression": False, - "LeaveTipsOn": False, - "MandrelExpression": "", - "Repeats": "1", - "RepeatsByVolume": False, - "Replicates": "1", - "ShowTipHandlingDetails": False, - "ShowTransferDetails": True, - "Solvent": "Water", - "Span8Wash": False, - "Span8WashVolume": "2", - "Span8WasteVolume": "1", - "SplitVolume": False, - "SplitVolumeCleaning": False, - "Stop": "Destinations", - "TipLocation": "BC1025F", - "UseCurrentTips": False, - "UseDisposableTips": True, - "UseFixedTips": False, - "UseJIT": True, - "UseMandrelSelection": True, - "UseProbes": [True, True, True, True, True, True, True, True], - "WashCycles": "1", - "WashVolume": "110%", - "Wizard": False - } - - items: dict = {} - items["Source"] = source - items["Destination"] = target - items["Volume"] = volume - transfer_params["items"] = items - transfer_params["Solvent"] = asp_params['Solvent'] - transfer_params["TipLocation"] = tip_rack - transfer_params.update(asp_params) - transfer_params.update(dis_params) - self.temp_protocol["steps"].append(transfer_params) - - return - labware_with_liquid = ''' [ { "id": "stock plate on P1", @@ -716,8 +737,6 @@ labware_with_liquid = ''' ''' - - handler = LiquidHandlerBiomek() handler.temp_protocol = { @@ -733,7 +752,6 @@ for step in input_steps['steps']: if step['operation'] != 'transfer': continue parameters = step['parameters'] - handler.transfer_biomek(source=parameters['source'], target=parameters['target'], @@ -742,6 +760,6 @@ for step in input_steps['steps']: aspirate_techniques='MC P300 high', dispense_techniques='MC P300 high' ) - -print(json.dumps(handler.temp_protocol['steps'],indent=4, ensure_ascii=False)) +with open('biomek_temporary_protocol.json', 'w') as f: + json.dump(handler.temp_protocol, f, indent=4, ensure_ascii=False) From 106d71e1db24cf9abc572c79eb69194063b5de65 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Fri, 6 Jun 2025 11:11:17 +0800 Subject: [PATCH 23/44] Refine --- .../devices/liquid_handling/biomek_test.py | 873 +++++++++--------- 1 file changed, 443 insertions(+), 430 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index c1f05f23..98b732f2 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -271,268 +271,270 @@ class LiquidHandlerBiomek: return -steps_info = ''' -{ - "steps": [ +if __name__ == "__main__": + + steps_info = ''' { - "step_number": 1, - "operation": "transfer", - "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", - "parameters": { - "source": "P1", - "target": "P11", - "tip_rack": "BC230", - "volume": 50 - } - }, - { - "step_number": 2, - "operation": "transfer", - "description": "加入2倍体积Bind Beads BC至产物中", - "parameters": { - "source": "P2", - "target": "P11", - "tip_rack": "BC230", - "volume": 100 - } - }, - { - "step_number": 3, - "operation": "move_labware", - "description": "移动P11至Orbital1用于振荡混匀", - "parameters": { - "source": "P11", - "target": "Orbital1" - } - }, - { - "step_number": 4, - "operation": "oscillation", - "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", - "parameters": { - "rpm": 800, - "time": 300 - } - }, - { - "step_number": 5, - "operation": "move_labware", - "description": "移动混匀后的板回P11", - "parameters": { - "source": "Orbital1", - "target": "P11" - } - }, - { - "step_number": 6, - "operation": "move_labware", - "description": "将P11移动到磁力架(P12)吸附3分钟", - "parameters": { - "source": "P11", - "target": "P12" - } - }, - { - "step_number": 7, - "operation": "incubation", - "description": "磁力架上室温静置3分钟完成吸附", - "parameters": { - "time": 180 - } - }, - { - "step_number": 8, - "operation": "transfer", - "description": "去除上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 150 - } - }, - { - "step_number": 9, - "operation": "transfer", - "description": "加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 10, - "operation": "move_labware", - "description": "移动清洗板到Orbital1进行振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 11, - "operation": "oscillation", - "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 12, - "operation": "move_labware", - "description": "振荡后将板移回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 13, - "operation": "incubation", - "description": "吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 14, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 15, - "operation": "transfer", - "description": "第二次加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 16, - "operation": "move_labware", - "description": "再次移动清洗板到Orbital1振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 17, - "operation": "oscillation", - "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 18, - "operation": "move_labware", - "description": "振荡后板送回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 19, - "operation": "incubation", - "description": "再次吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 20, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 21, - "operation": "incubation", - "description": "空气干燥15分钟", - "parameters": { - "time": 900 - } - }, - { - "step_number": 22, - "operation": "transfer", - "description": "加30-50μl Elution Buffer洗脱", - "parameters": { - "source": "P4", - "target": "P12", - "tip_rack": "BC230", - "volume": 40 - } - }, - { - "step_number": 23, - "operation": "move_labware", - "description": "移动到Orbital1振荡混匀(60秒)", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 24, - "operation": "oscillation", - "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", - "parameters": { - "rpm": 800, - "time": 60 - } - }, - { - "step_number": 25, - "operation": "move_labware", - "description": "振荡后送回磁力架P12", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 26, - "operation": "incubation", - "description": "室温静置3分钟(洗脱反应)", - "parameters": { - "time": 180 - } - }, - { - "step_number": 27, - "operation": "transfer", - "description": "将上清液(DNA)转移到新板(P13)", - "parameters": { - "source": "P12", - "target": "P13", - "tip_rack": "BC230", - "volume": 40 - } + "steps": [ + { + "step_number": 1, + "operation": "transfer", + "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", + "parameters": { + "source": "P1", + "target": "P11", + "tip_rack": "BC230", + "volume": 50 + } + }, + { + "step_number": 2, + "operation": "transfer", + "description": "加入2倍体积Bind Beads BC至产物中", + "parameters": { + "source": "P2", + "target": "P11", + "tip_rack": "BC230", + "volume": 100 + } + }, + { + "step_number": 3, + "operation": "move_labware", + "description": "移动P11至Orbital1用于振荡混匀", + "parameters": { + "source": "P11", + "target": "Orbital1" + } + }, + { + "step_number": 4, + "operation": "oscillation", + "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", + "parameters": { + "rpm": 800, + "time": 300 + } + }, + { + "step_number": 5, + "operation": "move_labware", + "description": "移动混匀后的板回P11", + "parameters": { + "source": "Orbital1", + "target": "P11" + } + }, + { + "step_number": 6, + "operation": "move_labware", + "description": "将P11移动到磁力架(P12)吸附3分钟", + "parameters": { + "source": "P11", + "target": "P12" + } + }, + { + "step_number": 7, + "operation": "incubation", + "description": "磁力架上室温静置3分钟完成吸附", + "parameters": { + "time": 180 + } + }, + { + "step_number": 8, + "operation": "transfer", + "description": "去除上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 150 + } + }, + { + "step_number": 9, + "operation": "transfer", + "description": "加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 10, + "operation": "move_labware", + "description": "移动清洗板到Orbital1进行振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 11, + "operation": "oscillation", + "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 12, + "operation": "move_labware", + "description": "振荡后将板移回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 13, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 14, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 15, + "operation": "transfer", + "description": "第二次加入300-500μl 75%乙醇清洗", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 16, + "operation": "move_labware", + "description": "再次移动清洗板到Orbital1振荡", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 17, + "operation": "oscillation", + "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", + "parameters": { + "rpm": 800, + "time": 45 + } + }, + { + "step_number": 18, + "operation": "move_labware", + "description": "振荡后板送回磁力架P12吸附", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 19, + "operation": "incubation", + "description": "再次吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 20, + "operation": "transfer", + "description": "去除乙醇上清液至废液槽", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 21, + "operation": "incubation", + "description": "空气干燥15分钟", + "parameters": { + "time": 900 + } + }, + { + "step_number": 22, + "operation": "transfer", + "description": "加30-50μl Elution Buffer洗脱", + "parameters": { + "source": "P4", + "target": "P12", + "tip_rack": "BC230", + "volume": 40 + } + }, + { + "step_number": 23, + "operation": "move_labware", + "description": "移动到Orbital1振荡混匀(60秒)", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 24, + "operation": "oscillation", + "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 25, + "operation": "move_labware", + "description": "振荡后送回磁力架P12", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 26, + "operation": "incubation", + "description": "室温静置3分钟(洗脱反应)", + "parameters": { + "time": 180 + } + }, + { + "step_number": 27, + "operation": "transfer", + "description": "将上清液(DNA)转移到新板(P13)", + "parameters": { + "source": "P12", + "target": "P13", + "tip_rack": "BC230", + "volume": 40 + } + } + ] } - ] -} -''' + ''' @@ -561,181 +563,193 @@ labware_with_liquid = ''' ] }, { - "id": "Tip Rack BC230 on TL3", - "parent": "deck", - "slot_on_deck": "TL3", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on TL4", - "parent": "deck", - "slot_on_deck": "TL4", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on TL5", - "parent": "deck", - "slot_on_deck": "TL5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P5", - "parent": "deck", - "slot_on_deck": "P5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P6", - "parent": "deck", - "slot_on_deck": "P6", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P7", - "parent": "deck", - "slot_on_deck": "P7", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on P8", - "parent": "deck", - "slot_on_deck": "P8", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P7", + "parent": "deck", + "slot_on_deck": "P7", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 P16", - "parent": "deck", - "slot_on_deck": "P16", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "stock plate on 4", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P2", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P3", - "parent": "deck", - "slot_on_deck": "P3", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "ethyl alcohol" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - - { - "id": "oscillation", - "parent": "deck", - "slot_on_deck": "Orbital1", - "class_name": "Orbital", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "working plate on P11", - "parent": "deck", - "slot_on_deck": "P11", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P8", + "parent": "deck", + "slot_on_deck": "P8", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "magnetics module on P12", - "parent": "deck", - "slot_on_deck": "P12", - "class_name": "magnetics module", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "working plate on P13", - "parent": "deck", - "slot_on_deck": "P13", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "waste on P22", - "parent": "deck", - "slot_on_deck": "P22", - "class_name": "nest_1_reservoir_195ml", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - } -] + "id": "stock plate on 4", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "ethyl alcohol" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "magnetics module on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "magnetics module", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "nest_1_reservoir_195ml", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + } + ] + + ''' + -''' handler = LiquidHandlerBiomek() @@ -760,6 +774,5 @@ for step in input_steps['steps']: aspirate_techniques='MC P300 high', dispense_techniques='MC P300 high' ) -with open('biomek_temporary_protocol.json', 'w') as f: - json.dump(handler.temp_protocol, f, indent=4, ensure_ascii=False) +print(json.dumps(handler.temp_protocol, indent=4)) From 24ecb13b79e7f37e7f969f5e5b28657db86bc969 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Fri, 6 Jun 2025 13:22:15 +0800 Subject: [PATCH 24/44] Update --- unilabos/devices/liquid_handling/biomek.py | 91 +++++++++++++--------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 9bd702d1..25a3f6ba 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -23,8 +23,8 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): 该类用于处理Biomek液体处理器的特定操作。 """ - def __init__(self, backend=None, deck=None, *args, **kwargs): - super().__init__(backend, deck, *args, **kwargs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self._status = "Idle" # 初始状态为 Idle self._success = False # 初始成功状态为 False self._status_queue = kwargs.get("status_queue", None) # 状态队列 @@ -32,46 +32,63 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 self.aspirate_techniques = { 'MC P300 high':{ - "Solvent": "Water", + 'Position': 'P1', + 'Height': -2.0, + 'Volume': '50', + 'liquidtype': 'Well Contents', + 'WellsX': 12, + 'LabwareClass': 'Matrix96_750uL', + 'AutoSelectPrototype': True, + 'ColsFirst': True, + 'CustomHeight': False, + 'DataSetPattern': False, + 'HeightFrom': 0, + 'LocalPattern': True, + 'Operation': 'Aspirate', + 'OverrideHeight': False, + 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), + 'Prototype': 'MC P300 High', + 'ReferencedPattern': '', + 'RowsFirst': False, + 'SectionExpression': '', + 'SelectionInfo': (1,), + 'SetMark': True, + 'Source': True, + 'StartAtMark': False, + 'StartAtSelection': True, + 'UseExpression': False}, } - } + self.dispense_techniques = { 'MC P300 high':{ - "Span8": False, - "Pod": "Pod1", - "Wash": False, - "Dynamic?": True, - "AutoSelectActiveWashTechnique": False, - "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": True, - "ChangeTipsBetweenSources": False, - "DefaultCaption": "", - "UseExpression": False, - "LeaveTipsOn": False, - "MandrelExpression": "", - "Repeats": "1", - "RepeatsByVolume": False, - "Replicates": "1", - "ShowTipHandlingDetails": False, - "ShowTransferDetails": True, - "Span8Wash": False, - "Span8WashVolume": "2", - "Span8WasteVolume": "1", - "SplitVolume": False, - "SplitVolumeCleaning": False, - "Stop": "Destinations", - "UseCurrentTips": False, - "UseDisposableTips": False, - "UseFixedTips": False, - "UseJIT": True, - "UseMandrelSelection": True, - "UseProbes": [True, True, True, True, True, True, True, True], - "WashCycles": "3", - "WashVolume": "110%", - "Wizard": False - } + 'Position': 'P11', + 'Height': -2.0, + 'Volume': '50', + 'liquidtype': 'Tip Contents', + 'WellsX': 12, + 'LabwareClass': 'Matrix96_750uL', + 'AutoSelectPrototype': True, + 'ColsFirst': True, + 'CustomHeight': False, + 'DataSetPattern': False, + 'HeightFrom': 0, + 'LocalPattern': True, + 'Operation': 'Dispense', + 'OverrideHeight': False, + 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), + 'Prototype': 'MC P300 High', + 'ReferencedPattern': '', + 'RowsFirst': False, + 'SectionExpression': '', + 'SelectionInfo': (1,), + 'SetMark': True, + 'Source': False, + 'StartAtMark': False, + 'StartAtSelection': True, + 'UseExpression': False} } + @classmethod def deserialize(cls, data: dict, allow_marshal: bool = False) -> LiquidHandler: return LiquidHandler.deserialize(data, allow_marshal) From 5bec899479cfbe261254cabfed241cb33222c6ec Mon Sep 17 00:00:00 2001 From: qxw138 Date: Fri, 6 Jun 2025 13:56:39 +0800 Subject: [PATCH 25/44] new actions --- unilabos/devices/liquid_handling/biomek.py | 84 ++++++++++++++++--- .../devices/liquid_handling/biomek_test.py | 52 ++++++------ 2 files changed, 102 insertions(+), 34 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 25a3f6ba..173ea091 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -46,7 +46,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, - 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), + 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, @@ -364,6 +364,61 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): return + def move_biomek( + self, + source: str, + target: str, + ): + """ + 处理Biomek移动板子的操作。 + + """ + + move_params = { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": source, + "Target": target, + "LeaveBottomLabware": False, + } + self.temp_protocol["steps"].append(move_params) + + return + + def incubation_biomek( + self, + time: int, + ): + """ + 处理Biomek的孵育操作。 + """ + incubation_params = { + "Message": "Paused", + "Location": "the whole system", + "Time": time, + "Mode": "TimedResource" + } + self.temp_protocol["steps"].append(incubation_params) + + return + + def oscillation_biomek( + self, + rpm: int, + time: int, + ): + """ + 处理Biomek的振荡操作。 + """ + oscillation_params = { + 'Device': 'OrbitalShaker0', + 'Parameters': (str(rpm), '2', str(time), 'CounterClockwise'), + 'Command': 'Timed Shake' + } + self.temp_protocol["steps"].append(oscillation_params) + + return + if __name__ == "__main__": @@ -857,16 +912,25 @@ input_steps = json.loads(steps_info) labwares = json.loads(labware_with_liquid) for step in input_steps['steps']: - if step['operation'] != 'transfer': - continue + operation = step['operation'] parameters = step['parameters'] - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=parameters['tip_rack'], - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high' - ) + if operation == 'transfer': + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=parameters['tip_rack'], + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high') + elif operation == 'move_labware': + handler.move_biomek(source=parameters['source'], + target=parameters['target']) + elif operation == 'oscillation': + handler.oscillation_biomek(rpm=parameters['rpm'], + time=parameters['time']) + elif operation == 'incubation': + handler.incubation_biomek(time=parameters['time']) + +print(json.dumps(handler.temp_protocol, indent=4)) diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 424d5ac7..e84000ab 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -1,14 +1,14 @@ -import requests +# import requests from typing import List, Sequence, Optional, Union, Literal # from geometry_msgs.msg import Point # from unilabos_msgs.msg import Resource -from pylabrobot.resources import ( - Resource, - TipRack, - Container, - Coordinate, - Well -) +# from pylabrobot.resources import ( +# Resource, +# TipRack, +# Container, +# Coordinate, +# Well +# ) # from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker # type: ignore # from .liquid_handler_abstract import LiquidHandlerAbstract @@ -299,13 +299,10 @@ class LiquidHandlerBiomek: 处理Biomek的孵育操作。 """ incubation_params = { - "BarcodeInput?": False, - "DeckItems": {}, - "Layout": "Multichannel", - "Pause?": True, - "PodSetup": {}, - "SplitterPosition": 206, - "VerifyPodSetup?": True + "Message": "Paused", + "Location": "the whole system", + "Time": time, + "Mode": "TimedResource" } self.temp_protocol["steps"].append(incubation_params) @@ -822,16 +819,23 @@ input_steps = json.loads(steps_info) labwares = json.loads(labware_with_liquid) for step in input_steps['steps']: - if step['operation'] != 'transfer': - continue + operation = step['operation'] parameters = step['parameters'] - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=parameters['tip_rack'], - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high' - ) + if operation == 'transfer': + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=parameters['tip_rack'], + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high') + elif operation == 'move_labware': + handler.move_biomek(source=parameters['source'], + target=parameters['target']) + elif operation == 'oscillation': + handler.oscillation_biomek(rpm=parameters['rpm'], + time=parameters['time']) + elif operation == 'incubation': + handler.incubation_biomek(time=parameters['time']) print(json.dumps(handler.temp_protocol, indent=4)) From 097114d38cef8f599590f5d4b70396a661c89f42 Mon Sep 17 00:00:00 2001 From: qxw138 Date: Fri, 6 Jun 2025 14:31:10 +0800 Subject: [PATCH 26/44] new actions --- unilabos_msgs/action/LiquidHandlerMoveBiomek.action | 6 ++++++ unilabos_msgs/action/LiquidHandlerOscillationBiomek.action | 6 ++++++ unilabos_msgs/action/LiquidHandlerPauseBiomek.action | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 unilabos_msgs/action/LiquidHandlerMoveBiomek.action create mode 100644 unilabos_msgs/action/LiquidHandlerOscillationBiomek.action create mode 100644 unilabos_msgs/action/LiquidHandlerPauseBiomek.action diff --git a/unilabos_msgs/action/LiquidHandlerMoveBiomek.action b/unilabos_msgs/action/LiquidHandlerMoveBiomek.action new file mode 100644 index 00000000..b27ca56b --- /dev/null +++ b/unilabos_msgs/action/LiquidHandlerMoveBiomek.action @@ -0,0 +1,6 @@ +string source +string target + +--- + +--- diff --git a/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action b/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action new file mode 100644 index 00000000..dda1ac11 --- /dev/null +++ b/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action @@ -0,0 +1,6 @@ +int32 rpm +int32 time + +--- + +--- diff --git a/unilabos_msgs/action/LiquidHandlerPauseBiomek.action b/unilabos_msgs/action/LiquidHandlerPauseBiomek.action new file mode 100644 index 00000000..46fd65cd --- /dev/null +++ b/unilabos_msgs/action/LiquidHandlerPauseBiomek.action @@ -0,0 +1,5 @@ +int32 time + +--- + +--- From 1b9f3c666d144a9d36016b6e8fd8a25f50e3d978 Mon Sep 17 00:00:00 2001 From: qxw138 Date: Fri, 6 Jun 2025 14:44:17 +0800 Subject: [PATCH 27/44] 1 --- unilabos_msgs/action/LiquidHandlerMoveBiomek.action | 2 +- unilabos_msgs/action/LiquidHandlerOscillationBiomek.action | 2 +- unilabos_msgs/action/LiquidHandlerPauseBiomek.action | 2 +- unilabos_msgs/action/LiquidHandlerTransferBiomek.action | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/unilabos_msgs/action/LiquidHandlerMoveBiomek.action b/unilabos_msgs/action/LiquidHandlerMoveBiomek.action index b27ca56b..9bcfc62d 100644 --- a/unilabos_msgs/action/LiquidHandlerMoveBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerMoveBiomek.action @@ -2,5 +2,5 @@ string source string target --- - +bool success --- diff --git a/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action b/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action index dda1ac11..5e37744b 100644 --- a/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action @@ -2,5 +2,5 @@ int32 rpm int32 time --- - +bool success --- diff --git a/unilabos_msgs/action/LiquidHandlerPauseBiomek.action b/unilabos_msgs/action/LiquidHandlerPauseBiomek.action index 46fd65cd..7746db77 100644 --- a/unilabos_msgs/action/LiquidHandlerPauseBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerPauseBiomek.action @@ -1,5 +1,5 @@ int32 time --- - +bool success --- diff --git a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action index b52dec57..46f9221b 100644 --- a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action @@ -6,5 +6,5 @@ string aspirate_technique string dispense_technique --- - +bool success --- From 55be5e818814602dc76372d5130b49a56db8cd3b Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Fri, 6 Jun 2025 17:21:19 +0800 Subject: [PATCH 28/44] registry --- unilabos/registry/registry.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unilabos/registry/registry.py b/unilabos/registry/registry.py index e95d25aa..2bc81874 100644 --- a/unilabos/registry/registry.py +++ b/unilabos/registry/registry.py @@ -214,6 +214,8 @@ class Registry: # 处理动作值映射 if "action_value_mappings" in device_config["class"]: for action_name, action_config in device_config["class"]["action_value_mappings"].items(): + if "handles" not in action_config: + device_config["handles"] = [] if "type" in action_config: action_config["type"] = self._replace_type_with_class( action_config["type"], device_id, f"动作 {action_name}" From 48c43d330329e7a340c0d9b51ca08f101ef2ed3d Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Fri, 6 Jun 2025 17:45:54 +0800 Subject: [PATCH 29/44] fix biomek startup add action handles --- unilabos/devices/liquid_handling/biomek.py | 461 +++++++++--------- unilabos/registry/devices/liquid_handler.yaml | 30 ++ 2 files changed, 257 insertions(+), 234 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 173ea091..451d45eb 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -23,8 +23,8 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): 该类用于处理Biomek液体处理器的特定操作。 """ - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, backend=None, deck=None, *args, **kwargs): + super().__init__(backend, deck, *args, **kwargs) self._status = "Idle" # 初始状态为 Idle self._success = False # 初始成功状态为 False self._status_queue = kwargs.get("status_queue", None) # 状态队列 @@ -421,7 +421,6 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): if __name__ == "__main__": - steps_info = ''' { "steps": [ @@ -684,33 +683,20 @@ if __name__ == "__main__": ] } ''' - - - -labware_with_liquid = ''' -[ { - "id": "stock plate on P1", - "parent": "deck", - "slot_on_deck": "P1", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "master_mix" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "Tip Rack BC230 TL2", - "parent": "deck", - "slot_on_deck": "TL2", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + labware_with_liquid = ''' + [ { + "id": "stock plate on P1", + "parent": "deck", + "slot_on_deck": "P1", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "master_mix" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, { "id": "Tip Rack BC230 TL2", "parent": "deck", @@ -722,215 +708,222 @@ labware_with_liquid = ''' ] }, { - "id": "Tip Rack BC230 on TL3", - "parent": "deck", - "slot_on_deck": "TL3", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on TL4", - "parent": "deck", - "slot_on_deck": "TL4", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on TL5", - "parent": "deck", - "slot_on_deck": "TL5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P5", - "parent": "deck", - "slot_on_deck": "P5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P6", - "parent": "deck", - "slot_on_deck": "P6", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 on P7", - "parent": "deck", - "slot_on_deck": "P7", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on P8", - "parent": "deck", - "slot_on_deck": "P8", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "Tip Rack BC230 on P7", + "parent": "deck", + "slot_on_deck": "P7", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "Tip Rack BC230 P16", - "parent": "deck", - "slot_on_deck": "P16", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "stock plate on 4", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P2", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P3", - "parent": "deck", - "slot_on_deck": "P3", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "ethyl alcohol" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - - { - "id": "oscillation", - "parent": "deck", - "slot_on_deck": "Orbital1", - "class_name": "Orbital", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "working plate on P11", - "parent": "deck", - "slot_on_deck": "P11", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 on P8", + "parent": "deck", + "slot_on_deck": "P8", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "magnetics module on P12", - "parent": "deck", - "slot_on_deck": "P12", - "class_name": "magnetics module", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "working plate on P13", - "parent": "deck", - "slot_on_deck": "P13", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + "id": "Tip Rack BC230 P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, { - "id": "waste on P22", - "parent": "deck", - "slot_on_deck": "P22", - "class_name": "nest_1_reservoir_195ml", - "liquid_type": [ - ], - "liquid_volume": [], - "liquid_input_wells": [ - ] - } - ] - - ''' - - - -handler = LiquidHandlerBiomek() - -handler.temp_protocol = { - "meta": {}, - "labwares": [], - "steps": [] -} - -input_steps = json.loads(steps_info) -labwares = json.loads(labware_with_liquid) - -for step in input_steps['steps']: - operation = step['operation'] - parameters = step['parameters'] - - if operation == 'transfer': - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=parameters['tip_rack'], - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high') - elif operation == 'move_labware': - handler.move_biomek(source=parameters['source'], - target=parameters['target']) - elif operation == 'oscillation': - handler.oscillation_biomek(rpm=parameters['rpm'], - time=parameters['time']) - elif operation == 'incubation': - handler.incubation_biomek(time=parameters['time']) - -print(json.dumps(handler.temp_protocol, indent=4)) + "id": "stock plate on 4", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "ethyl alcohol" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "magnetics module on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "magnetics module", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "nest_1_reservoir_195ml", + "liquid_type": [ + ], + "liquid_volume": [], + "liquid_input_wells": [ + ] + } + ] + + ''' + handler = LiquidHandlerBiomek() + + handler.temp_protocol = { + "meta": {}, + "labwares": [], + "steps": [] + } + + input_steps = json.loads(steps_info) + labwares = json.loads(labware_with_liquid) + + for step in input_steps['steps']: + operation = step['operation'] + parameters = step['parameters'] + + if operation == 'transfer': + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=parameters['tip_rack'], + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high') + elif operation == 'move_labware': + handler.move_biomek(source=parameters['source'], + target=parameters['target']) + elif operation == 'oscillation': + handler.oscillation_biomek(rpm=parameters['rpm'], + time=parameters['time']) + elif operation == 'incubation': + handler.incubation_biomek(time=parameters['time']) + + print(json.dumps(handler.temp_protocol, indent=4)) diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index eba2e0bc..c891fb22 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -340,6 +340,21 @@ liquid_handler.biomek: none_keys: none_keys feedback: {} result: {} + handles: + input: + - handler_key: liquid-input + label: Liquid Input + data_type: resource + io_type: target + data_source: handle + data_key: liquid + output: + - handler_key: liquid-output + label: Liquid Output + data_type: resource + io_type: source + data_source: executor + data_key: liquid transfer_biomek: type: LiquidHandlerTransferBiomek goal: @@ -351,6 +366,21 @@ liquid_handler.biomek: dispense_techniques: dispense_techniques feedback: {} result: {} + handles: + input: + - handler_key: liquid-input + label: Liquid Input + data_type: resource + io_type: target + data_source: handle + data_key: liquid + output: + - handler_key: liquid-output + label: Liquid Output + data_type: resource + io_type: source + data_source: executor + data_key: liquid schema: type: object properties: {} From c7b9c6a8252a16868c8d839f6d2fe24a11ba812a Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Fri, 6 Jun 2025 18:13:53 +0800 Subject: [PATCH 30/44] fix handles not as default entry --- unilabos/registry/registry.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unilabos/registry/registry.py b/unilabos/registry/registry.py index 2bc81874..9a5e3b59 100644 --- a/unilabos/registry/registry.py +++ b/unilabos/registry/registry.py @@ -64,6 +64,7 @@ class Registry: "goal_default": yaml.safe_load( io.StringIO(get_yaml_from_goal_type(self.ResourceCreateFromOuter.Goal)) ), + "handles": {}, }, "create_resource": { "type": self.ResourceCreateFromOuterEasy, @@ -84,6 +85,7 @@ class Registry: "goal_default": yaml.safe_load( io.StringIO(get_yaml_from_goal_type(self.ResourceCreateFromOuterEasy.Goal)) ), + "handles": {}, }, "test_latency": { "type": self.EmptyIn, @@ -92,6 +94,7 @@ class Registry: "result": {"latency_ms": "latency_ms", "time_diff_ms": "time_diff_ms"}, "schema": ros_action_to_json_schema(self.EmptyIn), "goal_default": {}, + "handles": {}, }, }, }, @@ -215,7 +218,7 @@ class Registry: if "action_value_mappings" in device_config["class"]: for action_name, action_config in device_config["class"]["action_value_mappings"].items(): if "handles" not in action_config: - device_config["handles"] = [] + action_config["handles"] = [] if "type" in action_config: action_config["type"] = self._replace_type_with_class( action_config["type"], device_id, f"动作 {action_name}" From 6573c9e02eefdf63e563cd60323d247903146f4f Mon Sep 17 00:00:00 2001 From: qxw138 Date: Fri, 6 Jun 2025 22:42:06 +0800 Subject: [PATCH 31/44] biomek_test.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json --- unilabos/devices/liquid_handling/biomek.py | 146 +- .../devices/liquid_handling/biomek_test.py | 428 +- .../complete_biomek_protocol.json | 3760 +++++++++++++++++ 3 files changed, 4119 insertions(+), 215 deletions(-) create mode 100644 unilabos/devices/liquid_handling/complete_biomek_protocol.json diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 173ea091..e4189e7c 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -688,133 +688,102 @@ if __name__ == "__main__": labware_with_liquid = ''' -[ { - "id": "stock plate on P1", - "parent": "deck", - "slot_on_deck": "P1", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "master_mix" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "Tip Rack BC230 TL2", - "parent": "deck", - "slot_on_deck": "TL2", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + [ { - "id": "Tip Rack BC230 TL2", + "id": "Tip Rack BC230 on TL1", + "parent": "deck", + "slot_on_deck": "TL1", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on TL2", "parent": "deck", "slot_on_deck": "TL2", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on TL3", "parent": "deck", "slot_on_deck": "TL3", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on TL4", "parent": "deck", "slot_on_deck": "TL4", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on TL5", "parent": "deck", "slot_on_deck": "TL5", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on P5", "parent": "deck", "slot_on_deck": "P5", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on P6", "parent": "deck", "slot_on_deck": "P6", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on P7", - "parent": "deck", - "slot_on_deck": "P7", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, { - "id": "Tip Rack BC230 on P8", + "id": "Tip Rack BC230 on P15", "parent": "deck", - "slot_on_deck": "P8", + "slot_on_deck": "P15", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { - "id": "Tip Rack BC230 P16", + { + "id": "Tip Rack BC230 on P16", "parent": "deck", "slot_on_deck": "P16", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, { - "id": "stock plate on 4", + "id": "stock plate on P1", "parent": "deck", - "slot_on_deck": "P2", + "slot_on_deck": "P1", "class_name": "nest_12_reservoir_15ml", "liquid_type": [ - "bind beads" + "master_mix" ], "liquid_volume": [10000], "liquid_input_wells": [ "A1" ] }, - { + { "id": "stock plate on P2", "parent": "deck", "slot_on_deck": "P2", @@ -827,7 +796,7 @@ labware_with_liquid = ''' "A1" ] }, - { + { "id": "stock plate on P3", "parent": "deck", "slot_on_deck": "P3", @@ -840,62 +809,65 @@ labware_with_liquid = ''' "A1" ] }, - - { + { + "id": "elution buffer on P4", + "parent": "deck", + "slot_on_deck": "P4", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "elution buffer" + ], + "liquid_volume": [5000], + "liquid_input_wells": [ + "A1" + ] + }, + { "id": "oscillation", "parent": "deck", "slot_on_deck": "Orbital1", "class_name": "Orbital", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "working plate on P11", "parent": "deck", "slot_on_deck": "P11", "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], + "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "magnetics module on P12", "parent": "deck", "slot_on_deck": "P12", "class_name": "magnetics module", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "working plate on P13", "parent": "deck", "slot_on_deck": "P13", "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], + "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "waste on P22", "parent": "deck", "slot_on_deck": "P22", "class_name": "nest_1_reservoir_195ml", - "liquid_type": [ - ], + "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] } ] - ''' diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index e84000ab..85777604 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -13,6 +13,7 @@ from typing import List, Sequence, Optional, Union, Literal # from .liquid_handler_abstract import LiquidHandlerAbstract import json +import pathlib from typing import Sequence, Optional, List, Union, Literal @@ -33,6 +34,23 @@ class LiquidHandlerBiomek: self._status_queue = kwargs.get("status_queue", None) # 状态队列 self.temp_protocol = {} self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 + + # 预定义的仪器分类 + self.tip_racks = [ + "BC230", "BC1025F", "BC50", "TipRack200", "TipRack1000", + "tip", "tips", "Tip", "Tips" + ] + + self.reservoirs = [ + "AgilentReservoir", "nest_12_reservoir_15ml", "nest_1_reservoir_195ml", + "reservoir", "Reservoir", "waste", "Waste" + ] + + self.plates_96 = [ + "BCDeep96Round", "Matrix96_750uL", "NEST 2ml Deep Well Plate", "nest_96_wellplate_100ul_pcr_full_skirt", + "nest_96_wellplate_200ul_flat", "Matrix96", "96", "plate", "Plate" + ] + self.aspirate_techniques = { 'MC P300 high':{ 'Position': 'P1', @@ -49,7 +67,7 @@ class LiquidHandlerBiomek: 'LocalPattern': True, 'Operation': 'Aspirate', 'OverrideHeight': False, - 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), + 'Pattern': (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True), 'Prototype': 'MC P300 High', 'ReferencedPattern': '', 'RowsFirst': False, @@ -92,6 +110,30 @@ class LiquidHandlerBiomek: } + def _get_instrument_type(self, class_name: str) -> str: + """ + 根据class_name判断仪器类型 + + Returns: + str: "tip_rack", "reservoir", "plate_96", 或 "unknown" + """ + # 检查是否是枪头架 + for tip_name in self.tip_racks: + if tip_name in class_name: + return "tip_rack" + + # 检查是否是储液槽 + for reservoir_name in self.reservoirs: + if reservoir_name in class_name: + return "reservoir" + + # 检查是否是96孔板 + for plate_name in self.plates_96: + if plate_name in class_name: + return "plate_96" + + return "unknown" + def create_protocol( self, protocol_name: str, @@ -198,7 +240,104 @@ class LiquidHandlerBiomek: # } # self.temp_protocol["labwares"].append(resource) # return resource - + def instrument_setup_biomek( + self, + id: str, + parent: str, + slot_on_deck: str, + class_name: str, + liquid_type: list[str], + liquid_volume: list[int], + liquid_input_wells: list[str], + ): + """ + 设置Biomek仪器的参数配置,完全按照Biomek的实际格式 + + 根据不同的仪器类型(容器、tip rack等)设置相应的参数结构 + """ + + # 判断仪器类型 + instrument_type = self._get_instrument_type(class_name) + + config = {} # 初始化为空字典,以便在各种情况下都能返回 + + if instrument_type == "reservoir": + # 储液槽类型配置 + config = { + "Properties": { + "Name": id, # 使用id作为名称 + "Device": "", + "liquidtype": liquid_type[0] if liquid_type else "Water", + "BarCode": "", + "SenseEveryTime": False + }, + "Known": True, + "Class": f"LabwareClasses\\{class_name}", + "DataSets": {"Volume": {}}, + "RuntimeDataSets": {"Volume": {}}, + "EvalAmounts": (float(liquid_volume[0]),) if liquid_volume else (0.0,), + "Nominal": False, + "EvalLiquids": (liquid_type[0],) if liquid_type else ("Water",) + } + + elif instrument_type == "plate_96": + # 96孔板类型配置 + volume_per_well = float(liquid_volume[0]) if liquid_volume else 500.0 + liquid_per_well = liquid_type[0] if liquid_type else "Water" + + config = { + "Properties": { + "Name": id, # 使用id作为名称 + "Device": "", + "liquidtype": liquid_per_well, + "BarCode": "", + "SenseEveryTime": False + }, + "Known": True, + "Class": f"LabwareClasses\\{class_name}", + "DataSets": {"Volume": {}}, + "RuntimeDataSets": {"Volume": {}}, + "EvalAmounts": tuple([volume_per_well] * 96), + "Nominal": False, + "EvalLiquids": tuple([liquid_per_well] * 96) + } + + elif instrument_type == "tip_rack": + # 枪头架类型配置 + tip_config = { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": False, + "RT_Used": False, + "Dirty": False, + "RT_Dirty": False, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + } + + config = { + "Tips": tip_config, + "RT_Tips": tip_config.copy(), + "Properties": {}, + "Known": False, + "Class": f"LabwareClasses\\{class_name}", + "DataSets": {"Volume": {}}, + "RuntimeDataSets": {"Volume": {}} + } + + else: + # 未知类型或空位置的默认配置 + config = {} + + # 将配置直接添加到labwares列表中 + if config: # 只有非空配置才添加 + # 添加Name字段用于标识 + config["Name"] = id + config["Position"] = slot_on_deck + self.temp_protocol["labwares"].append(config) + + return def transfer_biomek( self, @@ -266,7 +405,8 @@ class LiquidHandlerBiomek: transfer_params["items"] = items transfer_params["Solvent"] = 'Water' transfer_params["TipLocation"] = tip_rack - self.temp_protocol["steps"].append(transfer_params) + tmp={'transfer': transfer_params} + self.temp_protocol["steps"].append(tmp) return @@ -287,7 +427,8 @@ class LiquidHandlerBiomek: "Target": target, "LeaveBottomLabware": False, } - self.temp_protocol["steps"].append(move_params) + tmp={'move': move_params} + self.temp_protocol["steps"].append(tmp) return @@ -304,7 +445,8 @@ class LiquidHandlerBiomek: "Time": time, "Mode": "TimedResource" } - self.temp_protocol["steps"].append(incubation_params) + tmp={'incubation': incubation_params} + self.temp_protocol["steps"].append(tmp) return @@ -321,14 +463,19 @@ class LiquidHandlerBiomek: 'Parameters': (str(rpm), '2', str(time), 'CounterClockwise'), 'Command': 'Timed Shake' } - self.temp_protocol["steps"].append(oscillation_params) + tmp={'oscillation': oscillation_params} + self.temp_protocol["steps"].append(tmp) return if __name__ == "__main__": - + + print("=== Biomek完整流程测试 ===") + print("包含: 仪器设置 + 完整实验步骤") + + # 完整的步骤信息(从biomek.py复制) steps_info = ''' { "steps": [ @@ -592,136 +739,104 @@ if __name__ == "__main__": } ''' - - -labware_with_liquid = ''' -[ { - "id": "stock plate on P1", - "parent": "deck", - "slot_on_deck": "P1", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "master_mix" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "Tip Rack BC230 TL2", - "parent": "deck", - "slot_on_deck": "TL2", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] - }, + # 完整的labware配置信息(从biomek.py复制) + labware_with_liquid = ''' + [ { - "id": "Tip Rack BC230 TL2", + "id": "Tip Rack BC230 on TL1", + "parent": "deck", + "slot_on_deck": "TL1", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on TL2", "parent": "deck", "slot_on_deck": "TL2", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on TL3", "parent": "deck", "slot_on_deck": "TL3", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on TL4", "parent": "deck", "slot_on_deck": "TL4", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on TL5", "parent": "deck", "slot_on_deck": "TL5", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on P5", "parent": "deck", "slot_on_deck": "P5", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "Tip Rack BC230 on P6", "parent": "deck", "slot_on_deck": "P6", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] - }, - { - "id": "Tip Rack BC230 on P7", - "parent": "deck", - "slot_on_deck": "P7", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, { - "id": "Tip Rack BC230 on P8", + "id": "Tip Rack BC230 on P15", "parent": "deck", - "slot_on_deck": "P8", + "slot_on_deck": "P15", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { - "id": "Tip Rack BC230 P16", + { + "id": "Tip Rack BC230 on P16", "parent": "deck", "slot_on_deck": "P16", "class_name": "BC230", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, { - "id": "stock plate on 4", + "id": "stock plate on P1", "parent": "deck", - "slot_on_deck": "P2", + "slot_on_deck": "P1", "class_name": "nest_12_reservoir_15ml", "liquid_type": [ - "bind beads" + "master_mix" ], "liquid_volume": [10000], "liquid_input_wells": [ "A1" ] }, - { + { "id": "stock plate on P2", "parent": "deck", "slot_on_deck": "P2", @@ -734,7 +849,7 @@ labware_with_liquid = ''' "A1" ] }, - { + { "id": "stock plate on P3", "parent": "deck", "slot_on_deck": "P3", @@ -747,95 +862,152 @@ labware_with_liquid = ''' "A1" ] }, - - { + { + "id": "elution buffer on P4", + "parent": "deck", + "slot_on_deck": "P4", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "elution buffer" + ], + "liquid_volume": [5000], + "liquid_input_wells": [ + "A1" + ] + }, + { "id": "oscillation", "parent": "deck", "slot_on_deck": "Orbital1", "class_name": "Orbital", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "working plate on P11", "parent": "deck", "slot_on_deck": "P11", "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], + "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "magnetics module on P12", "parent": "deck", "slot_on_deck": "P12", "class_name": "magnetics module", "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "working plate on P13", "parent": "deck", "slot_on_deck": "P13", "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [ - ], + "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] }, - { + { "id": "waste on P22", "parent": "deck", "slot_on_deck": "P22", "class_name": "nest_1_reservoir_195ml", - "liquid_type": [ - ], + "liquid_type": [], "liquid_volume": [], - "liquid_input_wells": [ - ] + "liquid_input_wells": [] } ] - ''' + # 创建handler实例 + handler = LiquidHandlerBiomek() + + # 创建协议 + protocol = handler.create_protocol( + protocol_name="DNA纯化完整流程", + protocol_description="使用磁珠进行DNA纯化的完整自动化流程", + protocol_version="1.0", + protocol_author="Biomek系统", + protocol_date="2024-01-01", + protocol_type="DNA_purification" + ) + print("\n=== 第一步:设置所有仪器 ===") + # 解析labware配置 + labwares = json.loads(labware_with_liquid) + + # 设置所有仪器 + instrument_count = 0 + for labware in labwares: + print(f"设置仪器: {labware['id']} ({labware['class_name']}) 在位置 {labware['slot_on_deck']}") + handler.instrument_setup_biomek( + id=labware['id'], + parent=labware['parent'], + slot_on_deck=labware['slot_on_deck'], + class_name=labware['class_name'], + liquid_type=labware['liquid_type'], + liquid_volume=labware['liquid_volume'], + liquid_input_wells=labware['liquid_input_wells'] + ) + instrument_count += 1 + + print(f"总共设置了 {instrument_count} 个仪器位置") -handler = LiquidHandlerBiomek() + print("\n=== 第二步:执行实验步骤 ===") + # 解析步骤信息 + input_steps = json.loads(steps_info) + + # 执行所有步骤 + step_count = 0 + for step in input_steps['steps']: + operation = step['operation'] + parameters = step['parameters'] + description = step['description'] + + print(f"步骤 {step['step_number']}: {description}") + + if operation == 'transfer': + handler.transfer_biomek( + source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=parameters['tip_rack'], + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high' + ) + elif operation == 'move_labware': + handler.move_biomek( + source=parameters['source'], + target=parameters['target'] + ) + elif operation == 'oscillation': + handler.oscillation_biomek( + rpm=parameters['rpm'], + time=parameters['time'] + ) + elif operation == 'incubation': + handler.incubation_biomek( + time=parameters['time'] + ) + + step_count += 1 + + print(f"总共执行了 {step_count} 个步骤") -handler.temp_protocol = { - "meta": {}, - "labwares": [], - "steps": [] -} - -input_steps = json.loads(steps_info) -labwares = json.loads(labware_with_liquid) - -for step in input_steps['steps']: - operation = step['operation'] - parameters = step['parameters'] - - if operation == 'transfer': - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=parameters['tip_rack'], - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high') - elif operation == 'move_labware': - handler.move_biomek(source=parameters['source'], - target=parameters['target']) - elif operation == 'oscillation': - handler.oscillation_biomek(rpm=parameters['rpm'], - time=parameters['time']) - elif operation == 'incubation': - handler.incubation_biomek(time=parameters['time']) - -print(json.dumps(handler.temp_protocol, indent=4)) + print("\n=== 第三步:保存完整协议 ===") + # 获取脚本目录 + script_dir = pathlib.Path(__file__).parent + + # 保存完整协议 + complete_output_path = script_dir / "complete_biomek_protocol.json" + with open(complete_output_path, 'w', encoding='utf-8') as f: + json.dump(handler.temp_protocol, f, indent=4, ensure_ascii=False) + + print(f"完整协议已保存到: {complete_output_path}") + + print("\n=== 测试完成 ===") + print("完整的DNA纯化流程已成功转换为Biomek格式!") diff --git a/unilabos/devices/liquid_handling/complete_biomek_protocol.json b/unilabos/devices/liquid_handling/complete_biomek_protocol.json new file mode 100644 index 00000000..2c0e95fd --- /dev/null +++ b/unilabos/devices/liquid_handling/complete_biomek_protocol.json @@ -0,0 +1,3760 @@ +{ + "meta": { + "name": "DNA纯化完整流程", + "description": "使用磁珠进行DNA纯化的完整自动化流程", + "version": "1.0", + "author": "Biomek系统", + "date": "2024-01-01", + "type": "DNA_purification" + }, + "labwares": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on TL1", + "Position": "TL1" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on TL2", + "Position": "TL2" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on TL3", + "Position": "TL3" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on TL4", + "Position": "TL4" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on TL5", + "Position": "TL5" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on P5", + "Position": "P5" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on P6", + "Position": "P6" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on P15", + "Position": "P15" + }, + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "Name": "Tip Rack BC230 on P16", + "Position": "P16" + }, + { + "Properties": { + "Name": "stock plate on P1", + "Device": "", + "liquidtype": "master_mix", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 10000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "master_mix" + ], + "Name": "stock plate on P1", + "Position": "P1" + }, + { + "Properties": { + "Name": "stock plate on P2", + "Device": "", + "liquidtype": "bind beads", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 10000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "bind beads" + ], + "Name": "stock plate on P2", + "Position": "P2" + }, + { + "Properties": { + "Name": "stock plate on P3", + "Device": "", + "liquidtype": "ethyl alcohol", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 10000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "ethyl alcohol" + ], + "Name": "stock plate on P3", + "Position": "P3" + }, + { + "Properties": { + "Name": "elution buffer on P4", + "Device": "", + "liquidtype": "elution buffer", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 5000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "elution buffer" + ], + "Name": "elution buffer on P4", + "Position": "P4" + }, + { + "Properties": { + "Name": "working plate on P11", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\NEST 2ml Deep Well Plate", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water" + ], + "Name": "working plate on P11", + "Position": "P11" + }, + { + "Properties": { + "Name": "working plate on P13", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\NEST 2ml Deep Well Plate", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water" + ], + "Name": "working plate on P13", + "Position": "P13" + }, + { + "Properties": { + "Name": "waste on P22", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_1_reservoir_195ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 0.0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water" + ], + "Name": "waste on P22", + "Position": "P22" + } + ], + "steps": [ + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P11", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "300", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P11", + "LeaveBottomLabware": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P11", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "45", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "45", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 900, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "60", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + } + ] +} \ No newline at end of file From e840516ba4df2d09e926b6cffe077058e23b9930 Mon Sep 17 00:00:00 2001 From: qxw138 Date: Fri, 6 Jun 2025 22:50:11 +0800 Subject: [PATCH 32/44] Update biomek.py --- unilabos/devices/liquid_handling/biomek.py | 52 +++++++++++----------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 925ac53c..7d671a68 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -873,35 +873,35 @@ labware_with_liquid = ''' handler = LiquidHandlerBiomek() - handler.temp_protocol = { - "meta": {}, - "labwares": [], - "steps": [] - } +handler.temp_protocol = { + "meta": {}, + "labwares": [], + "steps": [] +} - input_steps = json.loads(steps_info) - labwares = json.loads(labware_with_liquid) +input_steps = json.loads(steps_info) +labwares = json.loads(labware_with_liquid) - for step in input_steps['steps']: - operation = step['operation'] - parameters = step['parameters'] +for step in input_steps['steps']: + operation = step['operation'] + parameters = step['parameters'] - if operation == 'transfer': - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=parameters['tip_rack'], - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high') - elif operation == 'move_labware': - handler.move_biomek(source=parameters['source'], - target=parameters['target']) - elif operation == 'oscillation': - handler.oscillation_biomek(rpm=parameters['rpm'], - time=parameters['time']) - elif operation == 'incubation': - handler.incubation_biomek(time=parameters['time']) + if operation == 'transfer': + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=parameters['tip_rack'], + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high') + elif operation == 'move_labware': + handler.move_biomek(source=parameters['source'], + target=parameters['target']) + elif operation == 'oscillation': + handler.oscillation_biomek(rpm=parameters['rpm'], + time=parameters['time']) + elif operation == 'incubation': + handler.incubation_biomek(time=parameters['time']) - print(json.dumps(handler.temp_protocol, indent=4)) +print(json.dumps(handler.temp_protocol, indent=4)) From 3f53f88390c3fe3d499f4534e52e56d6a81ab10e Mon Sep 17 00:00:00 2001 From: qxw138 Date: Sat, 7 Jun 2025 15:21:20 +0800 Subject: [PATCH 33/44] biomek_test.py --- .../devices/liquid_handling/biomek_test.py | 25 +- .../complete_biomek_protocol_0607.json | 3762 +++++++++++++++++ 2 files changed, 3773 insertions(+), 14 deletions(-) create mode 100644 unilabos/devices/liquid_handling/complete_biomek_protocol_0607.json diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 85777604..185d47b5 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -168,7 +168,7 @@ class LiquidHandlerBiomek: "date": protocol_date, "type": protocol_type, }, - "labwares": [], + "labwares": {}, # 改为字典格式以匹配DeckItems "steps": [], } return self.temp_protocol @@ -251,15 +251,16 @@ class LiquidHandlerBiomek: liquid_input_wells: list[str], ): """ - 设置Biomek仪器的参数配置,完全按照Biomek的实际格式 + 设置Biomek仪器的参数配置,按照DeckItems格式 根据不同的仪器类型(容器、tip rack等)设置相应的参数结构 + 位置作为键,配置列表作为值 """ # 判断仪器类型 instrument_type = self._get_instrument_type(class_name) - config = {} # 初始化为空字典,以便在各种情况下都能返回 + config = None # 初始化为None if instrument_type == "reservoir": # 储液槽类型配置 @@ -325,17 +326,13 @@ class LiquidHandlerBiomek: "DataSets": {"Volume": {}}, "RuntimeDataSets": {"Volume": {}} } - - else: - # 未知类型或空位置的默认配置 - config = {} - # 将配置直接添加到labwares列表中 - if config: # 只有非空配置才添加 - # 添加Name字段用于标识 - config["Name"] = id - config["Position"] = slot_on_deck - self.temp_protocol["labwares"].append(config) + # 按照DeckItems格式存储:位置作为键,配置列表作为值 + if config is not None: + self.temp_protocol["labwares"][slot_on_deck] = [config] + else: + # 空位置 + self.temp_protocol["labwares"][slot_on_deck] = [] return @@ -1003,7 +1000,7 @@ if __name__ == "__main__": script_dir = pathlib.Path(__file__).parent # 保存完整协议 - complete_output_path = script_dir / "complete_biomek_protocol.json" + complete_output_path = script_dir / "complete_biomek_protocol_0607.json" with open(complete_output_path, 'w', encoding='utf-8') as f: json.dump(handler.temp_protocol, f, indent=4, ensure_ascii=False) diff --git a/unilabos/devices/liquid_handling/complete_biomek_protocol_0607.json b/unilabos/devices/liquid_handling/complete_biomek_protocol_0607.json new file mode 100644 index 00000000..be73033c --- /dev/null +++ b/unilabos/devices/liquid_handling/complete_biomek_protocol_0607.json @@ -0,0 +1,3762 @@ +{ + "meta": { + "name": "DNA纯化完整流程", + "description": "使用磁珠进行DNA纯化的完整自动化流程", + "version": "1.0", + "author": "Biomek系统", + "date": "2024-01-01", + "type": "DNA_purification" + }, + "labwares": { + "TL1": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "TL2": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "TL3": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "TL4": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "TL5": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "P5": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "P6": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "P15": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "P16": [ + { + "Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "RT_Tips": { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": false, + "RT_Used": false, + "Dirty": false, + "RT_Dirty": false, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + }, + "Properties": {}, + "Known": false, + "Class": "LabwareClasses\\BC230", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + } + } + ], + "P1": [ + { + "Properties": { + "Name": "stock plate on P1", + "Device": "", + "liquidtype": "master_mix", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 10000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "master_mix" + ] + } + ], + "P2": [ + { + "Properties": { + "Name": "stock plate on P2", + "Device": "", + "liquidtype": "bind beads", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 10000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "bind beads" + ] + } + ], + "P3": [ + { + "Properties": { + "Name": "stock plate on P3", + "Device": "", + "liquidtype": "ethyl alcohol", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 10000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "ethyl alcohol" + ] + } + ], + "P4": [ + { + "Properties": { + "Name": "elution buffer on P4", + "Device": "", + "liquidtype": "elution buffer", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 5000.0 + ], + "Nominal": false, + "EvalLiquids": [ + "elution buffer" + ] + } + ], + "Orbital1": [], + "P11": [ + { + "Properties": { + "Name": "working plate on P11", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\NEST 2ml Deep Well Plate", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water" + ] + } + ], + "P12": [], + "P13": [ + { + "Properties": { + "Name": "working plate on P13", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\NEST 2ml Deep Well Plate", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0, + 500.0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water" + ] + } + ], + "P22": [ + { + "Properties": { + "Name": "waste on P22", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\nest_1_reservoir_195ml", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 0.0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water" + ] + } + ] + }, + "steps": [ + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P11", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "300", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P11", + "LeaveBottomLabware": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P11", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "45", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "45", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 900, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "60", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P13", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + } + ] +} \ No newline at end of file From 8698821c5289a483a4dc776b1a9d0bbf5397f2f9 Mon Sep 17 00:00:00 2001 From: Junhan Chang Date: Sat, 7 Jun 2025 18:52:20 +0800 Subject: [PATCH 34/44] fix liquid_handler.biomek handles --- unilabos/devices/liquid_handling/biomek.py | 9 ++ unilabos/registry/devices/liquid_handler.yaml | 87 +++++++++++++++++-- unilabos_msgs/CMakeLists.txt | 4 + ...ion => LiquidHandlerIncubateBiomek.action} | 0 ...on => LiquidHandlerOscillateBiomek.action} | 0 5 files changed, 93 insertions(+), 7 deletions(-) rename unilabos_msgs/action/{LiquidHandlerPauseBiomek.action => LiquidHandlerIncubateBiomek.action} (100%) rename unilabos_msgs/action/{LiquidHandlerOscillationBiomek.action => LiquidHandlerOscillateBiomek.action} (100%) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 451d45eb..469fb39b 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -93,6 +93,15 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): def deserialize(cls, data: dict, allow_marshal: bool = False) -> LiquidHandler: return LiquidHandler.deserialize(data, allow_marshal) + @property + def success(self): + """ + 获取操作是否成功的状态。 + + Returns: + bool: 如果操作成功,返回True;否则返回False。 + """ + return self._success def create_protocol( self, diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index c891fb22..eef04042 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -368,18 +368,91 @@ liquid_handler.biomek: result: {} handles: input: - - handler_key: liquid-input - label: Liquid Input + - handler_key: sources + label: sources + data_type: resource + data_source: handle + data_key: liquid + - handler_key: targets + label: targets + data_type: resource + data_source: executor + data_key: liquid + - handler_key: tip_rack + label: tip_rack + data_type: resource + data_source: executor + data_key: liquid + output: + - handler_key: sources_out + label: sources + data_type: resource + data_source: handle + data_key: liquid + - handler_key: targets_out + label: targets + data_type: resource + data_source: executor + data_key: liquid + oscillation_biomek: + type: LiquidHandlerOscillateBiomek + goal: + rpm: rpm + time: time + feedback: {} + result: {} + handles: + input: + - handler_key: plate + label: plate data_type: resource - io_type: target data_source: handle data_key: liquid output: - - handler_key: liquid-output - label: Liquid Output + - handler_key: plate_out + label: plate data_type: resource - io_type: source - data_source: executor + data_source: handle + data_key: liquid + move_biomek: + type: LiquidHandlerMoveBiomek + goal: + source: resource + target: target + feedback: {} + result: + name: name + handles: + input: + - handler_key: sources + label: sources + data_type: resource + data_source: handle + data_key: liquid + output: + - handler_key: targets + label: targets + data_type: resource + data_source: handle + data_key: liquid + incubation_biomek: + type: LiquidHandlerIncubateBiomek + goal: + time: time + feedback: {} + result: {} + handles: + input: + - handler_key: plate + label: plate + data_type: resource + data_source: handle + data_key: liquid + output: + - handler_key: plate_out + label: plate + data_type: resource + data_source: handle data_key: liquid schema: type: object diff --git a/unilabos_msgs/CMakeLists.txt b/unilabos_msgs/CMakeLists.txt index 098bb35c..3e98ce6e 100644 --- a/unilabos_msgs/CMakeLists.txt +++ b/unilabos_msgs/CMakeLists.txt @@ -45,7 +45,11 @@ set(action_files "action/LiquidHandlerReturnTips96.action" "action/LiquidHandlerStamp.action" "action/LiquidHandlerTransfer.action" + "action/LiquidHandlerTransferBiomek.action" + "action/LiquidHandlerIncubateBiomek.action" + "action/LiquidHandlerMoveBiomek.action" + "action/LiquidHandlerOscillateBiomek.action" "action/LiquidHandlerAdd.action" "action/LiquidHandlerMix.action" diff --git a/unilabos_msgs/action/LiquidHandlerPauseBiomek.action b/unilabos_msgs/action/LiquidHandlerIncubateBiomek.action similarity index 100% rename from unilabos_msgs/action/LiquidHandlerPauseBiomek.action rename to unilabos_msgs/action/LiquidHandlerIncubateBiomek.action diff --git a/unilabos_msgs/action/LiquidHandlerOscillationBiomek.action b/unilabos_msgs/action/LiquidHandlerOscillateBiomek.action similarity index 100% rename from unilabos_msgs/action/LiquidHandlerOscillationBiomek.action rename to unilabos_msgs/action/LiquidHandlerOscillateBiomek.action From c0b7f2decd21e3650ac34f521373e2e1ead13a70 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sun, 8 Jun 2025 13:23:55 +0800 Subject: [PATCH 35/44] =?UTF-8?q?host=20node=E6=96=B0=E5=A2=9Eresource=20a?= =?UTF-8?q?dd=E6=97=B6=E9=97=B4=E7=BB=9F=E8=AE=A1=20create=5Fresource?= =?UTF-8?q?=E6=96=B0=E5=A2=9Ehandle=20bump=20version=20to=200.9.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- README_zh.md | 2 +- recipes/ros-humble-unilabos-msgs/recipe.yaml | 2 +- recipes/unilabos/recipe.yaml | 2 +- setup.py | 2 +- unilabos/registry/registry.py | 10 +++++++++- unilabos/ros/nodes/presets/host_node.py | 4 +++- unilabos_msgs/action/AGVTransfer.action | 1 + unilabos_msgs/action/Clean.action | 1 + unilabos_msgs/action/EmptyIn.action | 2 +- unilabos_msgs/action/EvacuateAndRefill.action | 1 + unilabos_msgs/action/Evaporate.action | 1 + unilabos_msgs/action/FloatSingleInput.action | 1 + unilabos_msgs/action/HeatChill.action | 1 + unilabos_msgs/action/HeatChillStart.action | 1 + unilabos_msgs/action/HeatChillStop.action | 1 + unilabos_msgs/action/IntSingleInput.action | 1 + unilabos_msgs/action/LiquidHandlerAdd.action | 1 + unilabos_msgs/action/LiquidHandlerAspirate.action | 1 + unilabos_msgs/action/LiquidHandlerDiscardTips.action | 1 + unilabos_msgs/action/LiquidHandlerDispense.action | 1 + unilabos_msgs/action/LiquidHandlerDropTips.action | 1 + unilabos_msgs/action/LiquidHandlerDropTips96.action | 1 + .../action/LiquidHandlerIncubateBiomek.action | 1 + unilabos_msgs/action/LiquidHandlerMix.action | 1 + unilabos_msgs/action/LiquidHandlerMoveBiomek.action | 1 + unilabos_msgs/action/LiquidHandlerMoveLid.action | 1 + unilabos_msgs/action/LiquidHandlerMovePlate.action | 1 + unilabos_msgs/action/LiquidHandlerMoveResource.action | 1 + unilabos_msgs/action/LiquidHandlerMoveTo.action | 1 + .../action/LiquidHandlerOscillateBiomek.action | 1 + unilabos_msgs/action/LiquidHandlerPickUpTips.action | 1 + unilabos_msgs/action/LiquidHandlerPickUpTips96.action | 1 + .../action/LiquidHandlerProtocolCreation.action | 1 + unilabos_msgs/action/LiquidHandlerRemove.action | 1 + unilabos_msgs/action/LiquidHandlerReturnTips.action | 1 + unilabos_msgs/action/LiquidHandlerReturnTips96.action | 1 + unilabos_msgs/action/LiquidHandlerStamp.action | 1 + unilabos_msgs/action/LiquidHandlerTransfer.action | 1 + .../action/LiquidHandlerTransferBiomek.action | 1 + unilabos_msgs/action/Point3DSeparateInput.action | 1 + unilabos_msgs/action/PumpTransfer.action | 1 + unilabos_msgs/action/ResourceCreateFromOuter.action | 1 + .../action/ResourceCreateFromOuterEasy.action | 1 + unilabos_msgs/action/SendCmd.action | 1 + unilabos_msgs/action/Separate.action | 1 + unilabos_msgs/action/SolidDispenseAddPowderTube.action | 1 + unilabos_msgs/action/Stir.action | 1 + unilabos_msgs/action/StrSingleInput.action | 1 + unilabos_msgs/action/WorkStationRun.action | 1 + 50 files changed, 60 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c10ed4e0..00930671 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ conda env update --file unilabos-[YOUR_OS].yml -n environment_name # Currently, you need to install the `unilabos_msgs` package # You can download the system-specific package from the Release page -conda install ros-humble-unilabos-msgs-0.9.1-xxxxx.tar.bz2 +conda install ros-humble-unilabos-msgs-0.9.2-xxxxx.tar.bz2 # Install PyLabRobot and other prerequisites git clone https://github.com/PyLabRobot/pylabrobot plr_repo diff --git a/README_zh.md b/README_zh.md index b0b7b30c..433e3135 100644 --- a/README_zh.md +++ b/README_zh.md @@ -45,7 +45,7 @@ conda env update --file unilabos-[YOUR_OS].yml -n 环境名 # 现阶段,需要安装 `unilabos_msgs` 包 # 可以前往 Release 页面下载系统对应的包进行安装 -conda install ros-humble-unilabos-msgs-0.9.1-xxxxx.tar.bz2 +conda install ros-humble-unilabos-msgs-0.9.2-xxxxx.tar.bz2 # 安装PyLabRobot等前置 git clone https://github.com/PyLabRobot/pylabrobot plr_repo diff --git a/recipes/ros-humble-unilabos-msgs/recipe.yaml b/recipes/ros-humble-unilabos-msgs/recipe.yaml index 2ee7f1f8..a7faf4c1 100644 --- a/recipes/ros-humble-unilabos-msgs/recipe.yaml +++ b/recipes/ros-humble-unilabos-msgs/recipe.yaml @@ -1,6 +1,6 @@ package: name: ros-humble-unilabos-msgs - version: 0.9.1 + version: 0.9.2 source: path: ../../unilabos_msgs folder: ros-humble-unilabos-msgs/src/work diff --git a/recipes/unilabos/recipe.yaml b/recipes/unilabos/recipe.yaml index 5b036306..b261d16b 100644 --- a/recipes/unilabos/recipe.yaml +++ b/recipes/unilabos/recipe.yaml @@ -1,6 +1,6 @@ package: name: unilabos - version: "0.9.1" + version: "0.9.2" source: path: ../.. diff --git a/setup.py b/setup.py index 847098a5..e3a86cdb 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ package_name = 'unilabos' setup( name=package_name, - version='0.9.1', + version='0.9.2', packages=find_packages(), include_package_data=True, install_requires=['setuptools'], diff --git a/unilabos/registry/registry.py b/unilabos/registry/registry.py index 9a5e3b59..a1602727 100644 --- a/unilabos/registry/registry.py +++ b/unilabos/registry/registry.py @@ -85,7 +85,15 @@ class Registry: "goal_default": yaml.safe_load( io.StringIO(get_yaml_from_goal_type(self.ResourceCreateFromOuterEasy.Goal)) ), - "handles": {}, + "handles": { + "output": [{ + "handler_key": "Labware", + "label": "Labware", + "data_type": "resource", + "data_source": "handle", + "data_key": "liquid" + }] + }, }, "test_latency": { "type": self.EmptyIn, diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index 732e8bbd..f4284629 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -203,8 +203,10 @@ class HostNode(BaseROS2DeviceNode): try: for bridge in self.bridges: if hasattr(bridge, "resource_add"): - self.lab_logger().info("[Host Node-Resource] Adding resources to bridge.") + resource_start_time = time.time() resource_add_res = bridge.resource_add(add_schema(resource_with_parent_name)) + resource_end_time = time.time() + self.lab_logger().info(f"[Host Node-Resource] Adding resources to bridge. {round(resource_start_time - resource_end_time, 5)} seconds") except Exception as ex: self.lab_logger().error("[Host Node-Resource] 添加物料出错!") self.lab_logger().error(traceback.format_exc()) diff --git a/unilabos_msgs/action/AGVTransfer.action b/unilabos_msgs/action/AGVTransfer.action index 06c8c8ef..0c301f47 100644 --- a/unilabos_msgs/action/AGVTransfer.action +++ b/unilabos_msgs/action/AGVTransfer.action @@ -4,6 +4,7 @@ string from_repo_position Resource to_repo string to_repo_position --- +string return_info bool success --- string status diff --git a/unilabos_msgs/action/Clean.action b/unilabos_msgs/action/Clean.action index 093a0dad..8fb9be1e 100644 --- a/unilabos_msgs/action/Clean.action +++ b/unilabos_msgs/action/Clean.action @@ -5,6 +5,7 @@ float64 volume # Optional. Volume of solvent to clean vessel with. float64 temp # Optional. Temperature to heat vessel to while cleaning. int32 repeats # Optional. Number of cleaning cycles to perform. --- +string return_info bool success --- string status diff --git a/unilabos_msgs/action/EmptyIn.action b/unilabos_msgs/action/EmptyIn.action index c44b70c0..e7f59d07 100644 --- a/unilabos_msgs/action/EmptyIn.action +++ b/unilabos_msgs/action/EmptyIn.action @@ -1,4 +1,4 @@ --- - +string return_info --- \ No newline at end of file diff --git a/unilabos_msgs/action/EvacuateAndRefill.action b/unilabos_msgs/action/EvacuateAndRefill.action index ed138dd5..22ffc659 100644 --- a/unilabos_msgs/action/EvacuateAndRefill.action +++ b/unilabos_msgs/action/EvacuateAndRefill.action @@ -3,6 +3,7 @@ string vessel string gas int32 repeats --- +string return_info bool success --- string status diff --git a/unilabos_msgs/action/Evaporate.action b/unilabos_msgs/action/Evaporate.action index 9638a9a8..45887f27 100644 --- a/unilabos_msgs/action/Evaporate.action +++ b/unilabos_msgs/action/Evaporate.action @@ -5,6 +5,7 @@ float64 temp float64 time float64 stir_speed --- +string return_info bool success --- string status diff --git a/unilabos_msgs/action/FloatSingleInput.action b/unilabos_msgs/action/FloatSingleInput.action index 2542d31f..52feed71 100644 --- a/unilabos_msgs/action/FloatSingleInput.action +++ b/unilabos_msgs/action/FloatSingleInput.action @@ -1,4 +1,5 @@ float64 float_in --- +string return_info bool success --- \ No newline at end of file diff --git a/unilabos_msgs/action/HeatChill.action b/unilabos_msgs/action/HeatChill.action index 1c7f8411..87ebf526 100644 --- a/unilabos_msgs/action/HeatChill.action +++ b/unilabos_msgs/action/HeatChill.action @@ -6,6 +6,7 @@ bool stir float64 stir_speed string purpose --- +string return_info bool success --- string status \ No newline at end of file diff --git a/unilabos_msgs/action/HeatChillStart.action b/unilabos_msgs/action/HeatChillStart.action index f9286937..565bad1e 100644 --- a/unilabos_msgs/action/HeatChillStart.action +++ b/unilabos_msgs/action/HeatChillStart.action @@ -3,6 +3,7 @@ string vessel float64 temp string purpose --- +string return_info bool success --- string status \ No newline at end of file diff --git a/unilabos_msgs/action/HeatChillStop.action b/unilabos_msgs/action/HeatChillStop.action index 88fc0293..280ca154 100644 --- a/unilabos_msgs/action/HeatChillStop.action +++ b/unilabos_msgs/action/HeatChillStop.action @@ -1,6 +1,7 @@ # Organic string vessel --- +string return_info bool success --- string status \ No newline at end of file diff --git a/unilabos_msgs/action/IntSingleInput.action b/unilabos_msgs/action/IntSingleInput.action index 0f8b7aaa..23aeec6f 100644 --- a/unilabos_msgs/action/IntSingleInput.action +++ b/unilabos_msgs/action/IntSingleInput.action @@ -1,4 +1,5 @@ int32 int_input --- +string return_info bool success --- \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerAdd.action b/unilabos_msgs/action/LiquidHandlerAdd.action index 0611b276..a17a61c4 100644 --- a/unilabos_msgs/action/LiquidHandlerAdd.action +++ b/unilabos_msgs/action/LiquidHandlerAdd.action @@ -15,6 +15,7 @@ int32 mix_rate float64 mix_liquid_height string[] none_keys --- +string return_info bool success --- # 反馈 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerAspirate.action b/unilabos_msgs/action/LiquidHandlerAspirate.action index 9ba17068..b8558617 100644 --- a/unilabos_msgs/action/LiquidHandlerAspirate.action +++ b/unilabos_msgs/action/LiquidHandlerAspirate.action @@ -7,5 +7,6 @@ float64[] liquid_height float64[] blow_out_air_volume string spread --- +string return_info bool success --- \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerDiscardTips.action b/unilabos_msgs/action/LiquidHandlerDiscardTips.action index a7c6f8ae..c2d290d0 100644 --- a/unilabos_msgs/action/LiquidHandlerDiscardTips.action +++ b/unilabos_msgs/action/LiquidHandlerDiscardTips.action @@ -3,6 +3,7 @@ int32[] use_channels --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerDispense.action b/unilabos_msgs/action/LiquidHandlerDispense.action index 73c4d0f4..e06e3753 100644 --- a/unilabos_msgs/action/LiquidHandlerDispense.action +++ b/unilabos_msgs/action/LiquidHandlerDispense.action @@ -8,6 +8,7 @@ int32[] blow_out_air_volume string spread --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerDropTips.action b/unilabos_msgs/action/LiquidHandlerDropTips.action index 76a5625b..46f7e493 100644 --- a/unilabos_msgs/action/LiquidHandlerDropTips.action +++ b/unilabos_msgs/action/LiquidHandlerDropTips.action @@ -6,6 +6,7 @@ geometry_msgs/Point[] offsets bool allow_nonzero_volume --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerDropTips96.action b/unilabos_msgs/action/LiquidHandlerDropTips96.action index b4b7dfcf..a32891f5 100644 --- a/unilabos_msgs/action/LiquidHandlerDropTips96.action +++ b/unilabos_msgs/action/LiquidHandlerDropTips96.action @@ -5,6 +5,7 @@ geometry_msgs/Point offset bool allow_nonzero_volume --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerIncubateBiomek.action b/unilabos_msgs/action/LiquidHandlerIncubateBiomek.action index 7746db77..da9d7035 100644 --- a/unilabos_msgs/action/LiquidHandlerIncubateBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerIncubateBiomek.action @@ -1,5 +1,6 @@ int32 time --- +string return_info bool success --- diff --git a/unilabos_msgs/action/LiquidHandlerMix.action b/unilabos_msgs/action/LiquidHandlerMix.action index 81d1b71c..99abe939 100644 --- a/unilabos_msgs/action/LiquidHandlerMix.action +++ b/unilabos_msgs/action/LiquidHandlerMix.action @@ -6,6 +6,7 @@ geometry_msgs/Point[] offsets float64 mix_rate string[] none_keys --- +string return_info bool success --- # 反馈 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerMoveBiomek.action b/unilabos_msgs/action/LiquidHandlerMoveBiomek.action index 9bcfc62d..b12feb1d 100644 --- a/unilabos_msgs/action/LiquidHandlerMoveBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerMoveBiomek.action @@ -2,5 +2,6 @@ string source string target --- +string return_info bool success --- diff --git a/unilabos_msgs/action/LiquidHandlerMoveLid.action b/unilabos_msgs/action/LiquidHandlerMoveLid.action index 41a51e58..0c5d7477 100644 --- a/unilabos_msgs/action/LiquidHandlerMoveLid.action +++ b/unilabos_msgs/action/LiquidHandlerMoveLid.action @@ -12,6 +12,7 @@ string put_direction float64 pickup_distance_from_top --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerMovePlate.action b/unilabos_msgs/action/LiquidHandlerMovePlate.action index ea7503a1..6ad283db 100644 --- a/unilabos_msgs/action/LiquidHandlerMovePlate.action +++ b/unilabos_msgs/action/LiquidHandlerMovePlate.action @@ -13,6 +13,7 @@ string put_direction float64 pickup_distance_from_top --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerMoveResource.action b/unilabos_msgs/action/LiquidHandlerMoveResource.action index aaffa968..776d6cee 100644 --- a/unilabos_msgs/action/LiquidHandlerMoveResource.action +++ b/unilabos_msgs/action/LiquidHandlerMoveResource.action @@ -12,6 +12,7 @@ string get_direction string put_direction --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerMoveTo.action b/unilabos_msgs/action/LiquidHandlerMoveTo.action index 740d0fc6..0a9e1fe2 100644 --- a/unilabos_msgs/action/LiquidHandlerMoveTo.action +++ b/unilabos_msgs/action/LiquidHandlerMoveTo.action @@ -2,6 +2,7 @@ Resource well float64 dis_to_top int32 channel --- +string return_info bool success --- # 反馈 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerOscillateBiomek.action b/unilabos_msgs/action/LiquidHandlerOscillateBiomek.action index 5e37744b..b07eb76d 100644 --- a/unilabos_msgs/action/LiquidHandlerOscillateBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerOscillateBiomek.action @@ -2,5 +2,6 @@ int32 rpm int32 time --- +string return_info bool success --- diff --git a/unilabos_msgs/action/LiquidHandlerPickUpTips.action b/unilabos_msgs/action/LiquidHandlerPickUpTips.action index 096bf17e..89287d91 100644 --- a/unilabos_msgs/action/LiquidHandlerPickUpTips.action +++ b/unilabos_msgs/action/LiquidHandlerPickUpTips.action @@ -5,6 +5,7 @@ int32[] use_channels geometry_msgs/Point[] offsets --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerPickUpTips96.action b/unilabos_msgs/action/LiquidHandlerPickUpTips96.action index 761349a1..63a60b4a 100644 --- a/unilabos_msgs/action/LiquidHandlerPickUpTips96.action +++ b/unilabos_msgs/action/LiquidHandlerPickUpTips96.action @@ -4,6 +4,7 @@ Resource tip_rack geometry_msgs/Point offset --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerProtocolCreation.action b/unilabos_msgs/action/LiquidHandlerProtocolCreation.action index de8c605a..c63525a5 100644 --- a/unilabos_msgs/action/LiquidHandlerProtocolCreation.action +++ b/unilabos_msgs/action/LiquidHandlerProtocolCreation.action @@ -6,4 +6,5 @@ string protocol_date string protocol_type string[] none_keys --- +string return_info --- diff --git a/unilabos_msgs/action/LiquidHandlerRemove.action b/unilabos_msgs/action/LiquidHandlerRemove.action index e6b43c53..2b2656e5 100644 --- a/unilabos_msgs/action/LiquidHandlerRemove.action +++ b/unilabos_msgs/action/LiquidHandlerRemove.action @@ -12,6 +12,7 @@ bool is_96_well float64[] top string[] none_keys --- +string return_info bool success --- # 反馈 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerReturnTips.action b/unilabos_msgs/action/LiquidHandlerReturnTips.action index 25d15965..0c3b366c 100644 --- a/unilabos_msgs/action/LiquidHandlerReturnTips.action +++ b/unilabos_msgs/action/LiquidHandlerReturnTips.action @@ -4,6 +4,7 @@ int32[] use_channels bool allow_nonzero_volume --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerReturnTips96.action b/unilabos_msgs/action/LiquidHandlerReturnTips96.action index fd20d712..da670e5f 100644 --- a/unilabos_msgs/action/LiquidHandlerReturnTips96.action +++ b/unilabos_msgs/action/LiquidHandlerReturnTips96.action @@ -3,6 +3,7 @@ bool allow_nonzero_volume --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerStamp.action b/unilabos_msgs/action/LiquidHandlerStamp.action index a7db4bf2..383eee3e 100644 --- a/unilabos_msgs/action/LiquidHandlerStamp.action +++ b/unilabos_msgs/action/LiquidHandlerStamp.action @@ -7,6 +7,7 @@ float64 aspiration_flow_rate float64 dispense_flow_rate --- # 结果字段 +string return_info bool success --- # 反馈字段 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerTransfer.action b/unilabos_msgs/action/LiquidHandlerTransfer.action index 39df59bb..6130f20c 100644 --- a/unilabos_msgs/action/LiquidHandlerTransfer.action +++ b/unilabos_msgs/action/LiquidHandlerTransfer.action @@ -20,6 +20,7 @@ float64 mix_liquid_height int32[] delays string[] none_keys --- +string return_info bool success --- # 反馈 \ No newline at end of file diff --git a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action index 46f9221b..cee47bc7 100644 --- a/unilabos_msgs/action/LiquidHandlerTransferBiomek.action +++ b/unilabos_msgs/action/LiquidHandlerTransferBiomek.action @@ -6,5 +6,6 @@ string aspirate_technique string dispense_technique --- +string return_info bool success --- diff --git a/unilabos_msgs/action/Point3DSeparateInput.action b/unilabos_msgs/action/Point3DSeparateInput.action index 4e15e8f8..5d24125e 100644 --- a/unilabos_msgs/action/Point3DSeparateInput.action +++ b/unilabos_msgs/action/Point3DSeparateInput.action @@ -2,5 +2,6 @@ float64 x float64 y float64 z --- +string return_info bool success --- \ No newline at end of file diff --git a/unilabos_msgs/action/PumpTransfer.action b/unilabos_msgs/action/PumpTransfer.action index bbe6cb1e..69d22b6c 100644 --- a/unilabos_msgs/action/PumpTransfer.action +++ b/unilabos_msgs/action/PumpTransfer.action @@ -10,6 +10,7 @@ float64 rinsing_volume int32 rinsing_repeats bool solid --- +string return_info bool success --- string status diff --git a/unilabos_msgs/action/ResourceCreateFromOuter.action b/unilabos_msgs/action/ResourceCreateFromOuter.action index e0eeb1c7..57330758 100644 --- a/unilabos_msgs/action/ResourceCreateFromOuter.action +++ b/unilabos_msgs/action/ResourceCreateFromOuter.action @@ -4,5 +4,6 @@ string[] bind_parent_ids geometry_msgs/Point[] bind_locations string[] other_calling_params --- +string return_info bool success --- \ No newline at end of file diff --git a/unilabos_msgs/action/ResourceCreateFromOuterEasy.action b/unilabos_msgs/action/ResourceCreateFromOuterEasy.action index cc832a71..b4adaed9 100644 --- a/unilabos_msgs/action/ResourceCreateFromOuterEasy.action +++ b/unilabos_msgs/action/ResourceCreateFromOuterEasy.action @@ -8,5 +8,6 @@ string[] liquid_type float32[] liquid_volume int32 slot_on_deck --- +string return_info bool success --- diff --git a/unilabos_msgs/action/SendCmd.action b/unilabos_msgs/action/SendCmd.action index cc883204..6f453f6e 100644 --- a/unilabos_msgs/action/SendCmd.action +++ b/unilabos_msgs/action/SendCmd.action @@ -1,6 +1,7 @@ # Simple string command --- +string return_info bool success --- string status diff --git a/unilabos_msgs/action/Separate.action b/unilabos_msgs/action/Separate.action index 502b420c..fe8976a7 100644 --- a/unilabos_msgs/action/Separate.action +++ b/unilabos_msgs/action/Separate.action @@ -13,6 +13,7 @@ float64 stir_time # Optional. Time stir for after adding solvent, before separat float64 stir_speed # Optional. Speed to stir at after adding solvent, before separation of phases. float64 settling_time # Optional. Time --- +string return_info bool success --- string status diff --git a/unilabos_msgs/action/SolidDispenseAddPowderTube.action b/unilabos_msgs/action/SolidDispenseAddPowderTube.action index 674c4ffc..db0924e1 100644 --- a/unilabos_msgs/action/SolidDispenseAddPowderTube.action +++ b/unilabos_msgs/action/SolidDispenseAddPowderTube.action @@ -2,6 +2,7 @@ int32 powder_tube_number string target_tube_position float64 compound_mass --- +string return_info float64 actual_mass_mg bool success --- \ No newline at end of file diff --git a/unilabos_msgs/action/Stir.action b/unilabos_msgs/action/Stir.action index defbed34..9542f9dc 100644 --- a/unilabos_msgs/action/Stir.action +++ b/unilabos_msgs/action/Stir.action @@ -3,6 +3,7 @@ float64 stir_time float64 stir_speed float64 settling_time --- +string return_info bool success --- string status \ No newline at end of file diff --git a/unilabos_msgs/action/StrSingleInput.action b/unilabos_msgs/action/StrSingleInput.action index bb762a58..bac365bc 100644 --- a/unilabos_msgs/action/StrSingleInput.action +++ b/unilabos_msgs/action/StrSingleInput.action @@ -1,4 +1,5 @@ string string --- +string return_info bool success --- \ No newline at end of file diff --git a/unilabos_msgs/action/WorkStationRun.action b/unilabos_msgs/action/WorkStationRun.action index ea75668d..5ca9fd4e 100644 --- a/unilabos_msgs/action/WorkStationRun.action +++ b/unilabos_msgs/action/WorkStationRun.action @@ -3,6 +3,7 @@ string wf_name string params Resource resource --- +string return_info bool success --- string status From ab0c4b708b63fa5b195108fee9233c815e38c1f0 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sun, 8 Jun 2025 14:43:07 +0800 Subject: [PATCH 36/44] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=89=A9=E6=96=99?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=97=B6=E9=97=B4=20=E6=94=B9=E7=94=A8biomek?= =?UTF-8?q?=5Ftest=20=E5=A2=9E=E5=8A=A0ResultInfoEncoder=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/experiments/biomek.json | 22 + unilabos/app/mq.py | 7 +- unilabos/app/web/client.py | 6 +- unilabos/devices/liquid_handling/biomek.py | 434 +++++++++--------- unilabos/registry/devices/liquid_handler.yaml | 2 +- unilabos/ros/nodes/base_device_node.py | 135 ++++-- unilabos/ros/nodes/presets/host_node.py | 12 +- unilabos/utils/async_util.py | 7 +- unilabos/utils/type_check.py | 45 +- 9 files changed, 403 insertions(+), 267 deletions(-) create mode 100644 test/experiments/biomek.json diff --git a/test/experiments/biomek.json b/test/experiments/biomek.json new file mode 100644 index 00000000..604adccc --- /dev/null +++ b/test/experiments/biomek.json @@ -0,0 +1,22 @@ +{ + "nodes": [ + { + "id": "BIOMEK", + "name": "BIOMEK", + "parent": null, + "type": "device", + "class": "liquid_handler.biomek", + "position": { + "x": 620.6111111111111, + "y": 171, + "z": 0 + }, + "config": { + }, + "data": {}, + "children": [ + ] + } + ], + "links": [] +} \ No newline at end of file diff --git a/unilabos/app/mq.py b/unilabos/app/mq.py index 9f870691..36bc0337 100644 --- a/unilabos/app/mq.py +++ b/unilabos/app/mq.py @@ -1,6 +1,7 @@ import json import time import traceback +from typing import Optional import uuid import paho.mqtt.client as mqtt @@ -163,10 +164,12 @@ class MQTTClient: self.client.publish(address, json.dumps(status), qos=2) logger.critical(f"Device status published: address: {address}, {status}") - def publish_job_status(self, feedback_data: dict, job_id: str, status: str): + def publish_job_status(self, feedback_data: dict, job_id: str, status: str, return_info: Optional[dict] = None): if self.mqtt_disable: return - jobdata = {"job_id": job_id, "data": feedback_data, "status": status} + if return_info is None: + return_info = {} + jobdata = {"job_id": job_id, "data": feedback_data, "status": status, "return_info": return_info} self.client.publish(f"labs/{MQConfig.lab_id}/job/list/", json.dumps(jobdata), qos=2) def publish_registry(self, device_id: str, device_info: dict): diff --git a/unilabos/app/web/client.py b/unilabos/app/web/client.py index da5d0696..648859f6 100644 --- a/unilabos/app/web/client.py +++ b/unilabos/app/web/client.py @@ -30,18 +30,18 @@ class HTTPClient: self.auth = MQConfig.lab_id info(f"HTTPClient 初始化完成: remote_addr={self.remote_addr}") - def resource_add(self, resources: List[Dict[str, Any]]) -> requests.Response: + def resource_add(self, resources: List[Dict[str, Any]], database_process_later:bool) -> requests.Response: """ 添加资源 Args: resources: 要添加的资源列表 - + database_process_later: 后台处理资源 Returns: Response: API响应对象 """ response = requests.post( - f"{self.remote_addr}/lab/resource/", + f"{self.remote_addr}/lab/resource/?database_process_later={1 if database_process_later else 0}", json=resources, headers={"Authorization": f"lab {self.auth}"}, timeout=5, diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 61b2d936..ea7a9e9c 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -693,224 +693,220 @@ if __name__ == "__main__": } ''' - - -labware_with_liquid = ''' - [ - { - "id": "Tip Rack BC230 on TL1", - "parent": "deck", - "slot_on_deck": "TL1", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL2", - "parent": "deck", - "slot_on_deck": "TL2", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL3", - "parent": "deck", - "slot_on_deck": "TL3", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL4", - "parent": "deck", - "slot_on_deck": "TL4", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL5", - "parent": "deck", - "slot_on_deck": "TL5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P5", - "parent": "deck", - "slot_on_deck": "P5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P6", - "parent": "deck", - "slot_on_deck": "P6", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P15", - "parent": "deck", - "slot_on_deck": "P15", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P16", - "parent": "deck", - "slot_on_deck": "P16", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "stock plate on P1", - "parent": "deck", - "slot_on_deck": "P1", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "master_mix" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P2", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P3", - "parent": "deck", - "slot_on_deck": "P3", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "ethyl alcohol" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "elution buffer on P4", - "parent": "deck", - "slot_on_deck": "P4", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "elution buffer" - ], - "liquid_volume": [5000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "oscillation", - "parent": "deck", - "slot_on_deck": "Orbital1", - "class_name": "Orbital", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "working plate on P11", - "parent": "deck", - "slot_on_deck": "P11", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "magnetics module on P12", - "parent": "deck", - "slot_on_deck": "P12", - "class_name": "magnetics module", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "working plate on P13", - "parent": "deck", - "slot_on_deck": "P13", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "waste on P22", - "parent": "deck", - "slot_on_deck": "P22", - "class_name": "nest_1_reservoir_195ml", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - } - ] - ''' - - - -handler = LiquidHandlerBiomek() - -handler.temp_protocol = { - "meta": {}, - "labwares": [], - "steps": [] -} - -input_steps = json.loads(steps_info) -labwares = json.loads(labware_with_liquid) - -for step in input_steps['steps']: - operation = step['operation'] - parameters = step['parameters'] - - if operation == 'transfer': - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=parameters['tip_rack'], - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high') - elif operation == 'move_labware': - handler.move_biomek(source=parameters['source'], - target=parameters['target']) - elif operation == 'oscillation': - handler.oscillation_biomek(rpm=parameters['rpm'], - time=parameters['time']) - elif operation == 'incubation': - handler.incubation_biomek(time=parameters['time']) - -print(json.dumps(handler.temp_protocol, indent=4)) + labware_with_liquid = ''' + [ + { + "id": "Tip Rack BC230 on TL1", + "parent": "deck", + "slot_on_deck": "TL1", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on P15", + "parent": "deck", + "slot_on_deck": "P15", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 on P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "stock plate on P1", + "parent": "deck", + "slot_on_deck": "P1", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "master_mix" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "bind beads" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "ethyl alcohol" + ], + "liquid_volume": [10000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "elution buffer on P4", + "parent": "deck", + "slot_on_deck": "P4", + "class_name": "nest_12_reservoir_15ml", + "liquid_type": [ + "elution buffer" + ], + "liquid_volume": [5000], + "liquid_input_wells": [ + "A1" + ] + }, + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "magnetics module on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "magnetics module", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "NEST 2ml Deep Well Plate", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "nest_1_reservoir_195ml", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + } + ] + ''' + # 创建Biomek液体处理器实例 + handler = LiquidHandlerBiomek() + + handler.temp_protocol = { + "meta": {}, + "labwares": [], + "steps": [] + } + + input_steps = json.loads(steps_info) + labwares = json.loads(labware_with_liquid) + + for step in input_steps['steps']: + operation = step['operation'] + parameters = step['parameters'] + + if operation == 'transfer': + handler.transfer_biomek(source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=parameters['tip_rack'], + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high') + elif operation == 'move_labware': + handler.move_biomek(source=parameters['source'], + target=parameters['target']) + elif operation == 'oscillation': + handler.oscillation_biomek(rpm=parameters['rpm'], + time=parameters['time']) + elif operation == 'incubation': + handler.incubation_biomek(time=parameters['time']) + + print(json.dumps(handler.temp_protocol, indent=4)) diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index eef04042..6851f285 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -293,7 +293,7 @@ liquid_handler.biomek: description: Biomek液体处理器设备,基于pylabrobot控制 icon: icon_yiyezhan.webp class: - module: unilabos.devices.liquid_handling.biomek:LiquidHandlerBiomek + module: unilabos.devices.liquid_handling.biomek_test:LiquidHandlerBiomek type: python status_types: {} action_value_mappings: diff --git a/unilabos/ros/nodes/base_device_node.py b/unilabos/ros/nodes/base_device_node.py index e7991303..e75413f1 100644 --- a/unilabos/ros/nodes/base_device_node.py +++ b/unilabos/ros/nodes/base_device_node.py @@ -1,5 +1,4 @@ import copy -import functools import json import threading import time @@ -20,16 +19,29 @@ from rclpy.service import Service from unilabos_msgs.action import SendCmd from unilabos_msgs.srv._serial_command import SerialCommand_Request, SerialCommand_Response -from unilabos.resources.graphio import convert_resources_to_type, convert_resources_from_type, resource_ulab_to_plr, \ - initialize_resources, list_to_nested_dict, dict_to_tree, resource_plr_to_ulab, tree_to_list +from unilabos.resources.graphio import ( + convert_resources_to_type, + convert_resources_from_type, + resource_ulab_to_plr, + initialize_resources, + dict_to_tree, + resource_plr_to_ulab, + tree_to_list, +) from unilabos.ros.msgs.message_converter import ( convert_to_ros_msg, convert_from_ros_msg, convert_from_ros_msg_with_mapping, - convert_to_ros_msg_with_mapping, ros_action_to_json_schema, + convert_to_ros_msg_with_mapping, ) -from unilabos_msgs.srv import ResourceAdd, ResourceGet, ResourceDelete, ResourceUpdate, ResourceList, \ - SerialCommand # type: ignore +from unilabos_msgs.srv import ( + ResourceAdd, + ResourceGet, + ResourceDelete, + ResourceUpdate, + ResourceList, + SerialCommand, +) # type: ignore from unilabos_msgs.msg import Resource # type: ignore from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker @@ -37,7 +49,7 @@ from unilabos.ros.x.rclpyx import get_event_loop from unilabos.ros.utils.driver_creator import ProtocolNodeCreator, PyLabRobotCreator, DeviceClassCreator from unilabos.utils.async_util import run_async_func from unilabos.utils.log import info, debug, warning, error, critical, logger -from unilabos.utils.type_check import get_type_class, TypeEncoder +from unilabos.utils.type_check import get_type_class, TypeEncoder, serialize_result_info T = TypeVar("T") @@ -292,7 +304,9 @@ class BaseROS2DeviceNode(Node, Generic[T]): self.create_ros_action_server(action_name, action_value_mapping) # 创建线程池执行器 - self._executor = ThreadPoolExecutor(max_workers=max(len(action_value_mappings), 1), thread_name_prefix=f"ROSDevice{self.device_id}") + self._executor = ThreadPoolExecutor( + max_workers=max(len(action_value_mappings), 1), thread_name_prefix=f"ROSDevice{self.device_id}" + ) # 创建资源管理客户端 self._resource_clients: Dict[str, Client] = { @@ -334,7 +348,9 @@ class BaseROS2DeviceNode(Node, Generic[T]): other_calling_param["slot"] = slot # 本地拿到这个物料,可能需要先做初始化? if isinstance(resources, list): - if len(resources) == 1 and isinstance(resources[0], list) and not initialize_full: # 取消,不存在的情况 + if ( + len(resources) == 1 and isinstance(resources[0], list) and not initialize_full + ): # 取消,不存在的情况 # 预先initialize过,以整组的形式传入 request.resources = [convert_to_ros_msg(Resource, resource_) for resource_ in resources[0]] elif initialize_full: @@ -373,6 +389,7 @@ class BaseROS2DeviceNode(Node, Generic[T]): from pylabrobot.resources import Coordinate from pylabrobot.resources import OTDeck from pylabrobot.resources import Plate + contain_model = not isinstance(resource, Deck) if isinstance(resource, ResourcePLR): # resources.list() @@ -380,25 +397,38 @@ class BaseROS2DeviceNode(Node, Generic[T]): plr_instance = resource_ulab_to_plr(resources_tree[0], contain_model) if isinstance(plr_instance, Plate): empty_liquid_info_in = [(None, 0)] * plr_instance.num_items - for liquid_type, liquid_volume, liquid_input_slot in zip(ADD_LIQUID_TYPE, LIQUID_VOLUME, LIQUID_INPUT_SLOT): + for liquid_type, liquid_volume, liquid_input_slot in zip( + ADD_LIQUID_TYPE, LIQUID_VOLUME, LIQUID_INPUT_SLOT + ): empty_liquid_info_in[liquid_input_slot] = (liquid_type, liquid_volume) plr_instance.set_well_liquids(empty_liquid_info_in) if isinstance(resource, OTDeck) and "slot" in other_calling_param: resource.assign_child_at_slot(plr_instance, **other_calling_param) else: _discard_slot = other_calling_param.pop("slot", -1) - resource.assign_child_resource(plr_instance, Coordinate(location["x"], location["y"], location["z"]), **other_calling_param) - request2.resources = [convert_to_ros_msg(Resource, r) for r in tree_to_list([resource_plr_to_ulab(resource)])] + resource.assign_child_resource( + plr_instance, + Coordinate(location["x"], location["y"], location["z"]), + **other_calling_param, + ) + request2.resources = [ + convert_to_ros_msg(Resource, r) for r in tree_to_list([resource_plr_to_ulab(resource)]) + ] rclient2.call(request2) # 发送给ResourceMeshManager action_client = ActionClient( - self, SendCmd, "/devices/resource_mesh_manager/add_resource_mesh", callback_group=self.callback_group + self, + SendCmd, + "/devices/resource_mesh_manager/add_resource_mesh", + callback_group=self.callback_group, ) goal = SendCmd.Goal() - goal.command = json.dumps({ - "resources": resources, - "bind_parent_id": bind_parent_id, - }) + goal.command = json.dumps( + { + "resources": resources, + "bind_parent_id": bind_parent_id, + } + ) future = action_client.send_goal_async(goal, goal_uuid=uuid.uuid4()) def done_cb(*args): @@ -415,10 +445,16 @@ class BaseROS2DeviceNode(Node, Generic[T]): # noinspection PyTypeChecker self._service_server: Dict[str, Service] = { "query_host_name": self.create_service( - SerialCommand, f"/srv{self.namespace}/query_host_name", query_host_name_cb, callback_group=self.callback_group + SerialCommand, + f"/srv{self.namespace}/query_host_name", + query_host_name_cb, + callback_group=self.callback_group, ), "append_resource": self.create_service( - SerialCommand, f"/srv{self.namespace}/append_resource", append_resource, callback_group=self.callback_group + SerialCommand, + f"/srv{self.namespace}/append_resource", + append_resource, + callback_group=self.callback_group, ), } @@ -447,6 +483,7 @@ class BaseROS2DeviceNode(Node, Generic[T]): registered_devices[self.device_id] = device_info from unilabos.config.config import BasicConfig from unilabos.ros.nodes.presets.host_node import HostNode + if not BasicConfig.is_host_mode: sclient = self.create_client(SerialCommand, "/node_info_update") # 启动线程执行发送任务 @@ -454,7 +491,7 @@ class BaseROS2DeviceNode(Node, Generic[T]): target=self.send_slave_node_info, args=(sclient,), daemon=True, - name=f"ROSDevice{self.device_id}_send_slave_node_info" + name=f"ROSDevice{self.device_id}_send_slave_node_info", ).start() else: host_node = HostNode.get_instance(0) @@ -465,12 +502,18 @@ class BaseROS2DeviceNode(Node, Generic[T]): sclient.wait_for_service() request = SerialCommand.Request() from unilabos.config.config import BasicConfig - request.command = json.dumps({ - "SYNC_SLAVE_NODE_INFO": { - "machine_name": BasicConfig.machine_name, - "type": "slave", - "edge_device_id": self.device_id - }}, ensure_ascii=False, cls=TypeEncoder) + + request.command = json.dumps( + { + "SYNC_SLAVE_NODE_INFO": { + "machine_name": BasicConfig.machine_name, + "type": "slave", + "edge_device_id": self.device_id, + } + }, + ensure_ascii=False, + cls=TypeEncoder, + ) # 发送异步请求并等待结果 future = sclient.call_async(request) @@ -543,6 +586,11 @@ class BaseROS2DeviceNode(Node, Generic[T]): """创建动作执行回调函数""" async def execute_callback(goal_handle: ServerGoalHandle): + # 初始化结果信息变量 + execution_error = "" + execution_success = False + action_return_value = None + self.lab_logger().info(f"执行动作: {action_name}") goal = goal_handle.request @@ -582,7 +630,11 @@ class BaseROS2DeviceNode(Node, Generic[T]): current_resources.extend(response.resources) else: r = ResourceGet.Request() - r.id = action_kwargs[k]["id"] if v == "unilabos_msgs/Resource" else action_kwargs[k][0]["id"] + r.id = ( + action_kwargs[k]["id"] + if v == "unilabos_msgs/Resource" + else action_kwargs[k][0]["id"] + ) r.with_children = True response = await self._resource_clients["resource_get"].call_async(r) current_resources.extend(response.resources) @@ -605,7 +657,17 @@ class BaseROS2DeviceNode(Node, Generic[T]): if asyncio.iscoroutinefunction(ACTION): try: self.lab_logger().info(f"异步执行动作 {ACTION}") - future = ROS2DeviceNode.run_async_func(ACTION, **action_kwargs) + future = ROS2DeviceNode.run_async_func(ACTION, trace_error=False, **action_kwargs) + + def _handle_future_exception(fut): + try: + fut.result() + except Exception as e: + execution_error = traceback.format_exc() + error(f"异步任务 {ACTION.__name__} 报错了") + error(traceback.format_exc()) + + future.add_done_callback(_handle_future_exception) except Exception as e: self.lab_logger().error(f"创建异步任务失败: {traceback.format_exc()}") raise e @@ -617,6 +679,7 @@ class BaseROS2DeviceNode(Node, Generic[T]): try: fut.result() except Exception as e: + execution_error = traceback.format_exc() error(f"同步任务 {ACTION.__name__} 报错了") error(traceback.format_exc()) @@ -693,7 +756,9 @@ class BaseROS2DeviceNode(Node, Generic[T]): goal_handle.succeed() self.lab_logger().info(f"设置动作成功: {action_name}") - result_values = {} + result_values = { + "return_value": serialize_result_info(execution_error, execution_success, action_return_value) + } for msg_name, attr_name in action_value_mapping["result"].items(): if hasattr(self.driver_instance, f"get_{attr_name}"): result_values[msg_name] = getattr(self.driver_instance, f"get_{attr_name}")() @@ -752,8 +817,8 @@ class ROS2DeviceNode: return cls._loop @classmethod - def run_async_func(cls, func, **kwargs): - return run_async_func(func, loop=cls._loop, **kwargs) + def run_async_func(cls, func, trace_error=True, **kwargs): + return run_async_func(func, loop=cls._loop, trace_error=trace_error, **kwargs) @property def driver_instance(self): @@ -805,9 +870,11 @@ class ROS2DeviceNode: self.resource_tracker = DeviceNodeResourceTracker() # use_pylabrobot_creator 使用 cls的包路径检测 - use_pylabrobot_creator = (driver_class.__module__.startswith("pylabrobot") - or driver_class.__name__ == "LiquidHandlerAbstract" - or driver_class.__name__ == "LiquidHandlerBiomek") + use_pylabrobot_creator = ( + driver_class.__module__.startswith("pylabrobot") + or driver_class.__name__ == "LiquidHandlerAbstract" + or driver_class.__name__ == "LiquidHandlerBiomek" + ) # TODO: 要在创建之前预先请求服务器是否有当前id的物料,放到resource_tracker中,让pylabrobot进行创建 # 创建设备类实例 diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index f4284629..ece98857 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -151,7 +151,7 @@ class HostNode(BaseROS2DeviceNode): mqtt_client.publish_registry(device_info["id"], device_info) for resource_info in lab_registry.obtain_registry_resource_info(): mqtt_client.publish_registry(resource_info["id"], resource_info) - + time.sleep(1) # 等待MQTT连接稳定 # 首次发现网络中的设备 self._discover_devices() @@ -204,9 +204,11 @@ class HostNode(BaseROS2DeviceNode): for bridge in self.bridges: if hasattr(bridge, "resource_add"): resource_start_time = time.time() - resource_add_res = bridge.resource_add(add_schema(resource_with_parent_name)) + resource_add_res = bridge.resource_add(add_schema(resource_with_parent_name), True) resource_end_time = time.time() - self.lab_logger().info(f"[Host Node-Resource] Adding resources to bridge. {round(resource_start_time - resource_end_time, 5)} seconds") + self.lab_logger().info( + f"[Host Node-Resource] 物料上传 {round(resource_end_time - resource_start_time, 5) * 1000} ms" + ) except Exception as ex: self.lab_logger().error("[Host Node-Resource] 添加物料出错!") self.lab_logger().error(traceback.format_exc()) @@ -610,6 +612,8 @@ class HostNode(BaseROS2DeviceNode): def get_result_callback(self, action_id: str, uuid_str: Optional[str], future) -> None: """获取结果回调""" + import json + result_msg = future.result().result result_data = convert_from_ros_msg(result_msg) self.lab_logger().info(f"[Host Node] Result for {action_id} ({uuid_str}): success") @@ -618,7 +622,7 @@ class HostNode(BaseROS2DeviceNode): if uuid_str: for bridge in self.bridges: if hasattr(bridge, "publish_job_status"): - bridge.publish_job_status(result_data, uuid_str, "success") + bridge.publish_job_status(result_data, uuid_str, "success", result_data) def cancel_goal(self, goal_uuid: str) -> None: """取消目标""" diff --git a/unilabos/utils/async_util.py b/unilabos/utils/async_util.py index ce97f5a1..0f50a730 100644 --- a/unilabos/utils/async_util.py +++ b/unilabos/utils/async_util.py @@ -5,7 +5,7 @@ from asyncio import get_event_loop from unilabos.utils.log import error -def run_async_func(func, *, loop=None, **kwargs): +def run_async_func(func, *, loop=None, trace_error=True, **kwargs): if loop is None: loop = get_event_loop() @@ -17,5 +17,6 @@ def run_async_func(func, *, loop=None, **kwargs): error(traceback.format_exc()) future = asyncio.run_coroutine_threadsafe(func(**kwargs), loop) - future.add_done_callback(_handle_future_exception) - return future \ No newline at end of file + if trace_error: + future.add_done_callback(_handle_future_exception) + return future diff --git a/unilabos/utils/type_check.py b/unilabos/utils/type_check.py index 7366652b..578eb93d 100644 --- a/unilabos/utils/type_check.py +++ b/unilabos/utils/type_check.py @@ -1,4 +1,4 @@ -import collections +import collections.abc import json from typing import get_origin, get_args @@ -21,3 +21,46 @@ class TypeEncoder(json.JSONEncoder): return str(obj)[8:-2] return super().default(obj) + +class ResultInfoEncoder(json.JSONEncoder): + """专门用于处理任务执行结果信息的JSON编码器""" + + def default(self, obj): + # 优先处理类型对象 + if isinstance(obj, type): + return str(obj)[8:-2] + + # 对于无法序列化的对象,统一转换为字符串 + try: + # 尝试调用 __dict__ 或者其他序列化方法 + if hasattr(obj, "__dict__"): + return obj.__dict__ + elif hasattr(obj, "_asdict"): # namedtuple + return obj._asdict() + elif hasattr(obj, "to_dict"): + return obj.to_dict() + elif hasattr(obj, "dict"): + return obj.dict() + else: + # 如果都不行,转换为字符串 + return str(obj) + except Exception: + # 如果转换失败,直接返回字符串表示 + return str(obj) + + +def serialize_result_info(error: str, suc: bool, return_value=None) -> str: + """ + 序列化任务执行结果信息 + + Args: + error: 错误信息字符串 + suc: 是否成功的布尔值 + return_value: 返回值,可以是任何类型 + + Returns: + JSON字符串格式的结果信息 + """ + result_info = {"error": error, "suc": suc, "return_value": return_value} + + return json.dumps(result_info, ensure_ascii=False, cls=ResultInfoEncoder) From 6a14104e6b19af3fcf7a59307a0c16f327995300 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sun, 8 Jun 2025 15:06:38 +0800 Subject: [PATCH 37/44] =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E5=8F=91=E9=80=81retur?= =?UTF-8?q?n=5Finfo=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/app/mq.py | 4 ++-- unilabos/ros/nodes/base_device_node.py | 6 +++--- unilabos/ros/nodes/presets/host_node.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/unilabos/app/mq.py b/unilabos/app/mq.py index 36bc0337..dbaa57cd 100644 --- a/unilabos/app/mq.py +++ b/unilabos/app/mq.py @@ -164,11 +164,11 @@ class MQTTClient: self.client.publish(address, json.dumps(status), qos=2) logger.critical(f"Device status published: address: {address}, {status}") - def publish_job_status(self, feedback_data: dict, job_id: str, status: str, return_info: Optional[dict] = None): + def publish_job_status(self, feedback_data: dict, job_id: str, status: str, return_info: Optional[str] = None): if self.mqtt_disable: return if return_info is None: - return_info = {} + return_info = "{}" jobdata = {"job_id": job_id, "data": feedback_data, "status": status, "return_info": return_info} self.client.publish(f"labs/{MQConfig.lab_id}/job/list/", json.dumps(jobdata), qos=2) diff --git a/unilabos/ros/nodes/base_device_node.py b/unilabos/ros/nodes/base_device_node.py index e75413f1..95e3f0c7 100644 --- a/unilabos/ros/nodes/base_device_node.py +++ b/unilabos/ros/nodes/base_device_node.py @@ -756,9 +756,7 @@ class BaseROS2DeviceNode(Node, Generic[T]): goal_handle.succeed() self.lab_logger().info(f"设置动作成功: {action_name}") - result_values = { - "return_value": serialize_result_info(execution_error, execution_success, action_return_value) - } + result_values = {} for msg_name, attr_name in action_value_mapping["result"].items(): if hasattr(self.driver_instance, f"get_{attr_name}"): result_values[msg_name] = getattr(self.driver_instance, f"get_{attr_name}")() @@ -772,6 +770,8 @@ class BaseROS2DeviceNode(Node, Generic[T]): for attr_name in result_msg_types.keys(): if attr_name in ["success", "reached_goal"]: setattr(result_msg, attr_name, True) + elif attr_name == "return_info": + setattr(result_msg, attr_name, serialize_result_info(execution_error, execution_success, action_return_value)) self.lab_logger().info(f"动作 {action_name} 完成并返回结果") return result_msg diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index ece98857..91a9fa5a 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -622,7 +622,7 @@ class HostNode(BaseROS2DeviceNode): if uuid_str: for bridge in self.bridges: if hasattr(bridge, "publish_job_status"): - bridge.publish_job_status(result_data, uuid_str, "success", result_data) + bridge.publish_job_status(result_data, uuid_str, "success", result_data.get("return_info", "{}")) def cancel_goal(self, goal_uuid: str) -> None: """取消目标""" From aaa86314e376d75e6d137190d87b48fb60f67ee4 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sun, 8 Jun 2025 15:34:16 +0800 Subject: [PATCH 38/44] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/ros/nodes/base_device_node.py | 8 ++++++-- unilabos/ros/nodes/presets/host_node.py | 13 ++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/unilabos/ros/nodes/base_device_node.py b/unilabos/ros/nodes/base_device_node.py index 95e3f0c7..67cdb6f9 100644 --- a/unilabos/ros/nodes/base_device_node.py +++ b/unilabos/ros/nodes/base_device_node.py @@ -660,8 +660,10 @@ class BaseROS2DeviceNode(Node, Generic[T]): future = ROS2DeviceNode.run_async_func(ACTION, trace_error=False, **action_kwargs) def _handle_future_exception(fut): + nonlocal execution_error, execution_success, action_return_value try: - fut.result() + action_return_value = fut.result() + execution_success = True except Exception as e: execution_error = traceback.format_exc() error(f"异步任务 {ACTION.__name__} 报错了") @@ -676,8 +678,10 @@ class BaseROS2DeviceNode(Node, Generic[T]): future = self._executor.submit(ACTION, **action_kwargs) def _handle_future_exception(fut): + nonlocal execution_error, execution_success, action_return_value try: - fut.result() + action_return_value = fut.result() + execution_success = True except Exception as e: execution_error = traceback.format_exc() error(f"同步任务 {ACTION.__name__} 报错了") diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index 91a9fa5a..be9c9779 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -612,17 +612,23 @@ class HostNode(BaseROS2DeviceNode): def get_result_callback(self, action_id: str, uuid_str: Optional[str], future) -> None: """获取结果回调""" - import json - result_msg = future.result().result result_data = convert_from_ros_msg(result_msg) + status = "success" + try: + ret = json.loads(result_data.get("return_info", "{}")) # 确保返回信息是有效的JSON + suc = ret.get("suc", False) + if not suc: + status = "failed" + except json.JSONDecodeError: + status = "failed" self.lab_logger().info(f"[Host Node] Result for {action_id} ({uuid_str}): success") self.lab_logger().debug(f"[Host Node] Result data: {result_data}") if uuid_str: for bridge in self.bridges: if hasattr(bridge, "publish_job_status"): - bridge.publish_job_status(result_data, uuid_str, "success", result_data.get("return_info", "{}")) + bridge.publish_job_status(result_data, uuid_str, status, result_data.get("return_info", "{}")) def cancel_goal(self, goal_uuid: str) -> None: """取消目标""" @@ -862,6 +868,7 @@ class HostNode(BaseROS2DeviceNode): 测试网络延迟的action实现 通过5次ping-pong机制校对时间误差并计算实际延迟 """ + raise ValueError("test") import time import uuid as uuid_module From 526327727d566ae1bce7773264618e82c5ab5043 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sun, 8 Jun 2025 15:34:56 +0800 Subject: [PATCH 39/44] =?UTF-8?q?=E5=8F=96=E6=B6=88raiseValueError?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/ros/nodes/presets/host_node.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index be9c9779..a869b13d 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -868,8 +868,6 @@ class HostNode(BaseROS2DeviceNode): 测试网络延迟的action实现 通过5次ping-pong机制校对时间误差并计算实际延迟 """ - raise ValueError("test") - import time import uuid as uuid_module self.lab_logger().info("=" * 60) From 9b3377aedb68822a06dab0a751c6db4db908d03f Mon Sep 17 00:00:00 2001 From: qxw138 Date: Sun, 8 Jun 2025 15:52:20 +0800 Subject: [PATCH 40/44] Update biomek_test.py --- .../devices/liquid_handling/biomek_test.py | 888 +++++++++--------- 1 file changed, 442 insertions(+), 446 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 185d47b5..25e669d0 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -276,14 +276,14 @@ class LiquidHandlerBiomek: "Class": f"LabwareClasses\\{class_name}", "DataSets": {"Volume": {}}, "RuntimeDataSets": {"Volume": {}}, - "EvalAmounts": (float(liquid_volume[0]),) if liquid_volume else (0.0,), + "EvalAmounts": (float(liquid_volume[0]),) if liquid_volume else (0,), "Nominal": False, "EvalLiquids": (liquid_type[0],) if liquid_type else ("Water",) } elif instrument_type == "plate_96": # 96孔板类型配置 - volume_per_well = float(liquid_volume[0]) if liquid_volume else 500.0 + volume_per_well = float(liquid_volume[0]) if liquid_volume else 0 liquid_per_well = liquid_type[0] if liquid_type else "Water" config = { @@ -473,452 +473,448 @@ if __name__ == "__main__": print("包含: 仪器设置 + 完整实验步骤") # 完整的步骤信息(从biomek.py复制) - steps_info = ''' + steps_info = { + "steps": [ { - "steps": [ - { - "step_number": 1, - "operation": "transfer", - "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", - "parameters": { - "source": "P1", - "target": "P11", - "tip_rack": "BC230", - "volume": 50 - } - }, - { - "step_number": 2, - "operation": "transfer", - "description": "加入2倍体积Bind Beads BC至产物中", - "parameters": { - "source": "P2", - "target": "P11", - "tip_rack": "BC230", - "volume": 100 - } - }, - { - "step_number": 3, - "operation": "move_labware", - "description": "移动P11至Orbital1用于振荡混匀", - "parameters": { - "source": "P11", - "target": "Orbital1" - } - }, - { - "step_number": 4, - "operation": "oscillation", - "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", - "parameters": { - "rpm": 800, - "time": 300 - } - }, - { - "step_number": 5, - "operation": "move_labware", - "description": "移动混匀后的板回P11", - "parameters": { - "source": "Orbital1", - "target": "P11" - } - }, - { - "step_number": 6, - "operation": "move_labware", - "description": "将P11移动到磁力架(P12)吸附3分钟", - "parameters": { - "source": "P11", - "target": "P12" - } - }, - { - "step_number": 7, - "operation": "incubation", - "description": "磁力架上室温静置3分钟完成吸附", - "parameters": { - "time": 180 - } - }, - { - "step_number": 8, - "operation": "transfer", - "description": "去除上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 150 - } - }, - { - "step_number": 9, - "operation": "transfer", - "description": "加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 10, - "operation": "move_labware", - "description": "移动清洗板到Orbital1进行振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 11, - "operation": "oscillation", - "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 12, - "operation": "move_labware", - "description": "振荡后将板移回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 13, - "operation": "incubation", - "description": "吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 14, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 15, - "operation": "transfer", - "description": "第二次加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 16, - "operation": "move_labware", - "description": "再次移动清洗板到Orbital1振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 17, - "operation": "oscillation", - "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 18, - "operation": "move_labware", - "description": "振荡后板送回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 19, - "operation": "incubation", - "description": "再次吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 20, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 21, - "operation": "incubation", - "description": "空气干燥15分钟", - "parameters": { - "time": 900 - } - }, - { - "step_number": 22, - "operation": "transfer", - "description": "加30-50μl Elution Buffer洗脱", - "parameters": { - "source": "P4", - "target": "P12", - "tip_rack": "BC230", - "volume": 40 - } - }, - { - "step_number": 23, - "operation": "move_labware", - "description": "移动到Orbital1振荡混匀(60秒)", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 24, - "operation": "oscillation", - "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", - "parameters": { - "rpm": 800, - "time": 60 - } - }, - { - "step_number": 25, - "operation": "move_labware", - "description": "振荡后送回磁力架P12", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 26, - "operation": "incubation", - "description": "室温静置3分钟(洗脱反应)", - "parameters": { - "time": 180 - } - }, - { - "step_number": 27, - "operation": "transfer", - "description": "将上清液(DNA)转移到新板(P13)", - "parameters": { - "source": "P12", - "target": "P13", - "tip_rack": "BC230", - "volume": 40 - } - } - ] + "step_number": 1, + "operation": "transfer", + "description": "转移PCR产物或酶促反应液至0.5ml 96孔板中", + "parameters": { + "source": "P1", + "target": "P11", + "tip_rack": "BC230", + "volume": 50 + } + }, + { + "step_number": 2, + "operation": "transfer", + "description": "加入2倍体积的Bind Beads BC至产物中", + "parameters": { + "source": "P2", + "target": "P11", + "tip_rack": "BC230", + "volume": 100 + } + }, + { + "step_number": 3, + "operation": "oscillation", + "description": "振荡混匀300秒", + "parameters": { + "rpm": 800, + "time": 300 + } + }, + { + "step_number": 4, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附3分钟", + "parameters": { + "source": "P11", + "target": "P12" + } + }, + { + "step_number": 5, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 6, + "operation": "transfer", + "description": "吸弃或倒除上清液", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 150 + } + }, + { + "step_number": 7, + "operation": "transfer", + "description": "加入300-500μl 75%乙醇", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 8, + "operation": "move_labware", + "description": "移动至振荡器进行振荡混匀", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 9, + "operation": "oscillation", + "description": "振荡混匀60秒", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 10, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附3分钟", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 11, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 12, + "operation": "transfer", + "description": "吸弃或倒弃废液", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 13, + "operation": "transfer", + "description": "重复加入75%乙醇", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 14, + "operation": "move_labware", + "description": "移动至振荡器进行振荡混匀", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 15, + "operation": "oscillation", + "description": "振荡混匀60秒", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 16, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附3分钟", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 17, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 18, + "operation": "transfer", + "description": "吸弃或倒弃废液", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 19, + "operation": "move_labware", + "description": "正放96孔板,空气干燥15分钟", + "parameters": { + "source": "P12", + "target": "P13" + } + }, + { + "step_number": 20, + "operation": "incubation", + "description": "空气干燥15分钟", + "parameters": { + "time": 900 + } + }, + { + "step_number": 21, + "operation": "transfer", + "description": "加入30-50μl Elution Buffer", + "parameters": { + "source": "P4", + "target": "P13", + "tip_rack": "BC230", + "volume": 40 + } + }, + { + "step_number": 22, + "operation": "move_labware", + "description": "移动至振荡器进行振荡混匀", + "parameters": { + "source": "P13", + "target": "Orbital1" + } + }, + { + "step_number": 23, + "operation": "oscillation", + "description": "振荡混匀60秒", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 24, + "operation": "move_labware", + "description": "室温静置3分钟", + "parameters": { + "source": "Orbital1", + "target": "P13" + } + }, + { + "step_number": 25, + "operation": "incubation", + "description": "室温静置3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 26, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附2分钟", + "parameters": { + "source": "P13", + "target": "P12" + } + }, + { + "step_number": 27, + "operation": "incubation", + "description": "吸附2分钟", + "parameters": { + "time": 120 + } + }, + { + "step_number": 28, + "operation": "transfer", + "description": "将DNA转移至新的板中", + "parameters": { + "source": "P12", + "target": "P14", + "tip_rack": "BC230", + "volume": 40 + } } - ''' - - # 完整的labware配置信息(从biomek.py复制) - labware_with_liquid = ''' - [ - { - "id": "Tip Rack BC230 on TL1", - "parent": "deck", - "slot_on_deck": "TL1", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL2", - "parent": "deck", - "slot_on_deck": "TL2", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL3", - "parent": "deck", - "slot_on_deck": "TL3", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL4", - "parent": "deck", - "slot_on_deck": "TL4", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL5", - "parent": "deck", - "slot_on_deck": "TL5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P5", - "parent": "deck", - "slot_on_deck": "P5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P6", - "parent": "deck", - "slot_on_deck": "P6", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P15", - "parent": "deck", - "slot_on_deck": "P15", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P16", - "parent": "deck", - "slot_on_deck": "P16", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "stock plate on P1", - "parent": "deck", - "slot_on_deck": "P1", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "master_mix" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P2", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P3", - "parent": "deck", - "slot_on_deck": "P3", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "ethyl alcohol" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "elution buffer on P4", - "parent": "deck", - "slot_on_deck": "P4", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "elution buffer" - ], - "liquid_volume": [5000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "oscillation", - "parent": "deck", - "slot_on_deck": "Orbital1", - "class_name": "Orbital", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "working plate on P11", - "parent": "deck", - "slot_on_deck": "P11", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "magnetics module on P12", - "parent": "deck", - "slot_on_deck": "P12", - "class_name": "magnetics module", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "working plate on P13", - "parent": "deck", - "slot_on_deck": "P13", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "waste on P22", - "parent": "deck", - "slot_on_deck": "P22", - "class_name": "nest_1_reservoir_195ml", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - } - ] - ''' + ] +} + # 完整的labware配置信息 + labware_with_liquid = [ + { + "id": "Tip Rack BC230 TL1", + "parent": "deck", + "slot_on_deck": "TL1", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P15", + "parent": "deck", + "slot_on_deck": "P15", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "stock plate on P1", + "parent": "deck", + "slot_on_deck": "P1", + "class_name": "AgilentReservoir", + "liquid_type": ["PCR product"], + "liquid_volume": [5000], + "liquid_input_wells": ["A1"] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "AgilentReservoir", + "liquid_type": ["bind beads"], + "liquid_volume": [100000], + "liquid_input_wells": ["A1"] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "AgilentReservoir", + "liquid_type": ["75% ethanol"], + "liquid_volume": [100000], + "liquid_input_wells": ["A1"] + }, + { + "id": "stock plate on P4", + "parent": "deck", + "slot_on_deck": "P4", + "class_name": "AgilentReservoir", + "liquid_type": ["Elution Buffer"], + "liquid_volume": [5000], + "liquid_input_wells": ["A1"] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P14", + "parent": "deck", + "slot_on_deck": "P14", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "AgilentReservoir", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + } +] # 创建handler实例 handler = LiquidHandlerBiomek() From 6577fe12eb4dcb163eca0f251aa6260c32ad339a Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Sun, 8 Jun 2025 16:49:11 +0800 Subject: [PATCH 41/44] 0608 DONE --- .../devices/liquid_handling/biomek_test.py | 18 +- ...son => complete_biomek_protocol_0608.json} | 3479 ++++++++++------- 2 files changed, 1970 insertions(+), 1527 deletions(-) rename unilabos/devices/liquid_handling/{complete_biomek_protocol_0607.json => complete_biomek_protocol_0608.json} (87%) diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index 25e669d0..e3865983 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -473,7 +473,8 @@ if __name__ == "__main__": print("包含: 仪器设置 + 完整实验步骤") # 完整的步骤信息(从biomek.py复制) - steps_info = { + steps_info = ''' + { "steps": [ { "step_number": 1, @@ -737,12 +738,14 @@ if __name__ == "__main__": "target": "P14", "tip_rack": "BC230", "volume": 40 - } + } + } + ] } - ] -} +''' # 完整的labware配置信息 - labware_with_liquid = [ + labware_with_liquid = ''' + [ { "id": "Tip Rack BC230 TL1", "parent": "deck", @@ -914,7 +917,8 @@ if __name__ == "__main__": "liquid_volume": [], "liquid_input_wells": [] } -] + ] + ''' # 创建handler实例 handler = LiquidHandlerBiomek() @@ -996,7 +1000,7 @@ if __name__ == "__main__": script_dir = pathlib.Path(__file__).parent # 保存完整协议 - complete_output_path = script_dir / "complete_biomek_protocol_0607.json" + complete_output_path = script_dir / "complete_biomek_protocol_0608.json" with open(complete_output_path, 'w', encoding='utf-8') as f: json.dump(handler.temp_protocol, f, indent=4, ensure_ascii=False) diff --git a/unilabos/devices/liquid_handling/complete_biomek_protocol_0607.json b/unilabos/devices/liquid_handling/complete_biomek_protocol_0608.json similarity index 87% rename from unilabos/devices/liquid_handling/complete_biomek_protocol_0607.json rename to unilabos/devices/liquid_handling/complete_biomek_protocol_0608.json index be73033c..24b3d455 100644 --- a/unilabos/devices/liquid_handling/complete_biomek_protocol_0607.json +++ b/unilabos/devices/liquid_handling/complete_biomek_protocol_0608.json @@ -328,12 +328,12 @@ "Properties": { "Name": "stock plate on P1", "Device": "", - "liquidtype": "master_mix", + "liquidtype": "PCR product", "BarCode": "", "SenseEveryTime": false }, "Known": true, - "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "Class": "LabwareClasses\\AgilentReservoir", "DataSets": { "Volume": {} }, @@ -341,11 +341,11 @@ "Volume": {} }, "EvalAmounts": [ - 10000.0 + 5000.0 ], "Nominal": false, "EvalLiquids": [ - "master_mix" + "PCR product" ] } ], @@ -359,7 +359,7 @@ "SenseEveryTime": false }, "Known": true, - "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "Class": "LabwareClasses\\AgilentReservoir", "DataSets": { "Volume": {} }, @@ -367,7 +367,7 @@ "Volume": {} }, "EvalAmounts": [ - 10000.0 + 100000.0 ], "Nominal": false, "EvalLiquids": [ @@ -380,12 +380,12 @@ "Properties": { "Name": "stock plate on P3", "Device": "", - "liquidtype": "ethyl alcohol", + "liquidtype": "75% ethanol", "BarCode": "", "SenseEveryTime": false }, "Known": true, - "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "Class": "LabwareClasses\\AgilentReservoir", "DataSets": { "Volume": {} }, @@ -393,25 +393,25 @@ "Volume": {} }, "EvalAmounts": [ - 10000.0 + 100000.0 ], "Nominal": false, "EvalLiquids": [ - "ethyl alcohol" + "75% ethanol" ] } ], "P4": [ { "Properties": { - "Name": "elution buffer on P4", + "Name": "stock plate on P4", "Device": "", - "liquidtype": "elution buffer", + "liquidtype": "Elution Buffer", "BarCode": "", "SenseEveryTime": false }, "Known": true, - "Class": "LabwareClasses\\nest_12_reservoir_15ml", + "Class": "LabwareClasses\\AgilentReservoir", "DataSets": { "Volume": {} }, @@ -423,11 +423,10 @@ ], "Nominal": false, "EvalLiquids": [ - "elution buffer" + "Elution Buffer" ] } ], - "Orbital1": [], "P11": [ { "Properties": { @@ -438,7 +437,7 @@ "SenseEveryTime": false }, "Known": true, - "Class": "LabwareClasses\\NEST 2ml Deep Well Plate", + "Class": "LabwareClasses\\BCDeep96Round", "DataSets": { "Volume": {} }, @@ -446,102 +445,318 @@ "Volume": {} }, "EvalAmounts": [ - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water" + ] + } + ], + "P12": [ + { + "Properties": { + "Name": "working plate on P12", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\BCDeep96Round", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 ], "Nominal": false, "EvalLiquids": [ @@ -644,7 +859,6 @@ ] } ], - "P12": [], "P13": [ { "Properties": { @@ -655,7 +869,7 @@ "SenseEveryTime": false }, "Known": true, - "Class": "LabwareClasses\\NEST 2ml Deep Well Plate", + "Class": "LabwareClasses\\BCDeep96Round", "DataSets": { "Volume": {} }, @@ -663,102 +877,318 @@ "Volume": {} }, "EvalAmounts": [ - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0, - 500.0 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "Nominal": false, + "EvalLiquids": [ + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water", + "Water" + ] + } + ], + "P14": [ + { + "Properties": { + "Name": "working plate on P14", + "Device": "", + "liquidtype": "Water", + "BarCode": "", + "SenseEveryTime": false + }, + "Known": true, + "Class": "LabwareClasses\\BCDeep96Round", + "DataSets": { + "Volume": {} + }, + "RuntimeDataSets": { + "Volume": {} + }, + "EvalAmounts": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 ], "Nominal": false, "EvalLiquids": [ @@ -871,7 +1301,7 @@ "SenseEveryTime": false }, "Known": true, - "Class": "LabwareClasses\\nest_1_reservoir_195ml", + "Class": "LabwareClasses\\AgilentReservoir", "DataSets": { "Volume": {} }, @@ -879,14 +1309,15 @@ "Volume": {} }, "EvalAmounts": [ - 0.0 + 0 ], "Nominal": false, "EvalLiquids": [ "Water" ] } - ] + ], + "Orbital1": [] }, "steps": [ { @@ -1020,7 +1451,7 @@ "UseExpression": false }, { - "Position": "P13", + "Position": "P14", "Height": -2.0, "Volume": "40", "liquidtype": "Tip Contents", @@ -1320,7 +1751,7 @@ "UseExpression": false }, { - "Position": "P13", + "Position": "P14", "Height": -2.0, "Volume": "40", "liquidtype": "Tip Contents", @@ -1489,15 +1920,6 @@ "Wizard": false } }, - { - "move": { - "Pod": "Pod1", - "GripSide": "A1 near", - "Source": "P11", - "Target": "Orbital1", - "LeaveBottomLabware": false - } - }, { "oscillation": { "Device": "OrbitalShaker0", @@ -1510,15 +1932,6 @@ "Command": "Timed Shake" } }, - { - "move": { - "Pod": "Pod1", - "GripSide": "A1 near", - "Source": "Orbital1", - "Target": "P11", - "LeaveBottomLabware": false - } - }, { "move": { "Pod": "Pod1", @@ -1667,7 +2080,7 @@ "UseExpression": false }, { - "Position": "P13", + "Position": "P14", "Height": -2.0, "Volume": "40", "liquidtype": "Tip Contents", @@ -1967,1291 +2380,7 @@ "UseExpression": false }, { - "Position": "P13", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Tip Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Dispense", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": false, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - } - ], - "Wash": false, - "Dynamic?": true, - "AutoSelectActiveWashTechnique": false, - "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": true, - "ChangeTipsBetweenSources": false, - "DefaultCaption": "", - "UseExpression": false, - "LeaveTipsOn": false, - "MandrelExpression": "", - "Repeats": "1", - "RepeatsByVolume": false, - "Replicates": "1", - "ShowTipHandlingDetails": false, - "ShowTransferDetails": true, - "Solvent": "Water", - "Span8Wash": false, - "Span8WashVolume": "2", - "Span8WasteVolume": "1", - "SplitVolume": false, - "SplitVolumeCleaning": false, - "Stop": "Destinations", - "TipLocation": "BC230", - "UseCurrentTips": false, - "UseDisposableTips": false, - "UseFixedTips": false, - "UseJIT": true, - "UseMandrelSelection": true, - "UseProbes": [ - true, - true, - true, - true, - true, - true, - true, - true - ], - "WashCycles": "4", - "WashVolume": "110%", - "Wizard": false - } - }, - { - "move": { - "Pod": "Pod1", - "GripSide": "A1 near", - "Source": "P12", - "Target": "Orbital1", - "LeaveBottomLabware": false - } - }, - { - "oscillation": { - "Device": "OrbitalShaker0", - "Parameters": [ - "800", - "2", - "45", - "CounterClockwise" - ], - "Command": "Timed Shake" - } - }, - { - "move": { - "Pod": "Pod1", - "GripSide": "A1 near", - "Source": "Orbital1", - "Target": "P12", - "LeaveBottomLabware": false - } - }, - { - "incubation": { - "Message": "Paused", - "Location": "the whole system", - "Time": 180, - "Mode": "TimedResource" - } - }, - { - "transfer": { - "Span8": false, - "Pod": "Pod1", - "items": [ - { - "Position": "P12", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Well Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Aspirate", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": true, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - }, - { - "Position": "P13", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Tip Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Dispense", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": false, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - } - ], - "Wash": false, - "Dynamic?": true, - "AutoSelectActiveWashTechnique": false, - "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": true, - "ChangeTipsBetweenSources": false, - "DefaultCaption": "", - "UseExpression": false, - "LeaveTipsOn": false, - "MandrelExpression": "", - "Repeats": "1", - "RepeatsByVolume": false, - "Replicates": "1", - "ShowTipHandlingDetails": false, - "ShowTransferDetails": true, - "Solvent": "Water", - "Span8Wash": false, - "Span8WashVolume": "2", - "Span8WasteVolume": "1", - "SplitVolume": false, - "SplitVolumeCleaning": false, - "Stop": "Destinations", - "TipLocation": "BC230", - "UseCurrentTips": false, - "UseDisposableTips": false, - "UseFixedTips": false, - "UseJIT": true, - "UseMandrelSelection": true, - "UseProbes": [ - true, - true, - true, - true, - true, - true, - true, - true - ], - "WashCycles": "4", - "WashVolume": "110%", - "Wizard": false - } - }, - { - "transfer": { - "Span8": false, - "Pod": "Pod1", - "items": [ - { - "Position": "P12", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Well Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Aspirate", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": true, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - }, - { - "Position": "P13", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Tip Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Dispense", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": false, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - } - ], - "Wash": false, - "Dynamic?": true, - "AutoSelectActiveWashTechnique": false, - "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": true, - "ChangeTipsBetweenSources": false, - "DefaultCaption": "", - "UseExpression": false, - "LeaveTipsOn": false, - "MandrelExpression": "", - "Repeats": "1", - "RepeatsByVolume": false, - "Replicates": "1", - "ShowTipHandlingDetails": false, - "ShowTransferDetails": true, - "Solvent": "Water", - "Span8Wash": false, - "Span8WashVolume": "2", - "Span8WasteVolume": "1", - "SplitVolume": false, - "SplitVolumeCleaning": false, - "Stop": "Destinations", - "TipLocation": "BC230", - "UseCurrentTips": false, - "UseDisposableTips": false, - "UseFixedTips": false, - "UseJIT": true, - "UseMandrelSelection": true, - "UseProbes": [ - true, - true, - true, - true, - true, - true, - true, - true - ], - "WashCycles": "4", - "WashVolume": "110%", - "Wizard": false - } - }, - { - "move": { - "Pod": "Pod1", - "GripSide": "A1 near", - "Source": "P12", - "Target": "Orbital1", - "LeaveBottomLabware": false - } - }, - { - "oscillation": { - "Device": "OrbitalShaker0", - "Parameters": [ - "800", - "2", - "45", - "CounterClockwise" - ], - "Command": "Timed Shake" - } - }, - { - "move": { - "Pod": "Pod1", - "GripSide": "A1 near", - "Source": "Orbital1", - "Target": "P12", - "LeaveBottomLabware": false - } - }, - { - "incubation": { - "Message": "Paused", - "Location": "the whole system", - "Time": 180, - "Mode": "TimedResource" - } - }, - { - "transfer": { - "Span8": false, - "Pod": "Pod1", - "items": [ - { - "Position": "P12", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Well Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Aspirate", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": true, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - }, - { - "Position": "P13", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Tip Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Dispense", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": false, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - } - ], - "Wash": false, - "Dynamic?": true, - "AutoSelectActiveWashTechnique": false, - "ActiveWashTechnique": "", - "ChangeTipsBetweenDests": true, - "ChangeTipsBetweenSources": false, - "DefaultCaption": "", - "UseExpression": false, - "LeaveTipsOn": false, - "MandrelExpression": "", - "Repeats": "1", - "RepeatsByVolume": false, - "Replicates": "1", - "ShowTipHandlingDetails": false, - "ShowTransferDetails": true, - "Solvent": "Water", - "Span8Wash": false, - "Span8WashVolume": "2", - "Span8WasteVolume": "1", - "SplitVolume": false, - "SplitVolumeCleaning": false, - "Stop": "Destinations", - "TipLocation": "BC230", - "UseCurrentTips": false, - "UseDisposableTips": false, - "UseFixedTips": false, - "UseJIT": true, - "UseMandrelSelection": true, - "UseProbes": [ - true, - true, - true, - true, - true, - true, - true, - true - ], - "WashCycles": "4", - "WashVolume": "110%", - "Wizard": false - } - }, - { - "incubation": { - "Message": "Paused", - "Location": "the whole system", - "Time": 900, - "Mode": "TimedResource" - } - }, - { - "transfer": { - "Span8": false, - "Pod": "Pod1", - "items": [ - { - "Position": "P12", - "Height": -2.0, - "Volume": "40", - "liquidtype": "Well Contents", - "WellsX": 12, - "LabwareClass": "Matrix96_750uL", - "AutoSelectPrototype": true, - "ColsFirst": true, - "CustomHeight": false, - "DataSetPattern": false, - "HeightFrom": 0, - "LocalPattern": true, - "Operation": "Aspirate", - "OverrideHeight": false, - "Pattern": [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - "Prototype": "MC P300 High", - "ReferencedPattern": "", - "RowsFirst": false, - "SectionExpression": "", - "SelectionInfo": [ - 1 - ], - "SetMark": true, - "Source": true, - "StartAtMark": false, - "StartAtSelection": true, - "UseExpression": false - }, - { - "Position": "P13", + "Position": "P14", "Height": -2.0, "Volume": "40", "liquidtype": "Tip Contents", @@ -3589,7 +2718,1317 @@ "UseExpression": false }, { - "Position": "P13", + "Position": "P14", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P14", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "60", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P14", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P12", + "Target": "P13", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 900, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P14", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Tip Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Dispense", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": false, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + } + ], + "Wash": false, + "Dynamic?": true, + "AutoSelectActiveWashTechnique": false, + "ActiveWashTechnique": "", + "ChangeTipsBetweenDests": true, + "ChangeTipsBetweenSources": false, + "DefaultCaption": "", + "UseExpression": false, + "LeaveTipsOn": false, + "MandrelExpression": "", + "Repeats": "1", + "RepeatsByVolume": false, + "Replicates": "1", + "ShowTipHandlingDetails": false, + "ShowTransferDetails": true, + "Solvent": "Water", + "Span8Wash": false, + "Span8WashVolume": "2", + "Span8WasteVolume": "1", + "SplitVolume": false, + "SplitVolumeCleaning": false, + "Stop": "Destinations", + "TipLocation": "BC230", + "UseCurrentTips": false, + "UseDisposableTips": false, + "UseFixedTips": false, + "UseJIT": true, + "UseMandrelSelection": true, + "UseProbes": [ + true, + true, + true, + true, + true, + true, + true, + true + ], + "WashCycles": "4", + "WashVolume": "110%", + "Wizard": false + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P13", + "Target": "Orbital1", + "LeaveBottomLabware": false + } + }, + { + "oscillation": { + "Device": "OrbitalShaker0", + "Parameters": [ + "800", + "2", + "60", + "CounterClockwise" + ], + "Command": "Timed Shake" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "Orbital1", + "Target": "P13", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 180, + "Mode": "TimedResource" + } + }, + { + "move": { + "Pod": "Pod1", + "GripSide": "A1 near", + "Source": "P13", + "Target": "P12", + "LeaveBottomLabware": false + } + }, + { + "incubation": { + "Message": "Paused", + "Location": "the whole system", + "Time": 120, + "Mode": "TimedResource" + } + }, + { + "transfer": { + "Span8": false, + "Pod": "Pod1", + "items": [ + { + "Position": "P12", + "Height": -2.0, + "Volume": "40", + "liquidtype": "Well Contents", + "WellsX": 12, + "LabwareClass": "Matrix96_750uL", + "AutoSelectPrototype": true, + "ColsFirst": true, + "CustomHeight": false, + "DataSetPattern": false, + "HeightFrom": 0, + "LocalPattern": true, + "Operation": "Aspirate", + "OverrideHeight": false, + "Pattern": [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + "Prototype": "MC P300 High", + "ReferencedPattern": "", + "RowsFirst": false, + "SectionExpression": "", + "SelectionInfo": [ + 1 + ], + "SetMark": true, + "Source": true, + "StartAtMark": false, + "StartAtSelection": true, + "UseExpression": false + }, + { + "Position": "P14", "Height": -2.0, "Volume": "40", "liquidtype": "Tip Contents", From 12c17ec26edf4769acf8ea2df2b1a84af0b31518 Mon Sep 17 00:00:00 2001 From: Guangxin Zhang Date: Sun, 8 Jun 2025 16:58:19 +0800 Subject: [PATCH 42/44] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E4=BA=86Biomek.py=20?= =?UTF-8?q?=E7=8E=B0=E5=9C=A8=E5=BA=94=E5=8F=AF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/devices/liquid_handling/biomek.py | 1136 ++++++++++------- .../devices/liquid_handling/biomek_test.py | 2 +- 2 files changed, 669 insertions(+), 469 deletions(-) diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index ea7a9e9c..2e9b7b13 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -16,20 +16,37 @@ from .liquid_handler_abstract import LiquidHandlerAbstract import json from typing import Sequence, Optional, List, Union, Literal -class LiquidHandlerBiomek(LiquidHandlerAbstract): - +#class LiquidHandlerBiomek(LiquidHandlerAbstract): +class LiquidHandlerBiomek: """ Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 该类用于处理Biomek液体处理器的特定操作。 """ - def __init__(self, backend=None, deck=None, *args, **kwargs): - super().__init__(backend, deck, *args, **kwargs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self._status = "Idle" # 初始状态为 Idle self._success = False # 初始成功状态为 False self._status_queue = kwargs.get("status_queue", None) # 状态队列 self.temp_protocol = {} self.py32_path = "/opt/py32" # Biomek的Python 3.2路径 + + # 预定义的仪器分类 + self.tip_racks = [ + "BC230", "BC1025F", "BC50", "TipRack200", "TipRack1000", + "tip", "tips", "Tip", "Tips" + ] + + self.reservoirs = [ + "AgilentReservoir", "nest_12_reservoir_15ml", "nest_1_reservoir_195ml", + "reservoir", "Reservoir", "waste", "Waste" + ] + + self.plates_96 = [ + "BCDeep96Round", "Matrix96_750uL", "NEST 2ml Deep Well Plate", "nest_96_wellplate_100ul_pcr_full_skirt", + "nest_96_wellplate_200ul_flat", "Matrix96", "96", "plate", "Plate" + ] + self.aspirate_techniques = { 'MC P300 high':{ 'Position': 'P1', @@ -88,6 +105,29 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): 'UseExpression': False} } + def _get_instrument_type(self, class_name: str) -> str: + """ + 根据class_name判断仪器类型 + + Returns: + str: "tip_rack", "reservoir", "plate_96", 或 "unknown" + """ + # 检查是否是枪头架 + for tip_name in self.tip_racks: + if tip_name in class_name: + return "tip_rack" + + # 检查是否是储液槽 + for reservoir_name in self.reservoirs: + if reservoir_name in class_name: + return "reservoir" + + # 检查是否是96孔板 + for plate_name in self.plates_96: + if plate_name in class_name: + return "plate_96" + + return "unknown" @classmethod def deserialize(cls, data: dict, allow_marshal: bool = False) -> LiquidHandler: @@ -137,7 +177,7 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): "date": protocol_date, "type": protocol_type, }, - "labwares": [], + "labwares": {}, "steps": [], } return self.temp_protocol @@ -303,6 +343,104 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): return + def instrument_setup_biomek( + self, + id: str, + parent: str, + slot_on_deck: str, + class_name: str, + liquid_type: list[str], + liquid_volume: list[int], + liquid_input_wells: list[str], + ): + """ + 设置Biomek仪器的参数配置,按照DeckItems格式 + + 根据不同的仪器类型(容器、tip rack等)设置相应的参数结构 + 位置作为键,配置列表作为值 + """ + + # 判断仪器类型 + instrument_type = self._get_instrument_type(class_name) + + config = None # 初始化为None + + if instrument_type == "reservoir": + # 储液槽类型配置 + config = { + "Properties": { + "Name": id, # 使用id作为名称 + "Device": "", + "liquidtype": liquid_type[0] if liquid_type else "Water", + "BarCode": "", + "SenseEveryTime": False + }, + "Known": True, + "Class": f"LabwareClasses\\{class_name}", + "DataSets": {"Volume": {}}, + "RuntimeDataSets": {"Volume": {}}, + "EvalAmounts": (float(liquid_volume[0]),) if liquid_volume else (0,), + "Nominal": False, + "EvalLiquids": (liquid_type[0],) if liquid_type else ("Water",) + } + + elif instrument_type == "plate_96": + # 96孔板类型配置 + volume_per_well = float(liquid_volume[0]) if liquid_volume else 0 + liquid_per_well = liquid_type[0] if liquid_type else "Water" + + config = { + "Properties": { + "Name": id, # 使用id作为名称 + "Device": "", + "liquidtype": liquid_per_well, + "BarCode": "", + "SenseEveryTime": False + }, + "Known": True, + "Class": f"LabwareClasses\\{class_name}", + "DataSets": {"Volume": {}}, + "RuntimeDataSets": {"Volume": {}}, + "EvalAmounts": tuple([volume_per_well] * 96), + "Nominal": False, + "EvalLiquids": tuple([liquid_per_well] * 96) + } + + elif instrument_type == "tip_rack": + # 枪头架类型配置 + tip_config = { + "Class": "TipClasses\\T230", + "Contents": [], + "_RT_Contents": [], + "Used": False, + "RT_Used": False, + "Dirty": False, + "RT_Dirty": False, + "MaxVolumeUsed": 0.0, + "RT_MaxVolumeUsed": 0.0 + } + + config = { + "Tips": tip_config, + "RT_Tips": tip_config.copy(), + "Properties": {}, + "Known": False, + "Class": f"LabwareClasses\\{class_name}", + "DataSets": {"Volume": {}}, + "RuntimeDataSets": {"Volume": {}} + } + + # 按照DeckItems格式存储:位置作为键,配置列表作为值 + if config is not None: + self.temp_protocol["labwares"][slot_on_deck] = [config] + else: + # 空位置 + self.temp_protocol["labwares"][slot_on_deck] = [] + + return + + + def transfer_biomek( self, source: str, @@ -369,9 +507,11 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): transfer_params["items"] = items transfer_params["Solvent"] = 'Water' transfer_params["TipLocation"] = tip_rack - self.temp_protocol["steps"].append(transfer_params) + tmp={'transfer': transfer_params} + self.temp_protocol["steps"].append(tmp) + + return - return def move_biomek( self, @@ -430,483 +570,543 @@ class LiquidHandlerBiomek(LiquidHandlerAbstract): if __name__ == "__main__": - steps_info = ''' + + print("=== Biomek完整流程测试 ===") + print("包含: 仪器设置 + 完整实验步骤") + + # 完整的步骤信息(从biomek.py复制) + steps_info = ''' { - "steps": [ - { - "step_number": 1, - "operation": "transfer", - "description": "转移PCR产物或酶促反应液至0.05ml 96孔板中", - "parameters": { - "source": "P1", - "target": "P11", - "tip_rack": "BC230", - "volume": 50 - } - }, - { - "step_number": 2, - "operation": "transfer", - "description": "加入2倍体积Bind Beads BC至产物中", - "parameters": { - "source": "P2", - "target": "P11", - "tip_rack": "BC230", - "volume": 100 - } - }, - { - "step_number": 3, - "operation": "move_labware", - "description": "移动P11至Orbital1用于振荡混匀", - "parameters": { - "source": "P11", - "target": "Orbital1" - } - }, - { - "step_number": 4, - "operation": "oscillation", - "description": "在Orbital1上振荡混匀Bind Beads BC与PCR产物(700-900rpm,300秒)", - "parameters": { - "rpm": 800, - "time": 300 - } - }, - { - "step_number": 5, - "operation": "move_labware", - "description": "移动混匀后的板回P11", - "parameters": { - "source": "Orbital1", - "target": "P11" - } - }, - { - "step_number": 6, - "operation": "move_labware", - "description": "将P11移动到磁力架(P12)吸附3分钟", - "parameters": { - "source": "P11", - "target": "P12" - } - }, - { - "step_number": 7, - "operation": "incubation", - "description": "磁力架上室温静置3分钟完成吸附", - "parameters": { - "time": 180 - } - }, - { - "step_number": 8, - "operation": "transfer", - "description": "去除上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 150 - } - }, - { - "step_number": 9, - "operation": "transfer", - "description": "加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 10, - "operation": "move_labware", - "description": "移动清洗板到Orbital1进行振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 11, - "operation": "oscillation", - "description": "乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 12, - "operation": "move_labware", - "description": "振荡后将板移回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 13, - "operation": "incubation", - "description": "吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 14, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 15, - "operation": "transfer", - "description": "第二次加入300-500μl 75%乙醇清洗", - "parameters": { - "source": "P3", - "target": "P12", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 16, - "operation": "move_labware", - "description": "再次移动清洗板到Orbital1振荡", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 17, - "operation": "oscillation", - "description": "再次乙醇清洗液振荡混匀(700-900rpm, 45秒)", - "parameters": { - "rpm": 800, - "time": 45 - } - }, - { - "step_number": 18, - "operation": "move_labware", - "description": "振荡后板送回磁力架P12吸附", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 19, - "operation": "incubation", - "description": "再次吸附3分钟", - "parameters": { - "time": 180 - } - }, - { - "step_number": 20, - "operation": "transfer", - "description": "去除乙醇上清液至废液槽", - "parameters": { - "source": "P12", - "target": "P22", - "tip_rack": "BC230", - "volume": 400 - } - }, - { - "step_number": 21, - "operation": "incubation", - "description": "空气干燥15分钟", - "parameters": { - "time": 900 - } - }, - { - "step_number": 22, - "operation": "transfer", - "description": "加30-50μl Elution Buffer洗脱", - "parameters": { - "source": "P4", - "target": "P12", - "tip_rack": "BC230", - "volume": 40 - } - }, - { - "step_number": 23, - "operation": "move_labware", - "description": "移动到Orbital1振荡混匀(60秒)", - "parameters": { - "source": "P12", - "target": "Orbital1" - } - }, - { - "step_number": 24, - "operation": "oscillation", - "description": "Elution Buffer振荡混匀(700-900rpm, 60秒)", - "parameters": { - "rpm": 800, - "time": 60 - } - }, - { - "step_number": 25, - "operation": "move_labware", - "description": "振荡后送回磁力架P12", - "parameters": { - "source": "Orbital1", - "target": "P12" - } - }, - { - "step_number": 26, - "operation": "incubation", - "description": "室温静置3分钟(洗脱反应)", - "parameters": { - "time": 180 - } - }, - { - "step_number": 27, - "operation": "transfer", - "description": "将上清液(DNA)转移到新板(P13)", - "parameters": { - "source": "P12", - "target": "P13", - "tip_rack": "BC230", - "volume": 40 + "steps": [ + { + "step_number": 1, + "operation": "transfer", + "description": "转移PCR产物或酶促反应液至0.5ml 96孔板中", + "parameters": { + "source": "P1", + "target": "P11", + "tip_rack": "BC230", + "volume": 50 + } + }, + { + "step_number": 2, + "operation": "transfer", + "description": "加入2倍体积的Bind Beads BC至产物中", + "parameters": { + "source": "P2", + "target": "P11", + "tip_rack": "BC230", + "volume": 100 + } + }, + { + "step_number": 3, + "operation": "oscillation", + "description": "振荡混匀300秒", + "parameters": { + "rpm": 800, + "time": 300 + } + }, + { + "step_number": 4, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附3分钟", + "parameters": { + "source": "P11", + "target": "P12" + } + }, + { + "step_number": 5, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 6, + "operation": "transfer", + "description": "吸弃或倒除上清液", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 150 + } + }, + { + "step_number": 7, + "operation": "transfer", + "description": "加入300-500μl 75%乙醇", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 8, + "operation": "move_labware", + "description": "移动至振荡器进行振荡混匀", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 9, + "operation": "oscillation", + "description": "振荡混匀60秒", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 10, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附3分钟", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 11, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 12, + "operation": "transfer", + "description": "吸弃或倒弃废液", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 13, + "operation": "transfer", + "description": "重复加入75%乙醇", + "parameters": { + "source": "P3", + "target": "P12", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 14, + "operation": "move_labware", + "description": "移动至振荡器进行振荡混匀", + "parameters": { + "source": "P12", + "target": "Orbital1" + } + }, + { + "step_number": 15, + "operation": "oscillation", + "description": "振荡混匀60秒", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 16, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附3分钟", + "parameters": { + "source": "Orbital1", + "target": "P12" + } + }, + { + "step_number": 17, + "operation": "incubation", + "description": "吸附3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 18, + "operation": "transfer", + "description": "吸弃或倒弃废液", + "parameters": { + "source": "P12", + "target": "P22", + "tip_rack": "BC230", + "volume": 400 + } + }, + { + "step_number": 19, + "operation": "move_labware", + "description": "正放96孔板,空气干燥15分钟", + "parameters": { + "source": "P12", + "target": "P13" + } + }, + { + "step_number": 20, + "operation": "incubation", + "description": "空气干燥15分钟", + "parameters": { + "time": 900 + } + }, + { + "step_number": 21, + "operation": "transfer", + "description": "加入30-50μl Elution Buffer", + "parameters": { + "source": "P4", + "target": "P13", + "tip_rack": "BC230", + "volume": 40 + } + }, + { + "step_number": 22, + "operation": "move_labware", + "description": "移动至振荡器进行振荡混匀", + "parameters": { + "source": "P13", + "target": "Orbital1" + } + }, + { + "step_number": 23, + "operation": "oscillation", + "description": "振荡混匀60秒", + "parameters": { + "rpm": 800, + "time": 60 + } + }, + { + "step_number": 24, + "operation": "move_labware", + "description": "室温静置3分钟", + "parameters": { + "source": "Orbital1", + "target": "P13" + } + }, + { + "step_number": 25, + "operation": "incubation", + "description": "室温静置3分钟", + "parameters": { + "time": 180 + } + }, + { + "step_number": 26, + "operation": "move_labware", + "description": "转移至96孔磁力架上吸附2分钟", + "parameters": { + "source": "P13", + "target": "P12" + } + }, + { + "step_number": 27, + "operation": "incubation", + "description": "吸附2分钟", + "parameters": { + "time": 120 + } + }, + { + "step_number": 28, + "operation": "transfer", + "description": "将DNA转移至新的板中", + "parameters": { + "source": "P12", + "target": "P14", + "tip_rack": "BC230", + "volume": 40 } } ] } +''' + # 完整的labware配置信息 + labware_with_liquid = ''' + [ + { + "id": "Tip Rack BC230 TL1", + "parent": "deck", + "slot_on_deck": "TL1", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL2", + "parent": "deck", + "slot_on_deck": "TL2", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL3", + "parent": "deck", + "slot_on_deck": "TL3", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL4", + "parent": "deck", + "slot_on_deck": "TL4", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 TL5", + "parent": "deck", + "slot_on_deck": "TL5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P5", + "parent": "deck", + "slot_on_deck": "P5", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P6", + "parent": "deck", + "slot_on_deck": "P6", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P15", + "parent": "deck", + "slot_on_deck": "P15", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "Tip Rack BC230 P16", + "parent": "deck", + "slot_on_deck": "P16", + "class_name": "BC230", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "stock plate on P1", + "parent": "deck", + "slot_on_deck": "P1", + "class_name": "AgilentReservoir", + "liquid_type": ["PCR product"], + "liquid_volume": [5000], + "liquid_input_wells": ["A1"] + }, + { + "id": "stock plate on P2", + "parent": "deck", + "slot_on_deck": "P2", + "class_name": "AgilentReservoir", + "liquid_type": ["bind beads"], + "liquid_volume": [100000], + "liquid_input_wells": ["A1"] + }, + { + "id": "stock plate on P3", + "parent": "deck", + "slot_on_deck": "P3", + "class_name": "AgilentReservoir", + "liquid_type": ["75% ethanol"], + "liquid_volume": [100000], + "liquid_input_wells": ["A1"] + }, + { + "id": "stock plate on P4", + "parent": "deck", + "slot_on_deck": "P4", + "class_name": "AgilentReservoir", + "liquid_type": ["Elution Buffer"], + "liquid_volume": [5000], + "liquid_input_wells": ["A1"] + }, + { + "id": "working plate on P11", + "parent": "deck", + "slot_on_deck": "P11", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P12", + "parent": "deck", + "slot_on_deck": "P12", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P13", + "parent": "deck", + "slot_on_deck": "P13", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "working plate on P14", + "parent": "deck", + "slot_on_deck": "P14", + "class_name": "BCDeep96Round", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "waste on P22", + "parent": "deck", + "slot_on_deck": "P22", + "class_name": "AgilentReservoir", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + }, + { + "id": "oscillation", + "parent": "deck", + "slot_on_deck": "Orbital1", + "class_name": "Orbital", + "liquid_type": [], + "liquid_volume": [], + "liquid_input_wells": [] + } + ] ''' - labware_with_liquid = ''' - [ - { - "id": "Tip Rack BC230 on TL1", - "parent": "deck", - "slot_on_deck": "TL1", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL2", - "parent": "deck", - "slot_on_deck": "TL2", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL3", - "parent": "deck", - "slot_on_deck": "TL3", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL4", - "parent": "deck", - "slot_on_deck": "TL4", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on TL5", - "parent": "deck", - "slot_on_deck": "TL5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P5", - "parent": "deck", - "slot_on_deck": "P5", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P6", - "parent": "deck", - "slot_on_deck": "P6", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P15", - "parent": "deck", - "slot_on_deck": "P15", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "Tip Rack BC230 on P16", - "parent": "deck", - "slot_on_deck": "P16", - "class_name": "BC230", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "stock plate on P1", - "parent": "deck", - "slot_on_deck": "P1", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "master_mix" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P2", - "parent": "deck", - "slot_on_deck": "P2", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "bind beads" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "stock plate on P3", - "parent": "deck", - "slot_on_deck": "P3", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "ethyl alcohol" - ], - "liquid_volume": [10000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "elution buffer on P4", - "parent": "deck", - "slot_on_deck": "P4", - "class_name": "nest_12_reservoir_15ml", - "liquid_type": [ - "elution buffer" - ], - "liquid_volume": [5000], - "liquid_input_wells": [ - "A1" - ] - }, - { - "id": "oscillation", - "parent": "deck", - "slot_on_deck": "Orbital1", - "class_name": "Orbital", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "working plate on P11", - "parent": "deck", - "slot_on_deck": "P11", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "magnetics module on P12", - "parent": "deck", - "slot_on_deck": "P12", - "class_name": "magnetics module", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "working plate on P13", - "parent": "deck", - "slot_on_deck": "P13", - "class_name": "NEST 2ml Deep Well Plate", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - }, - { - "id": "waste on P22", - "parent": "deck", - "slot_on_deck": "P22", - "class_name": "nest_1_reservoir_195ml", - "liquid_type": [], - "liquid_volume": [], - "liquid_input_wells": [] - } - ] - ''' - # 创建Biomek液体处理器实例 + # 创建handler实例 handler = LiquidHandlerBiomek() + + # 创建协议 + protocol = handler.create_protocol( + protocol_name="DNA纯化完整流程", + protocol_description="使用磁珠进行DNA纯化的完整自动化流程", + protocol_version="1.0", + protocol_author="Biomek系统", + protocol_date="2024-01-01", + protocol_type="DNA_purification" + ) - handler.temp_protocol = { - "meta": {}, - "labwares": [], - "steps": [] - } - - input_steps = json.loads(steps_info) + print("\n=== 第一步:设置所有仪器 ===") + # 解析labware配置 labwares = json.loads(labware_with_liquid) + + # 设置所有仪器 + instrument_count = 0 + for labware in labwares: + print(f"设置仪器: {labware['id']} ({labware['class_name']}) 在位置 {labware['slot_on_deck']}") + handler.instrument_setup_biomek( + id=labware['id'], + parent=labware['parent'], + slot_on_deck=labware['slot_on_deck'], + class_name=labware['class_name'], + liquid_type=labware['liquid_type'], + liquid_volume=labware['liquid_volume'], + liquid_input_wells=labware['liquid_input_wells'] + ) + instrument_count += 1 + + print(f"总共设置了 {instrument_count} 个仪器位置") + print("\n=== 第二步:执行实验步骤 ===") + # 解析步骤信息 + input_steps = json.loads(steps_info) + + # 执行所有步骤 + step_count = 0 for step in input_steps['steps']: operation = step['operation'] parameters = step['parameters'] - + description = step['description'] + + print(f"步骤 {step['step_number']}: {description}") + if operation == 'transfer': - handler.transfer_biomek(source=parameters['source'], - target=parameters['target'], - volume=parameters['volume'], - tip_rack=parameters['tip_rack'], - aspirate_techniques='MC P300 high', - dispense_techniques='MC P300 high') + handler.transfer_biomek( + source=parameters['source'], + target=parameters['target'], + volume=parameters['volume'], + tip_rack=parameters['tip_rack'], + aspirate_techniques='MC P300 high', + dispense_techniques='MC P300 high' + ) elif operation == 'move_labware': - handler.move_biomek(source=parameters['source'], - target=parameters['target']) + handler.move_biomek( + source=parameters['source'], + target=parameters['target'] + ) elif operation == 'oscillation': - handler.oscillation_biomek(rpm=parameters['rpm'], - time=parameters['time']) + handler.oscillation_biomek( + rpm=parameters['rpm'], + time=parameters['time'] + ) elif operation == 'incubation': - handler.incubation_biomek(time=parameters['time']) - - print(json.dumps(handler.temp_protocol, indent=4)) - + handler.incubation_biomek( + time=parameters['time'] + ) + + step_count += 1 + + print(f"总共执行了 {step_count} 个步骤") + print("\n=== 第三步:保存完整协议 ===") + # 获取脚本目录 + script_dir = pathlib.Path(__file__).parent + + # 保存完整协议 + complete_output_path = script_dir / "complete_biomek_protocol_0608.json" + with open(complete_output_path, 'w', encoding='utf-8') as f: + json.dump(handler.temp_protocol, f, indent=4, ensure_ascii=False) + + print(f"完整协议已保存到: {complete_output_path}") + + print("\n=== 测试完成 ===") + print("完整的DNA纯化流程已成功转换为Biomek格式!") diff --git a/unilabos/devices/liquid_handling/biomek_test.py b/unilabos/devices/liquid_handling/biomek_test.py index e3865983..1e56f18e 100644 --- a/unilabos/devices/liquid_handling/biomek_test.py +++ b/unilabos/devices/liquid_handling/biomek_test.py @@ -468,7 +468,7 @@ class LiquidHandlerBiomek: if __name__ == "__main__": - + print("=== Biomek完整流程测试 ===") print("包含: 仪器设置 + 完整实验步骤") From bab4b1d67abbd79a14ba9ef5d76ae9b0c9bd5ab2 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sun, 8 Jun 2025 17:05:48 +0800 Subject: [PATCH 43/44] biomek switch back to non-test --- test/experiments/plr_test_converted_slim.json | 1710 +++++++++++++++++ unilabos/app/main.py | 5 +- unilabos/devices/liquid_handling/biomek.py | 56 +- unilabos/registry/devices/liquid_handler.yaml | 2 +- 4 files changed, 1739 insertions(+), 34 deletions(-) create mode 100644 test/experiments/plr_test_converted_slim.json diff --git a/test/experiments/plr_test_converted_slim.json b/test/experiments/plr_test_converted_slim.json new file mode 100644 index 00000000..43e05e7c --- /dev/null +++ b/test/experiments/plr_test_converted_slim.json @@ -0,0 +1,1710 @@ +{ + "nodes": [ + { + "id": "PLR_STATION", + "name": "PLR_LH_TEST", + "parent": null, + "type": "device", + "class": "liquid_handler", + "position": { + "x": 620.6111111111111, + "y": 171, + "z": 0 + }, + "config": { + "data": { + "children": [ + { + "_resource_child_name": "deck", + "_resource_type": "pylabrobot.resources.opentrons.deck:OTDeck" + } + ], + "backend": { + "type": "LiquidHandlerChatterboxBackend" + } + } + }, + "data": {}, + "children": [ + "deck" + ] + }, + { + "id": "deck", + "name": "deck", + "sample_id": null, + "children": [ + "tip_rack", + "plate_well" + ], + "parent": "PLR_STATION", + "type": "deck", + "class": "OTDeck", + "position": { + "x": 0, + "y": 0, + "z": 0 + }, + "config": { + "type": "OTDeck", + "with_trash": false, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + } + }, + "data": {} + }, + { + "id": "tip_rack", + "name": "tip_rack", + "sample_id": null, + "children": [ + "tip_rack_A1", + "tip_rack_B1", + "tip_rack_C1", + "tip_rack_D1", + "tip_rack_E1", + "tip_rack_F1", + "tip_rack_G1", + "tip_rack_H1", + "tip_rack_A2", + "tip_rack_B2", + "tip_rack_C2", + "tip_rack_D2", + "tip_rack_E2", + "tip_rack_F2", + "tip_rack_G2", + "tip_rack_H2" + ], + "parent": "deck", + "type": "plate", + "class": "opentrons_96_filtertiprack_1000ul", + "position": { + "x": 0, + "y": 0, + "z": 69 + }, + "config": { + "type": "TipRack", + "size_x": 122.4, + "size_y": 82.6, + "size_z": 20.0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_rack", + "model": "HTF", + "ordering": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A2", + "B2", + "C2", + "D2", + "E2", + "F2", + "G2", + "H2" + ] + }, + "data": {} + }, + { + "id": "tip_rack_A1", + "name": "tip_rack_A1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 68.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_B1", + "name": "tip_rack_B1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 59.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_C1", + "name": "tip_rack_C1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 50.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_D1", + "name": "tip_rack_D1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 41.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_E1", + "name": "tip_rack_E1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 32.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_F1", + "name": "tip_rack_F1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 23.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_G1", + "name": "tip_rack_G1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 14.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_H1", + "name": "tip_rack_H1", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 7.2, + "y": 5.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_A2", + "name": "tip_rack_A2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 68.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_B2", + "name": "tip_rack_B2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 59.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_C2", + "name": "tip_rack_C2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 50.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_D2", + "name": "tip_rack_D2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 41.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_E2", + "name": "tip_rack_E2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 32.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_F2", + "name": "tip_rack_F2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 23.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_G2", + "name": "tip_rack_G2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 14.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "tip_rack_H2", + "name": "tip_rack_H2", + "sample_id": null, + "children": [], + "parent": "tip_rack", + "type": "device", + "class": "", + "position": { + "x": 16.2, + "y": 5.3, + "z": 9.47 + }, + "config": { + "type": "TipSpot", + "size_x": 9.0, + "size_y": 9.0, + "size_z": 0, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "tip_spot", + "model": null, + "prototype_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + }, + "data": { + "tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + }, + "tip_state": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + }, + "pending_tip": { + "type": "Tip", + "total_tip_length": 39.2, + "has_filter": true, + "maximal_volume": 20.0, + "fitting_depth": 3.29 + } + } + }, + { + "id": "plate_well", + "name": "plate_well", + "sample_id": null, + "children": [ + "plate_well_A1", + "plate_well_B1", + "plate_well_C1", + "plate_well_D1", + "plate_well_E1", + "plate_well_F1", + "plate_well_G1", + "plate_well_H1", + "plate_well_A11", + "plate_well_B11", + "plate_well_C11", + "plate_well_D11", + "plate_well_E11", + "plate_well_F11", + "plate_well_G11", + "plate_well_H11" + ], + "parent": "deck", + "type": "plate", + "class": "nest_96_wellplate_2ml_deep", + "position": { + "x": 265.0, + "y": 0, + "z": 69 + }, + "config": { + "type": "Plate", + "size_x": 127.76, + "size_y": 85.48, + "size_z": 14.2, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "plate", + "model": "Cor_96_wellplate_360ul_Fb", + "ordering": [ + "A1", + "B1", + "C1", + "D1", + "E1", + "F1", + "G1", + "H1", + "A11", + "B11", + "C11", + "D11", + "E11", + "F11", + "G11", + "H11" + ] + }, + "data": {} + }, + { + "id": "plate_well_A1", + "name": "plate_well_A1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 70.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_B1", + "name": "plate_well_B1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 61.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_C1", + "name": "plate_well_C1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 52.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_D1", + "name": "plate_well_D1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 43.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_E1", + "name": "plate_well_E1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 34.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_F1", + "name": "plate_well_F1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 25.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_G1", + "name": "plate_well_G1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 16.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_H1", + "name": "plate_well_H1", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 10.87, + "y": 7.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_A11", + "name": "plate_well_A11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 70.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_B11", + "name": "plate_well_B11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 61.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_C11", + "name": "plate_well_C11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 52.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_D11", + "name": "plate_well_D11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 43.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_E11", + "name": "plate_well_E11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 34.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_F11", + "name": "plate_well_F11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 25.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_G11", + "name": "plate_well_G11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 16.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + }, + { + "id": "plate_well_H11", + "name": "plate_well_H11", + "sample_id": null, + "children": [], + "parent": "plate_well", + "type": "device", + "class": "", + "position": { + "x": 100.87, + "y": 7.77, + "z": 3.03 + }, + "config": { + "type": "Well", + "size_x": 6.86, + "size_y": 6.86, + "size_z": 10.67, + "rotation": { + "x": 0, + "y": 0, + "z": 0, + "type": "Rotation" + }, + "category": "well", + "model": null, + "max_volume": 360, + "material_z_thickness": 0.5, + "compute_volume_from_height": null, + "compute_height_from_volume": null, + "bottom_type": "flat", + "cross_section_type": "circle" + }, + "data": { + "liquids": [], + "pending_liquids": [], + "liquid_history": [] + } + } + ], + "links": [] +} \ No newline at end of file diff --git a/unilabos/app/main.py b/unilabos/app/main.py index 0db290a0..7a1b06bb 100644 --- a/unilabos/app/main.py +++ b/unilabos/app/main.py @@ -10,6 +10,8 @@ from copy import deepcopy import yaml +from unilabos.resources.graphio import tree_to_list + # 首先添加项目根目录到路径 current_dir = os.path.dirname(os.path.abspath(__file__)) unilabos_dir = os.path.dirname(os.path.dirname(current_dir)) @@ -145,9 +147,8 @@ def main(): ) devices_and_resources = dict_from_graph(graph_res.physical_setup_graph) args_dict["resources_config"] = initialize_resources(list(deepcopy(devices_and_resources).values())) + args_dict["resources_config"] = list(devices_and_resources.values()) args_dict["devices_config"] = dict_to_nested_dict(deepcopy(devices_and_resources), devices_only=False) - # args_dict["resources_config"] = dict_to_tree(devices_and_resources, devices_only=False) - args_dict["graph"] = graph_res.physical_setup_graph else: if args_dict["devices"] is None or args_dict["resources"] is None: diff --git a/unilabos/devices/liquid_handling/biomek.py b/unilabos/devices/liquid_handling/biomek.py index 2e9b7b13..ea71c6dd 100644 --- a/unilabos/devices/liquid_handling/biomek.py +++ b/unilabos/devices/liquid_handling/biomek.py @@ -1,22 +1,20 @@ +import json +import pathlib +from typing import Sequence, Optional, List, Union, Literal + import requests -from typing import List, Sequence, Optional, Union, Literal from geometry_msgs.msg import Point from pylabrobot.liquid_handling import LiquidHandler -from unilabos_msgs.msg import Resource - from pylabrobot.resources import ( TipRack, Container, Coordinate, ) +from unilabos_msgs.msg import Resource from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker # type: ignore -from .liquid_handler_abstract import LiquidHandlerAbstract -import json -from typing import Sequence, Optional, List, Union, Literal -#class LiquidHandlerBiomek(LiquidHandlerAbstract): class LiquidHandlerBiomek: """ Biomek液体处理器的实现类,继承自LiquidHandlerAbstract。 @@ -214,7 +212,6 @@ class LiquidHandlerBiomek: liquid_type: list[str], liquid_volume: list[int], slot_on_deck: int, - ): """ 创建一个新的资源。 @@ -236,26 +233,25 @@ class LiquidHandlerBiomek: # TODO:需要对好接口,下面这个是临时的 for resource in resources: res_id = resource.id - class_name = resource.class_name + class_name = resource.name parent = bind_parent_id - bind_locations = Coordinate.from_point(resource.bind_location) liquid_input_slot = liquid_input_slot liquid_type = liquid_type liquid_volume = liquid_volume slot_on_deck = slot_on_deck - resource = { - "id": res_id, - "class": class_name, - "parent": parent, - "bind_locations": bind_locations.to_dict(), - "liquid_input_slot": liquid_input_slot, - "liquid_type": liquid_type, - "liquid_volume": liquid_volume, - "slot_on_deck": slot_on_deck, - } - self.temp_protocol["labwares"].append(resource) - return resource + resource = { + "id": res_id, + "class": class_name, + "parent": parent, + "bind_locations": bind_location, + "liquid_input_slot": liquid_input_slot, + "liquid_type": liquid_type, + "liquid_volume": liquid_volume, + "slot_on_deck": slot_on_deck, + } + self.temp_protocol["labwares"].append(resource) + return resources def transfer_liquid( self, @@ -439,16 +435,14 @@ class LiquidHandlerBiomek: return - - def transfer_biomek( - self, - source: str, - target: str, - tip_rack: str, - volume: float, - aspirate_techniques: str, - dispense_techniques: str, + self, + source: str, + target: str, + tip_rack: str, + volume: float, + aspirate_techniques: str, + dispense_techniques: str, ): """ 处理Biomek的液体转移操作。 diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index 6851f285..eef04042 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -293,7 +293,7 @@ liquid_handler.biomek: description: Biomek液体处理器设备,基于pylabrobot控制 icon: icon_yiyezhan.webp class: - module: unilabos.devices.liquid_handling.biomek_test:LiquidHandlerBiomek + module: unilabos.devices.liquid_handling.biomek:LiquidHandlerBiomek type: python status_types: {} action_value_mappings: From 6ae77e04086445f5e6a5021f31f4ca4171029f75 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Sun, 8 Jun 2025 17:07:48 +0800 Subject: [PATCH 44/44] temp disable initialize resource --- unilabos/app/main.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/unilabos/app/main.py b/unilabos/app/main.py index 7a1b06bb..0f6b2f42 100644 --- a/unilabos/app/main.py +++ b/unilabos/app/main.py @@ -146,7 +146,7 @@ def main(): else read_graphml(args_dict["graph"]) ) devices_and_resources = dict_from_graph(graph_res.physical_setup_graph) - args_dict["resources_config"] = initialize_resources(list(deepcopy(devices_and_resources).values())) + # args_dict["resources_config"] = initialize_resources(list(deepcopy(devices_and_resources).values())) args_dict["resources_config"] = list(devices_and_resources.values()) args_dict["devices_config"] = dict_to_nested_dict(deepcopy(devices_and_resources), devices_only=False) args_dict["graph"] = graph_res.physical_setup_graph @@ -155,9 +155,10 @@ def main(): print_status("Either graph or devices and resources must be provided.", "error") sys.exit(1) args_dict["devices_config"] = json.load(open(args_dict["devices"], encoding="utf-8")) - args_dict["resources_config"] = initialize_resources( - list(json.load(open(args_dict["resources"], encoding="utf-8")).values()) - ) + # args_dict["resources_config"] = initialize_resources( + # list(json.load(open(args_dict["resources"], encoding="utf-8")).values()) + # ) + args_dict["resources_config"] = list(json.load(open(args_dict["resources"], encoding="utf-8")).values()) print_status(f"{len(args_dict['resources_config'])} Resources loaded:", "info") for i in args_dict["resources_config"]: