What's New in ROS 2 Lyrical Luth: EventsCBGExecutor and Other Changes
ROS 2 Lyrical Luth was released on May 22, 2026. It is the twelfth ROS 2 release and a Long Term Support release supported until May 2031. The headline change for performance-minded teams is the EventsCBGExecutor in rclcpp. According to the release notes, it uses 10% to 15% less CPU than the Single-Threaded and Multi-Threaded executors, and it supports multiple threads and multiple sources of ROS time. Lyrical also brings asyncio support in rclpy, zero-copy message buffers, many rosbag2 improvements, and a new platform baseline built on Ubuntu 26.04.
This summary is written for engineering leads deciding when to standardize on the new LTS. It only uses the official Lyrical release notes and concept pages, which are indexed in full in the ROS 2 knowledge base.
Lyrical Luth at a glance
Key facts from the Lyrical release pages
| Item | Lyrical Luth |
|---|---|
| Release (general availability) | Friday, May 22, 2026 |
| Support type and end-of-life | LTS, May 2031 (no updates after that, including security updates) |
| Tier 1 platforms | Ubuntu Resolute (26.04) amd64 and arm64; Windows 11 (VS2022) amd64 |
| Tier 2 platform | RHEL 10 amd64 |
| Default middleware | rmw_fastrtps_cpp |
| Tier 1 middleware | Fast DDS, Cyclone DDS and Zenoh on all architectures; Connext on all but arm64 |
| Minimum languages | C++20, C17, Python 3.12 to 3.14 |
The headline: the Callback Group Events Executor
The executors concept page is unusually direct about the history. The Single-Threaded and Multi-Threaded executors are simple to reason about, but they were a significant performance bottleneck. The EventsCBGExecutor, available from Lyrical Luth onward, is described as the result of years of work to reduce CPU overhead compared with the existing executors.
How it works
- It does not poll wait sets. Instead it uses a first-in first-out events queue, and an entity enqueues an event only when it becomes ready, so you don't pay for what you're not using.
- It improves on its predecessor, rclcpp::experimental::EventsExecutor, by supporting multiple sources of ROS time (including sim time), fixing bursts of timer events from slow-running timers, and adding multithreading.
- Because it creates a configurable number of worker threads, the docs say it can act as a drop-in replacement for the MultiThreadedExecutor. As with that executor, actual parallelism depends on your callback groups.
- In single-threaded mode, it causes less context switching and performs similarly to its predecessor.
How to try it
In code, instantiate rclcpp::executors::EventsCBGExecutor, call add_node(node), then spin(). For a single thread, the concept page constructs it as EventsCBGExecutor st_cbg_exec(rclcpp::ExecutorOptions(), 1). A default-constructed instance uses the maximum number of threads available. For composable nodes, use the new argument: ros2 run rclcpp_components component_container --executor-type events-cbg. With MultiThreadedExecutor or EventsCBGExecutor containers, the thread count comes from the ROS parameter thread_num.
The caveat in the docs
There is currently no limit to the number of events that can be added to the queue. If a process is overloaded and slows down, the number of ready entities in the queue can grow unbounded. Load-test before deploying it on a robot that runs close to its CPU limit.
Python: AsyncNode and asyncio
rclpy gains an experimental AsyncNode class (from rclpy.experimental import AsyncNode) that runs an asyncio event loop. Subscription, service and timer callbacks can await any asyncio operation, including await client.call(request) and the sim-time-aware await clock.sleep(...). The release notes say this class uses significantly less CPU than the default SingleThreadedExecutor. For Python-heavy stacks, such as a university research codebase or a startup's perception prototype, this is the change most likely to simplify code.
Data, recording and zero-copy
- rosidl::Buffer: in C++, all uint8[] fields now have the type rosidl::Buffer<uint8_t> instead of std::vector<uint8_t>. With an appropriate BufferBackend, messages can be published without moving data out of places such as a GPU. Publishers and subscribers on rmw_fastrtps_cpp or rmw_zenoh_cpp can use it.
- Remote bag control: rosbag2 exposes ~/record, ~/stop, ~/start_discovery, ~/stop_discovery and ~/is_discovery_running services.
- Python bag API: rosbag2_py.Recorder and rosbag2_py.Player can pause, resume, stop, seek and play the next message.
- Circular recording: --max-bag-files deletes the oldest split files as new ones are created.
- Traceable split names: files are now named {counter}_{prefix}_{timestamp}.{extension}.
- Message-loss observability: per-topic loss events are published on events/rosbag2_messages_lost, with the rate capped by --stats_max_publishing_rate.
Quality-of-life changes for developers
- Typed YAML parameters: tags such as !!str, !!bool, !!int, !!float, !!seq and !!map remove type ambiguity in parameter files.
- Array range checks: rclcpp now validates range descriptors on integer and double arrays.
- Launch: per-message log severity (the level argument, or log_debug, log_info, log_warning, log_error), plus string-join and path-join substitutions in XML and YAML launch files.
- Logging backend at run time: set RCL_LOGGING_IMPLEMENTATION to rcl_logging_spdlog (the default), rcl_logging_noop or your own implementation.
- CLI: ros2 param get across all nodes, multi-parameter get and set, ros2 service info --verbose, ros2 topic bw on several topics or --all, and a richer ros2 doctor --report.
- URDF 1.2: quaternions, capsule geometry, and acceleration, deceleration and jerk limits, enabled with version="1.2". RViz's Robot Model plugin does not support capsules yet.
- Shell and tracing: a setup.fish script, TRACETOOLS_RUNTIME_DISABLE=1 to skip loading the tracer, and snapshot and dual-session tracing modes.
Where Lyrical sits against Kilted and Jazzy
Kilted Kaiju, released May 23, 2025, reaches end-of-life in December 2026, much sooner than Lyrical's May 2031. Jazzy Jalisco runs until May 2029 and Humble Hawksbill until May 2027. The next release, Makoa Mata-mata, is planned for May 2027 as a regular release supported until December 2028. For a team picking a base for products that ship in 2027 and beyond, Lyrical offers the longest documented support window. The platform jump is the main cost: Ubuntu Noble (24.04) is only Tier 3 for Lyrical, with an early end-of-life on 2029-06-01.
Callback groups still decide how parallel you get
Switching executors does not remove the need to design callback groups. The concept page explains that there are two types. In a Mutually exclusive group, callbacks must not run in parallel. In a Reentrant group, they may. Callbacks in different groups may always run in parallel. Anything created without an explicit group goes into the node's default callback group. The docs also warn that a callback group must be stored for the whole life of the node, for example as a class member, or the executor will not be able to trigger its callbacks. With more than one thread, the EventsCBGExecutor follows these same rules, so a node that serializes everything in one mutually exclusive group will not get faster just because the executor has more threads.
A rollout plan for engineering leads
- Check your platforms. List every robot and workstation OS. Ubuntu 26.04 is Tier 1 for Lyrical, while Ubuntu 24.04 is Tier 3 and requires a source build.
- Stand up a reference image on Ubuntu 26.04 with ros-lyrical-desktop and confirm ROS_DISTRO=lyrical with printenv | grep -i ROS.
- Benchmark the executor on your heaviest nodes, comparing your current executor with the EventsCBGExecutor under realistic load. Watch the unbounded event queue.
- Turn on rosbag2 loss observability on test robots with ros2 bag record --all --stats_max_publishing_rate 10 and watch /events/rosbag2_messages_lost.
- Cut over whole systems. The documentation says nodes are not guaranteed to communicate across distributions, so don't run a mixed fleet on one network.
Ask the Lyrical release notes anything
Kopik's ROS 2 base indexes the official release notes of every distribution along with the Lyrical concepts and how-to guides. Ask “What's new in the Lyrical Luth executor for rclcpp, and how much CPU does it actually save compared to the older executors?” and get the answer with its source passage.
Teams that wire documentation into their own agents or CI bots can query the base through the developer API.
Frequently asked questions
When was ROS 2 Lyrical Luth released?
General availability was on Friday, May 22, 2026, according to the Lyrical release timeline. It is the twelfth release of ROS 2.
How much CPU does the EventsCBGExecutor save?
The release notes state that, compared to the Single and Multithreaded executors, the EventsCBGExecutor uses 10% to 15% less CPU.
Is Lyrical Luth an LTS release?
Yes. The release page says Lyrical Luth is a Long Term Support release supported until May 2031.
What is the default middleware in ROS 2 Lyrical?
The default middleware is rmw_fastrtps_cpp (Fast DDS). Cyclone DDS, Zenoh and Connext are also Tier 1, with Connext excluded on arm64.
When does Kilted Kaiju reach end-of-life?
Kilted Kaiju, released on May 23, 2025, reaches end-of-life in December 2026, well before Lyrical Luth's May 2031.
What is AsyncNode in ROS 2 Lyrical?
AsyncNode is a new experimental rclpy class that runs an asyncio event loop, so subscription, service and timer callbacks can await asyncio operations such as client.call(request). The release notes say it uses significantly less CPU than the default SingleThreadedExecutor.
Get the Kopik newsletter
New knowledge bases, RAG guides and product news. One email every week or two, unsubscribe in one click.
By subscribing you agree to receive our newsletter. We never share your address.