sick_ldmrs_node.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015, DFKI GmbH
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of DFKI GmbH nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * Created on: 20.11.2015
30  *
31  * Authors:
32  * Martin Günther <martin.guenther@dfki.de>
33  * Jochen Sprickerhof <jochen@sprickerhof.de>
34  *
35  */
36 
37 #include <iostream>
38 #include <shared_mutex>
39 
41 
43 
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 
51 #include <sick_ldmrs/devices/LD_MRS.hpp>
52 
53 #include <sick_ldmrs/tools/errorhandler.hpp>
54 #include <sick_ldmrs/tools/toolbox.hpp>
55 
56 #include <sick_ldmrs_msgs/ObjectArray.h>
57 #include <tf/transform_datatypes.h>
58 
59 
60 namespace sick_ldmrs_driver
61 {
62 
64  : application::BasicApplication()
65  , diagnostics_(diagnostics)
66  , manager_(manager)
67  , expected_frequency_(12.5)
68  , initialized_(false)
69 {
70  dynamic_reconfigure::Server<SickLDMRSDriverConfig>::CallbackType f;
71  f = boost::bind(&SickLDMRS::update_config, this, boost::placeholders::_1, boost::placeholders::_2);
72  dynamic_reconfigure_server_.setCallback(f);
73 
74  // point cloud publisher
75  pub_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud", 100);
76 
77  object_pub_ = nh_.advertise<sick_ldmrs_msgs::ObjectArray>("objects", 1);
78 
79  diagnostics_->setHardwareID("none"); // set from device after connection
80  diagnostics_->add("device info", this, &SickLDMRS::produce_diagnostics);
82  // frequency should be target +- 10%
84  // timestamp delta can be from -1 seconds to 1.3x what it ideally is at the lowest frequency
85  diagnostic_updater::TimeStampStatusParam(-1, 1.3 * 1.0 / 12.5));
86 }
87 
89 {
90  delete diagnosticPub_;
91 }
92 
94 {
95  if (isUpsideDown())
96  {
97  ROS_ERROR("Error: upside down mode is active, please disable!");
98  }
99  initialized_ = true;
101 }
102 
104 {
105  devices::LDMRS* ldmrs;
106  ldmrs = dynamic_cast<devices::LDMRS*>(manager_->getFirstDeviceByType(Sourcetype_LDMRS));
107  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Device information.");
108 
109  // REP-138 values (http://www.ros.org/reps/rep-0138.html#diagnostic-keys)
110  stat.add("IP Address", ldmrs->getIpAddress());
111  stat.add("IP Port", 12002); // LUX port number
112  stat.add("Vendor Name", "SICK");
113  stat.add("Product Name", "LD-MRS");
114  stat.add("Firmware Version", ldmrs->getFirmwareVersion()); // includes date, e.g. "3.03.5 2015-01-14 13:32"
115  stat.add("Device ID", ldmrs->getSerialNumber());
116 }
117 
118 void SickLDMRS::setData(BasicData &data)
119 {
120  std::string datatypeStr;
121  std::string sourceIdStr;
122 
123  switch (data.getDatatype())
124  {
125  case Datatype_Scan:
126  datatypeStr = "Scan (" + ::toString(((Scan&)data).getNumPoints()) + " points)";
127  {
128  Scan* scan = dynamic_cast<Scan*>(&data);
129  std::vector<ScannerInfo> scannerInfos = scan->getScannerInfos();
130  if (scannerInfos.size() != 1)
131  {
132  ROS_ERROR("Expected exactly 1 scannerInfo, got %zu!", scannerInfos.size());
133  return;
134  }
135 
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());
140 
141  PointCloud::Ptr cloud = pcl::make_shared<PointCloud>();
142  cloud->header.frame_id = config_.frame_id;
143  // not using time stamp from scanner here, because it is delayed by up to 1.5 seconds
144  cloud->header.stamp = (ros::Time::now().toSec() - 1 / expected_frequency_) * 1e6;
145 
146  cloud->height = 1;
147  cloud->width = scan->size();
148  for (size_t i = 0; i < scan->size(); ++i)
149  {
150  const ScanPoint& p = (*scan)[i];
152  np.x = p.getX();
153  np.y = p.getY();
154  np.z = p.getZ();
155  np.echowidth = p.getEchoWidth();
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);
160  }
161 
162  sensor_msgs::PointCloud2 msg;
163  pcl::toROSMsg(*cloud, msg);
165  }
166  break;
167  case Datatype_Objects:
168  datatypeStr = "Objects (" + ::toString(((ObjectList&)data).size()) + " objects)";
169  pubObjects((ObjectList&)data);
170  break;
171  case Datatype_Fields:
172  datatypeStr = "Fields (" + ::toString(((Fields&)data).getFields().size()) + " fields, " +
173  ::toString(((Fields&)data).getNumberOfValidFields()) + " of which are valid)";
174  break;
175  case Datatype_EvalCases:
176  datatypeStr = "EvalCases (" + ::toString(((EvalCases&)data).getEvalCases().size()) + " cases)";
177  break;
178  case Datatype_EvalCaseResults:
179  datatypeStr = "EvalCaseResults (" + ::toString(((EvalCaseResults&)data).size()) + " case results)";
180  break;
181  case Datatype_Msg:
182  datatypeStr = "Msg (" + ((Msg&)data).toString() + ")";
183  diagnostics_->broadcast(diagnostic_msgs::DiagnosticStatus::WARN, ((Msg&)data).toString());
184  diagnostics_->force_update();
185  break;
186  case Datatype_MeasurementList:
187  datatypeStr = "MeasurementList (" + ::toString(((MeasurementList&)data).m_list.size()) + " entries)";
188  break;
189  default:
190  datatypeStr = "(unknown)";
191  }
192 
193  sourceIdStr = ::toString(data.getSourceId());
194 
195  ROS_DEBUG("setData(): Called with data of type %s from ID %s", datatypeStr.c_str(), sourceIdStr.c_str());
196 }
197 
198 void SickLDMRS::validate_config(SickLDMRSDriverConfig &conf)
199 {
200  if (conf.start_angle <= conf.end_angle)
201  {
202  ROS_WARN("Start angle must be greater than end angle. Adjusting start_angle.");
203  conf.start_angle = conf.end_angle; // TODO: - 2 * ticks2rad
204  }
205 
206  if (conf.angular_resolution_type != SickLDMRSDriver_ConstantRes
207  && conf.scan_frequency != SickLDMRSDriver_ScanFreq1250)
208  {
209  ROS_WARN("Focused/flexible resolution only available at 12.5 Hz scan frequency. Adjusting scan frequency.");
210  conf.scan_frequency = SickLDMRSDriver_ScanFreq1250;
211  }
212 
213  if (conf.ignore_near_range && conf.layer_range_reduction != SickLDMRSDriver_RangeLowerReduced)
214  {
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;
217  }
218 
219  validate_flexres_resolution(conf.flexres_resolution1);
220  validate_flexres_resolution(conf.flexres_resolution2);
221  validate_flexres_resolution(conf.flexres_resolution3);
222  validate_flexres_resolution(conf.flexres_resolution4);
223  validate_flexres_resolution(conf.flexres_resolution5);
224  validate_flexres_resolution(conf.flexres_resolution6);
225  validate_flexres_resolution(conf.flexres_resolution7);
226  validate_flexres_resolution(conf.flexres_resolution8);
227  validate_flexres_start_angle(conf.flexres_start_angle1, conf.flexres_start_angle2);
228  validate_flexres_start_angle(conf.flexres_start_angle2, conf.flexres_start_angle3);
229  validate_flexres_start_angle(conf.flexres_start_angle3, conf.flexres_start_angle4);
230  validate_flexres_start_angle(conf.flexres_start_angle4, conf.flexres_start_angle5);
231  validate_flexres_start_angle(conf.flexres_start_angle5, conf.flexres_start_angle6);
232  validate_flexres_start_angle(conf.flexres_start_angle6, conf.flexres_start_angle7);
233  validate_flexres_start_angle(conf.flexres_start_angle7, conf.flexres_start_angle8);
234 }
235 
237 {
238  // Check that res is one of 4/8/16/32. This has to be checked manually here, since
239  // the dynamic parameter is an int with min 4 and max 32, so dynamic reconfigure
240  // doesn't prevent the user from setting an invalid value inside that range.
241  // (Values outside that range will still be clamped automatically.)
242 
243  switch (res)
244  {
245  case SickLDMRSDriver_Res0125:
246  case SickLDMRSDriver_Res0250:
247  case SickLDMRSDriver_Res0500:
248  case SickLDMRSDriver_Res1000:
249  break;
250  default:
251  ROS_WARN("Invalid flexres resolution %d! Setting to 32 (= 1 degree).", res);
252  res = SickLDMRSDriver_Res1000;
253  break;
254  }
255 }
256 
257 void SickLDMRS::validate_flexres_start_angle(double &angle1, double &angle2)
258 {
259  // make sure the angles are monotonically decreasing
260  if (angle2 > angle1)
261  {
262  angle2 = angle1;
263  }
264 }
265 
266 void SickLDMRS::pubObjects(datatypes::ObjectList &objects)
267 {
268  sick_ldmrs_msgs::ObjectArray oa;
269  oa.header.frame_id = config_.frame_id;
270  // not using time stamp from scanner here, because it is delayed by up to 1.5 seconds
271  oa.header.stamp = ros::Time::now();
272  oa.objects.resize(objects.size());
273 
274  for (int i = 0; i < objects.size(); i++)
275  {
276  oa.objects[i].id = objects[i].getObjectId();
277  oa.objects[i].tracking_time = ros::Time::now() - ros::Duration(objects[i].getObjectAge() / expected_frequency_);
278  oa.objects[i].last_seen = ros::Time::now() - ros::Duration(objects[i].getHiddenStatusAge() / expected_frequency_);
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();
285 
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();
290 
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();
293  oa.objects[i].object_box_center.pose.orientation = tf::createQuaternionMsgFromYaw(objects[i].getCourseAngle());
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();
299 
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++)
303  {
304  oa.objects[i].contour_points[j].x = contour[j].getX();
305  oa.objects[i].contour_points[j].y = contour[j].getY();
306  }
307 
308  //std::cout << objects[i].toString() << std::endl;
309  }
310 
311  object_pub_.publish(oa);
312 }
313 
315 {
316  devices::LDMRS* ldmrs;
317  ldmrs = dynamic_cast<devices::LDMRS*>(manager_->getFirstDeviceByType(Sourcetype_LDMRS));
318  if (ldmrs == NULL)
319  {
320  ROS_WARN("isUpsideDown: no connection to LDMRS!");
321  return true;
322  }
323 
324  UINT32 code;
325  ldmrs->getParameter(devices::ParaUpsideDownMode, &code);
326  return (code != 0);
327 }
328 
330 {
331  devices::LDMRS* ldmrs;
332  ldmrs = dynamic_cast<devices::LDMRS*>(manager_->getFirstDeviceByType(Sourcetype_LDMRS));
333  if (ldmrs == NULL)
334  {
335  ROS_WARN("printFlexResError: no connection to LDMRS!");
336  return;
337  }
338 
339  UINT32 code;
340  ldmrs->getParameter(devices::ParaDetailedError, &code);
341  std::string msg = flexres_err_to_string(code);
342  ROS_ERROR("FlexRes detailed error: %s", msg.c_str());
343 }
344 
345 void SickLDMRS::update_config(SickLDMRSDriverConfig &new_config, uint32_t level)
346 {
347  validate_config(new_config);
348  config_ = new_config;
349 
350  if (!initialized_)
351  return;
352 
353  ROS_INFO("Updating config...");
354 
355  devices::LDMRS* ldmrs;
356  ldmrs = dynamic_cast<devices::LDMRS*>(manager_->getFirstDeviceByType(Sourcetype_LDMRS));
357  if (ldmrs == NULL)
358  {
359  ROS_WARN("update_config: no connection to LDMRS!");
360  return;
361  }
362 
363  // TODO: if (new_config.start_angle < config_.end_angle): first update end angle,
364  // then start angle to ensure that always start_angle > end_angle; see comments
365  // in LuxBase::cmd_setScanAngles().
366  if (!ldmrs->setScanAngles(new_config.start_angle, new_config.end_angle))
367  ROS_WARN("Sending param not successful: ");
368 
369  switch (config_.scan_frequency)
370  {
371  case SickLDMRSDriver_ScanFreq1250:
372  expected_frequency_ = 12.5d;
373  break;
374  case SickLDMRSDriver_ScanFreq2500:
375  expected_frequency_ = 25.0d;
376  break;
377  case SickLDMRSDriver_ScanFreq5000:
378  expected_frequency_ = 50.0d;
379  break;
380  default:
381  ROS_ERROR("Unknown scan frequency: %i", config_.scan_frequency);
382  break;
383  }
384 
385  if (!ldmrs->setScanFrequency(expected_frequency_))
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");
401 
402  if (config_.angular_resolution_type == SickLDMRSDriver_FlexRes)
403  {
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));
413 
414  // --- skip zero-length sectors
415  for (int i = 0; i < res_map.size() - 1; ++i)
416  {
417  if (res_map[i].first > res_map[i + 1].first)
418  {
419  res_map_filtered.push_back(res_map[i]);
420  }
421  }
422  if (res_map[7].first > (-1918)) // -1918 = minimum start angle
423  {
424  res_map_filtered.push_back(res_map[7]);
425  }
426 
427  // --- ensure constraints are met
428  int shots_per_scan = 0;
429  double sum_res0125 = 0;
430  for (int i = 0; i < res_map_filtered.size() - 1; ++i)
431  {
432  // sector angle in degrees
433  double sector_angle = (res_map_filtered[i].first - res_map_filtered[i + 1].first) / 32.0;
434 
435  shots_per_scan += sector_angle * 32.0 / res_map_filtered[i].second;
436  if (res_map_filtered[i].second == SickLDMRSDriver_Res0125)
437  {
438  sum_res0125 += sector_angle;
439  }
440  }
441 
442  if (shots_per_scan > 440)
443  {
444  ROS_WARN("FlexRes: The number of shots per scan must be at most 440. Not updating FlexRes config!");
445  return;
446  }
447  if (sum_res0125 > 20.0)
448  {
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!");
450  return;
451  }
452 
453  // --- switch to constant resolution
454  // when applying FlexRes params, the angular resolution type has to be set
455  // to something other than FlexRes
456  if (!ldmrs->setParameter(devices::ParaAngularResolutionType, SickLDMRSDriver_ConstantRes))
457  ROS_WARN("Sending param not successful: AngularResolutionType");
458 
459  // sleep 10 seconds so that new config is applied by the scanner
460  usleep(10e6);
461 
462  // --- send FlexRes params to scanner
463  if (!ldmrs->setParameter(devices::ParaNumSectors, res_map_filtered.size()))
465 
466  for (int i = 0; i < res_map_filtered.size(); ++i)
467  {
468  // set sector start angle
469  if (!ldmrs->setParameter((devices::MrsParameterId)(0x4001 + i), res_map_filtered[i].first))
471 
472  // set sector resolution
473  if (!ldmrs->setParameter((devices::MrsParameterId)(0x4009 + i), res_map_filtered[i].second))
475  }
476  }
477 
478  // set angular resolution type *after* FlexRes config!
479  if (!ldmrs->setParameter(devices::ParaAngularResolutionType, config_.angular_resolution_type))
480  ROS_WARN("Sending param not successful: AngularResolutionType");
481 
482  ROS_INFO("... done updating config.");
483 }
484 
485 std::string SickLDMRS::flexres_err_to_string(const UINT32 code) const
486 {
487  switch (code)
488  {
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.";
503  default:
504  std::ostringstream ss;
505  ss << "UNKNOWN ERROR CODE (" << code << ")";
506  return ss.str();
507  }
508 }
509 
510 } /* namespace sick_ldmrs_driver */
511 
512 
513 int main(int argc, char **argv)
514 {
515  ros::init(argc, argv, "sick_ldmrs_node");
517  = boost::make_shared<diagnostic_updater::Updater>();
518 
519  // The MRS-App connects to an MRS, reads its configuration and receives all incoming data.
520  // First, create the manager object. The manager handles devices, collects
521  // device data and forwards it to the application(s).
522  ROS_INFO("Creating the manager.");
523  Manager manager;
524 
525  // Add the application. As the devices may send configuration data only once
526  // at startup, the applications must be present before the devices are
527  // started.
528  Sourcetype type;
529  std::string name;
530  UINT16 id;
531  bool result = false;
532 
533  ROS_INFO("Adding the application SickLDMRS.");
534  name = "Sick LDMRS ROS Driver App";
535  id = 1356;
536 
537  sick_ldmrs_driver::SickLDMRS app(&manager, diagnostics);
538  app.setApplicationName(name);
539 
540  result = manager.addApplication(&app, id);
541  if (result == false)
542  {
543  ROS_ERROR("Failed to add application %s, aborting!", name.c_str());
544  return EXIT_FAILURE;
545  }
546  ROS_INFO("Application is running.");
547 
548  //
549  // Add and run the sensor
550  //
551  // The MRS device could be configured like this:
552  // m_weWantScanData: true
553  // m_weWantObjectData: true
554  // m_weWantFieldData: false
555  // m_weWantScanDataFromSopas: false
556  ROS_INFO("Adding the LDMRS device.");
557  devices::LDMRS* ldmrs = new devices::LDMRS(&manager);
558  ldmrs->setWeWantObjectData(true);
559  std::string hostname;
560  ros::NodeHandle nh("~");
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);
564  name = "LDMRS-1";
565  id = 1;
566  result = manager.addAndRunDevice(ldmrs, name, id);
567  if (result == false)
568  {
569  ROS_ERROR("Failed to add device %s, aborting!", name.c_str());
570  return EXIT_FAILURE;
571  }
572 
573  std::string serial_number = ldmrs->getSerialNumber();
574  diagnostics->setHardwareID(serial_number);
575 
576  ROS_INFO("LD-MRS Firmware version is %s", ldmrs->getFirmwareVersion().c_str());
577 
578  // we need to initialize the app after setting up the ldmrs device
579  app.init();
580 
581  ROS_INFO("%s is initialized.", ros::this_node::getName().c_str());
582 
583  ros::Rate r(10.0);
584  while (ros::ok())
585  {
586  ros::spinOnce();
587  diagnostics->update();
588  r.sleep();
589  }
590 
591  return EXIT_SUCCESS;
592 }
sick_ldmrs_driver::SickLDMRS::produce_diagnostics
void produce_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
Definition: sick_ldmrs_node.cpp:103
sick_ldmrs_driver::SickLDMRS::diagnosticPub_
diagnostic_updater::DiagnosedPublisher< sensor_msgs::PointCloud2 > * diagnosticPub_
Definition: sick_ldmrs_node.hpp:91
main
int main(int argc, char **argv)
Definition: sick_ldmrs_node.cpp:513
Msg
sick_ldmrs_driver::SickLDMRS::printFlexResError
void printFlexResError()
Definition: sick_ldmrs_node.cpp:329
sick_ldmrs_msgs::SICK_LDMRS_Point::layer
std::uint8_t layer
msg
msg
boost::shared_ptr< diagnostic_updater::Updater >
diagnostic_updater::TimeStampStatusParam
diagnostic_updater::DiagnosticStatusWrapper::add
void add(const std::string &key, const bool &b)
ros::init
ROSCPP_DECL void init(const M_string &remappings, const std::string &name, uint32_t options=0)
sick_ldmrs_driver::SickLDMRS::init
void init()
Definition: sick_ldmrs_node.cpp:93
sick_ldmrs_driver::SickLDMRS::validate_flexres_resolution
void validate_flexres_resolution(int &res)
Definition: sick_ldmrs_node.cpp:236
sick_ldmrs_msgs::SICK_LDMRS_Point
ros::spinOnce
ROSCPP_DECL void spinOnce()
TimeBase< Time, Duration >::toSec
double toSec() const
sick_ldmrs_driver::SickLDMRS::pubObjects
void pubObjects(datatypes::ObjectList &objects)
Definition: sick_ldmrs_node.cpp:266
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
ros::NodeHandle::advertise
Publisher advertise(AdvertiseOptions &ops)
ros::ok
ROSCPP_DECL bool ok()
data
data
sick_ldmrs_driver::SickLDMRS::manager_
Manager * manager_
Definition: sick_ldmrs_node.hpp:98
f
f
sick_ldmrs_driver::SickLDMRS::update_config
void update_config(SickLDMRSDriverConfig &new_config, uint32_t level=0)
Definition: sick_ldmrs_node.cpp:345
diagnostic_updater::DiagnosticStatusWrapper::summary
void summary(const diagnostic_msgs::DiagnosticStatus &src)
diagnostic_updater::DiagnosedPublisher::publish
virtual void publish(const boost::shared_ptr< T > &message)
ROS_DEBUG
#define ROS_DEBUG(...)
sick_ldmrs_driver::SickLDMRS::setData
void setData(BasicData &data)
Definition: sick_ldmrs_node.cpp:118
sick_ldmrs_driver::SickLDMRS::dynamic_reconfigure_server_
dynamic_reconfigure::Server< SickLDMRSDriverConfig > dynamic_reconfigure_server_
Definition: sick_ldmrs_node.hpp:95
diagnostic_updater::DiagnosedPublisher< sensor_msgs::PointCloud2 >
sick_ldmrs_msgs::SICK_LDMRS_Point::echo
std::uint8_t echo
ROS_WARN
#define ROS_WARN(...)
sick_ldmrs_msgs::SICK_LDMRS_Point::flags
std::uint8_t flags
app
app
ros::Rate::sleep
bool sleep()
ros::this_node::getName
const ROSCPP_DECL std::string & getName()
transform_datatypes.h
sick_ldmrs_driver
Definition: sick_ldmrs_node.hpp:60
sick_ldmrs_driver::SickLDMRS::expected_frequency_
double expected_frequency_
Definition: sick_ldmrs_node.hpp:101
sick_ldmrs_driver::SickLDMRS::validate_config
void validate_config(SickLDMRSDriverConfig &conf)
Definition: sick_ldmrs_node.cpp:198
sick_ldmrs_node.hpp
ROS_ERROR
#define ROS_ERROR(...)
sick_ldmrs_driver::SickLDMRS::SickLDMRS
SickLDMRS(Manager *manager, boost::shared_ptr< diagnostic_updater::Updater > diagnostics)
Definition: sick_ldmrs_node.cpp:63
ros::NodeHandle::param
T param(const std::string &param_name, const T &default_val) const
diagnostic_updater::DiagnosticStatusWrapper
pcl::toROSMsg
void toROSMsg(const pcl::PointCloud< T > &cloud, sensor_msgs::Image &msg)
sick_ldmrs_driver::SickLDMRS::object_pub_
ros::Publisher object_pub_
Definition: sick_ldmrs_node.hpp:89
ros::Rate
sick_ldmrs_driver::SickLDMRS::isUpsideDown
bool isUpsideDown()
Definition: sick_ldmrs_node.cpp:314
sick_ldmrs_driver::SickLDMRS::initialized_
bool initialized_
Definition: sick_ldmrs_node.hpp:103
sick_ldmrs_driver::SickLDMRS::pub_
ros::Publisher pub_
Definition: sick_ldmrs_node.hpp:88
sick_ldmrs_driver::SickLDMRS::diagnostics_
boost::shared_ptr< diagnostic_updater::Updater > diagnostics_
Definition: sick_ldmrs_node.hpp:77
ROS_INFO
#define ROS_INFO(...)
sick_ldmrs_driver::SickLDMRS::nh_
ros::NodeHandle nh_
Definition: sick_ldmrs_node.hpp:87
tf::createQuaternionMsgFromYaw
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
sick_ldmrs_driver::SickLDMRS::config_
SickLDMRSDriverConfig config_
Definition: sick_ldmrs_node.hpp:94
sick_ldmrs_driver::SickLDMRS::flexres_err_to_string
std::string flexres_err_to_string(const UINT32 code) const
Definition: sick_ldmrs_node.cpp:485
ros::Duration
sick_ldmrs_driver::SickLDMRS::validate_flexres_start_angle
void validate_flexres_start_angle(double &angle1, double &angle2)
Definition: sick_ldmrs_node.cpp:257
sick_ldmrs_msgs::SICK_LDMRS_Point::echowidth
std::uint16_t echowidth
ros::NodeHandle
sick_ldmrs_driver::SickLDMRS
Definition: sick_ldmrs_node.hpp:65
sick_ldmrs_driver::SickLDMRS::~SickLDMRS
virtual ~SickLDMRS()
Definition: sick_ldmrs_node.cpp:88
ros::Time::now
static Time now()
diagnostic_updater::FrequencyStatusParam
pcl_conversions.h


sick_ldmrs_driver
Author(s): Martin Günther , Jochen Sprickerhof
autogenerated on Tue Oct 25 2022 02:14:18