新增版位推荐功能

This commit is contained in:
Guangxin Zhang
2025-09-17 21:07:19 +01:00
parent 09549d2839
commit 573c724a5c
4 changed files with 295 additions and 81 deletions

View File

@@ -593,6 +593,7 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
available_tips[idx] = tipSpot available_tips[idx] = tipSpot
continue continue
# 一般移动液体有两种方式,一对多和多对多 # 一般移动液体有两种方式,一对多和多对多
print("channel_num", self.channel_num)
if self.channel_num == 8: if self.channel_num == 8:
tip_prefix = list(available_tips.values())[0].name.split('_')[0] tip_prefix = list(available_tips.values())[0].name.split('_')[0]
@@ -601,8 +602,11 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
available_cols.sort() available_cols.sort()
available_tips_dict = {tip.name: tip for tip in available_tips.values()} available_tips_dict = {tip.name: tip for tip in available_tips.values()}
tips_to_use = [available_tips_dict[f"{tip_prefix}_{chr(65 + i)}{available_cols[0]}"] for i in range(8)] tips_to_use = [available_tips_dict[f"{tip_prefix}_{chr(65 + i)}{available_cols[0]}"] for i in range(8)]
print("tips_to_use", tips_to_use)
await self.pick_up_tips(tips_to_use, use_channels=list(range(0, 8))) await self.pick_up_tips(tips_to_use, use_channels=list(range(0, 8)))
print("source_wells", source_wells)
await self.aspirate(source_wells, [unit_volume] * 8, use_channels=list(range(0, 8))) await self.aspirate(source_wells, [unit_volume] * 8, use_channels=list(range(0, 8)))
print("target_wells", target_wells)
await self.dispense(target_wells, [unit_volume] * 8, use_channels=list(range(0, 8))) await self.dispense(target_wells, [unit_volume] * 8, use_channels=list(range(0, 8)))
await self.discard_tips(use_channels=list(range(0, 8))) await self.discard_tips(use_channels=list(range(0, 8)))
@@ -610,7 +614,10 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
for num_well in range(len(target_wells)): for num_well in range(len(target_wells)):
tip_to_use = available_tips[list(available_tips.keys())[num_well]] tip_to_use = available_tips[list(available_tips.keys())[num_well]]
print("tip_to_use", tip_to_use)
await self.pick_up_tips([tip_to_use], use_channels=[0]) await self.pick_up_tips([tip_to_use], use_channels=[0])
print("source_wells", source_wells)
print("target_wells", target_wells)
if len(source_wells) == 1: if len(source_wells) == 1:
await self.aspirate([source_wells[0]], [unit_volume], use_channels=[0]) await self.aspirate([source_wells[0]], [unit_volume], use_channels=[0])
else: else:

View File

