38 #include <shared_mutex> 
   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> 
   51 #include <sick_ldmrs/devices/LD_MRS.hpp> 
   53 #include <sick_ldmrs/tools/errorhandler.hpp> 
   54 #include <sick_ldmrs/tools/toolbox.hpp> 
   56 #include <sick_ldmrs_msgs/ObjectArray.h> 
   64   : application::BasicApplication()
 
   65   , diagnostics_(diagnostics)
 
   67   , expected_frequency_(12.5)
 
   70   dynamic_reconfigure::Server<SickLDMRSDriverConfig>::CallbackType 
f;
 
   97     ROS_ERROR(
"Error: upside down mode is active, please disable!");
 
  105   devices::LDMRS* ldmrs;
 
  106   ldmrs = 
dynamic_cast<devices::LDMRS*
>(
manager_->getFirstDeviceByType(Sourcetype_LDMRS));
 
  107   stat.
summary(diagnostic_msgs::DiagnosticStatus::OK, 
"Device information.");
 
  110   stat.
add(
"IP Address", ldmrs->getIpAddress());
 
  111   stat.
add(
"IP Port", 12002);   
 
  112   stat.
add(
"Vendor Name", 
"SICK");
 
  113   stat.
add(
"Product Name", 
"LD-MRS");
 
  114   stat.
add(
"Firmware Version", ldmrs->getFirmwareVersion());  
 
  115   stat.
add(
"Device ID", ldmrs->getSerialNumber());
 
  120   std::string datatypeStr;
 
  121   std::string sourceIdStr;
 
  123   switch (
data.getDatatype())
 
  126     datatypeStr = 
"Scan (" + ::toString(((Scan&)
data).getNumPoints()) + 
" points)";
 
  128       Scan* scan = 
dynamic_cast<Scan*
>(&
data);
 
  129       std::vector<ScannerInfo> scannerInfos = scan->getScannerInfos();
 
  130       if (scannerInfos.size() != 1)
 
  132         ROS_ERROR(
"Expected exactly 1 scannerInfo, got %zu!", scannerInfos.size());
 
  136       const Time& time = scannerInfos[0].getStartTimestamp();
 
  137       ROS_DEBUG(
"setData(): Scan start time: %s (%s)",
 
  138                 time.toString().c_str(),
 
  139                 time.toLongString().c_str());
 
  141       PointCloud::Ptr cloud = pcl::make_shared<PointCloud>();
 
  142       cloud->header.frame_id = 
config_.frame_id;
 
  147       cloud->width = scan->size();
 
  148       for (
size_t i = 0; i < scan->size(); ++i)
 
  150         const ScanPoint& p = (*scan)[i];
 
  156         np.
layer = p.getLayer() + (scannerInfos[0].isRearMirrorSide() ? 4 : 0);
 
  157         np.
echo = p.getEchoNum();
 
  158         np.
flags = p.getFlags();
 
  159         cloud->points.push_back(np);
 
  162       sensor_msgs::PointCloud2 
msg;
 
  167   case Datatype_Objects:
 
  168     datatypeStr = 
"Objects (" + ::toString(((ObjectList&)
data).size()) + 
" objects)";
 
  171   case Datatype_Fields:
 
  172     datatypeStr = 
"Fields (" + ::toString(((Fields&)
data).getFields().size()) + 
" fields, " +
 
  173                   ::toString(((Fields&)
data).getNumberOfValidFields()) + 
" of which are valid)";
 
  175   case Datatype_EvalCases:
 
  176     datatypeStr = 
"EvalCases (" + ::toString(((EvalCases&)
data).getEvalCases().size()) + 
" cases)";
 
  178   case Datatype_EvalCaseResults:
 
  179     datatypeStr = 
"EvalCaseResults (" + ::toString(((EvalCaseResults&)
data).size()) + 
" case results)";
 
  182     datatypeStr = 
"Msg (" + ((
Msg&)
data).toString() + 
")";
 
  186   case Datatype_MeasurementList:
 
  187     datatypeStr = 
"MeasurementList (" + ::toString(((MeasurementList&)
data).m_list.size()) + 
" entries)";
 
  190     datatypeStr = 
