Main MRPT website > C++ reference for MRPT 1.9.9
CSickLaserSerial.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 // This file contains portions of code from sicklms200.cc from the Player/Stage
11 // project.
12 
13 #include "hwdrivers-precomp.h" // Precompiled headers
14 
15 #include <mrpt/utils/crc.h>
16 #include <mrpt/utils/CTicTac.h>
17 #include <mrpt/system/os.h>
18 
20 
22 
23 #define RET_ERROR(msg) \
24  { \
25  cout << "[" << __CURRENT_FUNCTION_NAME__ << "] " << msg << endl; \
26  return false; \
27  }
28 
29 using namespace std;
30 using namespace mrpt;
31 using namespace mrpt::utils;
32 using namespace mrpt::comms;
33 using namespace mrpt::obs;
34 using namespace mrpt::poses;
35 using namespace mrpt::hwdrivers;
36 
37 int CSickLaserSerial::CRC16_GEN_POL = 0x8005;
38 
39 /*-------------------------------------------------------------
40  CSickLaserSerial
41 -------------------------------------------------------------*/
42 CSickLaserSerial::CSickLaserSerial()
43  : m_mm_mode(false),
44  m_scans_FOV(180),
45  m_scans_res(50),
46  m_com_port(),
47  m_mySerialPort(nullptr),
48  m_com_baudRate(38400),
49  m_nTries_connect(1),
50  m_nTries_current(0),
51  m_skip_laser_config(false)
52 {
53  m_sensorLabel = "SICKLMS";
55 }
56 
57 /*-------------------------------------------------------------
58  ~CSickLaserSerial
59 -------------------------------------------------------------*/
61 {
62  if (m_stream)
63  {
64  try
65  {
67  {
69  }
70  }
71  catch (...)
72  {
73  }
74  }
75 
76  if (m_mySerialPort)
77  {
78  delete m_mySerialPort;
79  m_mySerialPort = nullptr;
80  }
81 }
82 
83 /*-------------------------------------------------------------
84  doProcessSimple
85 -------------------------------------------------------------*/
87  bool& outThereIsObservation,
88  mrpt::obs::CObservation2DRangeScan& outObservation, bool& hardwareError)
89 {
90  outThereIsObservation = false;
91  hardwareError = false;
92 
93  if (!tryToOpenComms())
94  {
95  hardwareError = true;
96  return;
97  }
98 
99  vector<float> ranges;
100  unsigned char LMS_stat;
101  bool is_mm_mode;
102 
103  m_state = ssWorking;
104 
105  // Wait for a scan:
106  if (!waitContinuousSampleFrame(ranges, LMS_stat, is_mm_mode)) return;
107 
108  // Yes, we have a new scan:
109 
110  // -----------------------------------------------
111  // Extract the observation:
112  // -----------------------------------------------
113  outObservation.timestamp = mrpt::system::now();
114 
115  outObservation.sensorLabel = m_sensorLabel; // Set label
116 
117  // Extract the timestamp of the sensor:
118 
119  // And the scan ranges:
120  outObservation.rightToLeft = true;
121  outObservation.aperture = M_PIf;
122  outObservation.maxRange = is_mm_mode ? 32.7 : 81.0;
123  outObservation.stdError = 0.003f;
124  outObservation.sensorPose = mrpt::poses::CPose3D(m_sensorPose);
125 
126  outObservation.resizeScan(ranges.size());
127 
128  for (size_t i = 0; i < ranges.size(); i++)
129  {
130  outObservation.setScanRange(i, ranges[i]);
131  outObservation.setScanRangeValidity(
132  i, (outObservation.scan[i] <= outObservation.maxRange));
133  }
134 
135  // Do filter:
138  // Do show preview:
140 
141  outThereIsObservation = true;
142 }
143 
144 /*-------------------------------------------------------------
145  loadConfig_sensorSpecific
146 -------------------------------------------------------------*/
148  const mrpt::utils::CConfigFileBase& configSource,
149  const std::string& iniSection)
150 {
152  configSource.read_float(iniSection, "pose_x", 0),
153  configSource.read_float(iniSection, "pose_y", 0),
154  configSource.read_float(iniSection, "pose_z", 0),
155  DEG2RAD(configSource.read_float(iniSection, "pose_yaw", 0)),
156  DEG2RAD(configSource.read_float(iniSection, "pose_pitch", 0)),
157  DEG2RAD(configSource.read_float(iniSection, "pose_roll", 0)));
158 
159  m_mm_mode = configSource.read_bool(iniSection, "mm_mode", m_mm_mode);
160 
161 #ifdef MRPT_OS_WINDOWS
162  m_com_port =
163  configSource.read_string(iniSection, "COM_port_WIN", m_com_port, true);
164 #else
165  m_com_port =
166  configSource.read_string(iniSection, "COM_port_LIN", m_com_port, true);
167 #endif
168 
170  configSource.read_int(iniSection, "COM_baudRate", m_com_baudRate);
172  configSource.read_int(iniSection, "nTries_connect", m_nTries_connect);
173 
174  m_scans_FOV = configSource.read_int(iniSection, "FOV", m_scans_FOV);
175  m_scans_res = configSource.read_int(iniSection, "resolution", m_scans_res);
176 
177  m_skip_laser_config = configSource.read_bool(
178  iniSection, "skip_laser_config", m_skip_laser_config);
179 
180  // Parent options:
181  C2DRangeFinderAbstract::loadCommonParams(configSource, iniSection);
182 }
183 
184 /*-------------------------------------------------------------
185  turnOn
186 -------------------------------------------------------------*/
187 bool CSickLaserSerial::turnOn() { return true; }
188 /*-------------------------------------------------------------
189  turnOff
190 -------------------------------------------------------------*/
191 bool CSickLaserSerial::turnOff() { return true; }
192 /*-------------------------------------------------------------
193  Tries to open the com port and setup
194  all the LMS protocol. Returns true if OK or already open.
195 -------------------------------------------------------------*/
197 {
198  if (err_msg) *err_msg = "";
199  try
200  {
201  if (!m_stream)
202  {
203  ASSERT_(m_mySerialPort == nullptr);
204 
205  // There is no COMMS port open yet...
206  if (!m_com_port.empty())
207  {
208  // Create the port myself:
209  m_mySerialPort = new CSerialPort();
211  }
212  else
213  throw std::logic_error(
214  "ERROR: No serial port attached with bindIO, neither it "
215  "set with 'setSerialPort'");
216  }
217 
218  // We assure now we have a stream... try to open it, if it's not done
219  // yet.
220  bool just_open = false;
221  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
222  if (COM != nullptr)
223  {
224  if (!COM->isOpen())
225  {
226  // Try to open it now:
228  COM->open(); // will raise an exception on error.
229 
230  // Set basic params:
231  COM->setConfig(9600);
232  COM->setTimeouts(100, 0, 10, 0, 50);
233 
234  just_open = true;
235  }
236  }
237 
238  // It seems the port was open and working so we are done here.
239  if (!just_open) return true;
240 
241  // ==================================================================
242  // Otherwise, it was just opened now, we must send the
243  // ** initialization commands **
244  // and put the laser in continuous measuring mode:
245  // ==================================================================
246  if (!m_skip_laser_config)
247  {
248  if (!LMS_setupSerialComms()) RET_ERROR("error");
249 
250  bool res;
251  for (int nTry = 0; nTry < 4; nTry++)
252  if (true == (res = LMS_sendMeasuringMode_cm_mm())) break;
253 
254  if (!res) return false;
255 
256  for (int nTry = 0; nTry < 4; nTry++)
257  if (true == (res = LMS_startContinuousMode())) break;
258 
259  return res;
260  }
261  else
262  {
263  // Skip setup:
264  return true;
265  }
266  }
267  catch (std::exception& e)
268  {
269  std::string s = "[CSickLaserSerial] Error trying to open SICK at port ";
270  s += e.what();
271  if (err_msg) *err_msg = s;
272  MRPT_LOG_ERROR(s);
273  return false;
274  }
275 }
276 
277 /*-------------------------------------------------------------
278  waitContinuousSampleFrame
279 -------------------------------------------------------------*/
281  vector<float>& out_ranges_meters, unsigned char& LMS_status,
282  bool& is_mm_mode)
283 {
284  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
285  ASSERTMSG_(COM != nullptr, "No I/O channel bound to this object");
286 
287  size_t nRead, nBytesToRead;
288  size_t nFrameBytes = 0;
289  size_t lengthField;
290  unsigned char buf[2000];
291  buf[2] = buf[3] = buf[4] = 0;
292 
293  while (nFrameBytes < (lengthField = (6 + (buf[2] | (buf[3] << 8)))))
294  {
295  if (lengthField > 800)
296  {
297  cout << "#";
298  nFrameBytes = 0; // No es cabecera de trama correcta
299  buf[2] = buf[3] = 0;
300  }
301 
302  if (nFrameBytes < 4)
303  nBytesToRead = 1;
304  else
305  nBytesToRead = (lengthField)-nFrameBytes;
306 
307  try
308  {
309  nRead = COM->Read(buf + nFrameBytes, nBytesToRead);
310  }
311  catch (std::exception& e)
312  {
313  // Disconnected?
315  "[CSickLaserSerial::waitContinuousSampleFrame] Disconnecting "
316  "due to comms error: %s\n",
317  e.what());
318  // m_usbConnection->Close();
319  return false;
320  }
321 
322  if (!nRead && !nFrameBytes) return false;
323 
324  if (nRead < nBytesToRead) std::this_thread::sleep_for(1ms);
325 
326  // Lectura OK:
327  // Era la primera?
328  if (nFrameBytes > 1 || (!nFrameBytes && buf[0] == 0x02) ||
329  (nFrameBytes == 1 && buf[1] == 0x80))
330  {
331  nFrameBytes += nRead;
332  }
333  else
334  {
335  nFrameBytes = 0; // No es cabecera de trama correcta
336  buf[2] = buf[3] = 0;
337  // cerr << "."; //"[CSickLaserSerial] Skipping non-header..." <<
338  // endl;
339  }
340  }
341 
342  // Frame received
343  // --------------------------------------------------------------------------
344  // | STX | ADDR | L1 | L2 | COM | INF1 | INF2 | DATA | STA | CRC1 | CRC2
345  // |
346  // --------------------------------------------------------------------------
347 
348  // Trama completa:
349  // Checkear que el byte de comando es 0xB0:
350  if (buf[4] != 0xB0) return false;
351 
352  // GET FRAME INFO
353  int info = buf[5] | (buf[6] << 8); // Little Endian
354  int n_points = info & 0x01FF;
355  is_mm_mode = 0 != ((info & 0xC000) >> 14); // 0x00: cm 0x01: mm
356 
357  out_ranges_meters.resize(n_points);
358 
359  // Copiar rangos:
360  short mask = is_mm_mode ? 0x7FFF : 0x1FFF;
361  float meters_scale = is_mm_mode ? 0.001f : 0.01f;
362 
363  for (int i = 0; i < n_points; i++)
364  out_ranges_meters[i] =
365  ((buf[7 + i * 2] | (buf[8 + i * 2] << 8)) & mask) * meters_scale;
366 
367  // Status
368  LMS_status = buf[lengthField - 3];
369 
370  // CRC:
371  uint16_t CRC =
372  mrpt::utils::compute_CRC16(buf, lengthField - 2, CRC16_GEN_POL);
373  uint16_t CRC_packet = buf[lengthField - 2] | (buf[lengthField - 1] << 8);
374  if (CRC_packet != CRC)
375  {
376  cerr << format(
377  "[CSickLaserSerial::waitContinuousSampleFrame] bad CRC "
378  "len=%u nptns=%u: %i != %i",
379  unsigned(lengthField), unsigned(n_points), CRC_packet, CRC)
380  << endl;
381  return false; // Bad CRC
382  }
383 
384  // All OK
385  return true;
386 }
387 
388 /*-------------------------------------------------------------
389  initialize
390 -------------------------------------------------------------*/
392 {
393  string err_str;
395  if (!tryToOpenComms(&err_str))
396  {
397  cerr << err_str << endl;
398  throw std::logic_error(err_str);
399  }
400 }
401 
402 /*-----------------------------------------------------------------
403  Assures laser is connected and operating at 38400, in
404  its case returns true.
405  -----------------------------------------------------------------*/
407 {
408  ASSERT_(
409  m_com_baudRate == 9600 || m_com_baudRate == 38400 ||
410  m_com_baudRate == 500000);
411 
412  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
413  if (COM == nullptr) return true;
414 
415  int detected_rate = 0;
416  for (size_t reps = 0; !detected_rate && reps < m_nTries_connect; reps++)
417  {
418  m_nTries_current = reps;
419 
420  int rates[] = {0, 9600, 38400, 500000};
421 
422  // Try first the desired rate to speed up the process, just in case
423  // the laser is already setup from a previous run:
424  rates[0] = m_com_baudRate;
425 
426  detected_rate = 0;
427 
428  for (size_t i = 0;
429  !detected_rate && i < sizeof(rates) / sizeof(rates[0]); i++)
430  {
431  // Are we already receiving at 500k?
432  // ------------------------------------------------
433  COM->setConfig(rates[i]);
434 
435  LMS_endContinuousMode(); // Stop continuous mode.
436  std::this_thread::sleep_for(100ms);
437  COM->purgeBuffers();
438 
439  for (int nTry = 0; nTry < 4 && !detected_rate; nTry++)
440  {
441  COM->purgeBuffers();
442  // Ask for the laser status at the current rate:
443  if (LMS_statusQuery())
444  {
445  detected_rate = rates[i];
446  break;
447  }
448  std::this_thread::sleep_for(20ms);
449  } // for tries
450  // There is no link, or the baudrate is wrong...
451  }
452 
453  // Try again in a while:
454  if (!detected_rate && reps != (m_nTries_connect - 1))
455  std::this_thread::sleep_for(5000ms);
456  }
457 
458  // Are we connected at the right rate?
459  if (detected_rate == m_com_baudRate) return true;
460 
461  // Switch to the desired rate now
462  if (!this->LMS_setupBaudrate(m_com_baudRate)) RET_ERROR("error");
463 
464  // Check response is OK:
465  if (!(m_received_frame_buffer[2] == 0x03 &&
466  m_received_frame_buffer[4] == 0xA0 &&
467  m_received_frame_buffer[6] == 0x10))
468  return false;
469 
471  COM->purgeBuffers();
472 
473  // Wait...
474  std::this_thread::sleep_for(500ms);
475 
476  // And check comms at the new baud rate:
477  return LMS_statusQuery();
478 }
479 
480 /*-----------------------------------------------------------------
481  Query to LMS a baudrate change command.
482  Returns true if response is read ok.
483  -----------------------------------------------------------------*/
485 {
486  ASSERT_(m_stream);
487 
488  uint8_t cmd[4];
489  cmd[0] = 0x20;
490  switch (baud)
491  {
492  case 9600:
493  cmd[1] = 0x42;
494  break;
495  case 19200:
496  cmd[1] = 0x41;
497  break;
498  case 38400:
499  cmd[1] = 0x40;
500  break;
501  case 500000:
502  cmd[1] = 0x48;
503  break;
504  default:
505  THROW_EXCEPTION("Invalid baud rate value");
506  }
507 
508  uint16_t cmd_len = 2;
509 
510  if (!SendCommandToSICK(cmd, cmd_len)) return false;
511  return LMS_waitIncomingFrame(500);
512 }
513 
514 /*-----------------------------------------------------------------
515  Query to LMS a status query.
516  Returns true if response is read ok.
517  -----------------------------------------------------------------*/
519 {
520  ASSERT_(m_stream);
521 
522  uint8_t cmd[1];
523  cmd[0] = 0x31;
524  uint16_t cmd_len = 1;
525 
526  if (!SendCommandToSICK(cmd, cmd_len)) return false;
527  return LMS_waitIncomingFrame(500);
528 }
529 
530 // Returns false if timeout
532 {
533  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
534  ASSERT_(COM);
535 
536  uint8_t b = 0;
537  CTicTac tictac;
538  tictac.Tic();
539 
540  do
541  {
542  if (COM->Read(&b, 1))
543  { // Byte rx:
544  if (b == 0x06) return true;
545  }
546  } while (tictac.Tac() < timeout_ms * 1e-3);
547 
548  if (b == 0x15)
549  RET_ERROR(format("NACK received."))
550  else if (b != 0)
551  RET_ERROR(format("Unexpected code received: 0x%02X", b))
552  else
553  return false; // RET_ERROR("Timeout")
554 }
555 
556 // Returns false if timeout
558 {
559  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
560  ASSERT_(COM);
561 
562  uint8_t b;
563  unsigned int nBytes = 0;
564 
565  CTicTac tictac;
566  tictac.Tic();
567  const double maxTime = timeout * 1e-3;
568 
569  while (nBytes < 6 ||
570  (nBytes < (6U + m_received_frame_buffer[2] +
571  (uint16_t)(m_received_frame_buffer[3] << 8))))
572  {
573  if (COM->Read(&b, 1))
574  {
575  // First byte must be STX:
576  if (nBytes > 1 || (!nBytes && b == 0x02) ||
577  (nBytes == 1 && b == 0x80))
578  {
579  // Store in frame:
580  m_received_frame_buffer[nBytes] = b;
581  nBytes++;
582  }
583  }
584  if (tictac.Tac() >= maxTime) return false; // Timeout
585  }
586 
587  const uint16_t lengthField =
589  // Check len:
590  if (4U + lengthField + 2U != nBytes)
591  {
592  printf(
593  "[CSickLaserSerial::LMS_waitIncomingFrame] Error: expected %u "
594  "bytes, received %u\n",
595  4U + lengthField + 2U, nBytes);
596  return false;
597  }
598 
599  // Check CRC
601  m_received_frame_buffer, 4 + lengthField, CRC16_GEN_POL);
602  uint16_t CRC_packet = m_received_frame_buffer[4 + lengthField + 0] |
603  (m_received_frame_buffer[4 + lengthField + 1] << 8);
604  if (CRC_packet != CRC)
605  {
606  printf(
607  "[CSickLaserSerial::LMS_waitIncomingFrame] Error in CRC: rx: "
608  "0x%04X, computed: 0x%04X\n",
609  CRC_packet, CRC);
610  return false;
611  }
612 
613 #if 0
614  printf("RX: ");
615  for (unsigned int i=0;i<nBytes;i++)
616  printf("%02X ",m_received_frame_buffer[i]);
617  printf("\n");
618 #endif
619 
620  // OK
621  return true;
622 }
623 
625 {
626  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
627  ASSERT_(COM);
628 
629  // **************************
630  // Send command: Switch to Installation mode
631  // **************************
632  uint8_t cmd[128]; // =
633  // {0x02,0x00,0x0A,0x00,0x20,0x00,0x53,0x49,0x43,0x4B,0x5F,0x4C,0x4D,0x53,0xBE,0xC5};
634  cmd[0] = 0x20; /* mode change command */
635  cmd[1] = 0x00; /* configuration mode */
636  cmd[2] = 0x53; // S - the password
637  cmd[3] = 0x49; // I
638  cmd[4] = 0x43; // C
639  cmd[5] = 0x4B; // K
640  cmd[6] = 0x5F; // _
641  cmd[7] = 0x4C; // L
642  cmd[8] = 0x4D; // M
643  cmd[9] = 0x53; // S
644 
645  uint16_t cmd_len = 10;
646  if (!SendCommandToSICK(cmd, cmd_len))
647  RET_ERROR("Error waiting ACK to installation mode");
648  if (!LMS_waitIncomingFrame(500))
649  RET_ERROR("Error in response to installation mode");
650 
651  // Check response
652  if (!(m_received_frame_buffer[4] == 0xA0 &&
653  m_received_frame_buffer[5] == 0x00))
654  RET_ERROR("Wrong response to installation mode");
655 
656  // **************************
657  // Request LMS Configuration
658  // **************************
659  cmd[0] = 0x74;
660  cmd_len = 1;
661 
662  if (!SendCommandToSICK(cmd, cmd_len))
663  RET_ERROR("No ACK to 0x74 (req. config)");
664  if (!LMS_waitIncomingFrame(500))
665  RET_ERROR("No answer to 0x74 (req. config)");
666 
667  // 2. Check response
668  if (m_received_frame_buffer[4] != 0xF4)
669  RET_ERROR("No expected 0xF4 in response to 0x74 (req. config)");
670 
671  // ***********************************************************************
672  // Configure 1/2: Measuremente Range, Measurement Unit, Master/Slave Role
673  // ***********************************************************************
674  // 4.a Modify some values...
675 
676  // Measuring mode: Measurement range 32m in mm mode, or 80m+reflectance info
677  // in cm mode.
678  // See page 98 in LMS2xx_list_datagrams.pdf.
679  m_received_frame_buffer[10] = this->m_mm_mode ? 0x06 : 0x00;
680  m_received_frame_buffer[11] = this->m_mm_mode ? 0x01 : 0x00;
681 
682  // 4.2 Build the output command
683  m_received_frame_buffer[1] = 0x00; // Address
684  m_received_frame_buffer[2] = 0x23; // Length (low byte)
685  m_received_frame_buffer[3] = 0x00; // Length (high byte)
686  m_received_frame_buffer[4] = 0x77; // Configure command
687 
688  memcpy(cmd, m_received_frame_buffer + 4, 0x23);
689  cmd_len = 0x23;
690 
691  // 4.4 Send to the LMS
692  if (!SendCommandToSICK(cmd, cmd_len))
693  RET_ERROR("No ACK for config command (0x77)");
694  if (!LMS_waitIncomingFrame(600))
695  RET_ERROR("No answer for config command (0x77)");
696 
697  if (!(m_received_frame_buffer[4] == 0xF7 &&
698  m_received_frame_buffer[5] == 0x01))
699  RET_ERROR("Wrong answer for config command (0x77)");
700 
701  // **************************
702  // Switch to Monitoring mode
703  // **************************
704  cmd[0] = 0x20;
705  cmd[1] = 0x25;
706  cmd_len = 2;
707  if (!SendCommandToSICK(cmd, cmd_len))
708  RET_ERROR("No ACK for set monitoring mode");
709  if (!LMS_waitIncomingFrame(500))
710  RET_ERROR("No answer for set monitoring mode");
711 
712  if (!(m_received_frame_buffer[4] == 0xA0 &&
713  m_received_frame_buffer[5] == 0x00))
714  RET_ERROR("Wrong answer for set monitoring mode");
715 
716  // All ok.
717  return true;
718 }
719 
720 /*-----------------------------------------------------------------
721  Start continuous mode measurements.
722  Returns true if response is read ok.
723  -----------------------------------------------------------------*/
725 {
726  ASSERT_(m_scans_FOV == 100 || m_scans_FOV == 180);
727  ASSERT_(m_scans_res == 25 || m_scans_res == 50 || m_scans_res == 100);
728 
729  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
730  ASSERT_(COM);
731 
732  uint8_t cmd[40];
733 
734  // Config angle/resolution
735  cmd[0] = 0x3B;
736  cmd[1] = m_scans_FOV;
737  cmd[2] = 0x00;
738  cmd[3] = m_scans_res; // 25,50 or 100 - 1/100th of deg
739  cmd[4] = 0x00;
740  uint16_t cmd_len = 5;
741  if (!SendCommandToSICK(cmd, cmd_len))
742  RET_ERROR("Error waiting ack for change angle/resolution");
743  if (!LMS_waitIncomingFrame(500))
744  RET_ERROR("Error waiting answer for change angle/resolution");
745 
746  // Start continuous mode:
747  cmd[0] = 0x20;
748  cmd[1] = 0x24;
749  cmd_len = 2;
750  if (!SendCommandToSICK(cmd, cmd_len))
751  RET_ERROR("Error waiting ack for start scanning");
752  if (!LMS_waitIncomingFrame(500))
753  RET_ERROR("Error waiting answer for start scanning");
754 
755  return true;
756 }
757 
759 {
760  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
761  ASSERT_(COM);
762 
763  uint8_t cmd[40];
764 
765  // End continuous mode:
766  cmd[0] = 0x20;
767  cmd[1] = 0x25;
768  uint16_t cmd_len = 2;
769  if (!SendCommandToSICK(cmd, cmd_len)) return false;
770  return LMS_waitIncomingFrame(50);
771 }
772 
774  const uint8_t* cmd, const uint16_t cmd_len)
775 {
776  uint8_t cmd_full[1024];
777  ASSERT_(sizeof(cmd_full) > cmd_len + 4U + 2U);
778 
779  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
780  ASSERT_(COM);
781 
782  // Create header
783  cmd_full[0] = 0x02; // STX
784  cmd_full[1] = 0; // ADDR
785  cmd_full[2] = cmd_len & 0xFF;
786  cmd_full[3] = cmd_len >> 8;
787 
788  memcpy(cmd_full + 4, cmd, cmd_len);
789 
790  const uint16_t crc =
791  mrpt::utils::compute_CRC16(cmd_full, 4 + cmd_len, CRC16_GEN_POL);
792  cmd_full[4 + cmd_len + 0] = crc & 0xFF;
793  cmd_full[4 + cmd_len + 1] = crc >> 8;
794 
795  const size_t toWrite = 4 + cmd_len + 2;
796 
797 #if 0
798  printf("TX: ");
799  for (unsigned int i=0;i<toWrite;i++)
800  printf("%02X ",cmd_full[i]);
801  printf("\n");
802 #endif
803 
804  const int NTRIES = 3;
805 
806  for (int k = 0; k < NTRIES; k++)
807  {
808  if (toWrite != COM->Write(cmd_full, toWrite))
809  {
810  cout << "[CSickLaserSerial::SendCommandToSICK] Error writing data "
811  "to serial port."
812  << endl;
813  return false;
814  }
815  std::this_thread::sleep_for(15ms);
816  if (LMS_waitACK(50)) return true;
817  std::this_thread::sleep_for(10ms);
818  }
819 
820  return false;
821 }
void setSerialPortName(const std::string &COM_name)
Sets the serial port to open (it is an error to try to change this while open yet).
Definition: CSerialPort.h:74
size_t Write(const void *Buffer, size_t Count)
Implements the virtual method responsible for writing to the stream.
GLenum GLint GLuint mask
Definition: glext.h:4050
bool LMS_sendMeasuringMode_cm_mm()
Returns false on error.
bool read_bool(const std::string &section, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
unsigned __int16 uint16_t
Definition: rptypes.h:44
A communications serial port built as an implementation of a utils::CStream.
Definition: CSerialPort.h:47
utils::CStream * m_stream
The I/O channel (will be nullptr if not bound).
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
bool turnOff()
Disables the scanning mode (in this class this has no effect).
void setScanRange(const size_t i, const float val)
std::string m_sensorLabel
See CGenericSensor.
bool LMS_statusQuery()
Send a status query and wait for the answer.
#define THROW_EXCEPTION(msg)
void open()
Open the port.
Definition: CSerialPort.cpp:88
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
Definition: datetime.h:76
Contains classes for various device interfaces.
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
STL namespace.
int m_com_baudRate
Baudrate: 9600, 38400, 500000.
void filterByExclusionAreas(mrpt::obs::CObservation2DRangeScan &obs) const
Mark as invalid those points which (x,y) coordinates fall within the exclusion polygons.
void loadConfig_sensorSpecific(const mrpt::utils::CConfigFileBase &configSource, const std::string &iniSection)
See the class documentation at the top for expected parameters.
float stdError
The "sigma" error of the device in meters, used while inserting the scan in an occupancy grid...
#define MRPT_LOG_ERROR_FMT(_FMT_STRING,...)
GLdouble s
Definition: glext.h:3676
void setConfig(int baudRate, int parity=0, int bits=8, int nStopBits=1, bool enableFlowControl=false)
Changes the configuration of the port.
void Tic()
Starts the stopwatch.
Definition: CTicTac.cpp:82
void filterByExclusionAngles(mrpt::obs::CObservation2DRangeScan &obs) const
Mark as invalid those ranges in a set of forbiden angle ranges.
bool LMS_setupSerialComms()
Assures laser is connected and operating at 38400, in its case returns true.
#define RET_ERROR(msg)
This class allows loading and storing values and vectors of different types from a configuration text...
unsigned char uint8_t
Definition: rptypes.h:41
float maxRange
The maximum range allowed by the device, in meters (e.g.
bool LMS_setupBaudrate(int baud)
Send a command to change the LMS comms baudrate, return true if ACK is OK.
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
void initialize()
Set-up communication with the laser.
std::string m_com_port
If set to non-empty, the serial port will be attempted to be opened automatically when this class is ...
#define M_PIf
bool m_skip_laser_config
If true, doesn&#39;t send the initialization commands to the laser and go straight to capturing...
bool waitContinuousSampleFrame(std::vector< float > &ranges, unsigned char &LMS_status, bool &is_mm_mode)
This class implements a high-performance stopwatch.
Definition: CTicTac.h:23
bool isOpen() const
Returns if port has been correctly open.
This namespace contains representation of robot actions and observations.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
GLubyte GLubyte b
Definition: glext.h:6279
uint16_t compute_CRC16(const std::vector< uint8_t > &data, const uint16_t gen_pol=0x8005)
Computes the CRC16 checksum of a block of data.
Definition: crc.cpp:20
bool tryToOpenComms(std::string *err_msg=nullptr)
Tries to open the com port and setup all the LMS protocol.
bool LMS_waitIncomingFrame(uint16_t timeout)
Returns false if timeout.
mrpt::math::TPose3D m_sensorPose
The sensor 6D pose:
void purgeBuffers()
Purge tx and rx buffers.
#define DEG2RAD
void loadCommonParams(const mrpt::utils::CConfigFileBase &configSource, const std::string &iniSection)
Should be call by derived classes at "loadConfig" (loads exclusion areas AND exclusion angles)...
GLsizei const GLchar ** string
Definition: glext.h:4101
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
void setTimeouts(int ReadIntervalTimeout, int ReadTotalTimeoutMultiplier, int ReadTotalTimeoutConstant, int WriteTotalTimeoutMultiplier, int WriteTotalTimeoutConstant)
Changes the timeouts of the port, in milliseconds.
virtual ~CSickLaserSerial()
Destructor.
int m_scans_res
1/100th of deg: 100, 50 or 25
std::string sensorLabel
An arbitrary label that can be used to identify the sensor.
Definition: CObservation.h:60
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
bool SendCommandToSICK(const uint8_t *cmd, const uint16_t cmd_len)
Send header+command-data+crc and waits for ACK.
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:58
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
void resizeScan(const size_t len)
Resizes all data vectors to allocate a given number of scan rays.
This "software driver" implements the communication protocol for interfacing a SICK LMS 2XX laser sca...
void processPreview(const mrpt::obs::CObservation2DRangeScan &obs)
Must be called inside the capture method to allow optional GUI preview of scans.
double Tac()
Stops the stopwatch.
Definition: CTicTac.cpp:97
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
#define ASSERT_(f)
unsigned int m_nTries_connect
Default = 1.
bool turnOn()
Enables the scanning mode (in this class this has no effect).
#define MRPT_LOG_ERROR(_STRING)
GLuint res
Definition: glext.h:7268
Serial and networking devices and utilities.
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< float > > scan
The range values of the scan, in meters.
void doProcessSimple(bool &outThereIsObservation, mrpt::obs::CObservation2DRangeScan &outObservation, bool &hardwareError)
Specific laser scanner "software drivers" must process here new data from the I/O stream...
mrpt::comms::CSerialPort * m_mySerialPort
Will be !=nullptr only if I created it, so I must destroy it at the end.
#define ASSERTMSG_(f, __ERROR_MSG)
size_t Read(void *Buffer, size_t Count)
Implements the virtual method responsible for reading from the stream - Unlike CStream::ReadBuffer, this method will not raise an exception on zero bytes read, as long as there is not any fatal error in the communications.
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
bool LMS_waitACK(uint16_t timeout_ms)
Returns false if timeout.
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
Definition: os.cpp:355
void setScanRangeValidity(const size_t i, const bool val)



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019