Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
diagToF.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // Program: laelaps_diag
6 //
7 // File: diagToF.cxx
8 //
9 /*! \file
10  *
11  * \brief Perform Laelaps Time-of-Flight sensors diagnostics.
12  *
13  * \author Robin Knight (robin.knight@roadnarrows.com)
14  *
15  * \par Copyright
16  * \h_copy 2015-2017. RoadNarrows LLC.\n
17  * http://www.roadnarrows.com\n
18  * All Rights Reserved
19  */
20 /*
21  * @EulaBegin@
22  *
23  * Unless otherwise stated explicitly, all materials contained are copyrighted
24  * and may not be used without RoadNarrows LLC's written consent,
25  * except as provided in these terms and conditions or in the copyright
26  * notice (documents and software) or other proprietary notice provided with
27  * the relevant materials.
28  *
29  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
30  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
31  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
32  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
33  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
37  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
38  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
39  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
40  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
41  *
42  * @EulaEnd@
43  */
44 ////////////////////////////////////////////////////////////////////////////////
45 
46 #include <unistd.h>
47 #include <termios.h>
48 #include <string.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <stdarg.h>
52 
53 #include <iostream>
54 #include <fstream>
55 #include <string>
56 #include <vector>
57 
58 #include "rnr/rnrconfig.h"
59 #include "rnr/log.h"
60 #include "rnr/opts.h"
61 #include "rnr/pkg.h"
62 
63 // common
64 #include "Laelaps/laelaps.h"
65 #include "Laelaps/laeUtils.h"
66 #include "Laelaps/laeDesc.h"
67 
68 // hardware
69 #include "Laelaps/laeSysDev.h"
70 #include "Laelaps/laeI2C.h"
71 #include "Laelaps/laeVL6180.h"
72 
73 #include "laelaps_diag.h"
74 
75 using namespace std;
76 using namespace laelaps;
77 using namespace sensor::vl6180;
78 
79 static const char *SubSysName = "ToF";
80 static const char *ProdName = "VL6180";
81 
82 static const char *SensorKeys[ToFSensorMaxNumOf] =
83 {
84  "front", "left_front", "left", "left_rear",
85  "rear", "right_rear", "right", "right_front"
86 };
87 
88 static DiagStats initSensors(LaeRangeSensorGroup &rnggrp)
89 {
90  uint_t uVerMajor, uVerMinor, uFwVer;
91 
92  DiagStats stats;
93 
94  printSubHdr("Initialize Sensors");
95 
96  stats.testCnt += 1;
97 
98  if( rnggrp.setInterface(RobotDesc.getProdHwVer()) == LAE_OK )
99  {
100  printTestResult(PassTag, "Range Sensor Group interface set.");
101  stats.passCnt += 1;
102  }
103  else
104  {
105  printTestResult(FatalTag,
106  "Failed to set interface with product hw version 0x%x.",
107  RobotDesc.getProdHwVer());
108  stats.fatal = true;
109  }
110 
111  if( !stats.fatal )
112  {
113  stats.testCnt += 1;
114 
115  if( rnggrp.getInterfaceVersion(uVerMajor, uVerMinor, uFwVer) == LAE_OK )
116  {
117  printTestResult(PassTag, "Range Sensor Group interface %u.%u, fwver=%u.",
118  uVerMajor, uVerMinor, uFwVer);
119  stats.passCnt += 1;
120 
121  rnggrp.clearSensedData();
122  }
123  else
124  {
125  printTestResult(FailTag,
126  "Failed to read range sensor group interface version.");
127  }
128  }
129 
130  if( !stats.fatal )
131  {
132  stats.testCnt += 1;
133 
134  if( rnggrp.configure(RobotDesc) == LAE_OK )
135  {
136  printTestResult(PassTag,
137  "Configured range sensors from robot description.");
138  stats.passCnt += 1;
139  }
140  else
141  {
142  printTestResult(FailTag, "Failed to configure range sensors.");
143  }
144  }
145 
146  return stats;
147 }
148 
149 static DiagStats getSensorInfo(LaeRangeSensorGroup &rnggrp)
150 {
151  const char *sKey;
152 
153  // properties
154  string strRadiationType;
155  double fFoV;
156  double fBeamDir;
157  double fMin;
158  double fMax;
159  bool bInstalled;
160 
161  // identity
162  VL6180xIdentification ident;
163  bool bIdent;
164 
165  // tuning
166  uint_t uRangeOffset;
167  uint_t uRangeCrossTalk;
168  double fAlsGain;
169  uint_t uAlsIntPeriod;
170  bool bTunes;
171 
172  int rc;
173  DiagStats stats;
174 
175  printSubHdr("Read Sensors Properties and Tuning");
176 
177  //
178  // Read Info and Config
179  //
180  for(size_t i = 0; i < ToFSensorMaxNumOf; ++i)
181  {
182  sKey = SensorKeys[i];
183 
184  bInstalled = false;
185  bIdent = false;
186  bTunes = false;
187 
188  stats.testCnt += 1;
189 
190  rc = rnggrp.getSensorProps(sKey, strRadiationType,
191  fFoV, fBeamDir, fMin, fMax);
192 
193  if( rc == LAE_OK )
194  {
195  printTestResult(PassTag, "%s %s sensor: Got sensor properties.",
196  ProdName, sKey);
197  stats.passCnt += 1;
198  bInstalled = true;
199  }
200  else if( rc == -LAE_ECODE_BAD_VAL )
201  {
202  printTestResult(PassTag, "%s %s sensor: NOT INSTALLED.", ProdName, sKey);
203  stats.passCnt += 1;
204  }
205  else
206  {
207  printTestResult(FailTag, "%s %s sensor: Failed to get sensor properties.",
208  ProdName, sKey);
209  }
210 
211  if( bInstalled )
212  {
213  stats.testCnt += 1;
214 
215  rc = rnggrp.readSensorIdentity(sKey, ident);
216 
217  if( rc == LAE_OK )
218  {
219  printTestResult(PassTag, "%s %s sensor: Read sensor identity.",
220  ProdName, sKey);
221  stats.passCnt += 1;
222  bIdent = true;
223  }
224  else
225  {
226  printTestResult(FailTag,
227  "%s %s sensor: Failed to read sensor identity.",
228  ProdName, sKey);
229  }
230 
231  stats.testCnt += 1;
232 
233  rc = rnggrp.readSensorTunes(sKey, uRangeOffset, uRangeCrossTalk,
234  fAlsGain, uAlsIntPeriod);
235 
236  if( rc == LAE_OK )
237  {
238  printTestResult(PassTag, "%s %s sensor: Read sensor tuning parameters.",
239  ProdName, sKey);
240  stats.passCnt += 1;
241  bTunes = true;
242  }
243  else
244  {
245  printTestResult(PassTag,
246  "%s %s sensor: Failed to read sensor tuning parameters.",
247  ProdName, sKey);
248  }
249  }
250 
251  printf("\n");
252  printf("%s %s Sensor Info:\n", SubSysName, ProdName);
253  printf(" Properties\n");
254  printf(" Location: %s\n", sKey);
255  printf(" Installed: %s\n", (bInstalled? "yes": "no"));
256  printf(" Beam Direction: %.1lf degrees\n", radToDeg(fBeamDir));
257  printf(" Radiation: %s\n", strRadiationType.c_str());
258  printf(" FoV: %.1lf degrees\n", radToDeg(fFoV));
259  printf(" Min Distance: %.3lf meters\n", fMin);
260  printf(" MAx Distance: %.3lf meters\n", fMax);
261  if( bIdent )
262  {
263  printf(" Identity\n");
264  printf(" Model: 0x%02x v%u.%u\n",
265  ident.idModel, ident.idModelRevMajor, ident.idModelRevMinor);
266  printf(" Module: v%u.%u\n",
267  ident.idModuleRevMajor, ident.idModuleRevMinor);
268  printf(" Date/Time: %u/%u\n", ident.idDate, ident.idTime);
269  }
270  if( bTunes )
271  {
272  printf(" Tuning\n");
273  printf(" Range Offset: %u\n", uRangeOffset);
274  printf(" Range Cross-Talk: %u\n", uRangeCrossTalk);
275  printf(" ALS Gain: %.2lf\n", fAlsGain);
276  printf(" ALS Int. Period: %u\n", uAlsIntPeriod);
277  }
278  printf("\n");
279  }
280 
281  return stats;
282 }
283 
284 static DiagStats measureDistance(LaeRangeSensorGroup &rnggrp, int cnt)
285 {
286  vector<string> keys;
287  vector<double> distance;
288  bool showLabel;
289  int rc;
290 
291  DiagStats stats;
292 
293  showLabel = cnt == 0;
294 
295  ++stats.testCnt;
296 
297  rc = rnggrp.getRange(keys, distance);
298 
299  if( rc == OK )
300  {
301  ++stats.passCnt;
302  }
303  else
304  {
305  printTestResult(FailTag, "%s: Failed to get distance measurements.",
306  SubSysName);
307  showLabel = true;
308  }
309 
310  if( showLabel )
311  {
312  printf("%8s", "");
313  for(size_t i = 0; i < keys.size(); ++i)
314  {
315  printf("%10s ", keys[i].c_str());
316  }
317  printf("\n");
318  }
319 
320  printf("%6d. ", cnt);
321  for(size_t i = 0; i < distance.size(); ++i)
322  {
323  if( distance[i] > VL6180X_RANGE_MAX )
324  {
325  printf("%10s ", "noobj");
326  }
327  else if( distance[i] < 0 )
328  {
329  printf("%10s ", "error");
330  }
331  else
332  {
333  printf("%10.3lf ", distance[i]);
334  }
335  }
336  printf("\r");
337  fflush(stdout);
338 
339  return stats;
340 }
341 
342 static DiagStats measureAmbient(LaeRangeSensorGroup &rnggrp, int cnt)
343 {
344  vector<string> keys;
345  vector<double> ambient;
346  bool showLabel;
347  int rc;
348 
349  DiagStats stats;
350 
351  showLabel = cnt == 0;
352 
353  ++stats.testCnt;
354 
355  rc = rnggrp.getAmbientLight(keys, ambient);
356 
357  if( rc == OK )
358  {
359  ++stats.passCnt;
360  }
361  else
362  {
363  printTestResult(FailTag, "%s: Failed to get ambient light measurements.",
364  SubSysName);
365  showLabel = true;
366  }
367 
368  if( showLabel )
369  {
370  printf("%8s", "");
371  for(size_t i = 0; i < keys.size(); ++i)
372  {
373  printf("%10s ", keys[i].c_str());
374  }
375  printf("\n");
376  }
377 
378  printf("%6d. ", cnt);
379  for(size_t i = 0; i < ambient.size(); ++i)
380  {
381  printf("%10.2lf ", ambient[i]);
382  }
383  printf("\r");
384  fflush(stdout);
385 
386  return stats;
387 }
388 
389 DiagStats runToFDiagnostics(bool bAnyKey)
390 {
391  DiagStats statsTest;
392  DiagStats statsTotal;
393  int cnt;
394  bool bQuit;
395 
396  printHdr("Time-of-Flight Sensors Diagnostics");
397 
398  LaeRangeSensorGroup rangegroup(I2CBus);
399 
400  //
401  // Init Tests
402  //
403  statsTest = initSensors(rangegroup);
404 
405  printSubTotals(statsTest);
406 
407  statsTotal += statsTest;
408 
409  //
410  // Info and Config Tests
411  //
412  if( !statsTotal.fatal )
413  {
414  statsTest = getSensorInfo(rangegroup);
415 
416  printSubTotals(statsTest);
417 
418  statsTotal += statsTest;
419  }
420 
421  //
422  // Take distance measurements.
423  //
424 
425  statsTest.zero();
426  bQuit = statsTotal.fatal;
427  cnt = 0;
428 
429  printSubHdr("Distance Measurements");
430 
431  while( !bQuit )
432  {
433  rangegroup.exec();
434 
435  statsTest += measureDistance(rangegroup, cnt++);
436 
437  if( !bAnyKey || kbhit() || statsTest.fatal )
438  {
439  printf("\n");
440  printSubTotals(statsTest);
441  bQuit = true;
442  }
443  else
444  {
445  usleep(100000);
446  }
447  }
448 
449  statsTotal += statsTest;
450 
451  //
452  // Take ambient light measurements
453  //
454 
455  statsTest.zero();
456  bQuit = statsTotal.fatal;
457  cnt = 0;
458 
459  printSubHdr("Ambient Light Measurements");
460 
461  printf("\n");
462  printf("Warning: The ALS is experimental and is disabled in production.\n");
463  printf("\n");
464 
465  while( !bQuit )
466  {
467  rangegroup.exec();
468 
469  statsTest += measureAmbient(rangegroup, cnt++);
470 
471  if( !bAnyKey || kbhit() || statsTest.fatal )
472  {
473  printf("\n");
474  printSubTotals(statsTest);
475  bQuit = true;
476  }
477  else
478  {
479  usleep(500000);
480  }
481  }
482 
483  statsTotal += statsTest;
484 
485  //
486  // Summary
487  //
488  printTotals(statsTotal);
489 
490  return statsTotal;
491 }
Diagnotics header file.
uint_t getProdHwVer() const
Get this robot&#39;s packed hardware version number.
Definition: laeDesc.h:608
#define VL6180X_RANGE_MAX
maximum range (m)
Definition: laeVL6180.h:131
virtual int getRange(const std::string &strKey, double &fRange)
Get the shadowed range measurement.
void clearSensedData()
Clear sensed data.
Definition: laeVL6180.cxx:2388
virtual int getInterfaceVersion(uint_t &uVerMajor, uint_t &uVerMinor, uint_t &uFwVer)
Get interface version.
Definition: laeVL6180.cxx:2393
Laelaps I2C class interface.
double radToDeg(double r)
Convert radians to degrees.
Definition: laeUtils.h:136
virtual int configure(const laelaps::LaeDesc &desc)
Configure sensor group from product description.
Definition: laeVL6180.cxx:2401
Laelaps Time-of-Flight sensors. The ToFs are used as a virtual bumper for close-in obstacle detection...
void zero()
Zero statistics.
Definition: laelaps_diag.h:131
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
Laelaps robotic base mobile platform description class interface.
Simple diagnostics statistics class.
Definition: laelaps_diag.h:106
Laelaps common utilities.
virtual int readSensorIdentity(const std::string &strKey, VL6180xIdentification &ident)
Read sensor&#39;s identification.
Definition: laeVL6180.cxx:2451
Laelaps system devices.
int setInterface(uint_t uProdHwVer)
Set the interface, given the <b><i>Laelaps</i></b> hardware version.
Definition: laeVL6180.cxx:2368
virtual int getAmbientLight(const std::string &strKey, double &fAmbient)
Get the shadowed ambient light illuminance measurement.
virtual int getSensorProps(const std::string &strKey, std::string &strRadiationType, double &fFoV, double &fBeamDir, double &fMin, double &fMax)
Get range sensor properties.
Definition: laeVL6180.cxx:2437
virtual int readSensorTunes(const std::string &strKey, uint_t &uRangeOffset, uint_t &uRangeCrossTalk, double &fAlsGain, uint_t &uAlsIntPeriod)
Read sensor&#39;s current tuning parameters.
Definition: laeVL6180.cxx:2466
Range sensor group class.
Definition: laeVL6180.h:1535
Top-level package include file.