ROS 2 in Depth
Installing ROS 2 and the CLI
Three ways to get a working ROS 2 onto your machine, what sourcing the setup script really does, and the command-line tools you will use every day.
intermediate ยท 13 min read
Lesson content
There are three sensible ways to get ROS 2, and which one is right depends on whether you are learning, developing or shipping.
All three end in the same place: a shell where typing ros2 does something, with the distribution's packages on your path.
That phrase matters more than it looks. ROS 2 is not installed into a machine the way a normal program is. It is switched on inside one shell, by one line, and the rest of this lesson turns on understanding that line.
| apt packages | Docker | From source | |
|---|---|---|---|
| Setup effort | Low | Low | High |
| Needs the matching Ubuntu | Yes | No | No |
| Isolated from the host | No | Yes | Partly |
| Reproducible | Mostly | Exactly | If you pin |
| Can modify ROS itself | No | No | Yes |
| Best for | Learning, day-to-day development | CI, deployment, other distributions | Core development, unsupported platforms |
Setup effort
- apt packages
- Low
- Docker
- Low
- From source
- High
Needs the matching Ubuntu
- apt packages
- Yes
- Docker
- No
- From source
- No
Isolated from the host
- apt packages
- No
- Docker
- Yes
- From source
- Partly
Reproducible
- apt packages
- Mostly
- Docker
- Exactly
- From source
- If you pin
Can modify ROS itself
- apt packages
- No
- Docker
- No
- From source
- Yes
Best for
- apt packages
- Learning, day-to-day development
- Docker
- CI, deployment, other distributions
- From source
- Core development, unsupported platforms
# --- Ubuntu: install from packages ---sudo apt update && sudo apt install -y locales curl gnupg lsb-release# add the ROS 2 apt repository and key (see docs.ros.org for the current URL)sudo apt updatesudo apt install -y ros-jazzy-desktop # desktop = ROS + RViz + demossudo apt install -y ros-dev-tools # colcon, rosdep, vcstool# --- Make it available in this shell ---source /opt/ros/jazzy/setup.bash# --- Check it works ---ros2 doctor --report | head -20ros2 run demo_nodes_cpp talker # in one terminalros2 run demo_nodes_py listener # in anothersudo apt install -y ros-jazzy-desktop # desktop = ROS + RViz + demos-desktop includes RViz and the demos; -ros-base is the headless subset for a robot.
source /opt/ros/jazzy/setup.bashThis is the line everything depends on. Nothing ROS works in a shell that has not sourced it.
ros2 run demo_nodes_cpp talker # in one terminal
ros2 run demo_nodes_py listener # in anotherIf talker and listener see each other, your installation and your networking are both fine.
What does sourcing the setup script actually do?
It edits the current shell's environment. Four variables, four jobs.
PATH gains the ROS executables, which is what makes ros2 resolve at all.PYTHONPATH gains the Python packages, so import rclpy works.LD_LIBRARY_PATH gains the shared libraries the executables link against.AMENT_PREFIX_PATH tells ROS where to find package resources.
Nothing outside that shell changed. No service started, no file was written. Close the terminal and the effect is gone.
That is why every new terminal needs it again, and why almost everyone eventually puts the line in .bashrc.
Doing so is fine while you are learning, and a mild trap later. The moment you work with two distributions or two workspaces, an automatic source in .bashrc will quietly hand you the wrong one.
Plenty of developers keep a shell alias per environment instead, so choosing is always deliberate.
Once ROS is on your path, almost all interaction goes through one command. ros2 is a tree of sub-commands, one per concept, and learning it is the fastest route to being productive.
| Command | What it does | Most-used form |
|---|---|---|
| ros2 node | Inspect running nodes | ros2 node list, ros2 node info /x |
| ros2 topic | Inspect and interact with topics | list, echo, hz, info --verbose, pub |
| ros2 service | Inspect and call services | list, call |
| ros2 action | Inspect and send action goals | list, send_goal --feedback |
| ros2 param | Read, set and dump parameters | list, get, set, dump |
| ros2 interface | Show message, service and action definitions | show, list |
| ros2 run | Run one executable from a package | ros2 run pkg exe |
| ros2 launch | Start a launch file | ros2 launch pkg file.launch.py |
| ros2 bag | Record and replay message traffic | record -a, play file |
| ros2 pkg | Create and inspect packages | create, list, prefix |
| ros2 doctor | Check the installation and network | ros2 doctor --report |
Example
The five commands that solve most problems
ros2 node list asks whether the node you expect is running at all.ros2 topic list asks whether the topic even exists.ros2 topic hz /x asks whether anything is publishing to it.ros2 topic echo /x asks whether the values look sensible.ros2 topic info /x --verbose asks whether both sides agree on QoS.
Each one rules out a whole class of cause, which is why the order matters. There is no point checking values on a topic nobody publishes to.
Run in sequence, these five pin down the great majority of "it isn't working" reports. Reach for them before you open any code.
A handful of environment variables shape how ROS 2 behaves on the network, and setting them deliberately prevents a whole category of confusing problems.
# Partition the network. Nodes only discover others in the same domain.export ROS_DOMAIN_ID=42# Keep everything on this machine (useful while developing on a shared LAN).export ROS_LOCALHOST_ONLY=1# Choose a DDS vendor. Worth trying both if performance is poor.export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp# Make log output readable.export RCUTILS_COLORIZED_OUTPUT=1export RCUTILS_CONSOLE_OUTPUT_FORMAT='[{severity}] [{name}]: {message}'export ROS_DOMAIN_ID=42Set this per robot and per developer. Two people on the default domain will see each other's robots, and can command them.
export ROS_LOCALHOST_ONLY=1The quickest fix when you do not want your laptop appearing on a colleague's graph.
Two distributions in one shell will not work
Source both Humble and Jazzy in the same terminal and you get a broken environment.
Paths from both. Libraries that do not match each other. And errors that make no sense at all.
The same happens if you source a workspace built against one distribution while another one is active.
The rule is simple: one distribution per shell.
If you need several, use Docker containers, or separate terminals with explicit aliases. Never try to switch in place.
For deployment and CI, Docker is usually the right answer. The official images are ros:jazzy (base) and osrf/ros:jazzy-desktop (with GUI tools), and the one thing to get right is networking.
# Host networking so DDS discovery works between the container and the hostdocker run -it --rm --network host \ -e ROS_DOMAIN_ID=42 \ -v $(pwd):/ws \ osrf/ros:jazzy-desktop bash# For GUI tools (RViz) from inside a container, on X11:xhost +local:dockerdocker run -it --rm --network host \ -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \ osrf/ros:jazzy-desktop rviz2docker run -it --rm --network host \--network host is essentially required. Docker's default bridge blocks the multicast that DDS discovery relies on.
Forgetting to source the setup script in a new terminal.
ros2: command not found almost always means this. Source the distribution, then your workspace's install/setup.bash.
Running Docker with default bridge networking.
Discovery multicast does not cross it, so nodes never find each other and nothing reports an error. Use --network host.
Leaving ROS_DOMAIN_ID unset on a shared network.
Everyone on the default domain sees everyone else. Assign one per robot. The failure mode here is another machine acting on your commands.
Key takeaway
- apt for learning and development, Docker for CI and deployment, source only when you must modify ROS itself.
- Sourcing the setup script edits the current shell's environment, so every new terminal needs it again.
- The ros2 CLI is a tree of sub-commands; five of them localise most problems.
- Set ROS_DOMAIN_ID per robot, and use --network host for Docker.
- Never source two distributions in one shell.
Finished this lesson?
Guest progress is saved on this device.