From 678ace6109bc96b4dd33265b0a7833342eb508b6 Mon Sep 17 00:00:00 2001 From: Junhan Chang Date: Tue, 17 Jun 2025 13:53:38 +0800 Subject: [PATCH 1/6] Fix edge id --- .../comprehensive_station.json | 22 +++++++++---------- unilabos/resources/graphio.py | 3 +-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/test/experiments/comprehensive_protocol/comprehensive_station.json b/test/experiments/comprehensive_protocol/comprehensive_station.json index 19d0852..2b75c13 100644 --- a/test/experiments/comprehensive_protocol/comprehensive_station.json +++ b/test/experiments/comprehensive_protocol/comprehensive_station.json @@ -153,7 +153,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 200, "y": 150, @@ -174,7 +174,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 250, "y": 150, @@ -195,7 +195,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 300, "y": 150, @@ -216,7 +216,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 900, "y": 150, @@ -237,7 +237,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 950, "y": 150, @@ -302,7 +302,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 400, "y": 450, @@ -387,7 +387,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 500, "y": 400, @@ -406,7 +406,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 1100, "y": 500, @@ -570,7 +570,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 900, "y": 500, @@ -589,7 +589,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 950, "y": 500, @@ -608,7 +608,7 @@ "children": [], "parent": "ComprehensiveProtocolStation", "type": "container", - "class": null, + "class": "container", "position": { "x": 1050, "y": 500, diff --git a/unilabos/resources/graphio.py b/unilabos/resources/graphio.py index 17b0f27..3ed2e36 100644 --- a/unilabos/resources/graphio.py +++ b/unilabos/resources/graphio.py @@ -175,8 +175,7 @@ def modify_to_backend_format(data: list[dict[str, Any]]) -> list[dict[str, Any]] edge["targetHandle"] = port[target] elif "target_port" in edge: edge["targetHandle"] = edge.pop("target_port") - if "id" not in edge: - edge["id"] = f"reactflow__edge-{edge['sourceHandle']}-{edge['targetHandle']}" + edge["id"] = f"reactflow__edge-{source}-{edge['sourceHandle']}-{target}-{edge['targetHandle']}" for key in ["source_port", "target_port"]: if key in edge: edge.pop(key) From 183579fd7fc058a64654bb8ec1dca30fb10eff28 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:34:03 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E7=A7=BB=E9=99=A4device=E7=9A=84=E7=88=B6?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=85=B3=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/ros/nodes/presets/host_node.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index d6d9d35..ceba584 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -195,18 +195,18 @@ class HostNode(BaseROS2DeviceNode): resource_ids_to_instance = {i["id"]: i for i in resources_config} resource_name_to_with_parent_name = {} for res in resources_config: - if res.get("parent") and res.get("type") == "device" and res.get("class"): - parent_id = res.get("parent") - parent_res = resource_ids_to_instance[parent_id] - if parent_res.get("type") == "device" and parent_res.get("class"): - resource_with_parent_name.append(copy.deepcopy(res)) - resource_name_to_with_parent_name[resource_with_parent_name[-1]["id"]] = f"{parent_res['id']}/{res['id']}" - resource_with_parent_name[-1]["id"] = f"{parent_res['id']}/{res['id']}" - continue + # if res.get("parent") and res.get("type") == "device" and res.get("class"): + # parent_id = res.get("parent") + # parent_res = resource_ids_to_instance[parent_id] + # if parent_res.get("type") == "device" and parent_res.get("class"): + # resource_with_parent_name.append(copy.deepcopy(res)) + # resource_name_to_with_parent_name[resource_with_parent_name[-1]["id"]] = f"{parent_res['id']}/{res['id']}" + # resource_with_parent_name[-1]["id"] = f"{parent_res['id']}/{res['id']}" + # continue resource_with_parent_name.append(copy.deepcopy(res)) - for edge in self.resources_edge_config: - edge["source"] = resource_name_to_with_parent_name.get(edge.get("source"), edge.get("source")) - edge["target"] = resource_name_to_with_parent_name.get(edge.get("target"), edge.get("target")) + # for edge in self.resources_edge_config: + # edge["source"] = resource_name_to_with_parent_name.get(edge.get("source"), edge.get("source")) + # edge["target"] = resource_name_to_with_parent_name.get(edge.get("target"), edge.get("target")) try: for bridge in self.bridges: if hasattr(bridge, "resource_add"): From af812d630ac9b7b93dace8925e44fc1905c2462b Mon Sep 17 00:00:00 2001 From: Junhan Chang Date: Tue, 17 Jun 2025 15:37:36 +0800 Subject: [PATCH 3/6] separate registry sync and resource_add --- setup.py | 1 + unilabos/app/main.py | 28 +++++++++++-------- unilabos/registry/devices/virtual_device.yaml | 1 + unilabos/ros/nodes/presets/host_node.py | 12 ++++---- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index 3f71dff..080f1e1 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,7 @@ setup( entry_points={ 'console_scripts': [ "unilab = unilabos.app.main:main", + "unilab-register = unilabos.app.register:main" ], }, ) diff --git a/unilabos/app/main.py b/unilabos/app/main.py index 918ef59..471df4b 100644 --- a/unilabos/app/main.py +++ b/unilabos/app/main.py @@ -22,6 +22,21 @@ from unilabos.config.config import load_config, BasicConfig, _update_config_from from unilabos.utils.banner_print import print_status, print_unilab_banner +def load_config_from_file(config_path): + if config_path is None: + config_path = os.environ.get("UNILABOS.BASICCONFIG.CONFIG_PATH", None) + if config_path: + if not os.path.exists(config_path): + print_status(f"配置文件 {config_path} 不存在", "error") + elif not config_path.endswith(".py"): + print_status(f"配置文件 {config_path} 不是Python文件,必须以.py结尾", "error") + else: + load_config(config_path) + else: + print_status(f"启动 UniLab-OS时,配置文件参数未正确传入 --config '{config_path}' 尝试本地配置...", "warning") + load_config(config_path) + + def parse_args(): """解析命令行参数""" parser = argparse.ArgumentParser(description="Start Uni-Lab Edge server.") @@ -97,18 +112,7 @@ def main(): # 加载配置文件,优先加载config,然后从env读取 config_path = args_dict.get("config") - if config_path is None: - config_path = os.environ.get("UNILABOS.BASICCONFIG.CONFIG_PATH", None) - if config_path: - if not os.path.exists(config_path): - print_status(f"配置文件 {config_path} 不存在", "error") - elif not config_path.endswith(".py"): - print_status(f"配置文件 {config_path} 不是Python文件,必须以.py结尾", "error") - else: - load_config(config_path) - else: - print_status(f"启动 UniLab-OS时,配置文件参数未正确传入 --config '{config_path}' 尝试本地配置...", "warning") - load_config(config_path) + load_config_from_file(config_path) # 设置BasicConfig参数 BasicConfig.is_host_mode = not args_dict.get("without_host", False) diff --git a/unilabos/registry/devices/virtual_device.yaml b/unilabos/registry/devices/virtual_device.yaml index af00af1..ea244ec 100644 --- a/unilabos/registry/devices/virtual_device.yaml +++ b/unilabos/registry/devices/virtual_device.yaml @@ -211,6 +211,7 @@ virtual_multiway_valve: - handler_key: transferpump label: transferpump data_type: fluid + side: NORTH io_type: target data_source: handle data_key: fluid_in diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index ceba584..e8bd909 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -147,12 +147,12 @@ class HostNode(BaseROS2DeviceNode): self.device_status = {} # 用来存储设备状态 self.device_status_timestamps = {} # 用来存储设备状态最后更新时间 - from unilabos.app.mq import mqtt_client - - for device_info in lab_registry.obtain_registry_device_info(): - mqtt_client.publish_registry(device_info["id"], device_info) - for resource_info in lab_registry.obtain_registry_resource_info(): - mqtt_client.publish_registry(resource_info["id"], resource_info) + # from unilabos.app.mq import mqtt_client + # + # for device_info in lab_registry.obtain_registry_device_info(): + # mqtt_client.publish_registry(device_info["id"], device_info) + # for resource_info in lab_registry.obtain_registry_resource_info(): + # mqtt_client.publish_registry(resource_info["id"], resource_info) time.sleep(1) # 等待MQTT连接稳定 # 首次发现网络中的设备 self._discover_devices() From b1dae6da17aed9ca764b093a8bb9e03bcd24df31 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:58:56 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=B8=8D=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E6=B3=A8=E5=86=8C=E8=A1=A8=E6=8A=A5=E9=80=81=EF=BC=8C?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E5=91=BD=E4=BB=A4unilabos-register=E6=88=96?= =?UTF-8?q?=E8=80=85=E5=A2=9E=E5=8A=A0=E5=90=AF=E5=8A=A8=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/app/main.py | 6 ++++++ unilabos/app/mq.py | 5 +++-- unilabos/app/register.py | 10 +++++++--- unilabos/config/config.py | 3 ++- unilabos/ros/nodes/presets/host_node.py | 15 +++++++++------ 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/unilabos/app/main.py b/unilabos/app/main.py index 471df4b..835c57d 100644 --- a/unilabos/app/main.py +++ b/unilabos/app/main.py @@ -73,6 +73,11 @@ def parse_args(): action="store_true", help="Slave模式下跳过等待host服务", ) + parser.add_argument( + "--upload_registry", + action="store_true", + help="启动unilab时同时报送注册表信息", + ) parser.add_argument( "--config", type=str, @@ -117,6 +122,7 @@ def main(): # 设置BasicConfig参数 BasicConfig.is_host_mode = not args_dict.get("without_host", False) BasicConfig.slave_no_host = args_dict.get("slave_no_host", False) + BasicConfig.upload_registry = args_dict.get("upload_registry", False) machine_name = os.popen("hostname").read().strip() machine_name = "".join([c if c.isalnum() or c == "_" else "_" for c in machine_name]) BasicConfig.machine_name = machine_name diff --git a/unilabos/app/mq.py b/unilabos/app/mq.py index fbd57b9..ac744c9 100644 --- a/unilabos/app/mq.py +++ b/unilabos/app/mq.py @@ -172,13 +172,14 @@ class MQTTClient: jobdata = {"job_id": job_id, "data": feedback_data, "status": status, "return_info": return_info} self.client.publish(f"labs/{MQConfig.lab_id}/job/list/", json.dumps(jobdata), qos=2) - def publish_registry(self, device_id: str, device_info: dict): + def publish_registry(self, device_id: str, device_info: dict, print_debug: bool = True): if self.mqtt_disable: return address = f"labs/{MQConfig.lab_id}/registry/" registry_data = json.dumps({device_id: device_info}, ensure_ascii=False, cls=TypeEncoder) self.client.publish(address, registry_data, qos=2) - logger.debug(f"Registry data published: address: {address}, {registry_data}") + if print_debug: + logger.debug(f"Registry data published: address: {address}, {registry_data}") def publish_actions(self, action_id: str, action_info: dict): if self.mqtt_disable: diff --git a/unilabos/app/register.py b/unilabos/app/register.py index 478e1cf..76ad5a5 100644 --- a/unilabos/app/register.py +++ b/unilabos/app/register.py @@ -15,15 +15,15 @@ def register_devices_and_resources(mqtt_client, lab_registry): # 注册设备信息 for device_info in lab_registry.obtain_registry_device_info(): - mqtt_client.publish_registry(device_info["id"], device_info) + mqtt_client.publish_registry(device_info["id"], device_info, False) logger.debug(f"[UniLab Register] 注册设备: {device_info['id']}") # 注册资源信息 for resource_info in lab_registry.obtain_registry_resource_info(): - mqtt_client.publish_registry(resource_info["id"], resource_info) + mqtt_client.publish_registry(resource_info["id"], resource_info, False) logger.debug(f"[UniLab Register] 注册资源: {resource_info['id']}") - time.sleep(20) + time.sleep(10) logger.info("[UniLab Register] 设备和资源注册完成.") @@ -53,6 +53,10 @@ def main(): load_config_from_file(args.config) from unilabos.app.mq import mqtt_client + + # 连接mqtt + mqtt_client.start() + from unilabos.registry.registry import lab_registry # 注册设备和资源 diff --git a/unilabos/config/config.py b/unilabos/config/config.py index 0cf999e..32ebf68 100644 --- a/unilabos/config/config.py +++ b/unilabos/config/config.py @@ -10,8 +10,9 @@ from unilabos.utils import logger class BasicConfig: ENV = "pro" # 'test' config_path = "" - is_host_mode = True # 从registry.py移动过来 + is_host_mode = True slave_no_host = False # 是否跳过rclient.wait_for_service() + upload_registry = False machine_name = "undefined" vis_2d_enable = False diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index e8bd909..a4658de 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -22,6 +22,7 @@ from unilabos_msgs.srv import ( ) # type: ignore from unique_identifier_msgs.msg import UUID +from unilabos.config.config import BasicConfig from unilabos.registry.registry import lab_registry from unilabos.resources.graphio import initialize_resource from unilabos.resources.registry import add_schema @@ -146,13 +147,15 @@ class HostNode(BaseROS2DeviceNode): self.device_status = {} # 用来存储设备状态 self.device_status_timestamps = {} # 用来存储设备状态最后更新时间 + if BasicConfig.upload_registry: + from unilabos.app.mq import mqtt_client - # from unilabos.app.mq import mqtt_client - # - # for device_info in lab_registry.obtain_registry_device_info(): - # mqtt_client.publish_registry(device_info["id"], device_info) - # for resource_info in lab_registry.obtain_registry_resource_info(): - # mqtt_client.publish_registry(resource_info["id"], resource_info) + for device_info in lab_registry.obtain_registry_device_info(): + mqtt_client.publish_registry(device_info["id"], device_info) + for resource_info in lab_registry.obtain_registry_resource_info(): + mqtt_client.publish_registry(resource_info["id"], resource_info) + else: + self.lab_logger().warning("本次启动注册表不报送云端,如果您需要联网调试,请使用unilab-register命令进行单独报送") time.sleep(1) # 等待MQTT连接稳定 # 首次发现网络中的设备 self._discover_devices() From 2492af57c0be2a71f10802836beb791797c49a77 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:59:32 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E5=AE=8C=E5=96=84tip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/ros/nodes/presets/host_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unilabos/ros/nodes/presets/host_node.py b/unilabos/ros/nodes/presets/host_node.py index a4658de..6665165 100644 --- a/unilabos/ros/nodes/presets/host_node.py +++ b/unilabos/ros/nodes/presets/host_node.py @@ -155,7 +155,7 @@ class HostNode(BaseROS2DeviceNode): for resource_info in lab_registry.obtain_registry_resource_info(): mqtt_client.publish_registry(resource_info["id"], resource_info) else: - self.lab_logger().warning("本次启动注册表不报送云端,如果您需要联网调试,请使用unilab-register命令进行单独报送") + self.lab_logger().warning("本次启动注册表不报送云端,如果您需要联网调试,请使用unilab-register命令进行单独报送,或者在启动命令增加--upload_registry") time.sleep(1) # 等待MQTT连接稳定 # 首次发现网络中的设备 self._discover_devices() From ac88c59b506d4557ebfb7604eb9d99dfe2795bd7 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 17 Jun 2025 16:10:28 +0800 Subject: [PATCH 6/6] =?UTF-8?q?protocol=20node=E4=B8=8D=E5=86=8D=E5=B5=8C?= =?UTF-8?q?=E5=A5=97=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/ros/nodes/presets/protocol_node.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unilabos/ros/nodes/presets/protocol_node.py b/unilabos/ros/nodes/presets/protocol_node.py index 7b10e01..5c22ac2 100644 --- a/unilabos/ros/nodes/presets/protocol_node.py +++ b/unilabos/ros/nodes/presets/protocol_node.py @@ -110,7 +110,8 @@ class ROS2ProtocolNode(BaseROS2DeviceNode): def initialize_device(self, device_id, device_config): """初始化设备并创建相应的动作客户端""" - device_id_abs = f"{self.device_id}/{device_id}" + # device_id_abs = f"{self.device_id}/{device_id}" + device_id_abs = f"{device_id}" self.lab_logger().info(f"初始化子设备: {device_id_abs}") d = self.sub_devices[device_id] = initialize_device_from_dict(device_id_abs, device_config)