23 #define RET_ERROR(msg) \ 25 cout << "[" << __CURRENT_FUNCTION_NAME__ << "] " << msg << endl; \ 37 int CSickLaserSerial::CRC16_GEN_POL = 0x8005;
42 CSickLaserSerial::CSickLaserSerial()
47 m_mySerialPort(nullptr),
48 m_com_baudRate(38400),
51 m_skip_laser_config(false)
87 bool& outThereIsObservation,
90 outThereIsObservation =
false;
91 hardwareError =
false;
100 unsigned char LMS_stat;
122 outObservation.
maxRange = is_mm_mode ? 32.7 : 81.0;
128 for (
size_t i = 0; i < ranges.size(); i++)
132 i, (outObservation.
scan[i] <= outObservation.
maxRange));
141 outThereIsObservation =
true;
152 configSource.
read_float(iniSection,
"pose_x", 0),
153 configSource.
read_float(iniSection,
"pose_y", 0),
154 configSource.
read_float(iniSection,
"pose_z", 0),
161 #ifdef MRPT_OS_WINDOWS 198 if (err_msg) *err_msg =
"";
213 throw std::logic_error(
214 "ERROR: No serial port attached with bindIO, neither it " 215 "set with 'setSerialPort'");
220 bool just_open =
false;
239 if (!just_open)
return true;
251 for (
int nTry = 0; nTry < 4; nTry++)
254 if (!
res)
return false;
256 for (
int nTry = 0; nTry < 4; nTry++)
267 catch (std::exception& e)
269 std::string s =
"[CSickLaserSerial] Error trying to open SICK at port ";
271 if (err_msg) *err_msg =
s;
281 vector<float>& out_ranges_meters,
unsigned char& LMS_status,
285 ASSERTMSG_(COM !=
nullptr,
"No I/O channel bound to this object");
287 size_t nRead, nBytesToRead;
288 size_t nFrameBytes = 0;
290 unsigned char buf[2000];
291 buf[2] = buf[3] = buf[4] = 0;
293 while (nFrameBytes < (lengthField = (6 + (buf[2] | (buf[3] << 8)))))
295 if (lengthField > 800)
305 nBytesToRead = (lengthField)-nFrameBytes;
309 nRead = COM->
Read(buf + nFrameBytes, nBytesToRead);
311 catch (std::exception& e)
315 "[CSickLaserSerial::waitContinuousSampleFrame] Disconnecting " 316 "due to comms error: %s\n",
322 if (!nRead && !nFrameBytes)
return false;
324 if (nRead < nBytesToRead) std::this_thread::sleep_for(1ms);
328 if (nFrameBytes > 1 || (!nFrameBytes && buf[0] == 0x02) ||
329 (nFrameBytes == 1 && buf[1] == 0x80))
331 nFrameBytes += nRead;
350 if (buf[4] != 0xB0)
return false;
353 int info = buf[5] | (buf[6] << 8);
354 int n_points = info & 0x01FF;
355 is_mm_mode = 0 != ((info & 0xC000) >> 14);
357 out_ranges_meters.resize(n_points);
360 short mask = is_mm_mode ? 0x7FFF : 0x1FFF;
361 float meters_scale = is_mm_mode ? 0.001f : 0.01f;
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;
368 LMS_status = buf[lengthField - 3];
373 uint16_t CRC_packet = buf[lengthField - 2] | (buf[lengthField - 1] << 8);
374 if (CRC_packet != CRC)
377 "[CSickLaserSerial::waitContinuousSampleFrame] bad CRC " 378 "len=%u nptns=%u: %i != %i",
379 unsigned(lengthField),
unsigned(n_points), CRC_packet, CRC)
397 cerr << err_str << endl;
398 throw std::logic_error(err_str);
413 if (COM ==
nullptr)
return true;
415 int detected_rate = 0;
420 int rates[] = {0, 9600, 38400, 500000};
429 !detected_rate && i <
sizeof(rates) /
sizeof(rates[0]); i++)
436 std::this_thread::sleep_for(100ms);
439 for (
int nTry = 0; nTry < 4 && !detected_rate; nTry++)
445 detected_rate = rates[i];
448 std::this_thread::sleep_for(20ms);
455 std::this_thread::sleep_for(5000ms);
474 std::this_thread::sleep_for(500ms);
542 if (COM->
Read(&
b, 1))
544 if (
b == 0x06)
return true;
546 }
while (tictac.
Tac() < timeout_ms * 1e-3);
563 unsigned int nBytes = 0;
567 const double maxTime = timeout * 1e-3;
573 if (COM->
Read(&
b, 1))
576 if (nBytes > 1 || (!nBytes &&
b == 0x02) ||
577 (nBytes == 1 &&
b == 0x80))
584 if (tictac.
Tac() >= maxTime)
return false;
590 if (4U + lengthField + 2U != nBytes)
593 "[CSickLaserSerial::LMS_waitIncomingFrame] Error: expected %u " 594 "bytes, received %u\n",
595 4U + lengthField + 2U, nBytes);
604 if (CRC_packet != CRC)
607 "[CSickLaserSerial::LMS_waitIncomingFrame] Error in CRC: rx: " 608 "0x%04X, computed: 0x%04X\n",
615 for (
unsigned int i=0;i<nBytes;i++)
647 RET_ERROR(
"Error waiting ACK to installation mode");
649 RET_ERROR(
"Error in response to installation mode");
654 RET_ERROR(
"Wrong response to installation mode");
663 RET_ERROR(
"No ACK to 0x74 (req. config)");
665 RET_ERROR(
"No answer to 0x74 (req. config)");
669 RET_ERROR(
"No expected 0xF4 in response to 0x74 (req. config)");
693 RET_ERROR(
"No ACK for config command (0x77)");
695 RET_ERROR(
"No answer for config command (0x77)");
699 RET_ERROR(
"Wrong answer for config command (0x77)");
708 RET_ERROR(
"No ACK for set monitoring mode");
710 RET_ERROR(
"No answer for set monitoring mode");
714 RET_ERROR(
"Wrong answer for set monitoring mode");
742 RET_ERROR(
"Error waiting ack for change angle/resolution");
744 RET_ERROR(
"Error waiting answer for change angle/resolution");
751 RET_ERROR(
"Error waiting ack for start scanning");
753 RET_ERROR(
"Error waiting answer for start scanning");
777 ASSERT_(
sizeof(cmd_full) > cmd_len + 4U + 2U);
785 cmd_full[2] = cmd_len & 0xFF;
786 cmd_full[3] = cmd_len >> 8;
788 memcpy(cmd_full + 4, cmd, cmd_len);
792 cmd_full[4 + cmd_len + 0] =
crc & 0xFF;
793 cmd_full[4 + cmd_len + 1] =
crc >> 8;
795 const size_t toWrite = 4 + cmd_len + 2;
799 for (
unsigned int i=0;i<toWrite;i++)
800 printf(
"%02X ",cmd_full[i]);
804 const int NTRIES = 3;
806 for (
int k = 0; k < NTRIES; k++)
808 if (toWrite != COM->
Write(cmd_full, toWrite))
810 cout <<
"[CSickLaserSerial::SendCommandToSICK] Error writing data " 815 std::this_thread::sleep_for(15ms);
817 std::this_thread::sleep_for(10ms);
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).
size_t Write(const void *Buffer, size_t Count)
Implements the virtual method responsible for writing to the stream.
bool LMS_startContinuousMode()
int m_scans_FOV
100 or 180 deg
bool LMS_sendMeasuringMode_cm_mm()
Returns false on error.
bool read_bool(const std::string §ion, 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
A communications serial port built as an implementation of a utils::CStream.
utils::CStream * m_stream
The I/O channel (will be nullptr if not bound).
float read_float(const std::string §ion, 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.
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
Contains classes for various device interfaces.
std::string read_string(const std::string §ion, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
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,...)
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.
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.
This class allows loading and storing values and vectors of different types from a configuration text...
uint8_t m_received_frame_buffer[2000]
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 §ion, 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 ...
bool m_skip_laser_config
If true, doesn'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.
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.
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.
unsigned int m_nTries_current
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.
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
#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...
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.
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.
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).
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.
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
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)
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 LMS_endContinuousMode()
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".
void setScanRangeValidity(const size_t i, const bool val)