Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ jobs:
call conda activate check-env
call install\unilabos_msgs\setup.bat
echo Running HostLink, ROS2 domain and networking runtime tests...
python -m pytest -q tests\hostlink tests\networking tests\basic tests\device_runtime tests\app\test_backend_selection.py tests\app\test_rclpy_dll_patch.py tests\registry\test_backend_metadata.py tests\ros\test_domain_init.py tests\ros\test_device_node_contract.py -p no:launch_testing -p no:launch_ros
python -m pytest -q tests\hostlink tests\networking tests\basic tests\device_runtime tests\app\test_backend_selection.py tests\app\test_rclpy_dll_patch.py tests\registry\test_backend_metadata.py tests\ros\test_action_schema_compat.py tests\ros\test_domain_init.py tests\ros\test_device_node_contract.py -p no:launch_testing -p no:launch_ros

- name: Run check mode (AST registry validation)
# check_mode 会真实 import 所有设备类(连带 matplotlib/opencv 等原生库)。
Expand Down
24 changes: 24 additions & 0 deletions tests/ros/test_action_schema_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from unilabos.ros.msgs.message_converter import (
NavigateThroughPoses,
ros_action_result_mapping,
ros_action_to_json_schema,
)


def test_navigate_through_poses_result_contract_is_distro_independent() -> None:
"""Humble/Jazzy 的原始 Result 不同,但 UniLabOS 对外合同必须一致。"""
native_fields = set(
NavigateThroughPoses.Result.get_fields_and_field_types()
)
assert native_fields in ({"result"}, {"error_code", "error_msg"})

assert ros_action_result_mapping(NavigateThroughPoses) == {}
result_schema = ros_action_to_json_schema(NavigateThroughPoses)["properties"][
"result"
]
assert result_schema == {
"title": "NavigateThroughPoses_Result",
"type": "object",
"properties": {},
"additionalProperties": False,
}
12 changes: 2 additions & 10 deletions unilabos/registry/devices/robot_linear_motion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,7 @@ linear_motion.grbl:
poses: []
handles: {}
placeholder_keys: {}
result:
error_code: error_code
error_msg: error_msg
result: {}
schema:
description: ''
properties:
Expand Down Expand Up @@ -355,13 +353,7 @@ linear_motion.grbl:
type: object
result:
additionalProperties: false
properties:
error_code:
maximum: 65535
minimum: 0
type: integer
error_msg:
type: string
properties: {}
title: NavigateThroughPoses_Result
type: object
required:
Expand Down
4 changes: 2 additions & 2 deletions unilabos/registry/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
from unilabos.resources.site_definition import normalize_available_sites
from unilabos.ros.msgs.message_converter import (
msg_converter_manager,
ros_action_result_mapping,
ros_action_to_json_schema,
String,
ros_message_to_json_schema,
Expand Down Expand Up @@ -2039,8 +2040,7 @@ def _load_single_device_file(
pass
try:
if hasattr(action_type_obj, "Result"):
res_fields = action_type_obj.Result.get_fields_and_field_types()
entry_result = {f: f for f in res_fields}
entry_result = ros_action_result_mapping(action_type_obj)
except Exception:
pass
try:
Expand Down
29 changes: 28 additions & 1 deletion unilabos/ros/msgs/message_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,33 @@ def ros_message_to_json_schema(msg_class: Any, field_name: str) -> Dict[str, Any
return schema


def ros_action_result_mapping(action_class: Any) -> Dict[str, str]:
"""生成 action Result 字段映射,并消除跨 ROS 发行版的不稳定字段。

``NavigateThroughPoses.Result`` 在 Humble 中包装 ``std_msgs/Empty``,在
Jazzy 中则是 ``error_code/error_msg``。UniLabOS 的轨迹动作不读取这些
字段,因此统一声明为无结果映射,避免共享 registry 随发行版来回变化。
"""
if action_class is NavigateThroughPoses:
return {}
return {
field_name: field_name
for field_name in action_class.Result.get_fields_and_field_types()
}


def ros_action_result_to_json_schema(action_class: Any) -> Dict[str, Any]:
"""生成可跨受支持 ROS 发行版复用的 action Result schema。"""
if action_class is NavigateThroughPoses:
return {
"title": action_class.Result.__name__,
"type": "object",
"properties": {},
"additionalProperties": False,
}
return ros_message_to_json_schema(action_class.Result, action_class.Result.__name__)


def ros_action_to_json_schema(
action_class: Any, description="", previous_schema: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
Expand Down Expand Up @@ -1011,7 +1038,7 @@ def ros_action_to_json_schema(
},
"result": {
# 'description': 'Action 结果 - 完成后从服务器发送到客户端',
**ros_message_to_json_schema(action_class.Result, action_class.Result.__name__)
**ros_action_result_to_json_schema(action_class)
},
},
"required": ["goal"],
Expand Down
Loading