While laying out the mission architecture for our SUAS 2026 entry, I put ROS 2 on the table and spent some time working out what it would actually buy a camera-to-detection pipeline. This post is the summary of that review. It is not a field report: I am writing about what I learned evaluating the framework, not about battle scars from flying it. The tutorials will teach you what a node and a topic are in an afternoon. The more useful question is which parts of the framework matter for a vision system, and which parts a small team can honestly skip. The project this evaluation was done for is here.

Figure: rendered by me.
Nodes and topics, in one paragraph
A node is a process with one job. A topic is a named stream that nodes publish to and subscribe to without knowing about each other. That decoupling is the entire pitch: the camera node does not care whether one subscriber is listening or five, and you can swap the detector without touching the camera driver. Underneath, a DDS middleware handles discovery and transport, so there is no central broker to keep alive. For a vision pipeline, nodes, topics and parameters cover most of what you would ever touch. Services, actions and lifecycle nodes exist, but a small pipeline needs a handful of topics, and that is not a failure of ambition.
Where it would earn its keep
Three things stood out in the evaluation. First, explicit boundaries: camera, detector and geolocation become separate processes with a message contract between them, so each stage can be developed, tested and replaced on its own. Second, recording: rosbag2 captures the topics from a run, and you can replay them later and re-run the detector against real data at your desk. Third, introspection for free: ros2 topic list shows what exists, ros2 topic hz shows whether a stream is flowing at the rate you think, and rqt_graph shows whether the graph you built is the graph you meant to build.
Timestamps deserve their own mention. ROS 2 messages carry a header stamp, and the convention is to stamp at capture and carry that stamp through the pipeline untouched. For geolocation this is not pedantry: projecting a pixel onto the ground means pairing a detection with the aircraft pose from the same moment. Pair it with the pose from a slightly later moment and the aircraft has moved on, so the target lands metres from where it should on the map, with nothing in the logs looking wrong. message_filters exists to synchronize streams by stamp rather than by arrival order, and it is exactly the right tool for this.
QoS is where it silently breaks
Quality of Service settings are the part every tutorial mentions and many readers skip. Do not. A publisher and a subscriber with incompatible QoS profiles simply do not connect, and by default there is no error: the topic just stays silent. The documentation is clear about this, and it is the classic “why is my topic empty” trap.
For camera frames the sensible choice is the sensor data profile: best effort reliability with a small queue. You want the newest frame, not a faithful replay of every frame. Reliable delivery on a 30 fps image stream means that when the consumer hiccups, the middleware queues old frames and your detector starts processing the past. A detection pipeline running on stale frames is worse than one that drops them.
Images are heavy, plan for that
A 4K frame is a lot of bytes, and every publish across process boundaries pays serialization and copy costs. On a Jetson-class board, memory bandwidth is part of the real-time budget. The design consequence: keep the camera and the detector close, and publish small messages, not big ones. A detector can emit boxes, classes and confidences, a few hundred bytes instead of megabytes, and keep any annotated debug video behind a parameter, off by default. If two image-heavy nodes must talk at high rate, composition puts them in one process and intra-process communication skips the serialization entirely.
The honest part: you do not always need it
Here is the conclusion I keep coming back to. A single vehicle with one computer, one camera and three or four pipeline stages can be served by a single process: a capture thread, a queue, a detector, plain function calls. ROS 2 brings a build system, DDS configuration, QoS tuning and launch files, and that operational surface is a real cost. Its value grows with the number of processes, the number of contributors, and the need to record and replay. If one person writes the whole pipeline and it fits in one process, the framework mostly adds ceremony. My working heuristic: adopt it when you need process isolation, recorded replays, or several people integrating against stable interfaces. Until then, deferring is a defensible engineering decision, not a shortcut.
ROS 2 will not make a vision pipeline good. It makes the boundaries between its parts explicit, and whether that is worth the overhead depends on how many boundaries you actually have.