RobotForge
Published·~17 min

MoveIt 2: the practical guide

The motion-planning stack every ROS 2 arm runs. Setup Assistant, planning pipeline, controllers, perception. The week-of-work workflow for getting a new arm planning collision-free trajectories.

by RobotForge
#ros2#moveit#manipulation

MoveIt 2 is to arms what Nav2 is to mobile bases — the motion-planning stack that handles the hard parts (collision checking, kinematics, controller integration) so you can focus on what your arm actually does. Configured well, it plans a 6-DOF trajectory through clutter in milliseconds. Configured badly, it throws "no plan found" forever. Here's the practical workflow.

What MoveIt does (and doesn't)

Does:

  • Inverse kinematics (analytical, numerical, or both).
  • Sampling-based motion planning (OMPL: RRT, RRT-Connect, BiTRRT, …) and trajectory optimization (CHOMP, STOMP).
  • Collision checking against static + dynamic environments (FCL or Bullet).
  • Trajectory execution via ros2_control.
  • Cartesian path computation, pick-and-place pipelines, time parameterization.

Doesn't:

  • Object pose estimation (use a perception stack and feed it in).
  • Grasp generation (use Dex-Net / Contact-GraspNet / your method; pass the result to MoveIt to plan to).
  • Force / impedance control (use ros2_control with appropriate controllers).
  • Whole-body or floating-base motion (humanoids need OCS2, Pinocchio + MPC, etc.).

The bootstrap workflow (week-of-work)

Day 1: URDF + SRDF

You need a URDF for the arm (covered in the URDF lesson). Then run the MoveIt Setup Assistant:

ros2 launch moveit_setup_assistant setup_assistant.launch.py

Walks you through:

  • Loading your URDF.
  • Generating the self-collision matrix (which link pairs can never collide; speeds up planning by ~10×).
  • Defining planning groups (e.g., "arm" = 6 joints; "gripper" = 1 joint).
  • Defining named poses (home, ready, deg-zero) for tests.
  • Configuring end-effectors and controllers (matches your ros2_control setup).

Output: a my_robot_moveit_config package with everything wired up. This is your baseline.

Day 2: Bring up RViz with MoveIt

ros2 launch my_robot_moveit_config demo.launch.py

RViz comes up with the arm visualized. Drag the interactive marker to a new pose; click "Plan". A trajectory appears. Click "Execute". The simulated arm moves.

If anything fails here, fix it before going further. Day 1 issues that bite:

  • Bad URDF inertia values → execution oscillates.
  • Self-collision matrix incorrect → planner says "always in collision" or "never in collision" wrongly.
  • Wrong end-effector frame → grasping pipeline targets the wrong point.

Day 3: Plug in real (or simulated) hardware

The Setup Assistant assumes a fake controller. Swap to the real one by editing moveit_controllers.yaml and ensuring your URDF has a <ros2_control> block matching the joints. (See the ros2_control lesson.) Then test executing a small motion on the actual hardware.

Day 4: Add perception and collision objects

Until now, MoveIt only knows about the arm itself. To make it aware of the table, the part, the box, you have two paths:

  • Hand-defined planning scene: publish moveit_msgs/CollisionObject messages with primitives or meshes. Good for known fixtures.
  • Live perception: feed depth-camera point clouds into the OctomapServer for live obstacle modeling. Good for unstructured environments.

Day 5: Pick and place

MoveIt's moveit_msgs/Grasp structure encodes pre-grasp / grasp / retreat trajectories with attached objects. The PickAndPlace example in moveit2_tutorials is the template. Customize for your task.

The planning pipeline (where most tuning happens)

# planning_pipelines.yaml
default_planning_pipeline: ompl
planning_pipelines:
  pipeline_names: [ompl, chomp, stomp]

ompl:
  default_planner_request_adapters:
    - default_planner_request_adapters/AddTimeOptimalParameterization
    - default_planner_request_adapters/ResolveConstraintFrames
    - default_planner_request_adapters/FixWorkspaceBounds
    - default_planner_request_adapters/FixStartStateBounds
    - default_planner_request_adapters/FixStartStateCollision
    - default_planner_request_adapters/FixStartStatePathConstraints
  planner_configs:
    RRTConnectkConfigDefault:
      type: geometric::RRTConnect
      range: 0.0  # auto
    SBLkConfigDefault:
      type: geometric::SBL

Three knobs that change behavior most:

  • Default planner: RRTConnect for speed, BITstar for optimal-quality, STOMP for smooth, optimization-style.
  • Planning time: 5 s default. Increase if hard scenes; decrease if you need responsiveness.
  • Goal tolerance: tighter = more accuracy, more failures. Loosen for easier convergence.

Common MoveIt failures

  • "No plan found" — usually self-collision in the start or goal state. Check /move_group/display_grasp_markers; visualize the arm; loosen tolerances.
  • "Trajectory execution failed" — controller couldn't track the planned trajectory. Usually because joint velocity/acceleration limits were too aggressive. Edit joint_limits.yaml.
  • "Goal pose unreachable" — the IK solver found nothing. The point may be outside workspace; or your IK plug-in is too restrictive. Try TRAC-IK or KDL with iteration limits.
  • Random "always in collision" — the collision matrix is stale. Re-run the Setup Assistant after URDF changes.
  • Path through arm-self-collision — the collision matrix marked a pair as "never collides" when it can. Re-generate.

The plug-ins worth knowing

  • IKFast: analytical IK for arms with closed-form solutions (most 6-DOF spherical-wrist). 1000× faster than KDL.
  • TRAC-IK: numerical IK that handles joint limits and singularities much better than KDL. Default for many production setups.
  • Bio_IK: meta-heuristic IK that handles obstacles + multi-objective constraints in one solve.
  • MoveIt Servo: real-time Jacobian-based servoing for teleop. Subscribes to /cmd_vel at the end-effector.
  • OMPL Constraints: planning with task constraints (keep gripper upright while moving). Newer; powerful.

Performance tuning

  • Use IKFast if you can: dramatically faster than numerical alternatives.
  • Cache the collision matrix: regenerate only when URDF changes.
  • Reduce planning time on simple scenes: most plans should complete in < 100 ms.
  • Use Bullet over FCL for collision checking on heavy-mesh URDFs (5–10× faster on complex meshes).
  • Decimate visual meshes: collision checks against high-poly meshes is the slowest part of MoveIt. Substitute simplified collision meshes.

What's new in 2026

  • MoveIt 2 Pro — commercial layer on top of OSS MoveIt with hardened pick-and-place pipelines, in production at several manufacturers.
  • cuRobo integration — NVIDIA's GPU-accelerated motion planner; 100× speedup on certain problems. Plug-in for MoveIt.
  • Constraint-aware sampling — direct goal: find a configuration that satisfies a manifold of equality constraints (e.g., gripper-upright). Production-quality.
  • Learned warm starts — neural network proposes initial trajectories that classical planners optimize. Faster on hard problems.

Exercise

Take a 6-DOF arm URDF (e.g. UR5 or Panda from the official Universal Robots repo). Run the Setup Assistant. Bring up RViz. Plan from home to a pre-defined goal. Add a static collision box between them in code; replan. Then use a Cartesian path computation to move from A to B in a straight line. Three small wins; your understanding of MoveIt jumps.

Next

Debugging ROS 2 — the diagnostic toolkit (rqt, ros2 bag, rviz) that separates engineers who get unstuck from engineers who get stuck.

Comments

    Sign in to post a comment.