12 Commits

Author SHA1 Message Date
Calvin Cao
6413828c59 Merge pull request #183 from sun7151887/yb_fix5
添加新威电池测试系统设备节点到配置文件
2025-12-02 17:06:07 +08:00
dijkstra402
5072f00836 添加新威电池测试系统设备节点到配置文件
- 在 new_cellconfig3c.json 中新增 NewareTester 设备
- 配置 IP:127.0.0.1, Port:502, Machine_ID:1
- 修复之前的 JSON 格式错误(重复对象和数组语法错误)
- 设备位置设置为 (1500, 0, 0),避免与其他设备重叠
- 包含功能说明: 720通道监控、2盘电池物料管理、CSV批量提交
2025-12-02 17:01:02 +08:00
Calvin Cao
9dfbe3246e Merge pull request #182 from sun7151887/yb_fix5
解决前端物料显示问题
2025-12-02 16:07:55 +08:00
dijkstra402
bef69db3b6 解决前端物料显示问题 2025-12-02 15:42:07 +08:00
Calvin Cao
a061bc2942 Merge pull request #181 from sun7151887/yb_fix5
修复遇到的参数错误和物料转换问题
2025-12-02 11:26:54 +08:00
dijkstra402
8c9e11c04f chore: 更新 Excel 模板文件
- 更新 2025092701.xlsx 配方文件
- 更新 material_template.xlsx 物料模板
2025-12-02 11:08:48 +08:00
dijkstra402
e4e3ec805a feat: 添加三阶段工作流函数和别名映射
- 在 BioyondCellWorkstation 添加 run_feeding_stage, run_liquid_preparation_stage, run_transfer_stage 三个阶段函数
- 在 host_node.py 添加 JSON_COMMAND_ALIASES 映射表,支持 run_feeding_stage -> auto_feeding4to3 别名
- 修复 create_orders 中 transfer_resource_to_another 参数名错误
- 简化 run_transfer_stage,注释掉物料转换逻辑,只保留核心转运功能
2025-12-02 11:05:36 +08:00
dijkstra402
d634316bce feat: enhance BioyondCellWorkstation and CoinCellAssembly workflows
- Added support for transferring resources between workstations with detailed logging.
- Introduced new methods for material conversion and resource registration.
- Updated YAML configurations to reflect new parameters and structures for workflows.
- Enhanced error handling and logging for better debugging and operational clarity.
2025-11-27 10:46:40 +08:00
Calvin Cao
f5446c6480 Merge pull request #174 from sun7151887/yb_fix5
奔曜实现物料流
2025-11-25 18:39:56 +08:00
dijkstra402
a98d25c16d feat: expose workflow material outputs 2025-11-25 18:27:34 +08:00
Calvin Cao
80b9589973 Merge pull request #173 from sun7151887/yb_fix5
fix: 修复 BioyondCellWorkstation 和 CoinCellAssembly 工作流程
2025-11-25 18:26:26 +08:00
dijkstra402
4d4bbcbae8 fix: 修复 BioyondCellWorkstation 和 CoinCellAssembly 工作流程
- 修复 run 方法的函数参数语法错误(冒号改为等号)
- 将 BioyondCellWorkstation 的 run 函数移入类内部
- 添加 run_bioyond_cell_workflow 方法支持可选的 1to2 步骤
- 更新相关 YAML 配置文件
2025-11-25 15:39:07 +08:00
15 changed files with 1234 additions and 357 deletions

View File

