23 #define RET_ERROR(msg)                                                   \    25         cout << "[" << __CURRENT_FUNCTION_NAME__ << "] " << msg << endl; \    38 int CSickLaserSerial::CRC16_GEN_POL = 0x8005;
    43 CSickLaserSerial::CSickLaserSerial() : m_com_port()
    74     bool& outThereIsObservation,
    77     outThereIsObservation = 
false;
    78     hardwareError = 
false;
    87     unsigned char LMS_stat;
   116     outObservation.
maxRange = is_mm_mode ? 32.7 : 81.0;
   122     for (
size_t i = 0; i < ranges.size(); i++)
   135     outThereIsObservation = 
true;
   144     const std::string& iniSection)
   147         configSource.
read_float(iniSection, 
"pose_x", 0),
   148         configSource.
read_float(iniSection, 
"pose_y", 0),
   149         configSource.
read_float(iniSection, 
"pose_z", 0),
   193     if (err_msg) *err_msg = 
"";
   208                 throw std::logic_error(
   209                     "ERROR: No serial port attached with bindIO, neither it "   210                     "set with 'setSerialPort'");
   215         bool just_open = 
false;
   226                 COM->setConfig(9600);
   227                 COM->setTimeouts(100, 0, 10, 0, 50);
   234         if (!just_open) 
return true;
   246             for (
int nTry = 0; nTry < 4; nTry++)
   249             if (!res) 
return false;
   251             for (
int nTry = 0; nTry < 4; nTry++)
   262     catch (
const std::exception& e)
   264         std::string s = 
"[CSickLaserSerial] Error trying to open SICK at port ";
   266         if (err_msg) *err_msg = s;
   276     vector<float>& out_ranges_meters, 
unsigned char& LMS_status,
   280     ASSERTMSG_(COM != 
nullptr, 
"No I/O channel bound to this object");
   282     size_t nRead, nBytesToRead;
   283     size_t nFrameBytes = 0;
   285     unsigned char buf[2000];
   286     buf[2] = buf[3] = buf[4] = 0;
   288     while (nFrameBytes < (lengthField = (6 + (buf[2] | (buf[3] << 8)))))
   290         if (lengthField > 800)
   300             nBytesToRead = (lengthField)-nFrameBytes;
   304             nRead = COM->Read(buf + nFrameBytes, nBytesToRead);
   306         catch (
const std::exception& e)
   310                 "[CSickLaserSerial::waitContinuousSampleFrame] Disconnecting "   311                 "due to comms error: %s\n",
   317         if (!nRead && !nFrameBytes) 
return false;
   319         if (nRead < nBytesToRead) std::this_thread::sleep_for(1ms);
   323         if (nFrameBytes > 1 || (!nFrameBytes && buf[0] == 0x02) ||
   324             (nFrameBytes == 1 && buf[1] == 0x80))
   326             nFrameBytes += nRead;
   345     if (buf[4] != 0xB0) 
return false;
   348     int info = buf[5] | (buf[6] << 8);  
   349     int n_points = info & 0x01FF;
   350     is_mm_mode = 0 != ((info & 0xC000) >> 14);  
   352     out_ranges_meters.resize(n_points);
   355     short mask = is_mm_mode ? 0x7FFF : 0x1FFF;
   356     float meters_scale = is_mm_mode ? 0.001f : 0.01f;
   358     for (
int i = 0; i < n_points; i++)
   359         out_ranges_meters[i] =
   360             ((buf[7 + i * 2] | (buf[8 + i * 2] << 8)) & mask) * meters_scale;
   363     LMS_status = buf[lengthField - 3];
   368     uint16_t CRC_packet = buf[lengthField - 2] | (buf[lengthField - 1] << 8);
   369     if (CRC_packet != CRC)
   372                     "[CSickLaserSerial::waitContinuousSampleFrame] bad CRC "   373                     "len=%u nptns=%u: %i != %i",
   374                     unsigned(lengthField), 
unsigned(n_points), CRC_packet, CRC)
   392         cerr << err_str << endl;
   393         throw std::logic_error(err_str);
   408     if (COM == 
nullptr) 
return true;
   410     int detected_rate = 0;
   415         int rates[] = {0, 9600, 38400, 500000};
   424              !detected_rate && i < 
