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();