Skip to content
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

Add cbor-raw compression #452

Merged
merged 2 commits into from
Jan 8, 2020
Merged

Conversation

janpaul123
Copy link

@janpaul123 janpaul123 commented Jan 4, 2020

The CBOR compression is already a huge win over JSON or PNG encoding, but it’s still suboptimal in some situations. This PR adds support for getting messages in their raw binary (ROS-serialized) format. This has benefits in the following cases:

  • Your application already knows how to parse messages in bag files (e.g. using rosbag.js), which means that now you can use consistent code paths for both bags and live messages.
  • You want to parse messages as late as possible, or in parallel, e.g. only in the thread or WebWorker that cares about the message. Delaying the parsing of the message means that moving or copying the message to the thread is cheaper when its in binary form, since no serialization between threads is necessary.
  • You only care about part of the message, and don't need to parse the rest of it.
  • You really care about performance; no conversion between the ROS binary format and CBOR is done in the rosbridge_sever.

For Webviz we care about all of these cases, and so we’d really like to be able to use raw binary ROS messages.

This seemed easy to support by extending the current CBOR-format. We simply encode the outgoing_msg (which contains stuff like the operation and the topic name) with CBOR, just like with the existing CBOR encoding. The only difference is that in the current CBOR encoding, the “msg” field is itself a CBOR structure that encodes the message, where in our encoding it’s a CBOR object that contains a “bytes” field, which is just a bytearray with the raw binary message.

Besides the “bytes” fields we also added “secs” and “nsecs” fields with the current time, which is useful when using use_sim_time set to true. Webviz needs this to properly show the simulated received time of messages.

Now that we have the raw messages, we need to be able to parse them on the client. Bags contain the raw message definitions as stored on the ._full_text field on message instances, so we added a service call for accessing these raw message definitions for all topics in one call.

With both of these changes combined, you can now easily parse messages as late, parallel, partially, and fast as possible. In Webviz we intend to use this by either using rosbag.js or by parsing using the ROS deserializer compiled to WebAssembly, and by doing this in the WebWorker that actually controls the 3d canvas using the OffscreenCanvas API. This way we can have multiple rendering surfaces running from parallel threads. We already do this for some panels in Webviz, such as the Image panel, and we’ve seen substantial speedups with this method.

We also made a companion PR to roslibjs.

Documentation: we updated the ROSBRIDGE_PROTOCOL.md file with the new changes.

Test plan: we added a new test for the WebSocket server, modeled after the existing test. We also tested this end-to-end with our Webviz client, and it seems to work great.

Thanks to @vadimg for helping with this.

