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 sameapt installcommand 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 ur5eInstall 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
srcfolder. The location doesn’t matter; this example uses aprojectsfolder: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
- Sending and automatically executing URScript
- UR ROS2 controllers reference — lists controllers for reading/writing GPIO pins and explains
ScaledJointTrajectoryController, the controller MoveIt uses. Some general ROS2 knowledge is assumed.
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. forMoveItVisualTools). - 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.
Check: in the Python example, the path passed to create_ur_moveit_nodeshould be the full path to themoveit_cpp.yamlfile created earlier. The source example used an unrelated test path here — make sure you pass the actual path to your ownmoveit_cpp.yaml.
Related
- How to install ROS2 Humble and program a Doosan cobot in Python — installing ROS2 and controlling a Doosan cobot instead.
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.