@@ -90,9 +90,48 @@
}
},
"data": {}
},
{
"id": "NewareTester",
"name": "新威电池测试系统",
"parent": null,
"children": [],
"type": "device",
"class": "neware_battery_test_system",
"config": {
"ip": "127.0.0.1",
"port": 502,
"machine_id": 1,
"devtype": "27",
"timeout": 20,
"size_x": 500.0,
"size_y": 500.0,
"size_z": 2000.0
},
"position": {
"size": {
"height": 1600,
"width": 1200,
"depth": 800
},
"position": {
"x": 1500,
"y": 0,
"z": 0
}
},
"data": {
"功能说明": "新威电池测试系统提供720通道监控和CSV批量提交功能",
"监控功能": "支持720个通道的实时状态监控、2盘电池物料管理、状态导出等",
"提交功能": "通过submit_from_csv action从CSV文件批量提交测试任务"
}
}
],
"links": []
}

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from cgi import print_arguments
from doctest import debug
from typing import Dict, Any, List, Optional
from typing import Dict, Any, List, Optional, Tuple
import requests
from pylabrobot.resources.resource import Resource as ResourcePLR
from pathlib import Path
@@ -19,8 +19,22 @@ from unilabos.devices.workstation.bioyond_studio.config import (
)
from unilabos.devices.workstation.workstation_http_service import WorkstationHTTPService
from unilabos.resources.bioyond.decks import BIOYOND_YB_Deck
from unilabos.resources.graphio import resource_bioyond_to_plr
from unilabos.utils.log import logger
from unilabos.registry.registry import lab_registry
from unilabos.ros.nodes.base_device_node import ROS2DeviceNode
class device(BIOYOND_YB_Deck):
@classmethod
def deserialize(cls, data, allow_marshal=False): # type: ignore[override]
patched = dict(data)
if patched.get("type") == "device":
patched["type"] = "Deck"
if patched.get("category") == "device":
patched["category"] = "deck"
return super().deserialize(patched, allow_marshal=allow_marshal)
def _iso_local_now_ms() -> str:
# 文档要求:到毫秒 + Z例如 2025-08-15T05:43:22.814Z
@@ -44,8 +58,10 @@ class BioyondCellWorkstation(BioyondWorkstation):
**API_CONFIG,
"material_type_mappings": MATERIAL_TYPE_MAPPINGS,
"warehouse_mapping": WAREHOUSE_MAPPING,
"debug_mode": False
"debug_mode": False,
}
if config:
self.bioyond_config.update(config)
# "material_type_mappings": MATERIAL_TYPE_MAPPINGS
# "warehouse_mapping": WAREHOUSE_MAPPING
@@ -56,6 +72,12 @@ class BioyondCellWorkstation(BioyondWorkstation):
self.http_service_started = self.debug_mode
self._device_id = "bioyond_cell_workstation" # 默认值后续会从_ros_node获取
super().__init__(bioyond_config=config, deck=deck)
self.transfer_target_device_id = self.bioyond_config.get("transfer_target_device_id", "BatteryStation")
self.transfer_target_parent = self.bioyond_config.get("transfer_target_parent", "YB_YH_Deck")
self.transfer_timeout = float(self.bioyond_config.get("transfer_timeout", 180.0))
self.coin_cell_workflow_config = self.bioyond_config.get("coin_cell_workflow_config", {})
self.pending_transfer_materials: List[Dict[str, Any]] = []
self.pending_transfer_plr: List[ResourcePLR] = []
self.update_push_ip() #直接修改奔耀端的报送ip地址
logger.info("已更新奔耀端推送 IP 地址")
@@ -257,7 +279,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
def auto_feeding4to3(
self,
# ★ 修改点:默认模板路径
xlsx_path: Optional[str] = "/Users/calvincao/Desktop/work/uni-lab-all/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,
@@ -394,10 +416,14 @@ class BioyondCellWorkstation(BioyondWorkstation):
order_code = response.get("data", {}).get("orderCode")
if not order_code:
logger.error("上料任务未返回有效 orderCode")
return response
return {"api_response": response, "order_finish": None}
# 等待完成报送
result = self.wait_for_order_finish(order_code)
return result
return {
"api_response": response,
"order_finish": result,
"items": items,
}
def auto_batch_outbound_from_xlsx(self, xlsx_path: str) -> Dict[str, Any]:
@@ -468,7 +494,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
return response
# 2.14 新建实验
def create_orders(self, xlsx_path: str) -> Dict[str, Any]:
def create_orders(self, xlsx_path: str, *, material_filter: Optional[str] = None) -> Dict[str, Any]:
"""
从 Excel 解析并创建实验2.14
约定:
@@ -477,7 +503,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
- totalMass 自动计算为所有物料质量之和
- createTime 缺失或为空时自动填充为当前日期YYYY/M/D
"""
default_path = Path("/Users/calvincao/Desktop/work/uni-lab-all/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx")
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:
@@ -625,7 +651,34 @@ class BioyondCellWorkstation(BioyondWorkstation):
return response
# 等待完成报送
result = self.wait_for_order_finish(order_code)
return result
report_data = result.get("report") if isinstance(result, dict) else None
materials_from_report = (
report_data.get("usedMaterials") if isinstance(report_data, dict) else None
)
if materials_from_report:
materials = materials_from_report
logger.info(
"[create_orders] 使用订单完成报送中的物料信息: "
f"{len(materials)}"
)
else:
materials = self._fetch_bioyond_materials(filter_keyword=material_filter)
logger.info(
"[create_orders] 未收到订单报送物料信息,回退到实时查询"
)
print("materials_from_report:", materials_from_report)
# TODO: 需要将 materials 字典转换为 ResourceSlot 对象后才能转运
# self.transfer_resource_to_another(
# resource=[materials],
# mount_resource=["YB_YH_Deck"],
# sites=[None],
# mount_device_id="BatteryStation"
# )
return {
"api_response": response,
"order_finish": result,
"materials": materials,
}
# 2.7 启动调度
def scheduler_start(self) -> Dict[str, Any]:
@@ -697,6 +750,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
return response
# 等待完成报送
result = self.wait_for_order_finish(order_code)
return result
# 2.5 批量查询实验报告(post过滤关键字查询)
@@ -1165,137 +1219,221 @@ class BioyondCellWorkstation(BioyondWorkstation):
})
return final_result
def run_bioyond_cell_workflow(config: Dict[str, Any]) -> BioyondCellWorkstation:
"""按照统一配置执行奔曜配液与转运工作流。
Args:
config: 统一的工作流配置。字段示例:
{
"lab_registry": {"setup": True},
"deck": {"setup": True},
"workstation": {"config": {...}},
"update_push_ip": True,
"samples": [
{"name": "...", "board_type": "...", "bottle_type": "...", "location_code": "...", "warehouse_name": "..."}
],
"scheduler": {"start": True, "log": True},
"operations": {
"auto_feeding4to3": {"enabled": True},
"create_orders": {"excel_path": "...", "log": True},
"transfer_3_to_2_to_1": {"enabled": True, "log": True},
"transfer_1_to_2": {"enabled": True, "log": True}
},
"keep_alive": False,
"keep_alive_interval": 1
def _fetch_bioyond_materials(
self,
*,
filter_keyword: Optional[str] = None,
type_mode: int = 2,
) -> List[Dict[str, Any]]:
query: Dict[str, Any] = {
"typeMode": type_mode,
"includeDetail": True,
}
if filter_keyword:
query["filter"] = filter_keyword
Returns:
执行完毕的 `BioyondCellWorkstation` 实例。
"""
response = self._post_lims("/api/lims/storage/stock-material", query)
raw_materials = response.get("data")
if not isinstance(raw_materials, list):
raw_materials = []
if config.get("lab_registry", {}).get("setup", True):
lab_registry.setup()
try:
resource_bioyond_to_plr(
raw_materials,
type_mapping=self.bioyond_config.get("material_type_mappings", MATERIAL_TYPE_MAPPINGS),
deck=self.deck,
)
except Exception as exc:
logger.warning(f"转换奔曜物料到 PLR 失败: {exc}", exc_info=True)
deck_config = config.get("deck")
if isinstance(deck_config, dict):
deck = BIOYOND_YB_Deck(**deck_config)
elif deck_config is None:
deck = BIOYOND_YB_Deck(setup=True)
return raw_materials
def _convert_materials_to_plr(self, materials: List[Dict[str, Any]]) -> List[ResourcePLR]:
try:
return resource_bioyond_to_plr(
deepcopy(materials),
type_mapping=self.bioyond_config.get("material_type_mappings", MATERIAL_TYPE_MAPPINGS),
deck=self.deck,
)
except Exception as exc:
logger.error(f"物料转换为 PLR 失败: {exc}", exc_info=True)
return []
def _wait_for_future(self, future, stage: str, timeout: Optional[float] = None):
if future is None:
return None
timeout = timeout or self.transfer_timeout
start = time.time()
while not future.done():
if (time.time() - start) > timeout:
raise TimeoutError(f"{stage} 超时 {timeout}s")
time.sleep(0.05)
return future.result()
def _register_plr_resources(self, resources: List[ResourcePLR]) -> None:
if not resources or not hasattr(self, "_ros_node") or self._ros_node is None:
return
future = ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, resources=resources)
self._wait_for_future(future, "update_resource")
def _get_target_resource(self, name: str) -> ResourcePLR:
if not hasattr(self, "_ros_node") or self._ros_node is None:
raise RuntimeError("ROS 节点未初始化,无法获取资源")
resource = self._ros_node.resource_tracker.figure_resource({"name": name}, try_mode=False) # type: ignore
if resource is None:
raise ValueError(f"未找到目标资源: {name}")
return resource
def _allocate_sites(self, parent_resource: ResourcePLR, count: int) -> List[str]:
if not hasattr(parent_resource, "get_free_sites"):
raise ValueError(f"资源 {parent_resource} 不支持自动分配站位")
free_indices = list(parent_resource.get_free_sites())
if len(free_indices) < count:
raise ValueError(f"{parent_resource.name} 可用站位不足 (need {count}, have {len(free_indices)})")
ordering = list(getattr(parent_resource, "_ordering", {}).keys())
sites: List[str] = []
for idx in free_indices[:count]:
if ordering and idx < len(ordering):
sites.append(ordering[idx])
else:
deck = deck_config
sites.append(str(idx))
return sites
workstation_kwargs = dict(config.get("workstation", {}))
if "deck" not in workstation_kwargs:
workstation_kwargs["deck"] = deck
ws = BioyondCellWorkstation(**workstation_kwargs)
def _invoke_coin_cell_workflow(self, material_payload: List[Dict[str, Any]]) -> Any:
timeout = float(self.bioyond_config.get("coin_cell_workflow_timeout", 300.0))
workflow_payload: Dict[str, Any] = {}
if isinstance(self.coin_cell_workflow_config, dict):
workflow_payload.update(deepcopy(self.coin_cell_workflow_config))
workflow_payload["materials"] = deepcopy(material_payload)
return self._call_remote_device_method(
self.transfer_target_device_id,
"run_coin_cell_assembly_workflow",
timeout=timeout,
workflow_config=workflow_payload,
)
if config.get("update_push_ip", True):
ws.update_push_ip()
def _call_remote_device_method(
self,
device_id: str,
method: str,
*,
timeout: Optional[float] = None,
**kwargs,
) -> Any:
if not hasattr(self, "_ros_node") or self._ros_node is None:
raise RuntimeError("ROS 节点未初始化,无法调用远程设备")
if not device_id:
raise ValueError("device_id 不能为空")
if not method:
raise ValueError("method 不能为空")
for sample_cfg in config.get("samples", []):
ws.create_sample(**sample_cfg)
scheduler_cfg = config.get("scheduler", {})
if scheduler_cfg.get("start", True):
result = ws.scheduler_start()
if scheduler_cfg.get("log", True):
logger.info(result)
operations_cfg = config.get("operations", {})
auto_feeding_cfg = operations_cfg.get("auto_feeding4to3", {})
if auto_feeding_cfg.get("enabled", True):
result = ws.auto_feeding4to3()
if auto_feeding_cfg.get("log", True):
logger.info(result)
create_orders_cfg = operations_cfg.get("create_orders")
if create_orders_cfg:
excel_path = create_orders_cfg.get("excel_path")
if not excel_path:
raise ValueError("create_orders 需要提供 excel_path。")
result = ws.create_orders(Path(excel_path))
if create_orders_cfg.get("log", True):
logger.info(result)
transfer_321_cfg = operations_cfg.get("transfer_3_to_2_to_1", {})
if transfer_321_cfg.get("enabled", True):
result = ws.transfer_3_to_2_to_1()
if transfer_321_cfg.get("log", True):
logger.info(result)
transfer_12_cfg = operations_cfg.get("transfer_1_to_2", {})
if transfer_12_cfg.get("enabled", True):
result = ws.transfer_1_to_2()
if transfer_12_cfg.get("log", True):
logger.info(result)
if config.get("keep_alive", False):
interval = config.get("keep_alive_interval", 1)
while True:
time.sleep(interval)
return ws
if __name__ == "__main__":
workflow_config = {
"deck": {"setup": True},
"update_push_ip": True,
"samples": [
timeout = timeout or self.transfer_timeout
payload = json.dumps(
{
"name": "配液瓶",
"board_type": "配液瓶(小)板",
"bottle_type": "配液瓶(小)",
"location_code": "E01",
"function_name": method,
"function_args": kwargs,
},
{
"name": "分液瓶",
"board_type": "5ml分液瓶板",
"bottle_type": "5ml分液瓶",
"location_code": "D01",
},
],
"operations": {
"auto_feeding4to3": {"enabled": True, "log": True},
"create_orders": {
"excel_path": "/Users/calvincao/Desktop/work/uni-lab-all/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx",
"log": True,
},
"transfer_3_to_2_to_1": {"enabled": True, "log": True},
"transfer_1_to_2": {"enabled": True, "log": True},
},
"keep_alive": True,
ensure_ascii=False,
)
future = ROS2DeviceNode.run_async_func(
self._ros_node.execute_single_action,
True,
device_id=device_id,
action_name="_execute_driver_command_async",
action_kwargs={"string": payload},
)
result = self._wait_for_future(future, f"{device_id}.{method}", timeout)
if hasattr(result, "return_info"):
try:
return json.loads(result.return_info)
except Exception:
return result.return_info
return result
def run_feeding_stage(self) -> Dict[str, Any]:
self.create_sample(
board_type="配液瓶(小)板",
bottle_type="配液瓶(小)",
location_code="B01",
name="配液瓶",
warehouse_name="手动堆栈"
)
self.create_sample(
board_type="5ml分液瓶板",
bottle_type="5ml分液瓶",
location_code="B02",
name="分液瓶",
warehouse_name="手动堆栈"
)
self.scheduler_start()
feeding_task = self.auto_feeding4to3(
xlsx_path="/Users/sml/work/Unilab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx"
)
feeding_materials = self._fetch_bioyond_materials()
return {
"feeding_materials": feeding_materials,
"feeding_items": feeding_task.get("items", []),
"feeding_task": feeding_task,
}
run_bioyond_cell_workflow(workflow_config)
# 1. location code
# 2. 实验文件
# 3. material template file
def run_liquid_preparation_stage(
self,
feeding_materials: Optional[List[Dict[str, Any]]] = None,
) -> Dict[str, List[Dict[str, Any]]]:
result = self.create_orders(
xlsx_path="/Users/sml/work/Unilab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx"
)
filter_keyword = self.bioyond_config.get("mixing_material_filter") or None
materials = result.get("materials")
if materials is None:
materials = self._fetch_bioyond_materials(filter_keyword=filter_keyword)
return {
"feeding_materials": feeding_materials or [],
"liquid_materials": materials,
}
def run_transfer_stage(
self,
liquid_materials: Optional[List[Dict[str, Any]]] = None,
source_wh_id: Optional[str] = '3a19debc-84b4-0359-e2d4-b3beea49348b',
source_x: int = 1,
source_y: int = 1,
source_z: int = 1
) -> Dict[str, Any]:
"""转运阶段调用transfer_3_to_2_to_1执行3到2到1转运"""
logger.info("开始执行转运阶段 (run_transfer_stage)")
# 暂时注释掉物料转换和跨工站转运逻辑
# transfer_summary: Dict[str, Any] = {}
# try:
# source_materials = liquid_materials or self._fetch_bioyond_materials()
# transfer_plr = self._convert_materials_to_plr(source_materials)
# transfer_summary["plr_count"] = len(transfer_plr)
# ...
# except Exception as exc:
# transfer_summary["error"] = str(exc)
# logger.error(f"跨工站转运失败: {exc}", exc_info=True)
# 只执行核心的3到2到1转运
transfer_result = self.transfer_3_to_2_to_1(
source_wh_id=source_wh_id,
source_x=source_x,
source_y=source_y,
source_z=source_z
)
logger.info("转运阶段执行完成")
return {
"success": True,
"stage": "transfer",
"transfer_result": transfer_result
}
if __name__ == "__main__":
deck = BIOYOND_YB_Deck(setup=True)
w = BioyondCellWorkstation(deck=deck, address="172.16.28.102", port="502", debug_mode=False)
feeding = w.run_feeding_stage()
liquid = w.run_liquid_preparation_stage(feeding.get("feeding_materials"))
transfer = w.run_transfer_stage(liquid.get("liquid_materials"))
while True:
time.sleep(1)
# re=ws.scheduler_stop()

View File

@@ -8,8 +8,8 @@ import os
# BioyondCellWorkstation 默认配置(包含所有必需参数)
API_CONFIG = {
# API 连接配置
"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_host": os.getenv("BIOYOND_API_HOST", "http://172.16.1.143:44389"),#实机
"api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.11.219: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.16.2.140"), # HTTP服务监听地址监听计算机飞连ip地址
"HTTP_host": os.getenv("BIOYOND_HTTP_HOST", "172.16.11.2"), # HTTP服务监听地址监听计算机飞连ip地址
"HTTP_port": int(os.getenv("BIOYOND_HTTP_PORT", "8080")),
"debug_mode": False,# 调试模式
}

