Main MRPT website > C++ reference for MRPT 1.9.9
CIbeoLuxETH.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 
12 #include <mrpt/hwdrivers/CIbeoLuxETH.h> // Precompiled headers
13 
14 #include <bitset>
15 #include <thread>
16 
17 #define APPERTURE 4.712385 // in radian <=> 270°
18 
19 using namespace mrpt;
20 using namespace mrpt::system;
21 using namespace mrpt::poses;
22 using namespace mrpt::utils;
23 using namespace mrpt::hwdrivers;
24 using namespace mrpt::obs;
25 using namespace std;
26 
27 // TODO: Use enum instead
28 const unsigned char SearchForAF = 0;
29 const unsigned char SearchForFE = 1;
30 const unsigned char SearchForC0 = 2;
31 const unsigned char SearchForC2 = 3;
32 const unsigned char PacketFound = 4;
33 const unsigned char SaveData = 5;
34 
36 
37 CIbeoLuxETH::CIbeoLuxETH(string _ip, unsigned int _port)
38  : m_ip(_ip),
39  m_port(_port),
40  m_sensorPose(0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
41  m_maxRange(200.0),
42  m_beamApperture(.25 * M_PI / 180.0),
43  vwinkel(0.0)
44 {
45 }
46 
47 CIbeoLuxETH::~CIbeoLuxETH()
48 {
49  m_run = false;
50  dataCollectionThread.join();
51  // Wait a little for the thread to come down
52  // Don't ask why, it just works
53  // TODO: Try without the delay
54  std::this_thread::sleep_for(10ms);
55 }
56 
57 void CIbeoLuxETH::dataCollection()
58 {
59  unsigned char state = SearchForAF;
60  unsigned char msgIn[1], Header[20], ScanListHeader[44], ScanPointData[10];
61  unsigned int datatype, /*scannumber,*/ numScanpoints, angleTicks, SPlayer,
62  SPdistance; // SPecho;
63  int SPHangle;
64  unsigned char msg[32];
65 
66  // Start TCP-connection to laserscanner
67  m_client.connect(m_ip, m_port);
68 
69  // Send filter command
70  makeCommandHeader(msg);
71  makeTypeCommand(msg);
72  m_client.writeAsync(&msg[0], 32);
73 
74  // Send start command
75  makeCommandHeader(msg);
76  makeStartCommand(msg);
77  m_client.writeAsync(&msg[0], 28);
78 
79  while (m_run)
80  {
81  switch (state)
82  {
83  case SearchForAF:
84  m_client.readAsync(msgIn, 1, 100, 10);
85  if (msgIn[0] == 0xAF) state = SearchForFE;
86  break;
87  case SearchForFE:
88  m_client.readAsync(msgIn, 1, 100, 10);
89  if (msgIn[0] == 0xFE)
90  state = SearchForC0;
91  else
92  state = SearchForAF;
93  break;
94  case SearchForC0:
95  m_client.readAsync(msgIn, 1, 100, 10);
96  if (msgIn[0] == 0xC0)
97  state = SearchForC2;
98  else
99  state = SearchForAF;
100  break;
101  case SearchForC2:
102  m_client.readAsync(msgIn, 1, 100, 10);
103  if (msgIn[0] == 0xC2)
104  state = PacketFound;
105  else
106  state = SearchForAF;
107  break;
108  case PacketFound:
109  m_client.readAsync(Header, 20, 100, 10);
110  datatype = Header[10] * 0x100 + Header[11];
111  switch (datatype)
112  {
113  case 0x2030:
114  // do nothing
115  state = SearchForAF;
116  break;
117  case 0x2221:
118  // do nothing
119  state = SearchForAF;
120  break;
121  case 0x2805:
122  // do nothing
123  state = SearchForAF;
124  break;
125  case 0x2020:
126  // do nothing
127  state = SearchForAF;
128  break;
129  case 0x2202:
130  state = SaveData;
131  break;
132  default:
133  std::cerr << "UNKNOWN packet of type " << hex
134  << datatype << " received!!\n";
135  state = SearchForAF;
136  }
137  break;
138  case SaveData:
139  // Create new observation object pointer
141  mrpt::make_aligned_shared<CObservation3DRangeScan>();
142  newObs->hasPoints3D = true;
143  newObs->maxRange = 200.00;
144 
145  m_client.readAsync(ScanListHeader, 44, 10, 10);
146  /*scannumber =
147  ScanListHeader[1] * 0x100 + ScanListHeader[0]; */
148  numScanpoints = ScanListHeader[29] * 0x100 + ScanListHeader[28];
149  angleTicks = ScanListHeader[23] * 0x100 + ScanListHeader[22];
150 
151  for (unsigned int i = 0; i < numScanpoints; ++i)
152  {
153  bool dropPacket = false;
154 
155  m_client.readAsync(ScanPointData, 10, 10, 10);
156  SPlayer =
157  ScanPointData[0] & 0x0F; // two lower bits denote layer
158  // SPecho = ScanPointData[0] >> 4; // two higher bits
159  // denote echo
160  SPHangle = (char)ScanPointData[3] * 0x100 +
161  ScanPointData[2]; // signed INT16 here
162  SPdistance = ScanPointData[5] * 0x100 + ScanPointData[4];
163 
164  // Sanity checks
165  if (SPlayer > 4)
166  {
167  dropPacket = true;
168  // std::cerr << "Invalid layer: " << SPlayer << " should
169  // be element of [0,3] Scanpoint dropped.\n";
170  }
171  if ((SPHangle < -((int)angleTicks) / 2) ||
172  (SPHangle > (int)angleTicks / 2))
173  {
174  dropPacket = true;
175  // std::cerr << "Invalid horizontal angle: " <<
176  // (int)-angleTicks/2 << "< " << SPHangle << " <" <<
177  // angleTicks/2 << " Scanpoint dropped.\n";
178  }
179  if ((SPdistance < 30) || (SPdistance > 20000))
180  {
181  dropPacket = true;
182  // std::cerr << "Invalid distance: 30< " << SPdistance
183  // << " <20000 Scanpoint dropped.\n";
184  }
185 
186  if (!dropPacket)
187  {
188  // TODO: Process point information correctly
189  CPoint3D cartesianPoint = convertToCartesian(
190  convertLayerToRad(
191  SPlayer), // vertikal coord of scanner
192  convertTicksToHRad(
193  SPHangle,
194  angleTicks), // horizontal coord of scanner
195  SPdistance);
196 
197  // write scanpoint data to observation object
198  newObs->points3D_x.push_back(cartesianPoint.x());
199  newObs->points3D_y.push_back(cartesianPoint.y());
200  newObs->points3D_z.push_back(cartesianPoint.z());
201  }
202  } // for
203 
204  // return observation to framework
205  appendObservation(newObs);
206 
207  state = SearchForAF;
208  break; // SaveData
209  } // Switch
210  } // While
211 
212  // Send stop command
213  makeCommandHeader(msg);
214  makeStopCommand(msg);
215  m_client.writeAsync(&msg[0], 28);
216 
217  m_client.close();
218 } // dataCollection
219 
220 CPoint3D CIbeoLuxETH::convertToCartesian(float vrad, float hrad, float distance)
221 {
222  float x, y, z;
223  float rho, phi, theta;
224 
225  // Convert from laserscanner coordinate system to spherical coordinates
226  rho = distance / 100; // cm to meter
227  phi = -hrad + (M_PI / 2); // start with 0 pointing straight up
228  theta = vrad + M_PI; // 0 is straight ahead, going clockwise for 2 Pi
229 
230  x = rho * sin(phi) * cos(theta);
231  y = rho * sin(phi) * sin(theta);
232  z = rho * cos(phi);
233 
234  CPoint3D point(x, y, z);
235  return point;
236 }
237 
238 double CIbeoLuxETH::convertTicksToHRad(int hticks, int hticksPerRotation)
239 {
240  return M_PI * 2 * hticks / hticksPerRotation;
241 }
242 
243 double CIbeoLuxETH::convertLayerToRad(int scanlayer)
244 {
245  double vangle;
246 
247  switch (scanlayer)
248  {
249  case 0:
250  vangle = -0.02094395103;
251  break;
252  case 1:
253  vangle = -0.006981317009;
254  break;
255  case 2:
256  vangle = 0.006981317009;
257  break;
258  case 3:
259  vangle = 0.02094395103;
260  break;
261  default:
262  vangle = 0;
263  std::cerr << "Layer: " << scanlayer << "! Returning " << vangle
264  << " as angle.\n";
265  break;
266  }
267 
268  return vangle;
269 }
270 
271 void CIbeoLuxETH::loadConfig_sensorSpecific(
272  const mrpt::utils::CConfigFileBase& configSource,
273  const std::string& iniSection)
274 {
275  float pose_x, pose_y, pose_z, pose_yaw, pose_pitch, pose_roll;
276  bool faillNotFound = false;
277  pose_x = configSource.read_float(iniSection, "pose_x", 0, faillNotFound);
278  pose_y = configSource.read_float(iniSection, "pose_y", 0, faillNotFound);
279  pose_z = configSource.read_float(iniSection, "pose_z", 0, faillNotFound);
280  pose_yaw =
281  configSource.read_float(iniSection, "pose_yaw", 0, faillNotFound);
282  pose_pitch =
283  configSource.read_float(iniSection, "pose_pitch", 0, faillNotFound);
284  pose_roll =
285  configSource.read_float(iniSection, "pose_roll", 0, faillNotFound);
286 
287  m_sensorPose = CPose3D(
288  pose_x, pose_y, pose_z, DEG2RAD(pose_yaw), DEG2RAD(pose_pitch),
289  DEG2RAD(pose_roll));
290 }
291 
292 void CIbeoLuxETH::makeCommandHeader(unsigned char* buffer)
293 {
294  // Header - all big endian
295  buffer[0] = 0xAF; // magic word
296  buffer[1] = 0xFE;
297  buffer[2] = 0xC0;
298  buffer[3] = 0xC2;
299  buffer[4] = 0x00; // Size of previous message, here just left to null
300  buffer[5] = 0x00;
301  buffer[6] = 0x00;
302  buffer[7] = 0x00;
303  buffer[8] = 0x00; // Size of data block
304  buffer[9] = 0x00;
305  buffer[10] = 0x00;
306  buffer[11] = 0x00; // to be set by the command function
307  buffer[12] = 0x00; // Reserved + source Id
308  buffer[13] = 0x78; // source ID of 0x78 as observed
309  buffer[14] = 0x20; // Data Type - 2010 = command
310  buffer[15] = 0x10;
311  buffer[16] = 0x00; // 4* ntpp time (s) + 4* fractions of a second
312  buffer[17] = 0x00;
313  buffer[18] = 0x00;
314  buffer[19] = 0x00;
315  buffer[20] = 0x00;
316  buffer[21] = 0x00;
317  buffer[22] = 0x00;
318  buffer[23] = 0x00;
319 }
320 
321 void CIbeoLuxETH::makeStartCommand(unsigned char* buffer)
322 {
323  // Header - all big endian
324  buffer[11] = 0x04; // Size of data block
325  // Data Block - all little endian
326  buffer[24] = 0x20; // Start Measure 0x0020
327  buffer[25] = 0x00;
328  buffer[26] = 0x00; // Reserved, but obligatory
329  buffer[27] = 0x00;
330 }
331 
332 void CIbeoLuxETH::makeStopCommand(unsigned char* buffer)
333 {
334  // Header - all big endian
335  buffer[11] = 0x04; // Size of data block
336  // Data Block - all little endian
337  buffer[24] = 0x21; // Stop Measure 0x0021
338  buffer[25] = 0x00;
339  buffer[26] = 0x00; // Reserved, but obligatory
340  buffer[27] = 0x00;
341 }
342 
343 void CIbeoLuxETH::makeTypeCommand(unsigned char* buffer)
344 {
345  // Header - all big endian
346  buffer[11] = 0x08; // Size of data block
347  // Data Block - big endian (for filter command!)
348  buffer[24] = 0x00; // Command Type - 0005 = set datatype filter
349  buffer[25] = 0x05;
350  buffer[26] = 0x00; // Data type filter length
351  buffer[27] = 0x02;
352  buffer[28] = 0x22; // start value
353  buffer[29] = 0x00;
354  buffer[30] = 0x22; // end value
355  buffer[31] = 0x10;
356 }
357 
358 /** This method can or cannot be implemented in the derived class, depending on
359 * the need for it.
360 * \exception This method must throw an exception with a descriptive message if
361 * some critical error is found.
362 */
363 void CIbeoLuxETH::initialize()
364 {
365  m_run = true;
366 
367  // Start a thread to collect and interpret scandata
368  // std::cout << "Start dataCollectionThread\n";
369 
370  // boost threads:
371  // boost::thread
372  // dataCollectionThread(boost::bind(&CIbeoLuxETH::dataCollection,this));
373 
374  dataCollectionThread = std::thread(&CIbeoLuxETH::dataCollection, this);
375 }
376 
377 void CIbeoLuxETH::doProcess()
378 {
379  // nothing is done here
380  // data is collected in the dataCollection thread
381 }
double x() const
Common members of all points & poses classes.
Definition: CPoseOrPoint.h:135
const unsigned char PacketFound
Definition: CIbeoLuxETH.cpp:32
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
GLdouble GLdouble z
Definition: glext.h:3872
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
GLuint buffer
Definition: glext.h:3917
const unsigned char SaveData
Definition: CIbeoLuxETH.cpp:33
std::shared_ptr< CObservation3DRangeScan > Ptr
Contains classes for various device interfaces.
STL namespace.
#define M_PI
Definition: bits.h:92
This "software driver" implements the communication protocol for interfacing a Ibeo Lux laser scanner...
Definition: CIbeoLuxETH.h:45
const unsigned char SearchForC2
Definition: CIbeoLuxETH.cpp:31
This class allows loading and storing values and vectors of different types from a configuration text...
const unsigned char SearchForC0
Definition: CIbeoLuxETH.cpp:30
This namespace contains representation of robot actions and observations.
#define DEG2RAD
GLsizei const GLchar ** string
Definition: glext.h:4101
A class used to store a 3D point.
Definition: CPoint3D.h:32
#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
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
const unsigned char SearchForAF
Definition: CIbeoLuxETH.cpp:28
GLenum GLint GLint y
Definition: glext.h:3538
GLenum GLint x
Definition: glext.h:3538
const unsigned char SearchForFE
Definition: CIbeoLuxETH.cpp:29
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
Definition: geometry.cpp:1885



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