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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ SHELL := /bin/bash

COMPOSE := docker compose --env-file deployment/env/versions.env \
-f deployment/compose/compose.dev.yaml
BASE_PATHS := packages agents tasks evaluators tests/fixtures
BASE_PATHS := packages agents tasks evaluators tests
COLCON_ENV := COLCON_DEFAULTS_FILE=$(CURDIR)/colcon.defaults.yaml

CURRENT_USER := $(shell id -un)
Expand Down Expand Up @@ -57,6 +57,6 @@ test-local: build-local

lint-local:
python3 tools/validation/check_repository.py
ruff check tools
ruff check tools tests

check-local: lint-local list-local test-local
5 changes: 3 additions & 2 deletions packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ This domain contains shared RoboHarness platform and communication packages.
Packages must depend toward stable layers and must not statically depend on a
specific simulator, robot, agent, task, or evaluator implementation.

PR 01 intentionally contains no placeholder ROS packages. `rh_interfaces`,
`rh_core`, `rh_ros`, and `rh_experiment` are introduced by their roadmap PRs.
The first platform package is [`rh_interfaces`](rh_interfaces/README.md), which
owns the implementation-independent ROS wire contract. `rh_core`, `rh_ros`,
and `rh_experiment` are introduced by their roadmap PRs.
33 changes: 33 additions & 0 deletions packages/rh_interfaces/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.8)
project(rh_interfaces)

find_package(ament_cmake REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
"msg/ComponentStatus.msg"
"msg/EpisodeResult.msg"
"msg/EpisodeState.msg"
"msg/PointNavTask.msg"
"srv/AbortEpisode.srv"
"srv/ResetAgent.srv"
"srv/ResetEnv.srv"
"srv/StartEpisode.srv"
DEPENDENCIES
builtin_interfaces
geometry_msgs
)

ament_export_dependencies(rosidl_default_runtime)

if(BUILD_TESTING)
find_package(ament_cmake_lint_cmake REQUIRED)
find_package(ament_cmake_xmllint REQUIRED)

ament_lint_cmake()
ament_xmllint()
endif()

ament_package()
48 changes: 48 additions & 0 deletions packages/rh_interfaces/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# `rh_interfaces`

`rh_interfaces` is the implementation-independent ROS 2 wire contract shared
by the RoboHarness Environment, Agent, and Experiment containers. It contains
messages and services only: no nodes, transport helpers, state machines, or
simulator-specific code.

## Control-plane interfaces

| ROS name | Interface | Producer/server | Consumer/client |
|---|---|---|---|
| `/roboharness/env/status` | `ComponentStatus` | Environment | Experiment |
| `/roboharness/agent/status` | `ComponentStatus` | Agent | Experiment |
| `/roboharness/env/reset_episode` | `ResetEnv` | Environment | Experiment |
| `/roboharness/agent/reset_episode` | `ResetAgent` | Agent | Experiment |
| `/roboharness/episode/state` | `EpisodeState` | Experiment | Environment, Agent, Evaluator |
| `/roboharness/task/pointnav` | `PointNavTask` | Experiment | Environment, Agent, Evaluator |
| `/roboharness/episode/start` | `StartEpisode` | Experiment | Operator or automation |
| `/roboharness/episode/abort` | `AbortEpisode` | Experiment | Operator |
| `/roboharness/episode/result` | `EpisodeResult` | Experiment | Reporting tools |

The standard robot data plane continues to use ROS types such as
`geometry_msgs/Twist`, `nav_msgs/Odometry`, and `sensor_msgs/Imu`; this package
does not wrap those observations in a generic message.

## Contract rules

