sick_scan_common.cpp
Go to the documentation of this file.
1 
52 #ifdef _MSC_VER // compiling simulation for MS-Visual C++ - not defined for linux system
53 #pragma warning(disable: 4996)
54 #pragma warning(disable: 4267) // due to conversion warning size_t in the ros header file
55 #define _WIN32_WINNT 0x0501
56 
57 #endif
58 
62 
64 
65 #ifdef _MSC_VER
66 #include "sick_scan/rosconsole_simu.hpp"
67 #endif
68 
69 #include "sick_scan/binScanf.hpp"
70 // if there is a missing RadarScan.h, try to run catkin_make in der workspace-root
71 #include <sick_scan/RadarScan.h>
72 
73 
74 #include <cstdio>
75 #include <cstring>
76 
77 #define _USE_MATH_DEFINES
78 
79 #include <math.h>
80 
81 #ifndef rad2deg
82 #define rad2deg(x) ((x) / M_PI * 180.0)
83 #endif
84 
85 #define deg2rad_const (0.017453292519943295769236907684886f)
86 
87 #include "sick_scan/tcp/colaa.hpp"
88 #include "sick_scan/tcp/colab.hpp"
89 
90 #include <map>
91 #include <climits>
93 
99 void swap_endian(unsigned char *ptr, int numBytes)
100 {
101  unsigned char *buf = (ptr);
102  unsigned char tmpChar;
103  for (int i = 0; i < numBytes / 2; i++)
104  {
105  tmpChar = buf[numBytes - 1 - i];
106  buf[numBytes - 1 - i] = buf[i];
107  buf[i] = tmpChar;
108  }
109 }
110 
111 
119 std::vector<unsigned char> stringToVector(std::string s)
120 {
121  std::vector<unsigned char> result;
122  for (int j = 0; j < s.length(); j++)
123  {
124  result.push_back(s[j]);
125  }
126  return result;
127 
128 }
129 
130 
136 static int getDiagnosticErrorCode() // workaround due to compiling error under Visual C++
137 {
138 #ifdef _MSC_VER
139 #undef ERROR
140  return(2);
141 #else
142  return (diagnostic_msgs::DiagnosticStatus::ERROR);
143 #endif
144 }
145 
153 const std::string binScanfGetStringFromVec(std::vector<unsigned char> *replyDummy, int off, long len)
154 {
155  std::string s;
156  s = "";
157  for (int i = 0; i < len; i++)
158  {
159  char ch = (char) ((*replyDummy)[i + off]);
160  s += ch;
161  }
162  return (s);
163 }
164 
165 namespace sick_scan
166 {
174  unsigned char sick_crc8(unsigned char *msgBlock, int len)
175  {
176  unsigned char xorVal = 0x00;
177  int off = 0;
178  for (int i = off; i < len; i++)
179  {
180 
181  unsigned char val = msgBlock[i];
182  xorVal ^= val;
183  }
184  return (xorVal);
185  }
186 
192  std::string stripControl(std::vector<unsigned char> s)
193  {
194  bool isParamBinary = false;
195  int spaceCnt = 0x00;
196  int cnt0x02 = 0;
197 
198  for (int i = 0; i < s.size(); i++)
199  {
200  if (s[i] != 0x02)
201  {
202  isParamBinary = false;
203 
204  }
205  else
206  {
207  cnt0x02++;
208  }
209  if (i > 4)
210  {
211  break;
212  }
213  }
214  if (4 == cnt0x02)
215  {
216  isParamBinary = true;
217  }
218  std::string dest;
219  if (isParamBinary == true)
220  {
221  int parseState = 0;
222 
223  unsigned long lenId = 0x00;
224  char szDummy[255] = {0};
225  for (int i = 0; i < s.size(); i++)
226  {
227  switch(parseState)
228  {
229  case 0:
230  if (s[i] == 0x02)
231  {
232  dest += "<STX>";
233  }
234  else
235  {
236  dest += "?????";
237  }
238  if (i == 3)
239  {
240  parseState = 1;
241  }
242  break;
243  case 1:
244  lenId |= s[i] << (8 * (7 - i));
245  if (i == 7)
246  {
247  sprintf(szDummy, "<Len=%04lu>", lenId);
248  dest += szDummy;
249  parseState = 2;
250  }
251  break;
252  case 2:
253  {
254  unsigned long dataProcessed = i - 8;
255  if (s[i] == ' ')
256  {
257  spaceCnt++;
258  }
259  if (spaceCnt == 2)
260  {
261  parseState = 3;
262  }
263  dest += s[i];
264  if (dataProcessed >= (lenId - 1))
265  {
266  parseState = 4;
267  }
268 
269  break;
270  }
271 
272  case 3:
273  {
274  char ch = dest[dest.length()-1];
275  if (ch != ' ')
276  {
277  dest += ' ';
278  }
279  sprintf(szDummy, "0x%02x", s[i]);
280  dest += szDummy;
281 
282  unsigned long dataProcessed = i - 8;
283  if (dataProcessed >= (lenId -1))
284  {
285  parseState = 4;
286  }
287  break;
288  }
289  case 4:
290  {
291  sprintf(szDummy, " CRC:<0x%02x>", s[i]);
292  dest += szDummy;
293  break;
294  }
295  default:
296  break;
297  }
298  }
299  }
300  else
301  {
302  for (int i = 0; i < s.size(); i++)
303  {
304 
305  if (s[i] >= ' ')
306  {
307  // <todo> >= 0x80
308  dest += s[i];
309  }
310  else
311  {
312  switch (s[i])
313  {
314  case 0x02:
315  dest += "<STX>";
316  break;
317  case 0x03:
318  dest += "<ETX>";
319  break;
320  }
321  }
322  }
323  }
324 
325  return(dest);
326  }
327 
333  diagnosticPub_(NULL), parser_(parser)
334  // FIXME All Tims have 15Hz
335  {
337 
338  setSensorIsRadar(false);
339  init_cmdTables();
340 #ifndef _MSC_VER
341  dynamic_reconfigure::Server<sick_scan::SickScanConfig>::CallbackType f;
342  f = boost::bind(&sick_scan::SickScanCommon::update_config, this, _1, _2);
343  dynamic_reconfigure_server_.setCallback(f);
344 #else
345  // For simulation under MS Visual c++ the update config is switched off
346  {
347  SickScanConfig cfg;
348  ros::NodeHandle tmp("~");
349  double min_angle, max_angle, res_angle;
350  tmp.getParam(PARAM_MIN_ANG, min_angle);
351  tmp.getParam(PARAM_MAX_ANG, max_angle);
352  tmp.getParam(PARAM_RES_ANG, res_angle);
353  cfg.min_ang = min_angle;
354  cfg.max_ang = max_angle;
355  cfg.skip = 0;
356  update_config(cfg);
357  }
358 #endif
359  // datagram publisher (only for debug)
360  ros::NodeHandle pn("~");
361  pn.param<bool>("publish_datagram", publish_datagram_, false);
362  if (publish_datagram_)
363  {
364  datagram_pub_ = nh_.advertise<std_msgs::String>("datagram", 1000);
365  }
366 
367 
368  // Pointcloud2 publisher
369  //
370 
371 
372  std::string cloud_topic_val = "cloud";
373  pn.getParam("cloud_topic", cloud_topic_val);
374 
375  ROS_INFO("Publishing laserscan-pointcloud2 to %s", cloud_topic_val.c_str());
376  cloud_pub_ = nh_.advertise<sensor_msgs::PointCloud2>(cloud_topic_val, 100);
377 
378  // just for debugging, but very helpful for the start
379  cloud_radar_rawtarget_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud_radar_rawtarget", 100);
380  cloud_radar_track_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud_radar_track", 100);
381 
382  radarScan_pub_ = nh_.advertise<sick_scan::RadarScan>("radar", 100);
383  imuScan_pub_ = nh_.advertise<sensor_msgs::Imu>("imu", 100);
384  // scan publisher
385  pub_ = nh_.advertise<sensor_msgs::LaserScan>("scan", 1000);
386 
387 #ifndef _MSC_VER
388  diagnostics_.setHardwareID("none"); // set from device after connection
390  // frequency should be target +- 10%.
393  &expectedFrequency_, 0.1,
394  10),
395  // timestamp delta can be from 0.0 to 1.3x what it ideally is.
397  -1, 1.3 * 1.0 /
399  config_.time_offset));
400  ROS_ASSERT(diagnosticPub_ != NULL);
401 #endif
402  }
403 
409  {
410  /*
411  * Stop streaming measurements
412  */
413  const char requestScanData0[] = {"\x02sEN LMDscandata 0\x03\0"};
414  int result = sendSOPASCommand(requestScanData0, NULL);
415  if (result != 0)
416  {
417  // use printf because we cannot use ROS_ERROR from the destructor
418  printf("\nSOPAS - Error stopping streaming scan data!\n");
419  }
420  else
421  {
422  printf("\nSOPAS - Stopped streaming scan data.\n");
423  }
424 
425  return result;
426  }
427 
433  unsigned long SickScanCommon::convertBigEndianCharArrayToUnsignedLong(const unsigned char *vecArr)
434  {
435  unsigned long val = 0;
436  for (int i = 0; i < 4; i++)
437  {
438  val = val << 8;
439  val |= vecArr[i];
440  }
441  return (val);
442  }
443 
444 
450  int sick_scan::SickScanCommon::checkForBinaryAnswer(const std::vector<unsigned char> *reply)
451  {
452  int retVal = -1;
453 
454  if (reply == NULL)
455  {
456  }
457  else
458  {
459  if (reply->size() < 8)
460  {
461  retVal = -1;
462  }
463  else
464  {
465  const unsigned char *ptr = &((*reply)[0]);
466  unsigned binId = convertBigEndianCharArrayToUnsignedLong(ptr);
467  unsigned cmdLen = convertBigEndianCharArrayToUnsignedLong(ptr + 4);
468  if (binId == 0x02020202)
469  {
470  int replyLen = reply->size();
471  if (replyLen == 8 + cmdLen + 1)
472  {
473  retVal = cmdLen;
474  }
475  }
476  }
477  }
478  return (retVal);
479 
480  }
481 
482 
488  {
489  /*
490  * Set Maintenance access mode to allow reboot to be sent
491  */
492  std::vector<unsigned char> access_reply;
493  // changed from "03" to "3"
494  int result = sendSOPASCommand("\x02sMN SetAccessMode 3 F4724744\x03\0", &access_reply);
495  if (result != 0)
496  {
497  ROS_ERROR("SOPAS - Error setting access mode");
498  diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error setting access mode.");
499  return false;
500  }
501  std::string access_reply_str = replyToString(access_reply);
502  if (access_reply_str != "sAN SetAccessMode 1")
503  {
504  ROS_ERROR_STREAM("SOPAS - Error setting access mode, unexpected response : " << access_reply_str);
505  diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error setting access mode.");
506  return false;
507  }
508 
509  /*
510  * Send reboot command
511  */
512  std::vector<unsigned char> reboot_reply;
513  result = sendSOPASCommand("\x02sMN mSCreboot\x03\0", &reboot_reply);
514  if (result != 0)
515  {
516  ROS_ERROR("SOPAS - Error rebooting scanner");
517  diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error rebooting device.");
518  return false;
519  }
520  std::string reboot_reply_str = replyToString(reboot_reply);
521  if (reboot_reply_str != "sAN mSCreboot")
522  {
523  ROS_ERROR_STREAM("SOPAS - Error rebooting scanner, unexpected response : " << reboot_reply_str);
524  diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error setting access mode.");
525  return false;
526  }
527 
528  ROS_INFO("SOPAS - Rebooted scanner");
529 
530  // Wait a few seconds after rebooting
531  ros::Duration(15.0).sleep();
532 
533  return true;
534  }
535 
540  {
541  delete diagnosticPub_;
542 
543  printf("sick_scan driver exiting.\n");
544  }
545 
546 
552  std::string SickScanCommon::generateExpectedAnswerString(const std::vector<unsigned char> requestStr)
553  {
554  std::string expectedAnswer = "";
555  int i = 0;
556  char cntWhiteCharacter = 0;
557  int initalTokenCnt = 2; // number of initial token to identify command
558  std::map<std::string, int> specialTokenLen;
559  char firstToken[1024] = {0};
560  specialTokenLen["sRI"] = 1; // for SRi-Command only the first token identify the command
561  std::string tmpStr = "";
562  int cnt0x02 = 0;
563  bool isBinary = false;
564  for (int i = 0; i < 4; i++)
565  {
566  if (i < requestStr.size())
567  {
568  if (requestStr[i] == 0x02)
569  {
570  cnt0x02++;
571  }
572 
573  }
574  }
575 
576  int iStop = requestStr.size(); // copy string until end of string
577  if (cnt0x02 == 4)
578  {
579 
580  int cmdLen = 0;
581  for (int i = 0; i < 4; i++)
582  {
583  cmdLen |= cmdLen << 8;
584  cmdLen |= requestStr[i + 4];
585  }
586  iStop = cmdLen + 8;
587  isBinary = true;
588 
589  }
590  int iStart = (isBinary == true) ? 8 : 0;
591  for (int i = iStart; i < iStop; i++)
592  {
593  tmpStr += (char) requestStr[i];
594  }
595  if (isBinary)
596  {
597  tmpStr = "\x2" + tmpStr;
598  }
599  if (sscanf(tmpStr.c_str(), "\x2%s", firstToken) == 1)
600  {
601  if (specialTokenLen.find(firstToken) != specialTokenLen.end())
602  {
603  initalTokenCnt = specialTokenLen[firstToken];
604 
605  }
606  }
607 
608  for (int i = iStart; i < iStop; i++)
609  {
610  if ((requestStr[i] == ' ') || (requestStr[i] == '\x3'))
611  {
612  cntWhiteCharacter++;
613  }
614  if (cntWhiteCharacter >= initalTokenCnt)
615  {
616  break;
617  }
618  if (requestStr[i] == '\x2')
619  {
620  }
621  else
622  {
623  expectedAnswer += requestStr[i];
624  }
625  }
626 
630  std::map<std::string, std::string> keyWordMap;
631  keyWordMap["sWN"] = "sWA";
632  keyWordMap["sRN"] = "sRA";
633  keyWordMap["sRI"] = "sRA";
634  keyWordMap["sMN"] = "sAN";
635  keyWordMap["sEN"] = "sEA";
636 
637  for (std::map<std::string, std::string>::iterator it = keyWordMap.begin(); it != keyWordMap.end(); it++)
638  {
639 
640  std::string keyWord = it->first;
641  std::string newKeyWord = it->second;
642 
643  size_t pos = expectedAnswer.find(keyWord);
644  if (pos == std::string::npos)
645  {
646 
647  }
648  else
649  {
650  if (pos == 0) // must be 0, if keyword has been found
651  {
652  expectedAnswer.replace(pos, keyWord.length(), newKeyWord);
653  }
654  else
655  {
656  ROS_WARN("Unexpected position of key identifier.\n");
657  }
658  }
659 
660  }
661  return (expectedAnswer);
662 
663  }
664 
672  int SickScanCommon::sendSopasAndCheckAnswer(std::string requestStr, std::vector<unsigned char> *reply, int cmdId = -1)
673  {
674  std::vector<unsigned char> requestStringVec;
675  for (int i = 0; i < requestStr.length(); i++)
676  {
677  requestStringVec.push_back(requestStr[i]);
678  }
679  int retCode = sendSopasAndCheckAnswer(requestStringVec, reply, cmdId);
680  return (retCode);
681  }
682 
690  int SickScanCommon::sendSopasAndCheckAnswer(std::vector<unsigned char> requestStr, std::vector<unsigned char> *reply,
691  int cmdId = -1)
692  {
693 
694  std::string cmdStr = "";
695  int cmdLen = 0;
696  for (int i = 0; i < requestStr.size(); i++)
697  {
698  cmdLen++;
699  cmdStr += (char) requestStr[i];
700  }
701  int result = -1;
702 
703  std::string errString;
704  if (cmdId == -1)
705  {
706  errString = "Error unexpected Sopas Answer for request " + stripControl(requestStr);
707  }
708  else
709  {
710  errString = this->sopasCmdErrMsg[cmdId];
711  }
712 
713  std::string expectedAnswer = generateExpectedAnswerString(requestStr);
714 
715  // send sopas cmd
716 
717  std::string reqStr = replyToString(requestStr);
718  ROS_INFO("Sending : %s", stripControl(requestStr).c_str());
719  result = sendSOPASCommand(cmdStr.c_str(), reply, cmdLen);
720  std::string replyStr = replyToString(*reply);
721  std::vector<unsigned char> replyVec;
722  replyStr = "<STX>" + replyStr + "<ETX>";
723  replyVec=stringToVector(replyStr);
724  ROS_INFO("Receiving: %s", stripControl(replyVec).c_str());
725 
726  if (result != 0)
727  {
728  std::string tmpStr = "SOPAS Communication -" + errString;
729  ROS_INFO("%s\n", tmpStr.c_str());
731  }
732  else
733  {
734  std::string answerStr = replyToString(*reply);
735  std::string searchPattern = generateExpectedAnswerString(requestStr);
736 
737  if (answerStr.find(searchPattern) != std::string::npos)
738  {
739  result = 0;
740  }
741  else
742  {
743  if (cmdId == CMD_START_IMU_DATA)
744  {
745  ROS_INFO("IMU-Data transfer started. No checking of reply to avoid confusing with LMD Scandata\n");
746  result = 0;
747  }
748  else
749  {
750  std::string tmpMsg = "Error Sopas answer mismatch " + errString + "Answer= >>>" + answerStr + "<<<";
751  ROS_ERROR("%s\n", tmpMsg.c_str());
753  result = -1;
754  }
755  }
756  }
757  return result;
758 
759  }
760 
767  {
768  readTimeOutInMs = timeOutInMs;
769  }
770 
777  {
778  return (readTimeOutInMs);
779  }
780 
787  {
788  return m_protocolId;
789  }
790 
796  {
797  m_protocolId = cola_dialect_id;
798  }
799 
805  {
806  int result = init_device();
807  if (result != 0)
808  {
809  ROS_FATAL("Failed to init device: %d", result);
810  return result;
811  }
812  result = init_scanner();
813  if (result != 0)
814  {
815  ROS_INFO("Failed to init scanner Error Code: %d\nWaiting for timeout...\n"
816  "If the communication mode set in the scanner memory is different from that used by the driver, the scanner's communication mode is changed.\n"
817  "This requires a restart of the TCP-IP connection, which can extend the start time by up to 30 seconds. There are two ways to prevent this:\n"
818  "1. [Recommended] Set the communication mode with the SOPAS ET software to binary and save this setting in the scanner's EEPROM.\n"
819  "2. Use the parameter \"use_binary_protocol\" to overwrite the default settings of the driver.",
820  result);
821  }
822 
823  return result;
824  }
825 
826 
832  {
834  sopasCmdMaskVec.resize(
835  SickScanCommon::CMD_END); // you for cmd with variable content. sprintf should print into corresponding sopasCmdVec
836  sopasCmdErrMsg.resize(
837  SickScanCommon::CMD_END); // you for cmd with variable content. sprintf should print into corresponding sopasCmdVec
841 
842  std::string unknownStr = "Command or Error message not defined";
843  for (int i = 0; i < SickScanCommon::CMD_END; i++)
844  {
845  sopasCmdVec[i] = unknownStr;
846  sopasCmdMaskVec[i] = unknownStr; // for cmd with variable content. sprintf should print into corresponding sopasCmdVec
847  sopasCmdErrMsg[i] = unknownStr;
848  sopasReplyVec[i] = unknownStr;
849  sopasReplyStrVec[i] = unknownStr;
850  }
851 
852  sopasCmdVec[CMD_DEVICE_IDENT_LEGACY] = "\x02sRI 0\x03\0";
853  sopasCmdVec[CMD_DEVICE_IDENT] = "\x02sRN DeviceIdent\x03\0";
854  sopasCmdVec[CMD_REBOOT] = "\x02sMN mSCreboot\x03";
855  sopasCmdVec[CMD_WRITE_EEPROM] = "\x02sMN mEEwriteall\x03";
856  sopasCmdVec[CMD_SERIAL_NUMBER] = "\x02sRN SerialNumber\x03\0";
857  sopasCmdVec[CMD_FIRMWARE_VERSION] = "\x02sRN FirmwareVersion\x03\0";
858  sopasCmdVec[CMD_DEVICE_STATE] = "\x02sRN SCdevicestate\x03\0";
859  sopasCmdVec[CMD_OPERATION_HOURS] = "\x02sRN ODoprh\x03\0";
860  sopasCmdVec[CMD_POWER_ON_COUNT] = "\x02sRN ODpwrc\x03\0";
861  sopasCmdVec[CMD_LOCATION_NAME] = "\x02sRN LocationName\x03\0";
862  sopasCmdVec[CMD_ACTIVATE_STANDBY] = "\x02sMN LMCstandby\x03";
863  sopasCmdVec[CMD_SET_ACCESS_MODE_3] = "\x02sMN SetAccessMode 3 F4724744\x03\0";
864  sopasCmdVec[CMD_GET_OUTPUT_RANGES] = "\x02sRN LMPoutputRange\x03";
865  sopasCmdVec[CMD_RUN] = "\x02sMN Run\x03\0";
866  sopasCmdVec[CMD_STOP_SCANDATA] = "\x02sEN LMDscandata 0\x03";
867  sopasCmdVec[CMD_START_SCANDATA] = "\x02sEN LMDscandata 1\x03";
868  sopasCmdVec[CMD_START_RADARDATA] = "\x02sEN LMDradardata 1\x03";
869  sopasCmdVec[CMD_ACTIVATE_NTP_CLIENT] ="\x02sWN TSCRole 1\x03";
870  sopasCmdVec[CMD_SET_NTP_INTERFACE_ETH]= "\x02sWN TSCTCInterface 0\x03";
871 
872  /*
873  * Radar specific commands
874  */
875  sopasCmdVec[CMD_SET_TRANSMIT_RAWTARGETS_ON] = "\x02sWN TransmitTargets 1\x03"; // transmit raw target for radar
876  sopasCmdVec[CMD_SET_TRANSMIT_RAWTARGETS_OFF] = "\x02sWN TransmitTargets 0\x03"; // do not transmit raw target for radar
877  sopasCmdVec[CMD_SET_TRANSMIT_OBJECTS_ON] = "\x02sWN TransmitObjects 1\x03"; // transmit objects from radar tracking
878  sopasCmdVec[CMD_SET_TRANSMIT_OBJECTS_OFF] = "\x02sWN TransmitObjects 0\x03"; // do not transmit objects from radar tracking
879  sopasCmdVec[CMD_SET_TRACKING_MODE_0] = "\x02sWN TCTrackingMode 0\x03"; // set object tracking mode to BASIC
880  sopasCmdVec[CMD_SET_TRACKING_MODE_1] = "\x02sWN TCTrackingMode 1\x03"; // set object tracking mode to TRAFFIC
881 
882 
883  sopasCmdVec[CMD_LOAD_APPLICATION_DEFAULT] = "\x02sMN mSCloadappdef\x03"; // load application default
884  sopasCmdVec[CMD_DEVICE_TYPE] = "\x02sRN DItype\x03"; // ask for radar device type
885  sopasCmdVec[CMD_ORDER_NUMBER] = "\x02sRN OrdNum\x03"; // ask for radar order number
886 
887 
888 
889  sopasCmdVec[CMD_START_MEASUREMENT] = "\x02sMN LMCstartmeas\x03";
890  sopasCmdVec[CMD_STOP_MEASUREMENT] = "\x02sMN LMCstopmeas\x03";
891  sopasCmdVec[CMD_APPLICATION_MODE_FIELD_ON] = "\x02sWN SetActiveApplications 1 FEVL 1\x03"; // <STX>sWN{SPC}SetActiveApplications{SPC}1{SPC}FEVL{SPC}1<ETX>
892  sopasCmdVec[CMD_APPLICATION_MODE_FIELD_OFF] = "\x02sWN SetActiveApplications 1 FEVL 0\x03"; // <STX>sWN{SPC}SetActiveApplications{SPC}1{SPC}FEVL{SPC}1<ETX>
893  sopasCmdVec[CMD_APPLICATION_MODE_RANGING_ON] = "\x02sWN SetActiveApplications 1 RANG 1\x03";
894  sopasCmdVec[CMD_SET_TO_COLA_A_PROTOCOL] = "\x02sWN EIHstCola 0\x03";
895  sopasCmdVec[CMD_GET_PARTIAL_SCANDATA_CFG] = "\x02sRN LMDscandatacfg\x03";//<STX>sMN{SPC}mLMPsetscancfg{SPC } +5000{SPC}+1{SPC}+5000{SPC}-450000{SPC}+2250000<ETX>
896  sopasCmdVec[CMD_GET_PARTIAL_SCAN_CFG] = "\x02sRN LMPscancfg\x03";
897  sopasCmdVec[CMD_SET_TO_COLA_B_PROTOCOL] = "\x02sWN EIHstCola 1\x03";
898 
899  sopasCmdVec[CMD_STOP_IMU_DATA] = "\x02sEN InertialMeasurementUnit 0\x03";
900  sopasCmdVec[CMD_START_IMU_DATA] = "\x02sEN InertialMeasurementUnit 1\x03";
901 
902  // defining cmd mask for cmds with variable input
903  sopasCmdMaskVec[CMD_SET_PARTIAL_SCAN_CFG] = "\x02sMN mLMPsetscancfg %d 1 %d 0 0\x03";//scanfreq [1/100 Hz],angres [1/10000°],
904  sopasCmdMaskVec[CMD_SET_PARTICLE_FILTER] = "\x02sWN LFPparticle %d %d\x03";
905  sopasCmdMaskVec[CMD_SET_MEAN_FILTER] = "\x02sWN LFPmeanfilter %d +%d 1\x03";
906  sopasCmdMaskVec[CMD_ALIGNMENT_MODE] = "\x02sWN MMAlignmentMode %d\x03";
907  sopasCmdMaskVec[CMD_APPLICATION_MODE] = "\x02sWN SetActiveApplications 1 %s %d\x03";
908  sopasCmdMaskVec[CMD_SET_OUTPUT_RANGES] = "\x02sWN LMPoutputRange 1 %X %X %X\x03";
909  sopasCmdMaskVec[CMD_SET_PARTIAL_SCANDATA_CFG] = "\x02sWN LMDscandatacfg %02d 00 %d %d 0 00 00 0 0 0 1 1\x03";
910  sopasCmdMaskVec[CMD_SET_ECHO_FILTER] = "\x02sWN FREchoFilter %d\x03";
911  sopasCmdMaskVec[CMD_SET_NTP_UPDATETIME] = "\x02sWN TSCTCupdatetime %d\x03";
912  sopasCmdMaskVec[CMD_SET_NTP_TIMEZONE]= "sWN TSCTCtimezone %d";
913  sopasCmdMaskVec[CMD_SET_IP_ADDR] = "\x02sWN EIIpAddr %02X %02X %02X %02X\x03";
914  sopasCmdMaskVec[CMD_SET_NTP_SERVER_IP_ADDR] = "\x02sWN TSCTCSrvAddr %02X %02X %02X %02X\x03";
915  sopasCmdMaskVec[CMD_SET_GATEWAY] = "\x02sWN EIgate %02X %02X %02X %02X\x03";
916  //error Messages
917  sopasCmdErrMsg[CMD_DEVICE_IDENT_LEGACY] = "Error reading device ident";
918  sopasCmdErrMsg[CMD_DEVICE_IDENT] = "Error reading device ident for MRS-family";
919  sopasCmdErrMsg[CMD_SERIAL_NUMBER] = "Error reading SerialNumber";
920  sopasCmdErrMsg[CMD_FIRMWARE_VERSION] = "Error reading FirmwareVersion";
921  sopasCmdErrMsg[CMD_DEVICE_STATE] = "Error reading SCdevicestate";
922  sopasCmdErrMsg[CMD_OPERATION_HOURS] = "Error reading operation hours";
923  sopasCmdErrMsg[CMD_POWER_ON_COUNT] = "Error reading operation power on counter";
924  sopasCmdErrMsg[CMD_LOCATION_NAME] = "Error reading Locationname";
925  sopasCmdErrMsg[CMD_ACTIVATE_STANDBY] = "Error acticvating Standby";
926  sopasCmdErrMsg[CMD_SET_PARTICLE_FILTER] = "Error setting Particelefilter";
927  sopasCmdErrMsg[CMD_SET_MEAN_FILTER] = "Error setting Meanfilter";
928  sopasCmdErrMsg[CMD_ALIGNMENT_MODE] = "Error setting Alignmentmode";
929  sopasCmdErrMsg[CMD_APPLICATION_MODE] = "Error setting Meanfilter";
930  sopasCmdErrMsg[CMD_SET_ACCESS_MODE_3] = "Error Access Mode";
931  sopasCmdErrMsg[CMD_SET_OUTPUT_RANGES] = "Error setting angular ranges";
932  sopasCmdErrMsg[CMD_GET_OUTPUT_RANGES] = "Error reading angle range";
933  sopasCmdErrMsg[CMD_RUN] = "FATAL ERROR unable to start RUN mode!";
934  sopasCmdErrMsg[CMD_SET_PARTIAL_SCANDATA_CFG] = "Error setting Scandataconfig";
935  sopasCmdErrMsg[CMD_STOP_SCANDATA] = "Error stopping scandata output";
936  sopasCmdErrMsg[CMD_START_SCANDATA] = "Error starting Scandata output";
937  sopasCmdErrMsg[CMD_SET_IP_ADDR] = "Error setting IP address";
938  sopasCmdErrMsg[CMD_SET_GATEWAY] = "Error setting gateway";
939  sopasCmdErrMsg[CMD_REBOOT] = "Error rebooting the device";
940  sopasCmdErrMsg[CMD_WRITE_EEPROM] = "Error writing data to EEPRom";
941  sopasCmdErrMsg[CMD_ACTIVATE_NTP_CLIENT] ="Error activating NTP client";
942  sopasCmdErrMsg[CMD_SET_NTP_INTERFACE_ETH] ="Error setting NTP interface to ETH";
943  sopasCmdErrMsg[CMD_SET_NTP_SERVER_IP_ADDR] ="Error setting NTP server Adress";
944  sopasCmdErrMsg[CMD_SET_NTP_UPDATETIME] = "Error setting NTP update time";
945  sopasCmdErrMsg[CMD_SET_NTP_TIMEZONE] = "Error setting NTP timezone";
946 
947  // ML: Add hier more useful cmd and mask entries
948 
949  // After definition of command, we specify the command sequence for scanner initalisation
950 
951  // try for MRS1104
953 
955  {
957  }
958  else
959  {
960  //for binary Mode Testing
962  }
963 
964  bool tryToStopMeasurement = true;
966  {
967 
968  tryToStopMeasurement = false;
969  //XXX
970  // do not stop measurement for TiM571 otherwise the scanner would not start after start measurement
971  // do not change the application - not supported for TiM5xx
972  }
973  if (parser_->getCurrentParamPtr()->getDeviceIsRadar() == true)
974  {
975  sopasCmdChain.push_back(CMD_LOAD_APPLICATION_DEFAULT); // load application default for radar
976 
977  tryToStopMeasurement = false;
978  // do not stop measurement for RMS320 - the RMS320 does not support the stop command
979  }
980 
981  if (tryToStopMeasurement)
982  {
984  int numberOfLayers = parser_->getCurrentParamPtr()->getNumberOfLayers();
985 
986  switch (numberOfLayers)
987  {
988  case 4:
991  sopasCmdChain.push_back(CMD_DEVICE_IDENT);
992  sopasCmdChain.push_back(CMD_SERIAL_NUMBER);
993 
994  break;
995  case 24:
996  // just measuring - Application setting not supported
997  // "Old" device ident command "SRi 0" not supported
998  sopasCmdChain.push_back(CMD_DEVICE_IDENT);
999  break;
1000 
1001  default:
1005 
1006  sopasCmdChain.push_back(CMD_SERIAL_NUMBER);
1007  break;
1008  }
1009 
1010  }
1011  sopasCmdChain.push_back(CMD_FIRMWARE_VERSION); // read firmware
1012  sopasCmdChain.push_back(CMD_DEVICE_STATE); // read device state
1013  sopasCmdChain.push_back(CMD_OPERATION_HOURS); // read operation hours
1014  sopasCmdChain.push_back(CMD_POWER_ON_COUNT); // read power on count
1015  sopasCmdChain.push_back(CMD_LOCATION_NAME); // read location name
1016 
1017 
1018  return (0);
1019 
1020  }
1021 
1022 
1028  {
1029 
1030  const int MAX_STR_LEN = 1024;
1031 
1032  int maxNumberOfEchos = 1;
1033 
1034 
1035  maxNumberOfEchos = this->parser_->getCurrentParamPtr()->getNumberOfMaximumEchos(); // 1 for TIM 571, 3 for MRS1104, 5 for 6000
1036 
1037 
1038  bool rssiFlag = false;
1039  bool rssiResolutionIs16Bit = true; //True=16 bit Flase=8bit
1040  int activeEchos = 0;
1041  ros::NodeHandle pn("~");
1042 
1043  pn.getParam("intensity", rssiFlag);
1044  pn.getParam("intensity_resolution_16bit", rssiResolutionIs16Bit);
1045 
1046  //check new ip adress and add cmds to write ip to comand chain
1047  std::string sNewIPAddr = "";
1048  boost::asio::ip::address_v4 ipNewIPAddr;
1049  bool setNewIPAddr = false;
1050  setNewIPAddr = pn.getParam("new_IP_address", sNewIPAddr);
1051  if (setNewIPAddr)
1052  {
1053  boost::system::error_code ec;
1054  ipNewIPAddr = boost::asio::ip::address_v4::from_string(sNewIPAddr, ec);
1055  if (ec == 0)
1056  {
1057  sopasCmdChain.clear();
1059  }
1060  else
1061  {
1062  setNewIPAddr = false;
1063  ROS_ERROR("ERROR: IP ADDRESS could not be parsed Boost Error %s:%d", ec.category().name(), ec.value());;
1064  }
1065 
1066  }
1067  std::string sNTPIpAdress = "";
1068  boost::asio::ip::address_v4 NTPIpAdress;
1069  bool setUseNTP=false;
1070  setUseNTP = pn.getParam("ntp_server_address", sNTPIpAdress);
1071  if (setUseNTP)
1072  {
1073  boost::system::error_code ec;
1074  NTPIpAdress = boost::asio::ip::address_v4::from_string(sNTPIpAdress, ec);
1075  if (ec != 0)
1076  {
1077  setUseNTP = false;
1078  ROS_ERROR("ERROR: NTP Server IP ADDRESS could not be parsed Boost Error %s:%d", ec.category().name(), ec.value());;
1079  }
1080  }
1081 
1082  this->parser_->getCurrentParamPtr()->setIntensityResolutionIs16Bit(rssiResolutionIs16Bit);
1083 
1084  // parse active_echos entry and set flag array
1085  pn.getParam("active_echos", activeEchos);
1086 
1087  ROS_INFO("Parameter setting for <active_echo: %d>", activeEchos);
1088  std::vector<bool> outputChannelFlag;
1089  outputChannelFlag.resize(maxNumberOfEchos);
1090  int i;
1091  int numOfFlags = 0;
1092  for (i = 0; i < outputChannelFlag.size(); i++)
1093  {
1094  /*
1095  After consultation with the company SICK,
1096  all flags are set to true because the firmware currently does not support single selection of targets.
1097  The selection of the echoes takes place via FREchoFilter.
1098  */
1099  /* former implementation
1100  if (activeEchos & (1 << i))
1101  {
1102  outputChannelFlag[i] = true;
1103  numOfFlags++;
1104  }
1105  else
1106  {
1107  outputChannelFlag[i] = false;
1108  }
1109  */
1110  outputChannelFlag[i] = true; // always true (see comment above)
1111  numOfFlags++;
1112  }
1113 
1114  if (numOfFlags == 0) // Fallback-Solution
1115  {
1116  outputChannelFlag[0] = true;
1117  numOfFlags = 1;
1118  ROS_WARN("Activate at least one echo.");
1119  }
1120 
1121  int result;
1122  //================== DEFINE ANGULAR SETTING ==========================
1123  int angleRes10000th = 0;
1124  int angleStart10000th = 0;
1125  int angleEnd10000th = 0;
1126 
1127 
1128  // Mainloop for initial SOPAS cmd-Handling
1129  //
1130  // To add new commands do the followings:
1131  // 1. Define new enum-entry in the enumumation "enum SOPAS_CMD" in the file sick_scan_common.h
1132  // 2. Define new command sequence in the member function init_cmdTables()
1133  // 3. Add cmd-id in the sopasCmdChain to trigger sending of command.
1134  // 4. Add handling of reply by using for the pattern "REPLY_HANDLING" in this code and adding a new case instruction.
1135  // That's all!
1136 
1137 
1138  volatile bool useBinaryCmd = false;
1139  if (this->parser_->getCurrentParamPtr()->getUseBinaryProtocol()) // hard coded for every scanner type
1140  {
1141  useBinaryCmd = true; // shall we talk ascii or binary with the scanner type??
1142  }
1143 
1144  bool useBinaryCmdNow = false;
1145  int maxCmdLoop = 2; // try binary and ascii during startup
1146 
1147  const int shortTimeOutInMs = 5000; // during startup phase to check binary or ascii
1148  const int defaultTimeOutInMs = 20000; // standard time out 20 sec.
1149 
1150  setReadTimeOutInMs(shortTimeOutInMs);
1151 
1152  bool restartDueToProcolChange = false;
1153 
1154 
1155  for (int i = 0; i < this->sopasCmdChain.size(); i++)
1156  {
1157  ros::Duration(0.2).sleep(); // could maybe removed
1158 
1159  int cmdId = sopasCmdChain[i]; // get next command
1160  std::string sopasCmd = sopasCmdVec[cmdId];
1161  std::vector<unsigned char> replyDummy;
1162  std::vector<unsigned char> reqBinary;
1163 
1164  std::vector<unsigned char> sopasCmdVec;
1165  for (int j = 0; j < sopasCmd.length(); j++)
1166  {
1167  sopasCmdVec.push_back(sopasCmd[j]);
1168  }
1169  ROS_DEBUG("Command: %s", stripControl(sopasCmdVec).c_str());
1170 
1171  // switch to either binary or ascii after switching the command mode
1172  // via ... command
1173 
1174 
1175  for (int iLoop = 0; iLoop < maxCmdLoop; iLoop++)
1176  {
1177  if (iLoop == 0)
1178  {
1179  useBinaryCmdNow = useBinaryCmd; // start with expected value
1180 
1181  }
1182  else
1183  {
1184  useBinaryCmdNow = !useBinaryCmdNow;// try the other option
1185  useBinaryCmd = useBinaryCmdNow; // and use it from now on as default
1186 
1187  }
1188 
1189  this->setProtocolType(useBinaryCmdNow ? CoLa_B : CoLa_A);
1190 
1191 
1192  if (useBinaryCmdNow)
1193  {
1194  this->convertAscii2BinaryCmd(sopasCmd.c_str(), &reqBinary);
1195  result = sendSopasAndCheckAnswer(reqBinary, &replyDummy);
1196  sopasReplyBinVec[cmdId] = replyDummy;
1197  }
1198  else
1199  {
1200  result = sendSopasAndCheckAnswer(sopasCmd.c_str(), &replyDummy);
1201  }
1202  if (result == 0) // command sent successfully
1203  {
1204  // useBinaryCmd holds information about last successful command mode
1205  break;
1206  }
1207  }
1208  if (result != 0)
1209  {
1210  ROS_ERROR("%s", sopasCmdErrMsg[cmdId].c_str());
1212  }
1213  else
1214  {
1215  sopasReplyStrVec[cmdId] = replyToString(replyDummy);
1216  }
1217 
1218  //============================================
1219  // Handle reply of specific commands here by inserting new case instruction
1220  // REPLY_HANDLING
1221  //============================================
1222  maxCmdLoop = 1;
1223 
1224 
1225  // handle special configuration commands ...
1226 
1227  switch (cmdId)
1228  {
1229 
1231  {
1232  bool protocolCheck = checkForProtocolChangeAndMaybeReconnect(useBinaryCmdNow);
1233  if (false == protocolCheck)
1234  {
1235  restartDueToProcolChange = true;
1236  }
1237  useBinaryCmd = useBinaryCmdNow;
1238  setReadTimeOutInMs(defaultTimeOutInMs);
1239  }
1240  break;
1242  {
1243  bool protocolCheck = checkForProtocolChangeAndMaybeReconnect(useBinaryCmdNow);
1244  if (false == protocolCheck)
1245  {
1246  restartDueToProcolChange = true;
1247  }
1248  useBinaryCmd = useBinaryCmdNow;
1249  setReadTimeOutInMs(defaultTimeOutInMs);
1250  }
1251  break;
1252 
1253  /*
1254  SERIAL_NUMBER: Device ident must be read before!
1255  */
1256 
1257  case CMD_DEVICE_IDENT: // FOR MRS6xxx the Device Ident holds all specific information (used instead of CMD_SERIAL_NUMBER)
1258  {
1259  std::string deviceIdent = "";
1260  int cmdLen = this->checkForBinaryAnswer(&replyDummy);
1261  if (cmdLen == -1)
1262  {
1263  int idLen = 0;
1264  int versionLen = 0;
1265  // ASCII-Return
1266  std::string deviceIdentKeyWord = "sRA DeviceIdent";
1267  char *ptr = (char *) (&(replyDummy[0]));
1268  ptr++; // skip 0x02
1269  ptr += deviceIdentKeyWord.length();
1270  ptr++; //skip blank
1271  sscanf(ptr, "%d", &idLen);
1272  char *ptr2 = strchr(ptr, ' ');
1273  if (ptr2 != NULL)
1274  {
1275  ptr2++;
1276  for (int i = 0; i < idLen; i++)
1277  {
1278  deviceIdent += *ptr2;
1279  ptr2++;
1280  }
1281 
1282  }
1283  ptr = ptr2;
1284  ptr++; //skip blank
1285  sscanf(ptr, "%d", &versionLen);
1286  ptr2 = strchr(ptr, ' ');
1287  if (ptr2 != NULL)
1288  {
1289  ptr2++;
1290  deviceIdent += " V";
1291  for (int i = 0; i < versionLen; i++)
1292  {
1293  deviceIdent += *ptr2;
1294  ptr2++;
1295  }
1296  }
1297  diagnostics_.setHardwareID(deviceIdent);
1298  if (!isCompatibleDevice(deviceIdent))
1299  {
1300  return ExitFatal;
1301  }
1302 // ROS_ERROR("BINARY REPLY REQUIRED");
1303  }
1304  else
1305  {
1306  long dummy0, dummy1, identLen, versionLen;
1307  dummy0 = 0;
1308  dummy1 = 0;
1309  identLen = 0;
1310  versionLen = 0;
1311 
1312  const char *scanMask0 = "%04y%04ysRA DeviceIdent %02y";
1313  const char *scanMask1 = "%02y";
1314  unsigned char *replyPtr = &(replyDummy[0]);
1315  int scanDataLen0 = binScanfGuessDataLenFromMask(scanMask0);
1316  int scanDataLen1 = binScanfGuessDataLenFromMask(scanMask1); // should be: 2
1317  binScanfVec(&replyDummy, scanMask0, &dummy0, &dummy1, &identLen);
1318 
1319  std::string identStr = binScanfGetStringFromVec(&replyDummy, scanDataLen0, identLen);
1320  int off = scanDataLen0 + identLen; // consuming header + fixed part + ident
1321 
1322  std::vector<unsigned char> restOfReplyDummy = std::vector<unsigned char>(replyDummy.begin() + off,
1323  replyDummy.end());
1324 
1325  versionLen = 0;
1326  binScanfVec(&restOfReplyDummy, "%02y", &versionLen);
1327  std::string versionStr = binScanfGetStringFromVec(&restOfReplyDummy, scanDataLen1, versionLen);
1328  std::string fullIdentVersionInfo = identStr + " V" + versionStr;
1329  diagnostics_.setHardwareID(fullIdentVersionInfo);
1330  if (!isCompatibleDevice(fullIdentVersionInfo))
1331  {
1332  return ExitFatal;
1333  }
1334 
1335  }
1336  break;
1337  }
1338 
1339 
1340  case CMD_SERIAL_NUMBER:
1341  if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 4)
1342  {
1343  // do nothing for MRS1104 here
1344  }
1345  else
1346  {
1349 
1351  {
1352  return ExitFatal;
1353  }
1354  }
1355  break;
1356  /*
1357  DEVICE_STATE
1358  */
1359  case CMD_DEVICE_STATE:
1360  {
1361  int deviceState = -1;
1362  /*
1363  * Process device state, 0=Busy, 1=Ready, 2=Error
1364  * If configuration parameter is set, try resetting device in error state
1365  */
1366 
1367  int iRetVal = 0;
1368  if (useBinaryCmd)
1369  {
1370  long dummy0 = 0x00;
1371  long dummy1 = 0x00;
1372  deviceState = 0x00; // must be set to zero (because only one byte will be copied)
1373  iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_DEVICE_STATE]), "%4y%4ysRA SCdevicestate %1y", &dummy0,
1374  &dummy1, &deviceState);
1375  }
1376  else
1377  {
1378  iRetVal = sscanf(sopasReplyStrVec[CMD_DEVICE_STATE].c_str(), "sRA SCdevicestate %d", &deviceState);
1379  }
1380  if (iRetVal > 0) // 1 or 3 (depending of ASCII or Binary)
1381  {
1382  switch (deviceState)
1383  {
1384  case 0:
1385  ROS_DEBUG("Laser is busy");
1386  break;
1387  case 1:
1388  ROS_DEBUG("Laser is ready");
1389  break;
1390  case 2:
1391  ROS_ERROR_STREAM("Laser reports error state : " << sopasReplyStrVec[CMD_DEVICE_STATE]);
1392  if (config_.auto_reboot)
1393  {
1394  rebootScanner();
1395  };
1396  break;
1397  default:
1398  ROS_WARN_STREAM("Laser reports unknown devicestate : " << sopasReplyStrVec[CMD_DEVICE_STATE]);
1399  break;
1400  }
1401  }
1402  }
1403  break;
1404 
1405  case CMD_OPERATION_HOURS:
1406  {
1407  int operationHours = -1;
1408  int iRetVal = 0;
1409  /*
1410  * Process device state, 0=Busy, 1=Ready, 2=Error
1411  * If configuration parameter is set, try resetting device in error state
1412  */
1413  if (useBinaryCmd)
1414  {
1415  long dummy0, dummy1;
1416  dummy0 = 0;
1417  dummy1 = 0;
1418  operationHours = 0;
1419  iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_OPERATION_HOURS]), "%4y%4ysRA ODoprh %4y", &dummy0, &dummy1,
1420  &operationHours);
1421  }
1422  else
1423  {
1424  operationHours = 0;
1425  iRetVal = sscanf(sopasReplyStrVec[CMD_OPERATION_HOURS].c_str(), "sRA ODoprh %x", &operationHours);
1426  }
1427  if (iRetVal > 0)
1428  {
1429  double hours = 0.1 * operationHours;
1430  pn.setParam("operationHours", hours);
1431  }
1432  }
1433  break;
1434 
1435  case CMD_POWER_ON_COUNT:
1436  {
1437  int powerOnCount = -1;
1438  int iRetVal = -1;
1439  if (useBinaryCmd)
1440  {
1441  long dummy0, dummy1;
1442  powerOnCount = 0;
1443  iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_POWER_ON_COUNT]), "%4y%4ysRA ODpwrc %4y", &dummy0, &dummy1,
1444  &powerOnCount);
1445  }
1446  else
1447  {
1448  iRetVal = sscanf(sopasReplyStrVec[CMD_POWER_ON_COUNT].c_str(), "sRA ODpwrc %x", &powerOnCount);
1449  }
1450  if (iRetVal > 0)
1451  {
1452  pn.setParam("powerOnCount", powerOnCount);
1453  }
1454 
1455  }
1456  break;
1457 
1458  case CMD_LOCATION_NAME:
1459  {
1460  char szLocationName[MAX_STR_LEN] = {0};
1461  const char *strPtr = sopasReplyStrVec[CMD_LOCATION_NAME].c_str();
1462  const char *searchPattern = "sRA LocationName "; // Bug fix (leading space) Jan 2018
1463  strcpy(szLocationName, "unknown location");
1464  if (useBinaryCmd)
1465  {
1466  int iRetVal = 0;
1467  long dummy0, dummy1, locationNameLen;
1468  const char *binLocationNameMask = "%4y%4ysRA LocationName %2y";
1469  int prefixLen = binScanfGuessDataLenFromMask(binLocationNameMask);
1470  dummy0 = 0;
1471  dummy1 = 0;
1472  locationNameLen = 0;
1473 
1474  iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_LOCATION_NAME]), binLocationNameMask, &dummy0, &dummy1,
1475  &locationNameLen);
1476  if (iRetVal > 0)
1477  {
1478  std::string s;
1479  std::string locationNameStr = binScanfGetStringFromVec(&(sopasReplyBinVec[CMD_LOCATION_NAME]), prefixLen,
1480  locationNameLen);
1481  strcpy(szLocationName, locationNameStr.c_str());
1482  }
1483  }
1484  else
1485  {
1486  if (strstr(strPtr, searchPattern) == strPtr)
1487  {
1488  const char *ptr = strPtr + strlen(searchPattern);
1489  strcpy(szLocationName, ptr);
1490  }
1491  else
1492  {
1493  ROS_WARN("Location command not supported.\n");
1494  }
1495  }
1496  pn.setParam("locationName", std::string(szLocationName));
1497  }
1498  break;
1500  {
1501 
1502  const char *strPtr = sopasReplyStrVec[CMD_LOCATION_NAME].c_str();
1503  ROS_INFO("Config: %s\n", strPtr);
1504  }
1505  break;
1506  // ML: add here reply handling
1507  }
1508 
1509  if (restartDueToProcolChange)
1510  {
1511  return ExitError;
1512 
1513  }
1514 
1515  }
1516 
1517  if (setNewIPAddr)
1518  {
1519 
1520  setNewIpAddress(ipNewIPAddr, useBinaryCmd);
1521  ROS_INFO("IP address changed. Node restart required");
1522  ROS_INFO("Exiting node NOW.");
1523  exit(0);//stopping node hard to avoide further IP-Communication
1524  }
1525 
1526  if (setUseNTP)
1527  {
1528 
1529  setNTPServerAndStart(NTPIpAdress, useBinaryCmd);
1530  }
1531 
1533  {
1534  //=====================================================
1535  // Radar specific commands
1536  //=====================================================
1537  }
1538  else
1539  {
1540  //-----------------------------------------------------------------
1541  //
1542  // This is recommended to decide between TiM551 and TiM561/TiM571 capabilities
1543  // The TiM551 has an angular resolution of 1.000 [deg]
1544  // The TiM561 and TiM571 have an angular resolution of 0.333 [deg]
1545  //-----------------------------------------------------------------
1546 
1547  angleRes10000th = (int) (boost::math::round(
1548  10000.0 * this->parser_->getCurrentParamPtr()->getAngularDegreeResolution()));
1549  std::vector<unsigned char> askOutputAngularRangeReply;
1550 
1551  if (useBinaryCmd)
1552  {
1553  std::vector<unsigned char> reqBinary;
1554  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &reqBinary);
1556  }
1557  else
1558  {
1559  result = sendSopasAndCheckAnswer(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &askOutputAngularRangeReply);
1560  }
1561 
1562 
1563  if (0 == result)
1564  {
1565  int askTmpAngleRes10000th = 0;
1566  int askTmpAngleStart10000th = 0;
1567  int askTmpAngleEnd10000th = 0;
1568  char dummy0[MAX_STR_LEN] = {0};
1569  char dummy1[MAX_STR_LEN] = {0};
1570  int dummyInt = 0;
1571 
1572  int iDummy0, iDummy1;
1573  std::string askOutputAngularRangeStr = replyToString(askOutputAngularRangeReply);
1574  // Binary-Reply Tab. 63
1575  // 0x20 Space
1576  // 0x00 0x01 -
1577  // 0x00 0x00 0x05 0x14 // Resolution in 1/10000th degree --> 0.13°
1578  // 0x00 0x04 0x93 0xE0 // Start Angle 300000 -> 30°
1579  // 0x00 0x16 0xE3 0x60 // End Angle 1.500.000 -> 150° // in ROS +/-60°
1580  // 0x83 // Checksum
1581 
1582  int numArgs;
1583 
1584  if (useBinaryCmd)
1585  {
1586  iDummy0 = 0;
1587  iDummy1 = 0;
1588  dummyInt = 0;
1589  askTmpAngleRes10000th = 0;
1590  askTmpAngleStart10000th = 0;
1591  askTmpAngleEnd10000th = 0;
1592 
1593  const char *askOutputAngularRangeBinMask = "%4y%4ysRA LMPoutputRange %2y%4y%4y%4y";
1594  numArgs = binScanfVec(&sopasReplyBinVec[CMD_GET_OUTPUT_RANGES], askOutputAngularRangeBinMask, &iDummy0,
1595  &iDummy1,
1596  &dummyInt,
1597  &askTmpAngleRes10000th,
1598  &askTmpAngleStart10000th,
1599  &askTmpAngleEnd10000th);
1600  //
1601  }
1602  else
1603  {
1604  numArgs = sscanf(askOutputAngularRangeStr.c_str(), "%s %s %d %X %X %X", dummy0, dummy1,
1605  &dummyInt,
1606  &askTmpAngleRes10000th,
1607  &askTmpAngleStart10000th,
1608  &askTmpAngleEnd10000th);
1609  }
1610  if (numArgs >= 6)
1611  {
1612  double askTmpAngleRes = askTmpAngleRes10000th / 10000.0;
1613  double askTmpAngleStart = askTmpAngleStart10000th / 10000.0;
1614  double askTmpAngleEnd = askTmpAngleEnd10000th / 10000.0;
1615 
1616  angleRes10000th = askTmpAngleRes10000th;
1617  ROS_INFO("Angle resolution of scanner is %0.5lf [deg] (in 1/10000th deg: 0x%X)", askTmpAngleRes,
1618  askTmpAngleRes10000th);
1619 
1620  }
1621  }
1622  //-----------------------------------------------------------------
1623  //
1624  // Set Min- und Max scanning angle given by config
1625  //
1626  //-----------------------------------------------------------------
1627 
1628  ROS_INFO("MIN_ANG: %8.3f [rad] %8.3f [deg]", config_.min_ang, rad2deg(this->config_.min_ang));
1629  ROS_INFO("MAX_ANG: %8.3f [rad] %8.3f [deg]", config_.max_ang, rad2deg(this->config_.max_ang));
1630 
1631  // convert to 10000th degree
1632  double minAngSopas = rad2deg(this->config_.min_ang) + 90;
1633  double maxAngSopas = rad2deg(this->config_.max_ang) + 90;
1634  angleStart10000th = (int) (boost::math::round(10000.0 * minAngSopas));
1635  angleEnd10000th = (int) (boost::math::round(10000.0 * maxAngSopas));
1636 
1637  char requestOutputAngularRange[MAX_STR_LEN];
1638 
1639  std::vector<unsigned char> outputAngularRangeReply;
1640  const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_OUTPUT_RANGES].c_str();
1641  sprintf(requestOutputAngularRange, pcCmdMask, angleRes10000th, angleStart10000th, angleEnd10000th);
1642 
1643  if (useBinaryCmd)
1644  {
1645  unsigned char tmpBuffer[255] = {0};
1646  unsigned char sendBuffer[255] = {0};
1647  UINT16 sendLen;
1648  std::vector<unsigned char> reqBinary;
1649  int iStatus = 1;
1650  // const char *askOutputAngularRangeBinMask = "%4y%4ysWN LMPoutputRange %2y%4y%4y%4y";
1651  // int askOutputAngularRangeBinLen = binScanfGuessDataLenFromMask(askOutputAngularRangeBinMask);
1652  // askOutputAngularRangeBinLen -= 8; // due to header and length identifier
1653 
1654  strcpy((char *) tmpBuffer, "WN LMPoutputRange ");
1655  unsigned short orgLen = strlen((char *) tmpBuffer);
1656  colab::addIntegerToBuffer<UINT16>(tmpBuffer, orgLen, iStatus);
1657  colab::addIntegerToBuffer<UINT32>(tmpBuffer, orgLen, angleRes10000th);
1658  colab::addIntegerToBuffer<UINT32>(tmpBuffer, orgLen, angleStart10000th);
1659  colab::addIntegerToBuffer<UINT32>(tmpBuffer, orgLen, angleEnd10000th);
1660  sendLen = orgLen;
1661  colab::addFrameToBuffer(sendBuffer, tmpBuffer, &sendLen);
1662 
1663  // binSprintfVec(&reqBinary, askOutputAngularRangeBinMask, 0x02020202, askOutputAngularRangeBinLen, iStatus, angleRes10000th, angleStart10000th, angleEnd10000th);
1664 
1665  // unsigned char sickCrc = sick_crc8((unsigned char *)(&(reqBinary)[8]), reqBinary.size() - 8);
1666  // reqBinary.push_back(sickCrc);
1667  reqBinary = std::vector<unsigned char>(sendBuffer, sendBuffer + sendLen);
1668  // Here we must build a more complex binaryRequest
1669 
1670  // this->convertAscii2BinaryCmd(requestOutputAngularRange, &reqBinary);
1671  result = sendSopasAndCheckAnswer(reqBinary, &outputAngularRangeReply);
1672  }
1673  else
1674  {
1675  result = sendSopasAndCheckAnswer(requestOutputAngularRange, &outputAngularRangeReply);
1676  }
1677 
1678  //-----------------------------------------------------------------
1679  //
1680  // Get Min- und Max scanning angle from the scanner to verify angle setting and correct the config, if something went wrong.
1681  //
1682  // IMPORTANT:
1683  // Axis Orientation in ROS differs from SICK AXIS ORIENTATION!!!
1684  // In relation to a body the standard is:
1685  // x forward
1686  // y left
1687  // z up
1688  // see http://www.ros.org/reps/rep-0103.html#coordinate-frame-conventions for more details
1689  //-----------------------------------------------------------------
1690 
1691  askOutputAngularRangeReply.clear();
1692 
1693  if (useBinaryCmd)
1694  {
1695  std::vector<unsigned char> reqBinary;
1696  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &reqBinary);
1698  }
1699  else
1700  {
1701  result = sendSopasAndCheckAnswer(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &askOutputAngularRangeReply);
1702  }
1703 
1704  if (result == 0)
1705  {
1706  char dummy0[MAX_STR_LEN] = {0};
1707  char dummy1[MAX_STR_LEN] = {0};
1708  int dummyInt = 0;
1709  int askAngleRes10000th = 0;
1710  int askAngleStart10000th = 0;
1711  int askAngleEnd10000th = 0;
1712  int iDummy0, iDummy1;
1713  iDummy0 = 0;
1714  iDummy1 = 0;
1715  std::string askOutputAngularRangeStr = replyToString(askOutputAngularRangeReply);
1716  // Binary-Reply Tab. 63
1717  // 0x20 Space
1718  // 0x00 0x01 -
1719  // 0x00 0x00 0x05 0x14 // Resolution in 1/10000th degree --> 0.13°
1720  // 0x00 0x04 0x93 0xE0 // Start Angle 300000 -> 30°
1721  // 0x00 0x16 0xE3 0x60 // End Angle 1.500.000 -> 150° // in ROS +/-60°
1722  // 0x83 // Checksum
1723 
1724  int numArgs;
1725 
1726  /*
1727  *
1728  * Initialize variables
1729  */
1730 
1731  iDummy0 = 0;
1732  iDummy1 = 0;
1733  dummyInt = 0;
1734  askAngleRes10000th = 0;
1735  askAngleStart10000th = 0;
1736  askAngleEnd10000th = 0;
1737 
1738  /*
1739  * scan values
1740  *
1741  */
1742 
1743  if (useBinaryCmd)
1744  {
1745  const char *askOutputAngularRangeBinMask = "%4y%4ysRA LMPoutputRange %2y%4y%4y%4y";
1746  numArgs = binScanfVec(&sopasReplyBinVec[CMD_GET_OUTPUT_RANGES], askOutputAngularRangeBinMask, &iDummy0,
1747  &iDummy1,
1748  &dummyInt,
1749  &askAngleRes10000th,
1750  &askAngleStart10000th,
1751  &askAngleEnd10000th);
1752  //
1753  }
1754  else
1755  {
1756  numArgs = sscanf(askOutputAngularRangeStr.c_str(), "%s %s %d %X %X %X", dummy0, dummy1,
1757  &dummyInt,
1758  &askAngleRes10000th,
1759  &askAngleStart10000th,
1760  &askAngleEnd10000th);
1761  }
1762  if (numArgs >= 6)
1763  {
1764  double askTmpAngleRes = askAngleRes10000th / 10000.0;
1765  double askTmpAngleStart = askAngleStart10000th / 10000.0;
1766  double askTmpAngleEnd = askAngleEnd10000th / 10000.0;
1767 
1768  angleRes10000th = askAngleRes10000th;
1769  ROS_INFO("Angle resolution of scanner is %0.5lf [deg] (in 1/10000th deg: 0x%X)", askTmpAngleRes,
1770  askAngleRes10000th);
1771 
1772  }
1773  double askAngleRes = askAngleRes10000th / 10000.0;
1774  double askAngleStart = askAngleStart10000th / 10000.0;
1775  double askAngleEnd = askAngleEnd10000th / 10000.0;
1776 
1777  askAngleStart -= 90; // angle in ROS relative to y-axis
1778  askAngleEnd -= 90; // angle in ROS relative to y-axis
1779  this->config_.min_ang = askAngleStart / 180.0 * M_PI;
1780  this->config_.max_ang = askAngleEnd / 180.0 * M_PI;
1781  ros::NodeHandle nhPriv("~");
1782  nhPriv.setParam("min_ang",
1783  this->config_.min_ang); // update parameter setting with "true" values read from scanner
1784  nhPriv.setParam("max_ang",
1785  this->config_.max_ang); // update parameter setting with "true" values read from scanner
1786  ROS_INFO("MIN_ANG (after command verification): %8.3f [rad] %8.3f [deg]", config_.min_ang,
1787  rad2deg(this->config_.min_ang));
1788  ROS_INFO("MAX_ANG (after command verification): %8.3f [rad] %8.3f [deg]", config_.max_ang,
1789  rad2deg(this->config_.max_ang));
1790  }
1791 
1792 
1793 
1794  //-----------------------------------------------------------------
1795  //
1796  // Configure the data content of scan messing regarding to config.
1797  //
1798  //-----------------------------------------------------------------
1799  /*
1800  see 4.3.1 Configure the data content for the scan in the
1801  */
1802  // 1 2 3
1803  // Prepare flag array for echos
1804  // Except for the LMS5xx scanner here the mask is hard 00 see SICK Telegram listing "Telegram structure: sWN LMDscandatacfg" for details
1805 
1806  outputChannelFlagId = 0x00;
1807  for (int i = 0; i < outputChannelFlag.size(); i++)
1808  {
1809  outputChannelFlagId |= ((outputChannelFlag[i] == true) << i);
1810  }
1811  if (outputChannelFlagId < 1)
1812  {
1813  outputChannelFlagId = 1; // at least one channel must be set
1814  }
1816  {
1817  outputChannelFlagId = 1;
1818  ROS_INFO("LMS 5xx detected overwriting output channel flag ID");
1819 
1820  ROS_INFO("LMS 5xx detected overwriting resolution flag (only 8 bit supported)");
1822  rssiResolutionIs16Bit = this->parser_->getCurrentParamPtr()->getIntensityResolutionIs16Bit();
1823  }
1825  {
1826  ROS_INFO("MRS 1xxx detected overwriting resolution flag (only 8 bit supported)");
1828  rssiResolutionIs16Bit = this->parser_->getCurrentParamPtr()->getIntensityResolutionIs16Bit();
1829 
1830  }
1831 
1832  // set scanning angle for tim5xx and for mrs1104
1833  if ((this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 1)
1834  || (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 4)
1835  || (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 24)
1836  )
1837  {
1838  char requestLMDscandatacfg[MAX_STR_LEN];
1839  // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
1840  // CMD_SET_PARTIAL_SCANDATA_CFG = "\x02sWN LMDscandatacfg %02d 00 %d 0 0 00 00 0 0 0 0 1\x03";
1841  const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_PARTIAL_SCANDATA_CFG].c_str();
1842  sprintf(requestLMDscandatacfg, pcCmdMask, outputChannelFlagId, rssiFlag ? 1 : 0, rssiResolutionIs16Bit ? 1 : 0);
1843  if (useBinaryCmd)
1844  {
1845  std::vector<unsigned char> reqBinary;
1846  this->convertAscii2BinaryCmd(requestLMDscandatacfg, &reqBinary);
1847  // FOR MRS6124 this should be
1848  // like this:
1849  // 0000 02 02 02 02 00 00 00 20 73 57 4e 20 4c 4d 44 73 .......sWN LMDs
1850  // 0010 63 61 6e 64 61 74 61 63 66 67 20 1f 00 01 01 00 candatacfg .....
1851  // 0020 00 00 00 00 00 00 00 01 5c
1853  }
1854  else
1855  {
1856  std::vector<unsigned char> lmdScanDataCfgReply;
1857  result = sendSopasAndCheckAnswer(requestLMDscandatacfg, &lmdScanDataCfgReply);
1858  }
1859 
1860 
1861  // check setting
1862  char requestLMDscandatacfgRead[MAX_STR_LEN];
1863  // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
1864 
1865  strcpy(requestLMDscandatacfgRead, sopasCmdVec[CMD_GET_PARTIAL_SCANDATA_CFG].c_str());
1866  if (useBinaryCmd)
1867  {
1868  std::vector<unsigned char> reqBinary;
1869  this->convertAscii2BinaryCmd(requestLMDscandatacfgRead, &reqBinary);
1871  }
1872  else
1873  {
1874  std::vector<unsigned char> lmdScanDataCfgReadReply;
1875  result = sendSopasAndCheckAnswer(requestLMDscandatacfgRead, &lmdScanDataCfgReadReply);
1876  }
1877 
1878 
1879  }
1880  //BBB
1881  // set scanning angle for tim5xx and for mrs1104
1882  double scan_freq=0;
1883  double ang_res=0;
1884  pn.getParam("scan_freq", scan_freq); // filter_echos
1885  pn.getParam("ang_res", ang_res); // filter_echos
1886  if (scan_freq!=0 || ang_res!=0)
1887  {
1888  if(scan_freq!=0 && ang_res!=0)
1889  {
1890  char requestLMDscancfg[MAX_STR_LEN];
1891  // sopasCmdMaskVec[CMD_SET_PARTIAL_SCAN_CFG] = "\x02sMN mLMPsetscancfg %d 1 %d 0 0\x03";//scanfreq [1/100 Hz],angres [1/10000°],
1892  const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_PARTIAL_SCAN_CFG].c_str();
1893  sprintf(requestLMDscancfg, pcCmdMask, (long)(scan_freq*100+1e-9),(long)(ang_res*10000+1e-9));
1894  if (useBinaryCmd)
1895  {
1896  std::vector<unsigned char> reqBinary;
1897  this->convertAscii2BinaryCmd(requestLMDscancfg, &reqBinary);
1899  }
1900  else
1901  {
1902  std::vector<unsigned char> lmdScanCfgReply;
1903  result = sendSopasAndCheckAnswer(requestLMDscancfg, &lmdScanCfgReply);
1904  }
1905 
1906 
1907  // check setting
1908  char requestLMDscancfgRead[MAX_STR_LEN];
1909  // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
1910 
1911  strcpy(requestLMDscancfgRead, sopasCmdVec[CMD_GET_PARTIAL_SCAN_CFG].c_str());
1912  if (useBinaryCmd)
1913  {
1914  std::vector<unsigned char> reqBinary;
1915  this->convertAscii2BinaryCmd(requestLMDscancfgRead, &reqBinary);
1917  }
1918  else
1919  {
1920  std::vector<unsigned char> lmdScanDataCfgReadReply;
1921  result = sendSopasAndCheckAnswer(requestLMDscancfgRead, &lmdScanDataCfgReadReply);
1922  }
1923 
1924  }
1925  else
1926  {
1927  ROS_ERROR("ang_res and scan_freq have to be set, only one param is set skiping scan_fre/ang_res config");
1928  }
1929  }
1930  // CONFIG ECHO-Filter (only for MRS1000 not available for TiM5xx
1931  if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() >= 4)
1932  {
1933  char requestEchoSetting[MAX_STR_LEN];
1934  int filterEchoSetting = 0;
1935  pn.getParam("filter_echos", filterEchoSetting); // filter_echos
1936  if (filterEchoSetting < 0)
1937  { filterEchoSetting = 0; }
1938  if (filterEchoSetting > 2)
1939  { filterEchoSetting = 2; }
1940  // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
1941  const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_ECHO_FILTER].c_str();
1942  /*
1943  First echo : 0
1944  All echos : 1
1945  Last echo : 2
1946  */
1947  sprintf(requestEchoSetting, pcCmdMask, filterEchoSetting);
1948  std::vector<unsigned char> outputFilterEchoRangeReply;
1949 
1950 
1951  if (useBinaryCmd)
1952  {
1953  std::vector<unsigned char> reqBinary;
1954  this->convertAscii2BinaryCmd(requestEchoSetting, &reqBinary);
1956  }
1957  else
1958  {
1959  result = sendSopasAndCheckAnswer(requestEchoSetting, &outputFilterEchoRangeReply);
1960  }
1961 
1962  }
1963 
1964 
1965  }
1967 
1968 
1969  //-----------------------------------------------------------------
1970  //
1971  // Start sending LMD-Scandata messages
1972  //
1973  //-----------------------------------------------------------------
1974  std::vector<int> startProtocolSequence;
1975  bool deviceIsRadar = false;
1977  {
1978  ros::NodeHandle tmpParam("~");
1979  bool transmitRawTargets = true;
1980  bool transmitObjects = true;
1981  int trackingMode = 0;
1982  std::string trackingModeDescription[] = {"BASIC", "VEHICLE"};
1983 
1984  int numTrackingModes = sizeof(trackingModeDescription) / sizeof(trackingModeDescription[0]);
1985 
1986  tmpParam.getParam("transmit_raw_targets", transmitRawTargets);
1987  tmpParam.getParam("transmit_objects", transmitObjects);
1988  tmpParam.getParam("tracking_mode", trackingMode);
1989 
1990 
1991  if ((trackingMode < 0) || (trackingMode >= numTrackingModes))
1992  {
1993  ROS_WARN("tracking mode id invalid. Switch to tracking mode 0");
1994  trackingMode = 0;
1995  }
1996  ROS_INFO("Raw target transmission is switched [%s]", transmitRawTargets ? "ON" : "OFF");
1997  ROS_INFO("Object transmission is switched [%s]", transmitObjects ? "ON" : "OFF");
1998  ROS_INFO("Tracking mode is set to id [%d] [%s]", trackingMode, trackingModeDescription[trackingMode].c_str());
1999 
2000  deviceIsRadar = true;
2001 
2002  // Asking some informational from the radar
2003  startProtocolSequence.push_back(CMD_DEVICE_TYPE);
2004  startProtocolSequence.push_back(CMD_SERIAL_NUMBER);
2005  startProtocolSequence.push_back(CMD_ORDER_NUMBER);
2006 
2007  /*
2008  * With "sWN TCTrackingMode 0" BASIC-Tracking activated
2009  * With "sWN TCTrackingMode 1" TRAFFIC-Tracking activated
2010  *
2011  */
2012  if (transmitRawTargets)
2013  {
2014  startProtocolSequence.push_back(CMD_SET_TRANSMIT_RAWTARGETS_ON); // raw targets will be transmitted
2015  }
2016  else
2017  {
2018  startProtocolSequence.push_back(CMD_SET_TRANSMIT_RAWTARGETS_OFF); // NO raw targets will be transmitted
2019  }
2020 
2021  if (transmitObjects)
2022  {
2023  startProtocolSequence.push_back(CMD_SET_TRANSMIT_OBJECTS_ON); // tracking objects will be transmitted
2024  }
2025  else
2026  {
2027  startProtocolSequence.push_back(CMD_SET_TRANSMIT_OBJECTS_OFF); // NO tracking objects will be transmitted
2028  }
2029 
2030  switch (trackingMode)
2031  {
2032  case 0:
2033  startProtocolSequence.push_back(CMD_SET_TRACKING_MODE_0);
2034  break;
2035  case 1:
2036  startProtocolSequence.push_back(CMD_SET_TRACKING_MODE_1);
2037  break;
2038  default:
2039  ROS_DEBUG("Tracking mode switching sequence unknown\n");
2040  break;
2041 
2042  }
2043  // leave user level
2044 
2045  // sWN TransmitTargets 1
2046  // initializing sequence for radar based devices
2047  startProtocolSequence.push_back(CMD_RUN); // leave user level
2048  startProtocolSequence.push_back(CMD_START_RADARDATA);
2049  }
2050  else
2051  {
2052  // initializing sequence for laserscanner
2053  startProtocolSequence.push_back(CMD_START_MEASUREMENT);
2054  startProtocolSequence.push_back(CMD_RUN); // leave user level
2055  startProtocolSequence.push_back(CMD_START_SCANDATA);
2056  if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 4) // MRS1104 - start IMU-Transfer
2057  {
2058  ros::NodeHandle tmp("~");
2059  bool imu_enable = false;
2060  tmp.getParam("imu_enable", imu_enable);
2061  if (imu_enable)
2062  {
2063  if(useBinaryCmdNow==true)
2064  {
2065  ROS_INFO("Enable IMU data transfer");
2066  // TODO Flag to decide between IMU on or off
2067  startProtocolSequence.push_back(CMD_START_IMU_DATA);
2068  }
2069  else{
2070  ROS_FATAL("IMU USAGE NOT POSSIBLE IN ASCII COMMUNICATION MODE.\nTo use the IMU the communication with the scanner must be set to binary mode.\n This can be done by inserting the line:\n<param name=\"use_binary_protocol\" type=\"bool\" value=\"True\" />\n into the launchfile.\n See also https://github.com/SICKAG/sick_scan/blob/master/doc/IMU.md");
2071  exit(0);
2072  }
2073 
2074  }
2075  }
2076  }
2077 
2078  std::vector<int>::iterator it;
2079  for (it = startProtocolSequence.begin(); it != startProtocolSequence.end(); it++)
2080  {
2081  int cmdId = *it;
2082  std::vector<unsigned char> tmpReply;
2083  // sendSopasAndCheckAnswer(sopasCmdVec[cmdId].c_str(), &tmpReply);
2084 
2085  std::string sopasCmd = sopasCmdVec[cmdId];
2086  std::vector<unsigned char> replyDummy;
2087  std::vector<unsigned char> reqBinary;
2088  std::vector<unsigned char> sopasVec;
2089  sopasVec=stringToVector(sopasCmd);
2090  ROS_DEBUG("Command: %s", stripControl(sopasVec).c_str());
2091  if (useBinaryCmd)
2092  {
2093  this->convertAscii2BinaryCmd(sopasCmd.c_str(), &reqBinary);
2094  result = sendSopasAndCheckAnswer(reqBinary, &replyDummy, cmdId);
2095  sopasReplyBinVec[cmdId] = replyDummy;
2096 
2097  switch (cmdId)
2098  {
2099  case CMD_START_SCANDATA:
2100  // ROS_DEBUG("Sleeping for a couple of seconds of start measurement\n");
2101  // ros::Duration(10.0).sleep();
2102  break;
2103  }
2104  }
2105  else
2106  {
2107  result = sendSopasAndCheckAnswer(sopasCmd.c_str(), &replyDummy, cmdId);
2108  }
2109 
2110  if (result != 0)
2111  {
2112  ROS_ERROR("%s", sopasCmdErrMsg[cmdId].c_str());
2114  }
2115  else
2116  {
2117  sopasReplyStrVec[cmdId] = replyToString(replyDummy);
2118  }
2119 
2120 
2121  if (cmdId == CMD_START_RADARDATA)
2122  {
2123  ROS_DEBUG("Starting radar data ....\n");
2124  }
2125 
2126 
2127  if (cmdId == CMD_START_SCANDATA)
2128  {
2129  ROS_DEBUG("Starting scan data ....\n");
2130  }
2131 
2132  if (cmdId == CMD_RUN)
2133  {
2134  bool waitForDeviceState = true;
2135  if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 1)
2136  {
2137  waitForDeviceState = false; // do nothing for tim5xx
2138  }
2139  if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 24)
2140  {
2141  waitForDeviceState = false; // do nothing for MRS6xxx
2142  }
2143 
2144  if (waitForDeviceState)
2145  {
2146  int maxWaitForDeviceStateReady = 45; // max. 30 sec. (see manual)
2147  bool scannerReady = false;
2148  for (int i = 0; i < maxWaitForDeviceStateReady; i++)
2149  {
2150  double shortSleepTime = 1.0;
2151  std::string sopasCmd = sopasCmdVec[CMD_DEVICE_STATE];
2152  std::vector<unsigned char> replyDummy;
2153 
2154  int iRetVal = 0;
2155  int deviceState = 0;
2156 
2157  std::vector<unsigned char> reqBinary;
2158  std::vector<unsigned char> sopasVec;
2159  sopasVec=stringToVector(sopasCmd);
2160  ROS_DEBUG("Command: %s", stripControl(sopasVec).c_str());
2161  if (useBinaryCmd)
2162  {
2163  this->convertAscii2BinaryCmd(sopasCmd.c_str(), &reqBinary);
2164  result = sendSopasAndCheckAnswer(reqBinary, &replyDummy);
2165  sopasReplyBinVec[CMD_DEVICE_STATE] = replyDummy;
2166  }
2167  else
2168  {
2169  result = sendSopasAndCheckAnswer(sopasCmd.c_str(), &replyDummy);
2171  }
2172 
2173 
2174  if (useBinaryCmd)
2175  {
2176  long dummy0, dummy1;
2177  dummy0 = 0;
2178  dummy1 = 0;
2179  deviceState = 0;
2180  iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_DEVICE_STATE]), "%4y%4ysRA SCdevicestate %1y", &dummy0,
2181  &dummy1, &deviceState);
2182  }
2183  else
2184  {
2185  iRetVal = sscanf(sopasReplyStrVec[CMD_DEVICE_STATE].c_str(), "sRA SCdevicestate %d", &deviceState);
2186  }
2187  if (iRetVal > 0) // 1 or 3 (depending of ASCII or Binary)
2188  {
2189  if (deviceState == 1) // scanner is ready
2190  {
2191  scannerReady = true; // interrupt waiting for scanner ready
2192  ROS_INFO("Scanner ready for measurement after %d [sec]", i);
2193  break;
2194  }
2195  }
2196  ROS_INFO("Waiting for scanner ready state since %d secs", i);
2197  ros::Duration(shortSleepTime).sleep();
2198 
2199  if (scannerReady)
2200  {
2201  break;
2202  }
2203  }
2204  }
2205  }
2206  tmpReply.clear();
2207 
2208  }
2209  return ExitSuccess;
2210  }
2211 
2212 
2218  std::string sick_scan::SickScanCommon::replyToString(const std::vector<unsigned char> &reply)
2219  {
2220  std::string reply_str;
2221  std::vector<unsigned char>::const_iterator it_start, it_end;
2222  int binLen = this->checkForBinaryAnswer(&reply);
2223  if (binLen == -1) // ASCII-Cmd
2224  {
2225  it_start = reply.begin();
2226  it_end = reply.end();
2227  }
2228  else
2229  {
2230  it_start = reply.begin() + 8; // skip header and length id
2231  it_end = reply.end() - 1; // skip CRC
2232  }
2233  bool inHexPrintMode = false;
2234  for (std::vector<unsigned char>::const_iterator it = it_start; it != it_end; it++)
2235  {
2236  // inHexPrintMode means that we should continue printing hex value after we started with hex-Printing
2237  // That is easier to debug for a human instead of switching between ascii binary and then back to ascii
2238  if (*it >= 0x20 && (inHexPrintMode == false)) // filter control characters for display
2239  {
2240  reply_str.push_back(*it);
2241  }
2242  else
2243  {
2244  if (binLen != -1) // binary
2245  {
2246  char szTmp[255] = {0};
2247  unsigned char val = *it;
2248  inHexPrintMode = true;
2249  sprintf(szTmp, "\\x%02x", val);
2250  for (int ii = 0; ii < strlen(szTmp); ii++)
2251  {
2252  reply_str.push_back(szTmp[ii]);
2253  }
2254  }
2255  }
2256 
2257  }
2258  return reply_str;
2259  }
2260 
2261  bool sick_scan::SickScanCommon::dumpDatagramForDebugging(unsigned char *buffer, int bufLen)
2262  {
2263  bool ret = true;
2264  static int cnt = 0;
2265  char szDumpFileName[255] = {0};
2266  char szDir[255] = {0};
2267  if (cnt == 0)
2268  {
2269  ROS_INFO("Attention: verboseLevel is set to 1. Datagrams are stored in the /tmp folder.");
2270  }
2271 #ifdef _MSC_VER
2272  strcpy(szDir, "C:\\temp\\");
2273 #else
2274  strcpy(szDir, "/tmp/");
2275 #endif
2276  sprintf(szDumpFileName, "%ssick_datagram_%06d.bin", szDir, cnt);
2277  bool isBinary = this->parser_->getCurrentParamPtr()->getUseBinaryProtocol();
2278  if (isBinary)
2279  {
2280  FILE *ftmp;
2281  ftmp = fopen(szDumpFileName, "wb");
2282  if (ftmp != NULL)
2283  {
2284  fwrite(buffer, bufLen, 1, ftmp);
2285  fclose(ftmp);
2286  }
2287  }
2288  cnt++;
2289 
2290  return (true);
2291 
2292  }
2293 
2294 
2300  bool sick_scan::SickScanCommon::isCompatibleDevice(const std::string identStr) const
2301  {
2302  char device_string[7];
2303  int version_major = -1;
2304  int version_minor = -1;
2305 
2306  strcpy(device_string, "???");
2307  // special for TiM3-Firmware
2308  if (sscanf(identStr.c_str(), "sRA 0 6 %6s E V%d.%d", device_string,
2309  &version_major, &version_minor) == 3
2310  && strncmp("TiM3", device_string, 4) == 0
2311  && version_major >= 2 && version_minor >= 50)
2312  {
2313  ROS_ERROR("This scanner model/firmware combination does not support ranging output!");
2314  ROS_ERROR("Supported scanners: TiM5xx: all firmware versions; TiM3xx: firmware versions < V2.50.");
2315  ROS_ERROR("This is a %s, firmware version %d.%d", device_string, version_major, version_minor);
2316 
2317  return false;
2318  }
2319 
2320  bool supported = false;
2321 
2322  // DeviceIdent 8 MRS1xxxx 8 1.3.0.0R.
2323  if (sscanf(identStr.c_str(), "sRA 0 6 %6s E V%d.%d", device_string, &version_major, &version_minor) == 3)
2324  {
2325  std::string devStr = device_string;
2326 
2327 
2328  if (devStr.compare(0, 4, "TiM5") == 0)
2329  {
2330  supported = true;
2331  }
2332 
2333  if (supported == true)
2334  {
2335  ROS_INFO("Device %s V%d.%d found and supported by this driver.", identStr.c_str(), version_major,
2336  version_minor);
2337  }
2338 
2339  }
2340 
2341  if ((identStr.find("MRS1xxx") !=
2342  std::string::npos) // received pattern contains 4 'x' but we check only for 3 'x' (MRS1104 should be MRS1xxx)
2343  || (identStr.find("LMS1xxx") != std::string::npos)
2344  )
2345  {
2346  ROS_INFO("Deviceinfo %s found and supported by this driver.", identStr.c_str());
2347  supported = true;
2348  }
2349 
2350 
2351  if (identStr.find("MRS6") !=
2352  std::string::npos) // received pattern contains 4 'x' but we check only for 3 'x' (MRS1104 should be MRS1xxx)
2353  {
2354  ROS_INFO("Deviceinfo %s found and supported by this driver.", identStr.c_str());
2355  supported = true;
2356  }
2357 
2358  if (identStr.find("RMS3xx") !=
2359  std::string::npos) // received pattern contains 4 'x' but we check only for 3 'x' (MRS1104 should be MRS1xxx)
2360  {
2361  ROS_INFO("Deviceinfo %s found and supported by this driver.", identStr.c_str());
2362  supported = true;
2363  }
2364 
2365 
2366  if (supported == false)
2367  {
2368  ROS_WARN("Device %s V%d.%d found and maybe unsupported by this driver.", device_string, version_major,
2369  version_minor);
2370  ROS_WARN("Full SOPAS answer: %s", identStr.c_str());
2371  }
2372  return true;
2373  }
2374 
2375 
2381  {
2382  static int cnt = 0;
2383  diagnostics_.update();
2384 
2385  unsigned char receiveBuffer[65536];
2386  int actual_length = 0;
2387  static unsigned int iteration_count = 0;
2388  bool useBinaryProtocol = this->parser_->getCurrentParamPtr()->getUseBinaryProtocol();
2389 
2390  ros::Time recvTimeStamp = ros::Time::now(); // timestamp incoming package, will be overwritten by get_datagram
2391  // tcp packet
2392  ros::Time recvTimeStampPush = ros::Time::now(); // timestamp
2393 
2394  /*
2395  * Try to get datagram
2396  *
2397  *
2398  */
2399 
2400 
2401  int packetsInLoop = 0;
2402 
2403  const int maxNumAllowedPacketsToProcess = 25; // maximum number of packets, which will be processed in this loop.
2404 
2405  int numPacketsProcessed = 0; // count number of processed datagrams
2406 
2407  static bool firstTimeCalled = true;
2408  static bool dumpData = false;
2409  static int verboseLevel = 0;
2410  static bool slamBundle = false;
2411  float timeIncrement;
2412  static std::string echoForSlam = "";
2413  if (firstTimeCalled == true)
2414  {
2415 
2416  /* Dump Binary Protocol */
2417  ros::NodeHandle tmpParam("~");
2418  tmpParam.getParam("slam_echo", echoForSlam);
2419  tmpParam.getParam("slam_bundle", slamBundle);
2420  tmpParam.getParam("verboseLevel", verboseLevel);
2421  firstTimeCalled = false;
2422  }
2423  do
2424  {
2425 
2426  int result = get_datagram(recvTimeStamp, receiveBuffer, 65536, &actual_length, useBinaryProtocol, &packetsInLoop);
2427  numPacketsProcessed++;
2428 
2429  ros::Duration dur = recvTimeStampPush - recvTimeStamp;
2430 
2431  if (result != 0)
2432  {
2433  ROS_ERROR("Read Error when getting datagram: %i.", result);
2434  diagnostics_.broadcast(getDiagnosticErrorCode(), "Read Error when getting datagram.");
2435  return ExitError; // return failure to exit node
2436  }
2437  if (actual_length <= 0)
2438  {
2439  return ExitSuccess;
2440  } // return success to continue looping
2441 
2442  // ----- if requested, skip frames
2443  if (iteration_count++ % (config_.skip + 1) != 0)
2444  return ExitSuccess;
2445 
2446  if (publish_datagram_)
2447  {
2448  std_msgs::String datagram_msg;
2449  datagram_msg.data = std::string(reinterpret_cast<char *>(receiveBuffer));
2450  datagram_pub_.publish(datagram_msg);
2451  }
2452 
2453 
2454  if (verboseLevel > 0)
2455  {
2456  dumpDatagramForDebugging(receiveBuffer, actual_length);
2457  }
2458 
2459 
2460  bool deviceIsRadar = false;
2461 
2462  if (this->parser_->getCurrentParamPtr()->getDeviceIsRadar() == true)
2463  {
2464  deviceIsRadar = true;
2465  }
2466 
2467  if (true == deviceIsRadar)
2468  {
2469  SickScanRadar radar(this);
2470  int errorCode = ExitSuccess;
2471  // parse radar telegram and send pointcloud2-debug messages
2472  errorCode = radar.parseDatagram(recvTimeStamp, (unsigned char *) receiveBuffer, actual_length,
2473  useBinaryProtocol);
2474  return errorCode; // return success to continue looping
2475  }
2476 
2477  static SickScanImu scanImu(this); // todo remove static
2478  if (scanImu.isImuDatagram((char *) receiveBuffer, actual_length))
2479  {
2480  int errorCode = ExitSuccess;
2481  if (scanImu.isImuAckDatagram((char *) receiveBuffer, actual_length))
2482  {
2483 
2484  }
2485  else
2486  {
2487  // parse radar telegram and send pointcloud2-debug messages
2488  errorCode = scanImu.parseDatagram(recvTimeStamp, (unsigned char *) receiveBuffer, actual_length,
2489  useBinaryProtocol);
2490 
2491  }
2492  return errorCode; // return success to continue looping
2493 
2494 
2495  }
2496  else
2497  {
2498 
2499  sensor_msgs::LaserScan msg;
2500 
2501  msg.header.stamp = recvTimeStamp;
2502  double elevationAngleInRad = 0.0;
2503  /*
2504  * datagrams are enclosed in <STX> (0x02), <ETX> (0x03) pairs
2505  */
2506  char *buffer_pos = (char *) receiveBuffer;
2507  char *dstart, *dend;
2508  bool dumpDbg = true; // !!!!!
2509  bool dataToProcess = true;
2510  std::vector<float> vang_vec;
2511  vang_vec.clear();
2512  while (dataToProcess)
2513  {
2514  const int maxAllowedEchos = 5;
2515 
2516  int numValidEchos = 0;
2517  int aiValidEchoIdx[maxAllowedEchos] = {0};
2518  size_t dlength;
2519  int success = -1;
2520  int numEchos = 0;
2521  int echoMask = 0;
2522  bool publishPointCloud = true;
2523 
2524  if (useBinaryProtocol)
2525  {
2526  // if binary protocol used then parse binary message
2527  std::vector<unsigned char> receiveBufferVec = std::vector<unsigned char>(receiveBuffer,
2528  receiveBuffer + actual_length);
2529 #ifdef DEBUG_DUMP_TO_CONSOLE_ENABLED
2530  if (actual_length > 1000)
2531  {
2532  DataDumper::instance().dumpUcharBufferToConsole(receiveBuffer, actual_length);
2533 
2534  }
2535 
2536  DataDumper::instance().dumpUcharBufferToConsole(receiveBuffer, actual_length);
2537  #endif
2538  if (receiveBufferVec.size() > 8)
2539  {
2540  long idVal = 0;
2541  long lenVal = 0;
2542  memcpy(&idVal, receiveBuffer + 0, 4); // read identifier
2543  memcpy(&lenVal, receiveBuffer + 4, 4); // read length indicator
2544  swap_endian((unsigned char *) &lenVal, 4);
2545 
2546  if (idVal == 0x02020202) // id for binary message
2547  {
2548 #if 0
2549  {
2550  static int cnt = 0;
2551  char szFileName[255];
2552 
2553 #ifdef _MSC_VER
2554  sprintf(szFileName, "c:\\temp\\dump%05d.bin", cnt);
2555 #else
2556  sprintf(szFileName, "/tmp/dump%05d.txt", cnt);
2557 #endif
2558  FILE *fout;
2559  fout = fopen(szFileName, "wb");
2560  fwrite(receiveBuffer, actual_length, 1, fout);
2561  fclose(fout);
2562  cnt++;
2563  }
2564 #endif
2565  // binary message
2566  if (lenVal < actual_length)
2567  {
2568  short elevAngleX200 = 0; // signed short (F5 B2 -> Layer 24
2569  // F5B2h -> -2638/200= -13.19°
2570  int scanFrequencyX100 = 0;
2571  double elevAngle = 0.00;
2572  double scanFrequency = 0.0;
2573  long measurementFrequencyDiv100 = 0; // multiply with 100
2574  int numberOf16BitChannels = 0;
2575  int numberOf8BitChannels = 0;
2576  uint32_t SystemCountScan=0;
2577  uint32_t SystemCountTransmit=0;
2578 
2579  memcpy(&elevAngleX200, receiveBuffer + 50, 2);
2580  swap_endian((unsigned char *) &elevAngleX200, 2);
2581 
2582  elevationAngleInRad = -elevAngleX200 / 200.0 * deg2rad_const;
2583 
2584  msg.header.seq = elevAngleX200; // should be multiple of 0.625° starting with -2638 (corresponding to 13.19°)
2585 
2586  memcpy(&SystemCountScan, receiveBuffer + 0x26, 4);
2587  swap_endian((unsigned char *) &SystemCountScan, 4);
2588 
2589  memcpy(&SystemCountTransmit, receiveBuffer + 0x2A, 4);
2590  swap_endian((unsigned char *) &SystemCountTransmit, 4);
2591  bool bRet = SoftwarePLL::instance().updatePLL(recvTimeStamp.sec, recvTimeStamp.nsec,SystemCountTransmit);
2592  ros::Time tmp_time=recvTimeStamp;
2593  bRet = SoftwarePLL::instance().getCorrectedTimeStamp(recvTimeStamp.sec, recvTimeStamp.nsec,SystemCountScan);
2594  //TODO Handle return values
2595  ros::Duration debug_duration=recvTimeStamp-tmp_time;
2596 #ifdef DEBUG_DUMP_ENABLED
2597  double elevationAngleInDeg=elevationAngleInRad = -elevAngleX200 / 200.0;
2598  // DataDumper::instance().pushData((double)SystemCountScan, "LAYER", elevationAngleInDeg);
2599  //DataDumper::instance().pushData((double)SystemCountScan, "LASESCANTIME", SystemCountScan);
2600  //DataDumper::instance().pushData((double)SystemCountTransmit, "LASERTRANSMITTIME", SystemCountTransmit);
2601  //DataDumper::instance().pushData((double)SystemCountScan, "LASERTRANSMITDELAY", debug_duration.toSec());
2602 #endif
2603 
2604  memcpy(&scanFrequencyX100, receiveBuffer + 52, 4);
2605  swap_endian((unsigned char *) &scanFrequencyX100, 4);
2606 
2607  memcpy(&measurementFrequencyDiv100, receiveBuffer + 56, 4);
2608  swap_endian((unsigned char *) &measurementFrequencyDiv100, 4);
2609 
2610 
2611  msg.scan_time = 1.0 / (scanFrequencyX100 / 100.0);
2612 
2613  //due firmware inconsistency
2614  if(measurementFrequencyDiv100>10000)
2615  {
2616  measurementFrequencyDiv100/=100;
2617  }
2618  msg.time_increment = 1.0 / (measurementFrequencyDiv100 * 100.0);
2619  timeIncrement=msg.time_increment;
2620  msg.range_min = parser_->get_range_min();
2621  msg.range_max = parser_->get_range_max();
2622 
2623  memcpy(&numberOf16BitChannels, receiveBuffer + 62, 2);
2624  swap_endian((unsigned char *) &numberOf16BitChannels, 2);
2625 
2626  int parseOff = 64;
2627 
2628 
2629  char szChannel[255] = {0};
2630  float scaleFactor = 1.0;
2631  float scaleFactorOffset = 0.0;
2632  int32_t startAngleDiv10000 = 1;
2633  int32_t sizeOfSingleAngularStepDiv10000 = 1;
2634  double startAngle = 0.0;
2635  double sizeOfSingleAngularStep = 0.0;
2636  short numberOfItems = 0;
2637 
2638  static int cnt = 0;
2639  cnt++;
2640  // get number of 8 bit channels
2641  // we must jump of the 16 bit data blocks including header ...
2642  for (int i = 0; i < numberOf16BitChannels; i++)
2643  {
2644  int numberOfItems = 0x00;
2645  memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
2646  swap_endian((unsigned char *) &numberOfItems, 2);
2647  parseOff += 21; // 21 Byte header followed by data entries
2648  parseOff += numberOfItems * 2;
2649  }
2650 
2651  // now we can read the number of 8-Bit-Channels
2652  memcpy(&numberOf8BitChannels, receiveBuffer + parseOff, 2);
2653  swap_endian((unsigned char *) &numberOf8BitChannels, 2);
2654 
2655  parseOff = 64;
2656  enum datagram_parse_task
2657  {
2658  process_dist,
2659  process_vang,
2660  process_rssi,
2661  process_idle
2662  };
2663  for (int processLoop = 0; processLoop < 2; processLoop++)
2664  {
2665  int totalChannelCnt = 0;
2666  int distChannelCnt;
2667  int rssiCnt;
2668  bool bCont = true;
2669  int vangleCnt;
2670  datagram_parse_task task = process_idle;
2671  bool parsePacket = true;
2672  parseOff = 64;
2673  bool processData = false;
2674 
2675  if (processLoop == 0)
2676  {
2677  distChannelCnt = 0;
2678  rssiCnt = 0;
2679  vangleCnt = 0;
2680  }
2681 
2682  if (processLoop == 1)
2683  {
2684  processData = true;
2685  numEchos = distChannelCnt;
2686  msg.ranges.resize(numberOfItems * numEchos);
2687  if (rssiCnt > 0)
2688  {
2689  msg.intensities.resize(numberOfItems * rssiCnt);
2690  }
2691  else
2692  {
2693  }
2694  if (vangleCnt > 0) // should be 0 or 1
2695  {
2696  vang_vec.resize(numberOfItems * vangleCnt);
2697  }
2698  else
2699  {
2700  vang_vec.clear();
2701  }
2702  echoMask = (1 << numEchos) - 1;
2703 
2704  // reset count. We will use the counter for index calculation now.
2705  distChannelCnt = 0;
2706  rssiCnt = 0;
2707  vangleCnt = 0;
2708 
2709  }
2710 
2711  szChannel[6] = '\0';
2712  scaleFactor = 1.0;
2713  scaleFactorOffset = 0.0;
2714  startAngleDiv10000 = 1;
2715  sizeOfSingleAngularStepDiv10000 = 1;
2716  startAngle = 0.0;
2717  sizeOfSingleAngularStep = 0.0;
2718  numberOfItems = 0;
2719 
2720 
2721 #if 1 // prepared for multiecho parsing
2722 
2723  bCont = true;
2724  bool doVangVecProc = false;
2725  // try to get number of DIST and RSSI from binary data
2726  task = process_idle;
2727  do
2728  {
2729  task = process_idle;
2730  doVangVecProc = false;
2731  int processDataLenValuesInBytes = 2;
2732 
2733  if (totalChannelCnt == numberOf16BitChannels)
2734  {
2735  parseOff += 2; // jump of number of 8 bit channels- already parsed above
2736  }
2737 
2738  if (totalChannelCnt >= numberOf16BitChannels)
2739  {
2740  processDataLenValuesInBytes = 1; // then process 8 bit values ...
2741  }
2742  bCont = false;
2743  strcpy(szChannel, "");
2744 
2745  if (totalChannelCnt < (numberOf16BitChannels + numberOf8BitChannels))
2746  {
2747  szChannel[5] = '\0';
2748  strncpy(szChannel, (const char *) receiveBuffer + parseOff, 5);
2749  }
2750  else
2751  {
2752  // all channels processed (16 bit and 8 bit channels)
2753  }
2754 
2755  if (strstr(szChannel, "DIST") == szChannel)
2756  {
2757  task = process_dist;
2758  distChannelCnt++;
2759  bCont = true;
2760  numberOfItems = 0;
2761  memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
2762  swap_endian((unsigned char *) &numberOfItems, 2);
2763 
2764  }
2765  if (strstr(szChannel, "VANG") == szChannel)
2766  {
2767  vangleCnt++;
2768  task = process_vang;
2769  bCont = true;
2770  numberOfItems = 0;
2771  memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
2772  swap_endian((unsigned char *) &numberOfItems, 2);
2773 
2774  vang_vec.resize(numberOfItems);
2775 
2776  }
2777  if (strstr(szChannel, "RSSI") == szChannel)
2778  {
2779  task = process_rssi;
2780  rssiCnt++;
2781  bCont = true;
2782  numberOfItems = 0;
2783  // copy two byte value (unsigned short to numberOfItems
2784  memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
2785  swap_endian((unsigned char *) &numberOfItems, 2); // swap
2786 
2787  }
2788  if (bCont)
2789  {
2790  scaleFactor = 0.0;
2791  scaleFactorOffset = 0.0;
2792  startAngleDiv10000 = 0;
2793  sizeOfSingleAngularStepDiv10000 = 0;
2794  numberOfItems = 0;
2795 
2796  memcpy(&scaleFactor, receiveBuffer + parseOff + 5, 4);
2797  memcpy(&scaleFactorOffset, receiveBuffer + parseOff + 9, 4);
2798  memcpy(&startAngleDiv10000, receiveBuffer + parseOff + 13, 4);
2799  memcpy(&sizeOfSingleAngularStepDiv10000, receiveBuffer + parseOff + 17, 2);
2800  memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
2801 
2802 
2803  swap_endian((unsigned char *) &scaleFactor, 4);
2804  swap_endian((unsigned char *) &scaleFactorOffset, 4);
2805  swap_endian((unsigned char *) &startAngleDiv10000, 4);
2806  swap_endian((unsigned char *) &sizeOfSingleAngularStepDiv10000, 2);
2807  swap_endian((unsigned char *) &numberOfItems, 2);
2808 
2809  if (processData)
2810  {
2811  unsigned short *data = (unsigned short *) (receiveBuffer + parseOff + 21);
2812 
2813  unsigned char *swapPtr = (unsigned char *) data;
2814  // copy RSSI-Values +2 for 16-bit values +1 for 8-bit value
2815  for (int i = 0;
2816  i < numberOfItems * processDataLenValuesInBytes; i += processDataLenValuesInBytes)
2817  {
2818  if (processDataLenValuesInBytes == 1)
2819  {
2820  }
2821  else
2822  {
2823  unsigned char tmp;
2824  tmp = swapPtr[i + 1];
2825  swapPtr[i + 1] = swapPtr[i];
2826  swapPtr[i] = tmp;
2827  }
2828  }
2829  int idx = 0;
2830 
2831  switch (task)
2832  {
2833 
2834  case process_dist:
2835  {
2836  startAngle = startAngleDiv10000 / 10000.00;
2837  sizeOfSingleAngularStep = sizeOfSingleAngularStepDiv10000 / 10000.0;
2838  sizeOfSingleAngularStep *= (M_PI / 180.0);
2839 
2840  msg.angle_min = startAngle / 180.0 * M_PI - M_PI / 2;
2841  msg.angle_increment = sizeOfSingleAngularStep;
2842  msg.angle_max = msg.angle_min + (numberOfItems - 1) * msg.angle_increment;
2843 
2844  float *rangePtr = NULL;
2845 
2846  if (numberOfItems > 0)
2847  {
2848  rangePtr = &msg.ranges[0];
2849  }
2850  float scaleFactor_001= 0.001F * scaleFactor;// to avoid repeated multiplication
2851  for (int i = 0; i < numberOfItems; i++)
2852  {
2853  idx = i + numberOfItems * (distChannelCnt - 1);
2854  rangePtr[idx] = (float) data[i] * scaleFactor_001 + scaleFactorOffset;
2855 #ifdef DEBUG_DUMP_ENABLED
2856  if (distChannelCnt == 1)
2857  {
2858  if (i == floor(numberOfItems / 2))
2859  {
2860  double curTimeStamp = SystemCountScan + i * msg.time_increment * 1E6;
2861  //DataDumper::instance().pushData(curTimeStamp, "DIST", rangePtr[idx]);
2862  }
2863  }
2864 #endif
2865  //XXX
2866  }
2867 
2868  }
2869  break;
2870  case process_rssi:
2871  {
2872  // Das muss vom Protokoll abgeleitet werden. !!!
2873 
2874  float *intensityPtr = NULL;
2875 
2876  if (numberOfItems > 0)
2877  {
2878  intensityPtr = &msg.intensities[0];
2879 
2880  }
2881  for (int i = 0; i < numberOfItems; i++)
2882  {
2883  idx = i + numberOfItems * (rssiCnt - 1);
2884  // we must select between 16 bit and 8 bit values
2885  float rssiVal = 0.0;
2886  if (processDataLenValuesInBytes == 2)
2887  {
2888  rssiVal = (float) data[i];
2889  }
2890  else
2891  {
2892  unsigned char *data8Ptr = (unsigned char *) data;
2893  rssiVal = (float) data8Ptr[i];
2894  }
2895  intensityPtr[idx] = rssiVal * scaleFactor + scaleFactorOffset;
2896  }
2897  }
2898  break;
2899 
2900  case process_vang:
2901  float *vangPtr = NULL;
2902  if (numberOfItems > 0)
2903  {
2904  vangPtr = &vang_vec[0]; // much faster, with vang_vec[i] each time the size will be checked
2905  }
2906  for (int i = 0; i < numberOfItems; i++)
2907  {
2908  vangPtr[i] = (float) data[i] * scaleFactor + scaleFactorOffset;
2909  }
2910  break;
2911  }
2912  }
2913  parseOff += 21 + processDataLenValuesInBytes * numberOfItems;
2914 
2915 
2916  }
2917  totalChannelCnt++;
2918  } while (bCont);
2919  }
2920 #endif
2921 
2922  elevAngle = elevAngleX200 / 200.0;
2923  scanFrequency = scanFrequencyX100 / 100.0;
2924 
2925 
2926  }
2927  }
2928  }
2929 
2930 
2931  parser_->checkScanTiming(msg.time_increment, msg.scan_time, msg.angle_increment, 0.00001f);
2932 
2933  success = ExitSuccess;
2934  // change Parsing Mode
2935  dataToProcess = false; // only one package allowed - no chaining
2936  }
2937  else // Parsing of Ascii-Encoding of datagram, xxx
2938  {
2939  dstart = strchr(buffer_pos, 0x02);
2940  if (dstart != NULL)
2941  {
2942  dend = strchr(dstart + 1, 0x03);
2943  }
2944  if ((dstart != NULL) && (dend != NULL))
2945  {
2946  dataToProcess = true; // continue parasing
2947  dlength = dend - dstart;
2948  *dend = '\0';
2949  dstart++;
2950  }
2951  else
2952  {
2953  dataToProcess = false;
2954  break; //
2955  }
2956 
2957  if (dumpDbg)
2958  {
2959  {
2960  static int cnt = 0;
2961  char szFileName[255];
2962 
2963 #ifdef _MSC_VER
2964  sprintf(szFileName, "c:\\temp\\dump%05d.txt", cnt);
2965 #else
2966  sprintf(szFileName, "/tmp/dump%05d.txt", cnt);
2967 #endif
2968  FILE *fout;
2969  fout = fopen(szFileName, "wb");
2970  fwrite(dstart, dlength, 1, fout);
2971  fclose(fout);
2972  cnt++;
2973  }
2974  }
2975 
2976  // HEADER of data followed by DIST1 ... DIST2 ... DIST3 .... RSSI1 ... RSSI2.... RSSI3...
2977 
2978  // <frameid>_<sign>00500_DIST[1|2|3]
2979  numEchos = 1;
2980  // numEchos contains number of echos (1..5)
2981  // _msg holds ALL data of all echos
2982  success = parser_->parse_datagram(dstart, dlength, config_, msg, numEchos, echoMask);
2983  publishPointCloud = true; // for MRS1000
2984 
2985  numValidEchos = 0;
2986  for (int i = 0; i < maxAllowedEchos; i++)
2987  {
2988  aiValidEchoIdx[i] = 0;
2989  }
2990  }
2991 
2992 
2993  int numOfLayers = parser_->getCurrentParamPtr()->getNumberOfLayers();
2994 
2995  if (success == ExitSuccess)
2996  {
2997  bool elevationPreCalculated = false;
2998  double elevationAngleDegree = 0.0;
2999 
3000 
3001  std::vector<float> rangeTmp = msg.ranges; // copy all range value
3002  std::vector<float> intensityTmp = msg.intensities; // copy all intensity value
3003 
3004  int intensityTmpNum = intensityTmp.size();
3005  float *intensityTmpPtr = NULL;
3006  if (intensityTmpNum > 0)
3007  {
3008  intensityTmpPtr = &intensityTmp[0];
3009  }
3010 
3011  // Helpful: https://answers.ros.org/question/191265/pointcloud2-access-data/
3012  // https://gist.github.com/yuma-m/b5dcce1b515335c93ce8
3013  // Copy to pointcloud
3014  int layer = 0;
3015  int baseLayer = 0;
3016  bool useGivenElevationAngle = false;
3017  switch (numOfLayers)
3018  {
3019  case 1: // TIM571 etc.
3020  baseLayer = 0;
3021  break;
3022  case 4:
3023 
3024  baseLayer = -1;
3025  if (msg.header.seq == 250) layer = -1;
3026  else if (msg.header.seq == 0) layer = 0;
3027  else if (msg.header.seq == -250) layer = 1;
3028  else if (msg.header.seq == -500) layer = 2;
3029  elevationAngleDegree = this->parser_->getCurrentParamPtr()->getElevationDegreeResolution();
3030  elevationAngleDegree = elevationAngleDegree / 180.0 * M_PI;
3031  // 0.0436332 /*2.5 degrees*/;
3032  break;
3033  case 24: // Preparation for MRS6000
3034  baseLayer = -1;
3035  layer = (msg.header.seq - (-2638)) / 125;
3036  layer = (23 - layer) - 1;
3037 #if 0
3038  elevationAngleDegree = this->parser_->getCurrentParamPtr()->getElevationDegreeResolution();
3039  elevationAngleDegree = elevationAngleDegree / 180.0 * M_PI;
3040 #endif
3041 
3042  elevationPreCalculated = true;
3043  if (vang_vec.size() > 0)
3044  {
3045  useGivenElevationAngle = true;
3046  }
3047  break;
3048  default:
3049  assert(0);
3050  break; // unsupported
3051 
3052  }
3053 
3054 
3055 
3056 
3057 
3058  // XXX - HIER MEHRERE SCANS publish, falls Mehrzielszenario läuft
3059  if (numEchos > 5)
3060  {
3061  ROS_WARN("Too much echos");
3062  }
3063  else
3064  {
3065 
3066  int startOffset = 0;
3067  int endOffset = 0;
3068  int echoPartNum = msg.ranges.size() / numEchos;
3069  for (int i = 0; i < numEchos; i++)
3070  {
3071 
3072  bool sendMsg = false;
3073  if ((echoMask & (1 << i)) & outputChannelFlagId)
3074  {
3075  aiValidEchoIdx[numValidEchos] = i; // save index
3076  numValidEchos++;
3077  sendMsg = true;
3078  }
3079  startOffset = i * echoPartNum;
3080  endOffset = (i + 1) * echoPartNum;
3081 
3082  msg.ranges.clear();
3083  msg.intensities.clear();
3084  msg.ranges = std::vector<float>(
3085  rangeTmp.begin() + startOffset,
3086  rangeTmp.begin() + endOffset);
3087  // check also for MRS1104
3088  if (endOffset <= intensityTmp.size() && (intensityTmp.size() > 0))
3089  {
3090  msg.intensities = std::vector<float>(
3091  intensityTmp.begin() + startOffset,
3092  intensityTmp.begin() + endOffset);
3093  }
3094  else
3095  {
3096  msg.intensities.resize(echoPartNum); // fill with zeros
3097  }
3098  {
3099  // numEchos
3100  char szTmp[255] = {0};
3101  if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() > 1)
3102  {
3103  const char *cpFrameId = config_.frame_id.c_str();
3104 #if 0
3105  sprintf(szTmp, "%s_%+04d_DIST%d", cpFrameId, msg.header.seq, i + 1);
3106 #else // experimental
3107  char szSignName[10] = {0};
3108  if ((int) msg.header.seq < 0)
3109  {
3110  strcpy(szSignName, "NEG");
3111  }
3112  else
3113  {
3114  strcpy(szSignName, "POS");
3115 
3116  }
3117 
3118  sprintf(szTmp, "%s_%s_%03d_DIST%d", cpFrameId, szSignName, abs((int) msg.header.seq), i + 1);
3119 #endif
3120  }
3121  else
3122  {
3123  strcpy(szTmp, config_.frame_id.c_str());
3124  }
3125 
3126  msg.header.frame_id = std::string(szTmp);
3127  // Hector slam can only process ONE valid frame id.
3128  if (echoForSlam.length() > 0)
3129  {
3130  if (slamBundle)
3131  {
3132  // try to map first echos to horizontal layers.
3133  if (i == 0)
3134  {
3135  // first echo
3136  msg.header.frame_id = echoForSlam;
3137  strcpy(szTmp, echoForSlam.c_str()); //
3138  if (elevationAngleInRad != 0.0)
3139  {
3140  float cosVal = cos(elevationAngleInRad);
3141  int rangeNum = msg.ranges.size();
3142  for (int j = 0; j < rangeNum; j++)
3143  {
3144  msg.ranges[j] *= cosVal;
3145  }
3146  }
3147  }
3148  }
3149 
3150  if (echoForSlam.compare(szTmp) == 0)
3151  {
3152  sendMsg = true;
3153  }
3154  else
3155  {
3156  sendMsg = false;
3157  }
3158  }
3159 
3160  }
3161 #ifndef _MSC_VER
3162  if (numOfLayers > 4)
3163  {
3164  sendMsg = false; // too many layers for publish as scan message. Only pointcloud messages will be pub.
3165  }
3166  if (sendMsg &
3167  outputChannelFlagId) // publish only configured channels - workaround for cfg-bug MRS1104
3168  {
3169 
3170  pub_.publish(msg);
3171  }
3172 #else
3173  printf("MSG received...");
3174 #endif
3175  }
3176  }
3177 
3178 
3179 
3180  if (publishPointCloud == true)
3181  {
3182 
3183 
3184 
3185  const int numChannels = 4; // x y z i (for intensity)
3186 
3187  int numTmpLayer = numOfLayers;
3188 
3189 
3190  cloud_.header.stamp = recvTimeStamp;
3191  cloud_.header.frame_id = config_.frame_id;
3192  cloud_.header.seq = 0;
3193  cloud_.height = numTmpLayer * numValidEchos; // due to multi echo multiplied by num. of layers
3194  cloud_.width = msg.ranges.size();
3195  cloud_.is_bigendian = false;
3196  cloud_.is_dense = true;
3197  cloud_.point_step = numChannels * sizeof(float);
3198  cloud_.row_step = cloud_.point_step * cloud_.width;
3199  cloud_.fields.resize(numChannels);
3200  for (int i = 0; i < numChannels; i++)
3201  {
3202  std::string channelId[] = {"x", "y", "z", "intensity"};
3203  cloud_.fields[i].name = channelId[i];
3204  cloud_.fields[i].offset = i * sizeof(float);
3205  cloud_.fields[i].count = 1;
3206  cloud_.fields[i].datatype = sensor_msgs::PointField::FLOAT32;
3207  }
3208 
3209  cloud_.data.resize(cloud_.row_step * cloud_.height);
3210 
3211  unsigned char *cloudDataPtr = &(cloud_.data[0]);
3212 
3213 
3214  // prepare lookup for elevation angle table
3215 
3216  std::vector<float> cosAlphaTable;
3217  std::vector<float> sinAlphaTable;
3218  int rangeNum = rangeTmp.size() / numValidEchos;
3219  cosAlphaTable.resize(rangeNum);
3220  sinAlphaTable.resize(rangeNum);
3221 
3222  for (size_t iEcho = 0; iEcho < numValidEchos; iEcho++)
3223  {
3224 
3225  float angle = config_.min_ang;
3226 
3227 
3228  float *cosAlphaTablePtr = &cosAlphaTable[0];
3229  float *sinAlphaTablePtr = &sinAlphaTable[0];
3230 
3231  float *vangPtr = &vang_vec[0];
3232  float *rangeTmpPtr = &rangeTmp[0];
3233  for (size_t i = 0; i < rangeNum; i++)
3234  {
3235  enum enum_index_descr
3236  {
3237  idx_x,
3238  idx_y,
3239  idx_z,
3240  idx_intensity,
3241  idx_num
3242  };
3243  long adroff = i * (numChannels * (int) sizeof(float));
3244 
3245  adroff += (layer - baseLayer) * cloud_.row_step;
3246 
3247  adroff += iEcho * cloud_.row_step * numTmpLayer;
3248 
3249  unsigned char *ptr = cloudDataPtr + adroff;
3250  float *fptr = (float *)(cloudDataPtr + adroff);
3251 
3252  geometry_msgs::Point32 point;
3253  float range_meter = rangeTmpPtr[iEcho * rangeNum + i];
3254  float phi = angle; // azimuth angle
3255  float alpha = 0.0; // elevation angle
3256 
3257  if (useGivenElevationAngle) // FOR MRS6124
3258  {
3259  alpha = -vangPtr[i] * deg2rad_const;
3260  }
3261  else
3262  {
3263  if (elevationPreCalculated) // FOR MRS6124 without VANGL
3264  {
3265  alpha = elevationAngleInRad;
3266  }
3267  else
3268  {
3269  alpha = layer * elevationAngleDegree; // for MRS1104
3270  }
3271  }
3272 
3273  if (iEcho == 0)
3274  {
3275  cosAlphaTablePtr[i] = cos(alpha);
3276  sinAlphaTablePtr[i] = sin(alpha);
3277  }
3278  else
3279  {
3280  // Just for Debugging: printf("%3d %8.3lf %8.3lf\n", (int)i, cosAlphaTablePtr[i], sinAlphaTablePtr[i]);
3281  }
3282  // Thanks to Sebastian Pütz <spuetz@uos.de> for his hint
3283  float rangeCos=range_meter * cosAlphaTablePtr[i];
3284  fptr[idx_x] = rangeCos * cos(phi); // copy x value in pointcloud
3285  fptr[idx_y] = rangeCos * sin(phi); // copy y value in pointcloud
3286  fptr[idx_z] = range_meter * sinAlphaTablePtr[i];// copy z value in pointcloud
3287 
3288  fptr[idx_intensity] = 0.0;
3289  if (config_.intensity)
3290  {
3291  int intensityIndex = aiValidEchoIdx[iEcho] * rangeNum + i;
3292  // intensity values available??
3293  if (intensityIndex < intensityTmpNum)
3294  {
3295  fptr[idx_intensity] = intensityTmpPtr[intensityIndex]; // copy intensity value in pointcloud
3296  }
3297  }
3298  angle += msg.angle_increment;
3299  }
3300  // Publish
3301  static int cnt = 0;
3302  int layerOff = (layer - baseLayer);
3303 
3304  }
3305  // if ( (msg.header.seq == 0) || (layerOff == 0)) // FIXEN!!!!
3306  bool shallIFire = false;
3307  if ((msg.header.seq == 0) || (msg.header.seq == 237))
3308  {
3309  shallIFire = true;
3310  }
3311 
3312 
3313  static int layerCnt = 0;
3314  static int layerSeq[4];
3315 
3316  if (config_.cloud_output_mode>0)
3317  {
3318 
3319  layerSeq[layerCnt % 4] = layer;
3320  if (layerCnt >= 4) // mind. erst einmal vier Layer zusammensuchen
3321  {
3322  shallIFire = true; // here are at least 4 layers available
3323  }
3324  else
3325  {
3326  shallIFire = false;
3327  }
3328 
3329  layerCnt++;
3330  }
3331 
3332  if (shallIFire) // shall i fire the signal???
3333  {
3334  if (config_.cloud_output_mode==0)
3335  {
3336  // standard handling of scans
3338 
3339  }
3340  else if(config_.cloud_output_mode==2)
3341  {
3342  // Following cases are interesting:
3343  // LMS5xx: seq is always 0 -> publish every scan
3344  // MRS1104: Every 4th-Layer is 0 -> publish pointcloud every 4th layer message
3345  // LMS1104: Publish every layer. The timing for the LMS1104 seems to be:
3346  // Every 67 ms receiving of a new scan message
3347  // Scan message contains 367 measurements
3348  // angle increment is 0.75° (yields 274,5° covery -> OK)
3349  // MRS6124: Publish very 24th layer at the layer = 237 , MRS6124 contains no sequence with seq 0
3350  //BBB
3351 #ifndef _MSC_VER
3352  int numTotalShots = 360; //TODO where is this from ?
3353  int numPartialShots = 40; //
3354 
3355  for (int i = 0; i < numTotalShots; i += numPartialShots)
3356  {
3357  sensor_msgs::PointCloud2 partialCloud;
3358  partialCloud = cloud_;
3359  ros::Time partialTimeStamp = cloud_.header.stamp;
3360 
3361  partialTimeStamp += ros::Duration((i + 0.5 * (numPartialShots - 1)) * timeIncrement);
3362  partialTimeStamp += ros::Duration((3 * numTotalShots) * timeIncrement);
3363  partialCloud.header.stamp = partialTimeStamp;
3364  partialCloud.width = numPartialShots * 3; // die sind sicher in diesem Bereich
3365 
3366  int diffTo1100 = cloud_.width - 3 * (numTotalShots + i);
3367  if (diffTo1100 > numPartialShots)
3368  {
3369  diffTo1100 = numPartialShots;
3370  }
3371  if (diffTo1100 < 0)
3372  {
3373  diffTo1100 = 0;
3374  }
3375  partialCloud.width += diffTo1100;
3376  // printf("Offset: %4d Breite: %4d\n", i, partialCloud.width);
3377  partialCloud.height = 1;
3378 
3379 
3380  partialCloud.is_bigendian = false;
3381  partialCloud.is_dense = true;
3382  partialCloud.point_step = numChannels * sizeof(float);
3383  partialCloud.row_step = partialCloud.point_step * partialCloud.width;
3384  partialCloud.fields.resize(numChannels);
3385  for (int ii = 0; ii < numChannels; ii++)
3386  {
3387  std::string channelId[] = {"x", "y", "z", "intensity"};
3388  partialCloud.fields[ii].name = channelId[ii];
3389  partialCloud.fields[ii].offset = ii * sizeof(float);
3390  partialCloud.fields[ii].count = 1;
3391  partialCloud.fields[ii].datatype = sensor_msgs::PointField::FLOAT32;
3392  }
3393 
3394  partialCloud.data.resize(partialCloud.row_step);
3395 
3396  int partOff = 0;
3397  for (int j = 0; j < 4; j++)
3398  {
3399  int layerIdx = (j + (layerCnt)) % 4; // j = 0 -> oldest
3400  int rowIdx = 1 + layerSeq[layerIdx % 4]; // +1, da es bei -1 beginnt
3401  int colIdx = j * numTotalShots + i;
3402  int maxAvail = cloud_.width - colIdx; //
3403  if (maxAvail < 0)
3404  {
3405  maxAvail = 0;
3406  }
3407 
3408  if (maxAvail > numPartialShots)
3409  {
3410  maxAvail = numPartialShots;
3411  }
3412 
3413  // printf("Most recent LayerIdx: %2d RowIdx: %4d ColIdx: %4d\n", layer, rowIdx, colIdx);
3414  if (maxAvail > 0)
3415  {
3416  memcpy(&(partialCloud.data[partOff]),
3417  &(cloud_.data[(rowIdx * cloud_.width + colIdx + i) * cloud_.point_step]),
3418  cloud_.point_step * maxAvail);
3419 
3420  }
3421 
3422  partOff += maxAvail * partialCloud.point_step;
3423  }
3424  assert(partialCloud.data.size()==partialCloud.width*partialCloud.point_step);
3425 
3426 
3427  cloud_pub_.publish(partialCloud);
3428 #if 0
3429  memcpy(&(partialCloud.data[0]), &(cloud_.data[0]) + i * cloud_.point_step, cloud_.point_step * numPartialShots);
3430  cloud_pub_.publish(partialCloud);
3431 #endif
3432  }
3433  }
3434  // cloud_pub_.publish(cloud_);
3435 
3436 #else
3437  printf("PUBLISH:\n");
3438 #endif
3439  }
3440  }
3441  }
3442  // Start Point
3443  buffer_pos = dend + 1;
3444  } // end of while loop
3445  }
3446 
3447  // shall we process more data? I.e. are there more packets to process in the input queue???
3448 
3449  } while ( (packetsInLoop > 0) && (numPacketsProcessed < maxNumAllowedPacketsToProcess) );
3450  return ExitSuccess; // return success to continue looping
3451  }
3452 
3453 
3457  void SickScanCommon::check_angle_range(SickScanConfig &conf)
3458  {
3459  if (conf.min_ang > conf.max_ang)
3460  {
3461  ROS_WARN("Maximum angle must be greater than minimum angle. Adjusting >min_ang<.");
3462  conf.min_ang = conf.max_ang;
3463  }
3464  }
3465 
3471  void SickScanCommon::update_config(sick_scan::SickScanConfig &new_config, uint32_t level)
3472  {
3473  check_angle_range(new_config);
3474  config_ = new_config;
3475  }
3476 
3483  int SickScanCommon::convertAscii2BinaryCmd(const char *requestAscii, std::vector<unsigned char> *requestBinary)
3484  {
3485  requestBinary->clear();
3486  if (requestAscii == NULL)
3487  {
3488  return (-1);
3489  }
3490  int cmdLen = strlen(requestAscii);
3491  if (cmdLen == 0)
3492  {
3493  return (-1);
3494  }
3495  if (requestAscii[0] != 0x02)
3496  {
3497  return (-1);
3498  }
3499  if (requestAscii[cmdLen - 1] != 0x03)
3500  {
3501  return (-1);
3502  }
3503  // Here we know, that the ascii format is correctly framed with <stx> .. <etx>
3504  for (int i = 0; i < 4; i++)
3505  {
3506  requestBinary->push_back(0x02);
3507  }
3508 
3509  for (int i = 0; i < 4; i++) // Puffer for Length identifier
3510  {
3511  requestBinary->push_back(0x00);
3512  }
3513 
3514  unsigned long msgLen = cmdLen - 2; // without stx and etx
3515 
3516  // special handling for the following commands
3517  // due to higher number of command arguments
3518  std::string keyWord0 = "sMN SetAccessMode";
3519  std::string keyWord1 = "sWN FREchoFilter";
3520  std::string keyWord2 = "sEN LMDscandata";
3521  std::string keyWord3 = "sWN LMDscandatacfg";
3522  std::string keyWord4 = "sWN SetActiveApplications";
3523  std::string keyWord5 = "sEN IMUData";
3524  std::string keyWord6 = "sWN EIIpAddr";
3525  std::string keyWord7 = "sMN mLMPsetscancfg";
3526  std::string keyWord8 = "sWN TSCTCupdatetime";
3527  std::string keyWord9 = "sWN TSCTCSrvAddr";
3528  //BBB
3529 
3530  std::string cmdAscii = requestAscii;
3531 
3532 
3533  int copyUntilSpaceCnt = 2;
3534  int spaceCnt = 0;
3535  char hexStr[255] = {0};
3536  int level = 0;
3537  unsigned char buffer[255];
3538  int bufferLen = 0;
3539  if (cmdAscii.find(keyWord0) != std::string::npos) // SetAccessMode
3540  {
3541  copyUntilSpaceCnt = 2;
3542  int keyWord0Len = keyWord0.length();
3543  sscanf(requestAscii + keyWord0Len + 1, " %d %s", &level, hexStr);
3544  buffer[0] = (unsigned char) (0xFF & level);
3545  bufferLen = 1;
3546  char hexTmp[3] = {0};
3547  for (int i = 0; i < 4; i++)
3548  {
3549  int val;
3550  hexTmp[0] = hexStr[i * 2];
3551  hexTmp[1] = hexStr[i * 2 + 1];
3552  hexTmp[2] = 0x00;
3553  sscanf(hexTmp, "%x", &val);
3554  buffer[i + 1] = (unsigned char) (0xFF & val);
3555  bufferLen++;
3556  }
3557  }
3558  if (cmdAscii.find(keyWord1) != std::string::npos)
3559  {
3560  int echoCodeNumber = 0;
3561  int keyWord1Len = keyWord1.length();
3562  sscanf(requestAscii + keyWord1Len + 1, " %d", &echoCodeNumber);
3563  buffer[0] = (unsigned char) (0xFF & echoCodeNumber);
3564  bufferLen = 1;
3565  }
3566  if (cmdAscii.find(keyWord2) != std::string::npos)
3567  {
3568  int scanDataStatus = 0;
3569  int keyWord2Len = keyWord2.length();
3570  sscanf(requestAscii + keyWord2Len + 1, " %d", &scanDataStatus);
3571  buffer[0] = (unsigned char) (0xFF & scanDataStatus);
3572  bufferLen = 1;
3573  }
3574 
3575  if (cmdAscii.find(keyWord3) != std::string::npos)
3576  {
3577  int scanDataStatus = 0;
3578  int keyWord3Len = keyWord3.length();
3579  int dummyArr[12] = {0};
3580  if (12 == sscanf(requestAscii + keyWord3Len + 1, " %d %d %d %d %d %d %d %d %d %d %d %d",
3581  &dummyArr[0], &dummyArr[1], &dummyArr[2],
3582  &dummyArr[3], &dummyArr[4], &dummyArr[5],
3583  &dummyArr[6], &dummyArr[7], &dummyArr[8],
3584  &dummyArr[9], &dummyArr[10], &dummyArr[11]))
3585  {
3586  for (int i = 0; i < 13; i++)
3587  {
3588  buffer[i] = 0x00;
3589  }
3590  buffer[0] = (unsigned char) (0xFF & (dummyArr[0]));
3591  buffer[1] = 0x00;
3592  buffer[2] = (unsigned char) (0xFF & dummyArr[2]); // Remission
3593  buffer[3] = (unsigned char) (0xFF & dummyArr[3]); // Remission data format 0=8 bit 1= 16 bit
3594  buffer[10]= (unsigned char) (0xFF & dummyArr[10]); // Enable timestamp
3595  buffer[12] = (unsigned char) (0xFF & (dummyArr[11])); // nth-Scan
3596 
3597  bufferLen = 13;
3598  }
3599 
3600  }
3601 
3602  if (cmdAscii.find(keyWord4) != std::string::npos)
3603  {
3604  char tmpStr[1024] = {0};
3605  char szApplStr[255] = {0};
3606  int keyWord4Len = keyWord4.length();
3607  int scanDataStatus = 0;
3608  int dummy0, dummy1;
3609  strcpy(tmpStr, requestAscii + keyWord4Len + 2);
3610  sscanf(tmpStr, "%d %s %d", &dummy0, szApplStr, &dummy1);
3611  // rebuild string
3612  buffer[0] = 0x00;
3613  buffer[1] = dummy0 ? 0x01 : 0x00;
3614  for (int ii = 0; ii < 4; ii++)
3615  {
3616  buffer[2 + ii] = szApplStr[ii]; // idx: 1,2,3,4
3617  }
3618  buffer[6] = dummy1 ? 0x01 : 0x00;
3619  bufferLen = 7;
3620  }
3621 
3622  if (cmdAscii.find(keyWord5) != std::string::npos)
3623  {
3624  int imuSetStatus = 0;
3625  int keyWord5Len = keyWord5.length();
3626  sscanf(requestAscii + keyWord5Len + 1, " %d", &imuSetStatus);
3627  buffer[0] = (unsigned char) (0xFF & imuSetStatus);
3628  bufferLen = 1;
3629  }
3630 
3631  if (cmdAscii.find(keyWord6) != std::string::npos)
3632  {
3633  int adrPartArr[4];
3634  int imuSetStatus = 0;
3635  int keyWord6Len = keyWord6.length();
3636  sscanf(requestAscii + keyWord6Len + 1, " %x %x %x %x", &(adrPartArr[0]), &(adrPartArr[1]), &(adrPartArr[2]),
3637  &(adrPartArr[3]));
3638  buffer[0] = (unsigned char) (0xFF & adrPartArr[0]);
3639  buffer[1] = (unsigned char) (0xFF & adrPartArr[1]);
3640  buffer[2] = (unsigned char) (0xFF & adrPartArr[2]);
3641  buffer[3] = (unsigned char) (0xFF & adrPartArr[3]);
3642  bufferLen = 4;
3643  }
3644  //\x02sMN mLMPsetscancfg %d 1 %d 0 0\x03";
3645  //02 02 02 02 00 00 00 25 73 4D 4E 20 6D 4C 4D 50 73 65 74 73 63 61 6E 63 66 67 20
3646  // 00 00 13 88 4byte freq
3647  // 00 01 2 byte sectors always 1
3648  // 00 00 13 88 ang_res
3649  // FF F9 22 30 sector start always 0
3650  // 00 22 55 10 sector stop always 0
3651  // 21
3652  if (cmdAscii.find(keyWord7) != std::string::npos)
3653  {
3654  bufferLen = 18;
3655  for(int i=0;i<bufferLen;i++)
3656  {
3657  unsigned char uch=0x00;
3658  switch (i)
3659  {
3660  case 5:
3661  uch=0x01;break;
3662  }
3663  buffer[i]=uch;
3664  }
3665  char tmpStr[1024] = {0};
3666  char szApplStr[255] = {0};
3667  int keyWord7Len = keyWord7.length();
3668  int scanDataStatus = 0;
3669  int dummy0, dummy1;
3670  strcpy(tmpStr, requestAscii + keyWord7Len + 2);
3671  sscanf(tmpStr, "%d 1 %d", &dummy0, &dummy1);
3672 
3673  buffer[0] = (unsigned char)(0xFF & (dummy0 >> 24));
3674  buffer[1] = (unsigned char)(0xFF & (dummy0 >> 16));
3675  buffer[2] = (unsigned char)(0xFF & (dummy0 >> 8));
3676  buffer[3] = (unsigned char)(0xFF & (dummy0 >> 0));
3677 
3678 
3679  buffer[6] = (unsigned char)(0xFF & (dummy1 >> 24));
3680  buffer[7] = (unsigned char)(0xFF & (dummy1 >> 16));
3681  buffer[8] = (unsigned char)(0xFF & (dummy1 >> 8));
3682  buffer[9] = (unsigned char)(0xFF & (dummy1 >> 0));
3683 
3684 
3685  }
3686  if (cmdAscii.find(keyWord8) != std::string::npos)
3687  {
3688  uint32_t updatetime = 0;
3689  int keyWord8Len = keyWord8.length();
3690  sscanf(requestAscii + keyWord8Len + 1, " %d", &updatetime);
3691  buffer[0] = (unsigned char)(0xFF & (updatetime >> 24));
3692  buffer[1] = (unsigned char)(0xFF & (updatetime >> 16));
3693  buffer[2] = (unsigned char)(0xFF & (updatetime >> 8));
3694  buffer[3] = (unsigned char)(0xFF & (updatetime >> 0));
3695  bufferLen = 4;
3696  }
3697  if (cmdAscii.find(keyWord9) != std::string::npos)
3698  {
3699  int adrPartArr[4];
3700  int imuSetStatus = 0;
3701  int keyWord9Len = keyWord9.length();
3702  sscanf(requestAscii + keyWord9Len + 1, " %x %x %x %x", &(adrPartArr[0]), &(adrPartArr[1]), &(adrPartArr[2]),
3703  &(adrPartArr[3]));
3704  buffer[0] = (unsigned char) (0xFF & adrPartArr[0]);
3705  buffer[1] = (unsigned char) (0xFF & adrPartArr[1]);
3706  buffer[2] = (unsigned char) (0xFF & adrPartArr[2]);
3707  buffer[3] = (unsigned char) (0xFF & adrPartArr[3]);
3708  bufferLen = 4;
3709  }
3710  // copy base command string to buffer
3711  bool switchDoBinaryData = false;
3712  for (int i = 1; i <= (int) (msgLen); i++) // STX DATA ETX --> 0 1 2
3713  {
3714  char c = requestAscii[i];
3715  if (switchDoBinaryData == true)
3716  {
3717  if (0 == bufferLen) // no keyword handling before this point
3718  {
3719  if (c >= '0' && c <= '9') // standard data format expected - only one digit
3720  {
3721  c -= '0'; // convert ASCII-digit to hex-digit
3722  } // 48dez to 00dez and so on.
3723  }
3724  else
3725  {
3726  break;
3727  }
3728  }
3729  requestBinary->push_back(c);
3730  if (requestAscii[i] == 0x20) // space
3731  {
3732  spaceCnt++;
3733  if (spaceCnt >= copyUntilSpaceCnt)
3734  {
3735  switchDoBinaryData = true;
3736  }
3737  }
3738 
3739  }
3740  // if there are already process bytes (due to special key word handling)
3741  // copy these data bytes to the buffer
3742  for (int i = 0; i < bufferLen; i++) // append variable data
3743  {
3744  requestBinary->push_back(buffer[i]);
3745  }
3746 
3747  msgLen = requestBinary->size();
3748  msgLen -= 8;
3749  for (int i = 0; i < 4; i++)
3750  {
3751  unsigned char bigEndianLen = msgLen & (0xFF << (3 - i) * 8);
3752  (*requestBinary)[i + 4] = ((unsigned char) (bigEndianLen)); // HIER WEITERMACHEN!!!!
3753  }
3754  unsigned char xorVal = 0x00;
3755  xorVal = sick_crc8((unsigned char *) (&((*requestBinary)[8])), requestBinary->size() - 8);
3756  requestBinary->push_back(xorVal);
3757 #if 0
3758  for (int i = 0; i < requestBinary->size(); i++)
3759  {
3760  unsigned char c = (*requestBinary)[i];
3761  printf("[%c]%02x ", (c < ' ') ? '.' : c, c) ;
3762  }
3763  printf("\n");
3764 #endif
3765  return (0);
3766 
3767  };
3768 
3769 
3777  {
3778  bool retValue = true;
3779  bool shouldUseBinary = this->parser_->getCurrentParamPtr()->getUseBinaryProtocol();
3780  if (shouldUseBinary == useBinaryCmdNow)
3781  {
3782  retValue = true; // !!!! CHANGE ONLY FOR TEST!!!!!
3783  }
3784  else
3785  {
3786  /*
3787  // we must reconnect and set the new protocoltype
3788  int iRet = this->close_device();
3789  ROS_INFO("SOPAS - Close and reconnected to scanner due to protocol change and wait 15 sec. ");
3790  ROS_INFO("SOPAS - Changing from %s to %s\n", shouldUseBinary ? "ASCII" : "BINARY", shouldUseBinary ? "BINARY" : "ASCII");
3791  // Wait a few seconds after rebooting
3792  ros::Duration(15.0).sleep();
3793 
3794  iRet = this->init_device();
3795  */
3796  if (shouldUseBinary == true)
3797  {
3798  this->setProtocolType(CoLa_B);
3799  }
3800  else
3801  {
3802  this->setProtocolType(CoLa_A);
3803  }
3804 
3805  useBinaryCmdNow = shouldUseBinary;
3806  retValue = false;
3807  }
3808  return (retValue);
3809  }
3810 
3811 
3812  bool SickScanCommon::setNewIpAddress(boost::asio::ip::address_v4 ipNewIPAddr, bool useBinaryCmd)
3813  {
3814  int eepwritetTimeOut =1;
3815  char szCmd[255];
3816  bool result = false;
3817 
3818 
3819  unsigned long adrBytesLong[4];
3820  std::string s = ipNewIPAddr.to_string(); // convert to string, to_bytes not applicable for older linux version
3821  const char *ptr = s.c_str(); // char * to address
3822  // decompose pattern like aaa.bbb.ccc.ddd
3823  sscanf(ptr,"%lu.%lu.%lu.%lu", &(adrBytesLong[0]), &(adrBytesLong[1]), &(adrBytesLong[2]), &(adrBytesLong[3]));
3824 
3825  // convert into byte array
3826  unsigned char ipbytearray[4];
3827  for (int i = 0; i < 4; i++)
3828  {
3829  ipbytearray[i] = adrBytesLong[i] & 0xFF;
3830  }
3831 
3832 
3833  char ipcommand[255];
3834  const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_IP_ADDR].c_str();
3835  sprintf(ipcommand, pcCmdMask, ipbytearray[0], ipbytearray[1], ipbytearray[2], ipbytearray[3]);
3836  if (useBinaryCmd)
3837  {
3838  std::vector<unsigned char> reqBinary;
3839  this->convertAscii2BinaryCmd(ipcommand, &reqBinary);
3841  reqBinary.clear();
3842  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_WRITE_EEPROM].c_str(), &reqBinary);
3844  reqBinary.clear();
3845  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_RUN].c_str(), &reqBinary);
3846  result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_RUN]);
3847  reqBinary.clear();
3848  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_SET_ACCESS_MODE_3].c_str(), &reqBinary);
3850  reqBinary.clear();
3851  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_REBOOT].c_str(), &reqBinary);
3852  result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_REBOOT]);
3853  }
3854  else
3855  {
3856  std::vector<unsigned char> ipcomandReply;
3857  std::vector<unsigned char> resetReply;
3858  std::string runCmd = sopasCmdVec[CMD_RUN];
3859  std::string restartCmd = sopasCmdVec[CMD_REBOOT];
3860  std::string EEPCmd = sopasCmdVec[CMD_WRITE_EEPROM];
3861  std::string UserLvlCmd = sopasCmdVec[CMD_SET_ACCESS_MODE_3];
3862  result = sendSopasAndCheckAnswer(ipcommand, &ipcomandReply);
3863  result &= sendSopasAndCheckAnswer(EEPCmd, &resetReply);
3864  result &= sendSopasAndCheckAnswer(runCmd, &resetReply);
3865  result &= sendSopasAndCheckAnswer(UserLvlCmd, &resetReply);
3866  result &= sendSopasAndCheckAnswer(restartCmd, &resetReply);
3867  }
3868  return (result);
3869  }
3870 
3871  bool SickScanCommon::setNTPServerAndStart(boost::asio::ip::address_v4 ipNewIPAddr, bool useBinaryCmd)
3872  {
3873  char szCmd[255];
3874  bool result = false;
3875 
3876 
3877  unsigned long adrBytesLong[4];
3878  std::string s = ipNewIPAddr.to_string(); // convert to string, to_bytes not applicable for older linux version
3879  const char *ptr = s.c_str(); // char * to address
3880  // decompose pattern like aaa.bbb.ccc.ddd
3881  sscanf(ptr,"%lu.%lu.%lu.%lu", &(adrBytesLong[0]), &(adrBytesLong[1]), &(adrBytesLong[2]), &(adrBytesLong[3]));
3882 
3883  // convert into byte array
3884  unsigned char ipbytearray[4];
3885  for (int i = 0; i < 4; i++)
3886  {
3887  ipbytearray[i] = adrBytesLong[i] & 0xFF;
3888  }
3889 
3890 
3891  char ntpipcommand[255];
3892  char ntpupdatetimecommand[255];
3893  const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_NTP_SERVER_IP_ADDR].c_str();
3894  sprintf(ntpipcommand, pcCmdMask, ipbytearray[0], ipbytearray[1], ipbytearray[2], ipbytearray[3]);
3895 
3896  const char *pcCmdMaskUpdatetime = sopasCmdMaskVec[CMD_SET_NTP_UPDATETIME].c_str();
3897  sprintf(ntpupdatetimecommand, pcCmdMaskUpdatetime, 5);
3898  std::vector<unsigned char> outputFilterntpupdatetimecommand;
3899  //
3900  if (useBinaryCmd)
3901  {
3902  std::vector<unsigned char> reqBinary;
3903  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_SET_NTP_INTERFACE_ETH].c_str(), &reqBinary);
3905  reqBinary.clear();
3906  this->convertAscii2BinaryCmd(ntpipcommand, &reqBinary);
3908  reqBinary.clear();
3909  this->convertAscii2BinaryCmd(ntpupdatetimecommand, &reqBinary);
3911  reqBinary.clear();
3912  this->convertAscii2BinaryCmd(sopasCmdVec[CMD_ACTIVATE_NTP_CLIENT].c_str(), &reqBinary);
3914  reqBinary.clear();
3915 
3916  }
3917  else
3918  {
3919  std::vector<unsigned char> ipcomandReply;
3920  std::vector<unsigned char> resetReply;
3921  std::string ntpInterFaceETHCmd = sopasCmdVec[CMD_SET_NTP_INTERFACE_ETH];
3922  std::string activateNTPCmd = sopasCmdVec[CMD_ACTIVATE_NTP_CLIENT];
3923  result &= sendSopasAndCheckAnswer(ntpInterFaceETHCmd , &resetReply);
3924  result = sendSopasAndCheckAnswer(ntpipcommand, &ipcomandReply);
3925  result &= sendSopasAndCheckAnswer(activateNTPCmd, &resetReply);
3926  result &= sendSopasAndCheckAnswer(ntpupdatetimecommand, &outputFilterntpupdatetimecommand);
3927  }
3928  return (result);
3929  }
3930 
3932  {
3933  sensorIsRadar = _isRadar;
3934  }
3935 
3937  {
3938  return (sensorIsRadar);
3939  }
3940 
3941  // SopasProtocol m_protocolId;
3942 
3943 } /* namespace sick_scan */
3944 
3945 
3946 
msg
void setReadTimeOutInMs(int timeOutInMs)
set timeout in milliseconds
std::vector< std::string > sopasCmdErrMsg
void check_angle_range(SickScanConfig &conf)
check angle setting in the config and adjust the min_ang to the max_ang if min_ang greater than max_a...
int loopOnce()
parsing datagram and publishing ros messages
bool isImuDatagram(char *datagram, size_t datagram_length)
virtual int init_scanner()
initialize scanner
std::vector< std::string > sopasCmdMaskVec
int binScanfGuessDataLenFromMask(const char *scanfMask)
Definition: binScanf.cpp:366
#define ROS_FATAL(...)
#define PARAM_MIN_ANG
std::vector< std::string > sopasReplyStrVec
void publish(const boost::shared_ptr< M > &message) const
std::vector< std::string > sopasCmdVec
double getElevationDegreeResolution(void)
get angular resolution in VERTICAL direction for multilayer scanner
uint16_t UINT16
int getReadTimeOutInMs()
get timeout in milliseconds
f
void update_config(sick_scan::SickScanConfig &new_config, uint32_t level=0)
updating configuration
std::vector< unsigned char > stringToVector(std::string s)
Universal swapping function.
const std::string binScanfGetStringFromVec(std::vector< unsigned char > *replyDummy, int off, long len)
Convert part of unsigned char vector into a std::string.
void setHardwareID(const std::string &hwid)
std::string stripControl(std::vector< unsigned char > s)
Converts a SOPAS command to a human readable string.
static SoftwarePLL & instance()
Definition: softwarePLL.h:23
bool isImuAckDatagram(char *datagram, size_t datagram_length)
bool sleep() const
double getExpectedFrequency(void)
get expected scan frequency
bool dumpDatagramForDebugging(unsigned char *buffer, int bufLen)
ros::Publisher cloud_radar_track_pub_
SickScanCommon(SickGenericParser *parser)
Construction of SickScanCommon.
float get_range_min(void)
Getting minimum range.
data
int convertAscii2BinaryCmd(const char *requestAscii, std::vector< unsigned char > *requestBinary)
Convert ASCII-message to Binary-message.
virtual int init_device()=0
void swap_endian(unsigned char *ptr, int numBytes)
Universal swapping function.
#define ROS_WARN(...)
int parseDatagram(ros::Time timeStamp, unsigned char *receiveBuffer, int actual_length, bool useBinaryProtocol)
#define deg2rad_const
int binScanfVec(const std::vector< unsigned char > *vec, const char *fmt,...)
Definition: binScanf.cpp:345
Command Language ASCI.
bool setNewIpAddress(boost::asio::ip::address_v4 ipNewIPAddr, bool useBinaryCmd)
bool getIntensityResolutionIs16Bit(void)
Get the RSSI Value length.
#define rad2deg(x)
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
dynamic_reconfigure::Server< sick_scan::SickScanConfig > dynamic_reconfigure_server_
ros::Publisher cloud_radar_rawtarget_pub_
bool getCorrectedTimeStamp(uint32_t &sec, uint32_t &nanoSec, uint32_t tick)
diagnostic_updater::Updater diagnostics_
std::vector< std::string > sopasReplyVec
bool checkForProtocolChangeAndMaybeReconnect(bool &useBinaryCmdNow)
checks the current protocol type and gives information about necessary change
virtual bool rebootScanner()
Send a SOPAS command to the scanner that should cause a soft reset.
int getNumberOfLayers(void)
Getting number of scanner layers.
int getProtocolType(void)
get protocol type as enum
int getNumberOfMaximumEchos(void)
Get number of maximum echoes for this laser scanner type.
void setProtocolType(SopasProtocol cola_dialect_id)
set protocol type as enum
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std::vector< int > sopasCmdChain
void addFrameToBuffer(UINT8 *sendBuffer, UINT8 *cmdBuffer, UINT16 *len)
Definition: colab.cpp:99
std::string replyToString(const std::vector< unsigned char > &reply)
Converts reply from sendSOPASCommand to string.
virtual int parse_datagram(char *datagram, size_t datagram_length, SickScanConfig &config, sensor_msgs::LaserScan &msg, int &numEchos, int &echoMask)
Parsing Ascii datagram.
static int getDiagnosticErrorCode()
return diagnostic error code (small helper function) This small helper function was introduced to all...
void checkScanTiming(float time_increment, float scan_time, float angle_increment, float tol)
bool setNTPServerAndStart(boost::asio::ip::address_v4 ipNewIPAddr, bool useBinaryCmd)
float get_range_max(void)
Getting maximum range.
Command Language binary.
bool getUseBinaryProtocol(void)
flag to decide between usage of ASCII-sopas or BINARY-sopas
std::string generateExpectedAnswerString(const std::vector< unsigned char > requestStr)
Generate expected answer string from the command string.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
#define PARAM_MAX_ANG
#define ROS_WARN_STREAM(args)
ScannerBasicParam * getCurrentParamPtr()
Gets Pointer to parameter object.
static DataDumper & instance()
Definition: dataDumper.h:13
SickGenericParser * parser_
double getAngularDegreeResolution(void)
Get angular resolution in degress.
std::string getScannerName(void)
Getting name (type) of scanner.
int checkForBinaryAnswer(const std::vector< unsigned char > *reply)
Check block for correct framing and starting sequence of a binary message.
void setSensorIsRadar(bool _isRadar)
virtual ~SickScanCommon()
Destructor of SickScanCommon.
#define SICK_SCANNER_MRS_1XXX_NAME
int sendSopasAndCheckAnswer(std::string request, std::vector< unsigned char > *reply, int cmdId)
send command and check answer
unsigned long convertBigEndianCharArrayToUnsignedLong(const unsigned char *vecArr)
Convert little endian to big endian (should be replaced by swap-routine)
virtual int init()
init routine of scanner
#define PARAM_RES_ANG
void setIntensityResolutionIs16Bit(bool _IntensityResolutionIs16Bit)
Set the RSSI Value length.
bool getParam(const std::string &key, std::string &s) const
unsigned char sick_crc8(unsigned char *msgBlock, int len)
calculate crc-code for last byte of binary message XOR-calucation is done ONLY over message content (...
static Time now()
virtual int stop_scanner()
Stops sending scan data.
int parseDatagram(ros::Time timeStamp, unsigned char *receiveBuffer, int actual_length, bool useBinaryProtocol)
virtual int get_datagram(ros::Time &recvTimeStamp, unsigned char *receiveBuffer, int bufferSize, int *actual_length, bool isBinaryProtocol, int *numberOfRemainingFifoEntries)=0
Read a datagram from the device.
#define SICK_SCANNER_LMS_5XX_NAME
void broadcast(int lvl, const std::string msg)
bool isCompatibleDevice(const std::string identStr) const
check the identification string
#define ROS_ERROR_STREAM(args)
#define ROS_ASSERT(cond)
diagnostic_updater::DiagnosedPublisher< sensor_msgs::LaserScan > * diagnosticPub_
SopasProtocol
sensor_msgs::PointCloud2 cloud_
int dumpUcharBufferToConsole(unsigned char *buffer, int bufLen)
Definition: dataDumper.cpp:65
#define ROS_ERROR(...)
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
static sick_scan::SickScanCommonTcp * s
std::vector< std::vector< unsigned char > > sopasReplyBinVec
bool updatePLL(uint32_t sec, uint32_t nanoSec, uint32_t curtick)
Updates PLL internale State should be called only with network send timestamps.
int init_cmdTables()
init command tables and define startup sequence
bool getDeviceIsRadar(void)
flag to mark the device as radar (instead of laser scanner)
virtual int sendSOPASCommand(const char *request, std::vector< unsigned char > *reply, int cmdLen=-1)=0
Send a SOPAS command to the device and print out the response to the console.
#define ROS_DEBUG(...)


sick_scan
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Tue Jul 9 2019 04:55:32