"(unknown)";
 
  193   sourceIdStr = ::toString(
data.getSourceId());
 
  195   ROS_DEBUG(
"setData(): Called with data of type %s from ID %s", datatypeStr.c_str(), sourceIdStr.c_str());
 
  200   if (conf.start_angle <= conf.end_angle)
 
  202     ROS_WARN(
"Start angle must be greater than end angle. Adjusting start_angle.");
 
  203     conf.start_angle = conf.end_angle;  
 
  206   if (conf.angular_resolution_type != SickLDMRSDriver_ConstantRes
 
  207       && conf.scan_frequency != SickLDMRSDriver_ScanFreq1250)
 
  209     ROS_WARN(
"Focused/flexible resolution only available at 12.5 Hz scan frequency. Adjusting scan frequency.");
 
  210     conf.scan_frequency = SickLDMRSDriver_ScanFreq1250;
 
  213   if (conf.ignore_near_range && conf.layer_range_reduction != SickLDMRSDriver_RangeLowerReduced)
 
  215     ROS_WARN(
"If ignore_near_range is set, layer_range_reduction must be set to 'Lower 4 layers reduced range'. Adjusting layer_range_reduction.");
 
  216     conf.layer_range_reduction = SickLDMRSDriver_RangeLowerReduced;
 
  245   case SickLDMRSDriver_Res0125:
 
  246   case SickLDMRSDriver_Res0250:
 
  247   case SickLDMRSDriver_Res0500:
 
  248   case SickLDMRSDriver_Res1000:
 
  251     ROS_WARN(
"Invalid flexres resolution %d! Setting to 32 (= 1 degree).", res);
 
  252     res = SickLDMRSDriver_Res1000;
 
  268   sick_ldmrs_msgs::ObjectArray oa;
 
  269   oa.header.frame_id = 
config_.frame_id;
 
  272   oa.objects.resize(objects.size());
 
  274   for (
int i = 0; i < objects.size(); i++)
 
  276     oa.objects[i].id = objects[i].getObjectId();
 
  279     oa.objects[i].velocity.twist.linear.x = objects[i].getAbsoluteVelocity().getX();
 
  280     oa.objects[i].velocity.twist.linear.y = objects[i].getAbsoluteVelocity().getY();
 
  281     oa.objects[i].velocity.twist.linear.x = objects[i].getAbsoluteVelocity().getX();
 
  282     oa.objects[i].velocity.twist.linear.y = objects[i].getAbsoluteVelocity().getY();
 
  283     oa.objects[i].velocity.covariance[0] = objects[i].getAbsoluteVelocitySigma().getX();
 
  284     oa.objects[i].velocity.covariance[7] = objects[i].getAbsoluteVelocitySigma().getX();
 
  286     oa.objects[i].bounding_box_center.position.x = objects[i].getBoundingBoxCenter().getX();
 
  287     oa.objects[i].bounding_box_center.position.y = objects[i].getBoundingBoxCenter().getY();
 
  288     oa.objects[i].bounding_box_size.x = objects[i].getBoundingBox().getX();
 
  289     oa.objects[i].bounding_box_size.y = objects[i].getBoundingBox().getY();
 
  291     oa.objects[i].object_box_center.pose.position.x = objects[i].getCenterPoint().getX();
 
  292     oa.objects[i].object_box_center.pose.position.y = objects[i].getCenterPoint().getY();
 
  294     oa.objects[i].object_box_center.covariance[0] = objects[i].getCenterPointSigma().getX();
 
  295     oa.objects[i].object_box_center.covariance[7] = objects[i].getCenterPointSigma().getY();
 
  296     oa.objects[i].object_box_center.covariance[35] = objects[i].getCourseAngleSigma();
 
  297     oa.objects[i].object_box_size.x = objects[i].getObjectBox().getX();
 
  298     oa.objects[i].object_box_size.y = objects[i].getObjectBox().getY();
 
  300     datatypes::Polygon2D contour = objects[i].getContourPoints();
 
  301     oa.objects[i].contour_points.resize(contour.size());
 
  302     for (
int j = 0; j < contour.size(); j++)
 
  304       oa.objects[i].contour_points[j].x = contour[j].getX();
 
  305       oa.objects[i].contour_points[j].y = contour[j].getY();
 
  316   devices::LDMRS* ldmrs;
 
  317   ldmrs = 
