ROS Composition
ROS composition combines multiple nodes (ROS components) into a single process, enhancing performance and efficiency.
This way, you get Intra-process Communications inside ROS and thus enable Zero-Copy for message transport.
Can't you just use the ROS Executor and call
add_node
multiple times?Yes, you can manually adding nodes to an executor, and not have to register nodes as components. This is actually just static composition.
However, if you want dynamic composition by using ROS Launch Files, you want to register them into a shared library first (more on this later).
This is why you generally always see the RCLCPP_COMPONENTS_REGISTER_NODE
macro to register a node as a component.
Enabling Zero-Copy
ROS Composition enables intra-process communcations, and thus zero-copy operations since data is shared across a process. This is one of the most important things that you need to understand and master to get better performance out of ROS.
Resources
- ROSCon 2019 Macau: Composable Nodes in ROS2 (super helpful)
- https://arxiv.org/pdf/2305.09933.pdf (Fundamental paper explaining ROS Composition)
- https://docs.ros.org/en/humble/Concepts/About-Composition.html
- https://docs.ros.org/en/humble/Tutorials/Intermediate/Composition.html
There is a demo package: https://github.com/ros2/demos/tree/rolling/composition, which is what the slides is based on.
We also make use of composition in our launch files.
Ashwin first taught me about Composable Nodes. Apparently this is how data can be shared across CPU memory, instead of having to transmit the data across different CPUs.
Components DON'T have a
main
functionSince a component is only built into a shared library, it doesn’t have a
main
function.
Developing a ROS Component
These slides from ROSCon are the most helpful.
â—Ź Make your class dynamically loadable via registration macro in C++ source
There are 2 ways to do composition:
- Via inheritance from
rclcpp::Node
- Via composition
The inheritance way
The composition way
What is the
COMPOSITION_PUBLIC
keyword?I don’t know this macro, and I haven’t seen it in our Isaac ROS codebase.
In the source, you need to add the RCLCPP_COMPONENTS_REGISTER_NODE
macro to register it
Then, add them to the CmakeLists.txt
:
Composition does NOT work in Python
I only realized this recently after Andrew Saba told me about it, it’s probably due to the way Python works, since it’s a interpreter that goes through files and executes line by line.
Launching
There are 3 main ways to use ROS2 components (based on this tutorial):
- Create a launch file and use
ros2 launch
to create a container process with multiple components loaded. - Start a (generic container process) and call the ROS service load_node offered by the container. The ROS service will then load the component specified by the passed package name and library name and start executing it within the running process. Instead of calling the ROS service programmatically you can also use a command line tool to invoke the ROS service with the passed command line arguments
- Create a custom executable containing multiple nodes which are known at compile time. This approach requires that each component has a header file (which is not strictly needed for the first case).
The composition package contains a couple of different approaches on how to use components. The three most common ones
Launch File Launching
Use ComposableNodeContainer
if they are all in the same launch file. Else, use LaunchComposableNode
.
ROS components are built into a shared library.
NVIDIA
This stuff is actually fascinating, I really need to understand what is going on under the hood.
At NVIDIA, I learned this syntax. They actually use the RCLCPP_COMPONENTS_REGISTER_NODE
macro to avoid writing the int main()
thing? Need to build as shared.