From ceef342860e0124efa048183c303fa5b7f5cdbeb Mon Sep 17 00:00:00 2001 From: lixinyu1011 <674842481@qq.com> Date: Mon, 27 Oct 2025 18:16:26 +0800 Subject: [PATCH 1/2] 1027byxinyu --- test/resources/YB_materials_info.json | 12 + .../electrolysis_water_platfrom.py | 296 +++++++++ .../bioyond_cell/bioyond_cell_workstation.py | 24 +- .../workstation/bioyond_studio/config.py | 38 +- .../workstation/bioyond_studio/station.py | 1 + .../resources/bioyond/bottle_carriers.yaml | 126 +--- .../registry/resources/bioyond/bottles.yaml | 134 +--- .../resources/bioyond/bottle_carriers copy.py | 148 +++++ unilabos/resources/bioyond/bottle_carriers.py | 620 ------------------ unilabos/resources/bioyond/bottles copy.py | 24 + unilabos/resources/bioyond/bottles.py | 255 ------- unilabos/resources/graphio.py | 2 + 12 files changed, 508 insertions(+), 1172 deletions(-) create mode 100644 test/resources/YB_materials_info.json create mode 100644 unilabos/devices/electrolysis_water_platfrom/electrolysis_water_platfrom.py create mode 100644 unilabos/resources/bioyond/bottle_carriers copy.py delete mode 100644 unilabos/resources/bioyond/bottle_carriers.py create mode 100644 unilabos/resources/bioyond/bottles copy.py delete mode 100644 unilabos/resources/bioyond/bottles.py diff --git a/test/resources/YB_materials_info.json b/test/resources/YB_materials_info.json new file mode 100644 index 0000000..61d2de8 --- /dev/null +++ b/test/resources/YB_materials_info.json @@ -0,0 +1,12 @@ +[ + {'id': '3a1d2656-69bf-1ccf-fc38-85a0431ee498', 'typeName': '加样头(大)', 'code': '0005-00291', 'barCode': '', 'name': 'test', 'quantity': 1.0, 'lockQuantity': 0.0, 'unit': '个', 'status': 1, 'isUse': False, 'locations': [ + {'id': '3a19da56-1379-20c8-5886-f7c4fbcb5733', 'whid': '3a19da56-1378-613b-29f2-871e1a287aa5', 'whName': '粉末加样头堆栈', 'code': '0005-0003', 'x': 3, 'y': 1, 'z': 1, 'quantity': 0 + } + ], 'detail': [] + }, + {'id': '3a1d2657-d16f-a575-3506-5c029ff6810d', 'typeName': '加样头(大)', 'code': '0005-00293', 'barCode': '', 'name': 'dsfdsfd', 'quantity': 1.0, 'lockQuantity': 0.0, 'unit': '个', 'status': 1, 'isUse': False, 'locations': [ + {'id': '3a19da56-1379-e77d-0e65-7463b238a3b9', 'whid': '3a19da56-1378-613b-29f2-871e1a287aa5', 'whName': '粉末加样头堆栈', 'code': '0005-0005', 'x': 5, 'y': 1, 'z': 1, 'quantity': 0 + } + ], 'detail': [] + } +] \ No newline at end of file diff --git a/unilabos/devices/electrolysis_water_platfrom/electrolysis_water_platfrom.py b/unilabos/devices/electrolysis_water_platfrom/electrolysis_water_platfrom.py new file mode 100644 index 0000000..cfcfdee --- /dev/null +++ b/unilabos/devices/electrolysis_water_platfrom/electrolysis_water_platfrom.py @@ -0,0 +1,296 @@ +# -*- coding: utf-8 -*- +import serial +import time +import csv +import threading +import os +from collections import deque +from typing import Dict, Any, Optional +from pylabrobot.resources import Deck + +from unilabos.devices.workstation.workstation_base import WorkstationBase + + +class ElectrolysisWaterPlatform(WorkstationBase): + """ + 电解水平台工作站 + 基于 WorkstationBase 的电解水实验平台,支持串口通信和数据采集 + """ + + def __init__( + self, + deck: Deck, + port: str = "COM10", + baudrate: int = 115200, + csv_path: Optional[str] = None, + timeout: float = 0.2, + **kwargs + ): + super().__init__(deck, **kwargs) + + # ========== 配置 ========== + self.port = port + self.baudrate = baudrate + # 如果没有指定路径,默认保存在代码文件所在目录 + if csv_path is None: + current_dir = os.path.dirname(os.path.abspath(__file__)) + self.csv_path = os.path.join(current_dir, "stm32_data.csv") + else: + self.csv_path = csv_path + self.ser_timeout = timeout + self.chunk_read = 128 + + # 串口对象 + self.ser: Optional[serial.Serial] = None + self.stop_flag = False + + # 线程对象 + self.rx_thread: Optional[threading.Thread] = None + self.tx_thread: Optional[threading.Thread] = None + + # ==== 接收(下位机->上位机):固定 1+13+1 = 15 字节 ==== + self.RX_HEAD = 0x3E + self.RX_TAIL = 0x3E + self.RX_FRAME_LEN = 1 + 13 + 1 # 15 + + # ==== 发送(上位机->下位机):固定 1+9+1 = 11 字节 ==== + self.TX_HEAD = 0x3E + self.TX_TAIL = 0xE3 # 协议图中标注 E3 作为帧尾 + self.TX_FRAME_LEN = 1 + 9 + 1 # 11 + + def open_serial(self, port: Optional[str] = None, baudrate: Optional[int] = None, timeout: Optional[float] = None) -> Optional[serial.Serial]: + """打开串口""" + port = port or self.port + baudrate = baudrate or self.baudrate + timeout = timeout or self.ser_timeout + try: + ser = serial.Serial(port, baudrate, timeout=timeout) + print(f"[OK] 串口 {port} 已打开,波特率 {baudrate}") + ser.reset_input_buffer() + ser.reset_output_buffer() + self.ser = ser + return ser + except serial.SerialException as e: + print(f"[ERR] 无法打开串口 {port}: {e}") + return None + + def close_serial(self): + """关闭串口""" + if self.ser and self.ser.is_open: + self.ser.close() + print("[INFO] 串口已关闭") + + @staticmethod + def u16_be(h: int, l: int) -> int: + """将两个字节组合成16位无符号整数(大端序)""" + return ((h & 0xFF) << 8) | (l & 0xFF) + + @staticmethod + def split_u16_be(val: int) -> tuple: + """返回 (高字节, 低字节),输入会夹到 0..65535""" + v = int(max(0, min(65535, int(val)))) + return (v >> 8) & 0xFF, v & 0xFF + + # ================== 接收:固定15字节 ================== + def parse_rx_payload(self, dat13: bytes) -> Optional[Dict[str, Any]]: + """解析 13 字节数据区(下位机发送到上位机)""" + if len(dat13) != 13: + return None + current_mA = self.u16_be(dat13[0], dat13[1]) + voltage_mV = self.u16_be(dat13[2], dat13[3]) + temperature_raw = self.u16_be(dat13[4], dat13[5]) + tds_ppm = self.u16_be(dat13[6], dat13[7]) + gas_sccm = self.u16_be(dat13[8], dat13[9]) + liquid_mL = self.u16_be(dat13[10], dat13[11]) + ph_raw = dat13[12] & 0xFF + + return { + "Current_mA": current_mA, + "Voltage_mV": voltage_mV, + "Temperature_C": round(temperature_raw / 100.0, 2), + "TDS_ppm": tds_ppm, + "GasFlow_sccm": gas_sccm, + "LiquidFlow_mL": liquid_mL, + "pH": round(ph_raw / 10.0, 2) + } + + def try_parse_rx_frame(self, frame15: bytes) -> Optional[Dict[str, Any]]: + """尝试解析接收帧""" + if len(frame15) != self.RX_FRAME_LEN: + return None + if frame15[0] != self.RX_HEAD or frame15[-1] != self.RX_TAIL: + return None + return self.parse_rx_payload(frame15[1:-1]) + + def rx_thread_fn(self): + """接收线程函数""" + headers = ["Timestamp", "Current_mA", "Voltage_mV", + "Temperature_C", "TDS_ppm", "GasFlow_sccm", "LiquidFlow_mL", "pH"] + + new_file = not os.path.exists(self.csv_path) + f = open(self.csv_path, mode='a', newline='', encoding='utf-8') + writer = csv.writer(f) + if new_file: + writer.writerow(headers) + f.flush() + + buf = deque(maxlen=8192) + print(f"[RX] 开始接收(帧长 {self.RX_FRAME_LEN} 字节);写入:{self.csv_path}") + + try: + while not self.stop_flag and self.ser and self.ser.is_open: + chunk = self.ser.read(self.chunk_read) + if chunk: + buf.extend(chunk) + while True: + # 找帧头 + try: + start = next(i for i, b in enumerate(buf) if b == self.RX_HEAD) + except StopIteration: + buf.clear() + break + if start > 0: + for _ in range(start): + buf.popleft() + if len(buf) < self.RX_FRAME_LEN: + break + candidate = bytes([buf[i] for i in range(self.RX_FRAME_LEN)]) + if candidate[-1] == self.RX_TAIL: + parsed = self.try_parse_rx_frame(candidate) + for _ in range(self.RX_FRAME_LEN): + buf.popleft() + if parsed: + ts = time.strftime("%Y-%m-%d %H:%M:%S") + row = [ts, + parsed["Current_mA"], parsed["Voltage_mV"], + parsed["Temperature_C"], parsed["TDS_ppm"], + parsed["GasFlow_sccm"], parsed["LiquidFlow_mL"], + parsed["pH"]] + writer.writerow(row) + f.flush() + # 若不想打印可注释下一行 + # print(f"[{ts}] I={parsed['Current_mA']} mA, V={parsed['Voltage_mV']} mV, " + # f"T={parsed['Temperature_C']} °C, TDS={parsed['TDS_ppm']}, " + # f"Gas={parsed['GasFlow_sccm']} sccm, Liq={parsed['LiquidFlow_mL']} mL, pH={parsed['pH']}") + else: + # 头不变,尾不对,丢1字节继续对齐 + buf.popleft() + else: + time.sleep(0.01) + finally: + f.close() + print("[RX] 接收线程退出,CSV 已关闭") + + # ================== 发送:固定11字节 ================== + def build_tx_frame(self, mode: int, current_ma: int, voltage_mv: int, temp_c: float, ki: float, pump_percent: float) -> bytes: + """ + 发送帧:HEAD + [mode, I_hi, I_lo, V_hi, V_lo, T_hi, T_lo, Ki_byte, Pump_byte] + TAIL + - mode: 0=恒压, 1=恒流 + - current_ma: mA (0..65535) + - voltage_mv: mV (0..65535) + - temp_c: ℃,将 *100 后拆分为高/低字节 + - ki: 0.0..20.0 -> byte = round(ki * 10) 夹到 0..200 + - pump_percent: 0..100 -> byte = round(pump * 2) 夹到 0..200 + """ + mode_b = 1 if int(mode) == 1 else 0 + + i_hi, i_lo = self.split_u16_be(current_ma) + v_hi, v_lo = self.split_u16_be(voltage_mv) + + t100 = int(round(float(temp_c) * 100.0)) + t_hi, t_lo = self.split_u16_be(t100) + + ki_b = int(max(0, min(200, round(float(ki) * 10)))) + pump_b = int(max(0, min(200, round(float(pump_percent) * 2)))) + + return bytes(( + self.TX_HEAD, + mode_b, + i_hi, i_lo, + v_hi, v_lo, + t_hi, t_lo, + ki_b, + pump_b, + self.TX_TAIL + )) + + def tx_thread_fn(self): + """ + 发送线程函数 + 用户输入 6 个用逗号分隔的数值: + mode,current_mA,voltage_mV,set_temp_C,Ki,pump_percent + 例如: 0,1000,500,0,0,50 + """ + print("\n输入 6 个值(用英文逗号分隔),顺序为:") + print("mode,current_mA,voltage_mV,set_temp_C,Ki,pump_percent") + print("示例恒压:0,500,1000,25,0,100 (stop 结束)\n") + print("示例恒流:1,1000,500,25,0,100 (stop 结束)\n") + print("示例恒流:1,2000,500,25,0,100 (stop 结束)\n") + # 1,2000,500,25,0,100 + + while not self.stop_flag and self.ser and self.ser.is_open: + try: + line = input(">>> ").strip() + except EOFError: + self.stop_flag = True + break + + if not line: + continue + if line.lower() == "stop": + self.stop_flag = True + print("[SYS] 停止程序") + break + + try: + parts = [p.strip() for p in line.split(",")] + if len(parts) != 6: + raise ValueError("需要 6 个逗号分隔的数值") + mode = int(parts[0]) + i_ma = int(float(parts[1])) + v_mv = int(float(parts[2])) + t_c = float(parts[3]) + ki = float(parts[4]) + pump = float(parts[5]) + + frame = self.build_tx_frame(mode, i_ma, v_mv, t_c, ki, pump) + self.ser.write(frame) + print("[TX]", " ".join(f"{b:02X}" for b in frame)) + except Exception as e: + print("[TX] 输入/打包失败:", e) + print("格式:mode,current_mA,voltage_mV,set_temp_C,Ki,pump_percent") + continue + + def start(self): + """启动电解水平台""" + self.ser = self.open_serial() + if self.ser: + try: + self.rx_thread = threading.Thread(target=self.rx_thread_fn, daemon=True) + self.tx_thread = threading.Thread(target=self.tx_thread_fn, daemon=True) + self.rx_thread.start() + self.tx_thread.start() + print("[INFO] 电解水平台已启动") + self.tx_thread.join() # 等待用户输入线程结束(输入 stop) + finally: + self.close_serial() + + def stop(self): + """停止电解水平台""" + self.stop_flag = True + if self.rx_thread and self.rx_thread.is_alive(): + self.rx_thread.join(timeout=2.0) + if self.tx_thread and self.tx_thread.is_alive(): + self.tx_thread.join(timeout=2.0) + self.close_serial() + print("[INFO] 电解水平台已停止") + + +# ================== 主入口 ================== +if __name__ == "__main__": + # 创建一个简单的 Deck 用于测试 + from pylabrobot.resources import Deck + + deck = Deck() + platform = ElectrolysisWaterPlatform(deck) + platform.start() diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py index 7888039..c60a03e 100644 --- a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py +++ b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py @@ -10,7 +10,6 @@ from datetime import datetime, timedelta import re import threading import json - from urllib3 import response from unilabos.devices.workstation.workstation_base import WorkstationBase from unilabos.devices.workstation.bioyond_studio.station import BioyondWorkstation, BioyondResourceSynchronizer @@ -19,6 +18,8 @@ from unilabos.devices.workstation.bioyond_studio.config import ( ) from unilabos.devices.workstation.workstation_http_service import WorkstationHTTPService from unilabos.utils.log import logger +from unilabos.registry.registry import lab_registry + def _iso_local_now_ms() -> str: # 文档要求:到毫秒 + Z,例如 2025-08-15T05:43:22.814Z @@ -967,22 +968,23 @@ class BioyondCellWorkstation(BioyondWorkstation): if __name__ == "__main__": + lab_registry.setup() ws = BioyondCellWorkstation() - logger.info(ws.scheduler_stop()) + # logger.info(ws.scheduler_stop()) + logger.info(ws.scheduler_start()) - - results = ws.create_materials(SOLID_LIQUID_MAPPINGS) - for r in results: - logger.info(r) + # results = ws.create_materials(SOLID_LIQUID_MAPPINGS) + # for r in results: + # logger.info(r) # 从CSV文件读取物料列表并批量创建入库 - result = ws.create_and_inbound_materials() + # result = ws.create_and_inbound_materials() # 继续后续流程 - # logger.info(ws.auto_feeding4to3()) #搬运物料到3号箱 + logger.info(ws.auto_feeding4to3()) #搬运物料到3号箱 # # 使用正斜杠或 Path 对象来指定文件路径 - # excel_path = Path("unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025092701.xlsx") - # logger.info(ws.create_orders(excel_path)) - # logger.info(ws.transfer_3_to_2_to_1()) + excel_path = Path("unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025092701.xlsx") + logger.info(ws.create_orders(excel_path)) + logger.info(ws.transfer_3_to_2_to_1()) # logger.info(ws.transfer_1_to_2()) # logger.info(ws.scheduler_start()) diff --git a/unilabos/devices/workstation/bioyond_studio/config.py b/unilabos/devices/workstation/bioyond_studio/config.py index 3bf6250..81a9736 100644 --- a/unilabos/devices/workstation/bioyond_studio/config.py +++ b/unilabos/devices/workstation/bioyond_studio/config.py @@ -5,13 +5,10 @@ import os # ==================== API 基础配置 ==================== - - -# ==================== 完整的 Bioyond 配置 ==================== # BioyondCellWorkstation 默认配置(包含所有必需参数) API_CONFIG = { # API 连接配置 - "api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.11.219:44388"), + "api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.10.169:44388"), "api_key": os.getenv("BIOYOND_API_KEY", "8A819E5C"), "timeout": int(os.getenv("BIOYOND_TIMEOUT", "30")), @@ -19,11 +16,9 @@ API_CONFIG = { "report_token": os.getenv("BIOYOND_REPORT_TOKEN", "CHANGE_ME_TOKEN"), # HTTP 服务配置 - "HTTP_host": os.getenv("BIOYOND_HTTP_HOST", "0.0.0.0"), # HTTP服务监听地址(0.0.0.0 表示监听所有网络接口) + "HTTP_host": os.getenv("BIOYOND_HTTP_HOST", "172.21.32.91"), # HTTP服务监听地址,监听计算机飞连ip地址 "HTTP_port": int(os.getenv("BIOYOND_HTTP_PORT", "8080")), - "report_ip": os.getenv("BIOYOND_REPORT_IP", "172.21.32.172"), # 报送给 Bioyond 的本机IP地址(留空则自动检测) - # 调试模式 - "debug_mode": False, + "debug_mode": False,# 调试模式 } # 库位映射配置 @@ -57,29 +52,10 @@ WAREHOUSE_MAPPING = { # 物料类型配置 MATERIAL_TYPE_MAPPINGS = { - "烧杯": ("BIOYOND_PolymerStation_1FlaskCarrier", "3a14196b-24f2-ca49-9081-0cab8021bf1a"), - "试剂瓶": ("BIOYOND_PolymerStation_1BottleCarrier", ""), - "样品板": ("BIOYOND_PolymerStation_6StockCarrier", "3a14196e-b7a0-a5da-1931-35f3000281e9"), - "分装板": ("BIOYOND_PolymerStation_6VialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"), - "样品瓶": ("BIOYOND_PolymerStation_Solid_Stock", "3a14196a-cf7d-8aea-48d8-b9662c7dba94"), - "90%分装小瓶": ("BIOYOND_PolymerStation_Solid_Vial", "3a14196c-cdcf-088d-dc7d-5cf38f0ad9ea"), - "10%分装小瓶": ("BIOYOND_PolymerStation_Liquid_Vial", "3a14196c-76be-2279-4e22-7310d69aed68"), - "20ml分液瓶": ("BIOYOND_PolymerStation_6x20ml_DispensingVialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"), - "100ml液体": ("BIOYOND_PolymerStation_100ml_Liquid_Bottle", "d37166b3-ecaa-481e-bd84-3032b795ba07"), - "液": ("BIOYOND_PolymerStation_Liquid_Bottle", "3a190ca1-2add-2b23-f8e1-bbd348b7f790"), - "高粘液": ("BIOYOND_PolymerStation_High_Viscosity_Liquid_Bottle", "abe8df30-563d-43d2-85e0-cabec59ddc16"), - "加样头(大)": ("BIOYOND_PolymerStation_Large_Dispense_Head", "3a190ca0-b2f6-9aeb-8067-547e72c11469"), - "5ml分液瓶板": ("BIOYOND_PolymerStation_6x5ml_DispensingVialCarrier", "3a192fa4-007d-ec7b-456e-2a8be7a13f23"), - "5ml分液瓶": ("BIOYOND_PolymerStation_5ml_Dispensing_Vial", "3a192c2a-ebb7-58a1-480d-8b3863bf74f4"), - "20ml分液瓶板": ("BIOYOND_PolymerStation_6x20ml_DispensingVialCarrier", "3a192fa4-47db-3449-162a-eaf8aba57e27"), - "配液瓶(小)板": ("BIOYOND_PolymerStation_6x_SmallSolutionBottleCarrier", "3a190c8b-3284-af78-d29f-9a69463ad047"), - "配液瓶(小)": ("BIOYOND_PolymerStation_Small_Solution_Bottle", "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"), - "配液瓶(大)板": ("BIOYOND_PolymerStation_4x_LargeSolutionBottleCarrier", "53e50377-32dc-4781-b3c0-5ce45bc7dc27"), - "配液瓶(大)": ("BIOYOND_PolymerStation_Large_Solution_Bottle", "19c52ad1-51c5-494f-8854-576f4ca9c6ca"), - "加样头(大)板": ("BIOYOND_PolymerStation_6x_LargeDispenseHeadCarrier", "a8e714ae-2a4e-4eb9-9614-e4c140ec3f16"), - "适配器块": ("BIOYOND_PolymerStation_AdapterBlock", "efc3bb32-d504-4890-91c0-b64ed3ac80cf"), - "枪头盒": ("BIOYOND_PolymerStation_TipBox", "3a192c2e-20f3-a44a-0334-c8301839d0b3"), - "枪头": ("BIOYOND_PolymerStation_Pipette_Tip", "b6196971-1050-46da-9927-333e8dea062d"), + + "加样头(大)": ("YB_jia_yang_tou_da", "3a190ca0-b2f6-9aeb-8067-547e72c11469"), + "加样头(大)板": ("YB_jia_yang_tou_da_1X1_carrier", "a8e714ae-2a4e-4eb9-9614-e4c140ec3f16"), + # YB信息 } SOLID_LIQUID_MAPPINGS = { diff --git a/unilabos/devices/workstation/bioyond_studio/station.py b/unilabos/devices/workstation/bioyond_studio/station.py index 795b740..3ce7353 100644 --- a/unilabos/devices/workstation/bioyond_studio/station.py +++ b/unilabos/devices/workstation/bioyond_studio/station.py @@ -74,6 +74,7 @@ class BioyondResourceSynchronizer(ResourceSynchronizer): type_mapping=self.workstation.bioyond_config["material_type_mappings"], deck=self.workstation.deck ) + print("unilab_resources:",unilab_resources) logger.info(f"从Bioyond同步了 {len(unilab_resources)} 个资源") return True diff --git a/unilabos/registry/resources/bioyond/bottle_carriers.yaml b/unilabos/registry/resources/bioyond/bottle_carriers.yaml index 5889bcc..ac01cc3 100644 --- a/unilabos/registry/resources/bioyond/bottle_carriers.yaml +++ b/unilabos/registry/resources/bioyond/bottle_carriers.yaml @@ -1,130 +1,10 @@ -1BottleCarrier: - category: - - bottle_carriers - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_1BottleCarrier - type: pylabrobot - description: 1BottleCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -1FlaskCarrier: - category: - - bottle_carriers - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_1FlaskCarrier - type: pylabrobot - description: 1FlaskCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -6StockCarrier: - category: - - bottle_carriers - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_6StockCarrier - type: pylabrobot - description: 6StockCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -6VialCarrier: - category: - - bottle_carriers - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_6VialCarrier - type: pylabrobot - description: 6VialCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -6x5ml_DispensingVialCarrier: +YB_jia_yang_tou_da_1X1_carrier: category: - yb3 class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_6x5ml_DispensingVialCarrier + module: unilabos.resources.bioyond.bottle_carriers:YB_jia_yang_tou_da_1X1_carrier type: pylabrobot - description: 6x5ml_DispensingVialCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -6x20ml_DispensingVialCarrier: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_6x20ml_DispensingVialCarrier - type: pylabrobot - description: 6x20ml_DispensingVialCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -6x_SmallSolutionBottleCarrier: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_6x_SmallSolutionBottleCarrier - type: pylabrobot - description: 6x_SmallSolutionBottleCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -4x_LargeSolutionBottleCarrier: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_4x_LargeSolutionBottleCarrier - type: pylabrobot - description: 4x_LargeSolutionBottleCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -6x_LargeDispenseHeadCarrier: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_6x_LargeDispenseHeadCarrier - type: pylabrobot - description: 6x_LargeDispenseHeadCarrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -AdapterBlock: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_AdapterBlock - type: pylabrobot - description: AdapterBlock - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 -TipBox: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottle_carriers:BIOYOND_PolymerStation_TipBox - type: pylabrobot - description: TipBox + description: YB_jia_yang_tou_da_1X1_carrier handles: [] icon: '' init_param_schema: {} diff --git a/unilabos/registry/resources/bioyond/bottles.yaml b/unilabos/registry/resources/bioyond/bottles.yaml index 8d71f28..556b5f8 100644 --- a/unilabos/registry/resources/bioyond/bottles.yaml +++ b/unilabos/registry/resources/bioyond/bottles.yaml @@ -1,138 +1,8 @@ -Liquid_Vial: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Liquid_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Reagent_Bottle: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Reagent_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Solid_Stock: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Solid_Stock - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Solid_Vial: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Solid_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Solution_Beaker: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Solution_Beaker - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -100ml_Liquid_Bottle: +YB_jia_yang_tou_da: category: - yb3 class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_100ml_Liquid_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Liquid_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Liquid_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -High_Viscosity_Liquid_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_High_Viscosity_Liquid_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Large_Dispense_Head: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Large_Dispense_Head - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -5ml_Dispensing_Vial: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_5ml_Dispensing_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -20ml_Dispensing_Vial: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_20ml_Dispensing_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Small_Solution_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Small_Solution_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Large_Solution_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Large_Solution_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -Pipette_Tip: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_Pipette_Tip + module: unilabos.resources.bioyond.bottles:YB_jia_yang_tou_da type: pylabrobot handles: [] icon: '' diff --git a/unilabos/resources/bioyond/bottle_carriers copy.py b/unilabos/resources/bioyond/bottle_carriers copy.py new file mode 100644 index 0000000..a3b0044 --- /dev/null +++ b/unilabos/resources/bioyond/bottle_carriers copy.py @@ -0,0 +1,148 @@ +from pylabrobot.resources import create_homogeneous_resources, Coordinate, ResourceHolder, create_ordered_items_2d + +from unilabos.resources.itemized_carrier import Bottle, BottleCarrier +from unilabos.resources.bioyond.bottles import ( + YB_jia_yang_tou_da, +) +# 命名约定:试剂瓶-Bottle,烧杯-Beaker,烧瓶-Flask,小瓶-Vial + + + + + +def YB_jia_yang_tou_da_1X1_carrier(name: str) -> BottleCarrier: + """加样头(大)板 - 1x1布局,1个位置""" + + # 载架尺寸 (mm) + carrier_size_x = 127.8 + carrier_size_y = 85.5 + carrier_size_z = 95.0 + + # 瓶位尺寸 + bottle_diameter = 35.0 + bottle_spacing_x = 42.0 # X方向间距 + bottle_spacing_y = 35.0 # Y方向间距 + + # 计算起始位置 (居中排列) + start_x = (carrier_size_x - (1 - 1) * bottle_spacing_x - bottle_diameter) / 2 + start_y = (carrier_size_y - (1 - 1) * bottle_spacing_y - bottle_diameter) / 2 + + sites = create_ordered_items_2d( + klass=ResourceHolder, + num_items_x=1, + num_items_y=1, + dx=start_x, + dy=start_y, + dz=5.0, + item_dx=bottle_spacing_x, + item_dy=bottle_spacing_y, + size_x=bottle_diameter, + size_y=bottle_diameter, + size_z=carrier_size_z, + ) + for k, v in sites.items(): + v.name = f"{name}_{v.name}" + + carrier = BottleCarrier( + name=name, + size_x=carrier_size_x, + size_y=carrier_size_y, + size_z=carrier_size_z, + sites=sites, + model="YB_1X1_jia_yang_tou_da_carrier", + ) + carrier.num_items_x = 1 + carrier.num_items_y = 1 + carrier.num_items_z = 1 + carrier[0] = YB_jia_yang_tou_da(f"{name}_head_1") + return carrier + + +def BIOYOND_PolymerStation_AdapterBlock(name: str) -> BottleCarrier: + """适配器块 - 单个中央位置""" + + # 载架尺寸 (mm) + carrier_size_x = 127.8 + carrier_size_y = 85.5 + carrier_size_z = 30.0 + + # 适配器尺寸 + adapter_diameter = 80.0 + + # 计算中央位置 + center_x = (carrier_size_x - adapter_diameter) / 2 + center_y = (carrier_size_y - adapter_diameter) / 2 + center_z = 0.0 + + carrier = BottleCarrier( + name=name, + size_x=carrier_size_x, + size_y=carrier_size_y, + size_z=carrier_size_z, + sites=create_homogeneous_resources( + klass=ResourceHolder, + locations=[Coordinate(center_x, center_y, center_z)], + resource_size_x=adapter_diameter, + resource_size_y=adapter_diameter, + name_prefix=name, + ), + model="AdapterBlock", + ) + carrier.num_items_x = 1 + carrier.num_items_y = 1 + carrier.num_items_z = 1 + # 适配器块本身不包含瓶子,只是一个支撑结构 + return carrier + + +def BIOYOND_PolymerStation_TipBox(name: str) -> BottleCarrier: + """枪头盒 - 8x12布局,96个位置""" + + # 载架尺寸 (mm) + carrier_size_x = 127.8 + carrier_size_y = 85.5 + carrier_size_z = 55.0 + + # 枪头尺寸 + tip_diameter = 10.0 + tip_spacing_x = 9.0 # X方向间距 + tip_spacing_y = 9.0 # Y方向间距 + + # 计算起始位置 (居中排列) + start_x = (carrier_size_x - (12 - 1) * tip_spacing_x - tip_diameter) / 2 + start_y = (carrier_size_y - (8 - 1) * tip_spacing_y - tip_diameter) / 2 + + sites = create_ordered_items_2d( + klass=ResourceHolder, + num_items_x=12, + num_items_y=8, + dx=start_x, + dy=start_y, + dz=5.0, + item_dx=tip_spacing_x, + item_dy=tip_spacing_y, + size_x=tip_diameter, + size_y=tip_diameter, + size_z=carrier_size_z, + ) + for k, v in sites.items(): + v.name = f"{name}_{v.name}" + + carrier = BottleCarrier( + name=name, + size_x=carrier_size_x, + size_y=carrier_size_y, + size_z=carrier_size_z, + sites=sites, + model="TipBox", + ) + carrier.num_items_x = 12 + carrier.num_items_y = 8 + carrier.num_items_z = 1 + # 创建96个枪头 + for i in range(96): + row = chr(65 + i // 12) # A-H + col = (i % 12) + 1 # 1-12 + carrier[i] = BIOYOND_PolymerStation_Pipette_Tip(f"{name}_tip_{row}{col}") + return carrier + diff --git a/unilabos/resources/bioyond/bottle_carriers.py b/unilabos/resources/bioyond/bottle_carriers.py deleted file mode 100644 index ab0b656..0000000 --- a/unilabos/resources/bioyond/bottle_carriers.py +++ /dev/null @@ -1,620 +0,0 @@ -from pylabrobot.resources import create_homogeneous_resources, Coordinate, ResourceHolder, create_ordered_items_2d - -from unilabos.resources.itemized_carrier import Bottle, BottleCarrier -from unilabos.resources.bioyond.bottles import ( - BIOYOND_PolymerStation_Solid_Stock, - BIOYOND_PolymerStation_Solid_Vial, - BIOYOND_PolymerStation_Liquid_Vial, - BIOYOND_PolymerStation_Solution_Beaker, - BIOYOND_PolymerStation_Reagent_Bottle, - BIOYOND_PolymerStation_5ml_Dispensing_Vial, - BIOYOND_PolymerStation_20ml_Dispensing_Vial, - BIOYOND_PolymerStation_Small_Solution_Bottle, - BIOYOND_PolymerStation_Large_Solution_Bottle, - BIOYOND_PolymerStation_Large_Dispense_Head, - BIOYOND_PolymerStation_Pipette_Tip -) -# 命名约定:试剂瓶-Bottle,烧杯-Beaker,烧瓶-Flask,小瓶-Vial - - -def BIOYOND_Electrolyte_6VialCarrier(name: str) -> BottleCarrier: - """6瓶载架 - 2x3布局""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 50.0 - - # 瓶位尺寸 - bottle_diameter = 30.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (3 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=3, - num_items_y=2, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="Electrolyte_6VialCarrier", - ) - carrier.num_items_x = 3 - carrier.num_items_y = 2 - carrier.num_items_z = 1 - for i in range(6): - carrier[i] = BIOYOND_PolymerStation_Solid_Vial(f"{name}_vial_{i+1}") - return carrier - - -def BIOYOND_Electrolyte_1BottleCarrier(name: str) -> BottleCarrier: - """1瓶载架 - 单个中央位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 100.0 - - # 烧杯尺寸 - beaker_diameter = 80.0 - - # 计算中央位置 - center_x = (carrier_size_x - beaker_diameter) / 2 - center_y = (carrier_size_y - beaker_diameter) / 2 - center_z = 5.0 - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=create_homogeneous_resources( - klass=ResourceHolder, - locations=[Coordinate(center_x, center_y, center_z)], - resource_size_x=beaker_diameter, - resource_size_y=beaker_diameter, - name_prefix=name, - ), - model="Electrolyte_1BottleCarrier", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - carrier[0] = BIOYOND_PolymerStation_Solution_Beaker(f"{name}_beaker_1") - return carrier - - -def BIOYOND_PolymerStation_6StockCarrier(name: str) -> BottleCarrier: - """6瓶载架 - 2x3布局""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 50.0 - - # 瓶位尺寸 - bottle_diameter = 20.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (3 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=3, - num_items_y=2, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="6StockCarrier", - ) - carrier.num_items_x = 3 - carrier.num_items_y = 2 - carrier.num_items_z = 1 - ordering = ["A1", "A2", "A3", "B1", "B2", "B3"] # 自定义顺序 - for i in range(6): - carrier[i] = BIOYOND_PolymerStation_Solid_Stock(f"{name}_vial_{ordering[i]}") - return carrier - - -def BIOYOND_PolymerStation_6VialCarrier(name: str) -> BottleCarrier: - """6瓶载架 - 2x3布局""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 50.0 - - # 瓶位尺寸 - bottle_diameter = 30.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (3 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=3, - num_items_y=2, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="6VialCarrier", - ) - carrier.num_items_x = 3 - carrier.num_items_y = 2 - carrier.num_items_z = 1 - ordering = ["A1", "A2", "A3", "B1", "B2", "B3"] # 自定义顺序 - for i in range(3): - carrier[i] = BIOYOND_PolymerStation_Solid_Vial(f"{name}_solidvial_{ordering[i]}") - for i in range(3, 6): - carrier[i] = BIOYOND_PolymerStation_Liquid_Vial(f"{name}_liquidvial_{ordering[i]}") - return carrier - - -def BIOYOND_PolymerStation_1BottleCarrier(name: str) -> BottleCarrier: - """1瓶载架 - 单个中央位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 20.0 - - # 烧杯尺寸 - beaker_diameter = 60.0 - - # 计算中央位置 - center_x = (carrier_size_x - beaker_diameter) / 2 - center_y = (carrier_size_y - beaker_diameter) / 2 - center_z = 5.0 - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=create_homogeneous_resources( - klass=ResourceHolder, - locations=[Coordinate(center_x, center_y, center_z)], - resource_size_x=beaker_diameter, - resource_size_y=beaker_diameter, - name_prefix=name, - ), - model="1BottleCarrier", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - carrier[0] = BIOYOND_PolymerStation_Reagent_Bottle(f"{name}_flask_1") - return carrier - - -def BIOYOND_PolymerStation_1FlaskCarrier(name: str) -> BottleCarrier: - """1瓶载架 - 单个中央位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 20.0 - - # 烧杯尺寸 - beaker_diameter = 70.0 - - # 计算中央位置 - center_x = (carrier_size_x - beaker_diameter) / 2 - center_y = (carrier_size_y - beaker_diameter) / 2 - center_z = 5.0 - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=create_homogeneous_resources( - klass=ResourceHolder, - locations=[Coordinate(center_x, center_y, center_z)], - resource_size_x=beaker_diameter, - resource_size_y=beaker_diameter, - name_prefix=name, - ), - model="1FlaskCarrier", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - carrier[0] = BIOYOND_PolymerStation_Reagent_Bottle(f"{name}_bottle_1") - return carrier - - -def BIOYOND_PolymerStation_6x5ml_DispensingVialCarrier(name: str) -> BottleCarrier: - """5ml分液瓶板 - 4x2布局,8个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 50.0 - - # 瓶位尺寸 - bottle_diameter = 15.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (4 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=4, - num_items_y=2, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="6x5ml_DispensingVialCarrier", - ) - carrier.num_items_x = 4 - carrier.num_items_y = 2 - carrier.num_items_z = 1 - ordering = ["A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4"] - for i in range(8): - carrier[i] = BIOYOND_PolymerStation_5ml_Dispensing_Vial(f"{name}_vial_{ordering[i]}") - return carrier - - -def BIOYOND_PolymerStation_6x20ml_DispensingVialCarrier(name: str) -> BottleCarrier: - """20ml分液瓶板 - 4x2布局,8个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 70.0 - - # 瓶位尺寸 - bottle_diameter = 20.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (4 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=4, - num_items_y=2, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="6x20ml_DispensingVialCarrier", - ) - carrier.num_items_x = 4 - carrier.num_items_y = 2 - carrier.num_items_z = 1 - ordering = ["A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4"] - for i in range(8): - carrier[i] = BIOYOND_PolymerStation_20ml_Dispensing_Vial(f"{name}_vial_{ordering[i]}") - return carrier - - -def BIOYOND_PolymerStation_6x_SmallSolutionBottleCarrier(name: str) -> BottleCarrier: - """配液瓶(小)板 - 4x2布局,8个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 65.0 - - # 瓶位尺寸 - bottle_diameter = 35.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (4 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=4, - num_items_y=2, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="6x_SmallSolutionBottleCarrier", - ) - carrier.num_items_x = 4 - carrier.num_items_y = 2 - carrier.num_items_z = 1 - ordering = ["A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4"] - for i in range(8): - carrier[i] = BIOYOND_PolymerStation_Small_Solution_Bottle(f"{name}_bottle_{ordering[i]}") - return carrier - - -def BIOYOND_PolymerStation_4x_LargeSolutionBottleCarrier(name: str) -> BottleCarrier: - """配液瓶(大)板 - 2x2布局,4个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 95.0 - - # 瓶位尺寸 - bottle_diameter = 55.0 - bottle_spacing_x = 60.0 # X方向间距 - bottle_spacing_y = 60.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (2 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=2, - num_items_y=2, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="4x_LargeSolutionBottleCarrier", - ) - carrier.num_items_x = 2 - carrier.num_items_y = 2 - carrier.num_items_z = 1 - ordering = ["A1", "A2", "B1", "B2"] - for i in range(4): - carrier[i] = BIOYOND_PolymerStation_Large_Solution_Bottle(f"{name}_bottle_{ordering[i]}") - return carrier - - -def BIOYOND_PolymerStation_6x_LargeDispenseHeadCarrier(name: str) -> BottleCarrier: - """加样头(大)板 - 1x1布局,1个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 95.0 - - # 瓶位尺寸 - bottle_diameter = 35.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (1 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (1 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=1, - num_items_y=1, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="6x_LargeDispenseHeadCarrier", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - carrier[0] = BIOYOND_PolymerStation_Large_Dispense_Head(f"{name}_head_1") - return carrier - - -def BIOYOND_PolymerStation_AdapterBlock(name: str) -> BottleCarrier: - """适配器块 - 单个中央位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 30.0 - - # 适配器尺寸 - adapter_diameter = 80.0 - - # 计算中央位置 - center_x = (carrier_size_x - adapter_diameter) / 2 - center_y = (carrier_size_y - adapter_diameter) / 2 - center_z = 0.0 - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=create_homogeneous_resources( - klass=ResourceHolder, - locations=[Coordinate(center_x, center_y, center_z)], - resource_size_x=adapter_diameter, - resource_size_y=adapter_diameter, - name_prefix=name, - ), - model="AdapterBlock", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - # 适配器块本身不包含瓶子,只是一个支撑结构 - return carrier - - -def BIOYOND_PolymerStation_TipBox(name: str) -> BottleCarrier: - """枪头盒 - 8x12布局,96个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 55.0 - - # 枪头尺寸 - tip_diameter = 10.0 - tip_spacing_x = 9.0 # X方向间距 - tip_spacing_y = 9.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (12 - 1) * tip_spacing_x - tip_diameter) / 2 - start_y = (carrier_size_y - (8 - 1) * tip_spacing_y - tip_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=12, - num_items_y=8, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=tip_spacing_x, - item_dy=tip_spacing_y, - size_x=tip_diameter, - size_y=tip_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="TipBox", - ) - carrier.num_items_x = 12 - carrier.num_items_y = 8 - carrier.num_items_z = 1 - # 创建96个枪头 - for i in range(96): - row = chr(65 + i // 12) # A-H - col = (i % 12) + 1 # 1-12 - carrier[i] = BIOYOND_PolymerStation_Pipette_Tip(f"{name}_tip_{row}{col}") - return carrier - diff --git a/unilabos/resources/bioyond/bottles copy.py b/unilabos/resources/bioyond/bottles copy.py new file mode 100644 index 0000000..2504c37 --- /dev/null +++ b/unilabos/resources/bioyond/bottles copy.py @@ -0,0 +1,24 @@ +from unilabos.resources.itemized_carrier import Bottle, BottleCarrier +# 工厂函数 + + +def YB_jia_yang_tou_da( + name: str, + diameter: float = 35.0, + height: float = 90.0, + max_volume: float = 50000.0, # 50mL + code: str = None, + barcode: str = None, +) -> Bottle: + """创建加样头(大)""" + return Bottle( + name=name, + diameter=diameter, + height=height, + max_volume=max_volume, + barcode=barcode, + code=code, + model="YB_jia_yang_tou_da", + ) + + diff --git a/unilabos/resources/bioyond/bottles.py b/unilabos/resources/bioyond/bottles.py deleted file mode 100644 index 40cb9ef..0000000 --- a/unilabos/resources/bioyond/bottles.py +++ /dev/null @@ -1,255 +0,0 @@ -from unilabos.resources.itemized_carrier import Bottle, BottleCarrier -# 工厂函数 - - -def BIOYOND_PolymerStation_Solid_Stock( - name: str, - diameter: float = 20.0, - height: float = 100.0, - max_volume: float = 30000.0, # 30mL - barcode: str = None, -) -> Bottle: - """创建粉末瓶""" - return Bottle( - name=name, - diameter=diameter,# 未知 - height=height, - max_volume=max_volume, - barcode=barcode, - model="Solid_Stock", - ) - - -def BIOYOND_PolymerStation_Solid_Vial( - name: str, - diameter: float = 25.0, - height: float = 60.0, - max_volume: float = 30000.0, # 30mL - barcode: str = None, -) -> Bottle: - """创建粉末瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Solid_Vial", - ) - - -def BIOYOND_PolymerStation_Liquid_Vial( - name: str, - diameter: float = 25.0, - height: float = 60.0, - max_volume: float = 30000.0, # 30mL - barcode: str = None, -) -> Bottle: - """创建滴定液瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Liquid_Vial", - ) - - -def BIOYOND_PolymerStation_Solution_Beaker( - name: str, - diameter: float = 60.0, - height: float = 70.0, - max_volume: float = 200000.0, # 200mL - barcode: str = None, -) -> Bottle: - """创建溶液烧杯""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Solution_Beaker", - ) - - -def BIOYOND_PolymerStation_Reagent_Bottle( - name: str, - diameter: float = 70.0, - height: float = 120.0, - max_volume: float = 500000.0, # 500mL - barcode: str = None, -) -> Bottle: - """创建试剂瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Reagent_Bottle", - ) - - -def BIOYOND_PolymerStation_100ml_Liquid_Bottle( - name: str, - diameter: float = 50.0, - height: float = 80.0, - max_volume: float = 100000.0, # 100mL - barcode: str = None, -) -> Bottle: - """创建100ml液体瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="100ml_Liquid_Bottle", - ) - - -def BIOYOND_PolymerStation_Liquid_Bottle( - name: str, - diameter: float = 40.0, - height: float = 70.0, - max_volume: float = 50000.0, # 50mL - barcode: str = None, -) -> Bottle: - """创建液体瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Liquid_Bottle", - ) - - -def BIOYOND_PolymerStation_High_Viscosity_Liquid_Bottle( - name: str, - diameter: float = 45.0, - height: float = 75.0, - max_volume: float = 60000.0, # 60mL - barcode: str = None, -) -> Bottle: - """创建高粘液瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="High_Viscosity_Liquid_Bottle", - ) - - -def BIOYOND_PolymerStation_Large_Dispense_Head( - name: str, - diameter: float = 35.0, - height: float = 90.0, - max_volume: float = 50000.0, # 50mL - barcode: str = None, -) -> Bottle: - """创建加样头(大)""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Large_Dispense_Head", - ) - - -def BIOYOND_PolymerStation_5ml_Dispensing_Vial( - name: str, - diameter: float = 15.0, - height: float = 45.0, - max_volume: float = 5000.0, # 5mL - barcode: str = None, -) -> Bottle: - """创建5ml分液瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="5ml_Dispensing_Vial", - ) - - -def BIOYOND_PolymerStation_20ml_Dispensing_Vial( - name: str, - diameter: float = 20.0, - height: float = 65.0, - max_volume: float = 20000.0, # 20mL - barcode: str = None, -) -> Bottle: - """创建20ml分液瓶""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="20ml_Dispensing_Vial", - ) - - -def BIOYOND_PolymerStation_Small_Solution_Bottle( - name: str, - diameter: float = 35.0, - height: float = 60.0, - max_volume: float = 40000.0, # 40mL - barcode: str = None, -) -> Bottle: - """创建配液瓶(小)""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Small_Solution_Bottle", - ) - - -def BIOYOND_PolymerStation_Large_Solution_Bottle( - name: str, - diameter: float = 55.0, - height: float = 90.0, - max_volume: float = 150000.0, # 150mL - barcode: str = None, -) -> Bottle: - """创建配液瓶(大)""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Large_Solution_Bottle", - ) - - -def BIOYOND_PolymerStation_Pipette_Tip( - name: str, - diameter: float = 10.0, - height: float = 50.0, - max_volume: float = 1000.0, # 1mL - barcode: str = None, -) -> Bottle: - """创建枪头""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - model="Pipette_Tip", - ) - diff --git a/unilabos/resources/graphio.py b/unilabos/resources/graphio.py index bca92c9..92fcf1e 100644 --- a/unilabos/resources/graphio.py +++ b/unilabos/resources/graphio.py @@ -636,6 +636,8 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st plr_material: ResourcePLR = initialize_resource( {"name": material["name"], "class": className}, resource_type=ResourcePLR ) + print("plr_material:",plr_material) + print("code:",material.get("code", "")) plr_material.code = material.get("code", "") and material.get("barCode", "") or "" plr_material.unilabos_uuid = str(uuid.uuid4()) From 3231d606465292417f25b49143f1265ba832a5d1 Mon Sep 17 00:00:00 2001 From: lixinyu1011 <674842481@qq.com> Date: Mon, 27 Oct 2025 20:08:19 +0800 Subject: [PATCH 2/2] 1027by_Xinyu --- test/resources/YB_materials_info.json | 52 +++++- test/resources/test_resourcetreeset.py | 24 +-- .../bioyond_cell/bioyond_cell_workstation.py | 10 +- .../bioyond_cell/样品导入模板.xlsx | Bin 22007 -> 9686 bytes .../workstation/bioyond_studio/config.py | 4 +- .../workstation/bioyond_studio/station.py | 2 +- .../resources/bioyond/YB_bottle_carriers.yaml | 25 +++ .../resources/bioyond/bottle_carriers.yaml | 12 -- .../registry/resources/bioyond/bottles.yaml | 151 ----------------- ...ttle_carriers.py => YB_bottle_carriers.py} | 79 ++------- unilabos/resources/bioyond/YB_bottles.py | 38 +++++ unilabos/resources/bioyond/YB_warehouses.py | 160 ++++++++++++++++++ .../resources/bioyond/bottle_carriers copy.py | 148 ---------------- unilabos/resources/bioyond/bottles copy.py | 24 --- 14 files changed, 307 insertions(+), 422 deletions(-) create mode 100644 unilabos/registry/resources/bioyond/YB_bottle_carriers.yaml delete mode 100644 unilabos/registry/resources/bioyond/bottle_carriers.yaml delete mode 100644 unilabos/registry/resources/bioyond/bottles.yaml rename unilabos/resources/bioyond/{bottle_carriers.py => YB_bottle_carriers.py} (89%) create mode 100644 unilabos/resources/bioyond/YB_bottles.py create mode 100644 unilabos/resources/bioyond/YB_warehouses.py delete mode 100644 unilabos/resources/bioyond/bottle_carriers copy.py delete mode 100644 unilabos/resources/bioyond/bottles copy.py diff --git a/test/resources/YB_materials_info.json b/test/resources/YB_materials_info.json index 61d2de8..d5bc381 100644 --- a/test/resources/YB_materials_info.json +++ b/test/resources/YB_materials_info.json @@ -1,12 +1,52 @@ [ - {'id': '3a1d2656-69bf-1ccf-fc38-85a0431ee498', 'typeName': '加样头(大)', 'code': '0005-00291', 'barCode': '', 'name': 'test', 'quantity': 1.0, 'lockQuantity': 0.0, 'unit': '个', 'status': 1, 'isUse': False, 'locations': [ - {'id': '3a19da56-1379-20c8-5886-f7c4fbcb5733', 'whid': '3a19da56-1378-613b-29f2-871e1a287aa5', 'whName': '粉末加样头堆栈', 'code': '0005-0003', 'x': 3, 'y': 1, 'z': 1, 'quantity': 0 + { + "id": "3a1d377b-299d-d0f2-ced9-48257f60dfad", + "typeName": "加样头(大)", + "code": "0005-00145", + "barCode": "", + "name": "LiDFOB", + "quantity": 9999.0, + "lockQuantity": 0.0, + "unit": "个", + "status": 1, + "isUse": false, + "locations": [ + { + "id": "3a19da56-1379-ff7c-1745-07e200b44ce2", + "whid": "3a19da56-1378-613b-29f2-871e1a287aa5", + "whName": "粉末加样头堆栈", + "code": "0005-0001", + "x": 1, + "y": 1, + "z": 1, + "quantity": 0 } - ], 'detail': [] + ], + "detail": [] }, - {'id': '3a1d2657-d16f-a575-3506-5c029ff6810d', 'typeName': '加样头(大)', 'code': '0005-00293', 'barCode': '', 'name': 'dsfdsfd', 'quantity': 1.0, 'lockQuantity': 0.0, 'unit': '个', 'status': 1, 'isUse': False, 'locations': [ - {'id': '3a19da56-1379-e77d-0e65-7463b238a3b9', 'whid': '3a19da56-1378-613b-29f2-871e1a287aa5', 'whName': '粉末加样头堆栈', 'code': '0005-0005', 'x': 5, 'y': 1, 'z': 1, 'quantity': 0 + { + "id": "3a1d377b-6a81-6a7e-147c-f89f6463656d", + "typeName": "液", + "code": "0006-00141", + "barCode": "", + "name": "EMC", + "quantity": 99999.0, + "lockQuantity": 0.0, + "unit": "g", + "status": 1, + "isUse": false, + "locations": [ + { + "id": "3a1baa20-a7b1-c665-8b9c-d8099d07d2f6", + "whid": "3a1baa20-a7b0-5c19-8844-5de8924d4e78", + "whName": "4号手套箱内部堆栈", + "code": "0015-0001", + "x": 1, + "y": 1, + "z": 1, + "quantity": 0 } - ], 'detail': [] + ], + "detail": [] } ] \ No newline at end of file diff --git a/test/resources/test_resourcetreeset.py b/test/resources/test_resourcetreeset.py index ff5cfd0..b7602ed 100644 --- a/test/resources/test_resourcetreeset.py +++ b/test/resources/test_resourcetreeset.py @@ -1,3 +1,4 @@ +from ast import If import pytest import json import os @@ -13,13 +14,8 @@ lab_registry.setup() type_mapping = { - "烧杯": ("YB_1FlaskCarrier", "3a14196b-24f2-ca49-9081-0cab8021bf1a"), - "试剂瓶": ("YB_1BottleCarrier", ""), - "样品板": ("YB_6StockCarrier", "3a14196e-b7a0-a5da-1931-35f3000281e9"), - "分装板": ("YB_6VialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"), - "样品瓶": ("YB_Solid_Stock", "3a14196a-cf7d-8aea-48d8-b9662c7dba94"), - "90%分装小瓶": ("YB_Solid_Vial", "3a14196c-cdcf-088d-dc7d-5cf38f0ad9ea"), - "10%分装小瓶": ("YB_Liquid_Vial", "3a14196c-76be-2279-4e22-7310d69aed68"), + "加样头(大)": ("YB_jia_yang_tou_da_1X1_carrier", "3a190ca0-b2f6-9aeb-8067-547e72c11469"), + "液": ("YB_1BottleCarrier", "3a190ca1-2add-2b23-f8e1-bbd348b7f790"), } @@ -57,12 +53,20 @@ def bioyond_materials_liquidhandling_2() -> list[dict]: "bioyond_materials_reaction", "bioyond_materials_liquidhandling_1", ]) -def test_resourcetreeset_from_plr(materials_fixture, request) -> list[dict]: - materials = request.getfixturevalue(materials_fixture) +def test_resourcetreeset_from_plr() -> list[dict]: + # 直接加载 bioyond_materials_reaction.json 文件 + current_dir = os.path.dirname(os.path.abspath(__file__)) + json_path = os.path.join(current_dir, "YB_materials_info.json") + with open(json_path, "r", encoding="utf-8") as f: + materials = json.load(f) deck = BIOYOND_PolymerReactionStation_Deck("test_deck") output = resource_bioyond_to_plr(materials, type_mapping=type_mapping, deck=deck) - print(deck.summary()) + print(output) + # print(deck.summary()) r = ResourceTreeSet.from_plr_resources([deck]) print(r.dump()) # json.dump(deck.serialize(), open("test.json", "w", encoding="utf-8"), indent=4) + +if __name__ == "__main__": + test_resourcetreeset_from_plr() diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py index c60a03e..ff29574 100644 --- a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py +++ b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py @@ -971,7 +971,7 @@ if __name__ == "__main__": lab_registry.setup() ws = BioyondCellWorkstation() # logger.info(ws.scheduler_stop()) - logger.info(ws.scheduler_start()) + # logger.info(ws.scheduler_start()) # results = ws.create_materials(SOLID_LIQUID_MAPPINGS) # for r in results: @@ -980,11 +980,11 @@ if __name__ == "__main__": # result = ws.create_and_inbound_materials() # 继续后续流程 - logger.info(ws.auto_feeding4to3()) #搬运物料到3号箱 + # logger.info(ws.auto_feeding4to3()) #搬运物料到3号箱 # # 使用正斜杠或 Path 对象来指定文件路径 - excel_path = Path("unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025092701.xlsx") - logger.info(ws.create_orders(excel_path)) - logger.info(ws.transfer_3_to_2_to_1()) + # excel_path = Path("unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025092701.xlsx") + # logger.info(ws.create_orders(excel_path)) + # logger.info(ws.transfer_3_to_2_to_1()) # logger.info(ws.transfer_1_to_2()) # logger.info(ws.scheduler_start()) diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/样品导入模板.xlsx b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/样品导入模板.xlsx index a89f1bc27fa7eee453958723c88bd563c122cbe7..e6addeb9855082c3ba401dbff45cc4aecf81e8ca 100644 GIT binary patch literal 9686 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 xmGVzK06Qxi literal 22007 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 V=Cz;x8Dx3@{`(v_MRyDD{u^YnfQ0}6 diff --git a/unilabos/devices/workstation/bioyond_studio/config.py b/unilabos/devices/workstation/bioyond_studio/config.py index 4804da1..f184a28 100644 --- a/unilabos/devices/workstation/bioyond_studio/config.py +++ b/unilabos/devices/workstation/bioyond_studio/config.py @@ -135,8 +135,8 @@ WAREHOUSE_MAPPING = { # 物料类型配置 MATERIAL_TYPE_MAPPINGS = { - "加样头(大)": ("YB_jia_yang_tou_da", "3a190ca0-b2f6-9aeb-8067-547e72c11469"), - "加样头(大)板": ("YB_jia_yang_tou_da_1X1_carrier", "a8e714ae-2a4e-4eb9-9614-e4c140ec3f16"), + "加样头(大)": ("YB_jia_yang_tou_da_1X1_carrier", "3a190ca0-b2f6-9aeb-8067-547e72c11469"), + "液": ("YB_1BottleCarrier", "3a190ca1-2add-2b23-f8e1-bbd348b7f790"), # YB信息 } diff --git a/unilabos/devices/workstation/bioyond_studio/station.py b/unilabos/devices/workstation/bioyond_studio/station.py index 3ce7353..3e3e0b3 100644 --- a/unilabos/devices/workstation/bioyond_studio/station.py +++ b/unilabos/devices/workstation/bioyond_studio/station.py @@ -63,7 +63,7 @@ class BioyondResourceSynchronizer(ResourceSynchronizer): logger.error("Bioyond API客户端未初始化") return False - bioyond_data = self.bioyond_api_client.stock_material('{"typeMode": 2, "includeDetail": true}') + bioyond_data = self.bioyond_api_client.stock_material('{"typeMode": 1, "includeDetail": true}') if not bioyond_data: logger.warning("从Bioyond获取的物料数据为空") return False diff --git a/unilabos/registry/resources/bioyond/YB_bottle_carriers.yaml b/unilabos/registry/resources/bioyond/YB_bottle_carriers.yaml new file mode 100644 index 0000000..83320c5 --- /dev/null +++ b/unilabos/registry/resources/bioyond/YB_bottle_carriers.yaml @@ -0,0 +1,25 @@ +YB_jia_yang_tou_da_1X1_carrier: + category: + - yb3 + class: + module: unilabos.resources.bioyond.YB_bottle_carriers:YB_jia_yang_tou_da_1X1_carrier + type: pylabrobot + description: YB_jia_yang_tou_da_1X1_carrier + handles: [] + icon: '' + init_param_schema: {} + registry_type: resource + version: 1.0.0 + +YB_1BottleCarrier: + category: + - yb3 + class: + module: unilabos.resources.bioyond.YB_bottle_carriers:YB_1BottleCarrier + type: pylabrobot + description: YB_1BottleCarrier + handles: [] + icon: '' + init_param_schema: {} + registry_type: resource + version: 1.0.0 diff --git a/unilabos/registry/resources/bioyond/bottle_carriers.yaml b/unilabos/registry/resources/bioyond/bottle_carriers.yaml deleted file mode 100644 index ac01cc3..0000000 --- a/unilabos/registry/resources/bioyond/bottle_carriers.yaml +++ /dev/null @@ -1,12 +0,0 @@ -YB_jia_yang_tou_da_1X1_carrier: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottle_carriers:YB_jia_yang_tou_da_1X1_carrier - type: pylabrobot - description: YB_jia_yang_tou_da_1X1_carrier - handles: [] - icon: '' - init_param_schema: {} - registry_type: resource - version: 1.0.0 diff --git a/unilabos/registry/resources/bioyond/bottles.yaml b/unilabos/registry/resources/bioyond/bottles.yaml deleted file mode 100644 index b886510..0000000 --- a/unilabos/registry/resources/bioyond/bottles.yaml +++ /dev/null @@ -1,151 +0,0 @@ -YB_jia_yang_tou_da: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_jia_yang_tou_da - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 - -YB_Liquid_Vial: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:YB_Liquid_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Reagent_Bottle: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:YB_Reagent_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Solid_Stock: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:YB_Solid_Stock - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Solid_Vial: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:YB_Solid_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Solution_Beaker: - category: - - bottles - class: - module: unilabos.resources.bioyond.bottles:YB_Solution_Beaker - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_100ml_Liquid_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_100ml_Liquid_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Liquid_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_Liquid_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_High_Viscosity_Liquid_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_High_Viscosity_Liquid_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Large_Dispense_Head: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_Large_Dispense_Head - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_5ml_Dispensing_Vial: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_5ml_Dispensing_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_20ml_Dispensing_Vial: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_20ml_Dispensing_Vial - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Small_Solution_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_Small_Solution_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Large_Solution_Bottle: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_Large_Solution_Bottle - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 -YB_Pipette_Tip: - category: - - yb3 - class: - module: unilabos.resources.bioyond.bottles:YB_Pipette_Tip - type: pylabrobot - handles: [] - icon: '' - init_param_schema: {} - version: 1.0.0 diff --git a/unilabos/resources/bioyond/bottle_carriers.py b/unilabos/resources/bioyond/YB_bottle_carriers.py similarity index 89% rename from unilabos/resources/bioyond/bottle_carriers.py rename to unilabos/resources/bioyond/YB_bottle_carriers.py index 76e3a93..a4a3601 100644 --- a/unilabos/resources/bioyond/bottle_carriers.py +++ b/unilabos/resources/bioyond/YB_bottle_carriers.py @@ -1,18 +1,9 @@ from pylabrobot.resources import create_homogeneous_resources, Coordinate, ResourceHolder, create_ordered_items_2d from unilabos.resources.itemized_carrier import Bottle, BottleCarrier -from unilabos.resources.bioyond.bottles import ( - YB_Solid_Stock, - YB_Solid_Vial, - YB_Liquid_Vial, - YB_Solution_Beaker, - YB_Reagent_Bottle, - YB_5ml_Dispensing_Vial, - YB_20ml_Dispensing_Vial, - YB_Small_Solution_Bottle, - YB_Large_Solution_Bottle, - YB_Large_Dispense_Head, - YB_Pipette_Tip +from unilabos.resources.bioyond.YB_bottles import ( + YB_jia_yang_tou_da, + YB_ye_Bottle ) # 命名约定:试剂瓶-Bottle,烧杯-Beaker,烧瓶-Flask,小瓶-Vial @@ -207,10 +198,9 @@ def YB_6VialCarrier(name: str) -> BottleCarrier: carrier[i] = YB_Liquid_Vial(f"{name}_liquidvial_{ordering[i]}") return carrier - +"""1瓶载架 - 单个中央位置""" def YB_1BottleCarrier(name: str) -> BottleCarrier: - """1瓶载架 - 单个中央位置""" - + # 载架尺寸 (mm) carrier_size_x = 127.8 carrier_size_y = 85.5 @@ -241,49 +231,13 @@ def YB_1BottleCarrier(name: str) -> BottleCarrier: carrier.num_items_x = 1 carrier.num_items_y = 1 carrier.num_items_z = 1 - carrier[0] = YB_Reagent_Bottle(f"{name}_flask_1") - return carrier - - -def YB_1FlaskCarrier(name: str) -> BottleCarrier: - """1瓶载架 - 单个中央位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 20.0 - - # 烧杯尺寸 - beaker_diameter = 70.0 - - # 计算中央位置 - center_x = (carrier_size_x - beaker_diameter) / 2 - center_y = (carrier_size_y - beaker_diameter) / 2 - center_z = 5.0 - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=create_homogeneous_resources( - klass=ResourceHolder, - locations=[Coordinate(center_x, center_y, center_z)], - resource_size_x=beaker_diameter, - resource_size_y=beaker_diameter, - name_prefix=name, - ), - model="1FlaskCarrier", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - carrier[0] = YB_Reagent_Bottle(f"{name}_bottle_1") + carrier[0] = YB_ye_Bottle(f"{name}_flask_1") return carrier +"""5ml分液瓶板 - 4x2布局,8个位置""" def YB_6x5ml_DispensingVialCarrier(name: str) -> BottleCarrier: - """5ml分液瓶板 - 4x2布局,8个位置""" + # 载架尺寸 (mm) carrier_size_x = 127.8 @@ -331,9 +285,9 @@ def YB_6x5ml_DispensingVialCarrier(name: str) -> BottleCarrier: carrier[i] = YB_5ml_Dispensing_Vial(f"{name}_vial_{ordering[i]}") return carrier - +"""20ml分液瓶板 - 4x2布局,8个位置""" def YB_6x20ml_DispensingVialCarrier(name: str) -> BottleCarrier: - """20ml分液瓶板 - 4x2布局,8个位置""" + # 载架尺寸 (mm) carrier_size_x = 127.8 @@ -381,9 +335,9 @@ def YB_6x20ml_DispensingVialCarrier(name: str) -> BottleCarrier: carrier[i] = YB_20ml_Dispensing_Vial(f"{name}_vial_{ordering[i]}") return carrier - +"""配液瓶(小)板 - 4x2布局,8个位置""" def YB_6x_SmallSolutionBottleCarrier(name: str) -> BottleCarrier: - """配液瓶(小)板 - 4x2布局,8个位置""" + # 载架尺寸 (mm) carrier_size_x = 127.8 @@ -481,10 +435,9 @@ def YB_4x_LargeSolutionBottleCarrier(name: str) -> BottleCarrier: carrier[i] = YB_Large_Solution_Bottle(f"{name}_bottle_{ordering[i]}") return carrier - -def YB_6x_LargeDispenseHeadCarrier(name: str) -> BottleCarrier: - """加样头(大)板 - 1x1布局,1个位置""" - +"""加样头(大)板 - 1x1布局,1个位置""" +def YB_jia_yang_tou_da_1X1_carrier(name: str) -> BottleCarrier: + # 载架尺寸 (mm) carrier_size_x = 127.8 carrier_size_y = 85.5 @@ -526,7 +479,7 @@ def YB_6x_LargeDispenseHeadCarrier(name: str) -> BottleCarrier: carrier.num_items_x = 1 carrier.num_items_y = 1 carrier.num_items_z = 1 - carrier[0] = YB_Large_Dispense_Head(f"{name}_head_1") + carrier[0] = YB_jia_yang_tou_da(f"{name}_head_1") return carrier diff --git a/unilabos/resources/bioyond/YB_bottles.py b/unilabos/resources/bioyond/YB_bottles.py new file mode 100644 index 0000000..f38dc36 --- /dev/null +++ b/unilabos/resources/bioyond/YB_bottles.py @@ -0,0 +1,38 @@ +from unilabos.resources.itemized_carrier import Bottle, BottleCarrier +# 工厂函数 + +"""加样头(大)""" +def YB_jia_yang_tou_da( + name: str, + diameter: float = 20.0, + height: float = 100.0, + max_volume: float = 30000.0, # 30mL + barcode: str = None, +) -> Bottle: + """创建粉末瓶""" + return Bottle( + name=name, + diameter=diameter,# 未知 + height=height, + max_volume=max_volume, + barcode=barcode, + model="Solid_Stock", + ) + +"""液1x1""" +def YB_ye_Bottle( + name: str, + diameter: float = 40.0, + height: float = 70.0, + max_volume: float = 50000.0, # 50mL + barcode: str = None, +) -> Bottle: + """创建液体瓶""" + return Bottle( + name=name, + diameter=diameter, + height=height, + max_volume=max_volume, + barcode=barcode, + model="Liquid_Bottle", + ) diff --git a/unilabos/resources/bioyond/YB_warehouses.py b/unilabos/resources/bioyond/YB_warehouses.py new file mode 100644 index 0000000..c546759 --- /dev/null +++ b/unilabos/resources/bioyond/YB_warehouses.py @@ -0,0 +1,160 @@ +from unilabos.resources.warehouse import WareHouse, warehouse_factory + + +def bioyond_warehouse_1x4x4(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=1, + num_items_y=4, + num_items_z=4, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + ) + + +def bioyond_warehouse_1x4x2(name: str) -> WareHouse: + """创建BioYond 4x1x2仓库""" + return warehouse_factory( + name=name, + num_items_x=1, + num_items_y=4, + num_items_z=2, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + removed_positions=None + ) + # 定义benyond的堆栈 +def bioyond_warehouse_1x2x2(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=2, + num_items_y=2, + num_items_z=1, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="YB_warehouse", + ) +def bioyond_warehouse_10x1x1(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=10, + num_items_y=1, + num_items_z=1, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + ) +def bioyond_warehouse_1x3x3(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=1, + num_items_y=3, + num_items_z=3, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + ) +def bioyond_warehouse_2x1x3(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=2, + num_items_y=1, + num_items_z=3, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + ) + +def bioyond_warehouse_3x3x1(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=3, + num_items_y=3, + num_items_z=1, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + ) +def bioyond_warehouse_5x1x1(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=5, + num_items_y=1, + num_items_z=1, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + ) +def bioyond_warehouse_3x3x1_2(name: str) -> WareHouse: + """创建BioYond 4x1x4仓库""" + return warehouse_factory( + name=name, + num_items_x=3, + num_items_y=3, + num_items_z=1, + dx=12.0, + dy=12.0, + dz=12.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + ) + +def bioyond_warehouse_liquid_and_lid_handling(name: str) -> WareHouse: + """创建BioYond开关盖加液模块台面""" + return warehouse_factory( + name=name, + num_items_x=2, + num_items_y=5, + num_items_z=1, + dx=10.0, + dy=10.0, + dz=10.0, + item_dx=137.0, + item_dy=96.0, + item_dz=120.0, + category="warehouse", + removed_positions=None + ) \ No newline at end of file diff --git a/unilabos/resources/bioyond/bottle_carriers copy.py b/unilabos/resources/bioyond/bottle_carriers copy.py deleted file mode 100644 index a3b0044..0000000 --- a/unilabos/resources/bioyond/bottle_carriers copy.py +++ /dev/null @@ -1,148 +0,0 @@ -from pylabrobot.resources import create_homogeneous_resources, Coordinate, ResourceHolder, create_ordered_items_2d - -from unilabos.resources.itemized_carrier import Bottle, BottleCarrier -from unilabos.resources.bioyond.bottles import ( - YB_jia_yang_tou_da, -) -# 命名约定:试剂瓶-Bottle,烧杯-Beaker,烧瓶-Flask,小瓶-Vial - - - - - -def YB_jia_yang_tou_da_1X1_carrier(name: str) -> BottleCarrier: - """加样头(大)板 - 1x1布局,1个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 95.0 - - # 瓶位尺寸 - bottle_diameter = 35.0 - bottle_spacing_x = 42.0 # X方向间距 - bottle_spacing_y = 35.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (1 - 1) * bottle_spacing_x - bottle_diameter) / 2 - start_y = (carrier_size_y - (1 - 1) * bottle_spacing_y - bottle_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=1, - num_items_y=1, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=bottle_spacing_x, - item_dy=bottle_spacing_y, - size_x=bottle_diameter, - size_y=bottle_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="YB_1X1_jia_yang_tou_da_carrier", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - carrier[0] = YB_jia_yang_tou_da(f"{name}_head_1") - return carrier - - -def BIOYOND_PolymerStation_AdapterBlock(name: str) -> BottleCarrier: - """适配器块 - 单个中央位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 30.0 - - # 适配器尺寸 - adapter_diameter = 80.0 - - # 计算中央位置 - center_x = (carrier_size_x - adapter_diameter) / 2 - center_y = (carrier_size_y - adapter_diameter) / 2 - center_z = 0.0 - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=create_homogeneous_resources( - klass=ResourceHolder, - locations=[Coordinate(center_x, center_y, center_z)], - resource_size_x=adapter_diameter, - resource_size_y=adapter_diameter, - name_prefix=name, - ), - model="AdapterBlock", - ) - carrier.num_items_x = 1 - carrier.num_items_y = 1 - carrier.num_items_z = 1 - # 适配器块本身不包含瓶子,只是一个支撑结构 - return carrier - - -def BIOYOND_PolymerStation_TipBox(name: str) -> BottleCarrier: - """枪头盒 - 8x12布局,96个位置""" - - # 载架尺寸 (mm) - carrier_size_x = 127.8 - carrier_size_y = 85.5 - carrier_size_z = 55.0 - - # 枪头尺寸 - tip_diameter = 10.0 - tip_spacing_x = 9.0 # X方向间距 - tip_spacing_y = 9.0 # Y方向间距 - - # 计算起始位置 (居中排列) - start_x = (carrier_size_x - (12 - 1) * tip_spacing_x - tip_diameter) / 2 - start_y = (carrier_size_y - (8 - 1) * tip_spacing_y - tip_diameter) / 2 - - sites = create_ordered_items_2d( - klass=ResourceHolder, - num_items_x=12, - num_items_y=8, - dx=start_x, - dy=start_y, - dz=5.0, - item_dx=tip_spacing_x, - item_dy=tip_spacing_y, - size_x=tip_diameter, - size_y=tip_diameter, - size_z=carrier_size_z, - ) - for k, v in sites.items(): - v.name = f"{name}_{v.name}" - - carrier = BottleCarrier( - name=name, - size_x=carrier_size_x, - size_y=carrier_size_y, - size_z=carrier_size_z, - sites=sites, - model="TipBox", - ) - carrier.num_items_x = 12 - carrier.num_items_y = 8 - carrier.num_items_z = 1 - # 创建96个枪头 - for i in range(96): - row = chr(65 + i // 12) # A-H - col = (i % 12) + 1 # 1-12 - carrier[i] = BIOYOND_PolymerStation_Pipette_Tip(f"{name}_tip_{row}{col}") - return carrier - diff --git a/unilabos/resources/bioyond/bottles copy.py b/unilabos/resources/bioyond/bottles copy.py deleted file mode 100644 index 2504c37..0000000 --- a/unilabos/resources/bioyond/bottles copy.py +++ /dev/null @@ -1,24 +0,0 @@ -from unilabos.resources.itemized_carrier import Bottle, BottleCarrier -# 工厂函数 - - -def YB_jia_yang_tou_da( - name: str, - diameter: float = 35.0, - height: float = 90.0, - max_volume: float = 50000.0, # 50mL - code: str = None, - barcode: str = None, -) -> Bottle: - """创建加样头(大)""" - return Bottle( - name=name, - diameter=diameter, - height=height, - max_volume=max_volume, - barcode=barcode, - code=code, - model="YB_jia_yang_tou_da", - ) - -