dynamic_cast<devices::LDMRS*
>(
manager_->getFirstDeviceByType(Sourcetype_LDMRS));
 
  320     ROS_WARN(
"isUpsideDown: no connection to LDMRS!");
 
  325   ldmrs->getParameter(devices::ParaUpsideDownMode, &code);
 
  331   devices::LDMRS* ldmrs;
 
  332   ldmrs = 
dynamic_cast<devices::LDMRS*
>(
manager_->getFirstDeviceByType(Sourcetype_LDMRS));
 
  335     ROS_WARN(
"printFlexResError: no connection to LDMRS!");
 
  340   ldmrs->getParameter(devices::ParaDetailedError, &code);
 
  355   devices::LDMRS* ldmrs;
 
  356   ldmrs = 
dynamic_cast<devices::LDMRS*
>(
manager_->getFirstDeviceByType(Sourcetype_LDMRS));
 
  359     ROS_WARN(
"update_config: no connection to LDMRS!");
 
  366   if (!ldmrs->setScanAngles(new_config.start_angle, new_config.end_angle))
 
  367     ROS_WARN(
"Sending param not successful: ");
 
  369   switch (
config_.scan_frequency)
 
  371   case SickLDMRSDriver_ScanFreq1250:
 
  374   case SickLDMRSDriver_ScanFreq2500:
 
  377   case SickLDMRSDriver_ScanFreq5000:
 
  386     ROS_WARN(
"Sending param not successful: ScanFrequency");
 
  387   if (!ldmrs->setSyncAngleOffset(
config_.sync_angle_offset))
 
  388     ROS_WARN(
"Sending param not successful: SyncAngleOffset");
 
  389   if (!ldmrs->setParameter(devices::ParaContourPointDensity, 
config_.contour_point_density))
 
  390     ROS_WARN(
"Sending param not successful: ContourPointDensity");
 
  391   if (!ldmrs->setParameter(devices::ParaMinimumObjectAge, 
config_.min_object_age))
 
  392     ROS_WARN(
"Sending param not successful: MinimumObjectAge");
 
  393   if (!ldmrs->setParameter(devices::ParaMaximumPredictionAge, 
config_.max_prediction_age))
 
  394     ROS_WARN(
"Sending param not successful: MaximumPredictionAge");
 
  395   if (!ldmrs->setParameter(devices::ParaRangeReduction, 
config_.layer_range_reduction))
 
  396     ROS_WARN(
"Sending param not successful: RangeReduction");
 
  397   if (!ldmrs->setParameter(devices::ParaIgnoreNearRange, 
config_.ignore_near_range ? 1 : 0))
 
  398     ROS_WARN(
"Sending param not successful: IgnoreNearRange");
 
  399   if (!ldmrs->setParameter(devices::ParaSensitivityControl, 
config_.sensitivity_control ? 1 : 0))
 
  400     ROS_WARN(
"Sending param not successful: SensitivityControl");
 
  402   if (
config_.angular_resolution_type == SickLDMRSDriver_FlexRes)
 
  404     std::vector<std::pair<int, int> > res_map, res_map_filtered;
 
  405     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle1 * rad2deg * 32.0), 
config_.flexres_resolution1));
 
  406     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle2 * rad2deg * 32.0), 
config_.flexres_resolution2));
 
  407     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle3 * rad2deg * 32.0), 
config_.flexres_resolution3));
 
  408     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle4 * rad2deg * 32.0), 
config_.flexres_resolution4));
 
  409     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle5 * rad2deg * 32.0), 
config_.flexres_resolution5));
 
  410     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle6 * rad2deg * 32.0), 
config_.flexres_resolution6));
 
  411     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle7 * rad2deg * 32.0), 
