# Organizing point cloud from HDL-32E

Hi there,

in order to accelerate the data processing on my HLD-32E I would like to organized the data. To this point, I could, under Octave, compute manually an point cloud. But I do actually have no idea how to implement it in C++ and the suggested functions, such as KDTree, don't seems to be fast enough for this task...

Is there somewhere a topic giving information about how to work with those Point clouds in ROS?

edit retag close merge delete

Sort by » oldest newest most voted

Are you using the ROS velodyne stack to provide the data?

If so, the velodyne_pointcloud package handles converting the raw data packets received from the device into ROS sensor_msgs/PointCloud2 messages. The HDL-32E spews out about 700,000 points per second in a highly permuted order, the HDL-64E provides about 1,000,000 points per second in a very different and less regular order. So, velodyne_pointcloud keeps things simpler by always producing "unordered" point clouds as the data arrive from the device.

To prevent that unordered representation from losing useful information, velodyne_pointcloud publishes its data using a custom PCL point definition: velodyne_pointcloud::PointXYZIR, defined in the velodyne_pointcloud/point_types.h header. A PointXYZIR differs from the standard PCL PointXYZI (X, Y, Z, and intensity) in adding an additional field containing the "laser ring number" from which the point was measured.

Each ring number corresponds to a device-specific laser number, but the numbers are reordered so that ring 0 corresponds to the innermost laser (at the lowest angle) and ring 31 corresponds to the outermost laser (at the highest angle) of a 32E (that would be ring 63 on a 64E). That encoding ensures that adjacent lasers are labelled with adjacent ring numbers, which is not at all true of the hardware laser numbers. The actual mapping is defined in the velodyne_driver/ring_sequence.h header, provided by the velodyne_driver package. The permutation for a 32E is the same as the first 32 lasers of the 64E, so the same conversions work for both.

So, it should theoretically be possible to produce an ordered point cloud from the unordered PointXYZIR data by using the ring numbers as rows in a 2D representation. I have not heard of anyone actually doing that, and I suspect that the results might become somewhat confused when the device is in motion.

more

Sorry for the long delay, but it could finaly organize the pointcloud and now I can segment and classify the point cloud in less than 0.2s ;)

( 2013-07-03 07:54:50 -0500 )edit

@Dexter111 Do you mind describing how you were able to do that? Did you use PCL at all?

( 2013-07-18 10:22:19 -0500 )edit

Hi. I need the pointcloud from Velodyne VLP16. You mentioned that "velodyne_pointcloud publishes its data using a custom PCL point definition: velodyne_pointcloud::PointXYZIR". Do you mean that is a topic? After I do roslaunch "velodyne_pointclound VLP16_points.launch", nothing like that are found

( 2016-10-23 05:56:08 -0500 )edit

For Velodyne VLP16, nothing like velodyne_pointcloud::PointXYZIR are published. Please tell me why

( 2016-10-24 06:01:28 -0500 )edit

The topic name is /velodyne_points

( 2016-10-24 10:16:41 -0500 )edit
1

I don't know if this is still useful for you, but I wrote some code with PCL to organize a VLP16 point cloud and now I have a 16xN point cloud. I am still doing some tests, but you can find my code here: https://github.com/claydergc/vlp16_po...

( 2017-05-26 16:34:20 -0500 )edit

@claydergc, did you ever get that code fully functional? I've tried it out but haven't been able to get it working so far.

( 2019-03-07 14:16:42 -0500 )edit

TL;DR: Use the function I wrote here: organize_velodyne_cloud

I had to solve this problem recently in order to use the cloud for mesh creation with the Point Cloud Library (PCL). At the time I couldn't find anyone else who had solved this problem, so I had to write the code myself following the suggestions here from @joq. I've added to core functions to the repo linked above, as they're a bit too long to put here. Hopefully this will save anyone after me ~1-2 weeks effort.

How it works is this: every Velodyne LiDAR unit fires its lasers in a pre-defined sequence that repeats. E.g. 0, 16, 1, 17, 2, 18... But not every laser beam returns to the unit, so some parts of the cloud need to be filled in with points whose coordinates are NaN to preserve the organized nature of the cloud. My function creates a 2D organized cloud where there is one row for each "ring" of velodyne data. It then fills in each row, tracking how many points are in each row, i.e. what "column" of data is currently being filled in. When it moves from one column of data to the next, it fills in any gaps with NaN points.

Be careful how you use the organized cloud after this, as some PCL functions will crash if you input a cloud with NaNs, or worse, silently destroy the organized nature of the cloud without warning you.

more

@M@t: would this be something to contribute to some more visible package? I'm thinking laser_filters or something similar, but then for lidars. Perhaps even the velodyne package itself?

( 2019-03-28 11:00:29 -0500 )edit

That might certainly be a good idea, the velodyne package would be the best fit as the function depends on the specific operation of Velodyne LiDARs. How time consuming is that process likely to be? Unfortunately I have precious little spare time right now.

( 2019-03-28 15:27:34 -0500 )edit

re: time: no idea. I'd suggest just opening an issue on the velodyne tracker and seeing whether there is any interest.

( 2019-03-28 15:29:09 -0500 )edit

An organized point cloud is just a point cloud where some information about the sensor that captured the "depth image" is given. E.g. for a kinect with a resolution of 640 x 480 pixels, the properties of an organized point cloud would be set to

width: 640
height 480
isOrganized = true.


Internally, the point cloud stores all 3D points in a vector that contains

point(0,0), point(1,0), ..., point(638, 0), point(639,0),
point(0,1), point(1,1), ..., point(638, 1), point(639,1),
...
point(0,479), point(1,479), ..., point(638, 479), point(639,479)


The important bit is that all measured points have to be stored in the point cloud. As soon as some (invalid, ...) points are filtered, the cloud is no longer organized.

So if you have a laser that e.g. provides 1.000 points per line and scans 500 lines per "picture" (?), you'd just push_back the data points into the point cloud in the order which they were acquired (starting with the first one of the first line, ending with the last on eof the last line). Then set width to 1.000, height to 500, and voila!

Disclaimer: I haven't worked with lasers much, so apologies for the poor terminology! The above of course only makes sense when there's no motion in the scene during the time all lines are captured...

more