Reflecting on this thread years later, the debate here captured the defining architectural trade-off of the Gazebo Sim transition: modularity & process decoupling vs. transport performance.
The shift away from Gazebo-Classic’s in-process plugins to an independent ros_gz_bridge was undoubtedly the right move for clean dependency isolation and crash containment. However, the architectural penalty discussed here remains very real today—both at runtime and in maintenance:
- The Runtime Deep-Copy Tax: Even when running ros_gz_bridge as a ROS 2 Component in the same container with downstream nodes, the bridge still executes convert_gz_to_ros() on every frame. For 4K cameras or dense point clouds, this means repeatedly allocating and memcpying multi-megabyte payloads from gz::msgs::Image (Protobuf) into sensor_msgs::msg::Image (ROS 2 struct). The bottleneck isn’t just inter-process sockets—it’s this continuous struct-to-struct memory copy.
- The Maintenance Burden: Hardcoding hundreds of handwritten convert_gz_to_ros() and convert_ros_to_gz() functions makes the bridge repository heavily bloated with fragile boilerplate. Every time a new message or custom sensor type is added, someone has to manually PR another set of field mappings.
Recently, in our work on protoros2 Announcing protoros2: use protobuf in ros2 without compromise, we’ve been exploring how modern ROS 2 features can rethink this bridge architecture:
- Even if downstream ROS 2 nodes still consume standard ROS .msg structs:
By leveraging ROS 2’s native TypeAdapter and schema-level synthesis, ros_gz_bridge itself could be relieved of all manual conversion duties. The bridge could simply operate as a generic forwarder (e.g., publishing gz::msgs adapted to RosMsg via TypeAdapter), eliminating thousands of lines of handwritten glue code from the bridge repository and distributing the conversion overhead away from the bridge process. - For nodes that opt into Protobuf:
Standard ROS 2 RMWs (rmw_fastrtps_cpp, rmw_cyclonedds_cpp) natively support passing raw Protobuf byte buffers via publish_serialized. Subscribing nodes can ingest the serialized message directly into C++ Protobuf objects without CDR conversion, completely bypassing convert_gz_to_ros() and achieving near-native transport throughput.
Decoupling the bridge transport from manual schema conversion allows ros_gz_bridge to become what it was always intended to be: a clean, lightweight, near-zero-maintenance conduit between the two ecosystems.
Curious if the maintainers or community have considered standardizing on TypeAdapter or serialized pass-throughs for future Gazebo-ROS bridge iterations!