OpenRAL/rskill-moveit-multi-joints
rskill-moveit-multi-joints
OpenRAL rSkill — wraps the upstreammoveit_msgs/action/MoveGroupaction server as an OpenRAL rSkill so the Reasoner can dispatch collision-free joint-space motion planning through the sameExecuteRskillpath used by VLA skills. No model weights — the manifest is the entire artefact. Renamed fromopenral/rskill-moveit-plan-armas part of therskill-moveit-*rename.
This package uses kind: ros_action — a discriminator on RSkillManifest.kind that selects the `ROSActionRskill` engine at resolve time, with ros_integration.goal_builder: joint selecting the `JointGoalRskill` goal-lowering adapter. The adapter constructs an rclpy.action.ActionClient on the host RskillRunnerNode, sends one goal built from ros_integration.default_goal_json, awaits the result, and replays the returned trajectory_msgs/JointTrajectory one waypoint per step() call onto /openral/candidate_action so the safety supervisor still applies its per-joint envelope check to every commanded position.
What this skill does
Plans and executes a collision-free joint-space motion to a target joint configuration via MoveIt's MoveGroup action. The goal is authored as a joint block (joint_names + positions) — the clean, LLM-facing form (target angles, not hand-written constraint dicts) — which JointGoalRskill lowers into MoveGroup joint_constraints at configure time. The default goal targets the Franka Panda home pose (panda_arm planning group). Other arm embodiments need their own manifest copy with the correct planning-group name and joint names.
How it works
ROSActionRskill is a thin rSkillBase shim around an ActionClient, and goal_builder: joint lowers the LLM-facing joint block into the MoveGroup goal:
_configure_impllazy-importsmoveit_msgs.action.MoveGroup, opens anActionClienton/move_actionfrom theRskillRunnerNode-supplied node handle, and parsesros_integration.default_goal_jsononce.JointGoalRskillpops thejointblock (joint_names+positions+ tolerance) and lowers it intorequest.goal_constraints[0].joint_constraints— onemoveit_msgs/JointConstraintper joint.- On the first
_step_impl(world_state)call the adapter: - builds the
MoveGroup.Goalfrom the lowered dict (viarosidl_runtime_py.set_message_fields), - sends it and polls the goal-accept + result futures while the host node's main rclpy spin continues to service callbacks (same pattern as
rskill_runner_node._maybe_reset_hal_to_starting_pose), - extracts
result.planned_trajectory.joint_trajectory, reorders itsjoint_namesinto the hostRobotDescription.jointsorder (see `build_joint_permutation_from_names`), - returns waypoint 0 as a 1-row
Action(JOINT_POSITION, …). - Each subsequent
_step_implreturns the next cached waypoint. - After the last waypoint, the adapter raises
ROSRskillGoalSatisfied— the runner catches it specifically and closes theExecuteRskillgoal withsuccess=True.
The LLM overrides only joint.positions (one entry per planning-group joint, in the manifest's joint_names order); planner and tolerance defaults are inherited from default_goal_json. plan_only: true so MoveGroup never drives its own controllers — OpenRAL's per-waypoint replay is the only actuation path.
Observation → action contract
Why one row per chunk (chunk_size: 1 is schema-enforced for kind: ros_action): the OpenRAL safety supervisor only validates row 0 of every ActionChunk today (`supervisor_node.py`). Packing the full trajectory as one chunk with horizon=N would let waypoints 1..N actuate unchecked — unacceptable for a planner whose job is to thread between joint-limit walls.
GPU-accelerated planning (cuMotion)
On a host that clears the cuMotion GPU floor (RobotCapabilities.supports_cumotion() — Ampere+, CUDA ≥ 13, ~8 GB VRAM), the runner sets MotionPlanRequest.pipeline_id = "isaac_ros_cumotion" so MoveIt plans with NVIDIA's CUDA-accelerated cuMotion pipeline; otherwise it falls back to OMPL. Transparent — same skill, no manifest change — and it never bypasses the safety kernel: the planned trajectory still replays through /openral/candidate_action and is validated waypoint-by-waypoint. Install: see `docs/contributing/toolchain.md` → "GPU motion planning — cuMotion".
How it was trained / Upstream provenance
Nothing is trained — this rSkill wraps the upstream MoveIt motion planner.
Supported robots / embodiments
Listed embodiment_tags only gate which robots see this skill in the Reasoner's tool palette; actual resolution depends on move_group being up for that robot with a joint block matching its planning group.
Sensors required / Observation contract
This skill consumes nothing through OpenRAL's sensor pipeline. MoveIt's own subscriptions handle:
If your deployment uses a non-default topic remap, surface it on the MoveIt node's launch — the wrapped action's contract is intact.
Manifest summary
Full schema: `openral_core.schemas.RSkillManifest`.
Quick start
from openral_rskill.loader import rSkill
pkg = rSkill.from_yaml("rskills/rskill-moveit-joints/rskill.yaml")
print(pkg.manifest.name, pkg.manifest.kind, pkg.manifest.ros_integration.goal_builder)End-to-end, with a real MoveIt launch up:
# 1. Bring up MoveIt for your robot (example: Panda)
ros2 launch moveit_resources_panda_moveit_config demo.launch.py
# 2. Bring up the OpenRAL runner against the same robot
ros2 launch openral_rskill_ros skill_runner.launch.py robot:=franka_panda
# 3. From the Reasoner (or by hand via the action CLI), dispatch the goal:
ros2 action send_goal /openral/execute_rskill openral_msgs/action/ExecuteRskill \
"{rskill_id: 'OpenRAL/rskill-moveit-multi-joints', deadline_s: 30.0, prompt: 'move to home'}"Limitations / Roadmap
- Goal defaults live in the manifest. The LLM overrides
joint.positionsviagoal_params_json; planner settings and joint names are inherited fromdefault_goal_json. Cross-embodiment retargeting is a manifest copy with the correctjoint.joint_names+request.group_name. - OpenRAL safety supervisor does not do collision checking. We trust MoveIt's internal FCL pass. The per-joint envelope check still runs per waypoint. Collision checking inside the OpenRAL kernel is a separate ADR + multi-PR effort.
- No velocity / jerk bound at the supervisor. A planner emitting a rough trajectory would actuate today; the existing supervisor only checks per-joint position envelope. Tracked separately.
License
The rSkill package itself (this manifest + README) is Apache-2.0. The wrapped MoveIt code (moveit_msgs IDL, moveit2 planners) is BSD-3-Clause and lives outside this repository — installed via ros-${ROS_DISTRO}-moveit. Both postures are commercial-use-permissive.
See also
- MoveIt goal-builder library + rskill-moveit-* rename
- ROS-wrapped rSkills
- `openral_rskill.ros_action_rskill` — engine source
- `openral_rskill.joint_goal_rskill` — goal-lowering adapter
- `rskills/rskill-moveit-eef-pose/` — sibling Cartesian end-effector pose wrapper
- `rskills/rskill-moveit-look-at/` — sibling camera-aiming wrapper
- `rskills/rskill-nav2-navigate-to-pose/` — sibling Nav2 wrapper (result-only mode)
- CLAUDE.md §3 — Architecture Discipline
