Hekateros  3.4.3
RoadNarrows Robotics Robot Arm Project
ut-hekrobot.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Hekateros
4 //
5 // Unit Test: Test libhekateros library.
6 //
7 /*! \file
8  *
9  * $LastChangedDate: 2014-10-10 12:43:53 -0600 (Fri, 10 Oct 2014) $
10  * $Rev: 3781 $
11  *
12  * \ingroup hek_ut
13  *
14  * \brief Unit test for libhekateros HekRobot top-level class.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \copyright
19  * \h_copy 2013-2017. RoadNarrows LLC.\n
20  * http://www.roadnarrows.com\n
21  * All Rights Reserved
22  */
23 /*
24  * @EulaBegin@
25  *
26  * Unless otherwise stated explicitly, all materials contained are copyrighted
27  * and may not be used without RoadNarrows LLC's written consent,
28  * except as provided in these terms and conditions or in the copyright
29  * notice (documents and software) or other proprietary notice provided with
30  * the relevant materials.
31  *
32  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
33  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
34  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
35  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
36  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
37  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
40  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
41  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
42  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
43  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
44  *
45  * @EulaEnd@
46  */
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 #include <stdio.h>
50 
51 #include <iostream>
52 #include <string>
53 #include <vector>
54 
55 #include "rnr/rnrconfig.h"
56 #include "rnr/log.h"
57 
58 #include "Hekateros/hekateros.h"
59 #include "Hekateros/hekTune.h"
60 #include "Hekateros/hekXmlCfg.h"
61 #include "Hekateros/hekXmlTune.h"
62 #include "Hekateros/hekTraj.h"
63 #include "Hekateros/hekUtils.h"
64 #include "Hekateros/hekRobot.h"
65 
66 #include "gtest/gtest.h"
67 
68 using namespace ::std;
69 using namespace ::hekateros;
70 
71 /*!
72  * \ingroup hek_ut
73  * \defgroup hek_ut_robot Library libhekateros Unit Tests
74  * \brief Testing of basic functionality of \ref hekateros::HekRobot
75  * class instance.
76  * \{
77  */
78 
79 /*!
80  * \brief Test menu.
81  */
82 static const char *TestMenu =
83  "\nTest Menu\n"
84  " 1 Create robot.\n"
85  " 2 Delete robot.\n"
86  " 3 [<file>] Read xml cfg <file>. DEFAULT: /etc/hekateros.conf\n"
87  " 4 [<file>] Read xml tune <file>. DEFAULT: /etc/hek_tune.conf\n"
88  " 5 [<dev>] Connect to dynamixel bus <dev>. DEFAULT: /dev/ttyUSB0\n"
89  " 6 Disconnect from dynamixel bus.\n"
90  " 7 <how> [A]synchronously calibrate arm. <how> is 'a' or 's'. "
91  "DEFAULT: a\n"
92  " 8 <move> Execute pre-defined move: calibrated balanced parked "
93  " 9 <deg> Rotate wrist by the given degrees."
94  " a Cancel asynchronous task."
95  "gopen gclose.\n"
96  "\n"
97  " d Enable library diagnostics logging.\n"
98  " ? Show this menu.\n"
99  " q Quit unit test.\n\n";
100 
101 
102 void dbgPrintTunes(HekTunes &tunes)
103 {
104  HekTunes::MapJointTunes::iterator iter;
105 
106  fprintf(stderr, "HekTunes\n");
107  fprintf(stderr, "{\n");
108  fprintf(stderr, " m_fKinematicsHz = %lf;\n", tunes.m_fKinematicsHz);
109  fprintf(stderr, " m_fClearTorqueOffset = %lf;\n", tunes.m_fClearTorqueOffset);
110  fprintf(stderr, " m_fVelDerate = %lf;\n", tunes.m_fVelDerate);
111  fprintf(stderr, " m_eTrajNorm = %d;\n", tunes.m_eTrajNorm);
112  fprintf(stderr, " m_fTrajEpsilon = %lf;\n", tunes.m_fTrajEpsilon);
113  for(iter = tunes.m_mapJointTunes.begin();
114  iter != tunes.m_mapJointTunes.end();
115  ++iter)
116  {
117  fprintf(stderr, " joint %s\n", iter->first.c_str());
118  fprintf(stderr, " {\n");
119  fprintf(stderr, " m_fTolPos = %lf;\n", iter->second.m_fTolPos);
120  fprintf(stderr, " m_fTolVel = %lf;\n", iter->second.m_fTolVel);
121  fprintf(stderr, " m_fPidKp = %lf;\n", iter->second.m_fPidKp);
122  fprintf(stderr, " m_fPidKi = %lf;\n", iter->second.m_fPidKi);
123  fprintf(stderr, " m_fPidKd = %lf;\n", iter->second.m_fPidKd);
124  fprintf(stderr, " m_fOverTorqueTh = %lf;\n", iter->second.m_fOverTorqueTh);
125  fprintf(stderr, " };\n");
126  }
127  fprintf(stderr, "};\n");
128 }
129 
130 
131 // .............................................................................
132 // HekRobot Unit Tests
133 // .............................................................................
134 
135 /*!
136  * \brief Test HekRobot connected to hekateros.
137  *
138  * \return Returns 0 if test succeeds, else returns \h_lt 0.
139  */
140 static int testHekRobot()
141 {
142  /*!
143  * \brief Handy dandy checker.
144  */
145  #define BOT_CHK(conn) \
146  if( pRobot == NULL ) \
147  { \
148  printf("Error: Robot object does not exist - create first.\n"); \
149  continue; \
150  } \
151  else if( conn && !pRobot->isConnected() ) \
152  { \
153  printf("Error: Robot not connected.\n"); \
154  continue; \
155  }
156 
157  HekRobot *pRobot = NULL;
158  char c;
159  char line[256];
160  char arg1[64];
161  int nArgs;
162  double fVal;
163  bool bQuit = false;
164 
165  printf("%s", TestMenu);
166 
167  while( !bQuit )
168  {
169  printf("> ");
170 
171  if( gets(line) == NULL )
172  {
173  c = EOF;
174  }
175 
176  if( (nArgs = sscanf(line, " %c %s", &c, arg1)) == EOF )
177  {
178  continue;
179  }
180 
181 #if DEBGUG
182  fprintf(stderr, "#%d ", nArgs);
183  if( nArgs >= 1 )
184  {
185  fprintf(stderr, "c=%c ", c);
186  }
187  if( nArgs >= 2 )
188  {
189  fprintf(stderr, "arg1=%s ", arg1);
190  }
191  fprintf(stderr, "\n");
192 #endif
193 
194  switch(c)
195  {
196  // create robot object
197  case '1':
198  if( pRobot == NULL )
199  {
200  pRobot = new HekRobot;
201  printf("Robot created.\n");
202  }
203  else
204  {
205  printf("Robot already created.\n");
206  }
207  break;
208 
209  // delete robot object
210  case '2':
211  if( pRobot != NULL )
212  {
213  delete pRobot;
214  pRobot = NULL;
215  printf("Robot deleted.\n");
216  }
217  else
218  {
219  printf("Robot not created.\n");
220  }
221  break;
222 
223  // parse xml configuration and set robot descriptions
224  case '3':
225  BOT_CHK(false);
226  {
227  string str = nArgs<2? "/etc/hekateros.conf": arg1;
228  HekXmlCfg xml;
229  if( xml.loadFile(str) < 0 )
230  {
231  printf("Error: Loading XML file '%s' failed.\n", str.c_str());
232  }
233  else if( xml.setHekDescFromDOM(*pRobot->getHekDesc()) < 0 )
234  {
235  printf("Error: Setting robot description failed.\n");
236  }
237  else if( pRobot->getHekDesc()->markAsDescribed() < 0 )
238  {
239  printf("Error: Failed to finalize descriptions.\n");
240  }
241  else
242  {
243  printf("Robot description complete for %s.\n",
244  pRobot->getHekDesc()->getFullProdBrief().c_str());
245  }
246  }
247  break;
248 
249  // parse xml tune file
250  case '4':
251  BOT_CHK(false);
252  {
253  string str = nArgs<2? "/etc/hek_tune.conf": arg1;
254  fprintf(stderr, "rdk here 1\n");
255  HekXmlTune xml;
256  fprintf(stderr, "rdk here 2\n");
257  HekTunes tunes;
258  fprintf(stderr, "rdk here 3\n");
259  if( xml.loadFile(str) < 0 )
260  {
261  printf("Error: Loading XML file '%s' failed.\n", str.c_str());
262  }
263  else if( xml.setTunesFromDOM(tunes) < 0 )
264  {
265  printf("Error: Setting robot tune parameters failed.\n");
266  }
267  else
268  {
269  printf("Robot tuning complete.\n");
270  dbgPrintTunes(tunes);
271  }
272  }
273  break;
274 
275  // connect
276  case '5':
277  BOT_CHK(false);
278  {
279  string str = nArgs<2? "/dev/ttyUSB0": arg1;
280  if( pRobot->connect(str) < 0 )
281  {
282  printf("Error: Failed to connnect to '%s'.\n", str.c_str());
283  }
284  else
285  {
286  printf("Robot connected.\n");
287  }
288  }
289  break;
290 
291  // disconnect
292  case '6':
293  BOT_CHK(false);
294  if( pRobot->isConnected() )
295  {
296  pRobot->disconnect();
297  printf("Robot disconnected.\n");
298  }
299  else
300  {
301  printf("Robot not connected.\n");
302  }
303  break;
304 
305  // calibrate
306  case '7':
307  BOT_CHK(true);
308  {
309  string str = nArgs<2? "a": arg1;
310  if( (str == "s") || (str == "sync") )
311  {
312  if( pRobot->calibrate() < 0 )
313  {
314  printf("Error: Calibration failed.\n");
315  }
316  else
317  {
318  printf("Robot calibrated.\n");
319  }
320  }
321  else
322  {
323  if( pRobot->calibrateAsync() < 0 )
324  {
325  printf("Error: Async calibration failed.\n");
326  }
327  else
328  {
329  printf("Calibrating robot - enter '9' to cancel.\n");
330  }
331  }
332  }
333  break;
334 
335  // move
336  case '8':
337  BOT_CHK(true);
338  if( !pRobot->isCalibrated() )
339  {
340  printf("Error: Robot not calibrated.\n");
341  }
342  else if( nArgs < 2 )
343  {
344  printf("Error: Missing <move> argument.\n");
345  }
346  else if( strlen(arg1) < 2 )
347  {
348  printf("Error: \"%s\": Ambiguous <move>.\n", arg1);
349  }
350  else if( !strncmp(arg1, "calibrated", strlen(arg1)) )
351  {
352  pRobot->gotoZeroPtPos();
353  }
354  else if( !strncmp(arg1, "balanced", strlen(arg1)) )
355  {
356  pRobot->gotoBalancedPos();
357  }
358  else if( !strncmp(arg1, "park", strlen(arg1)) )
359  {
360  pRobot->gotoParkedPos();
361  }
362  else if( !strncmp(arg1, "gopen", strlen(arg1)) )
363  {
364  pRobot->openGripper();
365  }
366  else if( !strncmp(arg1, "gclose", strlen(arg1)) )
367  {
368  pRobot->closeGripper();
369  }
370  else
371  {
372  printf("Error: \"%s\": Unknown <move>.\n", arg1);
373  }
374  break;
375 
376  // move
377  case '9':
378  BOT_CHK(true);
379  if( !pRobot->isCalibrated() )
380  {
381  printf("Error: Robot not calibrated.\n");
382  }
383  else if( nArgs < 2 )
384  {
385  printf("Error: Missing <deg> argument.\n");
386  }
387  else if( sscanf(arg1, "%lf", &fVal) < 1 )
388  {
389  printf("Error: \"%s\": NaN.\n", arg1);
390  }
391  else
392  {
393  HekJointTrajectoryPoint trajPoint;
394  trajPoint.append(string("wrist_rot"), degToRad(fVal), 5.0);
395  pRobot->moveArm(trajPoint);
396  }
397  break;
398 
399  // cancel async task
400  case 'a':
401  BOT_CHK(true);
402  pRobot->cancelAsyncTask();
403  break;
404 
405  case 'd':
406  LOG_SET_THRESHOLD(LOG_LEVEL_DIAG3);
407  break;
408 
409  // show menu
410  case '?':
411  printf("%s", TestMenu);
412  break;
413 
414  // quit
415  case 'q':
416  case EOF:
417  bQuit = true;
418  break;
419 
420  default:
421  printf("'%c': huh?\n", c);
422  break;
423  }
424  }
425 
426  if( pRobot != NULL )
427  {
428  delete pRobot;
429  }
430 
431  return 0;
432 }
433 
434 
435 #ifndef JENKINS
436 
437 /*!
438  * \brief Test State Machine class.
439  *
440  * \par The Test:
441  * Construct a (2,3) Turing State Machin and run.
442  */
443 TEST(HEKROBOT, HEKROBOT)
444 {
445  EXPECT_TRUE( testHekRobot() == 0 );
446 }
447 
448 #endif // JENKINS
449 
450 
451 /*!
452  * \}
453  */
TEST(HEKROBOT, HEKROBOT)
Test State Machine class.
Joint points and trajectory class interfaces.
HekXmlCfg - <b><i>Hekateros</i></b> XML configuration class interface.
static int testHekRobot()
Test HekRobot connected to hekateros.
HekRobot - Hekateros Robot Class interface.
Top-level package include file.
double degToRad(double d)
Convert degrees to radians.
Definition: hekUtils.h:125
Hekateros common utilities.
Hekateros tuning.
The <b><i>Hekateros</i></b> namespace encapsulates all <b><i>Hekateros</i></b> related constructs...
Definition: hekateros.h:56
<b><i>Hekateros</i></b> XML tuning class interface.
static const char * TestMenu
Test menu.
Definition: ut-hekrobot.cxx:82