--- language: - en license: apache-2.0 pipeline_tag: robotics tags: - OpenRAL - rskill - ros2 - mobile_base - nav2 inference: false --- # rskill-nav2-navigate-to-pose > **OpenRAL rSkill** — wraps the upstream `nav2_msgs/action/NavigateToPose` > action server as an OpenRAL rSkill so the Reasoner can dispatch > mobile-base navigation through the same `ExecuteSkill` path used by > VLA skills. **Result-only mode** — Nav2's behaviour tree publishes > `/cmd_vel` directly to the base controller; no `Action` chunk flows > through OpenRAL's safety supervisor. This package uses `kind: ros_action` (see [ADR-0024](../../docs/adr/0024-ros-wrapped-rskills.md)) with `ros_integration.result_trajectory_field: null` to put the [`ROSActionRskill`](../../python/rskill/src/openral_rskill/ros_action_rskill.py) adapter into result-only mode: it sends the goal, awaits the action result, and raises `ROSRskillGoalSatisfied` on success. Compare with the sibling [`rskill-moveit-joints`](../rskill-moveit-joints/) skill, which sets `result_trajectory_field` and replays a joint trajectory one waypoint at a time. ## What this skill does Navigates the mobile base to a fixed `geometry_msgs/PoseStamped` target in the `map` frame via Nav2's `NavigateToPose` action. The default goal points at the map origin; override `ros_integration.default_goal_json` in a per-deployment copy for real targets. | Field | Value | | --- | --- | | Actions | `navigate` | | Objects | _none_ | | Scenes | `indoor` | | Embodiment | mobile-manipulator and similar mobile-base embodiments | ## How it works `ROSActionRskill` is a thin `rSkillBase` shim around an `ActionClient`: 1. `_configure_impl` lazy-imports `nav2_msgs.action.NavigateToPose`, opens an `ActionClient` on `/navigate_to_pose` from the `RskillRunnerNode`-supplied node handle, and parses `ros_integration.default_goal_json` once. 2. On the first `_step_impl(world_state)` call the adapter sends the goal, polls the goal-accept + result futures while the host node's main rclpy spin services callbacks, and — because `result_trajectory_field is None` — raises `ROSRskillGoalSatisfied` immediately on success. The runner catches it specifically and closes the `ExecuteSkill` goal with `success=True`. ### Observation → action contract (result-only mode) | Direction | Key | Shape | Notes | | --- | --- | --- | --- | | in | `world_state.joint_state` | unused | Nav2 consumes its own sensor topics (laser, odom, camera) | | out | _none via OpenRAL_ | — | Nav2's behaviour tree publishes `/cmd_vel` directly to the base controller | **Safety implication.** No `ActionChunk` is published on `/openral/candidate_action`, so the OpenRAL safety supervisor does NOT see Nav2's velocity commands. Collision avoidance relies entirely on Nav2's costmap + behaviour tree. The follow-up that brings velocity streams under the supervisor's envelope is tracked in ADR-0024's §Out-of-scope and depends on (a) a mobile-base HAL declaring `body_twist` in `supported_control_modes` (none exist in-tree today), and (b) a velocity / jerk envelope landing in the supervisor (it currently checks per-joint position only). ## How it was trained / Upstream provenance Nothing is trained — this rSkill wraps the upstream Nav2 stack. | Field | Value | | --- | --- | | Upstream | [`nav2_msgs/action/NavigateToPose`](https://github.com/ros-navigation/navigation2/blob/main/nav2_msgs/action/NavigateToPose.action) (Apache-2.0) | | Planner library | [Nav2](https://docs.nav2.org/) (Apache-2.0) | | Costmap / behaviour tree | Nav2's own subsystems — see Nav2 docs | | Wrapped artefact | rSkill manifest + README — no weights | ## Supported robots / embodiments | Robot | Embodiment tag | Status | Notes | | --- | --- | --- | --- | | Panda Mobile | `panda_mobile` | experimental | no HAL accepting `body_twist` ships in-tree yet; resolution depends on the deployment wiring its own mobile-base HAL or running Nav2's controllers against a sim | | Generic mobile-manipulator | `mobile_manipulator` | experimental | union tag — palette filter only | A real mobile-base HAL (Turtlebot 4, Clearpath Jackal, etc.) is the prerequisite for full end-to-end execution — tracked as a separate issue. ## Sensors required / Observation contract This skill consumes nothing through OpenRAL's sensor pipeline. Nav2's own subscriptions handle: | Source | Topic | Why Nav2 needs it | | --- | --- | --- | | Laser scan | `/scan` (or per-deployment remap) | Costmap obstacle layer | | Odometry | `/odom` | Localisation + behaviour-tree feedback | | TF | `/tf`, `/tf_static` | Resolve goal pose in the `map` frame | | Map | `/map` (or AMCL initial pose) | Global planner | If your deployment uses a non-default topic remap, surface it on the Nav2 launch — the wrapped action's contract is intact. ## Manifest summary | Field | Value | | --- | --- | | `name` | `OpenRAL/rskill-nav2-navigate-to-pose` | | `version` | `0.1.0` | | `license` | `apache-2.0` | | `kind` | `ros_action` | | `role` | `s1` | | `actions` | `[navigate]` | | `chunk_size` | `1` (schema-enforced for `kind: ros_action`) | | `latency_budget.per_chunk_ms` | `60000` (navigation is long-horizon; the adapter waits ×5 of this on the action result) | | `ros_integration.package` | `nav2_msgs` | | `ros_integration.interface_type` | `NavigateToPose` | | `ros_integration.interface_name` | `/navigate_to_pose` | | `ros_integration.result_trajectory_field` | _omitted → result-only mode_ | | `commercial_use_allowed` | `true` (apache-2.0) | Full schema: [`openral_core.schemas.RSkillManifest`](../../python/core/src/openral_core/schemas.py). ## Quick start ```python from openral_rskill.loader import rSkill pkg = rSkill.from_yaml("rskills/rskill-nav2-navigate-to-pose/rskill.yaml") print(pkg.manifest.name, pkg.manifest.kind, pkg.manifest.ros_integration.interface_name) ``` End-to-end, with a real Nav2 launch up (e.g. against a Gazebo / Turtlebot4 sim): ```bash # 1. Bring up Nav2 for your mobile-base sim or robot ros2 launch nav2_bringup tb4_simulation_launch.py # 2. Bring up the OpenRAL runner against that embodiment ros2 launch openral_rskill_ros skill_runner.launch.py robot:=panda_mobile # 3. From the Reasoner (or by hand), dispatch the goal: ros2 action send_goal /openral/execute_skill openral_msgs/action/ExecuteSkill \ "{rskill_id: 'OpenRAL/rskill-nav2-navigate-to-pose', deadline_s: 120.0, prompt: 'go to map origin'}" ``` ## Limitations / Roadmap - **Velocity stream bypasses the OpenRAL safety supervisor.** Nav2 publishes `/cmd_vel` directly. See ADR-0024 §Out-of-scope. - **Goal hard-coded in the manifest.** v1 ships one goal per manifest; structured-prompt support is the next ADR. - **No mobile-base HAL in-tree.** Until one lands, the skill resolves only inside deployments that ship their own mobile-base wiring. ## License The rSkill package itself (this manifest + README) is **Apache-2.0**. The wrapped Nav2 code (`nav2_msgs` IDL, `navigation2` planners) is **Apache-2.0** and lives outside this repository — installed via `ros-${ROS_DISTRO}-nav2-bringup`. Per [ADR-0012](../../docs/adr/0012-open-core-licensing.md) both postures are commercial-use-permissive. ## See also - [ADR-0024 — ROS-wrapped rSkills](../../docs/adr/0024-ros-wrapped-rskills.md) - [`openral_rskill.ros_action_rskill`](../../python/rskill/src/openral_rskill/ros_action_rskill.py) — adapter source - [`rskills/rskill-moveit-joints/`](../rskill-moveit-joints/) — sibling MoveIt wrapper (trajectory mode) - [CLAUDE.md §3 — Architecture Discipline](../../CLAUDE.md)