sizeof(rates) / 
sizeof(rates[0]); i++)
   428             COM->setConfig(rates[i]);
   431                     "[CSickLaserSerial] Testing if the scanner is "   432                     "set to %i bauds...\n",
   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);
   488         printf(
"[CSickLaserSerial::LMS_setupBaudrate] rate=%i\n", baud);
   510     uint16_t cmd_len = 2;
   526     uint16_t cmd_len = 1;
   544         if (COM->Read(&b, 1))
   546             if (b == 0x06) 
return true;
   548     } 
while (tictac.
Tac() < timeout_ms * 1e-3);
   565     unsigned int nBytes = 0;
   569     const double maxTime = timeout * 1e-3;
   575         if (COM->Read(&b, 1))
   578             if (nBytes > 1 || (!nBytes && b == 0x02) ||
   579                 (nBytes == 1 && b == 0x80))
   586                     printf(
"[CSickLaserSerial::Receive] RX: %02X\n", b);
   590         if (tictac.
Tac() >= maxTime) 
return false;  
   593     const uint16_t lengthField =
   596     if (4U + lengthField + 2U != nBytes)
   599             "[CSickLaserSerial::LMS_waitIncomingFrame] Error: expected %u "   600             "bytes, received %u\n",
   601             4U + lengthField + 2U, nBytes);
   610     if (CRC_packet != CRC)
   613             "[CSickLaserSerial::LMS_waitIncomingFrame] Error in CRC: rx: "   614             "0x%04X, computed: 0x%04X\n",
   621     for (
unsigned int i=0;i<nBytes;i++)
   651     uint16_t cmd_len = 10;
   653         RET_ERROR(
"Error waiting ACK to installation mode");
   655         RET_ERROR(
"Error in response to installation mode");
   660         RET_ERROR(
"Wrong response to installation mode");
   669         RET_ERROR(
"No ACK to 0x74 (req. config)");
   671         RET_ERROR(
"No answer to 0x74 (req. config)");
   675         RET_ERROR(
"No expected 0xF4 in response to 0x74 (req. config)");
   699         RET_ERROR(
"No ACK for config command (0x77)");
   701         RET_ERROR(
"No answer for config command (0x77)");
   705         RET_ERROR(
"Wrong answer for config command (0x77)");
   714         RET_ERROR(
"No ACK for set monitoring mode");
   716         RET_ERROR(
"No answer for set monitoring mode");
   720         RET_ERROR(
"Wrong answer for set monitoring mode");
   746     uint16_t cmd_len = 5;
   748         RET_ERROR(
"Error waiting ack for change angle/resolution");
   750         RET_ERROR(
"Error waiting answer for change angle/resolution");
   757         RET_ERROR(
"Error waiting ack for start scanning");
   759         RET_ERROR(
"Error waiting answer for start scanning");
   774     uint16_t cmd_len = 2;
   780     const uint8_t* cmd, 
const uint16_t cmd_len)
   782     uint8_t cmd_full[1024];
   783     ASSERT_(
sizeof(cmd_full) > cmd_len + 4U + 2U);
   791     cmd_full[2] = cmd_len & 0xFF;
   792     cmd_full[3] = cmd_len >> 8;
   794     memcpy(cmd_full + 4, cmd, cmd_len);
   798     cmd_full[4 + cmd_len + 0] = 
crc & 0xFF;
   799     cmd_full[4 + cmd_len + 1] = 
crc >> 8;
   801     const size_t toWrite = 4 + cmd_len + 2;
   805         printf(
"[CSickLaserSerial::SendCommandToSICK] TX: ");
   806         for (
unsigned int i = 0; i < toWrite; i++) printf(
"%02X ", cmd_full[i]);
   810     const int NTRIES = 3;
   812     for (
int k = 0; k < NTRIES; k++)
   814         if (toWrite != COM->Write(cmd_full, toWrite))
   816             cout << 
