ROS 2 releases a new distribution every year, and support windows, package availability, and tooling change
with every release. Everything version-specific below (release dates, EOL dates, Ubuntu pairings, Gazebo
pairings) was checked against Open Robotics' own release documentation and announcements at the time this
book was written. A few narrower technical details โ most notably the exact default RMW implementation and
the precise C++/Python baseline shipped with Lyrical โ could not be confirmed against a primary,
directly-fetchable source at writing time and are marked "not confirmed here โ check
docs.ros.org" instead of being guessed. Before you build a production system on any
fact in this appendix, re-check it against docs.ros.org for your exact
distribution, since this information ages the moment a new release ships.
A ROS 2 distribution (or "distro") is a versioned, tested collection of compatible ROS 2
packages โ rclcpp, rclpy, colcon, rviz2, tf2,
rosbag2, and thousands of community packages โ that are all built, released, and supported
together against a specific set of operating systems, compilers, and dependency versions.
ROS 2
โ
โโโ Humble Hawksbill (LTS)
โโโ Jazzy Jalisco (LTS)
โโโ Kilted Kaiju (non-LTS)
โโโ Lyrical Luth (LTS)
โโโ Rolling Ridley (continuous development)
ROS 2 itself is not an operating system โ it runs on top of one (mainly Linux, with Tier 1 or Tier 2 support for Windows and, on some releases, macOS). A distribution exists for the same reason a Linux distribution exists: dozens of interdependent packages need to be built, tested, and shipped together against one specific set of library versions, or nothing is guaranteed to work with anything else.
Distributions solve five concrete engineering problems:
rclcpp API should keep compiling on every Jazzy patch release.Think of a ROS 2 distribution the same way you think of an Ubuntu release: not a single program, but a coordinated, tested snapshot of an entire ecosystem, frozen at a point in time and supported for a known window.
Every ROS 2 distribution is codenamed alphabetically, and (since Foxy) released once a year in May.
| Distribution | Released | LTS? | Support ends | Ubuntu | Recommended today? |
|---|---|---|---|---|---|
| Ardent Apalone | Dec 2017 | No | Dec 2018 | 16.04 | โ EOL |
| Bouncy Bolson | Jun 2018 | No | Jun 2019 | 18.04 | โ EOL |
| Crystal Clemmys | Dec 2018 | No | Dec 2019 | 18.04 | โ EOL |
| Dashing Diademata | May 2019 | Yes | May 2021 | 18.04 | โ EOL |
| Eloquent Elusor | Nov 2019 | No | Nov 2020 | 18.04 | โ EOL |
| Foxy Fitzroy | May 2020 | Yes | May 2023 | 20.04 | โ EOL |
| Galactic Geochelone | May 2021 | No | Nov 2022 | 20.04 | โ EOL |
| Humble Hawksbill | May 2022 | Yes | May 2027 | 22.04 | โ ๏ธ Legacy-compatible only |
| Iron Irwini | May 2023 | No | Nov 2024 | 22.04 | โ EOL |
| Jazzy Jalisco | May 2024 | Yes | May 2029 | 24.04 | โ Still fully supported |
| Kilted Kaiju | May 2025 | No | Nov 2026 | 24.04 | โ ๏ธ Near end of support |
| Lyrical Luth | May 2026 | Yes | May 2031 | 26.04 | โ Recommended for new work |
| Rolling Ridley | Continuous | N/A | Ongoing | tracks newest Ubuntu | Dev/maintainers only |
Do not start a new production system on an EOL distribution (anything above Iron in this table) unless you have a specific legacy dependency you cannot yet move off of. EOL means no security patches, no bug fixes, and packages that will progressively stop building against current Ubuntu images.
LTS (Long Term Support) distributions โ Humble, Jazzy, and Lyrical โ get roughly five years of patches and security fixes. Non-LTS distributions like Iron and Kilted get about a year and a half, and exist mainly to ship new capabilities faster between LTS releases.
Humble โ LTS (5 years)
Jazzy โ LTS (5 years)
Kilted โ non-LTS (~18 months)
Lyrical โ LTS (5 years)
Robotics teams care about LTS releases specifically because of:
A production robot shipped on Jazzy in 2025 does not need to move to Lyrical the day it releases. Jazzy is supported until May 2029 โ the right question is not "is there a newer LTS?" but "does staying on Jazzy still meet my hardware, driver, and security requirements?"
Rolling Ridley is structurally different from every other entry in the table above: it is not a fixed, dated release โ it is a continuously updated development line that tracks the newest Ubuntu and the latest package versions as maintainers merge them.
Stable distribution (Jazzy, Lyrical, ...)
โ
fixed release, fixed lifecycle
โ
predictable, frozen APIs
Rolling Ridley
โ
continuously updated
โ
newest features, but breaking changes can land at any time
Rolling exists for package maintainers and Open Robotics itself: every future stable release (the next Lyrical-successor) is branched from Rolling at release time. It is where new features land first and get shaken out before being frozen into a named distribution.
Use it if you maintain a package and need to keep it building against upcoming ROS 2 changes, or you need a feature that hasn't shipped in a stable distro yet and you accept the risk.
Don't use it for a production robot, a classroom, or any project where "it worked yesterday" needs to still be true tomorrow.
Rather than a vague "newer is better," here is what actually changed release to release, limited to points that are officially documented:
| Area | Humble | Jazzy | Kilted | Lyrical |
|---|---|---|---|---|
| Ubuntu | 22.04 | 24.04 | 24.04 | 26.04 |
| LTS | Yes | Yes | No | Yes |
| Paired Gazebo | Gazebo Classic / Fortress | Gazebo Harmonic | Gazebo Ionic | Gazebo Jetty |
| Middleware options | Fast DDS, Cyclone DDS, Connext | Fast DDS, Cyclone DDS, Connext | + Eclipse Zenoh (Tier 1) | Fast DDS, Cyclone DDS, Connext, Zenoh |
| Python executor perf. | baseline | baseline | C++ Events Executor ported to rclpy | New EventsCBGExecutor (callback-group events) |
| Async Python support | โ | โ | โ | rclpy AsyncNode (native asyncio) |
| rosbag2 | baseline | baseline | multi-bag simultaneous playback, interactive progress bar | remote recording control via services |
Distro-by-distro changes to QoS defaults, the launch system's internals, and colcon/ament internals were
not confirmed against a primary source while writing this appendix, so they are deliberately left out
here rather than guessed. Check the "Migration" page of each release on docs.ros.org for the
authoritative, exhaustive list before relying on a specific behavioral change.
Lyrical Luth is the 12th official ROS 2 distribution, released in May 2026, and is an LTS release supported until roughly May 2031. It follows Kilted Kaiju (non-LTS) and, like Jazzy before it, pairs with the current Ubuntu LTS โ Ubuntu 26.04.
Release: May 2026 ยท LTS: Yes, until ~May 2031
Tier 1 platform: Ubuntu 26.04 (amd64, arm64), Windows 11 / VS2022 (amd64)
Tier 2: RHEL 10 (amd64)
Tier 3: Ubuntu 24.04 (Noble), Debian Trixie, macOS, OpenEmbedded
Default RMW / default Python-C++ baseline: not confirmed here โ verify against docs.ros.org/en/lyrical for your build before depending on it.
Changes that are specifically attributable to Lyrical (not inherited from Kilted or earlier):
rclpy AsyncNode โ native asyncio integration for writing ROS 2 callbacks as Python coroutines.uint8[] message fields now use a rosidl::Buffer<uint8_t> type, enabling zero-copy transfer (currently limited to rmw_fastrtps_cpp).Features that already existed in Kilted (the ported C++ Events Executor for Python, Zenoh as Tier 1 middleware, multi-bag rosbag2 playback) are not Lyrical-specific โ Lyrical inherits them. Only the items listed above are new in Lyrical itself.
For most robotics teams, Lyrical's practical significance is simpler than any single feature: it is the first LTS after Jazzy, meaning it is the release you plan a five-year deployment lifecycle around if you're starting a new robot today and Jazzy's Ubuntu 24.04 base doesn't already fit your hardware constraints.
Ubuntu
โ
โโโ 20.04 โ ROS 2 Foxy (EOL)
โโโ 22.04 โ ROS 2 Humble (LTS, supported)
โโโ 24.04 โ ROS 2 Jazzy / Kilted
โโโ 26.04 โ ROS 2 Lyrical (LTS, current)
Each ROS 2 distro binds to one primary Ubuntu LTS because the ROS packages are built against that Ubuntu
release's exact GCC, CMake, Python, and system-library versions. Installing "the wrong" ROS distro's .deb
packages on a mismatched Ubuntu version will fail to resolve dependencies โ it is not a supported
combination even where it might technically be coerced to work with a source build.
| Support tier | Meaning |
|---|---|
| Tier 1 | Official binary packages, full CI testing, guaranteed to work |
| Tier 2 | Built and tested, but with a narrower guarantee (e.g. fewer supported package combinations) |
| Tier 3 | Community-maintained or best-effort; may require building from source |
| Unsupported | Technically possible (source build, container tricks) but not validated by upstream |
Ubuntu compatibility cascades into everything downstream: the Python interpreter version, the GCC/CMake toolchain, system libraries like Boost and OpenSSL, the DDS implementation packages, and โ critically for robotics โ which Gazebo release is packaged and tested against your ROS distro.
lsb_release -a
uname -a
Confirm you are on the Tier 1 platform (Ubuntu 26.04, amd64 or arm64) before proceeding โ installing on a mismatched Ubuntu version is the single most common source of broken ROS 2 installs.
locale # check for UTF-8
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
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 $VERSION_CODENAME)_all.deb"
sudo apt install /tmp/ros2-apt-source.deb
This is the current (post-Humble) way ROS 2 registers its apt source โ it replaced the older manual apt-key + sources.list.d steps you may see in outdated tutorials.
sudo apt update
sudo apt upgrade
sudo apt install ros-lyrical-desktop
ros-lyrical-desktop includes RViz2, demos, and simulation-adjacent tooling on top of the core libraries โ good for a development machine. ros-lyrical-ros-base installs only the core communication libraries and CLI tools, no GUI tooling โ the right choice for a robot's onboard computer, a headless server, or a Docker image where every extra megabyte and dependency matters.
sudo apt install ros-lyrical-ros-base
source /opt/ros/lyrical/setup.bash
Sourcing this script sets the environment variables and shell functions ROS 2 needs to find packages,
executables, and message definitions. Without it, commands like ros2 won't exist in your shell
at all.
echo "source /opt/ros/lyrical/setup.bash" >> ~/.bashrc
source ~/.bashrc
Check what got set:
printenv | grep ROS
ROS_DISTRO=lyrical
ROS_VERSION=2
ROS_DOMAIN_ID=0
ROS_LOCALHOST_ONLY=0
Underlay โ /opt/ros/lyrical, the base ROS 2 install. Overlay โ your own workspace's install/setup.bash, sourced after the underlay, which layers your custom packages on top without touching the base install.
Terminal 1:
ros2 run demo_nodes_cpp talker
Terminal 2:
ros2 run demo_nodes_py listener
Talker Node
โ
โ /chatter
โผ
Listener Node
The talker publishes an incrementing string on /chatter; the listener subscribes and prints what it receives. If both terminals show matching output, your install, your DDS discovery, and your ROS_DOMAIN_ID are all working correctly together.
ros2 doctor
Meaning: Checks your ROS 2 environment, network configuration, and installation for common problems. When to use: First thing you run when "something is wrong" and you don't know what yet.
| Command | Purpose |
|---|---|
ros2 node list / ros2 node info <node> | See which nodes are running, and what each one publishes/subscribes/serves |
ros2 topic list / echo / info / hz | Inspect topics, watch live data, check publish rate |
ros2 topic pub | Manually publish a message for testing |
ros2 service list / type / call | Inspect and call ROS 2 services |
ros2 action list / info / send_goal | Inspect and trigger long-running actions |
ros2 param list / get / set | Read and change node parameters at runtime |
ros2 interface list / show | List and inspect message/service/action definitions |
ros2 pkg list / executables | List installed packages and their runnable executables |
ros2 run <pkg> <exe> | Run a single node executable |
ros2 launch <pkg> <file> | Start a whole system of nodes together |
ros2_ws/
โ
โโโ src/ โ your source packages
โโโ build/ โ intermediate build artifacts
โโโ install/ โ what you actually source
โโโ log/ โ build/test logs
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build
source install/setup.bash
| Command | When to use it |
|---|---|
colcon build | Build every package in src/ |
colcon build --symlink-install | Symlink Python/launch/config files instead of copying โ edit-and-rerun without rebuilding, essential during Python development |
colcon build --packages-select <pkg> | Build just one package |
colcon build --packages-up-to <pkg> | Build a package and everything it depends on |
colcon test / colcon test-result | Run and inspect a package's tests |
apt installs system packages. pip installs Python packages. rosdep doesn't install anything itself โ it reads each package's package.xml and figures out which apt/pip commands to run to satisfy its dependencies. colcon builds your workspace's source packages, it does not manage dependencies at all.
sudo rosdep init
rosdep update
rosdep install --from-paths src --ignore-src -r -y
# Python package
ros2 pkg create --build-type ament_python my_robot_pkg
# C++ package
ros2 pkg create --build-type ament_cmake my_robot_cpp
ament_python packages are built with setup.py/setup.cfg and pure Python; ament_cmake packages use CMakeLists.txt and compile C++ sources. A package can also mix both when it needs C++ performance-critical nodes alongside Python tooling.
ROS 2 API
โ
rclcpp / rclpy
โ
rcl
โ
RMW (ROS middleware interface)
โ
DDS implementation (Fast DDS / Cyclone DDS / Zenoh / ...)
โ
Network
The RMW layer lets ROS 2 swap DDS/middleware implementations without changing application code. Check the active one with:
echo $RMW_IMPLEMENTATION
Only change the middleware implementation for a concrete engineering reason โ e.g. Zenoh for constrained or lossy links, or a specific vendor's Connext for a certified deployment โ never as a default habit.
export ROS_DOMAIN_ID=10
Robot A, ROS_DOMAIN_ID=10 โโ
โโ can discover each other
Robot B, ROS_DOMAIN_ID=10 โโ
Robot C, ROS_DOMAIN_ID=20 โ isolated
ROS_DOMAIN_ID only partitions discovery on a shared network. It provides no authentication or encryption โ anyone on the same physical/logical network segment and domain can see and inject traffic. Real security requires DDS Security (authentication, access control, encryption) explicitly configured.
QoS (Quality of Service) exists because one policy doesn't fit every topic:
Practical workflow for "the motors aren't moving":
1. Is the navigation node alive? โ ros2 node list
2. Does /cmd_vel exist? โ ros2 topic list
3. Is /cmd_vel actually publishing? โ ros2 topic hz /cmd_vel
4. What does it contain? โ ros2 topic echo /cmd_vel
5. Is the controller subscribed? โ ros2 topic info /cmd_vel
6. Are message types compatible? โ ros2 topic info /cmd_vel --verbose
7. Are QoS profiles compatible? โ ros2 topic info /cmd_vel --verbose
Record and replay real robot data for offline debugging:
ros2 bag record /scan /odom /cmd_vel
ros2 bag play my_bag
ros2 bag info my_bag
Sensors โ Localization โ Global Planner โ Local Planner/Controller โ /cmd_vel โ Robot
Nav2 and ros2_control are both released per-distro alongside ROS 2 core and follow the same Ubuntu/ROS pairing โ install them as ros-lyrical-navigation2 and ros-lyrical-ros2-control once your apt source is configured.
Controller Manager
โ
โโโ Joint State Broadcaster
โโโ Diff Drive Controller
โโโ Other Controllers
โ
โผ
Hardware Interface
โ
โผ
Motor Drivers
Gazebo pairing follows the table in section B.5: Lyrical is packaged against Gazebo Jetty. Do not follow Gazebo Classic tutorials (gazebo_ros_pkgs) on Lyrical โ that lineage is discontinued; the current integration path is the ros_gz bridge packages.
Robot Arm โ MoveIt 2 โ Motion Planning โ ros2_control โ Joint Controllers
You need MoveIt 2 when you're planning collision-aware motion for a manipulator; you don't need it for a mobile base that only needs Nav2's 2D planning.
Breaking change โ old code stops compiling or running. Deprecation โ old code still works but warns, and will break in a future release. Behavioral change โ same API, different runtime behavior. New capability โ nothing to migrate, purely additive.
Before moving a package from an older distro to Lyrical:
rosdep install against the new Ubuntu base โ package names and available versions shift with each Ubuntu LTS.jazzy vs. a lyrical branch) โ many community packages maintain these separately.docs.ros.org/en/lyrical/Releases for the authoritative list โ this appendix is a map, not a replacement for it.Four years and several Ubuntu LTS releases separate them. API evolution, dependency version drift, compiler changes, and whether the maintainer even still builds for the new distro all affect this โ always check package compatibility before committing to a distro for a new project.
NVIDIA Jetson boards ship a specific JetPack/Ubuntu/CUDA combination determined by NVIDIA, which is frequently a version or more behind the newest desktop Ubuntu LTS. Before targeting Lyrical (Ubuntu 26.04) on Jetson hardware, verify NVIDIA's current JetPack base OS โ if it hasn't caught up yet, your practical choices are a containerized ROS 2 install (a Lyrical container on an older JetPack host OS), a source build, or staying on the ROS distro that matches your JetPack's actual Ubuntu base.
Native supported install โ JetPack's Ubuntu base matches a released ROS distro
Containerized ROS โ run a newer distro's container on an older host OS
Source build โ build ROS 2 from source against your exact JetPack image
Unsupported workaround โ forcing package installs across mismatched versions
Raspberry Pi (4/5) with a 64-bit Ubuntu Server or Desktop image gets Tier 1/Tier 3 ARM64 binaries depending on the distro โ prefer 64-bit over 32-bit for any current ROS 2 work, since 32-bit support has been dropped across the ecosystem.
Ubuntu Host
โ
โโโ ROS Container
โ โโโ Nav2
โ โโโ Perception
โ โโโ Application nodes
โ
โโโ Hardware / drivers
Docker gives reproducible dependency isolation and easy deployment, at the cost of extra complexity around DDS discovery across container network boundaries and GPU passthrough for perception workloads.
Starting a new robot?
โ
โผ
Need long-term production support?
โ
โโโ Yes โ newest LTS compatible with your hardware/OS/driver stack
โ
โโโ No
โ
โผ
Need newest ROS capabilities?
โ
โโโ Stable non-LTS release for early access with real support
โโโ Rolling only if you're a maintainer or doing pure research
| Scenario | Preferred strategy | Reason |
|---|---|---|
| Learning ROS 2 today | Current supported LTS (Lyrical, or Jazzy) | Best documentation coverage and longevity |
| New production robot | Newest LTS compatible with your sensors/Jetson/vendor SDKs | Five-year support window |
| Existing Ubuntu 22.04 fleet | Stay on Humble until a real reason to move | Re-validation cost of an OS jump is high |
| Research on newest APIs | Latest stable, Rolling only for direct package contribution | New capabilities without maintainer-only instability |
| Package maintainer | Target Rolling + the active LTS distros | Forward and backward compatibility |
Don't choose a ROS distribution by release date alone. First check your OS, GPU/AI stack (JetPack, CUDA), sensor and LiDAR driver support, Gazebo pairing, Nav2/ros2_control/MoveIt 2 availability, vendor SDKs, and your fleet's real maintenance lifecycle. "Newest ROS" and "best ROS for this robot" are frequently different answers.
| Symptom | Cause | Fix |
|---|---|---|
ros2: command not found | Forgot to source ROS | source /opt/ros/lyrical/setup.bash |
| Package not found after build | Forgot to source the workspace overlay | source install/setup.bash |
apt can't find ros-lyrical-* packages | Mixed distro name in package name, or wrong Ubuntu version | Match the package prefix to your actual installed ROS_DISTRO |
| Two nodes with the same name conflict | Duplicate node names on the graph | Rename or namespace one of them |
| Robots on the same LAN can't see each other | Different ROS_DOMAIN_ID | Align the domain ID, or intentionally isolate it |
| Nodes see each other but topics won't connect | Incompatible QoS profiles | Check ros2 topic info --verbose and align reliability/durability |
| Following an old blog post breaks the build | Blog was written for ROS 1, Foxy, Humble, or Gazebo Classic | Cross-check every command against docs.ros.org/en/lyrical |
# Environment
source /opt/ros/lyrical/setup.bash
printenv | grep ROS
# Nodes / Topics / Services / Actions
ros2 node list
ros2 topic list | echo | info | hz
ros2 service list | call
ros2 action list | send_goal
# Parameters
ros2 param list | get | set
# Packages & build
ros2 pkg create --build-type ament_python
colcon build --symlink-install
source install/setup.bash
# Dependencies
rosdep update
rosdep install --from-paths src --ignore-src -r -y
# Diagnostics & recording
ros2 doctor
ros2 bag record / play / info