40 #include <tf2/LinearMath/Quaternion.h>
44 #include <sick_ldmrs/datatypes/EvalCaseResults.hpp>
45 #include <sick_ldmrs/datatypes/EvalCases.hpp>
46 #include <sick_ldmrs/datatypes/Fields.hpp>
47 #include <sick_ldmrs/datatypes/Measurement.hpp>
48 #include <sick_ldmrs/datatypes/Msg.hpp>
49 #include <sick_ldmrs/datatypes/Scan.hpp>
50 #include <sick_ldmrs/devices/LD_MRS.hpp>
51 #include <sick_ldmrs/tools/errorhandler.hpp>
52 #include <sick_ldmrs/tools/toolbox.hpp>
64 : application::BasicApplication()
65 , diagnostics_(diagnostics)
67 , expected_frequency_(12.5)
83 int range_filter_handling = 0;
89 rosGetParam(nh,
"range_filter_handling", range_filter_handling);
91 ROS_INFO_STREAM(
"Range filter configuration for sick_scansegment_xd: range_min=" <<
range_min <<
", range_max=" <<
range_max <<
", range_filter_handling=" << range_filter_handling);
95 object_pub_ = rosAdvertise<sick_scan_msg::SickLdmrsObjectArray>(
nh_, nodename +
"/objects");
97 #if defined USE_DIAGNOSTIC_UPDATER
120 #if defined USE_DYNAMIC_RECONFIGURE && __ROS_VERSION == 1
123 f = std::bind(&SickLDMRS::update_config_cb,
this, std::placeholders::_1, std::placeholders::_2);
124 dynamic_reconfigure_server_.setCallback(
f);
125 #elif defined USE_DYNAMIC_RECONFIGURE && __ROS_VERSION == 2
126 rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr parameter_cb_handle =
127 nh_->add_on_set_parameters_callback(std::bind(&SickLDMRS::update_config_cb,
this, std::placeholders::_1));
133 devices::LDMRS* ldmrs;
138 stat.
add(
"IP Address", ldmrs->getIpAddress());
139 stat.
add(
"IP Port", 12002);
140 stat.
add(
"Vendor Name",
"SICK");
141 stat.
add(
"Product Name",
"LD-MRS");
142 stat.
add(
"Firmware Version", ldmrs->getFirmwareVersion());
143 stat.
add(
"FPGA Version", ldmrs->getFPGAVersion());
144 std::string temperature = std::to_string(ldmrs->getTemperature());
145 stat.
add(
"Temperature", temperature);
146 stat.
add(
"Device ID", ldmrs->getSerialNumber());
151 std::string datatypeStr;
152 std::string sourceIdStr;
154 switch (
data.getDatatype())
157 datatypeStr =
"Scan (" +
::toString(((Scan&)
data).getNumPoints()) +
" points)";
159 Scan* scan =
dynamic_cast<Scan*
>(&
data);
160 std::vector<ScannerInfo> scannerInfos = scan->getScannerInfos();
161 if (scannerInfos.size() != 1)
163 ROS_ERROR_STREAM(
"Expected exactly 1 scannerInfo, got " << scannerInfos.size());
166 const Time& time = scannerInfos[0].getStartTimestamp();
185 datatypeStr =
"Objects (" +
::toString(((ObjectList&)
data).size()) +
" objects)";
189 datatypeStr =
"Fields (" +
::toString(((Fields&)
data).getFields().size()) +
" fields, " +
190 ::toString(((Fields&)
data).getNumberOfValidFields()) +
" of which are valid)";
193 datatypeStr =
"EvalCases (" +
::toString(((EvalCases&)
data).getEvalCases().size()) +
" cases)";
196 datatypeStr =
"EvalCaseResults (" +
::toString(((EvalCaseResults&)
data).size()) +
" case results)";
199 datatypeStr =
"Msg (" + ((
Msg&)
data).toString() +
")";
204 datatypeStr =
"MeasurementList (" +
::toString(((MeasurementList&)
data).m_list.size()) +
" entries)";
207 datatypeStr =
"(unknown)";
212 ROS_DEBUG_STREAM(
"setData(): Called with data of type " << datatypeStr <<
" from ID " << sourceIdStr);
219 ROS_WARN_STREAM(
"Start angle must be greater than end angle. Adjusting start_angle.");
224 && conf.
scan_frequency != sick_ldmrs_driver::SickLDMRSDriverConfig::scan_freq_enum::ScanFreq1250)
226 ROS_WARN_STREAM(
"Focused/flexible resolution only available at 12.5 Hz scan frequency. Adjusting scan frequency.");
227 conf.
scan_frequency = sick_ldmrs_driver::SickLDMRSDriverConfig::scan_freq_enum::ScanFreq1250;
232 ROS_WARN_STREAM(
"If ignore_near_range is set, layer_range_reduction must be set to 'Lower 4 layers reduced range'. Adjusting layer_range_reduction.");
233 conf.
layer_range_reduction = sick_ldmrs_driver::SickLDMRSDriverConfig::range_reduction_enum::RangeLowerReduced;
262 case sick_ldmrs_driver::SickLDMRSDriverConfig::resolution_enum::Res0125:
263 case sick_ldmrs_driver::SickLDMRSDriverConfig::resolution_enum::Res0250:
264 case sick_ldmrs_driver::SickLDMRSDriverConfig::resolution_enum::Res0500:
265 case sick_ldmrs_driver::SickLDMRSDriverConfig::resolution_enum::Res1000:
268 ROS_WARN_STREAM(
"Invalid flexres resolution " << res <<
"! Setting to 32 (= 1 degree).");
269 res = sick_ldmrs_driver::SickLDMRSDriverConfig::resolution_enum::Res1000;
290 oa.objects.resize(objects.size());
292 for (
int i = 0; i < objects.size(); i++)
294 oa.objects[i].id = objects[i].getObjectId();
295 #if __ROS_VERSION == 2 // ROS-2 (Linux or Windows)
302 oa.objects[i].velocity.twist.linear.x = objects[i].getAbsoluteVelocity().getX();
303 oa.objects[i].velocity.twist.linear.y = objects[i].getAbsoluteVelocity().getY();
304 oa.objects[i].velocity.twist.linear.x = objects[i].getAbsoluteVelocity().getX();
305 oa.objects[i].velocity.twist.linear.y = objects[i].getAbsoluteVelocity().getY();
306 oa.objects[i].velocity.covariance[0] = objects[i].getAbsoluteVelocitySigma().getX();
307 oa.objects[i].velocity.covariance[7] = objects[i].getAbsoluteVelocitySigma().getX();
309 oa.objects[i].bounding_box_center.position.x = objects[i].getBoundingBoxCenter().getX();
310 oa.objects[i].bounding_box_center.position.y = objects[i].getBoundingBoxCenter().getY();
311 oa.objects[i].bounding_box_size.x = objects[i].getBoundingBox().getX();
312 oa.objects[i].bounding_box_size.y = objects[i].getBoundingBox().getY();
314 oa.objects[i].object_box_center.pose.position.x = objects[i].getCenterPoint().getX();
315 oa.objects[i].object_box_center.pose.position.y = objects[i].getCenterPoint().getY();
318 q.
setRPY(0, 0, objects[i].getCourseAngle());
319 oa.objects[i].object_box_center.pose.orientation.x = q.x();
320 oa.objects[i].object_box_center.pose.orientation.y = q.y();
321 oa.objects[i].object_box_center.pose.orientation.z = q.z();
322 oa.objects[i].object_box_center.pose.orientation.w = q.w();
323 oa.objects[i].object_box_center.covariance[0] = objects[i].getCenterPointSigma().getX();
324 oa.objects[i].object_box_center.covariance[7] = objects[i].getCenterPointSigma().getY();
325 oa.objects[i].object_box_center.covariance[35] = objects[i].getCourseAngleSigma();
326 oa.objects[i].object_box_size.x = objects[i].getObjectBox().getX();
327 oa.objects[i].object_box_size.y = objects[i].getObjectBox().getY();
329 datatypes::Polygon2D contour = objects[i].getContourPoints();
330 oa.objects[i].contour_points.resize(contour.size());
331 for (
int j = 0; j < contour.size(); j++)
333 oa.objects[i].contour_points[j].x = contour[j].getX();
334 oa.objects[i].contour_points[j].y = contour[j].getY();
346 devices::LDMRS* ldmrs;
355 ldmrs->getParameter(devices::ParaUpsideDownMode, &code);
361 devices::LDMRS* ldmrs;
370 ldmrs->getParameter(devices::ParaDetailedError, &code);
375 #if defined USE_DYNAMIC_RECONFIGURE && __ROS_VERSION == 1
376 void SickLDMRS::update_config_cb(sick_scan_xd::SickLDMRSDriverConfig &new_config, uint32_t level)
411 #if defined USE_DYNAMIC_RECONFIGURE && __ROS_VERSION == 2
412 rcl_interfaces::msg::SetParametersResult SickLDMRS::update_config_cb(
const std::vector<rclcpp::Parameter> ¶meters)
414 rcl_interfaces::msg::SetParametersResult result;
415 result.successful =
true;
416 result.reason =
"success";
417 if(!parameters.empty())
419 SickLDMRSDriverConfig new_config =
config_;
420 for (
const auto ¶meter : parameters)
422 ROS_INFO_STREAM(
"SickLDMRS::update_config_cb(): parameter " << parameter.get_name() <<
" (type " << rclcpp::to_string(parameter.get_type()) <<
") changed to " << parameter.as_string());
424 if(parameter.get_type() == rclcpp::ParameterType::PARAMETER_BOOL)
425 ok = new_config.set_parameter(parameter.get_name(), parameter.as_bool());
426 if(parameter.get_type() == rclcpp::ParameterType::PARAMETER_INTEGER)
427 ok = new_config.set_parameter(parameter.get_name(), parameter.as_int());
428 if(parameter.get_type() == rclcpp::ParameterType::PARAMETER_DOUBLE)
429 ok = new_config.set_parameter(parameter.get_name(), parameter.as_double());
430 if(parameter.get_type() == rclcpp::ParameterType::PARAMETER_STRING)
431 ok = new_config.set_parameter(parameter.get_name(), parameter.as_string());
434 result.successful =
false;
435 result.reason =
"parameter not supported";
454 devices::LDMRS* ldmrs;
470 case sick_ldmrs_driver::SickLDMRSDriverConfig::scan_freq_enum::ScanFreq1250:
473 case sick_ldmrs_driver::SickLDMRSDriverConfig::scan_freq_enum::ScanFreq2500:
476 case sick_ldmrs_driver::SickLDMRSDriverConfig::scan_freq_enum::ScanFreq5000:
503 std::vector<std::pair<int, int> > res_map, res_map_filtered;
514 for (
int i = 0; i < res_map.size() - 1; ++i)
516 if (res_map[i].first > res_map[i + 1].first)
518 res_map_filtered.push_back(res_map[i]);
521 if (res_map[7].first > (-1918))
523 res_map_filtered.push_back(res_map[7]);
527 int shots_per_scan = 0;
528 double sum_res0125 = 0;
529 for (
int i = 0; i < res_map_filtered.size() - 1; ++i)
532 double sector_angle = (res_map_filtered[i].first - res_map_filtered[i + 1].first) / 32.0;
534 shots_per_scan += sector_angle * 32.0 / res_map_filtered[i].second;
535 if (res_map_filtered[i].second == sick_ldmrs_driver::SickLDMRSDriverConfig::resolution_enum::Res0125)
537 sum_res0125 += sector_angle;
541 if (shots_per_scan > 440)
543 ROS_WARN_STREAM(
"FlexRes: The number of shots per scan must be at most 440. Not updating FlexRes config!");
546 if (sum_res0125 > 20.0)
548 ROS_WARN_STREAM(
"FlexRes: The sectors with a resolution of 0.125 deg must not sum up to more than 20 deg. Not updating FlexRes config!");
555 if (!ldmrs->setParameter(devices::ParaAngularResolutionType, sick_ldmrs_driver::SickLDMRSDriverConfig::angular_res_enum::ConstantRes))
556 ROS_WARN_STREAM(
"Sending param not successful: AngularResolutionType");
562 if (!ldmrs->setParameter(devices::ParaNumSectors, res_map_filtered.size()))
565 for (
int i = 0; i < res_map_filtered.size(); ++i)
568 if (!ldmrs->setParameter((devices::MrsParameterId)(0x4001 + i), res_map_filtered[i].first))
572 if (!ldmrs->setParameter((devices::MrsParameterId)(0x4009 + i), res_map_filtered[i].second))
579 ROS_WARN_STREAM(
"Sending param not successful: AngularResolutionType");
588 case devices::ErrFlexResNumShotsInvalid:
589 return "The number of shots per scan is higher than 440.";
590 case devices::ErrFlexResSizeOneEighthSectorInvalid:
591 return "The sectors with a resolution of 0.125 deg sum up to more than 20 deg.";
592 case devices::ErrFlexResFreqInvalid:
593 return "The scan frequency is not 12.5Hz.";
594 case devices::ErrFlexResSectorsOverlapping:
595 return "The start angles of the sectors decrease not strictly monotone.";
596 case devices::ErrFlexResScannerNotIdle:
597 return "Could not set FlexRes parameter because the sensor is in flex res mode and not idle.";
598 case devices::ErrFlexResResolutionInvalid:
599 return "The resolution of one sector is not 4, 8, 16 or 32 (0.125 deg, 0.25 deg, 0.5 deg, 1 deg).";
600 case devices::ErrFlexResNumSectorsInvalid:
601 return "The number of sectors is larger than 8.";
603 std::ostringstream ss;
604 ss <<
"UNKNOWN ERROR CODE (" << code <<
")";
614 typedef struct SICK_LDMRS_Point
624 uint8_t alignment[11];
627 msg.header.frame_id = frame_id;
631 msg.width = scan->size();
632 msg.is_bigendian =
false;
634 msg.point_step =
sizeof(SICK_LDMRS_Point);
635 msg.row_step =
msg.point_step *
msg.width;
637 msg.fields.resize(7);
638 msg.fields[0].name =
"x";
639 msg.fields[0].offset = 0;
640 msg.fields[0].count = 1;
641 msg.fields[0].datatype = ros_sensor_msgs::PointField::FLOAT32;
642 msg.fields[1].name =
"y";
643 msg.fields[1].offset =
msg.fields[0].offset +
sizeof(float);
644 msg.fields[1].count = 1;
645 msg.fields[1].datatype = ros_sensor_msgs::PointField::FLOAT32;
646 msg.fields[2].name =
"z";
647 msg.fields[2].offset =
msg.fields[1].offset +
sizeof(float);
648 msg.fields[2].count = 1;
649 msg.fields[2].datatype = ros_sensor_msgs::PointField::FLOAT32;
650 msg.fields[3].name =
"echowidth";
651 msg.fields[3].offset =
msg.fields[2].offset + 2 *
sizeof(float);
652 msg.fields[3].count = 1;
654 msg.fields[4].name =
"layer";
655 msg.fields[4].offset =
msg.fields[3].offset +
sizeof(uint16_t);
656 msg.fields[4].count = 1;
658 msg.fields[5].name =
"echo";
659 msg.fields[5].offset =
msg.fields[4].offset +
sizeof(uint8_t);
660 msg.fields[5].count = 1;
662 msg.fields[6].name =
"echo";
663 msg.fields[6].offset =
msg.fields[5].offset +
sizeof(uint8_t);
664 msg.fields[6].count = 1;
668 msg_polar.fields[0].name =
"range";
669 msg_polar.fields[1].name =
"azimuth";
670 msg_polar.fields[2].name =
"elevation";
672 msg.data.resize(
msg.row_step *
msg.height);
673 std::fill(
msg.data.begin(),
msg.data.end(), 0);
674 SICK_LDMRS_Point* data_p = (SICK_LDMRS_Point*)(&
msg.data[0]);
676 msg_polar.data.resize(msg_polar.row_step * msg_polar.height);
677 std::fill(msg_polar.data.begin(), msg_polar.data.end(), 0);
678 SICK_LDMRS_Point* polar_data_p = (SICK_LDMRS_Point*)(&msg_polar.data[0]);
680 size_t rangeNumPointcloud = 0;
681 for (
size_t i = 0; i < scan->size(); i++)
683 const ScanPoint& p = (*scan)[i];
684 float range = p.getDist();
685 bool range_modified =
false;
686 if (range_filter.
apply(range, range_modified))
688 float azi = p.getHAngle(), ele = -p.getVAngle();
691 data_p->x = range * cos(ele) * cos(azi);
692 data_p->y = range * cos(ele) * sin(azi);
693 data_p->z = range * sin(ele);
697 data_p->x = p.getX();
698 data_p->y = p.getY();
699 data_p->z = p.getZ();
701 add_transform_xyz_rpy.
applyTransform(data_p->x, data_p->y, data_p->z);
702 data_p->echowidth = p.getEchoWidth();
703 data_p->layer = p.getLayer() + (isRearMirrorSide ? 4 : 0);
704 data_p->echo = p.getEchoNum();
705 data_p->flags = p.getFlags();
706 *polar_data_p = *data_p;
707 polar_data_p->x = range;
708 polar_data_p->y = azi;
709 polar_data_p->z = ele;
710 rangeNumPointcloud++;
715 if (rangeNumPointcloud < scan->size())