SICKAG / sick_scan_xd

Based on the sick_scan drivers for ROS1, sick_scan_xd merges sick_scan, sick_scan2 and sick_scan_base repositories. The driver supports both Linux (native, ROS1, ROS2) and Windows (native and ROS2).
Apache License 2.0
89 stars 81 forks source link

Python Performance with SICK LMS4000 #323

Closed gsainsbury86 closed 1 month ago

gsainsbury86 commented 2 months ago

We are working with two SICK LMS4000 devices and using the Python API on nVidia Jetson hardware. The goal is to have the LiDAR mounted on a vehicle and drive it over field crops while the LiDAR is pointed down (nadir) to record the crops.

In the minimum_sick_scan_api_client.py example, the program registers a callback and prints when the message is received. When we run this on our hardware, over 10s we receive ~5100 callbacks i.e. 510Hz. However, if we try to do anything with the data, we cannot "keep up" with the advertised 600Hz of the LiDAR. For instance, even just copying the message buffer, it drops to around ~400Hz, or if we try to write that data to disk, it drops even further to 150-200Hz throughput.

I can see that in the sick_scan_xd_api_test.py there is a comment which says : # Note: Pointcloud conversion and visualization consumes cpu time, therefore we convert and publish the cartesian pointcloud with low frequency. but we are not doing any conversion in real time. We want to be able to save/serialize the data so that we can re-construct the point cloud after scanning has completed, is there an efficient way to do that using the Python API?

gsainsbury86 commented 2 months ago

I'll reply to myself here to say that if I run the script for longer than 10s (e.g. 60 seconds), I get much closer to the expected data rate (~585Hz).

rostest commented 2 months ago

Thanks for your feedback. Please note that running multiple lidars in one application using the API is currently not supported (https://github.com/SICKAG/sick_scan_xd/blob/develop/doc/sick_scan_api/sick_scan_api.md):

image

To run two LMS4000 devices simultaneously via the API, two separate processes should be used (one process for each lidar). We recommend using ROS-1 or ROS-2 to run more than one lidar.

The use of ROS or C++ can be advantageous for performance critical data handling. Using ROS, you can e.g. use rosbag to easily store and replay all messages. If using ROS-1 or ROS-2 is an option, consider using ROS to run your devices.

gsainsbury86 commented 2 months ago

Thanks for the reply. We ran the two of them in seprate processes. (e.g. ./examples/cpp/build/minimum_sick_scan_api_client <launchfile> hostname:=<lidar-ip-address-of-lidar-1> & ./examples/cpp/build/minimum_sick_scan_api_client <launchfile> hostname:=<lidar-ip-address-of-lidar-2>

It's worth noting that whether I was running either one or two LiDAR, the result was the same. A lower throughput than expected. What did seem to work though, was running them for more than a short burst. I suspect there is some warm-up time?

rostest commented 2 months ago

Thanks for your reply and additional information. There is a small delay of a few seconds after the start (i.e. after calling SickScanApiInit) due to the SOPAS initialisation of the lidar. After this initialisation phase, the message frequency (i.e. the number of calls to the callback function per second) should be almost constant.

If data processing reduces the message frequency, it is generally recommended to do all data processing in one or more background threads. Note that the implementation in sick_scan_xd_api_test.py is just an example to demonstrate the memory layout of the scan data and how to access scan points. It is not intended for real-time processing with high frequency.

gsainsbury86 commented 1 month ago

Thanks for your advice! We've had some success running the lidars and do the processing asynchronously.