stelzo / ros_pointcloud2

A PointCloud2 message conversion library for ROS1 and ROS2.

Home Page:https://crates.io/crates/ros_pointcloud2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

pack_rgb seems to be wrong

PatWie opened this issue · comments

Thanks for the work in this crate!
I am using it to visualize RGBA point-cloud scans. However, I observed wrongly produced colors. Debugging the output bytes I found the culprit to be (probably) in

fn pack_rgb(r: u8, g: u8, b: u8) -> f32 {

I did not open a pull-request yet, as I am lacking some confidence whether this is a foxglove visualization artifact or really a bug in this crate. The ROS documentation states

The fields are given as strings: "xyz" (3 floats), "rgb" (3 uchar stacked in a float), "rgba" (4 uchar stacked in a float)
is a bit unclear.

Here is a playground link:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e4315d3a5ce316b34beb2b498e8a433c
The output of the pack_rgb_fixed function (with u32) is what I consider reasonable. Patching this crate to use that u32-version indeed produces correctly colored rgba outputs in foxglove 3D view.

My understanding of the ROS documentation is that they do really simply stack these bytes but the wording is unclear. And who is really encoding 4x u8 in a float representation instead of u32 anyway?

Looking at
https://pointclouds.org/documentation/point__types_8hpp_source.html

 #define PCL_ADD_UNION_RGB \
   union \
   { \
     union \
     { \
       struct \
       { \
         std::uint8_t b; \
         std::uint8_t g; \
         std::uint8_t r; \
         std::uint8_t a; \
       }; \
       float rgb; \
     }; \
     std::uint32_t rgba; \
   };

it is really simply stacking bytes which would make pack_rgb_fixed having the correct behavior.

Thank you for the issue with clear description and playground link!

I also used the description from http://wiki.ros.org/rviz/DisplayTypes/PointCloudShared 0.0.2 and saw the C++ example.
I think I overlooked the difference of safe casting as f32 in Rust vs C++ reinterpret_cast<> in that example.

A possible fix could be to return u32 but set the metadata to f32 to keep it in sync with the ROS documentation. Maybe that is what you did in your patch? Making it u32 from the beginning would be the best choice of course but it could break C++ nodes receiving the PointCloud2 from the Rust node.
The only thing keeping me from merging this immediately is that the f32 version worked for me in RViz while testing.

@PatWie Did you also observe this behavior in RViz?

Did not test Rviz yet, as I try to avoid a ROS install on my system. But I will follow up on this and produce a MWE. Meanwhile, I did some digging in RViz source code for references

I am on travel 🙈and now need to remember:

  • don't push to prod on Friday
  • don't start traveling right after writing an issue

I my "fix" I really set the header field type to u32 (="6") along with the function signature change. But you are right! One probably has to produce a u32 and override this type field to f32 (or to use unsafe 🧟‍♂️).

Small update, I failed to get rviz running in docker. Will report once I get results in rviz. (I did not forget about this issue).

I finally had the time and a computer with rviz for debugging. It is a bug. There were too many colors when I tested it the first time, so it slipped through my fingers.

The PR will be published as v0.3.1, just update your version and it should work @PatWie .