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.
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/CollisionObjectmessages with primitives or meshes. Good for known fixtures. - Live perception: feed depth-camera point clouds into the
OctomapServerfor 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:
RRTConnectfor speed,BITstarfor optimal-quality,STOMPfor 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_velat 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.