How to install ROS2 Jazzy and MoveIt2 to control a Universal Robots cobot

Based on contributions by aron.

Controlling a Universal Robots cobot through ROS2 and MoveIt2 has a reputation for being difficult, mostly because the official documentation is spread across several sites. This guide condenses the setup into one path: installing ROS2 Jazzy on Ubuntu 24.04, installing the UR ROS2 driver, connecting to a real or simulated robot, and planning motions from the command line, C++, or Python.

What you need

  • A PC (or VM) running Ubuntu 24.04 LTS. ROS2 runs best directly on Linux.
  • A Universal Robots cobot on the CB3 or e-Series controller (this guide uses a UR5e as the example), or URSim if you don’t have access to a physical robot.
  • Docker, only if you plan to run URSim instead of a physical robot.
  • Root/sudo access on the machine you install ROS2 on.

Three ways to get Ubuntu 24.04 with ROS2:

  • Pre-built VM or Docker image: fastest to start, slower performance. Good for a single tutorial session.
  • Ubuntu 24.04 in a VM: more flexible, still slower than native. Good for experimenting with ROS2 more extensively.
  • Ubuntu 24.04 installed natively (dual-boot next to, or instead of, Windows): best performance, recommended for serious project work.

There are plenty of tutorials elsewhere for installing Ubuntu in any of these ways — pick whichever fits your situation.

Steps

1. Install ROS2 Jazzy

These steps follow the official ROS2 deb installation instructions, trimmed to what you need for this setup.

1.1 Make sure you have UTF-8 locale support. Some minimal Ubuntu installs don’t have it. Check with locale; if it’s missing, run:

sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

1.2 Enable Ubuntu’s Universe repository (ROS2 depends on it) and add the ROS2 apt source:

sudo apt install software-properties-common
sudo add-apt-repository universe

sudo apt update && sudo apt install curl -y
export ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F'"' '{print $4}')
curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}})_all.deb"
sudo dpkg -i /tmp/ros2-apt-source.deb

1.3 Update your system so there are no mismatched dependencies:

sudo apt update && sudo apt upgrade

1.4 Install ROS2 and the ros2_control tools:

sudo apt install ros-jazzy-desktop ros-dev-tools ros-jazzy-ros2-control ros-jazzy-ros2-controllers

This installs around 1163 packages on a freshly installed system, so it can take a while.

Tip: you can add ros-jazzy-ur (the UR driver, ~60 more packages) to this same apt install command so everything installs in one go while you walk away.

2. Install the Universal Robots ROS2 driver

The driver for UR cobots is packaged in the ROS2 repositories as ros-jazzy-ur. You can also build it from source — see the official installation docs — but the apt package is the quickest route:

sudo apt install ros-jazzy-ur

3. Prepare the robot

To let ROS2 move the robot, the teach pendant needs a program running that opens a reverse connection to your PC (called “external control”). This program lives in a URCap that you install on the robot controller.

Follow the official URCap installation instructions, which also list the required settings. For a CB3-series robot, the finished program should look like this:

No physical robot? Use URSim, UR’s Docker-based simulator, which runs the teaching pendant on your PC. A helper script spins up a URSim instance with the external control URCap already enabled, so you only need to create the program on the simulated pendant:

ros2 run ur_client_library start_ursim.sh -m ur5e

Install Docker first using the official Ubuntu instructions.

4. Start the driver and MoveIt

4.1 Launch the robot driver — this opens the communication link with the robot (real or simulated):

source /opt/ros/jazzy/setup.bash
ros2 launch ur_robot_driver ur_control.launch.py ur_type:=ur5e robot_ip:=192.168.56.101 launch_rviz:=false

Replace ur_type with your robot’s model and robot_ip with your robot’s actual IP address.

4.2 Start the external control program on the teach pendant that you prepared in step 3:

4.3 Launch MoveIt2:

ros2 launch ur_moveit_config ur_moveit.launch.py ur_type:=ur5e launch_rviz:=true

Programmatic control of the robot

Once MoveIt2 is running, you can plan and execute motions from your own C++ or Python program instead of the RViz GUI.

C++

Most MoveIt2 examples are written in C++. Follow the official Your First C++ MoveIt Project tutorial, with these changes for a UR robot instead of the tutorial’s Panda arm:

  • You don’t need a full ROS2 workspace yet — just a folder containing a src folder. The location doesn’t matter; this example uses a projects folder:
    mkdir -p ~/projects/ur_moveit_tutorial_workspace/src
    cd ~/projects/ur_moveit_tutorial_workspace/src
    # then continue with the commands from "Your First C++ MoveIt Project"
    ros2 pkg create \
      --build-type ament_cmake \
      --dependencies moveit_ros_planning_interface rclcpp \
      --node-name hello_moveit hello_moveit
    
  • The move group is not called "manipulator" — use "ur_manipulator".
  • When configuring MoveItVisualTools, the frame "base_link" doesn’t exist for the UR MoveIt config — use "world" instead.

Python

The Python API only exposes a subset of the C++ MoveIt API, but it doesn’t require a colcon workspace, which makes it convenient for quick prototyping in a Python shell (e.g. ipython).

Install the MoveIt Python bindings and dependencies:

sudo apt install ros-jazzy-moveit-py
pip install numpy pyyaml lark packaging

Create a moveit_cpp.yaml file and note its full path — you’ll need it below:

planning_pipelines:
  pipeline_names: ["ompl"]

plan_request_params:
  planning_attempts: 3
  planning_pipeline: ompl
  max_velocity_scaling_factor: 1.0
  max_acceleration_scaling_factor: 1.0

Use the following helper function to build the MoveIt interface:

def create_ur_moveit_node(robot_model: str, moveit_cpp_path: str, node_name="ur"):
    from pathlib import Path
    from moveit_configs_utils import MoveItConfigsBuilder

    moveit_config = (
        MoveItConfigsBuilder(robot_name="ur", package_name="ur_moveit_config")
        .robot_description_semantic(Path("srdf") / "ur.srdf.xacro", {"name": robot_model})
        .trajectory_execution(file_path="config/moveit_controllers.yaml")
        .moveit_cpp(moveit_cpp_path)
        .to_moveit_configs()
    ).to_dict()

    from moveit.planning import MoveItPy
    return MoveItPy(node_name=node_name, config_dict=moveit_config)

Moving the robot is then a few lines:

robot = create_ur_moveit_node("ur5e", "/home/user/moveit_cpp.yaml")

planner = robot.get_planning_component("ur_manipulator")
planner.set_goal_state("home")
res = planner.plan()
robot.execute(res.trajectory, controllers=[])

MoveIt2 ships two example scripts that show what set_goal_state accepts, and how to add collision objects that MoveIt will plan around.

Handy links

Troubleshooting / Common mistakes

  • Move group name: the UR MoveIt config uses "ur_manipulator", not "manipulator" as in the generic MoveIt tutorials.
  • Reference frame: use "world", not "base_link", when the tutorial asks for a base frame (e.g. for MoveItVisualTools).
  • Robot not moving: the driver (step 4.1) must be running and the external control program on the pendant must be started (step 4.2) before MoveIt can send trajectories.
  • :warning: Check: in the Python example, the path passed to create_ur_moveit_node should be the full path to the moveit_cpp.yaml file created earlier. The source example used an unrelated test path here — make sure you pass the actual path to your own moveit_cpp.yaml.

Related


Rewritten and consolidated (Sept 2026) from the original student how-to’s: How to install and control a Universal Robot cobot using ros2 and moveit.