ROS 2 Addressing BSON Handling For High-Overhead Data In Rosbridge_suite
This article addresses an issue within the ROS 2 ecosystem, specifically concerning the handling of Binary JSON (BSON) data in the rosbridge_suite
. The primary focus is on optimizing the transmission of high-overhead data types, such as sensor_msgs/msg/PointCloud2
, which suffer from significant performance bottlenecks when serialized into JSON text format. This proposal aims to rectify a long-standing problem by implementing a solution that leverages the efficiency of BSON for binary data, enhancing the overall performance and scalability of ROS 2 applications utilizing rosbridge
.
Background and Related Issues
The impetus for this discussion arises from the limitations encountered when using rosbridge
to transmit large messages. The conventional approach of converting binary data to JSON text results in substantial overhead, impacting bandwidth utilization and processing time. Prior attempts to address this issue are documented in the closed issues #718 and #596 within the RobotWebTools/rosbridge_suite
repository. Despite the previous closure of these issues, the underlying problem persists, necessitating a renewed effort to implement a viable solution. It is crucial to revisit these concerns to ensure the effective handling of binary data, particularly in scenarios involving high data throughput.
The Significance of BSON for ROS 2
BSON, a binary-encoded serialization format, offers a compact and efficient alternative to JSON for transmitting complex data structures. Unlike JSON, which is text-based, BSON stores data in binary format, reducing the size of the transmitted data and the computational overhead associated with serialization and deserialization. This makes BSON particularly well-suited for applications dealing with large volumes of binary data, such as point clouds, images, and sensor readings. By adopting BSON, ROS 2 can significantly improve the performance of systems that rely on transmitting such data over networks. The ability to handle binary data natively also aligns with the evolving needs of robotics and IoT applications, where efficient data transmission is paramount.
Understanding the Overhead in JSON Serialization
The traditional method of converting binary data to JSON text introduces several layers of overhead. First, the binary data must be encoded into a text representation, typically using Base64 encoding. This encoding process increases the size of the data, as Base64 represents 3 bytes of binary data using 4 ASCII characters. Second, the encoded data is embedded within a JSON structure, which includes additional characters for delimiters, keys, and metadata. This further increases the message size. Finally, the JSON text must be parsed and deserialized at the receiving end, adding computational overhead. In contrast, BSON eliminates these steps by directly representing data in a binary format, resulting in smaller message sizes and faster processing times. This efficiency is especially critical in real-time systems where timely data delivery is essential.
Problem Description
The core issue lies in the current implementation of rosbridge_server
, specifically within the websocket_handler.py
script. In the ros2
branch, the on_message
function indiscriminately attempts to decode all incoming binary messages as UTF-8, irrespective of the bson_only_mode
setting. This behavior effectively negates the intended functionality of the BSON-only mode, leading to decoding errors and preventing the proper handling of BSON-encoded messages. When the server is configured to operate in bson_only_mode
, it should ideally process BSON messages directly without attempting UTF-8 decoding. The failure to do so results in a critical flaw that impedes the efficient transmission of binary data.
The Technical Details of the Bug
The problematic code snippet is located within the on_message
function of the websocket_handler.py
script. When a binary message is received, the function attempts to decode it as UTF-8, assuming it is a text message. This assumption is incorrect when bson_only_mode
is enabled, as the incoming message is expected to be in BSON format, which is not a valid UTF-8 string. Consequently, a UnicodeDecodeError
is raised, disrupting the message processing pipeline. This error not only prevents the message from being handled correctly but can also lead to the server crashing or generating error logs. The issue highlights a fundamental flaw in the message handling logic, where the content type is not correctly inspected before attempting to decode it.
Impact on High-Overhead Data Transmission
The implications of this bug are particularly severe when transmitting high-overhead data types such as sensor_msgs/msg/PointCloud2
. Point cloud data consists of a large number of 3D points, often accompanied by additional attributes such as color and intensity. The size of these messages can easily reach several megabytes, making efficient serialization and transmission crucial. When serialized to JSON text, the overhead associated with encoding the binary data and the verbose JSON structure significantly increases the message size. This leads to higher bandwidth consumption, increased latency, and greater processing load on both the sender and receiver. By preventing the use of BSON, the current implementation effectively throttles the performance of applications that rely on transmitting point cloud data, limiting their scalability and responsiveness.
Steps to Reproduce
The issue can be readily reproduced by following a straightforward set of steps. First, launch the rosbridge_server
with the bson_only_mode
parameter set to true. This configuration instructs the server to expect BSON-encoded messages exclusively. Next, transmit a message containing BSON-encoded binary data to the server. Since the current implementation attempts to decode all binary messages as UTF-8, the server will throw a UnicodeDecodeError
. This error confirms the failure to handle BSON messages correctly when bson_only_mode
is enabled.
Detailed Reproduction Steps
-
Launch
rosbridge_server
in BSON-only mode:ros2 launch rosbridge_server rosbridge_websocket_launch.xml bson_only_mode:=true
This command starts the
rosbridge_server
with thebson_only_mode
parameter set totrue
. This setting should ensure that the server expects and processes only BSON-encoded messages. -
Run a client that sends a BSON-encoded message:
Implement a client application that encodes data into BSON format and sends it to the
rosbridge_server
. The specific details of the client implementation will vary depending on the programming language and libraries used, but the key aspect is to ensure that the message is serialized using BSON. A minimal example would involve creating a simple dictionary, encoding it using a BSON library, and sending the resulting binary data over a WebSocket connection.
Expected vs. Actual Behavior
The expected behavior is that the rosbridge_server
, when launched with bson_only_mode:=True
, should correctly process BSON binary messages without encountering decoding errors. It should recognize the incoming message as BSON and handle it accordingly, deserializing the data and forwarding it to the appropriate ROS 2 topics. The actual behavior, however, is that the rosbridge_server
throws a UnicodeDecodeError
and either crashes or outputs an error log. This discrepancy highlights the bug in the message handling logic, where the server incorrectly attempts to decode BSON messages as UTF-8 text.
Proposed Solution
The proposed solution involves modifying the on_message
function in websocket_handler.py
to conditionally process binary messages based on the bson_only_mode
setting. Specifically, when bson_only_mode
is enabled and the incoming message is binary, the function should bypass the UTF-8 decoding step and directly push the message onto the incoming queue. This ensures that BSON messages are handled as binary data, as intended. The suggested patch introduces a conditional check that distinguishes between BSON and UTF-8 messages, enabling the server to process each type correctly.
Code Patch Details
The proposed patch introduces a conditional statement that checks whether bson_only_mode
is enabled and the incoming message is binary. If both conditions are met, the message is pushed directly onto the incoming queue without attempting UTF-8 decoding. This allows BSON messages to be processed as binary data, bypassing the erroneous decoding step. If either condition is not met, the existing logic is preserved, ensuring that UTF-8 messages are still handled correctly. The patch effectively isolates the BSON handling logic, preventing it from interfering with the processing of other message types.
--- a/rosbridge_server/src/rosbridge_server/websocket_handler.py
+++ b/rosbridge_server/src/rosbridge_server/websocket_handler.py
@@ -158,15 +158,13 @@
@log_exceptions
def on_message(self, message):
- if isinstance(message, bytes):
- message = message.decode("utf-8")
- self.incoming_queue.push(message)
-
+ if self.bson_only_mode and isinstance(message, bytes):
+ # BSON ONLY MODE: push binary directly
+ self.incoming_queue.push(message)
+ else:
+ if isinstance(message, bytes):
+ message = message.decode("utf-8")
+ self.incoming_queue.push(message)
Benefits of the Proposed Solution
This solution offers several key benefits. First and foremost, it enables the correct handling of BSON messages when bson_only_mode
is enabled, resolving the core issue. This allows for the efficient transmission of binary data, such as point clouds, improving the performance of applications that rely on such data. Second, the patch is minimally invasive, modifying only a small section of code and preserving the existing message handling logic for UTF-8 messages. This reduces the risk of introducing unintended side effects. Finally, the solution is straightforward and easy to understand, making it easier to maintain and debug. By addressing the BSON handling issue, this patch significantly enhances the robustness and efficiency of rosbridge_server
.
Next Steps and Call for Feedback
To advance this proposal, the next step involves gathering feedback on the proposed solution and, if it is deemed acceptable, creating a pull request to integrate the patch into the rosbridge_suite
codebase. Community input is invaluable in ensuring that the solution is robust, well-tested, and aligned with the needs of ROS 2 users. Feedback on the approach, potential edge cases, and alternative solutions is highly encouraged. By fostering open discussion and collaboration, we can collectively refine the solution and ensure its successful implementation.
Invitation to Contribute
The author of this proposal extends an invitation to the ROS 2 community to contribute to this effort. Feedback on the proposed solution, suggestions for improvements, and testing of the patch are all valuable contributions. If the proposed direction is well-received, the author is prepared to create a pull request, initiating the formal process of integrating the patch into the rosbridge_suite
repository. Collaboration is key to ensuring that the solution is thoroughly vetted and meets the diverse needs of the ROS 2 community. By working together, we can enhance the performance and reliability of rosbridge_server
and improve the overall ROS 2 ecosystem.