config_.flexres_resolution7));
 
  412     res_map.push_back(std::pair<int, int>(round(
config_.flexres_start_angle8 * rad2deg * 32.0), 
config_.flexres_resolution8));
 
  415     for (
int i = 0; i < res_map.size() - 1; ++i)
 
  417       if (res_map[i].first > res_map[i + 1].first)
 
  419         res_map_filtered.push_back(res_map[i]);
 
  422     if (res_map[7].first > (-1918))   
 
  424       res_map_filtered.push_back(res_map[7]);
 
  428     int shots_per_scan = 0;
 
  429     double sum_res0125 = 0;
 
  430     for (
int i = 0; i < res_map_filtered.size() - 1; ++i)
 
  433       double sector_angle = (res_map_filtered[i].first - res_map_filtered[i + 1].first) / 32.0;
 
  435       shots_per_scan += sector_angle * 32.0 / res_map_filtered[i].second;
 
  436       if (res_map_filtered[i].second == SickLDMRSDriver_Res0125)
 
  438         sum_res0125 += sector_angle;
 
  442     if (shots_per_scan > 440)
 
  444       ROS_WARN(
"FlexRes: The number of shots per scan must be at most 440. Not updating FlexRes config!");
 
  447     if (sum_res0125 > 20.0)
 
  449       ROS_WARN(
"FlexRes: The sectors with a resolution of 0.125 deg must not sum up to more than 20 deg. Not updating FlexRes config!");
 
  456     if (!ldmrs->setParameter(devices::ParaAngularResolutionType, SickLDMRSDriver_ConstantRes))
 
  457       ROS_WARN(
"Sending param not successful: AngularResolutionType");
 
  463     if (!ldmrs->setParameter(devices::ParaNumSectors, res_map_filtered.size()))
 
  466     for (
int i = 0; i < res_map_filtered.size(); ++i)
 
  469       if (!ldmrs->setParameter((devices::MrsParameterId)(0x4001 + i), res_map_filtered[i].first))
 
  473       if (!ldmrs->setParameter((devices::MrsParameterId)(0x4009 + i), res_map_filtered[i].second))
 
  479   if (!ldmrs->setParameter(devices::ParaAngularResolutionType, 
config_.angular_resolution_type))
 
  480     ROS_WARN(
"Sending param not successful: AngularResolutionType");
 
  482   ROS_INFO(
"... done updating config.");
 
  489   case devices::ErrFlexResNumShotsInvalid:
 
  490     return "The number of shots per scan is higher than 440.";
 
  491   case devices::ErrFlexResSizeOneEighthSectorInvalid:
 
  492     return "The sectors with a resolution of 0.125 deg sum up to more than 20 deg.";
 
  493   case devices::ErrFlexResFreqInvalid:
 
  494     return "The scan frequency is not 12.5Hz.";
 
  495   case devices::ErrFlexResSectorsOverlapping:
 
  496     return "The start angles of the sectors decrease not strictly monotone.";
 
  497   case devices::ErrFlexResScannerNotIdle:
 
  498     return "Could not set FlexRes parameter because the sensor is in flex res mode and not idle.";
 
  499   case devices::ErrFlexResResolutionInvalid:
 
  500     return "The resolution of one sector is not 4, 8, 16 or 32 (0.125 deg, 0.25 deg, 0.5 deg, 1 deg).";
 
  501   case devices::ErrFlexResNumSectorsInvalid:
 
  502     return "The number of sectors is larger than 8.";
 
  504     std::ostringstream ss;
 
  505     ss << 
"UNKNOWN ERROR CODE (" << code << 
")";
 
  513 int main(
int argc, 
char **argv)
 
  515   ros::init(argc, argv, 
"sick_ldmrs_node");
 
  517     = boost::make_shared<diagnostic_updater::Updater>();
 
  533   ROS_INFO(
"Adding the application SickLDMRS.");
 
  534   name = 
"Sick LDMRS ROS Driver App";
 
  538   app.setApplicationName(name);
 
  540   result = manager.addApplication(&
app, 
id);
 
  543     ROS_ERROR(
"Failed to add application %s, aborting!", name.c_str());
 
  546   ROS_INFO(
"Application is running.");
 
  556   ROS_INFO(
"Adding the LDMRS device.");
 
  557   devices::LDMRS* ldmrs = 
new devices::LDMRS(&manager);
 
  558   ldmrs->setWeWantObjectData(
true);
 
  559   std::string hostname;
 
  561   nh.
param<std::string>(
"hostname", hostname, 
"192.168.0.1");
 
  562   ROS_INFO(
"Set IP address to %s", hostname.c_str());
 
  563   ldmrs->setIpAddress(hostname);
 
  566   result = manager.addAndRunDevice(ldmrs, name, 
id);
 
  569     ROS_ERROR(
"Failed to add device %s, aborting!", name.c_str());
 
  573   std::string serial_number = ldmrs->getSerialNumber();
 
  574   diagnostics->setHardwareID(serial_number);
 
  576   ROS_INFO(
"LD-MRS Firmware version is %s", ldmrs->getFirmwareVersion().c_str());
 
  587     diagnostics->update();