mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 13:01:12 +00:00
新增test_resource动作
This commit is contained in:
@@ -7,16 +7,17 @@ import importlib
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Union, Tuple
|
from typing import Any, Dict, List, Union, Tuple
|
||||||
|
|
||||||
import msgcenterpy
|
|
||||||
import yaml
|
import yaml
|
||||||
from rosidl_parser.definition import UnboundedSequence
|
|
||||||
from unilabos_msgs.action import LiquidHandlerTransfer
|
|
||||||
from unilabos_msgs.msg import Resource
|
from unilabos_msgs.msg import Resource
|
||||||
|
|
||||||
from unilabos.config.config import BasicConfig
|
from unilabos.config.config import BasicConfig
|
||||||
from unilabos.resources.graphio import resource_plr_to_ulab, tree_to_list
|
from unilabos.resources.graphio import resource_plr_to_ulab, tree_to_list
|
||||||
from unilabos.ros.msgs.message_converter import msg_converter_manager, ros_action_to_json_schema, String, \
|
from unilabos.ros.msgs.message_converter import (
|
||||||
ros_message_to_json_schema
|
msg_converter_manager,
|
||||||
|
ros_action_to_json_schema,
|
||||||
|
String,
|
||||||
|
ros_message_to_json_schema,
|
||||||
|
)
|
||||||
from unilabos.utils import logger
|
from unilabos.utils import logger
|
||||||
from unilabos.utils.decorator import singleton
|
from unilabos.utils.decorator import singleton
|
||||||
from unilabos.utils.import_manager import get_enhanced_class_info, get_class
|
from unilabos.utils.import_manager import get_enhanced_class_info, get_class
|
||||||
@@ -24,6 +25,7 @@ from unilabos.utils.type_check import NoAliasDumper
|
|||||||
|
|
||||||
DEFAULT_PATHS = [Path(__file__).absolute().parent]
|
DEFAULT_PATHS = [Path(__file__).absolute().parent]
|
||||||
|
|
||||||
|
|
||||||
class ROSMsgNotFound(Exception):
|
class ROSMsgNotFound(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -139,13 +141,57 @@ class Registry:
|
|||||||
"type": self.EmptyIn,
|
"type": self.EmptyIn,
|
||||||
"goal": {},
|
"goal": {},
|
||||||
"feedback": {},
|
"feedback": {},
|
||||||
"result": {"latency_ms": "latency_ms", "time_diff_ms": "time_diff_ms"},
|
"result": {},
|
||||||
"schema": ros_action_to_json_schema(
|
"schema": ros_action_to_json_schema(
|
||||||
self.EmptyIn, "用于测试延迟的动作,返回延迟时间和时间差。"
|
self.EmptyIn, "用于测试延迟的动作,返回延迟时间和时间差。"
|
||||||
),
|
),
|
||||||
"goal_default": {},
|
"goal_default": {},
|
||||||
"handles": {},
|
"handles": {},
|
||||||
},
|
},
|
||||||
|
"test_resource": {
|
||||||
|
"type": "UniLabJsonCommand",
|
||||||
|
"goal": {},
|
||||||
|
"feedback": {},
|
||||||
|
"result": {},
|
||||||
|
"schema": {
|
||||||
|
"description": "",
|
||||||
|
"properties": {
|
||||||
|
"feedback": {},
|
||||||
|
"goal": {
|
||||||
|
"properties": {
|
||||||
|
"resource": {
|
||||||
|
"properties": ros_message_to_json_schema(Resource, "resource"),
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"items": {
|
||||||
|
"properties": ros_message_to_json_schema(Resource, "resources"),
|
||||||
|
"title": "mount_resource",
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"devices": {
|
||||||
|
"items": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"result": {}
|
||||||
|
},
|
||||||
|
"required": ["goal"],
|
||||||
|
"title": "transfer_resource_to_another参数",
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
"goal_default": {},
|
||||||
|
"handles": {},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -436,10 +482,12 @@ class Registry:
|
|||||||
elif param_type == ("list", "unilabos.registry.placeholder_type:ResourceSlot"):
|
elif param_type == ("list", "unilabos.registry.placeholder_type:ResourceSlot"):
|
||||||
schema["properties"][param_name] = {
|
schema["properties"][param_name] = {
|
||||||
"items": ros_message_to_json_schema(Resource, param_name),
|
"items": ros_message_to_json_schema(Resource, param_name),
|
||||||
"type": "array"
|
"type": "array",
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
schema["properties"][param_name] = self._generate_schema_from_info(param_name, param_type, param_default)
|
schema["properties"][param_name] = self._generate_schema_from_info(
|
||||||
|
param_name, param_type, param_default
|
||||||
|
)
|
||||||
if param_required:
|
if param_required:
|
||||||
schema["required"].append(param_name)
|
schema["required"].append(param_name)
|
||||||
|
|
||||||
@@ -512,7 +560,9 @@ class Registry:
|
|||||||
status_type = "String" # 替换成ROS的String,便于显示
|
status_type = "String" # 替换成ROS的String,便于显示
|
||||||
device_config["class"]["status_types"][status_name] = status_type
|
device_config["class"]["status_types"][status_name] = status_type
|
||||||
try:
|
try:
|
||||||
target_type = self._replace_type_with_class(status_type, device_id, f"状态 {status_name}")
|
target_type = self._replace_type_with_class(
|
||||||
|
status_type, device_id, f"状态 {status_name}"
|
||||||
|
)
|
||||||
except ROSMsgNotFound:
|
except ROSMsgNotFound:
|
||||||
continue
|
continue
|
||||||
if target_type in [
|
if target_type in [
|
||||||
@@ -550,10 +600,22 @@ class Registry:
|
|||||||
"goal_default": {i["name"]: i["default"] for i in v["args"]},
|
"goal_default": {i["name"]: i["default"] for i in v["args"]},
|
||||||
"handles": [],
|
"handles": [],
|
||||||
"placeholder_keys": {
|
"placeholder_keys": {
|
||||||
i["name"]: "unilabos_resources" if i["type"] == "unilabos.registry.placeholder_type:ResourceSlot" or i["type"] == ("list", "unilabos.registry.placeholder_type:ResourceSlot") else "unilabos_devices"
|
i["name"]: (
|
||||||
|
"unilabos_resources"
|
||||||
|
if i["type"] == "unilabos.registry.placeholder_type:ResourceSlot"
|
||||||
|
or i["type"]
|
||||||
|
== ("list", "unilabos.registry.placeholder_type:ResourceSlot")
|
||||||
|
else "unilabos_devices"
|
||||||
|
)
|
||||||
for i in v["args"]
|
for i in v["args"]
|
||||||
if i.get("type", "") in ["unilabos.registry.placeholder_type:ResourceSlot", "unilabos.registry.placeholder_type:DeviceSlot", ("list", "unilabos.registry.placeholder_type:ResourceSlot"), ("list", "unilabos.registry.placeholder_type:DeviceSlot")]
|
if i.get("type", "")
|
||||||
}
|
in [
|
||||||
|
"unilabos.registry.placeholder_type:ResourceSlot",
|
||||||
|
"unilabos.registry.placeholder_type:DeviceSlot",
|
||||||
|
("list", "unilabos.registry.placeholder_type:ResourceSlot"),
|
||||||
|
("list", "unilabos.registry.placeholder_type:DeviceSlot"),
|
||||||
|
]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
# 不生成已配置action的动作
|
# 不生成已配置action的动作
|
||||||
for k, v in enhanced_info["action_methods"].items()
|
for k, v in enhanced_info["action_methods"].items()
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ from rclpy.service import Service
|
|||||||
from unilabos_msgs.msg import Resource # type: ignore
|
from unilabos_msgs.msg import Resource # type: ignore
|
||||||
from unilabos_msgs.srv import (
|
from unilabos_msgs.srv import (
|
||||||
ResourceAdd,
|
ResourceAdd,
|
||||||
ResourceGet,
|
|
||||||
ResourceDelete,
|
ResourceDelete,
|
||||||
ResourceUpdate,
|
ResourceUpdate,
|
||||||
ResourceList,
|
ResourceList,
|
||||||
@@ -44,6 +43,7 @@ from unilabos.ros.nodes.resource_tracker import (
|
|||||||
)
|
)
|
||||||
from unilabos.utils.exception import DeviceClassInvalid
|
from unilabos.utils.exception import DeviceClassInvalid
|
||||||
from unilabos.utils.type_check import serialize_result_info
|
from unilabos.utils.type_check import serialize_result_info
|
||||||
|
from unilabos.registry.placeholder_type import ResourceSlot, DeviceSlot
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from unilabos.app.ws_client import QueueItem, WSResourceChatData
|
from unilabos.app.ws_client import QueueItem, WSResourceChatData
|
||||||
@@ -152,6 +152,12 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
"/devices/host_node/test_latency",
|
"/devices/host_node/test_latency",
|
||||||
callback_group=self.callback_group,
|
callback_group=self.callback_group,
|
||||||
),
|
),
|
||||||
|
"/devices/host_node/test_resource": ActionClient(
|
||||||
|
self,
|
||||||
|
lab_registry.EmptyIn,
|
||||||
|
"/devices/host_node/test_resource",
|
||||||
|
callback_group=self.callback_group,
|
||||||
|
),
|
||||||
} # 用来存储多个ActionClient实例
|
} # 用来存储多个ActionClient实例
|
||||||
self._action_value_mappings: Dict[str, Dict] = (
|
self._action_value_mappings: Dict[str, Dict] = (
|
||||||
{}
|
{}
|
||||||
@@ -234,7 +240,8 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
)
|
)
|
||||||
# resources_config 通过各个设备的 resource_tracker 进行uuid更新,利用uuid_mapping
|
# resources_config 通过各个设备的 resource_tracker 进行uuid更新,利用uuid_mapping
|
||||||
# resources_config 的 root node 是
|
# resources_config 的 root node 是
|
||||||
for node in resources_config.root_nodes:
|
for tree in resources_config.trees:
|
||||||
|
node = tree.root_node
|
||||||
if node.res_content.type == "device":
|
if node.res_content.type == "device":
|
||||||
for sub_node in node.children:
|
for sub_node in node.children:
|
||||||
# 只有二级子设备
|
# 只有二级子设备
|
||||||
@@ -245,8 +252,11 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
{"name": sub_node.res_content.name})
|
{"name": sub_node.res_content.name})
|
||||||
device_tracker.loop_update_uuid(resource_instance, uuid_mapping)
|
device_tracker.loop_update_uuid(resource_instance, uuid_mapping)
|
||||||
else:
|
else:
|
||||||
resource_instance = self.resource_tracker.figure_resource({"name": node.res_content.name})
|
try:
|
||||||
self._resource_tracker.loop_update_uuid(resource_instance, uuid_mapping)
|
for plr_resource in ResourceTreeSet([tree]).to_plr_resources():
|
||||||
|
self.resource_tracker.add_resource(plr_resource)
|
||||||
|
except Exception as ex:
|
||||||
|
self.lab_logger().warning("[Host Node-Resource] 根节点物料序列化失败!")
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.lab_logger().error("[Host Node-Resource] 添加物料出错!")
|
self.lab_logger().error("[Host Node-Resource] 添加物料出错!")
|
||||||
self.lab_logger().error(traceback.format_exc())
|
self.lab_logger().error(traceback.format_exc())
|
||||||
@@ -799,7 +809,7 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
ResourceAdd, "/resources/add", self._resource_add_callback, callback_group=ReentrantCallbackGroup()
|
ResourceAdd, "/resources/add", self._resource_add_callback, callback_group=ReentrantCallbackGroup()
|
||||||
),
|
),
|
||||||
"resource_get": self.create_service(
|
"resource_get": self.create_service(
|
||||||
ResourceGet, "/resources/get", self._resource_get_callback, callback_group=ReentrantCallbackGroup()
|
SerialCommand, "/resources/get", self._resource_get_callback, callback_group=ReentrantCallbackGroup()
|
||||||
),
|
),
|
||||||
"resource_delete": self.create_service(
|
"resource_delete": self.create_service(
|
||||||
ResourceDelete,
|
ResourceDelete,
|
||||||
@@ -1011,7 +1021,7 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
resources = [convert_to_ros_msg(Resource, resource) for resource in r]
|
resources = [convert_to_ros_msg(Resource, resource) for resource in r]
|
||||||
return resources
|
return resources
|
||||||
|
|
||||||
def _resource_get_callback(self, request: ResourceGet.Request, response: ResourceGet.Response):
|
def _resource_get_callback(self, request: SerialCommand.Request, response: SerialCommand.Response):
|
||||||
"""
|
"""
|
||||||
获取资源回调
|
获取资源回调
|
||||||
|
|
||||||
@@ -1025,20 +1035,12 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
响应对象,包含查询到的资源
|
响应对象,包含查询到的资源
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
http_req = self.bridges[-1].resource_get(request.id, request.with_children)
|
data = json.loads(request.command)
|
||||||
response.resources = self._resource_get_process(http_req)
|
http_req = self.bridges[-1].resource_get(data["id"], data["with_children"])
|
||||||
|
response.response = json.dumps(http_req["data"])
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.lab_logger().error(f"[Host Node-Resource] Error retrieving from bridge: {str(e)}")
|
self.lab_logger().error(f"[Host Node-Resource] Error retrieving from bridge: {str(e)}")
|
||||||
# 从 ResourceTreeSet 中查找资源
|
|
||||||
resources_list = (
|
|
||||||
[node.res_content.model_dump(by_alias=True) for node in self.resources_config.all_nodes]
|
|
||||||
if self.resources_config
|
|
||||||
else []
|
|
||||||
)
|
|
||||||
r = [resource for resource in resources_list if resource.get("id") == request.id]
|
|
||||||
self.lab_logger().debug(f"[Host Node-Resource] Retrieved from local: {len(r)} resources")
|
|
||||||
response.resources = [convert_to_ros_msg(Resource, resource) for resource in r]
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _resource_delete_callback(self, request, response):
|
def _resource_delete_callback(self, request, response):
|
||||||
@@ -1240,6 +1242,12 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
"status": "success",
|
"status": "success",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def test_resource(self, resource: ResourceSlot, resources: List[ResourceSlot], device: DeviceSlot, devices: List[DeviceSlot]):
|
||||||
|
return {
|
||||||
|
"resources": ResourceTreeSet.from_plr_resources([resource, *resources]).dump(),
|
||||||
|
"devices": [device, *devices],
|
||||||
|
}
|
||||||
|
|
||||||
def handle_pong_response(self, pong_data: dict):
|
def handle_pong_response(self, pong_data: dict):
|
||||||
"""
|
"""
|
||||||
处理pong响应
|
处理pong响应
|
||||||
|
|||||||
Reference in New Issue
Block a user