Closed bertulli closed 1 week ago
Thanks for your feedback. The sick_scan_xd driver stores each UDP scan data telegram from the lidar in an internal FIFO buffer for further processing in a different thread. If the CPU can't process all incoming telegrams, the FIFO buffer size will increase. If the FIFO size reaches a given limit, telegrams will be dropped. The max. FIFO size can be set by parameter "udp_input_fifolength" in the launchfile (20 telegrams by default).
Note that picoScan lidars send their scan data in segments, i.e. a 276 degree full scan is sent in several segments and telegrams. The sick_scan_xd driver accumulates, converts and publishes these segments into full 276 degree point clouds. If telegrams are dropped, the full point cloud cannot be computed and will be dropped as well.
If your picoScan model supports interval filtering, this filter can be used to reduce the telegram frequency to every N-th scan. Set parameter host_set_LFPintervalFilter to True in the launchfile and configure parameter host_LFPintervalFilter to an appropriate value.
Note that running multiple lidars simultaneously in a single process is not supported by the sick_scan_xd API. To run multiple lidars simultaneously, we recommend using ROS or running sick_scan_xd in multiple and separate processes, so that each process serves one sensor. See multiple_lidars.md for details.
Thanks!
We are already using two different processes to read and process the incoming data.
In the example launch
file for the PicoScan, I can't find any parameter named host_set_LFPintervalFilter
(actually, I only see it for the MultiScan). How can I check if my device supports it?
In any case, it's not clear to me what happens when there are messages in the FIFO. In our application we are using the native Linux C API (no ROS), and we are only registering the callback for the full point cloud. Let's say a full cloud is made up of 15 telegrams. Given the default FIFO size of 20 telegrams, while we are still processing the first cloud, upon the new scan only 5 new telegrams can be hosted in the queue. Are the other 15 dropped? Or do they replace the ones in the FIFO?
If they replace them, can I still safely assume that inside the callback function, the message data won't change (I assume the data is copied)?
If, on the other hand, they are dropped, what happens when the CPU is free again? Will it drop the 5 "partial" packets, and proceed to wait for the next full cloud available?
Thanks.
Thanks for your follow up. The input FIFO decouples data receiving and data processing. The receiver thread receives UDP packets, collects incoming UDP data until a complete telegram is received and pushes each telegram into the input FIFO. Another thread pops each telegram from the FIFO, processes its data (including data parsing, conversion to cartesian coordinates and accumulation into full point clouds) and pushes the (segmented or fullframe) point cloud to an output FIFO. A third thread exports the point clouds (i.e. publishes point cloud messages on ROS resp. executes the registered callbacks). This way data receiving, processing and export is running concurrently to get a higher data throughput.
If the CPU can process each telegram, there will be no drops. If the receiver thread pushes more telegrams than the data processing thread can pop from the input FIFO, incoming telegrams are dropped. In this case both segment and full frame point clouds will be lost. If the input FIFO has reached its limit (20 telegrams by default), incoming telegrams are dropped. They do not replace telegrams in the FIFO.
If the lidar sends more UDP packets than the receiver thread can handle, incoming UDP packets will be lost. In this case the whole telegram will be discarded.
The purpose of the input and output FIFO is to receive and process the scan data concurrently to maximize the throughput. They are not intended to prevent drops. We recommend to set an Interval Filter to avoid possible drops in case of cpu limitations. Use SOPAS Air, i.e. open the ip address of your lidar in a browser, to check and configure filter settings on the lidar. Store the new settings in the lidars EEPROM to make them persistent. The configuration of the Interval Filter by launch file (parameter host_LFPintervalFilter and host_set_LFPintervalFilter) will be supported in the next release. Make sure the latest firmware version is installed on the lidar.
Note that the point cloud API callbacks receive both segmented and fullframe point clouds. The segment_idx in the point cloud message contains either the index of the segment, or -1 for the full frame point cloud. Ignore any messages with segment_idx >= 0, if you are only interested in full frame point clouds.
Thank you, it's clearer now.
We already implemented a check to only look at full cloud messages (by comparing the content of msg->topic
), by I presume your suggestion is faster, so we'll look into that.
As per the IntervalFilter, I don't know if it's feasible for us, because we would still need to carefully match (or conservatively underestimate) the processing frequency of the CPU, otherwise the FIFO would still eventually fill up. If I understood correctly your explanation, this behavior (which now is surely happening, as the FIFO is full) leads to fullframe clouds to be both dropped, and "lagged behind", as the data that entered the FIFO is very probably representing a "past" scan of the LiDAR.
A suggestion I can make is this: what happens if, instead of using the callback, we use the WaitNext functions? For instance, I see in the example sick_scan_xd_api_test.cpp
while(run_flag && *run_flag)
{
// Get/poll the next cartesian PointCloud message
int32_t ret = SickScanApiWaitNextCartesianPointCloudMsg(*apiHandle, &pointcloud_msg, wait_next_message_timeout);
if (ret == SICK_SCAN_API_SUCCESS)
apiTestCartesianPointCloudMsgCallback(*apiHandle, &pointcloud_msg);
else if (ret != SICK_SCAN_API_SUCCESS && ret != SICK_SCAN_API_TIMEOUT)
printf("## ERROR sick_scan_xd_api_test: SickScanApiWaitNextCartesianPointCloudMsg failed\n");
SickScanApiFreePointCloudMsg(*apiHandle, &pointcloud_msg);
}
What are the effects of the FIFO being full in this case?
Thanks.
Thank you for your reply. Unfortunately, using one of the WaitNext functions won't help. To compute a full-frame point cloud, all previous telegrams and segments for that point cloud must be fully processed. The WaitNext functions just return the next point cloud after completion in the background; using them won't reduce the CPU usage.
Your understanding of telegram drops in case of a full input FIFO is correct. Whenever a telegram is dropped, the corresponding segment and full frame point cloud cannot be computed and will be dropped, too.
The cpu usage of sick_scan_xd is approximately constant and inversely proportional to N (where N is the parameter of the interval filter, i.e. every Nth scan is computed). I suggest you measure the cpu usage on your target when sick_scan_xd is running standalone (e.g. with sick_scan_xd_api_test.cpp) and configure the interval filter to a value that results in an acceptable cpu usage without drops.
You can use msg->topic or msg->segment_idx to get the full point cloud messages; both checks are equivalent.
Thank you for the clarification. If I understand correctly then, registering the callback is roughly equivalent to using a thin wrapper thread that continuously calls the WaitNext functions. If this is the case, I agree that the best option is to reduce the frequency, that additionally will lower the CPU load.
Just to make sure I understood, the net effect of the FIFO right now (i.e., maximum and excessive frequency) is like this (I only draw the assembled FullframeClouds):
So in the end, the clouds we are seeing right now after the initial temporary startup are already at reduced frequency (see last note), and trying to "catch up in time"? Reducing the frequency would achieve the same effect, but
Did I understand everything?
Thanks!
Thanks for following up. The picoScan lidar sends UDP packets. Subsequent UDP packets form a telegram in the compact format (see https://cdn.sick.com/media/docs/3/23/623/technical_information_data_format_description_en_im0104623.pdf for full details). Typically such a telegram contains the scan data of one segment. A couple of segments make up a complete scan (typically 9 segments for picoScan lidars).
The input FIFO collects the compact telegrams. The export FIFO collects the segmented and full frame point clouds. A typical sequence looks like this:
If the CPU cannot process all telegrams due to high CPU load, the input FIFO fills up with telegrams. Whenever the FIFO reaches its limit, the udp_receiver_thread cannot push a telegram on top of the FIFO and the telegram is dropped. In this case both the segment point cloud and the full frame point cloud cannot be computed. To calculate the full point cloud, all 9 previous segments are required; thus the "SegmentCollector" cannot collect all seqments required for a full point cloud. Note that incoming telegrams are pushed as they are received. They are not reordered to prioritise chains of subsequent segments to build a full scan.
If the average rate of incoming telegrams is higher than the CPU can process, telegrams will be permanently dropped. In this case, the callback will receive the remaining segment point clouds, but most likely no full scans. For example, if 50% of all telegrams are dropped, the callback will be executed with 50% of the segment point clouds, but no full point clouds. To get full scans, telegram drops must be avoided. It is recommended to use the interval filter to reduce the scan rate, such that the system runs without (or with very few) telegram drops.
Thank you, you explained it perfectly. Now it's clear to me why our application was struggling in processing only FullframeClouds (and now I wonder how could we process any at all). We'll try lowering the frequency with the filter. I'll leave this issue open just in case we'll have problems with that, but I'm confident it can be closed otherwise. Thank you again!
Hi, thanks for your work.
We are using a relatively slow CPU (single threaded, ~700MHz) due to power saving, and we integrated in our system two SICK PicoScan150. I couldn't find any information in the documentation: what happens in cases like this?
Here, you see that the frequency at which the LiDAR is sending data point clouds to the CPU is much higher than the frequency at which the CPU is processing them. When the CPU finishes the first processing and receives the cloud 10, what happens? Does it process cloud 10 (dropping packets 2 to 9), or cloud 2 (and then 3, and so on)? Since our use case requires to process cloud 10, and simply skip the intermediate ones, do we have to implement a manual check?
Thanks!