"[CSickLaserSerial::SendCommandToSICK] Error writing data "   821         std::this_thread::sleep_for(15ms);
   823         std::this_thread::sleep_for(10ms);
 std::shared_ptr< mrpt::comms::CSerialPort > m_mySerialPort
Will be !=nullptr only if I created it, so I must destroy it at the end. 
 
double Tac() noexcept
Stops the stopwatch. 
 
bool LMS_startContinuousMode()
 
int m_scans_FOV
100 or 180 deg 
 
bool LMS_sendMeasuringMode_cm_mm()
Returns false on error. 
 
std::string read_string(const std::string §ion, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
 
#define MRPT_LOG_ERROR_FMT(_FMT_STRING,...)
 
A communications serial port built as an implementation of a utils::CStream. 
 
void initialize() override
Set-up communication with the laser. 
 
#define THROW_EXCEPTION(msg)
 
std::string std::string format(std::string_view fmt, ARGS &&... args)
 
void internal_notifyGoodScanNow()
Must be called from doProcessSimple() implementations. 
 
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. 
 
A high-performance stopwatch, with typical resolution of nanoseconds. 
 
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime. 
 
Contains classes for various device interfaces. 
 
void loadConfig_sensorSpecific(const mrpt::config::CConfigFileBase &configSource, const std::string &iniSection) override
See the class documentation at the top for expected parameters. 
 
float read_float(const std::string §ion, const std::string &name, float 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. 
 
float stdError
The "sigma" error of the device in meters, used while inserting the scan in an occupancy grid...
 
void filterByExclusionAngles(mrpt::obs::CObservation2DRangeScan &obs) const
Mark as invalid those ranges in a set of forbiden angle ranges. 
 
bool turnOn() override
Enables the scanning mode (in this class this has no effect). 
 
bool LMS_setupSerialComms()
Assures laser is connected and operating at 38400, in its case returns true. 
 
int read_int(const std::string §ion, const std::string &name, int defaultValue, bool failIfNotFound=false) const
 
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. 
 
#define ASSERT_(f)
Defines an assertion mechanism. 
 
std::string m_com_port
If set to non-empty, the serial port will be attempted to be opened automatically when this class is ...
 
This class allows loading and storing values and vectors of different types from a configuration text...
 
This base provides a set of functions for maths stuff. 
 
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)
 
constexpr double DEG2RAD(const double x)
Degrees to radians. 
 
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). 
 
This namespace contains representation of robot actions and observations. 
 
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. 
 
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism. 
 
mrpt::math::TPose3D m_sensorPose
The sensor 6D pose: 
 
#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...
 
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...
 
std::shared_ptr< mrpt::io::CStream > m_stream
The I/O channel (will be nullptr if not bound). 
 
A class used to store a 3D pose (a 3D translation + a rotation in 3D). 
 
bool internal_notifyNoScanReceived()
Must be called from doProcessSimple() implementations. 
 
#define MRPT_LOG_ERROR(_STRING)
 
void resizeScan(const size_t len)
Resizes all data vectors to allocate a given number of scan rays. 
 
bool read_bool(const std::string §ion, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
 
This "software driver" implements the communication protocol for interfacing a SICK LMS 2XX laser sca...
 
const float & getScanRange(const size_t i) const
The range values of the scan, in meters. 
 
bool turnOff() override
Disables the scanning mode (in this class this has no effect). 
 
void loadCommonParams(const mrpt::config::CConfigFileBase &configSource, const std::string &iniSection)
Should be call by derived classes at "loadConfig" (loads exclusion areas AND exclusion angles)...
 
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates). 
 
void processPreview(const mrpt::obs::CObservation2DRangeScan &obs)
Must be called inside the capture method to allow optional GUI preview of scans. 
 
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. 
 
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. 
 
Serial and networking devices and utilities. 
 
void Tic() noexcept
Starts the stopwatch. 
 
void doProcessSimple(bool &outThereIsObservation, mrpt::obs::CObservation2DRangeScan &outObservation, bool &hardwareError) override
Specific laser scanner "software drivers" must process here new data from the I/O stream...
 
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. 
 
~CSickLaserSerial() override
Destructor. 
 
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)