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



Page generated by Doxygen 1.8.14 for MRPT 1.5.5 Git: e06b63dbf Fri Dec 1 14:41:11 2017 +0100 at lun oct 28 01:31:35 CET 2019