diff --git a/unilabos/ros/nodes/base_device_node.py b/unilabos/ros/nodes/base_device_node.py index 24ee15b6..0f62d2ea 100644 --- a/unilabos/ros/nodes/base_device_node.py +++ b/unilabos/ros/nodes/base_device_node.py @@ -304,10 +304,16 @@ class BaseROS2DeviceNode(Node, Generic[T]): res.response = "" return res + def append_resource(req, res): + pass + self._service_server: Dict[str, Service] = { "query_host_name": self.create_service( SerialCommand, f"/srv{self.namespace}/query_host_name", query_host_name_cb, callback_group=self.callback_group ), + "append_resource": self.create_service( + SerialCommand, f"/srv{self.namespace}/append_resource", append_resource, callback_group=self.callback_group + ), } # 向全局在线设备注册表添加设备信息 @@ -667,7 +673,7 @@ class ROS2DeviceNode: self.resource_tracker = DeviceNodeResourceTracker() # use_pylabrobot_creator 使用 cls的包路径检测 - use_pylabrobot_creator = driver_class.__module__.startswith("pylabrobot") + use_pylabrobot_creator = driver_class.__module__.startswith("pylabrobot") or driver_class.__name__ == "DPLiquidHandler" # TODO: 要在创建之前预先请求服务器是否有当前id的物料,放到resource_tracker中,让pylabrobot进行创建 # 创建设备类实例 diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index a5584bd9..53ce6ca0 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -269,6 +269,18 @@ class HostNode(BaseROS2DeviceNode): def add_resource_from_outer(self, resources: list["Resource"], device_ids: list[str], bind_parent_ids: list[str]): for resource, device_id, bind_parent_id in zip(resources, device_ids, bind_parent_ids): + # 这里要求device_id传入必须是edge_device_id + namespace = "/devices/" + device_id + srv_address = f"/srv{namespace}/append_resource" + sclient = self.create_client(SerialCommand, srv_address) + request = SerialCommand.Request() + request.command = json.dumps({ + "machine_name": BasicConfig.machine_name, + "type": "slave", + "devices_config": devices_config_copy, + "registry_config": lab_registry.obtain_registry_device_info() + }, ensure_ascii=False, cls=TypeEncoder) + response = sclient.call(request) print("111") pass diff --git a/unilabos/ros/nodes/resource_tracker.py b/unilabos/ros/nodes/resource_tracker.py index dc9f9c4a..1115fcce 100644 --- a/unilabos/ros/nodes/resource_tracker.py +++ b/unilabos/ros/nodes/resource_tracker.py @@ -1,7 +1,7 @@ from unilabos.utils.log import logger -class DeviceNodeResourceTracker: +class DeviceNodeResourceTracker(object): def __init__(self): self.resources = [] @@ -15,44 +15,46 @@ class DeviceNodeResourceTracker: return resource def add_resource(self, resource): - # 使用内存地址跟踪是否为同一个resource for r in self.resources: if id(r) == id(resource): return - # 添加资源到跟踪器 self.resources.append(resource) def clear_resource(self): self.resources = [] - def figure_resource(self, resource): - # 使用内存地址跟踪是否为同一个resource - if isinstance(resource, list): - return [self.figure_resource(r) for r in resource] - res_id = resource.id if hasattr(resource, "id") else None - res_name = resource.name if hasattr(resource, "name") else None + def figure_resource(self, query_resource): + if isinstance(query_resource, list): + return [self.figure_resource(r) for r in query_resource] + res_id = query_resource.id if hasattr(query_resource, "id") else (query_resource.get("id") if isinstance(query_resource, dict) else None) + res_name = query_resource.name if hasattr(query_resource, "name") else (query_resource.get("name") if isinstance(query_resource, dict) else None) res_identifier = res_id if res_id else res_name identifier_key = "id" if res_id else "name" - resource_cls_type = type(resource) + resource_cls_type = type(query_resource) if res_identifier is None: - logger.warning(f"resource {resource} 没有id或name,暂不能对应figure") + logger.warning(f"resource {query_resource} 没有id或name,暂不能对应figure") res_list = [] for r in self.resources: - res_list.extend( - self.loop_find_resource(r, resource_cls_type, identifier_key, getattr(resource, identifier_key)) - ) + if isinstance(query_resource, dict): + res_list.extend( + self.loop_find_resource(r, resource_cls_type, identifier_key, query_resource[identifier_key]) + ) + else: + res_list.extend( + self.loop_find_resource(r, resource_cls_type, identifier_key, getattr(query_resource, identifier_key)) + ) assert len(res_list) == 1, f"找到多个资源,请检查资源是否唯一: {res_list}" - self.root_resource2resource[id(resource)] = res_list[0] + self.root_resource2resource[id(query_resource)] = res_list[0] # 后续加入其他对比方式 return res_list[0] - def loop_find_resource(self, resource, resource_cls_type, identifier_key, compare_value): + def loop_find_resource(self, resource, target_resource_cls_type, identifier_key, compare_value): res_list = [] - print(resource, resource_cls_type, identifier_key, compare_value) + # print(resource, target_resource_cls_type, identifier_key, compare_value) children = getattr(resource, "children", []) for child in children: - res_list.extend(self.loop_find_resource(child, resource_cls_type, identifier_key, compare_value)) - if resource_cls_type == type(resource): + res_list.extend(self.loop_find_resource(child, target_resource_cls_type, identifier_key, compare_value)) + if target_resource_cls_type == type(resource) or target_resource_cls_type == dict: if hasattr(resource, identifier_key): if getattr(resource, identifier_key) == compare_value: res_list.append(resource) diff --git a/unilabos/ros/utils/driver_creator.py b/unilabos/ros/utils/driver_creator.py index 2ea30856..52eacbf4 100644 --- a/unilabos/ros/utils/driver_creator.py +++ b/unilabos/ros/utils/driver_creator.py @@ -218,12 +218,14 @@ class PyLabRobotCreator(DeviceClassCreator[T]): logger.error(f"PyLabRobot反序列化失败: {deserialize_error}") logger.error(f"PyLabRobot反序列化堆栈: {stack}") - return self.device_instance + return self.device_instance def post_create(self): if hasattr(self.device_instance, "setup") and asyncio.iscoroutinefunction(getattr(self.device_instance, "setup")): from unilabos.ros.nodes.base_device_node import ROS2DeviceNode - ROS2DeviceNode.run_async_func(getattr(self.device_instance, "setup")).add_done_callback(lambda x: logger.debug(f"PyLabRobot设备实例 {self.device_instance} 设置完成")) + def done_cb(*args): + logger.debug(f"PyLabRobot设备实例 {self.device_instance} 设置完成") + ROS2DeviceNode.run_async_func(getattr(self.device_instance, "setup")).add_done_callback(done_cb) class ProtocolNodeCreator(DeviceClassCreator[T]):