mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 13:01:12 +00:00
1027byxinyu
This commit is contained in:
12
test/resources/YB_materials_info.json
Normal file
12
test/resources/YB_materials_info.json
Normal file
@@ -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': []
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -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()
|
||||||
@@ -10,7 +10,6 @@ from datetime import datetime, timedelta
|
|||||||
import re
|
import re
|
||||||
import threading
|
import threading
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from urllib3 import response
|
from urllib3 import response
|
||||||
from unilabos.devices.workstation.workstation_base import WorkstationBase
|
from unilabos.devices.workstation.workstation_base import WorkstationBase
|
||||||
from unilabos.devices.workstation.bioyond_studio.station import BioyondWorkstation, BioyondResourceSynchronizer
|
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.devices.workstation.workstation_http_service import WorkstationHTTPService
|
||||||
from unilabos.utils.log import logger
|
from unilabos.utils.log import logger
|
||||||
|
from unilabos.registry.registry import lab_registry
|
||||||
|
|
||||||
|
|
||||||
def _iso_local_now_ms() -> str:
|
def _iso_local_now_ms() -> str:
|
||||||
# 文档要求:到毫秒 + Z,例如 2025-08-15T05:43:22.814Z
|
# 文档要求:到毫秒 + Z,例如 2025-08-15T05:43:22.814Z
|
||||||
@@ -967,22 +968,23 @@ class BioyondCellWorkstation(BioyondWorkstation):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
lab_registry.setup()
|
||||||
ws = BioyondCellWorkstation()
|
ws = BioyondCellWorkstation()
|
||||||
logger.info(ws.scheduler_stop())
|
# logger.info(ws.scheduler_stop())
|
||||||
|
logger.info(ws.scheduler_start())
|
||||||
|
|
||||||
|
# results = ws.create_materials(SOLID_LIQUID_MAPPINGS)
|
||||||
results = ws.create_materials(SOLID_LIQUID_MAPPINGS)
|
# for r in results:
|
||||||
for r in results:
|
# logger.info(r)
|
||||||
logger.info(r)
|
|
||||||
# 从CSV文件读取物料列表并批量创建入库
|
# 从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 对象来指定文件路径
|
# # 使用正斜杠或 Path 对象来指定文件路径
|
||||||
# excel_path = Path("unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025092701.xlsx")
|
excel_path = Path("unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025092701.xlsx")
|
||||||
# logger.info(ws.create_orders(excel_path))
|
logger.info(ws.create_orders(excel_path))
|
||||||
# logger.info(ws.transfer_3_to_2_to_1())
|
logger.info(ws.transfer_3_to_2_to_1())
|
||||||
|
|
||||||
# logger.info(ws.transfer_1_to_2())
|
# logger.info(ws.transfer_1_to_2())
|
||||||
# logger.info(ws.scheduler_start())
|
# logger.info(ws.scheduler_start())
|
||||||
|
|||||||
@@ -5,13 +5,10 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
# ==================== API 基础配置 ====================
|
# ==================== API 基础配置 ====================
|
||||||
|
|
||||||
|
|
||||||
# ==================== 完整的 Bioyond 配置 ====================
|
|
||||||
# BioyondCellWorkstation 默认配置(包含所有必需参数)
|
# BioyondCellWorkstation 默认配置(包含所有必需参数)
|
||||||
API_CONFIG = {
|
API_CONFIG = {
|
||||||
# API 连接配置
|
# 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"),
|
"api_key": os.getenv("BIOYOND_API_KEY", "8A819E5C"),
|
||||||
"timeout": int(os.getenv("BIOYOND_TIMEOUT", "30")),
|
"timeout": int(os.getenv("BIOYOND_TIMEOUT", "30")),
|
||||||
|
|
||||||
@@ -19,11 +16,9 @@ API_CONFIG = {
|
|||||||
"report_token": os.getenv("BIOYOND_REPORT_TOKEN", "CHANGE_ME_TOKEN"),
|
"report_token": os.getenv("BIOYOND_REPORT_TOKEN", "CHANGE_ME_TOKEN"),
|
||||||
|
|
||||||
# HTTP 服务配置
|
# 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")),
|
"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 = {
|
MATERIAL_TYPE_MAPPINGS = {
|
||||||
"烧杯": ("BIOYOND_PolymerStation_1FlaskCarrier", "3a14196b-24f2-ca49-9081-0cab8021bf1a"),
|
|
||||||
"试剂瓶": ("BIOYOND_PolymerStation_1BottleCarrier", ""),
|
"加样头(大)": ("YB_jia_yang_tou_da", "3a190ca0-b2f6-9aeb-8067-547e72c11469"),
|
||||||
"样品板": ("BIOYOND_PolymerStation_6StockCarrier", "3a14196e-b7a0-a5da-1931-35f3000281e9"),
|
"加样头(大)板": ("YB_jia_yang_tou_da_1X1_carrier", "a8e714ae-2a4e-4eb9-9614-e4c140ec3f16"),
|
||||||
"分装板": ("BIOYOND_PolymerStation_6VialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"),
|
# YB信息
|
||||||
"样品瓶": ("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"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SOLID_LIQUID_MAPPINGS = {
|
SOLID_LIQUID_MAPPINGS = {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class BioyondResourceSynchronizer(ResourceSynchronizer):
|
|||||||
type_mapping=self.workstation.bioyond_config["material_type_mappings"],
|
type_mapping=self.workstation.bioyond_config["material_type_mappings"],
|
||||||
deck=self.workstation.deck
|
deck=self.workstation.deck
|
||||||
)
|
)
|
||||||
|
print("unilab_resources:",unilab_resources)
|
||||||
|
|
||||||
logger.info(f"从Bioyond同步了 {len(unilab_resources)} 个资源")
|
logger.info(f"从Bioyond同步了 {len(unilab_resources)} 个资源")
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -1,130 +1,10 @@
|
|||||||
1BottleCarrier:
|
YB_jia_yang_tou_da_1X1_carrier:
|
||||||
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:
|
|
||||||
category:
|
category:
|
||||||
- yb3
|
- yb3
|
||||||
class:
|
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
|
type: pylabrobot
|
||||||
description: 6x5ml_DispensingVialCarrier
|
description: YB_jia_yang_tou_da_1X1_carrier
|
||||||
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
|
|
||||||
handles: []
|
handles: []
|
||||||
icon: ''
|
icon: ''
|
||||||
init_param_schema: {}
|
init_param_schema: {}
|
||||||
|
|||||||
@@ -1,138 +1,8 @@
|
|||||||
Liquid_Vial:
|
YB_jia_yang_tou_da:
|
||||||
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:
|
|
||||||
category:
|
category:
|
||||||
- yb3
|
- yb3
|
||||||
class:
|
class:
|
||||||
module: unilabos.resources.bioyond.bottles:BIOYOND_PolymerStation_100ml_Liquid_Bottle
|
module: unilabos.resources.bioyond.bottles:YB_jia_yang_tou_da
|
||||||
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
|
|
||||||
type: pylabrobot
|
type: pylabrobot
|
||||||
handles: []
|
handles: []
|
||||||
icon: ''
|
icon: ''
|
||||||
|
|||||||
148
unilabos/resources/bioyond/bottle_carriers copy.py
Normal file
148
unilabos/resources/bioyond/bottle_carriers copy.py
Normal file
@@ -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
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
24
unilabos/resources/bioyond/bottles copy.py
Normal file
24
unilabos/resources/bioyond/bottles copy.py
Normal file
@@ -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",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -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",
|
|
||||||
)
|
|
||||||
|
|
||||||
@@ -636,6 +636,8 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st
|
|||||||
plr_material: ResourcePLR = initialize_resource(
|
plr_material: ResourcePLR = initialize_resource(
|
||||||
{"name": material["name"], "class": className}, resource_type=ResourcePLR
|
{"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.code = material.get("code", "") and material.get("barCode", "") or ""
|
||||||
plr_material.unilabos_uuid = str(uuid.uuid4())
|
plr_material.unilabos_uuid = str(uuid.uuid4())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user