The CBOR compression is already a huge win over JSON or PNG encoding,
but it’s still suboptimal in some situations. This PR adds support for
getting messages in their raw binary (ROS-serialized) format. This has
benefits in the following cases:
- Your application already knows how to parse messages in bag files
  (e.g. using [rosbag.js](https://github.com/cruise-automation/rosbag.js),
  which means that now you can use consistent code paths for both bags
  and live messages.
- You want to parse messages as late as possible, or in parallel, e.g.
  only in the thread or WebWorker that cares about the message. Delaying
  the parsing of the message means that moving or copying the message to
  the thread is cheaper when its in binary form, since no serialization
  between threads is necessary.
- You only care about part of the message, and don't need to parse the
  rest of it.
- You really care about performance; no conversion between the ROS
  binary format and CBOR is done in the rosbridge_sever.

For [Webviz](https://webviz.io) we care about all of these cases, and so
we’d really like to be able to use raw binary ROS messages.

This seemed easy to support by extending the current CBOR-format. We
simply encode the `outgoing_msg` (which contains stuff like the
operation and the topic name) with CBOR, just like with the existing
CBOR encoding. The only difference is that in the current CBOR encoding,
the “msg” field is itself a CBOR structure that encodes the message,
where in our encoding it’s a CBOR object that contains a “bytes” field,
which is just a bytearray with the raw binary message.

Besides the “bytes” fields we also added “secs” and “nsecs” fields with
the current time, which is useful when using `use_sim_time` set to true.
Webviz needs this to properly show the simulated received time of
messages.

Now that we have the raw messages, we need to be able to parse them on
the client. Bags contain the raw message definitions as stored on the
`._full_text` field on message instances, so we added a service call for
accessing these raw message definitions for all topics in one call.

With both of these changes combined, you can now easily parse messages
as late, parallel, partially, and fast as possible. In Webviz we intend
to use this by either using [rosbag.js](https://github.com/cruise-automation/rosbag.js)
or by parsing using the ROS deserializer compiled to WebAssembly, and by
doing this in the WebWorker that actually controls the 3d canvas using
the OffscreenCanvas API. This way we can have multiple rendering
surfaces running from parallel threads. We already do this for some
panels in Webviz, such as the Image panel, and we’ve seen substantial
speedups with this method.

We’ll post a companion PR to roslibjs.

Documentation: we updated the ROSBRIDGE_PROTOCOL.md file with the new
changes.

Test plan: we added a new test for the WebSocket server, modeled after
the existing test. We also tested this end-to-end with our Webviz
client, and it seems to work great.
janpaul123 pushed a commit to janpaul123/roslibjs that referenced this pull request Jan 4, 2020
And a `getTopicsAndRawTypes` service function.

This is a companion PR to RobotWebTools/rosbridge_suite#452.
Please see that PR for more details and motivation.
@mvollrath mvollrath self-requested a review January 6, 2020 14:23
Copy link
Contributor

@mvollrath mvollrath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@janpaul123
Copy link
Author

Awesome, thanks for reviewing! How does the release process usually work? Do you need another reviewer or can you merge this? And could you then cut a new version? Would that show up in apt-get and such? Sorry, I'm a bit of a noob when it comes to how ros/linux packages work. 😄

@mvollrath
Copy link
Contributor

I can merge this soon.

The next release should be pretty soon. Since the last release we changed the default websocket server library, so we want to be confident that everything has shaken loose. I'll be following up on that.

Once we tag a new release we will release it to ROS via bloom. ROS will then sync it as part of their release cycle, it usually happens every two weeks. See their discourse (for melodic) for details. Then it will be the new apt default.

@janpaul123
Copy link
Author

Awesome, that makes a lot of sense, thanks for explaining!

@mvollrath mvollrath merged commit dc7fcb2 into RobotWebTools:develop Jan 8, 2020
mvollrath pushed a commit to RobotWebTools/roslibjs that referenced this pull request Jan 8, 2020
Add cbor-raw compression and a `getTopicsAndRawTypes` service function.

This is a companion PR to RobotWebTools/rosbridge_suite#452.
Please see that PR for more details and motivation.
@janpaul123
Copy link
Author

Hey @mvollrath, any idea when you might have time to do some thorough testing (because of the new websocket library) and release? 😄 That way I can schedule some time to make the necessary changes on the Webviz side for this.

@janpaul123
Copy link
Author

Hey @mvollrath and @jihoonl — just another quick ping on if you think a release might happen soon, because then we can switch Webviz to use this new protocol which would be super useful for us!

@jihoonl
Copy link
Member

jihoonl commented Feb 20, 2020

on my way

@jihoonl
Copy link
Member

jihoonl commented Feb 20, 2020

@janpaul123
Copy link
Author

@jihoonl Thanks a bunch!! I'll update Webviz soon.

janpaul123 pushed a commit to cruise-automation/webviz that referenced this pull request Apr 9, 2020
Changelog:
- Added support for streaming a second bag using the `remote-bag-url-2` query parameter in the URL. #374
- Fixed crashing on bags with topics that don't have a message definition. #373
- Various performance improvements.
- Improved caching of deserialized messages should result in fewer browser crashes.
- Added `unlimitedMemoryCache` experimental feature to load everything in memory without regard for caching limits. Useful for when you have a machine with lots of memory and you're explicitly OK with Webviz taking up a lot of it. Use at your own risk; this might crash your browser!
- Included an "Add Topics" option for adding markers to the Image panel.
- Made performance improvements to the Plot and State Transitions panels. If you notice any issues, these performance improvements can be disabled in the Experimental Features menu, under "Use a web worker to render the Plot panel".
- In the Image panel, we again filter available marker topics by the namespace of the currently selected camera.
- Added support for publishing messages over the Websocket connection using a Publish panel. #323
- Added layout undo/redo shortcuts.
- Added support for transforms from [`/tf_static`](http://wiki.ros.org/tf2/Tutorials/Writing%20a%20tf2%20static%20broadcaster%20%28C%2B%2B%29). #336
- Deployed a faster format for displaying text in the 3D panel. You can now use `ctrl-f` (or Mac equivalent) to physically move the camera to matched text. If you notice any issues, this change can be disabled in the Experimental Features menu, under "Faster 3D Text".
- Fixed Webviz getting stuck in a reloading loop.
- Added support for streaming a second bag using the `remote-bag-url-2` query parameter in the URL. #374
- Fixed crashing on bags with topics that don't have a message definition. #373
- Fixed not always loading messages when subscribing to a new topic when paused ("backfilling").
- Improved caching of deserialized messages should result in fewer browser crashes.
- Improved startup time by not making multiple requests with different topics when loading the page.
- Fix some cases in which "syncing" 3d panels could cause panels to display a blank screen.
- Fixed not always loading messages when subscribing to a new topic when paused ("backfilling").
- Switched Websocket message encoding to [cbor-raw](RobotWebTools/rosbridge_suite#452). #361
janpaul123 added a commit to cruise-automation/webviz that referenced this pull request Apr 9, 2020
Changelog:
- Added support for streaming a second bag using the `remote-bag-url-2` query parameter in the URL. #374
- Fixed crashing on bags with topics that don't have a message definition. #373
- Various performance improvements.
- Improved caching of deserialized messages should result in fewer browser crashes.
- Added `unlimitedMemoryCache` experimental feature to load everything in memory without regard for caching limits. Useful for when you have a machine with lots of memory and you're explicitly OK with Webviz taking up a lot of it. Use at your own risk; this might crash your browser!
- Included an "Add Topics" option for adding markers to the Image panel.
- Made performance improvements to the Plot and State Transitions panels. If you notice any issues, these performance improvements can be disabled in the Experimental Features menu, under "Use a web worker to render the Plot panel".
- In the Image panel, we again filter available marker topics by the namespace of the currently selected camera.
- Added support for publishing messages over the Websocket connection using a Publish panel. #323
- Added layout undo/redo shortcuts.
- Added support for transforms from [`/tf_static`](http://wiki.ros.org/tf2/Tutorials/Writing%20a%20tf2%20static%20broadcaster%20%28C%2B%2B%29). #336
- Deployed a faster format for displaying text in the 3D panel. You can now use `ctrl-f` (or Mac equivalent) to physically move the camera to matched text. If you notice any issues, this change can be disabled in the Experimental Features menu, under "Faster 3D Text".
- Fixed Webviz getting stuck in a reloading loop.
- Fixed not always loading messages when subscribing to a new topic when paused ("backfilling").
- Improved startup time by not making multiple requests with different topics when loading the page.
- Fix some cases in which "syncing" 3d panels could cause panels to display a blank screen.
- Switched Websocket message encoding to [cbor-raw](RobotWebTools/rosbridge_suite#452). #361
@nilsbore
Copy link

@janpaul123 Thanks for an awesome job on this. It enabled me to use native ROS deserialization of the websocket messages in my ROS C++ client library for Emscripten. Are there any plans to extend cbor-raw compression to other transports (services, publish)?

@janpaul123
Copy link
Author

janpaul123 commented May 29, 2020 via email

@mvollrath
Copy link
Contributor

I think this would do it: #428

MatthijsBurgh pushed a commit to RobotWebTools/roslibjs that referenced this pull request Jun 20, 2021
Add cbor-raw compression and a `getTopicsAndRawTypes` service function.

This is a companion PR to RobotWebTools/rosbridge_suite#452.
Please see that PR for more details and motivation.
jtbandes pushed a commit to foxglove/rosbridge_suite that referenced this pull request Jul 16, 2021
The CBOR compression is already a huge win over JSON or PNG encoding,
but it’s still suboptimal in some situations. This PR adds support for
getting messages in their raw binary (ROS-serialized) format. This has
benefits in the following cases:
- Your application already knows how to parse messages in bag files
  (e.g. using [rosbag.js](https://github.com/cruise-automation/rosbag.js),
  which means that now you can use consistent code paths for both bags
  and live messages.
- You want to parse messages as late as possible, or in parallel, e.g.
  only in the thread or WebWorker that cares about the message. Delaying
  the parsing of the message means that moving or copying the message to
  the thread is cheaper when its in binary form, since no serialization
  between threads is necessary.
- You only care about part of the message, and don't need to parse the
  rest of it.
- You really care about performance; no conversion between the ROS
  binary format and CBOR is done in the rosbridge_sever.
jtbandes added a commit that referenced this pull request Aug 3, 2021
This is an adaptation of #452 for ROS 2.

After the initial cherry-pick, a new implementation of the `/rosapi/get_topics_and_raw_types` service was required for ROS 2, because the generated Python msg classes don't contain the original/combined message definition (see related rosbag2 discussion at ros2/rosbag2#782). To accomplish this, I added a `stringify_field_types()` which reconstitutes a plausible .msg definition (although without constants or default values) based on the `_fields_and_field_types`, in the `====`-separated format seen in ROS 1 bags, which can be parsed by ROS 2 .msg parsers such as [@foxglove/rosmsg](https://github.com/foxglove/rosmsg).

I hope that `stringify_field_types` could be removed in the future if message generation is modified to output the original message definition text (ros2/ros2#1159) — I see it as a stopgap solution to get basic compatibility working.

I also modified `get_publications_and_types` to remove the extra `/msg/` from the ROS 2 IDL names, so `std_msgs/msg/String` becomes `std_msgs/String` when the list of topics and datatypes are retrieved. This is more in line with what clients migrating from ROS 1 expect.

I had to make a few launch file / parameter changes to get the `rosbridge_websocket_launch.xml` to work. The test from #452 is not included, because it needs significant work to port to ROS 2 and I noticed that some other tests are also disabled in this branch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants