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; }
This "software driver" implements the communication protocol for interfacing a SICK LMS100 laser scan...
Definition: CLMS100eth.h:75
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
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
float beamAperture
The aperture of each beam, in radians, used to insert "thick" rays in the occupancy grid...
mrpt::system::TTimeStamp getCurrentTime()
Returns the current (UTC) system time.
Definition: datetime.cpp:73
void setScanRange(const size_t i, const float val)
#define THROW_EXCEPTION(msg)
#define MRPT_LOG_DEBUG_FMT(_FMT_STRING,...)
Contains classes for various device interfaces.
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
std::shared_ptr< CObservation2DRangeScan > Ptr
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,...)
This class allows loading and storing values and vectors of different types from a configuration text...
float maxRange
The maximum range allowed by the device, in meters (e.g.
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
char * strtok(char *str, const char *strDelimit, char **context) noexcept
An OS-independent method for tokenizing a string.
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.
Definition: format.cpp:19
#define MRPT_LOG_DEBUG(_STRING)
#define DEG2RAD
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:
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
std::string sensorLabel
An arbitrary label that can be used to identify the sensor.
Definition: CObservation.h:60
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:58
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
#define APPERTURE
Definition: CLMS100eth.cpp:19
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
void resizeScan(const size_t len)
Resizes all data vectors to allocate a given number of scan rays.
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
#define MRPT_LOG_ERROR(_STRING)
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
void setScanRangeValidity(const size_t i, const bool val)



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