32 Commits

Author SHA1 Message Date
Calvin Cao
7a284069d2 Merge pull request #158 from dptech-corp/workstation_dev_YB3
Workstation dev yb3
2025-11-09 17:12:41 +08:00
Calvin Cao
4a2d862333 Merge pull request #157 from sun7151887/fix/yb3-material-names-and-model
Update YB resources: add YB_ prefix to models and update deck configu…
2025-11-09 17:11:24 +08:00
dijkstra402
538891fcbe Update YB resources: add YB_ prefix to models and update deck configurations 2025-11-09 17:04:52 +08:00
Calvin Cao
a0e92b8e9b Merge pull request #156 from dptech-corp/workstation_dev_YB3
Workstation dev yb3
2025-11-09 15:48:35 +08:00
Calvin Cao
1d77225912 Merge branch 'workstation_dev_YB4' into workstation_dev_YB3 2025-11-09 15:48:22 +08:00
Calvin Cao
06e6ab0b7f Merge pull request #155 from sun7151887/fix/yb3-material-names-and-model
Fix warehouse mapping: use actual parent warehouse name instead of ha…
2025-11-09 15:15:55 +08:00
dijkstra402
5399c6c1cf Fix warehouse mapping: use actual parent warehouse name instead of hardcoded '手动堆栈' 2025-11-09 15:13:20 +08:00
Junhan Chang
f872d3ef56 add electrode_sheets definition, and fix magazines 2025-11-09 01:00:05 +08:00
Calvin Cao
85c6f4e688 Merge pull request #154 from lixinyu1011/workstation_dev_YB3
修改pymodbus和websocket的报送信息
2025-11-08 15:59:22 +08:00
lixinyu1011
442b759397 修改pymodbus和websocket的报送信息 2025-11-08 15:56:39 +08:00
Calvin Cao
47ecb154c8 Merge pull request #153 from sun7151887/fix/yb3-material-names-and-model
规范堆栈和瓶子的名称
2025-11-08 15:49:59 +08:00
dijkstra402
be429147c0 Fix infinite recursion in YB_jia_yang_tou_da by renaming carrier function to YB_jia_yang_tou_da_Carrier 2025-11-08 15:42:18 +08:00
Calvin Cao
123c69e97a Merge pull request #152 from lixinyu1011/workstation_dev_YB3
修改减少modbus报警信息,以及websocket报警信息
2025-11-08 15:21:33 +08:00
Calvin Cao
04004c9b6f Merge branch 'workstation_dev_YB3' into workstation_dev_YB3 2025-11-08 15:21:25 +08:00
lixinyu1011
45a778b928 修改减少modbus报警信息,以及websocket报警信息 2025-11-08 15:18:52 +08:00
Calvin Cao
c44ae32070 Merge pull request #151 from sun7151887/fix/yb3-material-names-and-model
Add debug prints to create_orders and add resource_tree_transfer method
2025-11-08 15:01:42 +08:00
dijkstra402
7af32b379b Add YB_ prefix to bottle carrier model names 2025-11-08 14:53:25 +08:00
Xuwznln
48d429ae00 fix resource_get param 2025-11-08 14:40:00 +08:00
dijkstra402
200105f647 Add debug prints to create_orders and add resource_tree_transfer method 2025-11-08 13:35:47 +08:00
Xuwznln
8b5653d801 fix json dumps 2025-11-08 12:13:57 +08:00
Xuwznln
5f859917d4 support name change during materials change 2025-11-08 12:13:56 +08:00
Xuwznln
af2fb7f34a enable slave mode 2025-11-08 12:13:54 +08:00
Xuwznln
baa107c230 change uuid logger to trace level 2025-11-08 12:13:52 +08:00
Xuwznln
83854a741d correct remove_resource stats 2025-11-08 12:13:50 +08:00
Xuwznln
86c7880b5c disable slave connect websocket 2025-11-08 12:13:48 +08:00
Xuwznln
6d934e354c adjust with_children param 2025-11-08 12:13:46 +08:00
Xuwznln
bed453034f modify devices to use correct executor (sleep, create_task) 2025-11-08 12:13:44 +08:00
Xuwznln
5331d7bfba support sleep and create_task in node 2025-11-08 12:13:41 +08:00
Xuwznln
38ab7d3e78 fix run async execution error 2025-11-08 12:13:41 +08:00
Calvin Cao
9a85bfddcd Merge pull request #147 from lixinyu1011/workstation_dev_YB3
1104_byxinyu
2025-11-04 03:57:57 +08:00
lixinyu1011
d4e1286df7 1104_byxinyu 2025-11-04 03:42:00 +08:00
calvincao
765038a136 Revert "Update YB_YH_materials.py"
This reverts commit bfd415279b.
2025-11-04 02:18:44 +08:00
20 changed files with 694 additions and 365 deletions

View File

@@ -15,9 +15,9 @@ lab_registry.setup()
type_mapping = {
"加样头(大)": ("YB_jia_yang_tou_da_1X1_carrier", "3a190ca0-b2f6-9aeb-8067-547e72c11469"),
"加样头(大)": ("YB_jia_yang_tou_da", "3a190ca0-b2f6-9aeb-8067-547e72c11469"),
"": ("YB_1BottleCarrier", "3a190ca1-2add-2b23-f8e1-bbd348b7f790"),
"配液瓶(小)板": ("YB_6x_SmallSolutionBottleCarrier", "3a190c8b-3284-af78-d29f-9a69463ad047"),
"配液瓶(小)板": ("YB_peiyepingxiaoban", "3a190c8b-3284-af78-d29f-9a69463ad047"),
"配液瓶(小)": ("YB_pei_ye_xiao_Bottler", "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"),
}

View File

