Main MRPT website > C++ reference for MRPT 1.9.9
CLMS100eth.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 
14 
15 #include <iostream>
16 #include <sstream>
17 #include <string.h>
18 
19 #define APPERTURE 4.712385 // in radian <=> 270°
20 
21 using namespace mrpt;
22 using namespace mrpt::system;
23 using namespace mrpt::utils;
24 using namespace mrpt::hwdrivers;
25 using namespace mrpt::poses;
26 using namespace mrpt::obs;
27 using namespace std;
28 
30 
31 CLMS100Eth::CLMS100Eth(string _ip, unsigned int _port)
32  : m_ip(_ip),
33  m_port(_port),
34  m_client(),
35  m_turnedOn(false),
36  m_cmd(),
37  m_connected(false),
38  m_sensorPose(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
39  m_maxRange(20.0),
40  m_beamApperture(.25 * M_PI / 180.0)
41 {
42  setVerbosityLevel(mrpt::utils::LVL_DEBUG);
43 }
44 
45 CLMS100Eth::~CLMS100Eth()
46 {
47  if (m_connected) m_client.close();
48  // delete m_client;
49  // delete m_sensorPose;
50 }
51 
52 void CLMS100Eth::initialize()
53 {
54  if (!checkIsConnected())
55  {
57  "Can't connect to LMS100 Ethernet Sensor check your configuration "
58  "file.");
59  }
60  turnOn();
61 }
62 
63 void CLMS100Eth::loadConfig_sensorSpecific(
64  const mrpt::utils::CConfigFileBase& configSource,
65  const std::string& iniSection)
66 {
67  C2DRangeFinderAbstract::loadCommonParams(configSource, iniSection);
68  float pose_x, pose_y, pose_z, pose_yaw, pose_pitch, pose_roll;
69 
70  pose_x = configSource.read_float(iniSection, "pose_x", 0, false);
71  pose_y = configSource.read_float(iniSection, "pose_y", 0, false);
72  pose_z = configSource.read_float(iniSection, "pose_z", 0, false);
73  pose_yaw = configSource.read_float(iniSection, "pose_yaw", 0, false);
74  pose_pitch = configSource.read_float(iniSection, "pose_pitch", 0, false);
75  pose_roll = configSource.read_float(iniSection, "pose_roll", 0, false);
76  m_ip = configSource.read_string(
77  iniSection, "ip_address", "192.168.0.1", false);
78  m_port = configSource.read_int(iniSection, "TCP_port", 2111, false);
79  m_process_rate =
80  configSource.read_int(iniSection, string("process_rate"), 10, false);
81  m_sensorLabel =
82  configSource.read_string(iniSection, "sensorLabel", "SICK", false);
83  m_sensorPose = CPose3D(
84  pose_x, pose_y, pose_z, DEG2RAD(pose_yaw), DEG2RAD(pose_pitch),
85  DEG2RAD(pose_roll));
86 }
87 
88 bool CLMS100Eth::checkIsConnected(void)
89 {
90  if (m_connected)
91  return true;
92  else
93  {
94  try
95  {
96  m_client.connect(m_ip, m_port);
97  }
98  catch (std::exception& e)
99  {
101  "[CLMS100ETH] ERROR TRYING TO OPEN Ethernet DEVICE:\n%s",
102  e.what());
103  return false;
104  }
105  }
106  m_connected = true;
107  return true;
108 }
109 
110 bool CLMS100Eth::turnOff()
111 {
112  if (m_client.isConnected()) m_client.close();
113  m_connected = false;
114  m_turnedOn = false;
115  return true;
116 }
117 
118 bool CLMS100Eth::turnOn()
119 {
120  /** From the LMS100 datasheet : :
121  * * Login sMN SetAccessMode 03 F4724744F4724744
122  * * Set Scanarea and Resolution
123  * * sMN mLMPsetscancfg
124  * * SWN LMDscandatacfg 01 00 0 1 0 00 00 0 0 0 0 1
125  * * SMN mEEwriteall Je ne le fais pas, car ca écrit en mémoire non
126  * volatile...
127  * * Request scan : sRN LMDscandata OR sEN LMDscandata
128  */
129  if (checkIsConnected())
130  {
131  try
132  {
133  {
134  char msg[] = {"sMN SetAccessMode 03 F4724744"};
135  char msgIn[100];
136  sendCommand(msg);
137 
138  size_t read = m_client.readAsync(msgIn, 100, 1000, 1000); // 18
139 
140  msgIn[read - 1] = 0;
141  MRPT_LOG_DEBUG_FMT("read : %u\n", (unsigned int)read);
142  MRPT_LOG_DEBUG_FMT("message : %s\n", string(&msgIn[1]).c_str());
143 
144  if (!read) return false;
145  }
146  {
147  char msg[] = {
148  "sMN mLMPsetscancfg +2500 +1 +2500 -450000 +2250000"};
149  char msgIn[100];
150  sendCommand(msg);
151 
152  size_t read = m_client.readAsync(msgIn, 100, 1000, 1000);
153 
154  msgIn[read - 1] = 0;
155  MRPT_LOG_DEBUG_FMT("read : %u\n", (unsigned int)read);
156  MRPT_LOG_DEBUG_FMT("message : %s\n", string(&msgIn[1]).c_str());
157 
158  if (!read) return false;
159  }
160  {
161  char msg[] = {
162  "sWN LMDscandatacfg 01 00 0 1 0 00 00 0 0 0 0 +1"};
163  char msgIn[100];
164  sendCommand(msg);
165 
166  size_t read = m_client.readAsync(msgIn, 100, 1000, 1000);
167 
168  msgIn[read - 1] = 0;
169  MRPT_LOG_DEBUG_FMT("read : %u\n", (unsigned int)read);
170  MRPT_LOG_DEBUG_FMT("message : %s\n", string(&msgIn[1]).c_str());
171 
172  if (!read) return false;
173  }
174  {
175  char msg[] = {"sMN LMCstartmeas"};
176  char msgIn[100];
177  sendCommand(msg);
178  size_t read = m_client.readAsync(msgIn, 100, 1000, 1000);
179 
180  msgIn[read - 1] = 0;
181  MRPT_LOG_DEBUG_FMT("message : %s\n", string(&msgIn[1]).c_str());
182  if (!read) return false;
183  }
184  {
185  char msgIn[100];
186  char msg[] = {"sRN STlms"};
187  do
188  {
189  sendCommand(msg);
190  size_t read = m_client.readAsync(msgIn, 100, 1000, 1000);
191  std::this_thread::sleep_for(10000ms);
192 
193  msgIn[read - 1] = 0;
194  MRPT_LOG_DEBUG_FMT("message : %s\n", &msgIn[1]);
195  MRPT_LOG_DEBUG_FMT("%c\n", msgIn[11]);
196  if (!read) return false;
197  } while (msgIn[11] != '7');
198  }
199  m_turnedOn = true;
200  }
201  catch (std::exception& e)
202  {
203  MRPT_LOG_ERROR_FMT("%s", e.what());
204  return false;
205  }
206  }
207  else
208  {
209  return false;
210  }
211  return true;
212 }
213 
214 void CLMS100Eth::sendCommand(const char* cmd)
215 {
216  generateCmd(cmd);
217  if (!m_cmd.empty()) // one never knows...
218  m_client.writeAsync(&m_cmd[0], m_cmd.size());
219 }
220 
221 /** Add the start and end character.
222  */
223 void CLMS100Eth::generateCmd(const char* cmd)
224 {
225  if (strlen(cmd) > 995)
226  {
227  MRPT_LOG_ERROR("Error: command is too long.");
228  return;
229  }
230  m_cmd = format("%c%s%c", 0x02, cmd, 0x03);
231 }
232 
233 bool CLMS100Eth::decodeScan(char* buff, CObservation2DRangeScan& outObservation)
234 {
235  char* next;
236  unsigned int idx = 0;
237  unsigned int scanCount = 0;
238  char* tmp;
239  // double factor;
240 
241  next = strtok(buff, " ", &tmp);
242 
243  while (next && scanCount == 0)
244  {
245  // cout << "Interpreting : " << next << endl;
246  switch (++idx)
247  {
248  case 1:
249  if (strncmp(&next[1], "sRA", 3) && strncmp(&next[1], "sSN", 3))
250  return false;
251  break;
252  case 2:
253  if (strcmp(next, "LMDscandata")) return false;
254  break;
255  case 6:
256  if (!strcmp(next, "1"))
257  {
258  MRPT_LOG_ERROR_FMT("STATUS error on LMS100: '%s'", next);
259  }
260  else if (!strcmp(next, "4"))
261  {
263  "Contamination error on LMS100: '%s'", next);
264  }
265  else
266  {
267  MRPT_LOG_DEBUG("STATUS Ok.\n");
268  }
269  break;
270  case 21:
271  if (strcmp(next, "DIST1"))
272  {
274  "LMS100 is not configured to send distances.");
275  return false;
276  }
277  MRPT_LOG_DEBUG("Distance : OK\n");
278  break;
279  case 22:
280  // factor = strtod(next, nullptr);
281  break;
282  case 26:
283  scanCount = strtoul(next, nullptr, 16);
284  MRPT_LOG_DEBUG_FMT("Scan Count : %d\n", scanCount);
285  break;
286  default:
287  break;
288  }
289  next = strtok(nullptr, " ", &tmp);
290  }
291  outObservation.aperture = (float)APPERTURE;
292  outObservation.rightToLeft = false;
293  outObservation.stdError = 0.012f;
294  outObservation.sensorPose = m_sensorPose;
295  outObservation.beamAperture = m_beamApperture;
296  outObservation.maxRange = m_maxRange;
297  outObservation.timestamp = mrpt::system::getCurrentTime();
298  outObservation.sensorLabel = m_sensorLabel;
299 
300  outObservation.resizeScan(scanCount);
301  unsigned int i;
302  for (i = 0; i < scanCount && next; i++, next = strtok(nullptr, " ", &tmp))
303  {
304  outObservation.setScanRange(
305  i, double(strtoul(next, nullptr, 16)) / 1000.0);
306  outObservation.setScanRangeValidity(
307  i, outObservation.getScanRange(i) <= outObservation.maxRange);
308  }
309  outObservation.resizeScan(i);
310  return i >= scanCount;
311 }
312 
313 void CLMS100Eth::doProcessSimple(
314  bool& outThereIsObservation, CObservation2DRangeScan& outObservation,
315  bool& hardwareError)
316 {
317  if (!m_turnedOn)
318  {
319  hardwareError = true;
320  outThereIsObservation = false;
321  return;
322  }
323  hardwareError = false;
324 
325  char msg[] = {"sRN LMDscandata"};
326  sendCommand(msg);
327  char buffIn[16 * 1024];
328  // size_t read = m_client.readAsync(buffIn, sizeof(buffIn), 100, 100);
329  // cout << "read :" << read << endl;
330  // while(m_client.readAsync(buffIn, sizeof(buffIn), 100, 100)) cout << "Lit
331  // dans le vent" << endl;
332 
333  m_client.readAsync(buffIn, sizeof(buffIn), 40, 40);
334 
335  if (decodeScan(buffIn, outObservation))
336  {
337  // Do filter:
338  C2DRangeFinderAbstract::filterByExclusionAreas(outObservation);
339  C2DRangeFinderAbstract::filterByExclusionAngles(outObservation);
340  // Do show preview:
341  C2DRangeFinderAbstract::processPreview(outObservation);
342 
343  outThereIsObservation = true;
344  hardwareError = false;
345  }
346  else
347  {
348  hardwareError = true;
349  outThereIsObservation = false;
350  MRPT_LOG_ERROR("doProcessSimple failed\n");
351  }
352 }
353 
354 /*-------------------------------------------------------------*/
355 void CLMS100Eth::doProcess()
356 {
358  mrpt::make_aligned_shared<CObservation2DRangeScan>();
359  try
360  {
361  bool isThereObservation, hwError;
362  doProcessSimple(isThereObservation, *obs, hwError);
363  if (hwError)
364  m_state = ssError;
365  else
366  m_state = ssWorking;
367  // if at least one data have been sensed :
368  if (isThereObservation)
369  {
370  appendObservation(obs);
371  }
372  }
373  catch (...)
374  {
375  m_state = ssError;
376  THROW_EXCEPTION("No observation received from the Phidget board!");
377  }
378 }
379 
380 /** A method to set the sensor pose on the robot.
381  */
382 void CLMS100Eth::setSensorPose(const CPose3D& _pose) { m_sensorPose = _pose; }
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
#define APPERTURE
Definition: CLMS100eth.cpp:19
#define MRPT_LOG_DEBUG_FMT(_FMT_STRING,...)
#define MRPT_LOG_ERROR(_STRING)
#define MRPT_LOG_DEBUG(_STRING)
#define MRPT_LOG_ERROR_FMT(_FMT_STRING,...)
#define M_PI
Definition: bits.h:92
#define DEG2RAD
Definition: bits.h:112
This "software driver" implements the communication protocol for interfacing a SICK LMS100 laser scan...
Definition: CLMS100eth.h:76
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
float maxRange
The maximum range allowed by the device, in meters (e.g.
float beamAperture
The aperture of each beam, in radians, used to insert "thick" rays in the occupancy grid.
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees).
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
std::shared_ptr< CObservation2DRangeScan > Ptr
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
void resizeScan(const size_t len)
Resizes all data vectors to allocate a given number of scan rays.
void setScanRangeValidity(const size_t i, const bool val)
float stdError
The "sigma" error of the device in meters, used while inserting the scan in an occupancy grid.
void setScanRange(const size_t i, const float val)
std::string sensorLabel
An arbitrary label that can be used to identify the sensor.
Definition: CObservation.h:60
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:58
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:89
This class allows loading and storing values and vectors of different types from a configuration text...
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
GLsizei const GLchar ** string
Definition: glext.h:4101
char * strtok(char *str, const char *strDelimit, char **context) noexcept
An OS-independent method for tokenizing a string.
mrpt::system::TTimeStamp getCurrentTime()
Returns the current (UTC) system time.
Definition: datetime.cpp:73
#define THROW_EXCEPTION(msg)
Definition: mrpt_macros.h:111
Contains classes for various device interfaces.
This namespace contains representation of robot actions and observations.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:18
This namespace provides a OS-independent interface to many useful functions: filenames manipulation,...
Definition: math_frwds.h:31
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 63ea9d1f1 Thu Nov 23 00:06:53 2017 +0100 at mar 26 may 2026 12:19:29 CEST