@@ -5,7 +5,7 @@ import json
import socket import socket
import time import time
from typing import Any, List, Dict, Optional, TypedDict, Union, Sequence, Iterator, Literal from typing import Any, List, Dict, Optional, TypedDict, Union, Sequence, Iterator, Literal
import pprint as pp
from pylabrobot.liquid_handling import ( from pylabrobot.liquid_handling import (
LiquidHandlerBackend, LiquidHandlerBackend,
Pickup, Pickup,
@@ -25,6 +25,7 @@ from pylabrobot.liquid_handling.standard import (
ResourceDrop, ResourceDrop,
) )
from pylabrobot.resources import Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate, TipSpot, Trash from pylabrobot.resources import Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate, TipSpot, Trash
from traitlets import Int
from unilabos.devices.liquid_handling.liquid_handler_abstract import LiquidHandlerAbstract from unilabos.devices.liquid_handling.liquid_handler_abstract import LiquidHandlerAbstract
@@ -445,10 +446,11 @@ class LabResource:
from typing import Dict, Any from typing import Dict, Any
import time
class DefaultLayout: class DefaultLayout:
def __init__(self, product_name: str = "PRCXI9300"): def __init__(self, product_name: str = "PRCXI9300"):
self.labresource = None self.labresource = {}
if product_name not in ["PRCXI9300", "PRCXI9320"]: if product_name not in ["PRCXI9300", "PRCXI9320"]:
raise ValueError(f"Unsupported product_name: {product_name}. Only 'PRCXI9300' and 'PRCXI9320' are supported.") raise ValueError(f"Unsupported product_name: {product_name}. Only 'PRCXI9300' and 'PRCXI9320' are supported.")
@@ -458,12 +460,32 @@ class DefaultLayout:
self.layout = [1, 2, 3, 4, 5, 6] self.layout = [1, 2, 3, 4, 5, 6]
self.trash_slot = 3 self.trash_slot = 3
self.waste_liquid_slot = 6 self.waste_liquid_slot = 6
elif product_name == "PRCXI9320": elif product_name == "PRCXI9320":
self.rows = 3 self.rows = 3
self.columns = 4 self.columns = 4
self.layout = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] self.layout = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
self.trash_slot = 3 self.trash_slot = 16
self.waste_liquid_slot = 12 self.waste_liquid_slot = 12
self.default_layout = {"MatrixId":f"{time.time()}","MatrixName":f"{time.time()}","MatrixCount":16,"WorkTablets":
[{"Number": 1, "Code": "T1", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 2, "Code": "T2", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 3, "Code": "T3", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 4, "Code": "T4", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 5, "Code": "T5", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 6, "Code": "T6", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 7, "Code": "T7", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 8, "Code": "T8", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 9, "Code": "T9", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 10, "Code": "T10", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 11, "Code": "T11", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 12, "Code": "T12", "Material": {"uuid": "730067cf07ae43849ddf4034299030e9", "materialEnum": 0}}, # 这个设置成废液槽,用储液槽表示
{"Number": 13, "Code": "T13", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 14, "Code": "T14", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 15, "Code": "T15", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 16, "Code": "T16", "Material": {"uuid": "730067cf07ae43849ddf4034299030e9", "materialEnum": 0}} # 这个设置成垃圾桶,用储液槽表示
]
}
def get_layout(self) -> Dict[str, Any]: def get_layout(self) -> Dict[str, Any]:
return { return {
@@ -480,89 +502,120 @@ class DefaultLayout:
def get_waste_liquid_slot(self) -> int: def get_waste_liquid_slot(self) -> int:
return self.waste_liquid_slot return self.waste_liquid_slot
def set_liquid_handler_layout(self, product_name: str): def add_lab_resource(self, material_info):
if product_name == "PRCXI9300": self.labresource = material_info
self.rows = 2
self.columns = 3
self.layout = [1, 2, 3, 4, 5, 6]
self.trash_slot = 3
self.waste_liquid_slot = 6
elif product_name == "PRCXI9320": def recommend_layout(self, needs: Dict[str, int]) -> Dict[str, Any]:
self.rows = 3
self.columns = 4
self.layout = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
self.trash_slot = 3
self.waste_liquid_slot = 12
def set_trash_slot(self, slot: int):
self.trash_slot = slot
def set_waste_liquid_slot(self, slot: int):
self.waste_liquid_slot = slot
def add_lab_resource(self, lab_resource: LabResource):
self.labresource = lab_resource.get_resources_info()
def recommend_layout(self, needs: Dict[str, Any]) -> Dict[str, Any]:
"""根据 needs 推荐布局""" """根据 needs 推荐布局"""
liquid_info = needs['liquid_setup'] for k, v in needs.items():
tip_info = needs['totals_by_tip'] # 修改这里:直接访问 totals_by_tip if k not in self.labresource:
print("当前实验所需物料信息:", liquid_info) raise ValueError(f"Material {k} not found in lab resources.")
print("当前实验所需枪头信息:", tip_info)
print(self.labresource) # 预留位置12和16不动
reserved_positions = {12, 16}
available_positions = [i for i in range(1, 17) if i not in reserved_positions]
# 计算总需求
total_needed = sum(needs.values())
if total_needed > len(available_positions):
raise ValueError(f"需要 {total_needed} 个位置,但只有 {len(available_positions)} 个可用位置排除位置12和16")
# 依次分配位置
current_pos = 0
for material_name, count in needs.items():
material_uuid = self.labresource[material_name]['uuid']
material_enum = self.labresource[material_name]['materialEnum']
for _ in range(count):
if current_pos >= len(available_positions):
raise ValueError("位置不足,无法分配更多物料")
position = available_positions[current_pos]
# 找到对应的tablet并更新
for tablet in self.default_layout['WorkTablets']:
if tablet['Number'] == position:
tablet['Material']['uuid'] = material_uuid
tablet['Material']['materialEnum'] = material_enum
break
current_pos += 1
return self.default_layout
for liquid in liquid_info:
# total_volume = liquid.values()
print(liquid)
#print(f"资源 {liquid} 需要的总体积: {total_volume}")
if __name__ == "__main__": if __name__ == "__main__":
# ---- 资源SUP 供液X中间板 R14 孔空),目标板 R24 孔空)---- with open("prcxi_material.json", "r") as f:
sup = MaterialResource("SUP", slot=5, well=[1], liquid_id="X", volume=10000) material_info = json.load(f)
r1 = MaterialResource("R1", slot=6, well=[1,2,3,4,5,6,7,8])
r2 = MaterialResource("R2", slot=7, well=[1,2,3,4,5,6,7,8])
pm = ProtocolManager() layout = DefaultLayout("PRCXI9320")
# 步骤1SUP -> R11->N 扇出,每孔 50 uL总 200 uL layout.add_lab_resource(material_info)
pm.add_transfer(sup, r1, unit_volume=10.0) plan = layout.recommend_layout({
# 步骤2R1 -> R2N->N 对应,每对 25 uL总 100 uL来自 R1 中已存在的混合物 X "10μL加长 Tip头": 2,
pm.add_transfer(r1, r2, unit_volume=120.0) "300μL Tip头": 2,
"96深孔板": 2,
out = pm.compute_min_initials_with_tips() })
# layout_planer = DefaultLayout('PRCXI9320') # if __name__ == "__main__":
# print(layout_planer.get_layout()) # # ---- 资源SUP 供液X中间板 R14 孔空),目标板 R24 孔空)----
# print("回推最小需求:", out["liquid_setup"]) # {'SUP': {'X': 200.0}} # # sup = MaterialResource("SUP", slot=5, well=[1], liquid_id="X", volume=10000)
# print("步骤枪头建议:", out["step_tips"]) # [{'idx':0,'tip':'TIP_200uL','unit_volume':50.0}, {'idx':1,'tip':'TIP_50uL','unit_volume':25.0}] # # r1 = MaterialResource("R1", slot=6, well=[1,2,3,4,5,6,7,8])
# # r2 = MaterialResource("R2", slot=7, well=[1,2,3,4,5,6,7,8])
# # 实际执行(可选) # # pm = ProtocolManager()
# transfer_liquid(sup, r1, unit_volume=50.0) # # # 步骤1SUP -> R11->N 扇出,每孔 50 uL总 200 uL
# transfer_liquid(r1, r2, unit_volume=25.0) # # pm.add_transfer(sup, r1, unit_volume=10.0)
# print("执行后 SUP", sup.get_resource()) # 总体积 -200 # # # 步骤2R1 -> R2N->N 对应,每对 25 uL总 100 uL来自 R1 中已存在的混合物 X
# print("执行后 R1", r1.get_resource()) # 每孔 25 uL50 进 -25 出) # # pm.add_transfer(r1, r2, unit_volume=120.0)
# print("执行后 R2", r2.get_resource()) # 每孔 25 uL
# # out = pm.compute_min_initials_with_tips()
# # # layout_planer = DefaultLayout('PRCXI9320')
# # # print(layout_planer.get_layout())
# # # print("回推最小需求:", out["liquid_setup"]) # {'SUP': {'X': 200.0}}
# # # print("步骤枪头建议:", out["step_tips"]) # [{'idx':0,'tip':'TIP_200uL','unit_volume':50.0}, {'idx':1,'tip':'TIP_50uL','unit_volume':25.0}]
# # # # 实际执行(可选)
# # # transfer_liquid(sup, r1, unit_volume=50.0)
# # # transfer_liquid(r1, r2, unit_volume=25.0)
# # # print("执行后 SUP", sup.get_resource()) # 总体积 -200
# # # print("执行后 R1", r1.get_resource()) # 每孔 25 uL50 进 -25 出)
# # # print("执行后 R2", r2.get_resource()) # 每孔 25 uL
from pylabrobot.resources.opentrons.tube_racks import * # # from pylabrobot.resources.opentrons.tube_racks import *
from pylabrobot.resources.opentrons.plates import * # # from pylabrobot.resources.opentrons.plates import *
from pylabrobot.resources.opentrons.tip_racks import * # # from pylabrobot.resources.opentrons.tip_racks import *
from pylabrobot.resources.opentrons.reservoirs import * # # from pylabrobot.resources.opentrons.reservoirs import *
plate = [locals()['nest_96_wellplate_2ml_deep'](name="thermoscientificnunc_96_wellplate_2000ul"), locals()['corning_96_wellplate_360ul_flat'](name="corning_96_wellplate_360ul_flat")] # # plate = [locals()['nest_96_wellplate_2ml_deep'](name="thermoscientificnunc_96_wellplate_2000ul"), locals()['corning_96_wellplate_360ul_flat'](name="corning_96_wellplate_360ul_flat")]
tiprack = [locals()['opentrons_96_tiprack_300ul'](name="opentrons_96_tiprack_300ul"), locals()['opentrons_96_tiprack_1000ul'](name="opentrons_96_tiprack_1000ul")] # # tiprack = [locals()['opentrons_96_tiprack_300ul'](name="opentrons_96_tiprack_300ul"), locals()['opentrons_96_tiprack_1000ul'](name="opentrons_96_tiprack_1000ul")]
trash = [locals()['axygen_1_reservoir_90ml'](name="axygen_1_reservoir_90ml")] # # trash = [locals()['axygen_1_reservoir_90ml'](name="axygen_1_reservoir_90ml")]
# # from pprint import pprint
# # lab_resource = LabResource()
# # lab_resource.add_tipracks(tiprack)
# # lab_resource.add_plates(plate)
# # lab_resource.add_trash(trash)
# # layout_planer = DefaultLayout('PRCXI9300')
# # layout_planer.add_lab_resource(lab_resource)
# # layout_planer.recommend_layout(out)
# with open("prcxi_material.json", "r") as f:
# material_info = json.load(f)
# # print("当前实验物料信息:", material_info)
# layout = DefaultLayout("PRCXI9320")
# layout.add_lab_resource(material_info)
# print(layout.default_layout['WorkTablets'])
# # plan = layout.recommend_layout({
# # "10μL加长 Tip头": 2,
# # "300μL Tip头": 2,
# # "96深孔板": 2,
# # })
from pprint import pprint
lab_resource = LabResource()
lab_resource.add_tipracks(tiprack)
lab_resource.add_plates(plate)
lab_resource.add_trash(trash)
layout_planer = DefaultLayout('PRCXI9300')
layout_planer.add_lab_resource(lab_resource)
layout_planer.recommend_layout(out)

View File

@@ -808,7 +808,7 @@ class PRCXI9300Api:
return self.call("IMatrix", "GetWorkTabletMatrixById", [matrix_id]) return self.call("IMatrix", "GetWorkTabletMatrixById", [matrix_id])
def add_WorkTablet_Matrix(self, matrix: MatrixInfo): def add_WorkTablet_Matrix(self, matrix: MatrixInfo):
return self.call("IMatrix", "AddWorkTabletMatrix", [matrix]) return self.call("IMatrix", "AddWorkTabletMatrix2", [matrix])
def Load(self, dosage: int, plate_no: int, is_whole_plate: bool, hole_row: int, hole_col: int, blending_times: int, def Load(self, dosage: int, plate_no: int, is_whole_plate: bool, hole_row: int, hole_col: int, blending_times: int,
balance_height: int, plate_or_hole: str, hole_numbers: str, assist_fun1: str = "", assist_fun2: str = "", balance_height: int, plate_or_hole: str, hole_numbers: str, assist_fun1: str = "", assist_fun2: str = "",
@@ -972,6 +972,102 @@ class PRCXI9300Api:
"LiquidDispensingMethod": liquid_method, "LiquidDispensingMethod": liquid_method,
} }
class DefaultLayout:
def __init__(self, product_name: str = "PRCXI9300"):
self.labresource = {}
if product_name not in ["PRCXI9300", "PRCXI9320"]:
raise ValueError(f"Unsupported product_name: {product_name}. Only 'PRCXI9300' and 'PRCXI9320' are supported.")
if product_name == "PRCXI9300":
self.rows = 2
self.columns = 3
self.layout = [1, 2, 3, 4, 5, 6]
self.trash_slot = 3
self.waste_liquid_slot = 6
elif product_name == "PRCXI9320":
self.rows = 3
self.columns = 4
self.layout = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
self.trash_slot = 16
self.waste_liquid_slot = 12
self.default_layout = {"MatrixId":f"{time.time()}","MatrixName":f"{time.time()}","MatrixCount":16,"WorkTablets":
[{"Number": 1, "Code": "T1", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 2, "Code": "T2", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 3, "Code": "T3", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 4, "Code": "T4", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 5, "Code": "T5", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 6, "Code": "T6", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 7, "Code": "T7", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 8, "Code": "T8", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 9, "Code": "T9", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 10, "Code": "T10", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 11, "Code": "T11", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 12, "Code": "T12", "Material": {"uuid": "730067cf07ae43849ddf4034299030e9", "materialEnum": 0}}, # 这个设置成废液槽,用储液槽表示
{"Number": 13, "Code": "T13", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 14, "Code": "T14", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 15, "Code": "T15", "Material": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": 0}},
{"Number": 16, "Code": "T16", "Material": {"uuid": "730067cf07ae43849ddf4034299030e9", "materialEnum": 0}} # 这个设置成垃圾桶,用储液槽表示
]
}
def get_layout(self) -> Dict[str, Any]:
return {
"rows": self.rows,
"columns": self.columns,
"layout": self.layout,
"trash_slot": self.trash_slot,
"waste_liquid_slot": self.waste_liquid_slot
}
def get_trash_slot(self) -> int:
return self.trash_slot
def get_waste_liquid_slot(self) -> int:
return self.waste_liquid_slot
def add_lab_resource(self, material_info):
self.labresource = material_info
def recommend_layout(self, needs: Dict[str, int]) -> Dict[str, Any]:
"""根据 needs 推荐布局"""
for k, v in needs.items():
if k not in self.labresource:
raise ValueError(f"Material {k} not found in lab resources.")
# 预留位置12和16不动
reserved_positions = {12, 16}
available_positions = [i for i in range(1, 17) if i not in reserved_positions]
# 计算总需求
total_needed = sum(needs.values())
if total_needed > len(available_positions):
raise ValueError(f"需要 {total_needed} 个位置,但只有 {len(available_positions)} 个可用位置排除位置12和16")
# 依次分配位置
current_pos = 0
for material_name, count in needs.items():
material_uuid = self.labresource[material_name]['uuid']
material_enum = self.labresource[material_name]['materialEnum']
for _ in range(count):
if current_pos >= len(available_positions):
raise ValueError("位置不足,无法分配更多物料")
position = available_positions[current_pos]
# 找到对应的tablet并更新
for tablet in self.default_layout['WorkTablets']:
if tablet['Number'] == position:
tablet['Material']['uuid'] = material_uuid
tablet['Material']['materialEnum'] = material_enum
break
current_pos += 1
return self.default_layout
if __name__ == "__main__": if __name__ == "__main__":
# Example usage # Example usage
@@ -1299,10 +1395,13 @@ if __name__ == "__main__":
# from pylabrobot.resources import set_tip_tracking # from pylabrobot.resources import set_tip_tracking
set_volume_tracking(enabled=True) set_volume_tracking(enabled=True)
plate_2_liquids = handler.set_group("water", [plate2.children[0]], [300])
#print(plate_2_liquids) # 第一种情景:一个孔往多个孔加液
# plate_2_liquids = handler.set_group("water", [plate2.children[0]], [300])
# plate5_liquids = handler.set_group("master_mix", plate5.children[:23], [100]*23)
# 第二个情景:多个孔往多个孔加液(但是个数得对应)
plate_2_liquids = handler.set_group("water", plate2.children[:23], [300]*23)
plate5_liquids = handler.set_group("master_mix", plate5.children[:23], [100]*23) plate5_liquids = handler.set_group("master_mix", plate5.children[:23], [100]*23)
#print(plate5_liquids)
# plate11.set_well_liquids([("Water", 100) if (i % 8 == 0 and i // 8 < 6) else (None, 100) for i in range(96)]) # Set liquids for every 8 wells in plate8 # plate11.set_well_liquids([("Water", 100) if (i % 8 == 0 and i // 8 < 6) else (None, 100) for i in range(96)]) # Set liquids for every 8 wells in plate8
@@ -1314,7 +1413,6 @@ if __name__ == "__main__":
# print(plate11.get_well(0).tracker.get_used_volume()) # print(plate11.get_well(0).tracker.get_used_volume())
asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection
asyncio.run(handler.transfer_group("water", "master_mix", 10)) # Reset tip tracking asyncio.run(handler.transfer_group("water", "master_mix", 10)) # Reset tip tracking
@@ -1326,7 +1424,7 @@ if __name__ == "__main__":
# # asyncio.run(handler.run_protocol()) # # asyncio.run(handler.run_protocol())
# asyncio.run(handler.dispense([plate1.children[0]],[10],[0])) # asyncio.run(handler.dispense([plate1.children[0]],[10],[0]))
# print(plate1.children[0]) # print(plate1.children[0])
# # asyncio.run(handler.run_protocol()) # asyncio.run(handler.run_protocol())
# asyncio.run(handler.mix([plate1.children[0]], mix_time=3, mix_vol=5, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100)) # asyncio.run(handler.mix([plate1.children[0]], mix_time=3, mix_vol=5, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100))
# print(plate1.children[0]) # print(plate1.children[0])
# asyncio.run(handler.discard_tips([0])) # asyncio.run(handler.discard_tips([0]))
@@ -1421,3 +1519,28 @@ if __name__ == "__main__":
# # # input("Press Enter to continue...") # Wait for user input before proceeding # # # input("Press Enter to continue...") # Wait for user input before proceeding
# # # print("PRCXI9300Handler initialized with deck and host settings.") # # # print("PRCXI9300Handler initialized with deck and host settings.")
# 一些推荐版位组合的测试样例:
with open("prcxi_material.json", "r") as f:
material_info = json.load(f)
layout = DefaultLayout("PRCXI9320")
layout.add_lab_resource(material_info)
MatrixLayout_1 = layout.recommend_layout({
"96 细胞培养皿": 3,
"12道储液槽": 1,
"200μL Tip头": 1,
"10μL加长 Tip头": 1,
})
print(MatrixLayout_1)
MatrixLayout_2 = layout.recommend_layout({
"96深孔板": 4,
"12道储液槽": 1,
"200μL Tip头": 1,
"10μL加长 Tip头": 1,
})

View File

@@ -0,0 +1,31 @@
{
"Tip头适配器 1250uL": {"uuid": "3b6f33ffbf734014bcc20e3c63e124d4", "materialEnum": "0"},
"ZHONGXI 适配器 300uL": {"uuid": "7c822592b360451fb59690e49ac6b181", "materialEnum": "0"},
"吸头10ul 适配器": {"uuid": "8cc3dce884ac41c09f4570d0bcbfb01c", "materialEnum": "0"},
"1250μL Tip头": {"uuid": "7960f49ddfe9448abadda89bd1556936", "materialEnum": "0"},
"10μL Tip头": {"uuid": "45f2ed3ad925484d96463d675a0ebf66", "materialEnum": "0"},
"10μL加长 Tip头": {"uuid": "068b3815e36b4a72a59bae017011b29f", "materialEnum": "1"},
"1000μL Tip头": {"uuid": "80652665f6a54402b2408d50b40398df", "materialEnum": "1"},
"300μL Tip头": {"uuid": "076250742950465b9d6ea29a225dfb00", "materialEnum": "1"},
"200μL Tip头": {"uuid": "7a73bb9e5c264515a8fcbe88aed0e6f7", "materialEnum": "0"},
"0.2ml PCR板": {"uuid": "73bb9b10bc394978b70e027bf45ce2d3", "materialEnum": "0"},
"2.2ml 深孔板": {"uuid": "ca877b8b114a4310b429d1de4aae96ee", "materialEnum": "0"},
"储液槽": {"uuid": "04211a2dc93547fe9bf6121eac533650", "materialEnum": "0"},
"全裙边 PCR适配器": {"uuid": "4a043a07c65a4f9bb97745e1f129b165", "materialEnum": "3"},
"储液槽 适配器": {"uuid": "6bdfdd7069df453896b0806df50f2f4d", "materialEnum": "0"},
"300ul深孔板适配器": {"uuid": "9a439bed8f3344549643d6b3bc5a5eb4", "materialEnum": "0"},
"10ul专用深孔板适配器": {"uuid": "4dc8d6ecfd0449549683b8ef815a861b", "materialEnum": "0"},
"爱津": {"uuid": "b01627718d3341aba649baa81c2c083c", "materialEnum": "0"},
"适配器": {"uuid": "adfabfffa8f24af5abfbba67b8d0f973", "materialEnum": "0"},
"废弃槽": {"uuid": "730067cf07ae43849ddf4034299030e9", "materialEnum": "0"},
"96深孔板": {"uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": "0"},
"384板": {"uuid": "853dcfb6226f476e8b23c250217dc7da", "materialEnum": "0"},
"4道储液槽": {"uuid": "01953864f6f140ccaa8ddffd4f3e46f5", "materialEnum": "0"},
"48孔深孔板": {"uuid": "026c5d5cf3d94e56b4e16b7fb53a995b", "materialEnum": "2"},
"12道储液槽": {"uuid": "0f1639987b154e1fac78f4fb29a1f7c1", "materialEnum": "0"},
"HPLC料盘": {"uuid": "548bbc3df0d4447586f2c19d2c0c0c55", "materialEnum": "0"},
"ep适配器": {"uuid": "e146697c395e4eabb3d6b74f0dd6aaf7", "materialEnum": "0"},
"30mm适配器": {"uuid": "a0757a90d8e44e81a68f306a608694f2", "materialEnum": "0"},
"细菌培养皿": {"uuid": "b05b3b2aafd94ec38ea0cd3215ecea8f", "materialEnum": "4"},
"96 细胞培养皿":{ "uuid": "57b1e4711e9e4a32b529f3132fc5931f", "materialEnum": "0"}
}