Hi everyone,
I would like to introduce ros2_cuda_ipc, an experimental ROS 2 library for sharing GPU-resident data between processes without copying it through CPU memory.
Motivation
GPU-accelerated perception pipelines often separate camera or LiDAR preprocessing, DNN inference, visualization, and encoding into different components.
Composable nodes can avoid inter-process copies, but they also place components inside the same process. Separating components provides better isolation and deployment flexibility, but GPU data often has to be copied through CPU memory at each process boundary.
The goal of “ros2_cuda_ipc” is to preserve process separation while keeping data on the GPU.
Relationship to ROS 2 buffer backends
While developing this project, ROS 2 Lyrical introduced “rosidl::Buffer” and a CUDA buffer backend.
The two projects were developed independently, but address substantially the same problem: transporting GPU-backed ROS data between processes without unnecessary CPU copies.
The Lyrical buffer-backend design provides a general, ROS-native storage abstraction integrated with generated message types and the middleware.
“ros2_cuda_ipc” takes a standalone library approach using explicit descriptors in ROS messages. It focuses on CUDA IPC, stream synchronization, buffer lifetime management, and compatibility with existing message definitions and older ROS 2 distributions.
The approaches have different integration points, but there may be opportunities to share ideas or eventually reuse parts of this work within the buffer-backend ecosystem.
Features
The library currently provides:
- inter-process GPU memory sharing using CUDA VMM file descriptors
- CUDA event-based stream synchronization
- buffer lifetime management for multiple consumers
- Python support for DLPack-compatible frameworks such as PyTorch and CuPy, with potential for direct integration into TensorRT inference pipelines via its Python API
The core package is intentionally untyped. Message-specific packages add typed interpretations such as “Image” and “PointCloud2”.
C++ example
Publisher:
auto block = manager.acquire_for_publish();
if (!block) {
return;
}
launch_kernel(block->device_ptr(), stream);
auto descriptor = block->prepare_publish(stream);
if (!descriptor) {
return;
}
msg.core = *descriptor;
publisher->publish(msg[;
Subscriber:
auto image = reader.read(msg, stream);
if (!image) {
return;
}
The read handle synchronizes with the consumer stream and keeps the underlying GPU buffer valid while it is in use.
Python example
The same GPU data can be consumed from Python through DLPack:
image = ImageMapper().map(msg)
tensor = torch.from_dlpack(image)
This makes it straightforward to plug the data into PyTorch-based pipelines, and similarly into TensorRT workflows via its Python bindings, where the resulting tensor can be used as an input without additional host copies.
Synchronization is performed using the CUDA stream selected by the consumer framework when the DLPack object is consumed.
Feedback welcome
The project is still experimental, and the API may continue to evolve.
I would especially appreciate feedback about:
- real-world perception and robotics use cases
- interoperability with ROS 2 buffer backends
- TensorRT or ONNX Runtime integration
- Python and DLPack support
- failure handling and crash recovery
- API usability
Issues, design discussions, and experiments are welcome.
GitHub - dskkato/ros2_cuda_ipc: ROS 2/CUDA IPC support · GitHub