- Identifiers and request IDs are opaque non-empty strings. Validation belongs
to the core/runtime layers rather than the generated interface classes.
- `PointNavTask.start`, `PointNavTask.goal`, and `ResetEnv.start` use the `map`
frame in the MVP. Task start and goal frames must match.
- Durations use seconds, distances use metres, and Episode metrics use
simulation time and the `map` frame.
- `ComponentStatus.stamp` records the last transition time. Repeated status
heartbeats retain it instead of replacing it with publication time.
- `EpisodeState.sequence` increases on every authoritative transition within an
Episode. Consumers reject stale Episode IDs or sequence values.
- `EpisodeResult` is deliberately compact. `result_uri` is opaque and points to
the durable JSON result; its storage scheme is not part of this ROS contract.
- A reset `request_id` is an idempotency key. Runtime behavior for duplicate
requests is implemented in a later protocol-helper PR.
- Numeric state and termination values are stable wire values. New values may
be appended, but existing values must never be reordered or reused.
- `detail`, abort `reason`, and `result_uri` are opaque strings. Correctness must
never depend on parsing human-readable text.

QoS, deadlines, heartbeat behavior, validation, and node implementations are
intentionally outside this package.
23 changes: 23 additions & 0 deletions packages/rh_interfaces/msg/ComponentStatus.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Lifecycle state reported by an Environment or Agent component.
# Existing numeric values are part of the wire contract and must not change.
uint8 STARTING=0
uint8 RESETTING=1
uint8 READY=2
uint8 ERROR=3

# Time of the latest state transition, not the heartbeat publication time.
builtin_interfaces/Time stamp

# Stable identifier of the component instance within an experiment.
string component_id

uint8 state

# Zero means no error. Non-zero code catalogs are owned by each component.
uint32 error_code

# Short human-readable context; consumers must not parse this field.
string detail

# True when an operator must restart or redeploy the component before reuse.
bool restart_required
17 changes: 17 additions & 0 deletions packages/rh_interfaces/msg/EpisodeResult.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Compact completion event. Detailed results remain in the referenced artifact.
string experiment_id
string episode_id

# Uses the termination reason constants defined by EpisodeState.
uint8 termination_reason

# Convenience summary; true exactly when termination_reason is SUCCESS.
bool success

# Metrics are measured in simulation time and the map frame.
float64 elapsed_time_s
float64 path_length_m
float64 final_distance_to_goal_m

# Opaque URI for the durable episode result document.
string result_uri
32 changes: 32 additions & 0 deletions packages/rh_interfaces/msg/EpisodeState.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Authoritative lifecycle state published by the Experiment orchestrator.
# Existing numeric values are part of the wire contract and must not change.
uint8 PREPARING=0
uint8 READY=1
uint8 RUNNING=2
uint8 TERMINATING=3
uint8 FINISHED=4

# A reason is final only when state is FINISHED. NONE is used before then.
uint8 NONE=0
uint8 SUCCESS=1
uint8 TIMEOUT=2
uint8 ABORTED=3
uint8 FAILURE=4
uint8 ENV_ERROR=5
uint8 AGENT_ERROR=6
uint8 INVALID_TASK=7

# Simulation time of this state transition.
builtin_interfaces/Time stamp

string experiment_id
string episode_id

# Strictly increases for every transition within an episode.
uint64 sequence

uint8 state
uint8 termination_reason

# Short human-readable context; consumers must not parse this field.
string detail
16 changes: 16 additions & 0 deletions packages/rh_interfaces/msg/PointNavTask.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Immutable PointNav task snapshot. start and goal must use the same frame.
# RoboHarness MVP requires that frame to be "map".
string experiment_id
string episode_id

geometry_msgs/PoseStamped start
geometry_msgs/PoseStamped goal

# Goal is reached when planar distance is less than or equal to this value.
float64 success_radius_m

# Episode timeout measured in simulation seconds.
float64 timeout_s

# Reproducibility seed; interpretation is owned by the selected backend/task.
int64 seed
27 changes: 27 additions & 0 deletions packages/rh_interfaces/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>rh_interfaces</name>
<version>0.0.0</version>
<description>Implementation-independent ROS 2 interfaces for RoboHarness.</description>
<maintainer email="2300012435@stu.pku.edu.cn">Staaaaaaaaar</maintainer>
<!-- Project licensing and release versioning are finalized by roadmap PR 18. -->
<license>NOASSERTION</license>

<buildtool_depend>ament_cmake</buildtool_depend>
<build_depend>rosidl_default_generators</build_depend>

<depend>builtin_interfaces</depend>
<depend>geometry_msgs</depend>

<exec_depend>rosidl_default_runtime</exec_depend>