View File

@@ -1,4 +1,3 @@
import csv
import inspect
import json
@@ -139,12 +138,11 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
time.sleep(2)
if not modbus_client.client.is_socket_open():
raise ValueError('modbus tcp connection failed')
self.nodes = BaseClient.load_csv(os.path.join(os.path.dirname(__file__), 'coin_cell_assembly_a.csv'))
self.nodes = BaseClient.load_csv(os.path.join(os.path.dirname(__file__), 'coin_cell_assembly_1105.csv'))
self.client = modbus_client.register_node_list(self.nodes)
else:
print("测试模式,跳过连接")
self.nodes, self.client = None, None
""" 工站的配置 """
self.success = False
@@ -161,6 +159,27 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
"resources": [self.deck]
})
def sync_transfer_resources(self) -> Dict[str, Any]:
"""
供跨工站转运完成后调用,强制将当前台面资源同步到云端/前端。
"""
if not hasattr(self, "_ros_node") or self._ros_node is None:
return {"status": "failed", "error": "ros_node_not_ready"}
if self.deck is None:
return {"status": "failed", "error": "deck_not_initialized"}
try:
future = ROS2DeviceNode.run_async_func(
self._ros_node.update_resource,
True,
resources=[self.deck],
)
if future:
future.result()
return {"status": "success"}
except Exception as exc:
logger.error(f"同步转运资源失败: {exc}", exc_info=True)
return {"status": "failed", "error": str(exc)}
# 批量操作在这里写
async def change_hole_sheet_to_2(self, hole: MaterialHole):
hole._unilabos_state["max_sheets"] = 2
@@ -986,6 +1005,31 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
#self.success = True
#return self.success
def run_packaging_workflow(self, workflow_config: Dict[str, Any]) -> "CoinCellAssemblyWorkstation":
config = workflow_config or {}
qiming_params = config.get("qiming") or {}
if qiming_params:
self.qiming_coin_cell_code(**qiming_params)
if config.get("init", True):
self.func_pack_device_init()
if config.get("auto", True):
self.func_pack_device_auto()
if config.get("start", True):
self.func_pack_device_start()
packaging_config = config.get("packaging") or {}
bottle_num = packaging_config.get("bottle_num")
if bottle_num is not None:
self.func_pack_send_bottle_num(bottle_num)
allpack_params = packaging_config.get("command") or {}
if allpack_params:
self.func_allpack_cmd(**allpack_params)
return self
def fun_wuliao_test(self) -> bool:
#找到data_init中构建的2个物料盘
liaopan3 = self.deck.get_resource("\u7535\u6c60\u6599\u76d8")
@@ -1202,93 +1246,92 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
'''
def run_coin_cell_packaging_workflow(config: Dict[str, Any]) -> CoinCellAssemblyWorkstation:
"""根据统一配置顺序执行扣电池装配工作流。
Args:
config: 统一的工作流配置。字段示例:
{
"deck": {"setup": True, "name": "coin_cell_deck"},
"workstation": {"address": "...", "port": "...", "debug_mode": False},
"qiming": {...},
"init": True,
"auto": True,
"start": True,
"packaging": {
"bottle_num": 16,
"command": {...}
}
}
Returns:
执行完毕的 `CoinCellAssemblyWorkstation` 实例。
"""
deck_config = config.get("deck")
if isinstance(deck_config, Deck):
deck = deck_config
elif isinstance(deck_config, dict):
deck = CoincellDeck(**deck_config)
elif deck_config is None:
deck = CoincellDeck(setup=True, name="coin_cell_deck")
def run_coin_cell_assembly_workflow(
self,
workflow_config: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
config: Dict[str, Any]
if workflow_config is None:
config = {}
elif isinstance(workflow_config, list):
config = {"materials": workflow_config}
else:
raise ValueError("deck 配置需为 Deck 实例或 dict。")
workstation_config = dict(config.get("workstation", {}))
workstation_config.setdefault("deck", deck)
workstation = CoinCellAssemblyWorkstation(**workstation_config)
qiming_params = config.get("qiming", {})
if qiming_params:
workstation.qiming_coin_cell_code(**qiming_params)
if config.get("init", True):
workstation.func_pack_device_init()
if config.get("auto", True):
workstation.func_pack_device_auto()
if config.get("start", True):
workstation.func_pack_device_start()
packaging_config = config.get("packaging", {})
bottle_num = packaging_config.get("bottle_num")
if bottle_num is not None:
workstation.func_pack_send_bottle_num(bottle_num)
allpack_params = packaging_config.get("command", {})
if allpack_params:
workstation.func_allpack_cmd(**allpack_params)
return workstation
if __name__ == "__main__":
workflow_config = {
"deck": {"setup": True, "name": "coin_cell_deck"},
"workstation": {
"address": "172.16.28.102",
"port": "502",
"debug_mode": False,
},
"qiming": {
config = workflow_config
qiming_defaults = {
"fujipian_panshu": 1,
"fujipian_juzhendianwei": 2,
"gemopanshu": 3,
"gemo_juzhendianwei": 4,
"lvbodian": False,
"battery_pressure_mode": False,
"fujipian_juzhendianwei": 0,
"gemopanshu": 1,
"gemo_juzhendianwei": 0,
"lvbodian": True,
"battery_pressure_mode": True,
"battery_pressure": 4200,
"battery_clean_ignore": False,
},
"packaging": {
"bottle_num": 16,
"command": {
"elec_num": 16,
"elec_use_num": 16,
}
qiming_params = {**qiming_defaults, **(config.get("qiming") or {})}
qiming_success = self.qiming_coin_cell_code(**qiming_params)
step_results: Dict[str, Any] = {}
try:
self.func_pack_device_init()
step_results["init"] = True
except Exception as exc:
step_results["init"] = f"error: {exc}"
try:
self.func_pack_device_auto()
step_results["auto"] = True
except Exception as exc:
step_results["auto"] = f"error: {exc}"
try:
self.func_pack_device_start()
step_results["start"] = True
except Exception as exc:
step_results["start"] = f"error: {exc}"
packaging_cfg = config.get("packaging") or {}
bottle_num = packaging_cfg.get("bottle_num", 1)
try:
self.func_pack_send_bottle_num(bottle_num)
step_results["send_bottle_num"] = True
except Exception as exc:
step_results["send_bottle_num"] = f"error: {exc}"
command_defaults = {
"elec_num": 1,
"elec_use_num": 1,
"elec_vol": 50,
"assembly_type": 7,
"assembly_pressure": 4200,
"file_path": "/Users/calvincao/Desktop/work/Uni-Lab-OS-hhm",
"file_path": "/Users/sml/work",
}
command_params = {**command_defaults, **(packaging_cfg.get("command") or {})}
packaging_result = self.func_allpack_cmd(**command_params)
finished_result = self.func_pack_send_finished_cmd()
stop_result = self.func_pack_device_stop()
return {
"qiming": {
"params": qiming_params,
"success": qiming_success,
},
"workflow_steps": step_results,
"packaging": {
"bottle_num": bottle_num,
"command": command_params,
"result": packaging_result,
},
"finish": {
"send_finished": finished_result,
"stop": stop_result,
},
}
run_coin_cell_packaging_workflow(workflow_config)
if __name__ == "__main__":
deck = CoincellDeck(setup=True, name="coin_cell_deck")
w = CoinCellAssemblyWorkstation(deck=deck, address="172.16.28.102", port="502", debug_mode=False)
w.run_coin_cell_assembly_workflow()

View File

@@ -821,6 +821,154 @@ bioyond_cell:
title: resource_tree_transfer参数
type: object
type: UniLabJsonCommand
auto-run_feeding_stage:
feedback: {}
goal: {}
goal_default: {}
handles:
input: []
output:
- data_key: feeding_materials
data_source: executor
data_type: resource
handler_key: feeding_materials
label: Feeding Materials
placeholder_keys: {}
result:
properties:
feeding_materials:
items:
type: object
type: array
required:
- feeding_materials
type: object
schema:
description: ''
properties:
feedback: {}
goal:
properties: {}
required: []
type: object
result: {}
required:
- goal
title: run_feeding_stage参数
type: object
type: UniLabJsonCommand
auto-run_liquid_preparation_stage:
feedback: {}
goal: {}
goal_default: {}
handles:
input:
- data_key: feeding_materials
data_source: handle
data_type: resource
handler_key: feeding_materials
label: Feeding Materials
output:
- data_key: liquid_materials
data_source: executor
data_type: resource
handler_key: liquid_materials
label: Liquid Materials
placeholder_keys: {}
result:
properties:
feeding_materials:
items:
type: object
type: array
liquid_materials:
items:
type: object
type: array
required:
- liquid_materials
type: object
schema:
description: ''
properties:
feedback: {}
goal:
properties:
feeding_materials:
items:
type: object
type: array
required: []
type: object
result: {}
required:
- goal
title: run_liquid_preparation_stage参数
type: object
type: UniLabJsonCommand
auto-run_transfer_stage:
feedback: {}
goal: {}
goal_default: {}
handles:
input:
- data_key: liquid_materials
data_source: handle
data_type: resource
handler_key: liquid_materials
label: Liquid Materials
output:
- data_key: transfer_materials
data_source: executor
data_type: resource
handler_key: transfer_materials
label: Transfer Materials
placeholder_keys: {}
result:
properties:
liquid_materials:
items:
type: object
type: array
transfer_materials:
items:
type: object
type: array
transfer_summary:
type: object
required:
- transfer_materials
type: object
schema:
description: ''
properties:
feedback: {}
goal:
properties:
liquid_materials:
items:
type: object
type: array
required: []
type: object
result:
properties:
liquid_materials:
items:
type: object
type: array
transfer_materials:
items:
type: object
type: array
transfer_summary:
type: object
type: object
required:
- goal
title: run_transfer_stage参数
type: object
type: UniLabJsonCommand
auto-scheduler_continue:
feedback: {}
goal: {}
@@ -1112,7 +1260,7 @@ bioyond_cell:
device_id: String
type: python
config_info: []
description: ''
description: 配液工站
handles: []
icon: benyao2.webp
init_param_schema:

View File

@@ -79,7 +79,7 @@ coincellassemblyworkstation_device:
elec_num: null
elec_use_num: null
elec_vol: 50
file_path: C:\Users\67484\Desktop
file_path: /Users/sml/work
handles: {}
placeholder_keys: {}
result: {}
@@ -103,7 +103,7 @@ coincellassemblyworkstation_device:
default: 50
type: integer
file_path:
default: C:\Users\67484\Desktop
default: /Users/sml/work
type: string
required:
- elec_num
@@ -332,7 +332,7 @@ coincellassemblyworkstation_device:
feedback: {}
goal: {}
goal_default:
file_path: D:\coin_cell_data
file_path: /Users/sml/work
handles: {}
placeholder_keys: {}
result: {}
@@ -343,7 +343,7 @@ coincellassemblyworkstation_device:
goal:
properties:
file_path:
default: D:\coin_cell_data
default: /Users/sml/work
type: string
required: []
type: object
@@ -477,6 +477,171 @@ coincellassemblyworkstation_device:
title: qiming_coin_cell_code参数
type: object
type: UniLabJsonCommand
auto-run_coin_cell_assembly_workflow:
feedback: {}
goal:
properties:
workflow_config:
type: object
required: []
type: object
goal_default:
workflow_config: {}
handles:
input:
- data_key: workflow_config
data_source: handle
data_type: resource
handler_key: WorkflowConfig
label: Workflow Config
output:
- data_key: qiming
data_source: executor
data_type: resource
handler_key: QimingResult
label: Qiming Result
- data_key: workflow_steps
data_source: executor
data_type: resource
handler_key: WorkflowSteps
label: Workflow Steps
- data_key: packaging
data_source: executor
data_type: resource
handler_key: PackagingResult
label: Packaging Result
- data_key: finish
data_source: executor
data_type: resource
handler_key: FinishResult
label: Finish Result
placeholder_keys: {}
result:
properties:
finish:
properties:
send_finished:
type: object
stop:
type: object
required:
- send_finished
- stop
type: object
packaging:
properties:
bottle_num:
type: integer
command:
type: object
result:
type: object
required:
- bottle_num
- command
- result
type: object
qiming:
properties:
params:
type: object
success:
type: boolean
required:
- params
- success
type: object
workflow_steps:
type: object
required:
- qiming
- workflow_steps
- packaging
- finish
type: object
schema:
description: ''
properties:
feedback: {}
goal:
properties:
workflow_config:
type: object
required: []
type: object
result:
properties:
finish:
properties:
send_finished:
type: object
stop:
type: object
required:
- send_finished
- stop
type: object
packaging:
properties:
bottle_num:
type: integer
command:
type: object
result:
type: object
required:
- bottle_num
- command
- result
type: object
qiming:
properties:
params:
type: object
success:
type: boolean
required:
- params
- success
type: object
workflow_steps:
type: object
required:
- qiming
- workflow_steps
- packaging
- finish
type: object
required:
- goal
title: run_coin_cell_assembly_workflow参数
type: object
type: UniLabJsonCommand
auto-run_packaging_workflow:
feedback: {}
goal: {}
goal_default:
workflow_config: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
workflow_config:
type: object
required:
- workflow_config
type: object
result: {}
required:
- goal
title: run_packaging_workflow参数
type: object
type: UniLabJsonCommand
module: unilabos.devices.workstation.coin_cell_assembly.coin_cell_assembly:CoinCellAssemblyWorkstation
status_types:
data_assembly_coin_cell_num: int
@@ -500,20 +665,22 @@ coincellassemblyworkstation_device:
sys_status: str
type: python
config_info: []
description: ''
description: 扣电工站
handles: []
icon: koudian.webp
init_param_schema:
config:
properties:
address:
default: 172.21.32.111
default: 172.16.28.102
type: string
config:
type: object
debug_mode:
default: false
type: boolean
deck:
type: object
type: string
port:
default: '502'
type: string

View File

@@ -654,6 +654,31 @@ liquid_handler:
title: iter_tips参数
type: object
type: UniLabJsonCommand
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: string
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
auto-set_group:
feedback: {}
goal: {}
@@ -6170,6 +6195,31 @@ liquid_handler.prcxi:
title: move_to参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
auto-run_protocol:
feedback: {}
goal: {}

View File

@@ -5,6 +5,73 @@ neware_battery_test_system:
- battery_test
class:
action_value_mappings:
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: string
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
auto-print_status_summary:
feedback: {}
goal: {}
goal_default: {}
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties: {}
required: []
type: object
result: {}
required:
- goal
title: print_status_summary参数
type: object
type: UniLabJsonCommand
auto-test_connection:
feedback: {}
goal: {}
goal_default: {}
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties: {}
required: []
type: object
result: {}
required:
- goal
title: test_connection参数
type: object
type: UniLabJsonCommand
debug_resource_names:
feedback: {}
goal: {}
@@ -320,28 +387,24 @@ neware_battery_test_system:
config:
properties:
devtype:
default: '27'
type: string
ip:
default: 127.0.0.1
type: string
machine_id:
default: 1
type: integer
port:
default: 502
type: integer
size_x:
default: 50.0
default: 50
type: number
size_y:
default: 50.0
default: 50
type: number
size_z:
default: 20.0
default: 20
type: number
timeout:
default: 20
type: integer
required: []
type: object

View File

@@ -45,6 +45,31 @@ virtual_centrifuge:
title: initialize参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
centrifuge:
feedback:
current_speed: current_speed
@@ -335,6 +360,31 @@ virtual_column:
title: initialize参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
run_column:
feedback:
current_status: current_status
@@ -732,6 +782,31 @@ virtual_filter:
title: initialize参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
filter:
feedback:
current_status: current_status
@@ -1358,6 +1433,31 @@ virtual_heatchill:
title: initialize参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
heat_chill:
feedback:
status: status
@@ -2358,6 +2458,31 @@ virtual_rotavap:
title: initialize参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
evaporate:
feedback:
current_device: current_device
@@ -2690,6 +2815,31 @@ virtual_separator:
title: initialize参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
separate:
feedback:
current_status: status
@@ -3600,6 +3750,31 @@ virtual_solenoid_valve:
title: is_closed参数
type: object
type: UniLabJsonCommand
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
auto-reset:
feedback: {}
goal: {}
@@ -4177,6 +4352,31 @@ virtual_solid_dispenser:
title: parse_mol_string参数
type: object
type: UniLabJsonCommand
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
module: unilabos.devices.virtual.virtual_solid_dispenser:VirtualSolidDispenser
status_types:
current_reagent: str
@@ -4278,6 +4478,31 @@ virtual_stirrer:
title: initialize参数
type: object
type: UniLabJsonCommandAsync
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
start_stir:
feedback:
status: status
@@ -4995,6 +5220,31 @@ virtual_transfer_pump:
title: is_full参数
type: object
type: UniLabJsonCommand
auto-post_init:
feedback: {}
goal: {}
goal_default:
ros_node: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
ros_node:
type: object
required:
- ros_node
type: object
result: {}
required:
- goal
title: post_init参数
type: object
type: UniLabJsonCommand
auto-pull_plunger:
feedback: {}
goal: {}

View File

@@ -1,16 +1,3 @@
YB_qiang_tou:
category:
- yb3
- YB_bottle
class:
module: unilabos.resources.bioyond.YB_bottles:YB_qiang_tou
type: pylabrobot
description: YB_qiang_tou
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_20ml_fenyeping:
category:
- yb3
@@ -37,6 +24,19 @@ YB_5ml_fenyeping:
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_pei_ye_da_Bottle:
category:
- yb3
@@ -63,14 +63,14 @@ YB_pei_ye_xiao_Bottle:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_jia_yang_tou_da:
YB_qiang_tou:
category:
- yb3
- YB_bottle
class:
module: unilabos.resources.bioyond.YB_bottles:YB_jia_yang_tou_da
module: unilabos.resources.bioyond.YB_bottles:YB_qiang_tou
type: pylabrobot
description: YB_jia_yang_tou_da
description: YB_qiang_tou
handles: []
icon: ''
init_param_schema: {}
@@ -80,6 +80,7 @@ YB_ye_Bottle:
category:
- yb3
- YB_bottle_carriers
- YB_bottle
class:
module: unilabos.resources.bioyond.YB_bottles:YB_ye_Bottle
type: pylabrobot

View File

@@ -11,71 +11,6 @@ YB_100ml_yeti:
init_param_schema: {}
registry_type: resource
version: 1.0.0
# 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_gaonianye
type: pylabrobot
description: YB_gaonianye
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_peiyepingdaban:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingdaban
type: pylabrobot
description: YB_peiyepingdaban
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_6StockCarrier:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6StockCarrier
type: pylabrobot
description: YB_6StockCarrier
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_6VialCarrier:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6VialCarrier
type: pylabrobot
description: YB_6VialCarrier
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_20ml_fenyepingban:
category:
- yb3
@@ -102,40 +37,27 @@ YB_5ml_fenyepingban:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_peiyepingxiaoban:
YB_6StockCarrier:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingxiaoban
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6StockCarrier
type: pylabrobot
description: YB_peiyepingxiaoban
description: YB_6StockCarrier
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_shi_pei_qi_kuai:
YB_6VialCarrier:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_shi_pei_qi_kuai
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6VialCarrier
type: pylabrobot
description: YB_shi_pei_qi_kuai
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_qiang_tou_he:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_qiang_tou_he
type: pylabrobot
description: YB_qiang_tou_he
description: YB_6VialCarrier
handles: []
icon: ''
init_param_schema: {}
@@ -154,19 +76,19 @@ YB_gao_nian_ye_Bottle:
init_param_schema: {}
registry_type: resource
version: 1.0.0
# 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_gaonianye:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_gaonianye
type: pylabrobot
description: YB_gaonianye
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_jia_yang_tou_da_Carrier:
category:
- yb3
@@ -180,14 +102,53 @@ YB_jia_yang_tou_da_Carrier:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_ye_100ml_Bottle:
YB_peiyepingdaban:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottles:YB_ye_100ml_Bottle
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingdaban
type: pylabrobot
description: YB_ye_100ml_Bottle
description: YB_peiyepingdaban
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_peiyepingxiaoban:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingxiaoban
type: pylabrobot
description: YB_peiyepingxiaoban
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_qiang_tou_he:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_qiang_tou_he
type: pylabrobot
description: YB_qiang_tou_he
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_shi_pei_qi_kuai:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_shi_pei_qi_kuai
type: pylabrobot
description: YB_shi_pei_qi_kuai
handles: []
icon: ''
init_param_schema: {}
@@ -206,3 +167,16 @@ YB_ye:
init_param_schema: {}
registry_type: resource
version: 1.0.0
YB_ye_100ml_Bottle:
category:
- yb3
- YB_bottle_carriers
class:
module: unilabos.resources.bioyond.YB_bottles:YB_ye_100ml_Bottle
type: pylabrobot
description: YB_ye_100ml_Bottle
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0

View File

@@ -674,10 +674,15 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st
for loc in material.get("locations", []):
if hasattr(deck, "warehouses") and loc.get("whName") in deck.warehouses:
warehouse = deck.warehouses[loc["whName"]]
num_x = getattr(warehouse, "num_items_x", 0) or 0
num_y = getattr(warehouse, "num_items_y", 0) or 0
num_z = getattr(warehouse, "num_items_z", 0) or 0
if num_x <= 0 or num_y <= 0 or num_z <= 0:
continue
idx = (
(loc.get("y", 0) - 1) * warehouse.num_items_x * warehouse.num_items_y
+ (loc.get("x", 0) - 1) * warehouse.num_items_x
+ (loc.get("z", 0) - 1)
(loc.get("z", 0) - 1) * num_x * num_y
+ (loc.get("y", 0) - 1) * num_x
+ (loc.get("x", 0) - 1)
)
if 0 <= idx < warehouse.capacity:
if warehouse[idx] is None or isinstance(warehouse[idx], ResourceHolder):

View File

@@ -402,7 +402,6 @@ class ROS2WorkstationNode(BaseROS2DeviceNode):
return result_future.result
"""还没有改过的部分"""
def _setup_hardware_proxy(
self, device: ROS2DeviceNode, communication_device: ROS2DeviceNode, read_method, write_method