MoveIt 2 is the de facto standard for motion planning in <a href="/services/physical-ai-robotics">ros</a> 2, enabling robotic arms to plan, execute, and adapt trajectories with collision avoidance. This guide covers installation, configuration, and practical use cases—from basic planning to real-time control—using MoveIt 2.8.0 (May 2026) on ROS 2 Jazzy.
TL;DR
- Install MoveIt 2 via
ros-jazzy-moveitor build from source for customization. - Use the MoveIt Setup Assistant to generate URDF/SRDF configs for your robot.
- Plan motions with OMPL planners (e.g.,
RRTConnectkConfigDefault) and visualize in RViz. - Enable MoveIt Servo for real-time trajectory tracking with
ros2_control. - Integrate perception (e.g., camera feeds) via ROS 2 topics and
moveit_msgs/PlanningScene.
1. Installation and the MoveIt Setup Assistant
Prerequisites
- Ubuntu 24.04 (Noble Numbat) + ROS 2 Jazzy (install guide).
- Python 3.10+ (MoveIt 2.8.0 requires Python 3.10+ due to
moveit_commanderupdates). - Git and colcon (for source builds).
Verify your setup:
echo $ROS_DISTRO # Should output "jazzy"
python3 --version # Should output 3.10+
Install MoveIt 2
Option A: Binary Install (Recommended)
sudo apt update
sudo apt install ros-jazzy-moveit
source /opt/ros/jazzy/setup.bash
Verify installation:
ros2 pkg prefix moveit_ros # Should return /opt/ros/jazzy
Option B: Source Build (For Customization)
mkdir -p ~/moveit2_ws/src && cd ~/moveit2_ws/src
git clone https://github.com/ros-planning/moveit2.git -b main
vcs import < moveit2/moveit2.repos
cd ~/moveit2_ws && colcon build --symlink-install
source install/setup.bash
Launch MoveIt Demo
Test with the Panda robot (included in MoveIt):
ros2 launch moveit2_demos panda_moveit_demo.launch.py
- Expected Output: RViz should open with the Panda arm and a planning scene.
- Gotcha: If RViz fails, ensure
ros-jazzy-rviz2andros-jazzy-ogreare installed:sudo apt install ros-jazzy-rviz2 ros-jazzy-ogre
2. Configuring a Robot (URDF/SRDF)
Step 1: Prepare Your URDF
MoveIt requires a URDF (robot description) and SRDF (semantic robot description). Use the MoveIt Setup Assistant to generate configs.
Example URDF (Simplified Panda Arm)
<!-- panda.urdf.xacro -->
<robot name="panda" xmlns:xacro="http://www.ros.org/wiki/xacro">
<link name="world"/>
<joint name="panda_joint" type="fixed">
<parent link="world"/>
<child link="panda_link0"/>
</joint>
<!-- Add your robot's joints/links here -->
</robot>
Step 2: Run the Setup Assistant
ros2 run moveit_setup_assistant setup_assistant
- Input:
- URDF file:
path/to/your_robot.urdf.xacro - Output directory:
~/moveit2_ws/src/your_robot_moveit_config
- URDF file:
- Output: Generates:
config/srdf/(semantic descriptions)config/joint_limits.yaml(joint constraints)launch/(launch files)
Step 3: Build and Source
cd ~/moveit2_ws && colcon build --packages-select your_robot_moveit_config
source install/setup.bash
Step 4: Launch Your Robot in MoveIt
ros2 launch your_robot_moveit_config demo.launch.py
- Expected Output: RViz with your robot’s kinematic tree and collision objects.
Gotchas
- Missing Joint Limits: If joints don’t move, check
joint_limits.yaml:joint_limits: panda_joint: has_velocity_limits: true max_velocity: 1.0 has_acceleration_limits: true max_acceleration: 2.0 - Collision Mesh Errors: Ensure all
<collision>and<visual>tags in URDF have<geometry>(e.g.,<mesh filename="package://meshes/panda_link.dae"/>). - SRDF Validation: Run:
ros2 run srdfdom check_srdf your_robot.srdf
3. Motion Planning with OMPL
Plan a Joint-Space Trajectory
Use moveit_commander (Python) or move_group (C++). Here’s a Python example:
#!/usr/bin/env python3
import rclpy
from moveit_commander import MoveGroupCommander
def plan_joint_trajectory():
rclpy.init()
group = MoveGroupCommander("panda_arm") # Group name from SRDF
group.set_planner_id("RRTConnectkConfigDefault") # OMPL planner
# Set a joint goal (radians)
joint_goal = [0.0, -0.785, 0.0, -2.356, 0.0, 1.571, 0.785]
group.set_joint_value_target(joint_goal)
# Plan and execute
plan = group.go(wait=True)
if plan:
print("Trajectory executed successfully!")
else:
print("Planning failed.")
if __name__ == "__main__":
plan_joint_trajectory()
rclpy.shutdown()
Key OMPL Planners in MoveIt 2.8.0
| Planner | Use Case | Notes |
|---|---|---|
RRTConnectkConfigDefault | General-purpose | Fast, good for redundant robots. |
TRRT | High-dimensional spaces | Better for many DOFs. |
ESTkConfigDefault | Precision tasks | Slower but more accurate. |
PilzIndustrial | Industrial arms (Pilz-compatible) | Requires moveit_pilz package. |
Visualize the Plan in RViz
- Add a Motion Planning display in RViz.
- Select your group (
panda_arm). - Click "Plan" to see the trajectory in red.
Gotchas
- Planning Failures: If
group.go()returnsFalse, try:- A different planner:
group.set_planner_id("TRRT"). - Adjusting
max_iterationsin the planner config:# config/planning_pipelines/panda.srdf planner_configs: RRTConnectkConfigDefault: max_iterations: 1000000
- A different planner:
- Self-Collisions: Ensure your URDF’s
<collision>tags are correct. Use:ros2 run moveit_ros_planning_interface check_collisions
4. Collision Checking and Planning Scenes
Add Objects to the Planning Scene
def add_box_to_scene():
scene = group.get_planning_scene()
box_pose = geometry_msgs.msg.PoseStamped()
box_pose.header.frame_id = "panda_link0"
box_pose.pose.position.z = 0.2 # Offset from end effector
scene.add_box("box1", box_pose, (0.1, 0.1, 0.1)) # (x, y, z) dimensions
scene.async_update() # Non-blocking update
Check Collisions
def check_collision():
collision_state = group.get_current_state()
result = group.check_state_collision(collision_state)
print(f"Collision detected: {result}")
Load/Save Scenes
# Save scene to file
scene.export_to_xml_file("scene.xml")
# Load scene
scene.load_from_xml_file("scene.xml")
Gotchas
- Stale Scene Data: Always call
scene.async_update()after modifications. - Object Frames: Ensure all object poses are in a valid frame (e.g.,
panda_link0). - Performance: For many objects, use
scene.async_update()to avoid blocking.
5. Cartesian Paths and Pick-and-Place
Plan a Cartesian Path
def plan_cartesian_path():
group.set_max_velocity_scaling_factor(0.5) # Slow down for precision
waypoints = []
# Start at current pose
waypoints.append(group.get_current_pose().pose)
# Define intermediate waypoints (6D pose: x,y,z,roll,pitch,yaw)
pose_target = geometry_msgs.msg.Pose()
pose_target.position.x = 0.3
pose_target.position.y = 0.1
pose_target.position.z = 0.2
pose_target.orientation.w = 1.0
waypoints.append(pose_target)
# Plan and execute
(plan, fraction) = group.compute_cartesian_path(
waypoints,
eef_step=0.01, # End-effector step size
jump_threshold=0.0
)
group.execute(plan)
Pick-and-Place Example
def pick_and_place():
# Approach the object
group.set_pose_target(pick_pose)
plan = group.go(wait=True)
# Attach the object (simulated)
group.attach_object("box1")
# Move to place pose
group.set_pose_target(place_pose)
plan = group.go(wait=True)
# Detach the object
group.detach_object("box1")
Gotchas
- Frame Mismatches: Ensure all poses are in the same frame (e.g.,
base_link). - Singularities: Cartesian paths may fail near singularities. Use:
group.set_goal_joint_tolerance(0.001) # Tighter tolerance - Gripper Control: For grippers, use
ros2_controlinterfaces (see Section 6).
6. MoveIt Servo for Real-Time Control
MoveIt Servo enables real-time trajectory tracking using ros2_control. This is critical for dynamic environments or high-speed tasks.
Prerequisites
- Install
ros2_controland hardware interfaces:sudo apt install ros-jazzy-ros2-control ros-jazzy-ros2-controllers
Configure Servo
-
Add Servo to Your Launch File:
<!-- launch/servo_demo.launch.py --> <launch> <include file="$(find your_robot_moveit_config)/launch/demo.launch.py"/> <node pkg="moveit_servo" exec="servo_node" name="servo_node"> <param name="robot_description" type="string" command="$(param robot_description)"/> <param name="group_name" value="panda_arm"/> <param name="servo_period" value="0.01"/> <!-- 100Hz --> </node> </launch> -
Run Servo:
ros2 launch your_robot_moveit_config servo_demo.launch.py
Send Real-Time Commands
def servo_cartesian_motion():
servo = MoveItServoCommander("panda_arm")
servo.start()
# Define a waypoint
waypoint = geometry_msgs.msg.PoseStamped()
waypoint.header.frame_id = "base_link"
waypoint.pose.position.x = 0.4
# Send at 100Hz
servo.send_cartesian_waypoint(waypoint, 0.01) # 0.01s interval
Gotchas
- Latency: Servo requires a real-time kernel for sub-10ms latency. Use:
sudo apt install ros-jazzy-ros2-realtime-tools - Controller Tuning: Adjust
servo_period(default: 0.01s). Lower values increase jitter. - Hardware Compatibility: Ensure your robot’s drivers support
ros2_control(e.g.,franka_ros2for Franka
