# adaptive-component
**Repository Path**: agiros/adaptive-component
## Basic Information
- **Project Name**: adaptive-component
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-01-15
- **Last Updated**: 2025-12-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# `adaptive_component`
**A composable stateless container for Adaptive ROS 2 Node computations. Select between FPGA, CPU or GPU at run-time**.
Nodes using hardware acceleration are able to perform computations faster relying on FPGAs or GPUs, improving performance. Adaptive ROS 2 Nodes leverage hardware acceleration at run-time, allowing robotics engineers to select which computational resource the Node uses *on-the-go*, giving roboticists a finer-grained control over the resources their computional graphs use in the underlying hardware.
This ROS 2 package provides a composable stateless container for Adaptive ROS 2 Node computations: [`adaptive_component`](https://github.com/ros-acceleration/adaptive_component). It allows building Nodes that can select between FPGA, CPU or GPU, at run-time.
Technically, it's a ROS 2 `Node`[^1] subclass programmed as a `Component`[^2] and including its own [single threaded executor](https://github.com/ros-acceleration/adaptive_component/blob/main/include/adaptive_component.hpp#L68)
to build adaptive computations. Adaptive ROS 2 `Nodes` can then be built easily and are able to perform computations in the CPU, the FPGA or the GPU. Adaptive behavior is controlled through the `adaptive` ROS 2 parameter, with the following values allowed:
- `0`: Hardware::CPU
- `1`: Hardware::FPGA
- `2`: Hardware::GPU
`adaptive_component` is *stateless* by default, if you need your Adaptive Nodes to be *stateful*, feel free to inherit from `composition::AdaptiveComponent` and create your own stateful subclasses[^5].
[^1]: A `Node` is a process that performs computations. ROS 2 is designed to be modular at a fine-grained scale; a robot control system usually comprises many nodes. Nodes execute arbitrary logic that contribute to the overall robotics behavior.
[^2]: A ROS 2 `Component` is a `Node` compiled into a shared library which is then loaded at runtime by a container process. This offers roboticists additional flexibility while building their computational graphs, making the layout process a deploy-time decision. A `Component` is commonly a subclass of `rclcpp::Node`. To maintain flexibility and modularity, `Components` shouldn’t perform any long running or blocking tasks in their constructors. Instead, they can use timers to get periodic notifications and use callbacks for publishers, subscribers, servers, or clients.
[^5]: See [this example](https://github.com/ros-acceleration/acceleration_examples/blob/main/nodes/doublevadd_publisher/src/doublevadd_publisher_adaptive_with_components_and_state.cpp) ([ROS 2 component](https://github.com/ros-acceleration/acceleration_examples/blob/main/nodes/doublevadd_publisher/src/doublevadd_component_adaptive_stateful.cpp)).
## How does it work?
[](https://asciinema.org/a/448016)
```cpp
using NodeCPU = composition::DoubleVaddComponent;
using NodeFPGA = composition::DoubleVaddComponentFPGA;
rclcpp::NodeOptions options;
// Create an executor
rclcpp::executors::MultiThreadedExecutor exec;
// Create an adaptive ROS 2 Node using "components", the resulting
// Node is also programed as a "component", retaining composability
auto adaptive_node = std::make_shared(
"doublevadd_publisher_adaptive",
options,
// CPU
std::make_shared("_doublevadd_publisher_adaptive_cpu", options),
// FPGA
std::make_shared("_doublevadd_publisher_adaptive_fpga", options),
// GPU
nullptr);
exec.add_node(adaptive_node); // fill up the executor
exec.spin(); // spin the executor
```
Then, dynamically, one could switch from CPU to FPGA by setting the `adaptive` parameter in the `/doublevadd_publisher_adaptive` Node:
- To run in the CPU: `ros2 param set /doublevadd_publisher_adaptive adaptive 0`
- To run in the FPGA: `ros2 param set /doublevadd_publisher_adaptive adaptive 1`
## Why should I care as a ROS package maintainer?
The integration of hardware acceleration into ROS often requires rewriting parts of the Node computations to further exploit parallelism. These changes often conflict with CPU-centric architectures and as a maintainer, you're likely to care for "not breaking" CPU-centric implementations.
To consistently integrate hardware acceleration, **avoid unnecessary forks** and discourage package fragmentation, `composition::AdaptiveComponent` allows to extend ROS 2 CPU-centric Nodes[^3] with their computational counterparts separating concerns at build-time. From a package-maintenance perspective, each Node (across computation options) is written in a separated file and as a separated Component. These can live either within the same package, or in totally different (disconnected) ones. [`adaptive_component`](https://github.com/ros-acceleration/adaptive_component) takes care of putting them together at launch time and no dependency with the package is required at build-time[^4].
From an execution perspective, developers can easily create Adaptive ROS 2 Nodes and compose them together as desired at launch-time, with capabilities to adaptively switch between compute alternatives at run-time.
[^3]: Assumes Nodes are written as components, but it they are not, it's a great chance to do so ;).
[^4]: Though `adaptive_component` allows to disconnect nodes across packages, to facilitate source code maintenance across CPU-centric implementations and counterparts, it should be encouraged to keep the source code within the same ROS 2 package with suffixes indicating of the compute substrate (e.g. `_fpga.cpp`, etc.). This will facilitate maintaining implementations across different compute substrates, avoid versioning issues and fragmentation issues.
## Some examples
Examples of using `adaptive_component`:
- [An Adaptive ROS 2 Node](https://github.com/ros-acceleration/acceleration_examples/blob/main/nodes/doublevadd_publisher/src/doublevadd_publisher_adaptive.cpp)
- [An Adaptive stateless ROS 2 Component](https://github.com/ros-acceleration/acceleration_examples/blob/main/nodes/doublevadd_publisher/src/doublevadd_component_adaptive.cpp) ([Node example using it](https://github.com/ros-acceleration/acceleration_examples/blob/main/nodes/doublevadd_publisher/src/doublevadd_publisher_adaptive_with_components.cpp))
- [An Adaptive stateful ROS 2 Component](https://github.com/ros-acceleration/acceleration_examples/blob/main/nodes/doublevadd_publisher/src/doublevadd_component_adaptive_stateful.cpp) ([Node example using it](https://github.com/ros-acceleration/acceleration_examples/blob/main/nodes/doublevadd_publisher/src/doublevadd_publisher_adaptive_with_components_and_state.cpp))
## Conventions and recommendations
The following conventions and recommendations are meant to facilitate the integration of hardware acceleration in existing ROS packages
1. **Component-oriented**: [`AdaptiveComponent`](https://github.com/ros-acceleration/adaptive_component/blob/main/src/adaptive_component.cpp) is built as a component and should be used as such to maintain composability of Nodes.
2. **Naming**: The Adaptive Node should be suffix with `_adaptive` to identify in the computational graph which Nodes have adaptive capabilities and which do not.
3. **Hidden sub-Nodes**: Adaptive Node components (compute-specific ones e.g. CPU's or FPGA's) should be named with a hyphen (`_`) as a prefix, which will make them *hidden* Nodes by default.
4. **File names**: When possible, source code file names should adhere to the following guidelines:
- CPU-based computational Nodes can optionally add the `_cpu` suffix
- FPGA-based computational Nodes shall add the `_fpga` suffix
- GPU-based computational Nodes shall add the `_gpu` suffix
## Quality Declaration
This package claims to be in the **Quality Level 4** category, see the [Quality Declaration](./QUALITY_DECLARATION.md) for more details.