mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 13:01:12 +00:00
更新物料接口
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
这个模块包含用于创建设备类实例的工厂类。
|
||||
基础工厂类提供通用的实例创建方法,而特定工厂类提供针对特定设备类的创建方法。
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import inspect
|
||||
import traceback
|
||||
@@ -53,7 +54,6 @@ class DeviceClassCreator(Generic[T]):
|
||||
if c["type"] != "device":
|
||||
self.resource_tracker.add_resource(c)
|
||||
|
||||
|
||||
def create_instance(self, data: Dict[str, Any]) -> T:
|
||||
"""
|
||||
创建设备类实例
|
||||
@@ -118,7 +118,9 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
return nested_dict_to_list(resource), Resource
|
||||
return resource, source_type
|
||||
|
||||
def _process_resource_references(self, data: Any, to_dict=False, states=None, prefix_path="") -> Any:
|
||||
def _process_resource_references(
|
||||
self, data: Any, to_dict=False, states=None, prefix_path="", name_to_uuid=None
|
||||
) -> Any:
|
||||
"""
|
||||
递归处理资源引用,替换_resource_child_name对应的资源
|
||||
|
||||
@@ -127,11 +129,13 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
to_dict: 是否返回字典形式的资源
|
||||
states: 用于保存所有资源状态
|
||||
prefix_path: 当前递归路径
|
||||
name_to_uuid: name到uuid的映射字典
|
||||
|
||||
Returns:
|
||||
处理后的数据
|
||||
"""
|
||||
from pylabrobot.resources import Deck, Resource
|
||||
|
||||
if states is None:
|
||||
states = {}
|
||||
|
||||
@@ -155,6 +159,9 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
return serialized
|
||||
else:
|
||||
self.resource_tracker.add_resource(resource_instance)
|
||||
# 立即设置UUID
|
||||
if name_to_uuid:
|
||||
self.resource_tracker.loop_set_uuid(resource_instance, name_to_uuid)
|
||||
return resource_instance
|
||||
except Exception as e:
|
||||
logger.warning(f"无法导入资源类型 {type_path}: {e}")
|
||||
@@ -169,12 +176,12 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
result = {}
|
||||
for key, value in data.items():
|
||||
new_prefix = f"{prefix_path}.{key}" if prefix_path else key
|
||||
result[key] = self._process_resource_references(value, to_dict, states, new_prefix)
|
||||
result[key] = self._process_resource_references(value, to_dict, states, new_prefix, name_to_uuid)
|
||||
return result
|
||||
|
||||
elif isinstance(data, list):
|
||||
return [
|
||||
self._process_resource_references(item, to_dict, states, f"{prefix_path}[{i}]")
|
||||
self._process_resource_references(item, to_dict, states, f"{prefix_path}[{i}]", name_to_uuid)
|
||||
for i, item in enumerate(data)
|
||||
]
|
||||
|
||||
@@ -193,22 +200,42 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
"""
|
||||
deserialize_error = None
|
||||
stack = None
|
||||
|
||||
# 递归遍历 children 构建 name_to_uuid 映射
|
||||
def collect_name_to_uuid(children_dict: Dict[str, Any], result: Dict[str, str]):
|
||||
"""递归遍历嵌套的 children 字典,收集 name 到 uuid 的映射"""
|
||||
for child in children_dict.values():
|
||||
if isinstance(child, dict):
|
||||
result[child["name"]] = child["uuid"]
|
||||
collect_name_to_uuid(child["children"], result)
|
||||
|
||||
name_to_uuid = {}
|
||||
collect_name_to_uuid(self.children, name_to_uuid)
|
||||
if self.has_deserialize:
|
||||
deserialize_method = getattr(self.device_cls, "deserialize")
|
||||
spect = inspect.signature(deserialize_method)
|
||||
spec_args = spect.parameters
|
||||
for param_name, param_value in data.copy().items():
|
||||
if isinstance(param_value, dict) and "_resource_child_name" in param_value and "_resource_type" not in param_value:
|
||||
if (
|
||||
isinstance(param_value, dict)
|
||||
and "_resource_child_name" in param_value
|
||||
and "_resource_type" not in param_value
|
||||
):
|
||||
arg_value = spec_args[param_name].annotation
|
||||
data[param_name]["_resource_type"] = self.device_cls.__module__ + ":" + arg_value
|
||||
logger.debug(f"自动补充 _resource_type: {data[param_name]['_resource_type']}")
|
||||
|
||||
# 首先处理资源引用
|
||||
states = {}
|
||||
processed_data = self._process_resource_references(data, to_dict=True, states=states)
|
||||
processed_data = self._process_resource_references(
|
||||
data, to_dict=True, states=states, name_to_uuid=name_to_uuid
|
||||
)
|
||||
|
||||
try:
|
||||
self.device_instance = deserialize_method(**processed_data)
|
||||
from pylabrobot.resources import Resource
|
||||
|
||||
self.device_instance: Resource = deserialize_method(**processed_data)
|
||||
self.resource_tracker.loop_set_uuid(self.device_instance, name_to_uuid)
|
||||
all_states = self.device_instance.serialize_all_state()
|
||||
for k, v in states.items():
|
||||
logger.debug(f"PyLabRobot反序列化设置状态:{k}")
|
||||
@@ -229,11 +256,15 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
spect = inspect.signature(self.device_cls.__init__)
|
||||
spec_args = spect.parameters
|
||||
for param_name, param_value in data.copy().items():
|
||||
if isinstance(param_value, dict) and "_resource_child_name" in param_value and "_resource_type" not in param_value:
|
||||
if (
|
||||
isinstance(param_value, dict)
|
||||
and "_resource_child_name" in param_value
|
||||
and "_resource_type" not in param_value
|
||||
):
|
||||
arg_value = spec_args[param_name].annotation
|
||||
data[param_name]["_resource_type"] = self.device_cls.__module__ + ":" + arg_value
|
||||
logger.debug(f"自动补充 _resource_type: {data[param_name]['_resource_type']}")
|
||||
processed_data = self._process_resource_references(data, to_dict=False)
|
||||
processed_data = self._process_resource_references(data, to_dict=False, name_to_uuid=name_to_uuid)
|
||||
self.device_instance = super(PyLabRobotCreator, self).create_instance(processed_data)
|
||||
except Exception as e:
|
||||
logger.error(f"PyLabRobot创建实例失败: {e}")
|
||||
@@ -247,22 +278,31 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
return self.device_instance
|
||||
|
||||
def post_create(self):
|
||||
if hasattr(self.device_instance, "setup") and asyncio.iscoroutinefunction(getattr(self.device_instance, "setup")):
|
||||
if hasattr(self.device_instance, "setup") and asyncio.iscoroutinefunction(
|
||||
getattr(self.device_instance, "setup")
|
||||
):
|
||||
from unilabos.ros.nodes.base_device_node import ROS2DeviceNode
|
||||
|
||||
def done_cb(*args):
|
||||
from pylabrobot.resources import set_volume_tracking
|
||||
|
||||
# from pylabrobot.resources import set_tip_tracking
|
||||
set_volume_tracking(enabled=True)
|
||||
# set_tip_tracking(enabled=True) # 序列化tip_spot has为False
|
||||
logger.debug(f"PyLabRobot设备实例 {self.device_instance} 设置完成")
|
||||
from unilabos.config.config import BasicConfig
|
||||
|
||||
if BasicConfig.vis_2d_enable:
|
||||
from pylabrobot.visualizer.visualizer import Visualizer
|
||||
|
||||
vis = Visualizer(resource=self.device_instance, open_browser=True)
|
||||
|
||||
def vis_done_cb(*args):
|
||||
logger.info(f"PyLabRobot设备实例开启了Visualizer {self.device_instance}")
|
||||
|
||||
ROS2DeviceNode.run_async_func(vis.setup).add_done_callback(vis_done_cb)
|
||||
logger.debug(f"PyLabRobot设备实例提交开启Visualizer {self.device_instance}")
|
||||
|
||||
ROS2DeviceNode.run_async_func(getattr(self.device_instance, "setup")).add_done_callback(done_cb)
|
||||
|
||||
|
||||
@@ -299,6 +339,7 @@ class WorkstationNodeCreator(DeviceClassCreator[T]):
|
||||
deck_dict = data.get("deck")
|
||||
if deck_dict:
|
||||
from pylabrobot.resources import Deck, Resource
|
||||
|
||||
plrc = PyLabRobotCreator(Deck, self.children, self.resource_tracker)
|
||||
deck = plrc.create_instance(deck_dict)
|
||||
data["deck"] = deck
|
||||
|
||||
Reference in New Issue
Block a user