A comprehensive ROS2 workspace for a 6-DOF gem cutter manipulator robot with MoveIt motion planning framework integration. This project includes robot description (URDF), Gazebo simulation, and MoveIt configuration for motion planning and control.
- Project Overview
- Project Structure
- Prerequisites
- Building the Workspace
- Major Files Explained
- Running Major Commands
- Robot Description (URDF)
- MoveIt Configuration
- Kinematics Solver (KDL)
- Arm Configuration Details
- Usage Examples
This workspace contains three main ROS2 packages:
gem_cutter_description: Contains the robot's URDF/XACRO description files, visual materials, and RViz configurationgem_cutter_gazebo: Gazebo simulation launch files and world definitionsgem_cutter_moveit_config: Complete MoveIt configuration package generated using MoveIt Setup Assistant
The robot is a 6-DOF manipulator designed for gem cutting operations, with the following joint configuration:
- J1: Base yaw (rotation around Z-axis)
- J2: Shoulder pitch (rotation around Y-axis)
- J3: Elbow pitch (rotation around Y-axis)
- J4: Wrist pitch (rotation around Y-axis)
- J5: Wrist roll (rotation around X-axis)
- J6: Tool yaw (rotation around Z-axis)
Figure 1: Gem cutter manipulator visualized in RViz with joint_state_publisher_gui for manual joint control
gem_cutter_manipulator/
├── build/ # Build artifacts (generated)
├── install/ # Installed packages (generated)
├── log/ # Build logs (generated)
├── rebuild.sh # Build script
├── src/
│ ├── gem_cutter_description/
│ │ ├── urdf/
│ │ │ ├── gem_cutter_arm.urdf.xacro # Main robot URDF (XACRO)
│ │ │ ├── gem_cutter.urdf # Plain URDF (non-XACRO)
│ │ │ └── materials.xacro # Visual materials definition
│ │ ├── launch/
│ │ │ └── display.launch.py # RViz visualization launch
│ │ ├── config/
│ │ │ └── rviz/
│ │ │ └── config.rviz # RViz configuration
│ │ └── package.xml
│ ├── gem_cutter_gazebo/
│ │ ├── launch/
│ │ │ ├── sim.launch.py # Basic Gazebo simulation
│ │ │ └── sim_with_moveit.launch.py # Gazebo + MoveIt integration
│ │ ├── worlds/
│ │ │ └── gem_cutter_world.sdf # Gazebo world definition
│ │ └── package.xml
│ └── gem_cutter_moveit_config/
│ ├── config/
│ │ ├── gem_cutter_arm.srdf # Semantic Robot Description Format
│ │ ├── gem_cutter_arm.urdf.xacro # URDF with ros2_control integration
│ │ ├── gem_cutter_arm.ros2_control.xacro # ros2_control configuration
│ │ ├── kinematics.yaml # Kinematics solver configuration
│ │ ├── joint_limits.yaml # Joint velocity/acceleration limits
│ │ ├── moveit_controllers.yaml # MoveIt controller configuration
│ │ ├── ros2_controllers.yaml # ROS2 controller configuration
│ │ ├── initial_positions.yaml # Initial joint positions
│ │ ├── pilz_cartesian_limits.yaml # Pilz planner limits
│ │ └── moveit.rviz # MoveIt RViz configuration
│ ├── launch/
│ │ ├── demo.launch.py # Main demo launch (MoveIt + RViz)
│ │ ├── setup_assistant.launch.py # MoveIt Setup Assistant
│ │ ├── move_group.launch.py # MoveIt move_group node
│ │ ├── moveit_rviz.launch.py # MoveIt RViz visualization
│ │ ├── rsp.launch.py # Robot State Publisher
│ │ └── spawn_controllers.launch.py # Controller spawning
│ ├── scripts/
│ │ └── spawn_scene.py # Scene object spawner
│ └── package.xml
- ROS2 Distribution: Jazzy Jalisco (Ubuntu 24.04)
- Required ROS2 Packages:
moveit2moveit_configs_utilsros_gz_sim(Gazebo Sim)ros_gz_bridgexacrorobot_state_publisherjoint_state_publisherjoint_state_publisher_guirviz2controller_managerjoint_trajectory_controller
Install dependencies:
sudo apt update
sudo apt install ros-jazzy-moveit2 \
ros-jazzy-moveit-configs-utils \
ros-jazzy-ros-gz-sim \
ros-jazzy-ros-gz-bridge \
ros-jazzy-xacro \
ros-jazzy-robot-state-publisher \
ros-jazzy-joint-state-publisher \
ros-jazzy-joint-state-publisher-gui \
ros-jazzy-rviz2 \
ros-jazzy-controller-manager \
ros-jazzy-joint-trajectory-controllerThe rebuild.sh script automates the entire build process:
cd ~/development/ros/gem_cutter_manipulator
./rebuild.shWhat rebuild.sh does:
- Cleans previous build artifacts (
build/,install/,log/) - Sources ROS2 Jazzy base installation
- Builds the workspace using
colcon build --symlink-install - Sources the workspace overlay
- Sets up Gazebo resource paths
# 1. Source ROS2 base
source /opt/ros/jazzy/setup.bash
# 2. Navigate to workspace
cd ~/development/ros/gem_cutter_manipulator
# 3. Build workspace
colcon build --symlink-install
# 4. Source workspace overlay
source install/setup.bash
# 5. Set Gazebo resource path (optional, for simulation)
export GZ_SIM_RESOURCE_PATH="${GZ_SIM_RESOURCE_PATH:+$GZ_SIM_RESOURCE_PATH:}$(ros2 pkg prefix gem_cutter_description)/share"Note: The --symlink-install flag creates symbolic links instead of copying files, allowing you to edit source files without rebuilding.
- Purpose: Main robot description file using XACRO macros
- Key Features:
- Defines all 6 joints and 7 links (base_link + 6 links)
- Includes inertial properties (mass, inertia tensors)
- Visual and collision geometries
- Joint limits, dynamics (damping, friction)
- Supports prefix argument for multi-robot scenarios
- Structure:
- Base link: 9cm × 8.4cm plate
- Link 1: Pedestal with shoulder servo block
- Link 2: Upper arm (purple)
- Link 3: Forearm (light blueish green)
- Link 4: Wrist pitch link (green)
- Link 5: Roll body with offset fin (light blue)
- Link 6: Tool mount and end effector
- Purpose: Defines visual materials/colors for RViz visualization
- Materials: gray, purple, light_blueish_green, green, light_blue, tool_silver, marker_red
- Purpose: Semantic Robot Description Format - extends URDF with MoveIt-specific information
- Key Sections:
- Groups: Defines planning groups (e.g.,
gem_cuttergroup includes all arm links/joints) - Group States: Named poses (home, pose1, pose2)
- End Effector: Defines
ee_toolas end effector - Virtual Joint: Connects robot to world frame
- Disabled Collisions: Optimizes collision checking by disabling unnecessary checks
- Groups: Defines planning groups (e.g.,
- Purpose: Configures the kinematics solver
- Configuration:
gem_cutter: kinematics_solver: kdl_kinematics_plugin/KDLKinematicsPlugin kinematics_solver_search_resolution: 0.005 kinematics_solver_timeout: 0.005
- Solver: KDL (Kinematics and Dynamics Library) - see Kinematics Solver section
- Purpose: Defines velocity and acceleration limits for each joint
- Key Parameters:
default_velocity_scaling_factor: 0.5 (50% of max velocity)default_acceleration_scaling_factor: 0.5 (50% of max acceleration)- Per-joint limits for safety and realistic motion
- Purpose: Configures MoveIt's controller manager
- Controller:
gem_cutter_controller(FollowJointTrajectory action)
- Purpose: ROS2 controller configuration for ros2_control
- Controller Type:
joint_trajectory_controller/JointTrajectoryController - Update Rate: 100 Hz
- Interfaces: Position command, position/velocity state
- Purpose: Defines ros2_control hardware interface
- Hardware Plugin:
mock_components/GenericSystem(for simulation/testing) - Joints: All 6 joints with position command and position/velocity state interfaces
- Purpose: Main demo launch file - starts MoveIt with RViz
- What it launches:
- MoveIt move_group node
- Robot State Publisher
- RViz with MoveIt plugin
- Scene spawner (adds collision objects after 2 seconds)
- Purpose: Launches MoveIt Setup Assistant GUI for reconfiguring MoveIt
- Usage: See Running Major Commands
- Purpose: Integrates Gazebo simulation with MoveIt
- What it launches:
- Gazebo simulation
- Robot State Publisher
- MoveIt move_group
- RViz with MoveIt plugin
- Clock bridge (Gazebo → ROS2)
Before using MoveIt Setup Assistant, you need to generate a plain URDF file:
# Source workspace
source ~/development/ros/gem_cutter_manipulator/install/setup.bash
# Generate URDF
ros2 run xacro xacro \
$(ros2 pkg prefix gem_cutter_description)/share/gem_cutter_description/urdf/gem_cutter_arm.urdf.xacro \
> /tmp/gem_cutter_arm.urdfPurpose: MoveIt Setup Assistant requires a plain URDF file (not XACRO). This command processes the XACRO file and outputs a complete URDF.
# Source workspace
source ~/development/ros/gem_cutter_manipulator/install/setup.bash
# Launch Setup Assistant
ros2 launch gem_cutter_moveit_config setup_assistant.launch.pyPurpose: Opens the MoveIt Setup Assistant GUI for:
- Reconfiguring planning groups
- Adjusting collision checking
- Setting up end effectors
- Configuring kinematics solvers
- Defining group states (named poses)
Note: The configuration is already set up, but you can use this to modify it.
Figure 2: MoveIt Setup Assistant GUI showing the gem_cutter planning group configuration
cd ~/development/ros/gem_cutter_manipulator
./rebuild.shPurpose: Clean rebuild of the entire workspace. Use this after:
- Modifying URDF files
- Changing MoveIt configuration
- Adding new packages
# Source workspace
source ~/development/ros/gem_cutter_manipulator/install/setup.bash
# Launch demo
ros2 launch gem_cutter_moveit_config demo.launch.pyWhat happens:
- Starts MoveIt move_group node
- Launches RViz with MoveIt plugin
- After 2 seconds, spawns scene objects (ground plane, gem stand, gem)
- You can interactively plan and execute motions
In RViz, you can:
- Use "Planning" tab to plan motions
- Use "Motion Planning" plugin to drag end effector
- Execute planned trajectories
- View collision objects
Figure 4: ROS2 node graph showing the communication structure between nodes when running the MoveIt demo
source ~/development/ros/gem_cutter_manipulator/install/setup.bash
ros2 launch gem_cutter_description display.launch.pyPurpose: Simple visualization with joint_state_publisher_gui for manual joint control.
source ~/development/ros/gem_cutter_manipulator/install/setup.bash
ros2 launch gem_cutter_gazebo sim_with_moveit.launch.pyPurpose: Runs Gazebo simulation integrated with MoveIt for realistic physics simulation.
Figure 3: Gem cutter manipulator in Gazebo simulation environment
source ~/development/ros/gem_cutter_manipulator/install/setup.bash
ros2 launch gem_cutter_gazebo sim.launch.pyPurpose: Basic Gazebo simulation without MoveIt integration.
Figure 5: Physical assembly showing the Raspberry Pi controller, power supply, and the 5-DOF manipulator arm.
The robot is defined using URDF (Unified Robot Description Format) with XACRO macros for parameterization.
| Joint | Name | Type | Axis | Limits (rad) | Effort | Velocity |
|---|---|---|---|---|---|---|
| J1 | joint1_base_yaw |
Revolute | Z (0,0,1) | ±π | 2.0 N⋅m | 2.0 rad/s |
| J2 | joint2_shoulder_pitch |
Revolute | Y (0,1,0) | -1.25 to 1.35 | 2.0 N⋅m | 2.0 rad/s |
| J3 | joint3_elbow_pitch |
Revolute | Y (0,1,0) | ±2.10 | 2.0 N⋅m | 2.0 rad/s |
| J4 | joint4_wrist_pitch |
Revolute | Y (0,1,0) | ±1.70 | 1.5 N⋅m | 2.5 rad/s |
| J5 | joint5_wrist_roll |
Revolute | X (1,0,0) | ±π | 1.0 N⋅m | 4.0 rad/s |
| J6 | joint6_tool_yaw |
Revolute | Z (0,0,1) | ±π | 0.8 N⋅m | 4.0 rad/s |
base_link
└── joint1_base_yaw (Z-axis rotation)
└── link1_pedestal
└── joint2_shoulder_pitch (Y-axis rotation)
└── link2_upper_arm
└── joint3_elbow_pitch (Y-axis rotation)
└── link3_forearm
└── joint4_wrist_pitch (Y-axis rotation)
└── link4_wrist_pitch_link
└── joint5_wrist_roll (X-axis rotation)
└── link5_roll_body
└── joint6_tool_yaw (Z-axis rotation)
└── tool_mount
└── ee_fixed (fixed joint)
└── ee_tool (end effector)
The robot follows REP-103 convention:
- X: Forward
- Y: Left
- Z: Up
Each link includes:
- Inertial properties: Mass, center of mass, inertia tensor
- Visual geometry: For visualization in RViz/Gazebo
- Collision geometry: For collision checking (can be simplified)
- Base Plate: 9cm × 8.4cm rectangular base
- Pedestal: Cylindrical pedestal with shoulder servo block
- Upper Arm: 11cm long link (purple)
- Forearm: 10cm long link (light blueish green)
- Wrist: Compact wrist assembly with pitch and roll
- End Effector: Fixed tool (cutter/screwdriver style) ~3.3cm long
MoveIt is a motion planning framework for ROS that provides:
- Motion Planning: Path planning algorithms (OMPL planners)
- Kinematics: Forward/inverse kinematics solvers
- Collision Checking: Self-collision and environment collision detection
- Trajectory Execution: Controller integration for executing planned paths
- Visualization: RViz integration for interactive planning
The gem_cutter planning group includes:
- All 7 links (base_link through ee_tool)
- All 6 revolute joints
- Virtual joint connecting to world frame
- Name:
ee_tool - Parent Link:
tool_mount - Planning Group:
gem_cutter
- Name:
virtual_joint - Type: Fixed
- Parent Frame:
world - Child Link:
base_link
This connects the robot to a fixed world frame, allowing MoveIt to plan motions relative to the world.
MoveIt disables collision checking between:
- Adjacent links (always in contact)
- Links that never collide (optimization)
- Example:
ee_toolandlink3_forearm(never collide)
Predefined poses:
- home: All joints at 0
- pose1: Extended pose
- pose2: Different extended pose with rotation
MoveIt uses OMPL (Open Motion Planning Library) planners:
- Default Planner: RRTConnect
- Planning Time: Configurable (default ~5 seconds)
- Planning Attempts: Multiple attempts if first fails
MoveIt communicates with controllers via:
- Action Interface:
FollowJointTrajectoryaction - Controller:
gem_cutter_controller - Trajectory Execution: Monitors execution and handles errors
KDL (Kinematics and Dynamics Library) is a C++ library that provides:
- Forward kinematics (joint angles → end effector pose)
- Inverse kinematics (end effector pose → joint angles)
- Jacobian computation
- Dynamics computations
MoveIt uses kdl_kinematics_plugin/KDLKinematicsPlugin which:
- Implements MoveIt's kinematics plugin interface
- Uses KDL's numerical inverse kinematics solver
- Supports 6-DOF manipulators (like this robot)
gem_cutter:
kinematics_solver: kdl_kinematics_plugin/KDLKinematicsPlugin
kinematics_solver_search_resolution: 0.005
kinematics_solver_timeout: 0.005Parameters:
kinematics_solver: Plugin namekinematics_solver_search_resolution: 0.005 rad (~0.29°) - discretization for IK searchkinematics_solver_timeout: 0.005 seconds - timeout per IK attempt
- Numerical Method: Uses iterative numerical optimization (not analytical)
- Seed State: Requires initial joint configuration (seed)
- Search: Explores joint space around seed to find solution
- Resolution: Smaller resolution = more accurate but slower
- Timeout: If no solution found within timeout, returns failure
- General: Works for any robot configuration
- No Closed-Form Required: Doesn't need analytical IK solution
- Well-Tested: Mature, widely-used library
- ROS Integration: Native ROS support
- Slower: Numerical methods are slower than analytical IK
- No Guarantee: May not find solution even if one exists
- Local Minima: Can get stuck in local minima
- Seed Dependent: Quality depends on seed configuration
For this 6-DOF robot, you could also use:
- TRAC-IK: Faster, more robust IK solver
- Analytical IK: If closed-form solution exists (rare for 6-DOF)
- Range: ±π radians (±180°)
- Purpose: Full rotation for workspace coverage
- Limitation: None (full rotation)
- Range: -1.25 to 1.35 radians (~-72° to +77°)
- Purpose: Prevents upper arm from hitting pedestal/base
- Limitation: Asymmetric limits prevent collision with base structure
- Range: ±2.10 radians (±120°)
- Purpose: Allows large fold/unfold motions
- Limitation: Prevents extreme back-bending that could cause self-collision
- Range: ±1.70 radians (±97°)
- Purpose: Tool orientation control
- Limitation: Prevents tool from colliding with forearm
- Range: ±π radians (±180°)
- Purpose: Tool roll orientation
- Limitation: None (full rotation)
- Range: ±π radians (±180°)
- Purpose: Final tool orientation
- Limitation: None (full rotation)
Each joint includes dynamics:
- Damping: Friction-like resistance (0.05-0.25)
- Friction: Static friction (0.05-0.10)
Higher damping/friction values make motion more realistic but require more effort.
Reach: Approximately 0.25-0.30 meters from base
- Base to shoulder: ~0.065 m
- Upper arm: 0.11 m
- Forearm: 0.10 m
- Wrist + tool: ~0.07 m
- Total: ~0.35 m theoretical, ~0.25-0.30 m practical
Workspace Shape: Spherical shell (due to J1 full rotation)
Total robot mass: ~1.22 kg
- Base: 0.35 kg
- Link 1: 0.25 kg
- Link 2: 0.22 kg
- Link 3: 0.18 kg
- Link 4: 0.10 kg
- Link 5: 0.09 kg
- Tool mount: 0.03 kg
- End effector: 0.05 kg
Each link includes inertia tensor (6 values: Ixx, Iyy, Izz, Ixy, Ixz, Iyz):
- Base: Largest inertia (0.0008 Izz)
- Upper arm: Significant inertia (0.00045 Iyy, Izz)
- End effector: Smallest inertia (0.000005)
These values affect:
- Motion dynamics
- Torque requirements
- Collision response
# Terminal 1: Launch visualization
source install/setup.bash
ros2 launch gem_cutter_description display.launch.py
# In RViz:
# - Use joint_state_publisher_gui to move joints
# - Robot model updates in real-timeThe visualization shows the robot model with all 6 joints controllable via the joint_state_publisher_gui (see Figure 1 above).
# Terminal 1: Launch MoveIt demo
source install/setup.bash
ros2 launch gem_cutter_moveit_config demo.launch.py
# In RViz Motion Planning plugin:
# 1. Click "Planning" tab
# 2. Select "gem_cutter" planning group
# 3. Drag end effector to desired pose
# 4. Click "Plan" button
# 5. Review planned path (green line)
# 6. Click "Execute" to execute trajectory# After launching demo.launch.py
# In RViz Motion Planning plugin:
# 1. Go to "Planning" tab
# 2. Select "gem_cutter" group
# 3. Under "Query" section, select named state:
# - "home" (all zeros)
# - "pose1" (extended pose)
# - "pose2" (rotated extended pose)
# 4. Click "Plan and Execute"Create a Python script to plan motions programmatically:
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from moveit_msgs.msg import MoveItErrorCodes
from moveit_msgs.srv import GetMotionPlan
from geometry_msgs.msg import Pose
class MoveItPlanner(Node):
def __init__(self):
super().__init__('moveit_planner')
self.plan_client = self.create_client(
GetMotionPlan,
'/plan_kinematic_path'
)
def plan_to_pose(self, target_pose: Pose):
# Create planning request
request = GetMotionPlan.Request()
request.motion_plan_request.group_name = "gem_cutter"
request.motion_plan_request.num_planning_attempts = 10
request.motion_plan_request.allowed_planning_time = 5.0
# Set target pose
request.motion_plan_request.goal_constraints[0].position_constraints[0].constraint_region.primitive_poses[0] = target_pose
# Send request
future = self.plan_client.call_async(request)
rclpy.spin_until_future_complete(self, future)
return future.result()
# Usage
if __name__ == '__main__':
rclpy.init()
planner = MoveItPlanner()
# ... create target pose ...
result = planner.plan_to_pose(target_pose)
rclpy.shutdown()# Terminal 1: Launch Gazebo + MoveIt
source install/setup.bash
ros2 launch gem_cutter_gazebo sim_with_moveit.launch.py
# This launches:
# - Gazebo with physics simulation
# - Robot model in Gazebo
# - MoveIt planning
# - RViz visualization
# You can now plan motions that respect physics!The Gazebo simulation provides realistic physics-based motion (see Figure 3 above).
Solution:
# Make sure workspace is sourced
source install/setup.bash
# Verify robot description is available
ros2 param get /robot_state_publisher robot_descriptionPossible causes:
- Target pose unreachable
- Collision with environment
- Self-collision
- IK solver timeout too short
Solutions:
- Check target pose is within workspace
- Increase
kinematics_solver_timeoutinkinematics.yaml - Increase planning time in RViz
- Check collision objects in scene
Solution:
# Check if controllers are loaded
ros2 control list_controllers
# If not, spawn them manually
ros2 launch gem_cutter_moveit_config spawn_controllers.launch.pySolution:
- Ensure
ros2_controlis properly configured - Check controller manager is running
- Verify joint state publisher is publishing
- MoveIt Documentation
- ROS2 Documentation
- URDF Tutorial
- MoveIt Setup Assistant Guide
- KDL Documentation
gem_cutter_description: Apache-2.0gem_cutter_gazebo: Apache-2.0gem_cutter_moveit_config: BSD-3-Clause
Nihara Randini (shniharard@gmail.com)
- Workspace: Current
- MoveIt Config: 0.3.0
- ROS2: Jazzy Jalisco