68 std::vector<std::string> parameters;
70 std::map<std::string, std::string> key_value_pairs;
71 for(
int n = 0; n < parameters.size(); n++)
74 std::vector<std::string> key_value_pair;
76 if (key_value_pair.size() != 2)
78 ROS_ERROR_STREAM(
"## ERROR CustomPointCloudConfiguration(name=" << cfg_name <<
", value=" << cfg_str <<
"): can't parse " << parameters[n] <<
", expected key=value format, check configuration");
81 key_value_pairs[key_value_pair[0]] = key_value_pair[1];
82 ROS_DEBUG_STREAM(
"CustomPointCloudConfiguration(" << cfg_name <<
"): " << key_value_pair[0] <<
" = " << key_value_pair[1]);
85 m_publish = (key_value_pairs[
"publish"].empty() ? false : std::stoi(key_value_pairs[
"publish"]) > 0);
86 m_topic = key_value_pairs[
"topic"];
88 m_coordinate_notation = (key_value_pairs[
"coordinateNotation"].empty() ? 0 : std::stoi(key_value_pairs[
"coordinateNotation"]));
89 m_update_method = (key_value_pairs[
"updateMethod"].empty() ? 0 : std::stoi(key_value_pairs[
"updateMethod"]));
91 key_value_pairs[
"fields"] =
"x,y,z,i";
93 key_value_pairs[
"fields"] =
"azimuth,elevation,range,i";
95 key_value_pairs[
"fields"] =
"x,y,z,azimuth,elevation,range,i";
97 ROS_ERROR_STREAM(
"## ERROR CustomPointCloudConfiguration(name=" << cfg_name <<
", value=" << cfg_str <<
"): coordinateNotation has invalid value " <<
m_coordinate_notation <<
", check configuration");
98 if (!key_value_pairs[
"rangeFilter"].empty())
100 const std::string& range_filter_str = key_value_pairs[
"rangeFilter"];
101 std::vector<std::string> range_filter_args;
103 if(range_filter_args.size() == 3)
105 float range_min = std::stof(range_filter_args[0]);
106 float range_max = std::stof(range_filter_args[1]);
107 int range_filter_handling = std::stoi(range_filter_args[2]);
110 else if(!range_filter_args.empty())
112 ROS_ERROR_STREAM(
"## ERROR CustomPointCloudConfiguration(name=" << cfg_name <<
", value=" << cfg_str <<
"): rangeFilter has invalid value " << range_filter_str <<
", check configuration");
115 std::vector<std::string> fields;
116 std::vector<int> echos, layers, reflectors, infringed;
122 for(
int n = 0; n < layers.size(); n++)
126 fields = {
"x",
"y",
"z",
"i",
"range",
"azimuth",
"elevation",
"layer",
"echo",
"reflector" };
130 layers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
131 if (reflectors.empty())
132 reflectors = { 0, 1 };
133 if (infringed.empty())
134 infringed = { 0, 1 };
136 for(
int n = 0; n < fields.size(); n++)
138 for(
int n = 0; n < echos.size(); n++)
140 for(
int n = 0; n < layers.size(); n++)
142 for(
int n = 0; n < reflectors.size(); n++)
144 for(
int n = 0; n < infringed.size(); n++)
149 ROS_ERROR_STREAM(
"## ERROR CustomPointCloudConfiguration(name=" << cfg_name <<
", value=" << cfg_str <<
"): topic and frameid required, pointcloud will not be published, check configuration");
156 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): publish = " << m_publish);
157 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): topic = " << m_topic);
158 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): frameid = " << m_frameid);
159 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): coordinate_notation = " << m_coordinate_notation);
160 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): update_method = " << m_update_method);
161 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): fields_enabled = " << printValuesEnabled(m_field_enabled));
162 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): echos_enabled = " << printValuesEnabled(m_echo_enabled));
163 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): layers_enabled = " << printValuesEnabled(m_layer_enabled));
164 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): reflector_enabled = " << printValuesEnabled(m_reflector_enabled));
165 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): infringed_enabled = " << printValuesEnabled(m_infringed_enabled));
166 ROS_INFO_STREAM(
"CustomPointCloudConfiguration(" << m_cfg_name <<
"): range_filter = " << m_range_filter.print());
172 for(
auto iter = mapped_values.cbegin(); iter != mapped_values.cend(); iter++)
175 s << (
s.str().empty() ?
"" : delim) << iter->first;
183 for(
auto iter = mapped_values.cbegin(); iter != mapped_values.cend(); iter++)
186 s << (
s.str().empty() ?
"" : delim) << (
int)(iter->first);
197 std::vector<std::string> parameter_token;
201 if(parameter_token.size() >= 3 && std::stoi(parameter_token[0]) > 0)
203 float all_segments_azimuth_min_deg = std::stof(parameter_token[1]);
204 float all_segments_azimuth_max_deg = std::stof(parameter_token[2]);
205 m_all_segments_azimuth_min_deg = std::max<float>(m_all_segments_azimuth_min_deg, all_segments_azimuth_min_deg);
206 m_all_segments_azimuth_max_deg = std::min<float>(m_all_segments_azimuth_max_deg, all_segments_azimuth_max_deg);
210 catch(
const std::exception& e)
212 ROS_ERROR_STREAM(
"## ERROR in RosMsgpackPublisher: can't parse LFPangleRangeFilter settings, exception " << e.what() <<
", check LFPangleRangeFilter configuration in the launchfile");
224 std::vector<std::string> parameter_token;
228 if(parameter_token.size() >= 17 && std::stoi(parameter_token[0]) > 0)
230 float all_segments_elevation_min_deg = 999;
231 float all_segments_elevation_max_deg = -999;
232 for(
int n = 1; n < parameter_token.size(); n++)
234 if(std::stoi(parameter_token[n]) > 0)
237 all_segments_elevation_min_deg = std::min<float>(all_segments_elevation_min_deg, layer_elevation_deg);
238 all_segments_elevation_max_deg = std::max<float>(all_segments_elevation_max_deg, layer_elevation_deg);
241 if (all_segments_elevation_max_deg > all_segments_elevation_min_deg)
243 m_all_segments_elevation_min_deg = all_segments_elevation_min_deg;
244 m_all_segments_elevation_max_deg = all_segments_elevation_max_deg;
249 catch(
const std::exception& e)
251 ROS_ERROR_STREAM(
"## ERROR in RosMsgpackPublisher: can't parse initLFPlayerFilterSettings settings, exception " << e.what() <<
", check initLFPlayerFilterSettings configuration in the launchfile");
265 #if defined __ROS_VERSION && __ROS_VERSION > 1
270 m_frame_id =
config.publish_frame_id;
272 m_laserscan_layer_filter =
config.laserscan_layer_filter;
274 m_all_segments_azimuth_min_deg = (float)
config.all_segments_min_deg;
275 m_all_segments_azimuth_max_deg = (
float)
config.all_segments_max_deg;
276 m_host_FREchoFilter =
config.host_FREchoFilter;
277 m_host_set_FREchoFilter =
config.host_set_FREchoFilter;
278 if (
config.host_set_LFPangleRangeFilter)
280 initLFPangleRangeFilterSettings(
config.host_LFPangleRangeFilter);
282 if (
config.host_set_LFPlayerFilter)
284 initLFPlayerFilterSettings(
config.host_LFPlayerFilter);
286 std::string imu_topic =
config.imu_topic;
287 #if defined __ROS_VERSION && __ROS_VERSION > 1 // ROS-2 publisher
288 rosQoS qos = rclcpp::SystemDefaultsQoS();
289 QoSConverter qos_converter;
294 qos = qos_converter.convert(qos_val);
295 m_publisher_laserscan_segment = create_publisher<ros_sensor_msgs::LaserScan>(
config.publish_laserscan_segment_topic, qos);
296 ROS_INFO_STREAM(
"RosMsgpackPublisher: publishing LaserScan segment messages on topic \"" << m_publisher_laserscan_segment->get_topic_name() <<
"\"");
297 m_publisher_laserscan_360 = create_publisher<ros_sensor_msgs::LaserScan>(
config.publish_laserscan_fullframe_topic, qos);
298 ROS_INFO_STREAM(
"RosMsgpackPublisher: publishing LaserScan fullframe messages on topic \"" << m_publisher_laserscan_360->get_topic_name() <<
"\"");
301 if (imu_topic[0] !=
'/')
302 imu_topic =
"~/" + imu_topic;
303 m_publisher_imu = create_publisher<ros_sensor_msgs::Imu>(imu_topic, qos);
304 m_publisher_imu_initialized =
true;
305 ROS_INFO_STREAM(
"RosMsgpackPublisher: publishing Imu messages on topic \"" << m_publisher_imu->get_topic_name() <<
"\"");
307 #elif defined __ROS_VERSION && __ROS_VERSION > 0 // ROS-1 publisher
308 int qos = 16 * 12 * 3;
315 ROS_INFO_STREAM(
"RosMsgpackPublisher: publishing LaserScan segment messages on topic \"" <<
config.publish_laserscan_segment_topic <<
"\"");
317 ROS_INFO_STREAM(
"RosMsgpackPublisher: publishing LaserScan fullframe messages on topic \"" <<
config.publish_laserscan_fullframe_topic <<
"\"");
322 m_publisher_imu_initialized =
true;
323 ROS_INFO_STREAM(
"RosMsgpackPublisher: publishing Imu messages on topic \"" <<
config.imu_topic <<
"\"");
393 std::string custom_pointclouds =
"";
395 rosGetParam(m_node,
"custom_pointclouds", custom_pointclouds);
396 std::vector<std::string> custom_pointclouds_tokens;
398 for(
int n = 0; n < custom_pointclouds_tokens.size(); n++)
400 std::string custom_pointcloud_cfg_str =
"";
401 rosDeclareParam(m_node, custom_pointclouds_tokens[n], custom_pointcloud_cfg_str);
402 rosGetParam(m_node, custom_pointclouds_tokens[n], custom_pointcloud_cfg_str);
404 if (custom_pointcloud_cfg.
publish())
406 custom_pointcloud_cfg.
print();
407 #if defined __ROS_VERSION && __ROS_VERSION > 1 // ROS-2 publisher
408 custom_pointcloud_cfg.
publisher() = create_publisher<PointCloud2Msg>(custom_pointcloud_cfg.
topic(), qos);
409 #elif defined __ROS_VERSION && __ROS_VERSION > 0 // ROS-1 publisher
412 m_custom_pointclouds_cfg.push_back(custom_pointcloud_cfg);
428 for (
int echoIdx = 0; echoIdx < lidar_points.size(); echoIdx++)
430 s << (echoIdx > 0 ?
", " :
"") <<
"echo" << echoIdx <<
":[";
431 int last_elevation_mdeg = -99999, last_azimuth_ideg = -99999;
432 for (
int n = 0; n < lidar_points[echoIdx].size(); n++)
435 float elevation_deg = point.
elevation * 180.0f / (float)M_PI;
436 float azimuth_fdeg = point.
azimuth * 180.0f / (float)M_PI;
437 int elevation_mdeg = (int)(1000.0
f * elevation_deg);
438 int azimuth_ideg = (int)(azimuth_fdeg);
439 if (elevation_mdeg != last_elevation_mdeg || azimuth_ideg != last_azimuth_ideg)
440 s << (n > 0 ?
"," :
"") <<
" (" << (elevation_mdeg/1000) <<
"," << azimuth_ideg <<
")";
441 last_elevation_mdeg = elevation_mdeg;
442 last_azimuth_ideg = azimuth_ideg;
456 for (std::map<
int, std::map<int, int>>::const_iterator coverage_elevation_iter = elevation_azimuth_histograms.cbegin(); coverage_elevation_iter != elevation_azimuth_histograms.cend(); coverage_elevation_iter++)
458 int elevation_mdeg = coverage_elevation_iter->first;
459 const std::map<int, int>& azimuth_histogram = coverage_elevation_iter->second;
460 for (std::map<int, int>::const_iterator coverage_azimuth_iter = azimuth_histogram.cbegin(); coverage_azimuth_iter != azimuth_histogram.cend(); coverage_azimuth_iter++)
462 const int& azimuth_ideg = coverage_azimuth_iter->first;
463 const int& azimuth_cnt = coverage_azimuth_iter->second;
465 s <<
" (" << (elevation_mdeg/1000) <<
"," << azimuth_ideg <<
"),";
475 if (coordinate_notation == 0)
480 #if defined RASPBERRY && RASPBERRY > 0 // polar pointcloud deactivated on Raspberry for performance reasons
482 if (coordinate_notation == 1)
488 #if defined __ROS_VERSION && __ROS_VERSION > 1
489 publisher->
publish(pointcloud_msg);
490 #elif defined __ROS_VERSION && __ROS_VERSION > 0
491 publisher.
publish(pointcloud_msg);
492 #elif defined ROSSIMU
500 #if defined RASPBERRY && RASPBERRY > 0 // laserscan messages deactivated on Raspberry for performance reasons
502 for(LaserScanMsgMap::iterator laser_scan_echo_iter = laser_scan_msg_map.begin(); laser_scan_echo_iter != laser_scan_msg_map.end(); laser_scan_echo_iter++)
504 int echo_idx = laser_scan_echo_iter->first;
505 std::map<int,ros_sensor_msgs::LaserScan>& laser_scan_layer_map = laser_scan_echo_iter->second;
506 for(std::map<int,ros_sensor_msgs::LaserScan>::iterator laser_scan_msg_iter = laser_scan_layer_map.begin(); laser_scan_msg_iter != laser_scan_layer_map.end(); laser_scan_msg_iter++)
508 int layer_idx = laser_scan_msg_iter->first;
510 if (laser_scan_msg.ranges.size() > 0)
512 #if defined __ROS_VERSION && __ROS_VERSION > 1
513 laserscan_publisher->
publish(laser_scan_msg);
514 #elif defined __ROS_VERSION && __ROS_VERSION > 0
515 laserscan_publisher.
publish(laser_scan_msg);
542 uint32_t time_offset_nanosec = 0;
543 float time_offset_sec = 0;
544 uint32_t lidar_sec = 0;
545 uint32_t lidar_nsec = 0;
562 pointcloud_msg.header.stamp.sec = timestamp_sec;
563 #if defined __ROS_VERSION && __ROS_VERSION > 1
564 pointcloud_msg.header.stamp.nanosec = timestamp_nsec;
566 pointcloud_msg.header.stamp.nsec = timestamp_nsec;
568 pointcloud_msg.header.frame_id = pointcloud_cfg.
frameid();
571 std::vector<PointCloudFieldProperty> field_properties;
572 field_properties.reserve(12);
574 field_properties.push_back(
PointCloudFieldProperty(
"x", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.
x - (uint8_t*)&dummy_lidar_point));
576 field_properties.push_back(
PointCloudFieldProperty(
"y", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.y - (uint8_t*)&dummy_lidar_point));
578 field_properties.push_back(
PointCloudFieldProperty(
"z", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.z - (uint8_t*)&dummy_lidar_point));
580 field_properties.push_back(
PointCloudFieldProperty(
"i", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.i - (uint8_t*)&dummy_lidar_point));
582 field_properties.push_back(
PointCloudFieldProperty(
"range", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.range - (uint8_t*)&dummy_lidar_point));
584 field_properties.push_back(
PointCloudFieldProperty(
"azimuth", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.azimuth - (uint8_t*)&dummy_lidar_point));
586 field_properties.push_back(
PointCloudFieldProperty(
"elevation", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.elevation - (uint8_t*)&dummy_lidar_point));
590 field_properties.push_back(
PointCloudFieldProperty(
"ts", PointField::FLOAT32,
sizeof(
float), (uint8_t*)&dummy_lidar_point.time_offset_sec - (uint8_t*)&dummy_lidar_point));
605 int num_fields = field_properties.size();
606 size_t max_number_of_points = 0;
607 for (
int echo_idx = 0; echo_idx < lidar_points.size(); echo_idx++)
609 max_number_of_points += lidar_points[echo_idx].size();
611 pointcloud_msg.height = 1;
612 pointcloud_msg.width = max_number_of_points;
613 pointcloud_msg.is_bigendian =
false;
614 pointcloud_msg.is_dense =
true;
615 pointcloud_msg.point_step = 0;
616 pointcloud_msg.fields.resize(num_fields);
617 for (
int i = 0; i < num_fields; i++)
619 pointcloud_msg.fields[i].count = 1;
620 pointcloud_msg.fields[i].name = field_properties[i].name;
621 pointcloud_msg.fields[i].datatype = field_properties[i].datatype;
622 pointcloud_msg.fields[i].offset = pointcloud_msg.point_step;
623 pointcloud_msg.point_step += field_properties[i].datasize;
625 pointcloud_msg.row_step = pointcloud_msg.point_step * max_number_of_points;
626 pointcloud_msg.data.clear();
627 pointcloud_msg.data.resize(pointcloud_msg.row_step * pointcloud_msg.height, 0);
630 for (
int echo_idx = 0; echo_idx < lidar_points.size(); echo_idx++)
632 for (
int point_idx = 0; point_cnt < max_number_of_points && point_idx < lidar_points[echo_idx].size(); point_idx++)
634 CustomizedPointXYZRAEI32f cur_lidar_point(timestamp_sec, timestamp_nsec, lidar_timestamp_start_microsec, lidar_points[echo_idx][point_idx]);
637 size_t pointcloud_offset = point_cnt * pointcloud_msg.point_step;
638 const uint8_t* src_lidar_point = (
const uint8_t*)(&cur_lidar_point);
639 for(
int field_idx = 0; field_idx < field_properties.size(); field_idx++)
641 size_t field_offset = field_properties[field_idx].fieldoffset;
642 for (
int n = 0; n < field_properties[field_idx].datasize; n++, pointcloud_offset++, field_offset++)
644 pointcloud_msg.data[pointcloud_offset] = src_lidar_point[field_offset];
652 pointcloud_msg.width = point_cnt;
653 pointcloud_msg.row_step = pointcloud_msg.point_step * point_cnt;
654 pointcloud_msg.data.resize(pointcloud_msg.row_step * pointcloud_msg.height);
655 ROS_DEBUG_STREAM(
"CustomPointCloudConfiguration " << pointcloud_cfg.
cfgName() <<
": " << point_cnt <<
" points per cloud, " << num_fields <<
" fields per point");
668 LaserScanMsgMap& laser_scan_msg_map,
const std::string& frame_id,
bool is_fullframe)
670 #if defined RASPBERRY && RASPBERRY > 0 // laserscan messages deactivated on Raspberry for performance reasons
673 struct LaserScanMsgPoint
675 LaserScanMsgPoint(
float _range = 0,
float _azimuth = 0,
float _i = 0) : range(_range), azimuth(_azimuth), i(_i) {}
681 typedef std::vector<LaserScanMsgPoint> LaserScanMsgPoints;
682 typedef std::vector<LaserScanMsgPoints> LaserScanMsgSegments;
683 typedef std::map<int,std::map<int,LaserScanMsgSegments>> LaserScanMsgEchoLayerSegments;
684 typedef std::map<int,std::map<int,LaserScanMsgPoints>> LaserScanMsgEchoLayerSortedPoints;
685 struct SortSegmentsAscendingAzimuth
687 bool operator()(
const LaserScanMsgPoints& segment1,
const LaserScanMsgPoints& segment2) {
return !segment1.empty() && !segment2.empty() && segment1[0].azimuth < segment2[0].azimuth; }
689 struct SortSegmentsDescendingAzimuth
691 bool operator()(
const LaserScanMsgPoints& segment1,
const LaserScanMsgPoints& segment2) {
return !segment1.empty() && !segment2.empty() && segment1[0].azimuth > segment2[0].azimuth; }
693 struct ScanPointPrinter
695 static std::string printAzimuthTable(
const std::vector<sick_scansegment_xd::PointXYZRAEI32f>& points)
698 for (
int pointIdx = 0; pointIdx < points.size(); pointIdx++)
699 s << (pointIdx>0?
",":
"") << std::fixed << std::setprecision(1) << points[pointIdx].azimuth * 180.0 / M_PI;
702 static std::string printAzimuthTable(
const LaserScanMsgPoints& points)
705 for (
int pointIdx = 0; pointIdx < points.size(); pointIdx++)
706 s << (pointIdx>0?
",":
"") << std::fixed << std::setprecision(1) << points[pointIdx].azimuth * 180.0 / M_PI;
711 LaserScanMsgEchoLayerSegments points_echo_layer_segment_map;
712 for (
int echoIdx = 0; echoIdx < lidar_points.size(); echoIdx++)
714 int last_layer = INT_MAX;
715 float last_azimuth = FLT_MAX;
718 for (
int pointIdx = 0; pointIdx < lidar_points[echoIdx].size(); pointIdx++)
721 bool layer_enabled = (m_laserscan_layer_filter.empty() ? 1 : (m_laserscan_layer_filter[lidar_point.
layer]));
724 LaserScanMsgSegments& point_segment = points_echo_layer_segment_map[lidar_point.
echo][lidar_point.
layer];
725 if (point_segment.empty() || last_layer != lidar_point.
layer || std::abs(last_azimuth - lidar_point.
azimuth) > (2.0*M_PI/180.0))
726 point_segment.push_back(LaserScanMsgPoints());
727 point_segment.back().push_back(LaserScanMsgPoint(lidar_point));
728 last_layer = lidar_point.
layer;
729 last_azimuth = lidar_point.
azimuth;
735 LaserScanMsgEchoLayerSortedPoints sorted_points_echo_layer_map;
736 for(std::map<
int,std::map<int,LaserScanMsgSegments>>::iterator iter_echos = points_echo_layer_segment_map.begin(); iter_echos != points_echo_layer_segment_map.end(); iter_echos++)
738 const int& echo = iter_echos->first;
739 for(std::map<int,LaserScanMsgSegments>::iterator iter_layer = iter_echos->second.begin(); iter_layer != iter_echos->second.end(); iter_layer++)
741 const int& layer = iter_layer->first;
742 LaserScanMsgSegments& segments = iter_layer->second;
744 int segment_cnt_azimuth_ascending = 0, segment_cnt_azimuth_descending = 0;
745 for(
int segment_cnt = 0; segment_cnt < segments.size(); segment_cnt++)
747 const LaserScanMsgPoints& segment_points = segments[segment_cnt];
748 segment_cnt_azimuth_ascending += ((segment_points.size() > 1 && segment_points[0].azimuth < segment_points[1].azimuth) ? 1 : 0);
749 segment_cnt_azimuth_descending += ((segment_points.size() > 1 && segment_points[0].azimuth > segment_points[1].azimuth) ? 1 : 0);
753 if(segments.size() > 1)
755 if(segment_cnt_azimuth_ascending > 0 && segment_cnt_azimuth_descending > 0)
757 ROS_ERROR_STREAM(
"## ERROR convertPointsToLaserscanMsg(): " << segment_cnt_azimuth_ascending <<
" segments ordered by ascending azimuth, " << segment_cnt_azimuth_descending <<
" segments ordered by descending azimuth");
760 if (segment_cnt_azimuth_ascending > 0)
761 std::sort(segments.begin(), segments.end(), SortSegmentsAscendingAzimuth());
762 else if(segment_cnt_azimuth_descending > 0)
763 std::sort(segments.begin(), segments.end(), SortSegmentsDescendingAzimuth());
766 ROS_ERROR_STREAM(
"## ERROR convertPointsToLaserscanMsg(): " << segment_cnt_azimuth_ascending <<
" segments ordered by ascending azimuth, " << segment_cnt_azimuth_descending <<
" segments ordered by descending azimuth");
770 for(
int segment_cnt = 0; segment_cnt < segments.size(); segment_cnt++)
772 const LaserScanMsgPoints& segment_points = segments[segment_cnt];
773 sorted_points_echo_layer_map[echo][layer].insert(sorted_points_echo_layer_map[echo][layer].end(), segment_points.begin(), segment_points.end());
791 LaserScanMsgPoints sorted_points = sorted_points_echo_layer_map[echo][layer];
792 if (!sorted_points.empty())
795 laser_scan_msg.ranges.clear();
796 laser_scan_msg.intensities.clear();
797 laser_scan_msg.ranges.reserve(sorted_points.size());
798 laser_scan_msg.intensities.reserve(sorted_points.size());
799 laser_scan_msg.angle_min = sorted_points.front().azimuth;
800 laser_scan_msg.angle_max = sorted_points.back().azimuth;
801 laser_scan_msg.range_min = sorted_points.front().range;
802 laser_scan_msg.range_max = sorted_points.front().range;
803 float delta_azimuth_expected = (laser_scan_msg.angle_max - laser_scan_msg.angle_min) / std::max(1.0
f, (
float)sorted_points.size() - 1.0f);
804 for(
int point_cnt = 0; point_cnt < sorted_points.size(); point_cnt++)
806 laser_scan_msg.ranges.push_back(sorted_points[point_cnt].range);
807 laser_scan_msg.intensities.push_back(sorted_points[point_cnt].i);
808 laser_scan_msg.range_min = std::min(sorted_points[point_cnt].range, laser_scan_msg.range_min);
809 laser_scan_msg.range_max = std::max(sorted_points[point_cnt].range, laser_scan_msg.range_max);
823 int num_echos = (int)lidar_points.size();
825 for(LaserScanMsgMap::iterator laser_scan_echo_iter = laser_scan_msg_map.begin(); laser_scan_echo_iter != laser_scan_msg_map.end(); laser_scan_echo_iter++)
827 int echo_idx = laser_scan_echo_iter->first;
828 bool echo_enabled =
true;
830 if (m_host_set_FREchoFilter &&
num_echos > 1 && (m_host_FREchoFilter == 0 || m_host_FREchoFilter == 2))
832 num_echos_publish = 1;
833 if (m_host_FREchoFilter == 0 && echo_idx > 0)
834 echo_enabled =
false;
835 else if (m_host_FREchoFilter == 2 && echo_idx <
num_echos - 1)
836 echo_enabled =
false;
840 std::map<int,ros_sensor_msgs::LaserScan>& laser_scan_layer_map = laser_scan_echo_iter->second;
841 for(std::map<int,ros_sensor_msgs::LaserScan>::iterator laser_scan_msg_iter = laser_scan_layer_map.begin(); laser_scan_msg_iter != laser_scan_layer_map.end(); laser_scan_msg_iter++)
843 int layer_idx = laser_scan_msg_iter->first;
845 if (laser_scan_msg.ranges.size() > 1 && laser_scan_msg.angle_max > laser_scan_msg.angle_min)
847 float angle_diff = laser_scan_msg.angle_max - laser_scan_msg.angle_min;
848 while (angle_diff > (
float)(2.0 * M_PI))
849 angle_diff -= (float)(2.0 * M_PI);
850 while (angle_diff < 0)
851 angle_diff += (float)(2.0 * M_PI);
852 laser_scan_msg.angle_increment = angle_diff / (float)(laser_scan_msg.ranges.size() - 1);
853 laser_scan_msg.range_min -= 1.0e-03
f;
854 laser_scan_msg.range_max += 1.0e-03
f;
855 laser_scan_msg.range_min = std::max(0.05
f, laser_scan_msg.range_min);
858 laser_scan_msg.header.stamp.sec = timestamp_sec;
859 #if defined __ROS_VERSION && __ROS_VERSION > 1
860 laser_scan_msg.header.stamp.nanosec = timestamp_nsec;
861 #elif defined __ROS_VERSION && __ROS_VERSION > 0
862 laser_scan_msg.header.stamp.nsec = timestamp_nsec;
864 laser_scan_msg.header.frame_id = frame_id +
"_" + std::to_string(layer_idx + 1);
865 if (num_echos_publish > 1)
866 laser_scan_msg.header.frame_id = laser_scan_msg.header.frame_id +
"_" + std::to_string(echo_idx);
868 laser_scan_msg.scan_time = m_scan_time;
870 laser_scan_msg.time_increment = laser_scan_msg.scan_time / (float)(laser_scan_msg.ranges.size() * 2.0 * M_PI / angle_diff);
875 laser_scan_msg.ranges.clear();
876 laser_scan_msg.intensities.clear();
881 for(LaserScanMsgMap::iterator laser_scan_echo_iter = laser_scan_msg_map.begin(); laser_scan_echo_iter != laser_scan_msg_map.end(); )
883 int echo_idx = laser_scan_echo_iter->first;
884 bool echo_found =
false;
885 std::map<int,ros_sensor_msgs::LaserScan>& laser_scan_layer_map = laser_scan_echo_iter->second;
886 for(std::map<int,ros_sensor_msgs::LaserScan>::iterator laser_scan_msg_iter = laser_scan_layer_map.begin(); !echo_found && laser_scan_msg_iter != laser_scan_layer_map.end(); laser_scan_msg_iter++)
888 int layer_idx = laser_scan_msg_iter->first;
890 if (!laser_scan_msg.header.frame_id.empty() && !laser_scan_msg.ranges.empty())
894 laser_scan_echo_iter = laser_scan_msg_map.erase(laser_scan_echo_iter);
896 laser_scan_echo_iter++;
917 #if defined __ROS_VERSION && __ROS_VERSION > 1
922 imu_msg.header.frame_id = m_frame_id;
934 for(
int n = 0; n < 9; n++)
936 imu_msg.orientation_covariance[n] = 0;
937 imu_msg.angular_velocity_covariance[n] = 0;
938 imu_msg.linear_acceleration_covariance[n] = 0;
942 if (m_publisher_imu_initialized)
944 #if defined __ROS_VERSION && __ROS_VERSION > 1
945 m_publisher_imu->publish(imu_msg);
947 m_publisher_imu.publish(imu_msg);
953 size_t echo_count = 0;
954 size_t point_count_per_echo = 0;
955 size_t total_point_count = 0;
958 for (
int groupIdx = 0; groupIdx < msgpack_data.
scandata.size(); groupIdx++)
960 echo_count = std::max(msgpack_data.
scandata[groupIdx].scanlines.size(), echo_count);
961 for (
int echoIdx = 0; echoIdx < msgpack_data.
scandata[groupIdx].scanlines.size(); echoIdx++)
963 total_point_count += msgpack_data.
scandata[groupIdx].scanlines[echoIdx].points.size();
964 point_count_per_echo = std::max(msgpack_data.
scandata[groupIdx].scanlines[echoIdx].points.size(), point_count_per_echo);
967 float lidar_points_min_azimuth = +2.0f * (float)M_PI, lidar_points_max_azimuth = -2.0
f * (
float)M_PI;
968 std::vector<std::vector<sick_scansegment_xd::PointXYZRAEI32f>> lidar_points(echo_count);
969 for (
int echoIdx = 0; echoIdx < echo_count; echoIdx++)
971 lidar_points[echoIdx].reserve(point_count_per_echo);
973 uint64_t lidar_timestamp_start_microsec = std::numeric_limits<uint64_t>::max();
974 for (
int groupIdx = 0; groupIdx < msgpack_data.
scandata.size(); groupIdx++)
976 for (
int echoIdx = 0; echoIdx < msgpack_data.
scandata[groupIdx].scanlines.size(); echoIdx++)
978 const std::vector<sick_scansegment_xd::ScanSegmentParserOutput::LidarPoint>& scanline = msgpack_data.
scandata[groupIdx].scanlines[echoIdx].points;
979 for (
int pointIdx = 0; pointIdx < scanline.size(); pointIdx++)
984 lidar_points_min_azimuth = std::min(lidar_points_min_azimuth, point.
azimuth);
985 lidar_points_max_azimuth = std::max(lidar_points_max_azimuth, point.
azimuth);
1006 float precheck_min_azimuth_deg = m_points_collector.min_azimuth * 180.0f / (float)M_PI;
1007 float precheck_max_azimuth_deg = m_points_collector.max_azimuth * 180.0f / (float)M_PI;
1008 bool publish_cloud_360 = (precheck_max_azimuth_deg - precheck_min_azimuth_deg + 1 >= m_all_segments_azimuth_max_deg - m_all_segments_azimuth_min_deg - 1)
1009 && m_points_collector.allSegmentsCovered(m_all_segments_azimuth_min_deg, m_all_segments_azimuth_max_deg, m_all_segments_elevation_min_deg, m_all_segments_elevation_max_deg);
1015 if (m_points_collector.total_point_count <= 0 || m_points_collector.telegram_cnt <= 0 || publish_cloud_360 || m_points_collector.lastSegmentIdx() > segment_idx)
1019 if (m_points_collector.total_point_count > 0 && m_points_collector.telegram_cnt > 0 && publish_cloud_360)
1023 m_scan_time = (msgpack_data.
timestamp_sec + 1.0e-9 * msgpack_data.
timestamp_nsec) - (m_points_collector.timestamp_sec + 1.0e-9 * m_points_collector.timestamp_nsec);
1024 for (
int cloud_cnt = 0; cloud_cnt < m_custom_pointclouds_cfg.size(); cloud_cnt++)
1030 convertPointsToCustomizedFieldsCloud(m_points_collector.timestamp_sec, m_points_collector.timestamp_nsec, m_points_collector.lidar_timestamp_start_microsec,
1031 m_points_collector.lidar_points, custom_pointcloud_cfg, pointcloud_msg_custom_fields);
1032 publishPointCloud2Msg(m_node, custom_pointcloud_cfg.
publisher(), pointcloud_msg_custom_fields, std::max(1, (
int)echo_count), -1, custom_pointcloud_cfg.
coordinateNotation(), custom_pointcloud_cfg.
topic());
1038 convertPointsToLaserscanMsg(m_points_collector.timestamp_sec, m_points_collector.timestamp_nsec, m_points_collector.lidar_points, m_points_collector.total_point_count, laser_scan_msg_map, m_frame_id,
true);
1039 publishLaserScanMsg(m_node, m_publisher_laserscan_360, laser_scan_msg_map, std::max(1, (
int)echo_count), -1);
1043 m_points_collector.timestamp_sec = msgpack_data.
timestamp_sec;
1045 m_points_collector.total_point_count = total_point_count;
1046 m_points_collector.lidar_points = std::vector<std::vector<sick_scansegment_xd::PointXYZRAEI32f>>(lidar_points.size());
1047 for (
int echoIdx = 0; echoIdx < lidar_points.size(); echoIdx++)
1048 m_points_collector.lidar_points[echoIdx].reserve(12 * lidar_points[echoIdx].size());
1049 m_points_collector.appendLidarPoints(lidar_points, segment_idx, telegram_cnt);
1050 m_points_collector.min_azimuth = lidar_points_min_azimuth;
1051 m_points_collector.max_azimuth = lidar_points_max_azimuth;
1058 else if (telegram_cnt > m_points_collector.telegram_cnt)
1060 if (m_points_collector.lidar_points.size() < lidar_points.size())
1061 m_points_collector.lidar_points.resize(lidar_points.size());
1063 m_points_collector.telegram_cnt = telegram_cnt;
1064 m_points_collector.total_point_count += total_point_count;
1065 m_points_collector.appendLidarPoints(lidar_points, segment_idx, telegram_cnt);
1066 m_points_collector.min_azimuth = std::min(m_points_collector.min_azimuth, lidar_points_min_azimuth);
1067 m_points_collector.max_azimuth = std::max(m_points_collector.max_azimuth, lidar_points_max_azimuth);
1078 if (m_points_collector.telegram_cnt > telegram_cnt)
1080 ROS_INFO_STREAM(
"RosMsgpackPublisher::HandleMsgPackData(): current telegram cnt: " << telegram_cnt <<
", last telegram cnt in collector: " << m_points_collector.telegram_cnt
1081 <<
", 360-degree-pointcloud not published (ok if sick_scan_xd is running in a test enviroment with recorded and repeated telegrams from pcapng- or upd-player, otherwise not ok)");
1085 ROS_WARN_STREAM(
"## WARNING RosMsgpackPublisher::HandleMsgPackData(): current segment: " << segment_idx <<
", last segment in collector: " << m_points_collector.lastSegmentIdx()
1086 <<
", current telegram: " << telegram_cnt <<
", last telegram in collector: " << m_points_collector.telegram_cnt
1087 <<
", datagram(s) missing, 360-degree-pointcloud not published");
1088 if (m_points_collector.numEchos() > 1)
1090 ROS_WARN_STREAM(
"## WARNING RosMsgpackPublisher::HandleMsgPackData(): " << m_points_collector.numEchos() <<
" echos received. Activate the echo filter in the launchfile to reduce system load (e.g. last echo only)");
1101 for (
int cloud_cnt = 0; cloud_cnt < m_custom_pointclouds_cfg.size(); cloud_cnt++)
1107 convertPointsToCustomizedFieldsCloud(msgpack_data.
timestamp_sec, msgpack_data.
timestamp_nsec, lidar_timestamp_start_microsec, lidar_points, custom_pointcloud_cfg, pointcloud_msg_custom_fields);
1108 publishPointCloud2Msg(m_node, custom_pointcloud_cfg.
publisher(), pointcloud_msg_custom_fields, std::max(1, (
int)echo_count), segment_idx, custom_pointcloud_cfg.
coordinateNotation(), custom_pointcloud_cfg.
topic());
1109 ROS_DEBUG_STREAM(
"publishPointCloud2Msg: " << pointcloud_msg_custom_fields.width <<
"x" << pointcloud_msg_custom_fields.height <<
" pointcloud, " << pointcloud_msg_custom_fields.fields.size() <<
" fields/point, " << pointcloud_msg_custom_fields.data.size() <<
" bytes");
1112 #if defined RASPBERRY && RASPBERRY > 0 // laserscan messages deactivated on Raspberry for performance reasons
1115 convertPointsToLaserscanMsg(msgpack_data.
timestamp_sec, msgpack_data.
timestamp_nsec, lidar_points, total_point_count, laser_scan_msg_map, m_frame_id,
false);
1116 publishLaserScanMsg(m_node, m_publisher_laserscan_segment, laser_scan_msg_map, std::max(1, (
int)echo_count), segment_idx);