<test_depend>ament_cmake_lint_cmake</test_depend>
<test_depend>ament_cmake_xmllint</test_depend>

<member_of_group>rosidl_interface_packages</member_of_group>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
12 changes: 12 additions & 0 deletions packages/rh_interfaces/srv/AbortEpisode.srv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
string experiment_id
string episode_id

# Human-readable operator intent. The committed result uses EpisodeState.ABORTED.
string reason
---

# Acceptance only acknowledges the transition request; finalization is asynchronous.
bool accepted

# Short human-readable context; clients must not parse this field.
string detail
12 changes: 12 additions & 0 deletions packages/rh_interfaces/srv/ResetAgent.srv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Opaque idempotency key. Repeating a completed request_id must not reset twice.
string request_id
string experiment_id
string episode_id
---
bool success

# Zero means no error. Non-zero values are component-specific.
uint32 error_code

# Short human-readable context; clients must not parse this field.
string detail
18 changes: 18 additions & 0 deletions packages/rh_interfaces/srv/ResetEnv.srv
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Opaque idempotency key. Repeating a completed request_id must not reset twice.
string request_id
string experiment_id
string episode_id

# Requested robot root pose. RoboHarness MVP requires the "map" frame.
geometry_msgs/PoseStamped start

# Reproducibility seed supplied to the environment backend.
int64 seed
---
bool success

# Zero means no error. Non-zero values are component-specific.
uint32 error_code

# Short human-readable context; clients must not parse this field.
string detail
9 changes: 9 additions & 0 deletions packages/rh_interfaces/srv/StartEpisode.srv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
string experiment_id
string episode_id
---

# Acceptance only acknowledges the transition request; it is not an episode result.
bool accepted

# Short human-readable context; clients must not parse this field.
string detail
6 changes: 4 additions & 2 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
This directory is reserved for contract, cross-process, cross-container, and
end-to-end tests. Unit tests stay with their owning package.

`fixtures/` will contain deterministic CPU-only mock components; it is a Colcon
base path but contains no placeholder package in PR 01.
- [`contracts/`](contracts/README.md) verifies public interfaces across
language bindings and package boundaries.
- `fixtures/` will contain deterministic CPU-only mock components in later
roadmap PRs.
6 changes: 6 additions & 0 deletions tests/contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Contract tests

This domain contains black-box tests for public RoboHarness contracts. The
`rh_interfaces_contract_tests` package verifies generated C++ and Python ROS 2
types, stable field/constant definitions, serialization round trips, and the
interface package dependency boundary.
20 changes: 20 additions & 0 deletions tests/contracts/rh_interfaces_contract_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.8)
project(rh_interfaces_contract_tests)

find_package(ament_cmake REQUIRED)
find_package(ament_cmake_gtest REQUIRED)
find_package(ament_cmake_pytest REQUIRED)
find_package(rh_interfaces REQUIRED)
find_package(rosidl_typesupport_cpp REQUIRED)

ament_add_gtest(test_cpp_typesupport test/test_cpp_typesupport.cpp)
ament_target_dependencies(test_cpp_typesupport
rh_interfaces
rosidl_typesupport_cpp
)

ament_add_pytest_test(test_python_contract test/test_python_contract.py
TIMEOUT 30
)

ament_package()
23 changes: 23 additions & 0 deletions tests/contracts/rh_interfaces_contract_tests/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>rh_interfaces_contract_tests</name>
<version>0.0.0</version>
<description>Cross-language contract tests for the RoboHarness ROS interfaces.</description>
<maintainer email="2300012435@stu.pku.edu.cn">Staaaaaaaaar</maintainer>
<!-- Project licensing and release versioning are finalized by roadmap PR 18. -->
<license>NOASSERTION</license>

<buildtool_depend>ament_cmake</buildtool_depend>

<test_depend>ament_cmake_gtest</test_depend>
<test_depend>ament_cmake_pytest</test_depend>
<test_depend>ament_index_python</test_depend>
<test_depend>rclpy</test_depend>
<test_depend>rh_interfaces</test_depend>
<test_depend>rosidl_typesupport_cpp</test_depend>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
Loading
Loading