@@ -421,7 +421,7 @@ class MessageProcessor:
ssl_context = ssl_module.create_default_context()
ws_logger = logging.getLogger("websockets.client")
ws_logger.setLevel(logging.INFO)
# 日志级别已在 unilabos.utils.log 中统一配置为 WARNING
async with websockets.connect(
self.websocket_url,
@@ -1197,7 +1197,7 @@ class WebSocketClient(BaseCommunicationClient):
},
}
self.message_processor.send_message(message)
logger.debug(f"[WebSocketClient] Device status published: {device_id}.{property_name}")
logger.trace(f"[WebSocketClient] Device status published: {device_id}.{property_name}")
def publish_job_status(
self, feedback_data: dict, item: QueueItem, status: str, return_info: Optional[dict] = None

View File

@@ -3,6 +3,7 @@ from cgi import print_arguments
from doctest import debug
from typing import Dict, Any, List, Optional
import requests
from pylabrobot.resources.resource import Resource as ResourcePLR
from pathlib import Path
import pandas as pd
import time
@@ -255,7 +256,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
def auto_feeding4to3(
self,
# ★ 修改点:默认模板路径
xlsx_path: Optional[str] = "C:/ML/GitHub/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx",
xlsx_path: Optional[str] = "/Users/sml/work/Unilab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx",
# ---------------- WH4 - 加样头面 (Z=1, 12个点位) ----------------
WH4_x1_y1_z1_1_materialName: str = "", WH4_x1_y1_z1_1_quantity: float = 0.0,
WH4_x2_y1_z1_2_materialName: str = "", WH4_x2_y1_z1_2_quantity: float = 0.0,
@@ -307,7 +308,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
# ---------- 模式 1: Excel 导入 ----------
if xlsx_path:
path = Path(xlsx_path)
path = Path(__file__).parent / Path(xlsx_path)
if path.exists(): # ★ 修改点:路径存在才加载
try:
df = pd.read_excel(path, sheet_name=0, header=None, engine="openpyxl")
@@ -472,14 +473,23 @@ class BioyondCellWorkstation(BioyondWorkstation):
- totalMass 自动计算为所有物料质量之和
- createTime 缺失或为空时自动填充为当前日期YYYY/M/D
"""
path = Path(xlsx_path)
default_path = Path("/Users/sml/work/Unilab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx")
path = Path(xlsx_path) if xlsx_path else default_path
print(f"[create_orders] 使用 Excel 路径: {path}")
if path != default_path:
print("[create_orders] 来源: 调用方传入自定义路径")
else:
print("[create_orders] 来源: 使用默认模板路径")
if not path.exists():
print(f"[create_orders] ⚠️ Excel 文件不存在: {path}")
raise FileNotFoundError(f"未找到 Excel 文件:{path}")
try:
df = pd.read_excel(path, sheet_name=0, engine="openpyxl")
except Exception as e:
raise RuntimeError(f"读取 Excel 失败:{e}")
print(f"[create_orders] Excel 读取成功,行数: {len(df)}, 列: {list(df.columns)}")
# 列名容错:返回可选列名,找不到则返回 None
def _pick(col_names: List[str]) -> Optional[str]:
@@ -496,9 +506,20 @@ class BioyondCellWorkstation(BioyondWorkstation):
col_pouch = _pick(["软包组装分液体积", "pouchCellInfo"])
col_cond = _pick(["电导测试分液体积", "conductivityInfo"])
col_cond_cnt = _pick(["电导测试分液瓶数", "conductivityBottleCount"])
print("[create_orders] 列匹配结果:", {
"order_name": col_order_name,
"create_time": col_create_time,
"bottle_type": col_bottle_type,
"mix_time": col_mix_time,
"load": col_load,
"pouch": col_pouch,
"conductivity": col_cond,
"conductivity_bottle_count": col_cond_cnt,
})
# 物料列:所有以 (g) 结尾
material_cols = [c for c in df.columns if isinstance(c, str) and c.endswith("(g)")]
print(f"[create_orders] 识别到的物料列: {material_cols}")
if not material_cols:
raise KeyError("未发现任何以“(g)”结尾的物料列,请检查表头。")
@@ -546,6 +567,9 @@ class BioyondCellWorkstation(BioyondWorkstation):
if mass > 0:
mats.append({"name": mcol.replace("(g)", ""), "mass": mass})
total_mass += mass
else:
if mass < 0:
print(f"[create_orders] 第 {idx+1} 行物料 {mcol} 数值为负数: {mass}")
order_data = {
"batchId": batch_id,
@@ -560,11 +584,23 @@ class BioyondCellWorkstation(BioyondWorkstation):
"materialInfos": mats,
"totalMass": round(total_mass, 4) # 自动汇总
}
print(f"[create_orders] 第 {idx+1} 行解析结果: orderName={order_data['orderName']}, "
f"loadShedding={order_data['loadSheddingInfo']}, pouchCell={order_data['pouchCellInfo']}, "
f"conductivity={order_data['conductivityInfo']}, totalMass={order_data['totalMass']}, "
f"material_count={len(mats)}")
if order_data["totalMass"] <= 0:
print(f"[create_orders] ⚠️ 第 {idx+1} 行总质量 <= 0可能导致 LIMS 校验失败")
if not mats:
print(f"[create_orders] ⚠️ 第 {idx+1} 行未找到有效物料")
orders.append(order_data)
print("================================================")
print("orders:", orders)
print(f"[create_orders] 即将提交订单数量: {len(orders)}")
response = self._post_lims("/api/lims/order/orders", orders)
print(response)
print(f"[create_orders] 接口返回: {response}")
# 等待任务报送成功
data_list = response.get("data", [])
if data_list:
@@ -1015,24 +1051,71 @@ class BioyondCellWorkstation(BioyondWorkstation):
"create_result": create_result,
"inbound_result": inbound_result,
}
def resource_tree_transfer(self, old_parent: ResourcePLR, plr_resource: ResourcePLR, parent_resource: ResourcePLR):
# ROS2DeviceNode.run_async_func(self._ros_node.resource_tree_transfer, True, **{
# "old_parent": old_parent,
# "plr_resource": plr_resource,
# "parent_resource": parent_resource,
# })
print("resource_tree_transfer", plr_resource, parent_resource)
if hasattr(plr_resource, "unilabos_extra") and plr_resource.unilabos_extra:
if "update_resource_site" in plr_resource.unilabos_extra:
site = plr_resource.unilabos_extra["update_resource_site"]
plr_model = plr_resource.model
board_type = None
for key, (moudle_name,moudle_uuid) in MATERIAL_TYPE_MAPPINGS.items():
if plr_model == moudle_name:
board_type = key
break
if board_type is None:
pass
bottle1 = plr_resource.children[0]
bottle_moudle = bottle1.model
bottle_type = None
for key, (moudle_name, moudle_uuid) in MATERIAL_TYPE_MAPPINGS.items():
if bottle_moudle == moudle_name:
bottle_type = key
break
# 从 parent_resource 获取仓库名称
warehouse_name = parent_resource.name if parent_resource else "手动堆栈"
logger.info(f"拖拽上料: {plr_resource.name} -> {warehouse_name} / {site}")
self.create_sample(plr_resource.name, board_type, bottle_type, site, warehouse_name)
return
self.lab_logger().warning(f"无库位的上料,不处理,{plr_resource} 挂载到 {parent_resource}")
def create_sample(
self,
name: str,
board_type: str,
bottle_type: str,
location_code: str
location_code: str,
warehouse_name: str = "手动堆栈"
) -> Dict[str, Any]:
"""创建配液板物料并自动入库。
Args:
material_name: 物料名称,支持 "5ml分液瓶板"/"5ml分液瓶""配液瓶(小)板"/"配液瓶(小)"
quantity: 主物料与明细的数量,默认 1。
location_code: 库位编号,例如 "A01",将自动映射为 "手动堆栈" 下的 UUID。
name: 物料名称
board_type: 板类型,如 "5ml分液瓶板""配液瓶(小)板"
bottle_type: 瓶类型,如 "5ml分液瓶""配液瓶(小)"
location_code: 库位编号,例如 "A01"
warehouse_name: 仓库名称,默认为 "手动堆栈",支持 "自动堆栈-左""自动堆栈-右"
"""
carrier_type_id = MATERIAL_TYPE_MAPPINGS[board_type][1]
bottle_type_id = MATERIAL_TYPE_MAPPINGS[bottle_type][1]
location_id = WAREHOUSE_MAPPING["手动堆栈"]["site_uuids"][location_code]
# 从指定仓库获取库位UUID
if warehouse_name not in WAREHOUSE_MAPPING:
logger.error(f"未找到仓库: {warehouse_name},回退到手动堆栈")
warehouse_name = "手动堆栈"
if location_code not in WAREHOUSE_MAPPING[warehouse_name]["site_uuids"]:
logger.error(f"仓库 {warehouse_name} 中未找到库位 {location_code}")
raise ValueError(f"库位 {location_code} 在仓库 {warehouse_name} 中不存在")
location_id = WAREHOUSE_MAPPING[warehouse_name]["site_uuids"][location_code]
logger.info(f"创建样品入库: {name} -> {warehouse_name}/{location_code} (UUID: {location_id})")
# 新建小瓶
details = []

View File

@@ -8,8 +8,8 @@ import os
# BioyondCellWorkstation 默认配置(包含所有必需参数)
API_CONFIG = {
# API 连接配置
# "api_host": os.getenv("BIOYOND_API_HOST", "http://172.21.32.65:44389"),#实机
"api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.10.169:44388"),# 仿真机
"api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.1.143:44389"),#实机
# "api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.7.149:44388"),# 仿真机
"api_key": os.getenv("BIOYOND_API_KEY", "8A819E5C"),
"timeout": int(os.getenv("BIOYOND_TIMEOUT", "30")),
@@ -17,7 +17,7 @@ API_CONFIG = {
"report_token": os.getenv("BIOYOND_REPORT_TOKEN", "CHANGE_ME_TOKEN"),
# HTTP 服务配置
"HTTP_host": os.getenv("BIOYOND_HTTP_HOST", "172.21.32.115"), # HTTP服务监听地址监听计算机飞连ip地址
"HTTP_host": os.getenv("BIOYOND_HTTP_HOST", "172.16.2.140"), # HTTP服务监听地址监听计算机飞连ip地址
"HTTP_port": int(os.getenv("BIOYOND_HTTP_PORT", "8080")),
"debug_mode": False,# 调试模式
}
@@ -234,22 +234,22 @@ WAREHOUSE_MAPPING = {
# 物料类型配置
MATERIAL_TYPE_MAPPINGS = {
"100ml液体": ("YB_1Bottle100mlCarrier", "d37166b3-ecaa-481e-bd84-3032b795ba07"),
"": ("YB_1BottleCarrier", "3a190ca1-2add-2b23-f8e1-bbd348b7f790"),
"高粘液": ("YB_1GaoNianYeBottleCarrier", "abe8df30-563d-43d2-85e0-cabec59ddc16"),
"加样头(大)": ("YB_jia_yang_tou_da_1X1_carrier", "3a190ca0-b2f6-9aeb-8067-547e72c11469"),
# "加样头(大)板": ("YB_jia_yang_tou_da_1X1_carrier", "a8e714ae-2a4e-4eb9-9614-e4c140ec3f16"),
"5ml分液瓶板": ("YB_6x5ml_DispensingVialCarrier", "3a192fa4-007d-ec7b-456e-2a8be7a13f23"),
"5ml分液瓶": ("YB_fen_ye_5ml_Bottle", "3a192c2a-ebb7-58a1-480d-8b3863bf74f4"),
"20ml分液瓶板": ("YB_6x20ml_DispensingVialCarrier", "3a192fa4-47db-3449-162a-eaf8aba57e27"),
"20ml分液瓶": ("YB_fen_ye_20ml_Bottle", "3a192c2b-19e8-f0a3-035e-041ca8ca1035"),
"配液瓶(小)板": ("YB_6x_SmallSolutionBottleCarrier", "3a190c8b-3284-af78-d29f-9a69463ad047"),
"100ml液体": ("YB_100ml_yeti", "d37166b3-ecaa-481e-bd84-3032b795ba07"),
"": ("YB_ye", "3a190ca1-2add-2b23-f8e1-bbd348b7f790"),
"高粘液": ("YB_gaonianye", "abe8df30-563d-43d2-85e0-cabec59ddc16"),
"加样头(大)": ("YB_jia_yang_tou_da_Carrier", "3a190ca0-b2f6-9aeb-8067-547e72c11469"),
# "加样头(大)板": ("YB_jia_yang_tou_da", "a8e714ae-2a4e-4eb9-9614-e4c140ec3f16"),
"5ml分液瓶板": ("YB_5ml_fenyepingban", "3a192fa4-007d-ec7b-456e-2a8be7a13f23"),
"5ml分液瓶": ("YB_5ml_fenyeping", "3a192c2a-ebb7-58a1-480d-8b3863bf74f4"),
"20ml分液瓶板": ("YB_20ml_fenyepingban", "3a192fa4-47db-3449-162a-eaf8aba57e27"),
"20ml分液瓶": ("YB_20ml_fenyeping", "3a192c2b-19e8-f0a3-035e-041ca8ca1035"),
"配液瓶(小)板": ("YB_peiyepingxiaoban", "3a190c8b-3284-af78-d29f-9a69463ad047"),
"配液瓶(小)": ("YB_pei_ye_xiao_Bottle", "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"),
"配液瓶(大)板": ("YB_4x_LargeSolutionBottleCarrier", "53e50377-32dc-4781-b3c0-5ce45bc7dc27"),
"配液瓶(大)板": ("YB_peiyepingdaban", "53e50377-32dc-4781-b3c0-5ce45bc7dc27"),
"配液瓶(大)": ("YB_pei_ye_da_Bottle", "19c52ad1-51c5-494f-8854-576f4ca9c6ca"),
"适配器块": ("YB_AdapterBlock", "efc3bb32-d504-4890-91c0-b64ed3ac80cf"),
"枪头盒": ("YB_TipBox", "3a192c2e-20f3-a44a-0334-c8301839d0b3"),
"枪头": ("YB_Pipette_Tip", "b6196971-1050-46da-9927-333e8dea062d"),
"适配器块": ("YB_shi_pei_qi_kuai", "efc3bb32-d504-4890-91c0-b64ed3ac80cf"),
"枪头盒": ("YB_qiang_tou_he", "3a192c2e-20f3-a44a-0334-c8301839d0b3"),
"枪头": ("YB_qiang_tou", "b6196971-1050-46da-9927-333e8dea062d"),
}
SOLID_LIQUID_MAPPINGS = {

View File

@@ -177,7 +177,18 @@ class BioyondWorkstation(WorkstationBase):
ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{
"resources": [self.deck]
})
def resource_tree_transfer(self, old_parent: ResourcePLR, plr_resource: ResourcePLR, parent_resource: ResourcePLR):
# ROS2DeviceNode.run_async_func(self._ros_node.resource_tree_transfer, True, **{
# "old_parent": old_parent,
# "plr_resource": plr_resource,
# "parent_resource": parent_resource,
# })
print("resource_tree_transfer", plr_resource, parent_resource)
if hasattr(plr_resource, "unilabos_data") and plr_resource.unilabos_data:
if "update_resource_site" in plr_resource.unilabos_data:
site = plr_resource.unilabos_data["update_resource_site"]
return
self.lab_logger().warning(f"无库位的上料,不处理,{plr_resource} 挂载到 {parent_resource}")
def transfer_resource_to_another(self, resource: List[ResourceSlot], mount_resource: List[ResourceSlot], sites: List[str], mount_device_id: DeviceSlot):
ROS2DeviceNode.run_async_func(self._ros_node.transfer_resource_to_another, True, **{
"plr_resources": resource,

View File

@@ -18,70 +18,11 @@ from pylabrobot.resources.tip_rack import TipRack, TipSpot
from pylabrobot.resources.trash import Trash
from pylabrobot.resources.utils import create_ordered_items_2d
from unilabos.resources.battery.magazine import MagazineHolder_1, MagazineHolder_2, MagazineHolder_4, MagazineHolder_6
from unilabos.resources.battery.magazine import MagazineHolder_4_Cathode, MagazineHolder_6_Cathode, MagazineHolder_6_Anode, MagazineHolder_6_Battery
from unilabos.resources.battery.bottle_carriers import YIHUA_Electrolyte_12VialCarrier
class ElectrodeSheetState(TypedDict):
diameter: float # 直径 (mm)
thickness: float # 厚度 (mm)
mass: float # 质量 (g)
material_type: str # 材料类型(正极、负极、隔膜、弹片、垫片、铝箔等)
height: float
electrolyte_name: str
data_electrolyte_code: str
open_circuit_voltage: float
assembly_pressure: float
electrolyte_volume: float
info: Optional[str] # 附加信息
class ElectrodeSheet(Resource):
"""极片类 - 包含正负极片、隔膜、弹片、垫片、铝箔等所有片状材料"""
def __init__(
self,
name: str = "极片",
size_x=10,
size_y=10,
size_z=10,
category: str = "electrode_sheet",
model: Optional[str] = None,
):
"""初始化极片
Args:
name: 极片名称
category: 类别
model: 型号
"""
super().__init__(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
category=category,
model=model,
)
self._unilabos_state: ElectrodeSheetState = ElectrodeSheetState(
diameter=14,
thickness=0.1,
mass=0.5,
material_type="copper",
info=None
)
# TODO: 这个还要不要给self._unilabos_state赋值的
def load_state(self, state: Dict[str, Any]) -> None:
"""格式不变"""
super().load_state(state)
self._unilabos_state = state
#序列化
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
"""格式不变"""
data = super().serialize_state()
data.update(self._unilabos_state) # Container自身的信息云端物料将保存这一data本地也通过这里的data进行读写当前类用来表示这个物料的长宽高大小的属性而datastate用来表示物料的内容细节等
return data
# TODO: 这个应该只能放一个极片
class MaterialHoleState(TypedDict):
@@ -477,13 +418,13 @@ def TipBox64(
size_x: float = 127.8,
size_y: float = 85.5,
size_z: float = 60.0,
category: str = "tip_box_64",
category: str = "tip_rack",
model: Optional[str] = None,
):
"""64孔枪头盒类"""
from pylabrobot.resources.tip import Tip
# 创建8x8=64个枪头位
# 创建12x8=96个枪头位
def make_tip():
return Tip(
has_filter=False,
@@ -508,17 +449,19 @@ def TipBox64(
)
idx_available = list(range(0, 32)) + list(range(64, 96))
tip_spots_available = {k: v for i, (k, v) in enumerate(tip_spots.items()) if i in idx_available}
return TipRack(
tip_rack = TipRack(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
ordered_items=tip_spots_available,
# ordered_items=tip_spots_available,
ordered_items=tip_spots,
category=category,
model=model,
with_tips=True,
with_tips=False,
)
tip_rack.set_tip_state([True]*32 + [False]*32 + [True]*32) # 前32和后32个有枪头中间32个无枪头
return tip_rack
class WasteTipBoxstate(TypedDict):
@@ -629,58 +572,23 @@ class CoincellDeck(Deck):
def setup(self) -> None:
"""设置工作站的标准布局 - 包含子弹夹、料盘、瓶架等完整配置"""
# ====================================== 子弹夹 ============================================
# 铝箔1个洞位
lvbo_zip = MagazineHolder_1("铝箔弹夹", 80, 80, 10)
self.assign_child_resource(lvbo_zip, Coordinate(x=2737.0, y=301.0, z=0))
# 正极片4个洞位2x2布局
zhengji_zip = MagazineHolder_4("正极弹夹", 80, 80, 10)
zhengji_zip = MagazineHolder_4_Cathode("正极&铝箔弹夹")
self.assign_child_resource(zhengji_zip, Coordinate(x=2799.0, y=356.0, z=0))
# 正极壳4个洞位2x2布局
zhengjike_zip = MagazineHolder_4("正极壳弹夹", 80, 80, 10)
# 正极壳、平垫片6个洞位2x2+2布局)
zhengjike_zip = MagazineHolder_6_Cathode("正极壳&平垫片弹夹")
self.assign_child_resource(zhengjike_zip, Coordinate(x=2586.0, y=1143.0, z=0))
# 垫片(2个洞位,1x2布局
danpian_zip = MagazineHolder_2("垫片弹夹", 80, 80, 10)
self.assign_child_resource(danpian_zip, Coordinate(x=2690.0, y=1141.0, z=0))
# 负极壳4个洞位2x2布局
fujike_zip = MagazineHolder_4("负极壳弹夹", 80, 80, 10)
# 负极壳、弹垫片(6个洞位,2x2+2布局
fujike_zip = MagazineHolder_6_Anode("负极壳&弹垫片弹夹")
self.assign_child_resource(fujike_zip, Coordinate(x=2492.0, y=1144.0, z=0))
# 弹片2个洞位1x2布局
tanpian_zip = MagazineHolder_2("弹片弹夹", 80, 80, 10)
self.assign_child_resource(tanpian_zip, Coordinate(x=2492.0, y=1139.0, z=0))
# 成品弹夹6个洞位3x2布局
chengpindanjia_zip = MagazineHolder_6("成品弹夹", 80, 80, 10)
chengpindanjia_zip = MagazineHolder_6_Battery("成品弹夹")
self.assign_child_resource(chengpindanjia_zip, Coordinate(x=3112.0, y=1295.0, z=0))
# 为子弹夹添加极片
for i in range(1): # MagazineHolder_1 有1个洞位
lvbo = ElectrodeSheet(name=f"铝箔_{i}", size_x=12, size_y=12, size_z=0.1)
lvbo_zip.children[i].assign_child_resource(lvbo, location=None)
for i in range(4): # MagazineHolder_4 有4个洞位
zhengji = ElectrodeSheet(name=f"正极_{i}", size_x=12, size_y=12, size_z=0.1)
zhengji_zip.children[i].assign_child_resource(zhengji, location=None)
for i in range(4): # MagazineHolder_4 有4个洞位
zhengjike = ElectrodeSheet(name=f"正极壳_{i}", size_x=12, size_y=12, size_z=0.1)
zhengjike_zip.children[i].assign_child_resource(zhengjike, location=None)
for i in range(2): # MagazineHolder_2 有2个洞位
danpian = ElectrodeSheet(name=f"垫片_{i}", size_x=12, size_y=12, size_z=0.1)
danpian_zip.children[i].assign_child_resource(danpian, location=None)
for i in range(4): # MagazineHolder_4 有4个洞位
fujike = ElectrodeSheet(name=f"负极壳_{i}", size_x=12, size_y=12, size_z=0.1)
fujike_zip.children[i].assign_child_resource(fujike, location=None)
for i in range(2): # MagazineHolder_2 有2个洞位
tanpian = ElectrodeSheet(name=f"弹片_{i}", size_x=12, size_y=12, size_z=0.1)
tanpian_zip.children[i].assign_child_resource(tanpian, location=None)
# for i in range(6): # MagazineHolder_6 有6个洞位
# chengpindanjia = ElectrodeSheet(name=f"成品弹夹_{i}", size_x=12, size_y=12, size_z=0.1)
# chengpindanjia_zip.children[i].assign_child_resource(chengpindanjia, location=None)
# ====================================== 物料板 ============================================
# 创建物料板料盘carrier- 4x4布局
# 负极料盘
@@ -699,7 +607,7 @@ class CoincellDeck(Deck):
# ====================================== 瓶架、移液枪 ============================================
# 在台面上放置 3x4 瓶架、6x2 瓶架 与 64孔移液枪头盒
# 奔耀上料5ml分液瓶小板 - 由奔曜跨站转运而来,不单独写
# 奔耀上料5ml分液瓶小板 - 由奔曜跨站转运而来,不单独写,但是这里应该有一个堆栈用于摆放分液瓶小板
# bottle_rack_3x4 = BottleRack(
# name="bottle_rack_3x4",
@@ -728,5 +636,5 @@ class CoincellDeck(Deck):
if __name__ == "__main__":
deck = CoincellDeck(setup=True)
deck = create_coin_cell_deck()
print(deck)

View File

@@ -112,7 +112,7 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
def __init__(self,
config: dict = None,
deck=None,
address: str = "172.21.33.176",
address: str = "172.16.28.102",
port: str = "502",
debug_mode: bool = False,
*args,
@@ -879,7 +879,7 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
return self.success
def func_allpack_cmd(self, elec_num, elec_use_num, elec_vol:int=50, assembly_type:int=7, assembly_pressure:int=4200, file_path: str="C:\\Users\\67484\\Desktop") -> bool:
def func_allpack_cmd(self, elec_num, elec_use_num, elec_vol:int=50, assembly_type:int=7, assembly_pressure:int=4200, file_path: str="/Users/sml/work") -> bool:
elec_num, elec_use_num, elec_vol, assembly_type, assembly_pressure = int(elec_num), int(elec_use_num), int(elec_vol), int(assembly_type), int(assembly_pressure)
summary_csv_file = os.path.join(file_path, "duandian.csv")
# 如果断点文件存在,先读取之前的进度

View File

@@ -0,0 +1,64 @@
Name,DataType,InitValue,Comment,Attribute,DeviceType,Address,
COIL_SYS_START_CMD,BOOL,,,,coil,9010,
COIL_SYS_STOP_CMD,BOOL,,,,coil,9020,
COIL_SYS_RESET_CMD,BOOL,,,,coil,9030,
COIL_SYS_HAND_CMD,BOOL,,,,coil,9040,
COIL_SYS_AUTO_CMD,BOOL,,,,coil,9050,
COIL_SYS_INIT_CMD,BOOL,,,,coil,9060,
COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,,,,coil,9700,
COIL_UNILAB_REC_MSG_SUCC_CMD,BOOL,,,,coil,9710,unilab_rec_msg_succ_cmd
COIL_SYS_START_STATUS,BOOL,,,,coil,9210,
COIL_SYS_STOP_STATUS,BOOL,,,,coil,9220,
COIL_SYS_RESET_STATUS,BOOL,,,,coil,9230,
COIL_SYS_HAND_STATUS,BOOL,,,,coil,9240,
COIL_SYS_AUTO_STATUS,BOOL,,,,coil,9250,
COIL_SYS_INIT_STATUS,BOOL,,,,coil,9260,
COIL_REQUEST_REC_MSG_STATUS,BOOL,,,,coil,9500,
COIL_REQUEST_SEND_MSG_STATUS,BOOL,,,,coil,9510,request_send_msg_status
REG_MSG_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,17000,
REG_MSG_ELECTROLYTE_NUM,INT16,,,,hold_register,17002,unilab_send_msg_electrolyte_num
REG_MSG_ELECTROLYTE_VOLUME,INT16,,,,hold_register,17004,unilab_send_msg_electrolyte_vol
REG_MSG_ASSEMBLY_TYPE,INT16,,,,hold_register,17006,unilab_send_msg_assembly_type
REG_MSG_ASSEMBLY_PRESSURE,INT16,,,,hold_register,17008,unilab_send_msg_assembly_pressure
REG_DATA_ASSEMBLY_COIN_CELL_NUM,INT16,,,,hold_register,16000,data_assembly_coin_cell_num
REG_DATA_OPEN_CIRCUIT_VOLTAGE,FLOAT32,,,,hold_register,16002,data_open_circuit_voltage
REG_DATA_AXIS_X_POS,FLOAT32,,,,hold_register,16004,
REG_DATA_AXIS_Y_POS,FLOAT32,,,,hold_register,16006,
REG_DATA_AXIS_Z_POS,FLOAT32,,,,hold_register,16008,
REG_DATA_POLE_WEIGHT,FLOAT32,,,,hold_register,16010,data_pole_weight
REG_DATA_ASSEMBLY_PER_TIME,FLOAT32,,,,hold_register,16012,data_assembly_time
REG_DATA_ASSEMBLY_PRESSURE,INT16,,,,hold_register,16014,data_assembly_pressure
REG_DATA_ELECTROLYTE_VOLUME,INT16,,,,hold_register,16016,data_electrolyte_volume
REG_DATA_COIN_NUM,INT16,,,,hold_register,16018,data_coin_num
REG_DATA_ELECTROLYTE_CODE,STRING,,,,hold_register,16020,data_electrolyte_code()
REG_DATA_COIN_CELL_CODE,STRING,,,,hold_register,16030,data_coin_cell_code()
REG_DATA_STACK_VISON_CODE,STRING,,,,hold_register,18004,data_stack_vision_code()
REG_DATA_GLOVE_BOX_PRESSURE,FLOAT32,,,,hold_register,16050,data_glove_box_pressure
REG_DATA_GLOVE_BOX_WATER_CONTENT,FLOAT32,,,,hold_register,16052,data_glove_box_water_content
REG_DATA_GLOVE_BOX_O2_CONTENT,FLOAT32,,,,hold_register,16054,data_glove_box_o2_content
UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,9720,
UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,9520,
REG_MSG_ELECTROLYTE_NUM_USED,INT16,,,,hold_register,17496,
REG_DATA_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,16000,
UNILAB_SEND_FINISHED_CMD,BOOL,,,,coil,9730,
UNILAB_RECE_FINISHED_CMD,BOOL,,,,coil,9530,
REG_DATA_ASSEMBLY_TYPE,INT16,,,,hold_register,16018,ASSEMBLY_TYPE7or8
COIL_ALUMINUM_FOIL,BOOL,,使用铝箔垫,,coil,9340,
REG_MSG_NE_PLATE_MATRIX,INT16,,负极片矩阵点位,,hold_register,17440,
REG_MSG_SEPARATOR_PLATE_MATRIX,INT16,,隔膜矩阵点位,,hold_register,17450,
REG_MSG_TIP_BOX_MATRIX,INT16,,移液枪头矩阵点位,,hold_register,17480,
REG_MSG_NE_PLATE_NUM,INT16,,负极片盘数,,hold_register,17443,
REG_MSG_SEPARATOR_PLATE_NUM,INT16,,隔膜盘数,,hold_register,17453,
REG_MSG_PRESS_MODE,BOOL,,压制模式false:压力检测模式True:距离模式),,coil,9360,电池压制模式
,,,,,,,
,BOOL,,视觉对位false:使用true:忽略),,coil,9300,视觉对位
,BOOL,,复检false:使用true:忽略),,coil,9310,视觉复检
,BOOL,,手套箱_左仓false:使用true:忽略),,coil,9320,手套箱左仓
,BOOL,,手套箱_右仓false:使用true:忽略),,coil,9420,手套箱右仓
,BOOL,,真空检知false:使用true:忽略),,coil,9350,真空检知
,BOOL,,电解液添加模式false:单次滴液true:二次滴液),,coil,9370,滴液模式
,BOOL,,正极片称重false:使用true:忽略),,coil,9380,正极片称重
,BOOL,,正负极片组装方式false:正装true:倒装),,coil,9390,正负极反装
,BOOL,,压制清洁false:使用true:忽略),,coil,9400,压制清洁
,BOOL,,物料盘摆盘方式false:水平摆盘true:堆叠摆盘),,coil,9410,负极片摆盘方式
REG_MSG_BATTERY_CLEAN_IGNORE,BOOL,,忽略电池清洁false:使用true:忽略),,coil,9460,
1 Name DataType InitValue Comment Attribute DeviceType Address
2 COIL_SYS_START_CMD BOOL coil 9010
3 COIL_SYS_STOP_CMD BOOL coil 9020
4 COIL_SYS_RESET_CMD BOOL coil 9030
5 COIL_SYS_HAND_CMD BOOL coil 9040
6 COIL_SYS_AUTO_CMD BOOL coil 9050
7 COIL_SYS_INIT_CMD BOOL coil 9060
8 COIL_UNILAB_SEND_MSG_SUCC_CMD BOOL coil 9700
9 COIL_UNILAB_REC_MSG_SUCC_CMD BOOL coil 9710 unilab_rec_msg_succ_cmd
10 COIL_SYS_START_STATUS BOOL coil 9210
11 COIL_SYS_STOP_STATUS BOOL coil 9220
12 COIL_SYS_RESET_STATUS BOOL coil 9230
13 COIL_SYS_HAND_STATUS BOOL coil 9240
14 COIL_SYS_AUTO_STATUS BOOL coil 9250
15 COIL_SYS_INIT_STATUS BOOL coil 9260
16 COIL_REQUEST_REC_MSG_STATUS BOOL coil 9500
17 COIL_REQUEST_SEND_MSG_STATUS BOOL coil 9510 request_send_msg_status
18 REG_MSG_ELECTROLYTE_USE_NUM INT16 hold_register 17000
19 REG_MSG_ELECTROLYTE_NUM INT16 hold_register 17002 unilab_send_msg_electrolyte_num
20 REG_MSG_ELECTROLYTE_VOLUME INT16 hold_register 17004 unilab_send_msg_electrolyte_vol
21 REG_MSG_ASSEMBLY_TYPE INT16 hold_register 17006 unilab_send_msg_assembly_type
22 REG_MSG_ASSEMBLY_PRESSURE INT16 hold_register 17008 unilab_send_msg_assembly_pressure
23 REG_DATA_ASSEMBLY_COIN_CELL_NUM INT16 hold_register 16000 data_assembly_coin_cell_num
24 REG_DATA_OPEN_CIRCUIT_VOLTAGE FLOAT32 hold_register 16002 data_open_circuit_voltage
25 REG_DATA_AXIS_X_POS FLOAT32 hold_register 16004
26 REG_DATA_AXIS_Y_POS FLOAT32 hold_register 16006
27 REG_DATA_AXIS_Z_POS FLOAT32 hold_register 16008
28 REG_DATA_POLE_WEIGHT FLOAT32 hold_register 16010 data_pole_weight
29 REG_DATA_ASSEMBLY_PER_TIME FLOAT32 hold_register 16012 data_assembly_time
30 REG_DATA_ASSEMBLY_PRESSURE INT16 hold_register 16014 data_assembly_pressure
31 REG_DATA_ELECTROLYTE_VOLUME INT16 hold_register 16016 data_electrolyte_volume
32 REG_DATA_COIN_NUM INT16 hold_register 16018 data_coin_num
33 REG_DATA_ELECTROLYTE_CODE STRING hold_register 16020 data_electrolyte_code()
34 REG_DATA_COIN_CELL_CODE STRING hold_register 16030 data_coin_cell_code()
35 REG_DATA_STACK_VISON_CODE STRING hold_register 18004 data_stack_vision_code()
36 REG_DATA_GLOVE_BOX_PRESSURE FLOAT32 hold_register 16050 data_glove_box_pressure
37 REG_DATA_GLOVE_BOX_WATER_CONTENT FLOAT32 hold_register 16052 data_glove_box_water_content
38 REG_DATA_GLOVE_BOX_O2_CONTENT FLOAT32 hold_register 16054 data_glove_box_o2_content
39 UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM BOOL coil 9720
40 UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM BOOL coil 9520
41 REG_MSG_ELECTROLYTE_NUM_USED INT16 hold_register 17496
42 REG_DATA_ELECTROLYTE_USE_NUM INT16 hold_register 16000
43 UNILAB_SEND_FINISHED_CMD BOOL coil 9730
44 UNILAB_RECE_FINISHED_CMD BOOL coil 9530
45 REG_DATA_ASSEMBLY_TYPE INT16 hold_register 16018 ASSEMBLY_TYPE7or8
46 COIL_ALUMINUM_FOIL BOOL 使用铝箔垫 coil 9340
47 REG_MSG_NE_PLATE_MATRIX INT16 负极片矩阵点位 hold_register 17440
48 REG_MSG_SEPARATOR_PLATE_MATRIX INT16 隔膜矩阵点位 hold_register 17450
49 REG_MSG_TIP_BOX_MATRIX INT16 移液枪头矩阵点位 hold_register 17480
50 REG_MSG_NE_PLATE_NUM INT16 负极片盘数 hold_register 17443
51 REG_MSG_SEPARATOR_PLATE_NUM INT16 隔膜盘数 hold_register 17453
52 REG_MSG_PRESS_MODE BOOL 压制模式(false:压力检测模式,True:距离模式) coil 9360 电池压制模式
53
54 BOOL 视觉对位(false:使用,true:忽略) coil 9300 视觉对位
55 BOOL 复检(false:使用,true:忽略) coil 9310 视觉复检
56 BOOL 手套箱_左仓(false:使用,true:忽略) coil 9320 手套箱左仓
57 BOOL 手套箱_右仓(false:使用,true:忽略) coil 9420 手套箱右仓
58 BOOL 真空检知(false:使用,true:忽略) coil 9350 真空检知
59 BOOL 电解液添加模式(false:单次滴液,true:二次滴液) coil 9370 滴液模式
60 BOOL 正极片称重(false:使用,true:忽略) coil 9380 正极片称重
61 BOOL 正负极片组装方式(false:正装,true:倒装) coil 9390 正负极反装
62 BOOL 压制清洁(false:使用,true:忽略) coil 9400 压制清洁
63 BOOL 物料盘摆盘方式(false:水平摆盘,true:堆叠摆盘) coil 9410 负极片摆盘方式
64 REG_MSG_BATTERY_CLEAN_IGNORE BOOL 忽略电池清洁(false:使用,true:忽略) coil 9460

View File

@@ -502,7 +502,7 @@ coincellassemblyworkstation_device:
config_info: []
description: ''
handles: []
icon: ''
icon: coin_cell_assembly_picture.webp
init_param_schema:
config:
properties:

View File

@@ -1,37 +1,37 @@
YB_Pipette_Tip:
YB_qiang_tou:
category:
- yb3
- YB_bottle
class:
module: unilabos.resources.bioyond.YB_bottles:YB_Pipette_Tip
module: unilabos.resources.bioyond.YB_bottles:YB_qiang_tou
type: pylabrobot
description: YB_Pipette_Tip
description: YB_qiang_tou
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_fen_ye_20ml_Bottle:
YB_20ml_fenyeping:
category:
- yb3
- YB_bottle
class:
module: unilabos.resources.bioyond.YB_bottles:YB_fen_ye_20ml_Bottle
module: unilabos.resources.bioyond.YB_bottles:YB_20ml_fenyeping
type: pylabrobot
description: YB_fen_ye_20ml_Bottle
description: YB_20ml_fenyeping
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_fen_ye_5ml_Bottle:
YB_5ml_fenyeping:
category:
- yb3
- YB_bottle
class:
module: unilabos.resources.bioyond.YB_bottles:YB_fen_ye_5ml_Bottle
module: unilabos.resources.bioyond.YB_bottles:YB_5ml_fenyeping
type: pylabrobot
description: YB_fen_ye_5ml_Bottle
description: YB_5ml_fenyeping
handles: []
icon: ''
init_param_schema: {}
@@ -63,3 +63,29 @@ YB_pei_ye_xiao_Bottle:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_jia_yang_tou_da:
category:
- yb3
- YB_bottle
class:
module: unilabos.resources.bioyond.YB_bottles:YB_jia_yang_tou_da
type: pylabrobot
description: YB_jia_yang_tou_da
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_ye_Bottle:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottles:YB_ye_Bottle
type: pylabrobot
description: YB_ye_Bottle
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0

View File

@@ -1,50 +1,50 @@
YB_1Bottle100mlCarrier:
YB_100ml_yeti:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_1Bottle100mlCarrier
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_100ml_yeti
type: pylabrobot
description: YB_1Bottle100mlCarrier
description: YB_100ml_yeti
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_1BottleCarrier:
# YB_1BottleCarrier:
# category:
# - yb3
# - YB_bottle_carriers
# 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
YB_gaonianye:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_1BottleCarrier
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_gaonianye
type: pylabrobot
description: YB_1BottleCarrier
description: YB_gaonianye
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_1GaoNianYeBottleCarrier:
YB_peiyepingdaban:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_1GaoNianYeBottleCarrier
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingdaban
type: pylabrobot
description: YB_1GaoNianYeBottleCarrier
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_4x_LargeSolutionBottleCarrier:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_4x_LargeSolutionBottleCarrier
type: pylabrobot
description: YB_4x_LargeSolutionBottleCarrier
description: YB_peiyepingdaban
handles: []
icon: ''
init_param_schema: {}
@@ -76,66 +76,66 @@ YB_6VialCarrier:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_6x20ml_DispensingVialCarrier:
YB_20ml_fenyepingban:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6x20ml_DispensingVialCarrier
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_20ml_fenyepingban
type: pylabrobot
description: YB_6x20ml_DispensingVialCarrier
description: YB_20ml_fenyepingban
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_6x5ml_DispensingVialCarrier:
YB_5ml_fenyepingban:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6x5ml_DispensingVialCarrier
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_5ml_fenyepingban
type: pylabrobot
description: YB_6x5ml_DispensingVialCarrier
description: YB_5ml_fenyepingban
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_6x_SmallSolutionBottleCarrier:
YB_peiyepingxiaoban:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6x_SmallSolutionBottleCarrier
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingxiaoban
type: pylabrobot
description: YB_6x_SmallSolutionBottleCarrier
description: YB_peiyepingxiaoban
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_AdapterBlock:
YB_shi_pei_qi_kuai:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_AdapterBlock
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_shi_pei_qi_kuai
type: pylabrobot
description: YB_AdapterBlock
description: YB_shi_pei_qi_kuai
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_TipBox:
YB_qiang_tou_he:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_TipBox
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_qiang_tou_he
type: pylabrobot
description: YB_TipBox
description: YB_qiang_tou_he
handles: []
icon: ''
init_param_schema: {}
@@ -154,27 +154,27 @@ YB_gao_nian_ye_Bottle:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_jia_yang_tou_da:
# YB_jia_yang_tou_da:
# category:
# - yb3
# - YB_bottle_carriers
# class:
# module: unilabos.resources.bioyond.YB_bottles:YB_jia_yang_tou_da
# type: pylabrobot
# description: YB_jia_yang_tou_da
# handles: []
# icon: ''
# init_param_schema: {}
# registry_type: resource
# version: 1.0.0
YB_jia_yang_tou_da_Carrier:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottles:YB_jia_yang_tou_da
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_jia_yang_tou_da_Carrier
type: pylabrobot
description: YB_jia_yang_tou_da
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_jia_yang_tou_da_1X1_carrier:
category:
- yb3
- YB_bottle_carriers
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
description: YB_jia_yang_tou_da_Carrier
handles: []
icon: ''
init_param_schema: {}
@@ -193,14 +193,14 @@ YB_ye_100ml_Bottle:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_ye_Bottle:
YB_ye:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottles:YB_ye_Bottle
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_ye
type: pylabrobot
description: YB_ye_Bottle
description: YB_ye_Bottle_Carrier
handles: []
icon: ''
init_param_schema: {}

View File

@@ -0,0 +1,179 @@
from typing import Any, Dict, Optional, TypedDict
from pylabrobot.resources import Resource as ResourcePLR
from pylabrobot.resources import Container
electrode_colors = {
"PositiveCan": "#ff0000",
"PositiveElectrode": "#cc3333",
"NegativeCan": "#000000",
"NegativeElectrode": "#666666",
"SpringWasher": "#8b7355",
"FlatWasher": "a9a9a9",
"AluminumFoil": "#ffcccc",
"Battery": "#00ff00",
}
class ElectrodeSheetState(TypedDict):
mass: float # 质量 (g)
material_type: str # 材料类型(铜、铝、不锈钢、弹簧钢等)
color: str # 材料类型对应的颜色
class ElectrodeSheet(ResourcePLR):
"""极片类 - 包含正负极片、隔膜、弹片、垫片、铝箔等所有片状材料"""
def __init__(
self,
name: str = "极片",
size_x=10,
size_y=10,
size_z=10,
category: str = "electrode_sheet",
model: Optional[str] = None,
):
"""初始化极片
Args:
name: 极片名称
category: 类别
model: 型号
"""
super().__init__(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
category=category,
model=model,
)
self._unilabos_state: ElectrodeSheetState = ElectrodeSheetState(
diameter=14,
thickness=0.1,
mass=0.5,
material_type="copper",
info=None
)
# TODO: 这个还要不要给self._unilabos_state赋值的
def load_state(self, state: Dict[str, Any]) -> None:
"""格式不变"""
super().load_state(state)
self._unilabos_state = state
#序列化
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
"""格式不变"""
data = super().serialize_state()
data.update(self._unilabos_state) # Container自身的信息云端物料将保存这一data本地也通过这里的data进行读写当前类用来表示这个物料的长宽高大小的属性而datastate用来表示物料的内容细节等
return data
def PositiveCan(name: str) -> ElectrodeSheet:
"""创建正极壳"""
sheet = ElectrodeSheet(name=name, size_x=12, size_y=12, size_z=3.0, model="PositiveCan")
sheet.load_state({"material_type": "aluminum", "color": electrode_colors["PositiveCan"]})
return sheet
def PositiveElectrode(name: str) -> ElectrodeSheet:
"""创建正极片"""
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.1, model="PositiveElectrode")
sheet.load_state({"material_type": "positive_electrode", "color": electrode_colors["PositiveElectrode"]})
return sheet
def NegativeCan(name: str) -> ElectrodeSheet:
"""创建负极壳"""
sheet = ElectrodeSheet(name=name, size_x=12, size_y=12, size_z=2.0, model="NegativeCan")
sheet.load_state({"material_type": "steel", "color": electrode_colors["NegativeCan"]})
return sheet
def NegativeElectrode(name: str) -> ElectrodeSheet:
"""创建负极片"""
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.1, model="NegativeElectrode")
sheet.load_state({"material_type": "negative_electrode", "color": electrode_colors["NegativeElectrode"]})
return sheet
def SpringWasher(name: str) -> ElectrodeSheet:
"""创建弹片"""
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.5, model="SpringWasher")
sheet.load_state({"material_type": "spring_steel", "color": electrode_colors["SpringWasher"]})
return sheet
def FlatWasher(name: str) -> ElectrodeSheet:
"""创建垫片"""
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.2, model="FlatWasher")
sheet.load_state({"material_type": "steel", "color": electrode_colors["FlatWasher"]})
return sheet
def AluminumFoil(name: str) -> ElectrodeSheet:
"""创建铝箔"""
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.05, model="AluminumFoil")
sheet.load_state({"material_type": "aluminum", "color": electrode_colors["AluminumFoil"]})
return sheet
class BatteryState(TypedDict):
color: str # 材料类型对应的颜色
electrolyte_name: str
data_electrolyte_code: str
open_circuit_voltage: float
assembly_pressure: float
electrolyte_volume: float
info: Optional[str] # 附加信息
class Battery(Container):
"""电池类 - 包含组装好的电池"""
def __init__(
self,
name: str = "电池",
size_x=12,
size_y=12,
size_z=6,
category: str = "battery",
model: Optional[str] = None,
):
"""初始化电池
Args:
name: 电池名称
category: 类别
model: 型号
"""
super().__init__(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
category=category,
model=model,
)
self._unilabos_state: BatteryState = BatteryState(
color=electrode_colors["Battery"],
electrolyte_name="",
data_electrolyte_code="",
open_circuit_voltage=0.0,
assembly_pressure=0.0,
electrolyte_volume=0.0,
info=None
)
def load_state(self, state: Dict[str, Any]) -> None:
"""格式不变"""
super().load_state(state)
self._unilabos_state = state
#序列化
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
"""格式不变"""
data = super().serialize_state()
data.update(self._unilabos_state) # Container自身的信息云端物料将保存这一data本地也通过这里的data进行读写当前类用来表示这个物料的长宽高大小的属性而datastate用来表示物料的内容细节等
return data

View File

@@ -1,10 +1,18 @@
from typing import Dict, List, Optional, OrderedDict, Union
from typing import Dict, List, Optional, OrderedDict, Union, Callable
import math
from pylabrobot.resources.coordinate import Coordinate
from pylabrobot.resources import Resource, ResourceStack, ItemizedResource
from pylabrobot.resources.carrier import create_homogeneous_resources
from unilabos.resources.battery.electrode_sheet import (
PositiveCan, PositiveElectrode,
NegativeCan, NegativeElectrode,
SpringWasher, FlatWasher,
AluminumFoil,
Battery
)
class Magazine(ResourceStack):
"""子弹夹洞位类"""
@@ -32,6 +40,18 @@ class Magazine(ResourceStack):
)
self.max_sheets = max_sheets
@property
def size_x(self) -> float:
return self.get_size_x()
@property
def size_y(self) -> float:
return self.get_size_y()
@property
def size_z(self) -> float:
return self.get_size_z()
class MagazineHolder(ItemizedResource):
"""子弹夹类 - 有多个洞位,每个洞位放多个极片"""
@@ -98,6 +118,7 @@ def magazine_factory(
size_y: float,
size_z: float,
locations: List[Coordinate],
klasses: Optional[List[Callable[[str], str]]] = None,
hole_diameter: float = 14.0,
hole_depth: float = 10.0,
max_sheets_per_hole: int = 100,
@@ -112,12 +133,17 @@ def magazine_factory(
size_y: 宽度 (mm)
size_z: 高度 (mm)
locations: 洞位坐标列表
klasses: 每个洞位中极片的类列表
hole_diameter: 洞直径 (mm)
hole_depth: 洞深度 (mm)
max_sheets_per_hole: 每个洞位最大极片数量
category: 类别
model: 型号
"""
for loc in locations:
loc.x -= hole_diameter / 2
loc.y -= hole_diameter / 2
# 创建洞位
_sites = create_homogeneous_resources(
klass=Magazine,
@@ -132,7 +158,7 @@ def magazine_factory(
keys = [f"A{i+1}" for i in range(len(locations))]
sites = dict(zip(keys, _sites.values()))
return MagazineHolder(
holder = MagazineHolder(
name=name,
size_x=size_x,
size_y=size_y,
@@ -145,18 +171,143 @@ def magazine_factory(
model=model,
)
if klasses is not None:
for i, klass in enumerate(klasses):
hole_key = keys[i]
hole = holder.children[i]
for j in reversed(range(max_sheets_per_hole)):
item_name = f"{hole_key}_sheet{j+1}"
item = klass(name=item_name)
hole.assign_child_resource(item)
return holder
def MagazineHolder_4(
def MagazineHolder_6_Cathode(
name: str,
size_x: float = 80.0,
size_y: float = 80.0,
size_z: float = 10.0,
size_z: float = 40.0,
hole_diameter: float = 14.0,
hole_depth: float = 10.0,
hole_spacing: float = 25.0,
hole_spacing: float = 20.0,
max_sheets_per_hole: int = 100,
) -> MagazineHolder:
"""创建6孔子弹夹 - 六边形排布"""
center_x = size_x / 2
center_y = size_y / 2
locations = []
# 周围6个孔按六边形排布
for i in range(6):
angle = i * 60 * math.pi / 180 # 每60度一个孔
x = center_x + hole_spacing * math.cos(angle)
y = center_y + hole_spacing * math.sin(angle)
locations.append(Coordinate(x, y, size_z - hole_depth))
return magazine_factory(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
locations=locations,
klasses=[FlatWasher, PositiveCan, PositiveCan, FlatWasher, PositiveCan, PositiveCan],
hole_diameter=hole_diameter,
hole_depth=hole_depth,
max_sheets_per_hole=max_sheets_per_hole,
category="magazine_holder",
model="MagazineHolder_6_Cathode",
)
def MagazineHolder_6_Anode(
name: str,
size_x: float = 80.0,
size_y: float = 80.0,
size_z: float = 40.0,
hole_diameter: float = 14.0,
hole_depth: float = 10.0,
hole_spacing: float = 20.0,
max_sheets_per_hole: int = 100,
) -> MagazineHolder:
"""创建6孔子弹夹 - 六边形排布"""
center_x = size_x / 2
center_y = size_y / 2
locations = []
# 周围6个孔按六边形排布
for i in range(6):
angle = i * 60 * math.pi / 180 # 每60度一个孔
x = center_x + hole_spacing * math.cos(angle)
y = center_y + hole_spacing * math.sin(angle)
locations.append(Coordinate(x, y, size_z - hole_depth))
return magazine_factory(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
locations=locations,
klasses=[SpringWasher, NegativeCan, NegativeCan, SpringWasher, NegativeCan, NegativeCan],
hole_diameter=hole_diameter,
hole_depth=hole_depth,
max_sheets_per_hole=max_sheets_per_hole,
category="magazine_holder",
model="MagazineHolder_6_Anode",
)
def MagazineHolder_6_Battery(
name: str,
size_x: float = 80.0,
size_y: float = 80.0,
size_z: float = 40.0,
hole_diameter: float = 14.0,
hole_depth: float = 10.0,
hole_spacing: float = 20.0,
max_sheets_per_hole: int = 100,
) -> MagazineHolder:
"""创建6孔子弹夹 - 六边形排布"""
center_x = size_x / 2
center_y = size_y / 2
locations = []
# 周围6个孔按六边形排布
for i in range(6):
angle = i * 60 * math.pi / 180 # 每60度一个孔
x = center_x + hole_spacing * math.cos(angle)
y = center_y + hole_spacing * math.sin(angle)
locations.append(Coordinate(x, y, size_z - hole_depth))
return magazine_factory(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
locations=locations,
klasses=None, # 初始化时,不放入装好的电池
hole_diameter=hole_diameter,
hole_depth=hole_depth,
max_sheets_per_hole=max_sheets_per_hole,
category="magazine_holder",
model="MagazineHolder_6_Battery",
)
def MagazineHolder_4_Cathode(
name: str,
) -> MagazineHolder:
"""创建4孔子弹夹 - 正方形四角排布"""
size_x: float = 80.0
size_y: float = 80.0
size_z: float = 10.0
hole_diameter: float = 14.0
hole_depth: float = 10.0
hole_spacing: float = 25.0
max_sheets_per_hole: int = 100
# 计算4个洞位的坐标正方形四角排布
center_x = size_x / 2
center_y = size_y / 2
@@ -175,110 +326,10 @@ def MagazineHolder_4(
size_y=size_y,
size_z=size_z,
locations=locations,
klasses=[AluminumFoil, PositiveElectrode, PositiveElectrode, PositiveElectrode],
hole_diameter=hole_diameter,
hole_depth=hole_depth,
max_sheets_per_hole=max_sheets_per_hole,
category="clip_magazine_four",
category="magazine_holder",
model="MagazineHolder_4_Cathode",
)
def MagazineHolder_2(
name: str,
size_x: float = 80.0,
size_y: float = 80.0,
size_z: float = 10.0,
hole_diameter: float = 14.0,
hole_depth: float = 10.0,
hole_spacing: float = 25.0,
max_sheets_per_hole: int = 100,
) -> MagazineHolder:
"""创建2孔子弹夹 - 竖向排布"""
# 计算2个洞位的坐标竖向排布
center_x = size_x / 2
center_y = size_y / 2
offset = hole_spacing / 2
locations = [
Coordinate(center_x, center_y - offset, size_z - hole_depth), # 下方
Coordinate(center_x, center_y + offset, size_z - hole_depth), # 上方
]
return magazine_factory(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
locations=locations,
hole_diameter=hole_diameter,
hole_depth=hole_depth,
max_sheets_per_hole=max_sheets_per_hole,
category="clip_magazine_two",
)
def MagazineHolder_1(
name: str,
size_x: float = 80.0,
size_y: float = 80.0,
size_z: float = 10.0,
hole_diameter: float = 14.0,
hole_depth: float = 10.0,
max_sheets_per_hole: int = 100,
) -> MagazineHolder:
"""创建1孔子弹夹 - 中心单孔"""
# 计算1个洞位的坐标中心位置
center_x = size_x / 2
center_y = size_y / 2
locations = [
Coordinate(center_x, center_y, size_z - hole_depth), # 中心
]
return magazine_factory(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
locations=locations,
hole_diameter=hole_diameter,
hole_depth=hole_depth,
max_sheets_per_hole=max_sheets_per_hole,
category="clip_magazine_one",
)
def MagazineHolder_6(
name: str,
size_x: float = 80.0,
size_y: float = 80.0,
size_z: float = 40.0,
hole_diameter: float = 14.0,
hole_depth: float = 10.0,
hole_spacing: float = 20.0,
max_sheets_per_hole: int = 100,
) -> MagazineHolder:
"""创建6孔子弹夹 - 六边形排布"""
# 计算6个洞位的坐标六边形排布中心1个周围5个
center_x = size_x / 2
center_y = size_y / 2
locations = []
# 周围6个孔按六边形排布
for i in range(6):
angle = i * 60 * math.pi / 180 # 每60度一个孔
x = center_x + hole_spacing * math.cos(angle)
y = center_y + hole_spacing * math.sin(angle)
locations.append(Coordinate(x, y, size_z - hole_depth))
return magazine_factory(
name=name,
size_x=size_x,
size_y=size_y,
size_z=size_z,
locations=locations,
hole_diameter=hole_diameter,
hole_depth=hole_depth,
max_sheets_per_hole=max_sheets_per_hole,
category="clip_magazine_six",
)

View File

@@ -6,11 +6,11 @@ from unilabos.resources.bioyond.YB_bottles import (
YB_ye_Bottle,
YB_ye_100ml_Bottle,
YB_gao_nian_ye_Bottle,
YB_fen_ye_5ml_Bottle,
YB_fen_ye_20ml_Bottle,
YB_5ml_fenyeping,
YB_20ml_fenyeping,
YB_pei_ye_xiao_Bottle,
YB_pei_ye_da_Bottle,
YB_Pipette_Tip,
YB_qiang_tou,
)
# 命名约定:试剂瓶-Bottle烧杯-Beaker烧瓶-Flask小瓶-Vial
@@ -206,7 +206,7 @@ def YB_6VialCarrier(name: str) -> BottleCarrier:
return carrier
# 1瓶载架 - 单个中央位置
def YB_1BottleCarrier(name: str) -> BottleCarrier:
def YB_ye(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
carrier_size_x = 127.8
@@ -233,7 +233,7 @@ def YB_1BottleCarrier(name: str) -> BottleCarrier:
resource_size_y=beaker_diameter,
name_prefix=name,
),
model="1BottleCarrier",
model="YB_ye",
)
carrier.num_items_x = 1
carrier.num_items_y = 1
@@ -243,7 +243,7 @@ def YB_1BottleCarrier(name: str) -> BottleCarrier:
# 高粘液瓶载架 - 单个中央位置
def YB_1GaoNianYeBottleCarrier(name: str) -> BottleCarrier:
def YB_gaonianye(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
carrier_size_x = 127.8
@@ -270,7 +270,7 @@ def YB_1GaoNianYeBottleCarrier(name: str) -> BottleCarrier:
resource_size_y=beaker_diameter,
name_prefix=name,
),
model="1GaoNianYeBottleCarrier",
model="YB_gaonianye",
)
carrier.num_items_x = 1
carrier.num_items_y = 1
@@ -280,7 +280,7 @@ def YB_1GaoNianYeBottleCarrier(name: str) -> BottleCarrier:
# 100ml液体瓶载架 - 单个中央位置
def YB_1Bottle100mlCarrier(name: str) -> BottleCarrier:
def YB_100ml_yeti(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
carrier_size_x = 127.8
@@ -307,7 +307,7 @@ def YB_1Bottle100mlCarrier(name: str) -> BottleCarrier:
resource_size_y=beaker_diameter,
name_prefix=name,
),
model="1Bottle100mlCarrier",
model="YB_100ml_yeti",
)
carrier.num_items_x = 1
carrier.num_items_y = 1
@@ -316,7 +316,7 @@ def YB_1Bottle100mlCarrier(name: str) -> BottleCarrier:
return carrier
# 5ml分液瓶板 - 4x2布局8个位置
def YB_6x5ml_DispensingVialCarrier(name: str) -> BottleCarrier:
def YB_5ml_fenyepingban(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
@@ -355,18 +355,18 @@ def YB_6x5ml_DispensingVialCarrier(name: str) -> BottleCarrier:
size_y=carrier_size_y,
size_z=carrier_size_z,
sites=sites,
model="6x5ml_DispensingVialCarrier",
model="YB_5ml_fenyepingban",
)
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] = YB_fen_ye_5ml_Bottle(f"{name}_vial_{ordering[i]}")
carrier[i] = YB_5ml_fenyeping(f"{name}_vial_{ordering[i]}")
return carrier
# 20ml分液瓶板 - 4x2布局8个位置
def YB_6x20ml_DispensingVialCarrier(name: str) -> BottleCarrier:
def YB_20ml_fenyepingban(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
@@ -405,18 +405,18 @@ def YB_6x20ml_DispensingVialCarrier(name: str) -> BottleCarrier:
size_y=carrier_size_y,
size_z=carrier_size_z,
sites=sites,
model="6x20ml_DispensingVialCarrier",
model="YB_20ml_fenyepingban",
)
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] = YB_fen_ye_20ml_Bottle(f"{name}_vial_{ordering[i]}")
carrier[i] = YB_20ml_fenyeping(f"{name}_vial_{ordering[i]}")
return carrier
# 配液瓶(小)板 - 4x2布局8个位置
def YB_6x_SmallSolutionBottleCarrier(name: str) -> BottleCarrier:
def YB_peiyepingxiaoban(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
@@ -455,7 +455,7 @@ def YB_6x_SmallSolutionBottleCarrier(name: str) -> BottleCarrier:
size_y=carrier_size_y,
size_z=carrier_size_z,
sites=sites,
model="6x_SmallSolutionBottleCarrier",
model="YB_peiyepingxiaoban",
)
carrier.num_items_x = 4
carrier.num_items_y = 2
@@ -467,7 +467,7 @@ def YB_6x_SmallSolutionBottleCarrier(name: str) -> BottleCarrier:
# 配液瓶(大)板 - 2x2布局4个位置
def YB_4x_LargeSolutionBottleCarrier(name: str) -> BottleCarrier:
def YB_peiyepingdaban(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
carrier_size_x = 127.8
@@ -505,7 +505,7 @@ def YB_4x_LargeSolutionBottleCarrier(name: str) -> BottleCarrier:
size_y=carrier_size_y,
size_z=carrier_size_z,
sites=sites,
model="4x_LargeSolutionBottleCarrier",
model="YB_peiyepingdaban",
)
carrier.num_items_x = 2
carrier.num_items_y = 2
@@ -516,7 +516,7 @@ def YB_4x_LargeSolutionBottleCarrier(name: str) -> BottleCarrier:
return carrier
# 加样头(大)板 - 1x1布局1个位置
def YB_jia_yang_tou_da_1X1_carrier(name: str) -> BottleCarrier:
def YB_jia_yang_tou_da_Carrier(name: str) -> BottleCarrier:
# 载架尺寸 (mm)
carrier_size_x = 127.8
@@ -554,7 +554,7 @@ def YB_jia_yang_tou_da_1X1_carrier(name: str) -> BottleCarrier:
size_y=carrier_size_y,
size_z=carrier_size_z,
sites=sites,
model="6x_LargeDispenseHeadCarrier",
model="YB_jia_yang_tou_da_Carrier",
)
carrier.num_items_x = 1
carrier.num_items_y = 1
@@ -563,7 +563,7 @@ def YB_jia_yang_tou_da_1X1_carrier(name: str) -> BottleCarrier:
return carrier
def YB_AdapterBlock(name: str) -> BottleCarrier:
def YB_shi_pei_qi_kuai(name: str) -> BottleCarrier:
"""适配器块 - 单个中央位置"""
# 载架尺寸 (mm)
@@ -591,7 +591,7 @@ def YB_AdapterBlock(name: str) -> BottleCarrier:
resource_size_y=adapter_diameter,
name_prefix=name,
),
model="AdapterBlock",
model="YB_shi_pei_qi_kuai",
)
carrier.num_items_x = 1
carrier.num_items_y = 1
@@ -600,7 +600,7 @@ def YB_AdapterBlock(name: str) -> BottleCarrier:
return carrier
def YB_TipBox(name: str) -> BottleCarrier:
def YB_qiang_tou_he(name: str) -> BottleCarrier:
"""枪头盒 - 8x12布局96个位置"""
# 载架尺寸 (mm)
@@ -639,7 +639,7 @@ def YB_TipBox(name: str) -> BottleCarrier:
size_y=carrier_size_y,
size_z=carrier_size_z,
sites=sites,
model="TipBox",
model="YB_qiang_tou_he",
)
carrier.num_items_x = 12
carrier.num_items_y = 8
@@ -648,6 +648,6 @@ def YB_TipBox(name: str) -> BottleCarrier:
for i in range(96):
row = chr(65 + i // 12) # A-H
col = (i % 12) + 1 # 1-12
carrier[i] = YB_Pipette_Tip(f"{name}_tip_{row}{col}")
carrier[i] = YB_qiang_tou(f"{name}_tip_{row}{col}")
return carrier

View File

@@ -15,7 +15,7 @@ def YB_jia_yang_tou_da(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Solid_Stock",
model="YB_jia_yang_tou_da",
)
"""液1x1"""
@@ -33,7 +33,7 @@ def YB_ye_Bottle(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Liquid_Bottle",
model="YB_ye_Bottle",
)
"""100ml液体"""
@@ -51,7 +51,7 @@ def YB_ye_100ml_Bottle(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Liquid_Bottle_100ml",
model="YB_100ml_yeti",
)
"""高粘液"""
@@ -73,7 +73,7 @@ def YB_gao_nian_ye_Bottle(
)
"""5ml分液瓶"""
def YB_fen_ye_5ml_Bottle(
def YB_5ml_fenyeping(
name: str,
diameter: float = 20.0,
height: float = 50.0,
@@ -87,11 +87,11 @@ def YB_fen_ye_5ml_Bottle(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Separation_Bottle_5ml",
model="YB_5ml_fenyeping",
)
"""20ml分液瓶"""
def YB_fen_ye_20ml_Bottle(
def YB_20ml_fenyeping(
name: str,
diameter: float = 30.0,
height: float = 65.0,
@@ -105,7 +105,7 @@ def YB_fen_ye_20ml_Bottle(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Separation_Bottle_20ml",
model="YB_20ml_fenyeping",
)
"""配液瓶(小)"""
@@ -123,7 +123,7 @@ def YB_pei_ye_xiao_Bottle(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Mixing_Bottle_Small",
model="YB_pei_ye_xiao_Bottle",
)
"""配液瓶(大)"""
@@ -141,11 +141,11 @@ def YB_pei_ye_da_Bottle(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Mixing_Bottle_Large",
model="YB_pei_ye_da_Bottle",
)
"""枪头"""
def YB_Pipette_Tip(
def YB_qiang_tou(
name: str,
diameter: float = 10.0,
height: float = 50.0,
@@ -159,5 +159,5 @@ def YB_Pipette_Tip(
height=height,
max_volume=max_volume,
barcode=barcode,
model="Pipette_Tip",
model="YB_qiang_tou",
)

View File

@@ -89,11 +89,9 @@ class BIOYOND_YB_Deck(Deck):
"自动堆栈-右": bioyond_warehouse_2x2x1("自动堆栈-右"),
"手动堆栈-左": bioyond_warehouse_3x5x1("手动堆栈-左"),
"手动堆栈-右": bioyond_warehouse_3x5x1("手动堆栈-右"),
"粉末加样头堆栈-左": bioyond_warehouse_10x1x1("粉末加样头堆栈-左"),
"粉末加样头堆栈-右": bioyond_warehouse_10x1x1("粉末加样头堆栈-右"),
"粉末加样头堆栈": bioyond_warehouse_20x1x1("粉末加样头堆栈"),
"配液站内试剂仓库": bioyond_warehouse_3x3x1("配液站内试剂仓库"),
"试剂替换仓库-左": bioyond_warehouse_5x1x1("试剂替换仓库-左"),
"试剂替换仓库-右": bioyond_warehouse_5x1x1("试剂替换仓库-右"),
"试剂替换仓库": bioyond_warehouse_10x1x1("试剂替换仓库"),
}
# warehouse 的位置
self.warehouse_locations = {
@@ -101,11 +99,9 @@ class BIOYOND_YB_Deck(Deck):
"自动堆栈-右": Coordinate(4160.0, 158.0, 0.0),
"手动堆栈-左": Coordinate(-400.0, 877.0, 0.0),
"手动堆栈-右": Coordinate(4160.0, 877.0, 0.0),
"粉末加样头堆栈-左": Coordinate(415.0, 1301.0, 0.0),
"粉末加样头堆栈-右": Coordinate(2200.0, 1304.0, 0.0),
"粉末加样头堆栈": Coordinate(415.0, 1301.0, 0.0),
"配液站内试剂仓库": Coordinate(2162.0, 337.0, 0.0),
"试剂替换仓库-左": Coordinate(1173.0, 702.0, 0.0),
"试剂替换仓库-右": Coordinate(2721.0, 739.0, 0.0),
"试剂替换仓库": Coordinate(1173.0, 702.0, 0.0),
}
for warehouse_name, warehouse in self.warehouses.items():

View File

@@ -652,7 +652,7 @@ class HostNode(BaseROS2DeviceNode):
if bCreate:
self.lab_logger().trace(f"Status created: {device_id}.{property_name} = {msg.data}")
else:
self.lab_logger().debug(f"Status updated: {device_id}.{property_name} = {msg.data}")
self.lab_logger().trace(f"Status updated: {device_id}.{property_name} = {msg.data}")
def send_goal(
self,

View File

@@ -191,8 +191,19 @@ def configure_logger(loglevel=None):
# 添加处理器到根日志记录器
root_logger.addHandler(console_handler)
logging.getLogger("asyncio").setLevel(logging.INFO)
logging.getLogger("urllib3").setLevel(logging.INFO)
# 降低第三方库的日志级别,避免过多输出
# pymodbus 库的日志太详细,设置为 WARNING
logging.getLogger('pymodbus').setLevel(logging.WARNING)
logging.getLogger('pymodbus.logging').setLevel(logging.WARNING)
logging.getLogger('pymodbus.logging.base').setLevel(logging.WARNING)
logging.getLogger('pymodbus.logging.decoders').setLevel(logging.WARNING)
# websockets 库的日志输出较多,设置为 WARNING
logging.getLogger('websockets').setLevel(logging.WARNING)
logging.getLogger('websockets.client').setLevel(logging.WARNING)
logging.getLogger('websockets.server').setLevel(logging.WARNING)
# 配置日志系统
configure_logger()