When to Use
- A
scene_*_g2_{op,sp} is running (via the launch-scene skill) and
the user wants planning + RViz on top.
- User wants to switch the active IK plugin or A/B the GenieBioIK
"human priors" (torso-straight, chassis-pin, head LookAt).
- User wants to drive the arm directly via
/joint_command (e.g.
wok_flip_cmds.py) without ros2_control fighting the publisher.
Do not use for:
- Robots other than Genie G2 — the SRDF, coupled-joint constraints,
and ros2_controllers manifest are G2-only. Other robots run on the
engine but don't have a packaged MoveIt config.
- Launching the simulator itself →
launch-scene skill.
- Building the workspace →
build-workspace skill.
Critical Patterns
arm and gripper are independent. Defaults are
arm:=crsB gripper:=swiftpicker. The launch wires both into the
URDF filename and the SRDF xacro mappings, so any
(arm, gripper) combo that has a corresponding URDF under
genie_sim_robot_model/urdf/ works.
- Match MoveIt's
(arm, gripper) to the scene's robot variant.
scene_pnp_g2_op → gripper:=omnipicker,
scene_wbc_g2_sp → gripper:=swiftpicker. Mismatched values
produce a URDF MoveIt can plan against but a robot the engine
refuses to drive.
- Pick the IK plugin via
use_human_priors, not by editing yaml.
use_human_priors:=true (default) loads
config/kinematics.yaml (GenieBioIK with priors);
use_human_priors:=false loads config/kinematics_vanilla.yaml
(upstream BioIK, every prior weight zeroed). Both files share the
plugin selection / IK links / timeouts so the only A/B variable is
the goal stack.
use_ros2_control:=false for /joint_command driving. When an
external publisher (teleop, wok-flip script) writes
/joint_command, the ros2_control node would republish at the CM
update rate and fight it — set this flag to leave move_group
alone (the /compute_ik, /compute_fk services) so there's a
single source on the topic.
The matrix
Scene (from launch-scene) |
Recommended wbc.launch.py args |
scene_pnp_g2_op |
arm:=crsB gripper:=omnipicker |
scene_wbc_g2_sp |
arm:=crsB gripper:=swiftpicker (defaults) |
scene_flat_g2_sp / _chef / _shirt |
defaults (crsB + swiftpicker) |
| IK plugin / mode |
Args |
| GenieBioIK with human priors (default) |
use_human_priors:=true |
| Upstream BioIK (priors zeroed, for A/B) |
use_human_priors:=false |
move_group only — /compute_ik services, no controllers |
use_ros2_control:=false |
Workflow
Step 1 — Confirm the scene is up
launch-scene skill should already be running in another shell.
Verify:
ros2 topic list | grep -E "joint_states|tf|clock"
ros2 topic hz /clock # sim-time pacing should be live
Step 2 — Pick arm + gripper
Ask via AskUserQuestion if not given. Default to the scene's
gripper (see matrix above).
Step 3 — Launch MoveIt
source devel/setup.bash
# Default (Genie G2 + crsB + swiftpicker + human priors + ros2_control):
ros2 launch genie_sim_moveit wbc.launch.py
# crs arm + omnipicker:
ros2 launch genie_sim_moveit wbc.launch.py arm:=crs gripper:=omnipicker
# A/B vanilla BioIK (priors disabled):
ros2 launch genie_sim_moveit wbc.launch.py use_human_priors:=false
# Direct /joint_command (e.g. external teleop / wok_flip_cmds.py):
ros2 launch genie_sim_moveit wbc.launch.py use_ros2_control:=false
Step 4 — Plan in RViz
The launch starts move_group, robot_state_publisher, and
rviz2 with the MoveIt-Plan-Execute panel. Drag the interactive
marker on the IK link, hit Plan, then Execute.
Step 5 — (optional) Drive the chassis as a single chain
simple_body_controller claims the same body-joint position
interfaces as simple_waist_controller + simple_torso_controller,
so it's configured but not auto-spawned. To drive the body as one
chain:
ros2 control switch_controllers \
--activate simple_body_controller \
--deactivate simple_waist_controller simple_torso_controller
Commands (copy-paste summary for the user)
# Inside the container, after sourcing the overlay:
source devel/setup.bash
# Most common: match a pnp scene
ros2 launch genie_sim_moveit wbc.launch.py arm:=crsB gripper:=omnipicker
# A/B the human priors
ros2 launch genie_sim_moveit wbc.launch.py use_human_priors:=false
# move_group only (for external /joint_command publishers)
ros2 launch genie_sim_moveit wbc.launch.py use_ros2_control:=false
Notes
- The MoveIt URDF joint limits are widened by ±0.01 rad / ±0.001 m
at launch time to absorb MuJoCo soft-limit drift —
CheckStartStateBounds reads URDF limits directly, so the
per-pipeline start_state_max_bounds_error doesn't help. Helper
lives in genie_sim_robot_model.urdf_utils.pad_urdf_joint_limits.
- Default workspace half-extent for OMPL planar-joint bounds is set
to 200 m via
ompl.default_workspace_bounds — without this,
FixWorkspaceBounds clamps planar_joint/trans_{x,y} to a narrow
box that excludes the actual map → base_link pose.
fix_start_state:=true lets jazzy's CheckStartStateBounds adapter
actively renormalise joint values that drift past <limit> by
sub-mrad under contact load (default upstream is false).
- The MoveIt config is distro-agnostic (Humble + Jazzy). Distro
drift is absorbed by
moveit_compat.hpp in
genie_sim_moveit_plugins/, never by #ifdef in the config
package.
Resources
1---2name: moveit-wbc3description: Bring up MoveIt 2 + whole-body-control RViz for the Genie G2 family, using `ros2 launch genie_sim_moveit wbc.launch.py`. Covers arm × gripper selection, the three packaged IK plugins (KDL-coupled, bio_ik-coupled, relaxed-IK), the GenieBioIK human-prior A/B switch, and the `use_ros2_control:=false` mode for direct `/joint_command` driving. Trigger: When the user asks to "start moveit", "wbc rviz", "plan with moveit", "switch IK plugin", "drive joint_command directly", "compare human priors", or pairs MoveIt with a `scene_*_g2_*` launched by the `launch-scene` skill.4license: MPL-2.05---67## When to Use89- A `scene_*_g2_{op,sp}` is running (via the `launch-scene` skill) and10 the user wants planning + RViz on top.11- User wants to switch the active IK plugin or A/B the GenieBioIK12 "human priors" (torso-straight, chassis-pin, head LookAt).13- User wants to drive the arm directly via `/joint_command` (e.g.14 `wok_flip_cmds.py`) without ros2_control fighting the publisher.1516Do **not** use for:17- Robots other than Genie G2 — the SRDF, coupled-joint constraints,18 and ros2_controllers manifest are G2-only. Other robots run on the19 engine but don't have a packaged MoveIt config.20- Launching the simulator itself → `launch-scene` skill.21- Building the workspace → `build-workspace` skill.2223## Critical Patterns24251. **`arm` and `gripper` are independent.** Defaults are26 `arm:=crsB gripper:=swiftpicker`. The launch wires both into the27 URDF filename and the SRDF xacro mappings, so any28 `(arm, gripper)` combo that has a corresponding URDF under29 `genie_sim_robot_model/urdf/` works.302. **Match MoveIt's `(arm, gripper)` to the scene's robot variant.**31 `scene_pnp_g2_op` → `gripper:=omnipicker`,32 `scene_wbc_g2_sp` → `gripper:=swiftpicker`. Mismatched values33 produce a URDF MoveIt can plan against but a robot the engine34 refuses to drive.353. **Pick the IK plugin via `use_human_priors`, not by editing yaml.**36 `use_human_priors:=true` (default) loads37 `config/kinematics.yaml` (GenieBioIK with priors);38 `use_human_priors:=false` loads `config/kinematics_vanilla.yaml`39 (upstream BioIK, every prior weight zeroed). Both files share the40 plugin selection / IK links / timeouts so the only A/B variable is41 the goal stack.424. **`use_ros2_control:=false` for `/joint_command` driving.** When an43 external publisher (teleop, wok-flip script) writes44 `/joint_command`, the ros2_control node would republish at the CM45 update rate and fight it — set this flag to leave `move_group`46 alone (the `/compute_ik`, `/compute_fk` services) so there's a47 single source on the topic.4849## The matrix5051| Scene (from `launch-scene`) | Recommended `wbc.launch.py` args |52|---|---|53| `scene_pnp_g2_op` | `arm:=crsB gripper:=omnipicker` |54| `scene_wbc_g2_sp` | `arm:=crsB gripper:=swiftpicker` (defaults) |55| `scene_flat_g2_sp` / `_chef` / `_shirt` | defaults (`crsB` + `swiftpicker`) |5657| IK plugin / mode | Args |58|---|---|59| GenieBioIK with human priors (default) | `use_human_priors:=true` |60| Upstream BioIK (priors zeroed, for A/B) | `use_human_priors:=false` |61| `move_group` only — `/compute_ik` services, no controllers | `use_ros2_control:=false` |6263## Workflow6465### Step 1 — Confirm the scene is up6667`launch-scene` skill should already be running in another shell.68Verify:6970```bash71ros2 topic list | grep -E "joint_states|tf|clock"72ros2 topic hz /clock # sim-time pacing should be live73```7475### Step 2 — Pick `arm` + `gripper`7677Ask via `AskUserQuestion` if not given. Default to the scene's78gripper (see matrix above).7980### Step 3 — Launch MoveIt8182```bash83source devel/setup.bash8485# Default (Genie G2 + crsB + swiftpicker + human priors + ros2_control):86ros2 launch genie_sim_moveit wbc.launch.py8788# crs arm + omnipicker:89ros2 launch genie_sim_moveit wbc.launch.py arm:=crs gripper:=omnipicker9091# A/B vanilla BioIK (priors disabled):92ros2 launch genie_sim_moveit wbc.launch.py use_human_priors:=false9394# Direct /joint_command (e.g. external teleop / wok_flip_cmds.py):95ros2 launch genie_sim_moveit wbc.launch.py use_ros2_control:=false96```9798### Step 4 — Plan in RViz99100The launch starts `move_group`, `robot_state_publisher`, and101`rviz2` with the MoveIt-Plan-Execute panel. Drag the interactive102marker on the IK link, hit **Plan**, then **Execute**.103104### Step 5 — (optional) Drive the chassis as a single chain105106`simple_body_controller` claims the same body-joint position107interfaces as `simple_waist_controller` + `simple_torso_controller`,108so it's configured but not auto-spawned. To drive the body as one109chain:110111```bash112ros2 control switch_controllers \113 --activate simple_body_controller \114 --deactivate simple_waist_controller simple_torso_controller115```116117## Commands (copy-paste summary for the user)118119```bash120# Inside the container, after sourcing the overlay:121source devel/setup.bash122123# Most common: match a pnp scene124ros2 launch genie_sim_moveit wbc.launch.py arm:=crsB gripper:=omnipicker125126# A/B the human priors127ros2 launch genie_sim_moveit wbc.launch.py use_human_priors:=false128129# move_group only (for external /joint_command publishers)130ros2 launch genie_sim_moveit wbc.launch.py use_ros2_control:=false131```132133## Notes134135- The MoveIt URDF joint limits are widened by ±0.01 rad / ±0.001 m136 at launch time to absorb MuJoCo soft-limit drift —137 `CheckStartStateBounds` reads URDF limits directly, so the138 per-pipeline `start_state_max_bounds_error` doesn't help. Helper139 lives in `genie_sim_robot_model.urdf_utils.pad_urdf_joint_limits`.140- Default workspace half-extent for OMPL planar-joint bounds is set141 to 200 m via `ompl.default_workspace_bounds` — without this,142 `FixWorkspaceBounds` clamps `planar_joint/trans_{x,y}` to a narrow143 box that excludes the actual map → base_link pose.144- `fix_start_state:=true` lets jazzy's `CheckStartStateBounds` adapter145 actively renormalise joint values that drift past `<limit>` by146 sub-mrad under contact load (default upstream is false).147- The MoveIt config is **distro-agnostic** (Humble + Jazzy). Distro148 drift is absorbed by `moveit_compat.hpp` in149 `genie_sim_moveit_plugins/`, never by `#ifdef` in the config150 package.151152## Resources153154- **Launch file**: [source/geniesim_ros/src/ros_ws/src/genie_sim_moveit/launch/wbc.launch.py](../../src/ros_ws/src/genie_sim_moveit/launch/wbc.launch.py)155- **Per-gripper SRDF fragments**: [source/geniesim_ros/src/ros_ws/src/genie_sim_moveit/config/srdf_grippers/](../../src/ros_ws/src/genie_sim_moveit/config/srdf_grippers/)156- **IK plugins**: [source/geniesim_ros/src/ros_ws/src/genie_sim_moveit_plugins/](../../src/ros_ws/src/genie_sim_moveit_plugins/)157- **MoveIt config overview**: [source/geniesim_ros/src/ros_ws/src/genie_sim_moveit/AGENTS.md](../../src/ros_ws/src/genie_sim_moveit/AGENTS.md)