rskill-moveit-joints
OpenRAL rSkill β wraps the upstream
moveit_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-armunder ADR-0052.
This package uses kind: ros_action (see
ADR-0024) β 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 (ADR-0052). 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.
| Field | Value |
|---|---|
| Actions | reach |
| Objects | none β no per-object specialisation |
| Scenes | none β the wrapped planner does its own collision check against the live /planning_scene |
| Embodiment | franka_panda (default goal); other arm tags listed in the manifest for capability filtering |
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 (seebuild_joint_permutation_from_names), - returns waypoint 0 as a 1-row
Action(JOINT_POSITION, β¦).
- builds the
- 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
| Direction | Key | Shape | Notes |
|---|---|---|---|
| in | world_state.joint_state |
(n_dof,) float |
Read for logging only; the wrapped server consumes its own /joint_states subscription |
| out | per-waypoint Action |
joint_targets=[[n_dof floats]], horizon=1, is_terminal=False |
One chunk per step() until completion is signalled by exception |
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.
How it was trained / Upstream provenance
Nothing is trained β this rSkill wraps the upstream MoveIt motion planner.
| Field | Value |
|---|---|
| Upstream | moveit_msgs/action/MoveGroup (BSD-3-Clause) |
| Planner library | MoveIt 2 (BSD-3-Clause) |
| Collision check | FCL via MoveIt's PlanningScene (run during planning) |
| Wrapped artefact | rSkill manifest + README β no weights, no preprocessor JSONs |
Supported robots / embodiments
| Robot | Embodiment tag | Status | Notes |
|---|---|---|---|
| Franka Panda | franka_panda |
validated | default goal targets panda_arm home pose |
| Universal Robots UR5e | ur5e |
experimental | needs a joint / request.group_name override ("manipulator", UR joint names) |
| Universal Robots UR10e | ur10e |
experimental | same as UR5e |
| SO-100 follower | so100_follower |
experimental | needs a MoveIt config and joint-name override |
| OpenArm | openarm |
experimental | bi-manual β choose left_arm or right_arm group |
| Flexiv Rizon4 | rizon4 |
experimental | upstream MoveIt config exists; manifest override needed |
| Rethink Sawyer | sawyer |
experimental | upstream MoveIt config exists |
| Trossen WidowX | widowx |
experimental | upstream MoveIt config exists |
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:
| Source | Topic | Why MoveIt needs it |
|---|---|---|
| Joint state | /joint_states |
Plan from the live start state |
| Planning scene | /planning_scene (or /monitored_planning_scene) |
Self- and environment-collision check |
| TF | /tf, /tf_static |
Resolve goal pose / link frames |
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
| Field | Value |
|---|---|
name |
OpenRAL/rskill-moveit-joints |
version |
0.1.0 |
license |
apache-2.0 |
kind |
ros_action |
role |
s1 |
actions |
[reach] |
chunk_size |
1 (schema-enforced for kind: ros_action) |
latency_budget.per_chunk_ms |
2000 (planning latency; the adapter waits Γ5 of this on the action result) |
ros_integration.package |
moveit_msgs |
ros_integration.interface_type |
MoveGroup |
ros_integration.interface_name |
/move_action |
ros_integration.goal_builder |
joint (selects JointGoalRskill) |
ros_integration.result_trajectory_field |
planned_trajectory.joint_trajectory |
commercial_use_allowed |
true (apache-2.0) |
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-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. Per
ADR-0012 both postures
are commercial-use-permissive.
See also
- ADR-0052 β MoveIt goal-builder library + rskill-moveit-* rename
- ADR-0024 β ROS-wrapped rSkills
openral_rskill.ros_action_rskillβ engine sourceopenral_rskill.joint_goal_rskillβ goal-lowering adapterrskills/rskill-moveit-eef-pose/β sibling Cartesian end-effector pose wrapperrskills/rskill-moveit-look-at/β sibling camera-aiming wrapperrskills/rskill-nav2-navigate-to-pose/β sibling Nav2 wrapper (result-only mode)- CLAUDE.md Β§3 β Architecture Discipline