Main MRPT website > C++ reference for MRPT 1.9.9
CHokuyoURG.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 #include "hwdrivers-precomp.h" // Precompiled headers
11 
13 #include <mrpt/comms/CSerialPort.h>
15 #include <mrpt/system/os.h>
16 #include <mrpt/opengl/CPlanarLaserScan.h> // in library mrpt-maps
17 #include <mrpt/opengl/CAxis.h>
18 
20 
21 using namespace mrpt::utils;
22 using namespace mrpt::obs;
23 using namespace mrpt::hwdrivers;
24 using namespace mrpt::comms;
25 using namespace mrpt::system;
26 using namespace mrpt::opengl;
27 using namespace std;
28 
30 
31 /*-------------------------------------------------------------
32  Constructor
33 -------------------------------------------------------------*/
34 CHokuyoURG::CHokuyoURG()
35  : m_firstRange(44),
36  m_lastRange(725),
37  m_motorSpeed_rpm(0),
38  m_sensorPose(0, 0, 0),
39  m_rx_buffer(40000),
40  m_highSensMode(false),
41  m_reduced_fov(0),
42  m_com_port(""),
43  m_ip_dir(""),
44  m_port_dir(10940),
45  m_I_am_owner_serial_port(false),
46  m_timeStartUI(0),
47  m_timeStartSynchDelay(0),
48  m_disable_firmware_timestamp(false),
49  m_intensity(false)
50 {
51  m_sensorLabel = "Hokuyo";
52 }
53 
54 /*-------------------------------------------------------------
55  ~CHokuyoURG
56 -------------------------------------------------------------*/
58 {
59  if (m_stream)
60  {
61  turnOff();
62 
64  m_stream = nullptr;
65  }
66 
67  // FAMD
68  m_win.reset();
69 }
70 
71 /*-------------------------------------------------------------
72  doProcessSimple
73 -------------------------------------------------------------*/
75  bool& outThereIsObservation,
76  mrpt::obs::CObservation2DRangeScan& outObservation, bool& hardwareError)
77 {
78  outThereIsObservation = false;
79  hardwareError = false;
80 
81  // Bound?
82  if (!checkCOMisOpen())
83  {
84  m_timeStartUI = 0;
86  hardwareError = true;
87  return;
88  }
89 
90  // Wait for a message:
91  char rcv_status0, rcv_status1;
92  vector_byte rcv_data(10000);
93  int rcv_dataLength;
94  int nRanges = m_lastRange - m_firstRange + 1;
95  int expectedSize = nRanges * 3 + 4;
96 
97  if (m_intensity)
98  {
99  expectedSize += nRanges * 3;
100  }
101 
102  m_state = ssWorking;
103  if (!receiveResponse(
104  m_lastSentMeasCmd.c_str(), rcv_status0, rcv_status1,
105  (char*)&rcv_data[0], rcv_dataLength))
106  {
107  // No new data
108  return;
109  }
110 
111  // DECODE:
112  if (rcv_status0 != '0' && rcv_status0 != '9')
113  {
114  hardwareError = true;
115  return;
116  }
117 
118  // -----------------------------------------------
119  // Extract the observation:
120  // -----------------------------------------------
121  outObservation.timestamp = mrpt::system::now();
122 
123  if (expectedSize != rcv_dataLength)
124  {
126  "[CHokuyoURG::doProcess] ERROR: Expecting %u data bytes, received "
127  "%u instead!\n",
128  expectedSize, rcv_dataLength);
129  hardwareError = true;
130  return;
131  }
132  // Delay the sync of timestamps due to instability in the constant rate
133  // during the first few packets.
134  bool do_timestamp_sync = !m_disable_firmware_timestamp;
135  if (do_timestamp_sync &&
137  {
138  do_timestamp_sync = false;
140  }
141 
142  if (do_timestamp_sync)
143  {
144  // Extract the timestamp of the sensor:
145  uint32_t nowUI = ((rcv_data[0] - 0x30) << 18) +
146  ((rcv_data[1] - 0x30) << 12) +
147  ((rcv_data[2] - 0x30) << 6) + (rcv_data[3] - 0x30);
148 
149  uint32_t AtUI = 0;
150  if (m_timeStartUI == 0)
151  {
152  m_timeStartUI = nowUI;
154  }
155  else
156  AtUI = nowUI - m_timeStartUI;
157 
159  AtUI * 1e-3 /* Board time is ms */);
160  outObservation.timestamp = m_timeStartTT + AtDO;
161  }
162 
163  // And the scan ranges:
164  outObservation.rightToLeft = true;
165 
166  outObservation.aperture =
167  nRanges * 2 * M_PI / m_sensor_info.scans_per_360deg;
168 
169  outObservation.maxRange = m_sensor_info.d_max;
170  outObservation.stdError = 0.010f;
171  outObservation.sensorPose = m_sensorPose;
172  outObservation.sensorLabel = m_sensorLabel;
173 
174  outObservation.resizeScan(nRanges);
175  char* ptr = (char*)&rcv_data[4];
176 
177  if (m_intensity) outObservation.setScanHasIntensity(true);
178 
179  for (int i = 0; i < nRanges; i++)
180  {
181  int b1 = (*ptr++) - 0x30;
182  int b2 = (*ptr++) - 0x30;
183  int b3 = (*ptr++) - 0x30;
184 
185  int range_mm = ((b1 << 12) | (b2 << 6) | b3);
186 
187  outObservation.setScanRange(i, range_mm * 0.001f);
188  outObservation.setScanRangeValidity(
189  i, range_mm >= 20 &&
190  (outObservation.scan[i] <= outObservation.maxRange));
191 
192  if (m_intensity)
193  {
194  int b4 = (*ptr++) - 0x30;
195  int b5 = (*ptr++) - 0x30;
196  int b6 = (*ptr++) - 0x30;
197  outObservation.setScanIntensity(i, ((b4 << 12) | (b5 << 6) | b6));
198  }
199  }
200 
201  // Do filter:
204  // Do show preview:
206 
207  outThereIsObservation = true;
208 }
209 
210 /*-------------------------------------------------------------
211  loadConfig_sensorSpecific
212 -------------------------------------------------------------*/
214  const mrpt::utils::CConfigFileBase& configSource,
215  const std::string& iniSection)
216 {
217  m_reduced_fov =
218  DEG2RAD(configSource.read_float(iniSection, "reduced_fov", 0)),
219 
221  configSource.read_int(iniSection, "HOKUYO_motorSpeed_rpm", 0);
223  configSource.read_float(iniSection, "pose_x", 0),
224  configSource.read_float(iniSection, "pose_y", 0),
225  configSource.read_float(iniSection, "pose_z", 0),
226  DEG2RAD(configSource.read_float(iniSection, "pose_yaw", 0)),
227  DEG2RAD(configSource.read_float(iniSection, "pose_pitch", 0)),
228  DEG2RAD(configSource.read_float(iniSection, "pose_roll", 0)));
229 
231  configSource.read_bool(iniSection, "HOKUYO_HS_mode", m_highSensMode);
232 
233 #ifdef MRPT_OS_WINDOWS
234  m_com_port =
235  configSource.read_string(iniSection, "COM_port_WIN", m_com_port);
236 #else
237  m_com_port =
238  configSource.read_string(iniSection, "COM_port_LIN", m_com_port);
239 #endif
240 
241  m_ip_dir = configSource.read_string(iniSection, "IP_DIR", m_ip_dir);
242  m_port_dir = configSource.read_int(iniSection, "PORT_DIR", m_port_dir);
243 
244  ASSERTMSG_(
245  !m_com_port.empty() || !m_ip_dir.empty(),
246  "Either COM_port or IP_DIR must be defined in the configuration file!");
247  ASSERTMSG_(
248  m_com_port.empty() || m_ip_dir.empty(),
249  "Both COM_port and IP_DIR set! Please, define only one of them.");
250  if (!m_ip_dir.empty())
251  {
252  ASSERTMSG_(
253  m_port_dir,
254  "A TCP/IP port number `PORT_DIR` must be specified for Ethernet "
255  "connection");
256  }
257 
259  iniSection, "disable_firmware_timestamp", m_disable_firmware_timestamp);
260  m_intensity = configSource.read_bool(iniSection, "intensity", m_intensity),
261 
262  // Parent options:
263  C2DRangeFinderAbstract::loadCommonParams(configSource, iniSection);
264 }
265 
266 /*-------------------------------------------------------------
267  turnOn
268 -------------------------------------------------------------*/
270 {
271  MRPT_START
272 
273  // Bound?
274  if (!checkCOMisOpen()) return false;
275 
276  // If we are over a serial link, set it up:
277  if (m_ip_dir.empty())
278  {
279  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
280 
281  if (COM != nullptr)
282  {
283  // It is a COM:
284  COM->setConfig(19200);
285  COM->setTimeouts(100, 0, 200, 0, 0);
286 
287  // Assure the laser is off and quiet:
288  switchLaserOff();
289  std::this_thread::sleep_for(10ms);
290 
291  COM->purgeBuffers();
292  std::this_thread::sleep_for(10ms);
293 
294  COM->setConfig(115200);
295  switchLaserOff();
296  std::this_thread::sleep_for(10ms);
297  COM->purgeBuffers();
298  std::this_thread::sleep_for(10ms);
299  COM->setConfig(19200);
300  }
301 
302  if (COM != nullptr)
303  {
304  // Set 115200 baud rate:
305  setHighBaudrate();
306  enableSCIP20();
307  COM->setConfig(115200);
308  }
309  }
310  else
311  {
312  CClientTCPSocket* COM = dynamic_cast<CClientTCPSocket*>(m_stream);
313 
314  if (COM != nullptr)
315  {
316  // Assure the laser is off and quiet:
317  switchLaserOff();
318  std::this_thread::sleep_for(10ms);
319 
320  purgeBuffers();
321  std::this_thread::sleep_for(10ms);
322 
323  switchLaserOff();
324  std::this_thread::sleep_for(10ms);
325  purgeBuffers();
326  }
327  }
328 
329  if (!enableSCIP20()) return false;
330 
331  // Turn on the laser:
332  if (!switchLaserOn()) return false;
333 
334  // Set the motor speed:
335  if (m_motorSpeed_rpm)
336  if (!setMotorSpeed(m_motorSpeed_rpm)) return false;
337 
338  // Set HS mode:
340 
341  // Display sensor information:
342  if (!displaySensorInfo(&m_sensor_info)) return false;
343 
344  // Set for scanning angles:
347 
348  // Artificially reduced FOV?
349  if (m_reduced_fov > 0 && m_reduced_fov < 2 * M_PI)
350  {
351  int center = (m_lastRange + m_firstRange) >> 1;
352  const int half_range = static_cast<int>(
355  1;
356  m_firstRange = center - half_range;
357  m_lastRange = center + half_range;
358  cout << "[HOKUYO::turnOn] Using reduced FOV: ranges [" << m_firstRange
359  << "-" << m_lastRange << "] for " << RAD2DEG(m_reduced_fov)
360  << " deg. FOV" << endl;
361  }
362 
363  if (!displayVersionInfo())
364  {
365  // return false; // It's not SO important
366  }
367 
368  // Start!
369  if (!startScanningMode()) return false;
370 
371  return true;
372 
373  MRPT_END
374 }
375 
376 /*-------------------------------------------------------------
377  turnOff
378 -------------------------------------------------------------*/
380 {
381  // Turn off the laser:
382  if (!switchLaserOff()) return false;
383 
384  return true;
385 }
386 
387 /*-------------------------------------------------------------
388  setHighBaudrate
389 -------------------------------------------------------------*/
391 {
392  char cmd[20];
393  char rcv_status0, rcv_status1;
394  char rcv_data[100];
395  size_t toWrite;
396  int rcv_dataLength;
397 
398  if (!checkCOMisOpen()) return false;
399 
401  "[CHokuyoURG::setHighBaudrate] Changing baudrate to 115200...");
402 
403  // Send command:
404  os::strcpy(cmd, 20, "SS115200\x0A");
405  toWrite = 9;
406 
407  m_stream->WriteBuffer(cmd, toWrite);
408 
409  // Receive response:
410  if (!receiveResponse(
411  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
412  {
413  std::cerr << "Error waiting for response\n";
414  return false;
415  }
416 
417  // DECODE:
418  if (rcv_status0 != '0')
419  {
420  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
421  return false;
422  }
423 
424  MRPT_LOG_DEBUG("OK\n");
425  return true;
426 }
427 
428 /*-------------------------------------------------------------
429  assureBufferHasBytes
430 -------------------------------------------------------------*/
431 bool CHokuyoURG::assureBufferHasBytes(const size_t nDesiredBytes)
432 {
433  ASSERT_(nDesiredBytes < m_rx_buffer.capacity());
434 
435  if (m_rx_buffer.size() >= nDesiredBytes)
436  {
437  return true;
438  }
439  else
440  {
441  // Try to read more bytes:
442  uint8_t buf[128];
443  const size_t to_read = std::min(m_rx_buffer.available(), sizeof(buf));
444 
445  try
446  {
447  size_t nRead;
448 
449  if (!m_ip_dir.empty())
450  {
451  CClientTCPSocket* client =
452  dynamic_cast<CClientTCPSocket*>(m_stream);
453  nRead = client->readAsync(buf, to_read, 100, 10);
454  }
455  else
456  {
457  nRead = m_stream->ReadBuffer(buf, to_read);
458  }
459 
460  m_rx_buffer.push_many(buf, nRead);
461  }
462  catch (std::exception&)
463  {
464  // 0 bytes read
465  }
466 
467  return (m_rx_buffer.size() >= nDesiredBytes);
468  }
469 }
470 
471 /*-------------------------------------------------------------
472  receiveResponse
473 -------------------------------------------------------------*/
475  const char* sentCmd_forEchoVerification, char& rcv_status0,
476  char& rcv_status1, char* rcv_data, int& rcv_dataLength)
477 {
478  if (!checkCOMisOpen()) return false;
479 
480  ASSERT_(sentCmd_forEchoVerification != nullptr);
481 
482  try
483  {
484  // Process response:
485  // ---------------------------------
486 
487  // COMMAND ECHO ---------
488  int i = 0;
489  const int verifLen = strlen(sentCmd_forEchoVerification);
490 
491  if (verifLen)
492  {
493  do
494  {
495  if (!assureBufferHasBytes(verifLen - i)) return false;
496 
497  // If matches the echo, go on:
498  if (m_rx_buffer.pop() == sentCmd_forEchoVerification[i])
499  i++;
500  else
501  i = 0;
502  } while (i < verifLen);
503  }
504 
505  // printf("VERIF.CMD OK!: %s", sentCmd_forEchoVerification);
506 
507  // Now, the status bytes:
508  if (!assureBufferHasBytes(2)) return false;
509 
510  rcv_status0 = m_rx_buffer.pop();
511  rcv_status1 = m_rx_buffer.pop();
512  // printf("STATUS: %c%c\n", rcv_status0,rcv_status1);
513 
514  // In SCIP2.0, there is an additional sum char:
515  if (rcv_status1 != 0x0A)
516  {
517  // Yes, it is SCIP2.0
518  if (!assureBufferHasBytes(1)) return false;
519 
520  // Ignore this byte: sumStatus
521  m_rx_buffer.pop();
522 
523  // printf("STATUS SUM: %c\n",sumStatus);
524  }
525  else
526  {
527  // Continue, it seems a SCIP1.1 response...
528  }
529 
530  // After the status bytes, there is a LF:
531  if (!assureBufferHasBytes(1)) return false;
532  char nextChar = m_rx_buffer.pop();
533  if (nextChar != 0x0A) return false;
534 
535  // -----------------------------------------------------------------------------
536  // Now the data:
537  // There's a problem here, we don't know in advance how many bytes to
538  // read,
539  // so rely on the serial port class implemented buffer and call many
540  // times
541  // the read method with only 1 byte each time:
542  // -----------------------------------------------------------------------------
543  bool lastWasLF = false;
544  i = 0;
545  for (;;)
546  {
547  if (!assureBufferHasBytes(1))
548  {
549  return false;
550  }
551  rcv_data[i] = m_rx_buffer.pop();
552 
553  // printf("%c",rcv_data[i]);
554 
555  i++; // One more byte in the buffer
556 
557  // No data?
558  if (i == 1 && rcv_data[0] == 0x0A)
559  {
560  rcv_dataLength = 0;
561  return true;
562  }
563 
564  // Is it a LF?
565  if (rcv_data[i - 1] == 0x0A)
566  {
567  if (!lastWasLF)
568  {
569  // Discard SUM+LF
570  ASSERT_(i >= 2);
571  i -= 2;
572  }
573  else
574  {
575  // Discard this last LF:
576  i--;
577 
578  // Done!
579  rcv_data[i] = 0;
580  // printf("RX %u:\n'%s'\n",i,rcv_data);
581 
582  rcv_dataLength = i;
583  return true;
584  }
585  lastWasLF = true;
586  }
587  else
588  lastWasLF = false;
589  }
590  }
591  catch (std::exception&)
592  {
593  // cerr << e.what() << endl;
594  return false;
595  }
596  catch (...)
597  {
598  return false; // Serial port timeout,...
599  }
600 }
601 
602 /*-------------------------------------------------------------
603  enableSCIP20
604 -------------------------------------------------------------*/
606 {
607  char cmd[20];
608  char rcv_status0, rcv_status1;
609  char rcv_data[100];
610  size_t toWrite;
611  int rcv_dataLength;
612 
613  if (!checkCOMisOpen()) return false;
614 
616  "[CHokuyoURG::enableSCIP20] Changing protocol to SCIP2.0...");
617 
618  // Send command:
619  os::strcpy(cmd, 20, "SCIP2.0\x0A");
620  toWrite = 8;
621 
622  m_stream->WriteBuffer(cmd, toWrite);
623 
624  // Receive response:
625  if (!receiveResponse(
626  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
627  {
628  std::cerr << "Error waiting for response\n";
629  return false;
630  }
631 
632  // DECODE:
633  if (rcv_status0 != '0')
634  {
635  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
636  return false;
637  }
638 
639  MRPT_LOG_DEBUG("OK\n");
640  return true;
641 }
642 
643 /*-------------------------------------------------------------
644  switchLaserOn
645 -------------------------------------------------------------*/
647 {
648  char cmd[20];
649  char rcv_status0, rcv_status1;
650  char rcv_data[100];
651  size_t toWrite;
652  int rcv_dataLength;
653 
654  if (!checkCOMisOpen()) return false;
655 
656  MRPT_LOG_DEBUG("[CHokuyoURG::switchLaserOn] Switching laser ON...");
657 
658  // Send command:
659  os::strcpy(cmd, 20, "BM\x0A");
660  toWrite = 3;
661 
662  m_stream->WriteBuffer(cmd, toWrite);
663 
664  // Receive response:
665  if (!receiveResponse(
666  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
667  {
668  std::cerr << "Error waiting for response\n";
669  return false;
670  }
671 
672  // DECODE:
673  if (rcv_status0 != '0')
674  {
675  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
676  return false;
677  }
678 
679  MRPT_LOG_DEBUG("OK\n");
680 
681  return true;
682 }
683 
684 /*-------------------------------------------------------------
685  switchLaserOff
686 -------------------------------------------------------------*/
688 {
689  char cmd[20];
690  char rcv_status0, rcv_status1;
691  char rcv_data[100];
692  size_t toWrite;
693  int rcv_dataLength;
694 
695  if (!checkCOMisOpen()) return false;
696 
697  MRPT_LOG_DEBUG("[CHokuyoURG::switchLaserOff] Switching laser OFF...");
698 
699  // Send command:
700  os::strcpy(cmd, 20, "QT\x0A");
701  toWrite = 3;
702 
703  m_stream->WriteBuffer(cmd, toWrite);
704 
705  // Receive response:
706  if (!receiveResponse(
707  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
708  {
709  std::cerr << "Error waiting for response\n";
710  return false;
711  }
712 
713  // DECODE:
714  if (rcv_status0 != '0')
715  {
716  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
717  return false;
718  }
719 
720  MRPT_LOG_DEBUG("OK\n");
721  return true;
722 }
723 
724 /*-------------------------------------------------------------
725  setMotorSpeed
726 -------------------------------------------------------------*/
727 bool CHokuyoURG::setMotorSpeed(int motoSpeed_rpm)
728 {
729  char cmd[20];
730  char rcv_status0, rcv_status1;
731  char rcv_data[100];
732  size_t toWrite;
733  int rcv_dataLength;
734 
735  if (!checkCOMisOpen()) return false;
736 
738  "[CHokuyoURG::setMotorSpeed] Setting to %i rpm...", motoSpeed_rpm);
739 
740  // Send command:
741  int motorSpeedCode = (600 - motoSpeed_rpm) / 6;
742  if (motorSpeedCode < 0 || motorSpeedCode > 10)
743  {
744  printf("ERROR! Motorspeed must be in the range 540-600 rpm\n");
745  return false;
746  }
747 
748  os::sprintf(cmd, 20, "CR%02i\x0A", motorSpeedCode);
749  toWrite = 5;
750 
751  m_stream->WriteBuffer(cmd, toWrite);
752 
753  // Receive response:
754  if (!receiveResponse(
755  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
756  {
757  std::cerr << "Error waiting for response\n";
758  return false;
759  }
760 
761  // DECODE:
762  if (rcv_status0 != '0')
763  {
764  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
765  return false;
766  }
767 
768  MRPT_LOG_DEBUG("OK\n");
769  return true;
770 }
771 
772 /*-------------------------------------------------------------
773  setHighSensitivityMode
774 -------------------------------------------------------------*/
776 {
777  char cmd[20];
778  char rcv_status0, rcv_status1;
779  char rcv_data[100];
780  size_t toWrite;
781  int rcv_dataLength;
782 
783  if (!checkCOMisOpen()) return false;
784 
786  "[CHokuyoURG::setHighSensitivityMode] Setting HS mode to: %s...",
787  enabled ? "true" : "false");
788 
789  // Send command:
790  os::sprintf(cmd, 20, "HS%i\x0A", enabled ? 1 : 0);
791  toWrite = 4;
792 
793  m_stream->WriteBuffer(cmd, toWrite);
794 
795  // Receive response:
796  if (!receiveResponse(
797  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
798  {
799  std::cerr << "Error waiting for response\n";
800  return false;
801  }
802 
803  // DECODE:
804  if (rcv_status0 != '0')
805  {
806  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
807  return false;
808  }
809 
810  MRPT_LOG_DEBUG("OK\n");
811  return true;
812 }
813 
814 /*-------------------------------------------------------------
815  setIntensityMode
816 -------------------------------------------------------------*/
818 {
819  m_intensity = enabled;
820  return true;
821 }
822 
823 /*-------------------------------------------------------------
824  displayVersionInfo
825 -------------------------------------------------------------*/
827 {
828  char cmd[20];
829  char rcv_status0, rcv_status1;
830  char rcv_data[2000];
831  size_t toWrite;
832  int rcv_dataLength;
833 
834  if (!checkCOMisOpen()) return false;
835 
836  MRPT_LOG_DEBUG("[CHokuyoURG::displayVersionInfo] Asking info...");
837 
838  // Send command:
839  os::sprintf(cmd, 20, "VV\x0A");
840  toWrite = 3;
841 
842  m_stream->WriteBuffer(cmd, toWrite);
843 
844  // Receive response:
845  if (!receiveResponse(
846  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
847  {
848  std::cerr << "Error waiting for response\n";
849  return false;
850  }
851 
852  // DECODE:
853  if (rcv_status0 != '0')
854  {
855  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
856  return false;
857  }
858 
859  MRPT_LOG_DEBUG("OK\n");
860 
861  // PRINT:
862  for (int i = 0; i < rcv_dataLength; i++)
863  {
864  if (rcv_data[i] == ';') rcv_data[i] = '\n';
865  }
866  rcv_data[rcv_dataLength] = 0;
867 
869  "\n------------- HOKUYO Scanner: Version Information ------\n"
870  "%s\n"
871  "-------------------------------------------------------\n\n",
872  rcv_data);
873  return true;
874 }
875 
876 /*-------------------------------------------------------------
877  displaySensorInfo
878 -------------------------------------------------------------*/
880 {
881  char cmd[20];
882  char rcv_status0, rcv_status1;
883  char rcv_data[1000];
884  size_t toWrite;
885  int rcv_dataLength;
886 
887  if (!checkCOMisOpen()) return false;
888 
889  MRPT_LOG_DEBUG("[CHokuyoURG::displaySensorInfo] Asking for info...");
890 
891  // Send command:
892  os::sprintf(cmd, 20, "PP\x0A");
893  toWrite = 3;
894 
895  m_stream->WriteBuffer(cmd, toWrite);
896 
897  // Receive response:
898  if (!receiveResponse(
899  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
900  {
901  std::cerr << "Error waiting for response\n";
902  return false;
903  }
904 
905  // DECODE:
906  if (rcv_status0 != '0')
907  {
908  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
909  return false;
910  }
911 
912  MRPT_LOG_DEBUG("OK\n");
913 
914  // PRINT:
915  for (int i = 0; i < rcv_dataLength; i++)
916  {
917  if (rcv_data[i] == ';') rcv_data[i] = '\n';
918  }
919  rcv_data[rcv_dataLength] = 0;
920 
922  "\n------------- HOKUYO Scanner: Product Information ------\n"
923  "%s\n"
924  "-------------------------------------------------------\n\n",
925  rcv_data);
926 
927  // Parse the data:
928  if (out_data)
929  {
930  const char* ptr;
931 
932  if (nullptr != (ptr = strstr(rcv_data, "DMAX:")))
933  out_data->d_max = 0.001 * atoi(ptr + 5);
934  else
935  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
936  "DMAX"
937  << endl;
938 
939  if (nullptr != (ptr = strstr(rcv_data, "DMIN:")))
940  out_data->d_min = 0.001 * atoi(ptr + 5);
941  else
942  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
943  "DMIN"
944  << endl;
945 
946  if (nullptr != (ptr = strstr(rcv_data, "ARES:")))
947  out_data->scans_per_360deg = atoi(ptr + 5);
948  else
949  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
950  "ARES"
951  << endl;
952 
953  if (nullptr != (ptr = strstr(rcv_data, "SCAN:")))
954  out_data->motor_speed_rpm = atoi(ptr + 5);
955  else
956  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
957  "SCAN"
958  << endl;
959 
960  if (nullptr != (ptr = strstr(rcv_data, "AMIN:")))
961  out_data->scan_first = atoi(ptr + 5);
962  else
963  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
964  "AMIN"
965  << endl;
966  if (nullptr != (ptr = strstr(rcv_data, "AMAX:")))
967  out_data->scan_last = atoi(ptr + 5);
968  else
969  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
970  "AMAX"
971  << endl;
972  if (nullptr != (ptr = strstr(rcv_data, "AFRT:")))
973  out_data->scan_front = atoi(ptr + 5);
974  else
975  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
976  "AFRT"
977  << endl;
978 
979  if (nullptr != (ptr = strstr(rcv_data, "MODL:")))
980  {
981  char aux[30];
982  memcpy(aux, ptr + 5, 8);
983  aux[8] = '\0';
984  out_data->model = aux;
985  }
986  else
987  cerr << "[CHokuyoURG::displayVersionInfo] Parse error: didn't find "
988  "AFRT"
989  << endl;
990  }
991 
992  return true;
993 }
994 
995 /*-------------------------------------------------------------
996  startScanningMode
997 -------------------------------------------------------------*/
999 {
1000  char cmd[100];
1001  char rcv_status0, rcv_status1;
1002  char rcv_data[6000];
1003  size_t toWrite;
1004  int rcv_dataLength;
1005 
1006  if (!checkCOMisOpen()) return false;
1007 
1008  MRPT_LOG_DEBUG("[CHokuyoURG::startScanningMode] Starting scanning mode...");
1009 
1010  // Send command:
1011  if (m_intensity)
1012  os::sprintf(cmd, 50, "ME%04u%04u01000\x0A", m_firstRange, m_lastRange);
1013  else
1014  os::sprintf(cmd, 50, "MD%04u%04u01000\x0A", m_firstRange, m_lastRange);
1015  toWrite = 16;
1016 
1017  m_lastSentMeasCmd = cmd;
1018 
1019  m_stream->WriteBuffer(cmd, toWrite);
1020 
1021  // Receive response:
1022  if (!receiveResponse(
1023  cmd, rcv_status0, rcv_status1, rcv_data, rcv_dataLength))
1024  {
1025  std::cerr << "Error waiting for response\n";
1026  return false;
1027  }
1028 
1029  // DECODE:
1030  if (rcv_status0 != '0')
1031  {
1032  std::cerr << "Error in LIDAR status: " << (int)rcv_status0 << "\n";
1033  return false;
1034  }
1035 
1036  MRPT_LOG_DEBUG("OK\n");
1037  return true;
1038 }
1039 
1040 /*-------------------------------------------------------------
1041  checkCOMisOpen
1042 -------------------------------------------------------------*/
1044 {
1045  MRPT_START
1046 
1047  if (m_stream)
1048  {
1049  // Socket or USB connection?
1050  if (!m_ip_dir.empty() && m_port_dir)
1051  {
1052  // Has the port been disconected (USB serial ports)??
1053  CClientTCPSocket* COM = dynamic_cast<CClientTCPSocket*>(m_stream);
1054 
1055  if (COM != nullptr)
1056  {
1057  if (COM->isConnected()) return true;
1058 
1059  // It has been disconnected... try to reconnect:
1060  cerr << "[CHokuyoURG] Socket connection lost! trying to "
1061  "reconnect..."
1062  << endl;
1063 
1064  try
1065  {
1066  COM->connect(m_ip_dir, m_port_dir);
1067  // OK, reconfigure the laser:
1068  turnOn();
1069  return true;
1070  }
1071  catch (...)
1072  {
1073  // Not yet..
1074  return false;
1075  }
1076  }
1077  else
1078  {
1079  return true; // Assume OK
1080  }
1081  }
1082  else
1083  {
1084  // Has the port been disconected (USB serial ports)??
1085  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
1086  if (COM != nullptr)
1087  {
1088  if (COM->isOpen()) return true;
1089 
1090  // It has been disconnected... try to reconnect:
1091  cerr << "[CHokuyoURG] Serial port connection lost! Trying to "
1092  "reconnect..."
1093  << endl;
1094 
1095  try
1096  {
1097  COM->open();
1098  // OK, reconfigure the laser:
1099  turnOn();
1100  return true;
1101  }
1102  catch (...)
1103  {
1104  // Not yet..
1105  return false;
1106  }
1107  }
1108  else
1109  {
1110  return true; // Assume OK
1111  }
1112  }
1113  }
1114  else
1115  {
1116  if (m_com_port.empty() && m_ip_dir.empty() && !m_port_dir)
1117  {
1119  "No stream bound to the laser nor COM serial port or ip and "
1120  "port provided in 'm_com_port','m_ip_dir' and 'm_port_dir'");
1121  }
1122 
1123  if (!m_ip_dir.empty())
1124  {
1125  // Try to open the serial port:
1126  CClientTCPSocket* theCOM = new CClientTCPSocket();
1127 
1128  printf(
1129  "[CHokuyoURG] Connecting to %s:%u...\n", m_ip_dir.c_str(),
1130  m_port_dir);
1131  theCOM->connect(m_ip_dir, m_port_dir);
1132 
1133  if (!theCOM->isConnected())
1134  {
1135  cerr << "[CHokuyoURG] Cannot connect with the server '"
1136  << m_com_port << "'" << endl;
1137  delete theCOM;
1138  return false;
1139  }
1140 
1141  // Bind:
1142  bindIO(theCOM);
1143 
1144  m_I_am_owner_serial_port = true;
1145  }
1146 
1147  else
1148  {
1149  // Try to open the serial port:
1150  CSerialPort* theCOM = new CSerialPort(m_com_port, true);
1151 
1152  if (!theCOM->isOpen())
1153  {
1154  cerr << "[CHokuyoURG] Cannot open serial port '" << m_com_port
1155  << "'" << endl;
1156  delete theCOM;
1157  return false;
1158  }
1159 
1160  // Bind:
1161  bindIO(theCOM);
1162 
1163  m_I_am_owner_serial_port = true;
1164  }
1165 
1166  return true;
1167  }
1168  MRPT_END
1169 }
1170 
1171 /*-------------------------------------------------------------
1172  initialize
1173 -------------------------------------------------------------*/
1175 {
1176  if (!checkCOMisOpen()) return;
1177 
1178  if (!turnOn())
1179  {
1180  cerr << "[CHokuyoURG::initialize] Error initializing HOKUYO scanner"
1181  << endl;
1182  return;
1183  }
1184 }
1185 
1186 /*-------------------------------------------------------------
1187  purgeBuffers
1188 -------------------------------------------------------------*/
1190 {
1191  if (!checkCOMisOpen()) return;
1192 
1193  if (m_ip_dir.empty())
1194  {
1195  CSerialPort* COM = dynamic_cast<CSerialPort*>(m_stream);
1196  if (COM != nullptr)
1197  {
1198  COM->purgeBuffers();
1199  }
1200  }
1201  else // Socket connection
1202  {
1203  CClientTCPSocket* COM = dynamic_cast<CClientTCPSocket*>(m_stream);
1204 
1205  size_t to_read = COM->getReadPendingBytes();
1206 
1207  if (to_read)
1208  {
1209  void* buf = malloc(sizeof(uint8_t) * to_read);
1210 
1211  size_t nRead = m_stream->ReadBuffer(buf, to_read);
1212 
1213  if (nRead != to_read)
1215  "Error in purge buffers: read and expected number of bytes "
1216  "are different.");
1217 
1218  free(buf);
1219  }
1220  }
1221 }
uint64_t TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1...
Definition: datetime.h:32
size_t ReadBuffer(void *Buffer, size_t Count)
Reads a block of bytes from the stream into Buffer.
Definition: CStream.cpp:40
std::string m_com_port
If set to non-empty, the serial port will be attempted to be opened automatically when this class is ...
Definition: CHokuyoURG.h:249
uint32_t m_timeStartUI
Time of the first data packet, for synchronization purposes.
Definition: CHokuyoURG.h:264
virtual ~CHokuyoURG()
Destructor: turns the laser off.
Definition: CHokuyoURG.cpp:57
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.
int m_firstRange
The first and last ranges to consider from the scan.
Definition: CHokuyoURG.h:94
#define min(a, b)
std::vector< uint8_t > vector_byte
Definition: types_simple.h:27
A communications serial port built as an implementation of a utils::CStream.
Definition: CSerialPort.h:47
void connect(const std::string &remotePartAddress, unsigned short remotePartTCPPort, unsigned int timeout_ms=0)
Establishes a connection with a remote part.
utils::CStream * m_stream
The I/O channel (will be nullptr if not bound).
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
bool m_intensity
Get intensity from lidar scan (default: false)
Definition: CHokuyoURG.h:271
bool isConnected()
Returns true if this objects represents a successfully connected socket.
void setScanRange(const size_t i, const float val)
void loadConfig_sensorSpecific(const mrpt::utils::CConfigFileBase &configSource, const std::string &iniSection)
See the class documentation at the top for expected parameters.
Definition: CHokuyoURG.cpp:213
std::string m_sensorLabel
See CGenericSensor.
size_t available() const
The maximum number of elements that can be written ("push") without rising an overflow error...
#define THROW_EXCEPTION(msg)
#define MRPT_LOG_DEBUG_FMT(_FMT_STRING,...)
size_t size() const
Return the number of elements available for read ("pop") in the buffer (this is NOT the maximum size ...
void WriteBuffer(const void *Buffer, size_t Count)
Writes a block of bytes to the stream from Buffer.
Definition: CStream.cpp:64
bool assureBufferHasBytes(const size_t nDesiredBytes)
Assures a minimum number of bytes in the input buffer, reading from the serial port only if required...
Definition: CHokuyoURG.cpp:431
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.
void setScanHasIntensity(bool setHasIntensityFlag)
Marks this scan as having or not intensity data.
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
STL namespace.
#define M_PI
Definition: bits.h:92
void filterByExclusionAreas(mrpt::obs::CObservation2DRangeScan &obs) const
Mark as invalid those points which (x,y) coordinates fall within the exclusion polygons.
float stdError
The "sigma" error of the device in meters, used while inserting the scan in an occupancy grid...
void setConfig(int baudRate, int parity=0, int bits=8, int nStopBits=1, bool enableFlowControl=false)
Changes the configuration of the port.
void filterByExclusionAngles(mrpt::obs::CObservation2DRangeScan &obs) const
Mark as invalid those ranges in a set of forbiden angle ranges.
bool switchLaserOn()
Switchs the laser on.
Definition: CHokuyoURG.cpp:646
unsigned int m_port_dir
If set to non-empty and m_ip_dir too, the program will try to connect to a Hokuyo using Ethernet comm...
Definition: CHokuyoURG.h:256
This class allows loading and storing values and vectors of different types from a configuration text...
std::string m_lastSentMeasCmd
The last sent measurement command (MDXXX), including the last 0x0A.
Definition: CHokuyoURG.h:103
mrpt::gui::CDisplayWindow3D::Ptr m_win
Definition: CHokuyoURG.h:107
unsigned char uint8_t
Definition: rptypes.h:41
float maxRange
The maximum range allowed by the device, in meters (e.g.
const int MINIMUM_PACKETS_TO_SET_TIMESTAMP_REFERENCE
Definition: CHokuyoURG.cpp:29
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
#define MRPT_END
bool displaySensorInfo(CHokuyoURG::TSensorInfo *out_data=nullptr)
Ask to the device, and print to the debug stream, details about the sensor model. ...
Definition: CHokuyoURG.cpp:879
Used in CHokuyoURG::displayVersionInfo.
Definition: CHokuyoURG.h:78
void setScanIntensity(const size_t i, const int val)
bool setIntensityMode(bool enabled)
If true scans will capture intensity.
Definition: CHokuyoURG.cpp:817
bool displayVersionInfo()
Ask to the device, and print to the debug stream, details about the firmware version,serial number,...
Definition: CHokuyoURG.cpp:826
bool isOpen() const
Returns if port has been correctly open.
This namespace contains representation of robot actions and observations.
#define MRPT_LOG_DEBUG(_STRING)
int m_timeStartSynchDelay
Counter to discard to first few packets before setting the correspondence between device and computer...
Definition: CHokuyoURG.h:267
bool enableSCIP20()
Enables the SCIP2.0 protocol (this must be called at the very begining!).
Definition: CHokuyoURG.cpp:605
void purgeBuffers()
Purge tx and rx buffers.
void bindIO(mrpt::utils::CStream *streamIO)
Binds the object to a given I/O channel.
mrpt::system::TTimeStamp m_timeStartTT
Definition: CHokuyoURG.h:268
#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:
void setTimeouts(int ReadIntervalTimeout, int ReadTotalTimeoutMultiplier, int ReadTotalTimeoutConstant, int WriteTotalTimeoutMultiplier, int WriteTotalTimeoutConstant)
Changes the timeouts of the port, in milliseconds.
T pop()
Retrieve an element from the buffer.
bool switchLaserOff()
Switchs the laser off.
Definition: CHokuyoURG.cpp:687
int m_motorSpeed_rpm
The motor speed (default=600rpm)
Definition: CHokuyoURG.h:96
#define MRPT_START
std::string sensorLabel
An arbitrary label that can be used to identify the sensor.
Definition: CObservation.h:60
#define RAD2DEG
void purgeBuffers()
Empties the RX buffers of the serial port.
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:58
int scan_first
First, last, and front step of the scanner angular span.
Definition: CHokuyoURG.h:87
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
bool startScanningMode()
Start the scanning mode, using parameters stored in the object (loaded from the .ini file) After this...
Definition: CHokuyoURG.cpp:998
bool checkCOMisOpen()
Returns true if there is a valid stream bound to the laser scanner, otherwise it first try to open th...
void resizeScan(const size_t len)
Resizes all data vectors to allocate a given number of scan rays.
void setFromValues(const double x0, const double y0, const double z0, const double yaw=0, const double pitch=0, const double roll=0)
Set the pose from a 3D position (meters) and yaw/pitch/roll angles (radians) - This method recomputes...
Definition: CPose3D.cpp:248
A TCP socket that can be connected to a TCP server, implementing MRPT&#39;s CStream interface for passing...
bool turnOn()
Enables the scanning mode (which may depend on the specific laser device); this must be called before...
Definition: CHokuyoURG.cpp:269
void processPreview(const mrpt::obs::CObservation2DRangeScan &obs)
Must be called inside the capture method to allow optional GUI preview of scans.
bool setMotorSpeed(int motoSpeed_rpm)
Changes the motor speed in rpm&#39;s (default 600rpm)
Definition: CHokuyoURG.cpp:727
#define MRPT_LOG_INFO_FMT(_FMT_STRING,...)
double d_min
Min/Max ranges, in meters.
Definition: CHokuyoURG.h:83
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:15
This software driver implements the protocol SCIP-2.0 for interfacing HOKUYO URG/UTM/UXM/UST laser sc...
Definition: CHokuyoURG.h:73
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
#define ASSERT_(f)
size_t capacity() const
Return the maximum capacity of the buffer.
void initialize()
Turns the laser on.
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...
Definition: CHokuyoURG.cpp:74
bool setHighBaudrate()
Passes to 115200bps bitrate.
Definition: CHokuyoURG.cpp:390
poses::CPose3D m_sensorPose
The sensor 6D pose:
Definition: CHokuyoURG.h:98
TSensorInfo m_sensor_info
The information gathered when the laser is first open.
Definition: CHokuyoURG.h:259
mrpt::system::TTimeStamp secondsToTimestamp(const double nSeconds)
Transform a time interval (in seconds) into TTimeStamp (e.g.
Definition: datetime.cpp:223
bool m_highSensMode
High sensitivity [HS] mode (default: false)
Definition: CHokuyoURG.h:106
size_t getReadPendingBytes()
Return the number of bytes already in the receive queue (they can be read without waiting) ...
std::string model
The sensor model.
Definition: CHokuyoURG.h:81
Serial and networking devices and utilities.
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< float > > scan
The range values of the scan, in meters.
double m_reduced_fov
Used to reduce artificially the interval of scan ranges.
Definition: CHokuyoURG.h:244
char * strcpy(char *dest, size_t destSize, const char *source) noexcept
An OS-independent version of strcpy.
Definition: os.cpp:296
mrpt::utils::circular_buffer< uint8_t > m_rx_buffer
Auxiliary buffer for readings.
Definition: CHokuyoURG.h:100
int motor_speed_rpm
Standard motor speed, rpm.
Definition: CHokuyoURG.h:89
size_t readAsync(void *Buffer, const size_t Count, const int timeoutStart_ms=-1, const int timeoutBetween_ms=-1)
A method for reading from the socket with an optional timeout.
void push_many(T *array_elements, size_t count)
Insert an array of elements in the buffer.
unsigned __int32 uint32_t
Definition: rptypes.h:47
bool turnOff()
Disables the scanning mode (this can be used to turn the device in low energy mode, if available)
Definition: CHokuyoURG.cpp:379
#define ASSERTMSG_(f, __ERROR_MSG)
bool setHighSensitivityMode(bool enabled)
Changes the high sensitivity mode (HS) (default: false)
Definition: CHokuyoURG.cpp:775
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
int sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
Definition: os.cpp:188
bool receiveResponse(const char *sentCmd_forEchoVerification, char &rcv_status0, char &rcv_status1, char *rcv_data, int &rcv_dataLength)
Waits for a response from the device.
Definition: CHokuyoURG.cpp:474
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
std::string m_ip_dir
If set to non-empty and m_port_dir too, the program will try to connect to a Hokuyo using Ethernet co...
Definition: CHokuyoURG.h:253
void setScanRangeValidity(const size_t i, const bool val)
int scans_per_360deg
Number of measuremens per 360 degrees.
Definition: CHokuyoURG.h:85



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