-
Notifications
You must be signed in to change notification settings - Fork 519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CBOR compression summary #367
Comments
All merged 👍 |
Hi @mvollrath , this is the exactly problem what i met, i use rosbridge send the point cloud to Unity and it is JSON, which is too slow and lagging, i am new to ROS , as i understood, if i want to use CBOR, i have to write a subscriber in ROS side to recive the point cloud data as JSON and a publisher to republish the data with CBOR, and wirte another subscriber in Unity side to recive the CBOR data. is it right to use the CBOR like this? thanks in advance Wei |
Hi Wei, To get PointCloud2 data from ROS to Unity over rosbridge using CBOR you shouldn't need to write any ROS subscribers, rosbridge will do the CBOR encoding for you. From Unity you will connect to the rosbridge socket and send a "subscribe" message with the "compression" field set to "cbor". Whenever a point cloud message comes into Unity over the socket, it will be a CBOR-encoded binary "publish" message. |
Hi @mvollrath thanks for the answer. |
ROSBridgeLib does not support CBOR decoding. You have a few options:
Sorry about this, CBOR encoding on the server side is a new feature and the client libraries haven't caught up yet. |
@mvollrath Thanks for the detailed answer. i am new to programming and computer science, but i will try it:) |
Hi @mvollrath , |
@eisenwu that looks correct, make sure you're running at least rosbridge_suite version 0.11.3. You should get binary messages. Compare to "compression": "json" which should yield text messages. |
Hi @mvollrath , |
That e.g. |
Hi @mvollrath , |
That is possible, maybe something to do with how C# If your version of rosbridge_suite didn't support CBOR it would just send JSON. |
I was confusing why the rosbridge server only send CBOR but not receive it. |
I just wrote a C++11 based rosbridge client where CBOR (de)serializer supported. |
Thanks for this doc. That's a great introduction! I'm wondering, however, how is CBOR compared with some common bytes-compatible serialization schemes like bson or msgpack? I did a simple benchmark and it seems that CBOR didn't do better than them, so I would like to know if there is additional rationale behind which I didn't take into consideration. Thanks! |
The thing I was looking for was performance at homogenous typed arrays, e.g. large arrays of int16 being transformed into JavaScript typed arrays. There's a big difference between a CBOR array and a tagged typed array; instead of declaring the type of each array element you just put a tag in front and pack the bytes as densely as possible. Decoding the bytes is very efficient in most languages incl. JavaScript (typed arrays from byte strings is superfast) and Python (import struct and unpack is superfast). These kinds of homogenous arrays are used in ROS messages like point clouds and occupancy grids and such, and these are the kinds of messages CBOR encoding was intended for. JSON is still faster in typical browsers for small messages or messages with many keys because it has native implementation. Otherwise:
|
Hi, i'm having the following error when using cbor for OccupancyGrid
|
I'm having exactly the same issue |
PRs
Background
Previous to these changes, there are two options for encoding data between rosbridge and clients: JSON and JSON inside a base64-encoded PNG image.
Both of these options are text-based. Human-readable messages are great, but when the message data is thousands of integer values, the value of human readability diminishes and decoding speed becomes a bigger concern. When visualizing messages containing large blobs of binary data such as PointCloud2 or OccupancyGrid, these existing methods don't scale.
With the goal of increasing both the capacity and speed of rosbridge/roslibjs encoding and decoding, I started looking for a binary encoding format that could a) comply to the rosbridge protocol and b) quickly decode numeric arrays as views of a JavaScript
ArrayBuffer
.CBOR is a perfect fit. It implements a superset of JSON, adds byte arrays, and is extensible with tags. With the addition of the draft typed array tags, it meets all of the requirements. CBOR libraries are available for most languages and I found fast implementations for Python and JavaScript.
Benchmarks
Before implementing CBOR compression I wanted to make sure it was actually faster than JSON or PNG compression. I set up a Node.js application to simulate encoding and decoding some ubiquitous ROS message types containing binary data: sensor_msgs/Image and sensor_msgs/PointCloud2.
640x480 RBG Image:
PointCloud2 with 1928 points @ 32 point_step:
For sake of completeness, I also tested geometry_msgs/PoseStamped where JSON is faster, as expected:
After my proof-of-concept integration with rosbridge and roslibjs, I ran some more tests on a real application to verify that it would increase frame rate in a "real world" setting where message decoding competes with rendering for JavaScript time. I compared the average decoding time for the first 100 messages of a 5,000 point PointCloud2:
Note that PNG didn't actually spend 45ms on the main thread because it decodes asynchronously, this was the "wall time" from message receipt to the handler being run.
A 80,000 point PointCloud2 demonstrates how much better binary encoding can scale:
Finally, I ran a "stress test" to see how a ROS3DJS PointCloud2 compares to rviz. I made a small patch to ROS3DJS to enable CBOR encoding with fast buffer-flipping. I was able to view a 250,000 point cloud with no frames dropped. The same application with JSON or PNG decoding dropped at least one frame per message at this scale. When I increased the cloud density to 500,000 points there was a visible frame drop with CBOR. I noticed a similar frame drop in rviz on the same cloud.
To summarize, when CBOR compression is used, ROS3DJS has the same capacity for rendering point clouds as rviz.
Web Socket Compression
To make CBOR message wire size as small as possible, I made a PR to enable per-message deflate algorithm on the web socket server. This should result in smaller messages than PNG compression where wire size is a concern (not connecting to localhost).
This compression technique is better than PNG compression because it is handled by the browser before the message makes it to the JavaScript main thread.
Implementation
CBOR works best when transmitted as a binary web socket message, so I took some liberty with the protocol. Instead of sending a JSON message with a base64 string of CBOR data, the server sends an unwrapped binary protocol message.
On the client side, this message is received as an
ArrayBuffer
and the CBOR decoder is run on it directly to produce an object, just like the JSON decoder. From there, everything works the same.I produced some code to support typed array tags:
Backwards Compatibility
Since CBOR is completely opt-in (the server will never send a CBOR binary message unless the client requests it), clients without CBOR decoding support are safe from newer server versions.
If the client requests CBOR but it is not available on the server side, the server will send JSON messages instead.
When to use CBOR
CBOR is not ideal for all messages and transports, but it's safe to say that it's the best choice for any message containing a large amount of binary data when using roslibjs in a browser.
JSON is still faster and better for small messages such as transforms, or messages containing mostly strings.
PNG is best in some specific edge cases. It is still potentially the smallest wire size where transport compression is not available, depending on the data. When the data is mostly redundant, e.g. an array full of zeros, PNG messages can be smaller and decode faster than CBOR, because the deflate algorithm is efficient in this case, but when the data is more random, PNG will often have a larger wire size and longer decoding time than regular JSON compression. This makes it a poor choice for PointCloud2 and situationally useful for Image or OccupancyGrid.
The text was updated successfully, but these errors were encountered: