Hekateros  3.4.3
RoadNarrows Robotics Robot Arm Project
hekRobot.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Hekateros
4 //
5 // Library: libhekateros
6 //
7 // File: hekRobot.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-04-17 15:31:34 -0600 (Fri, 17 Apr 2015) $
12  * $Rev: 3942 $
13  *
14  * \brief HekRobot - Hekateros Robot Class implementation.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  * \author Daniel Packard (daniel@roadnarrows.com)
18  *
19  * \copyright
20  * \h_copy 2011-2017. RoadNarrows LLC.\n
21  * http://www.roadnarrows.com\n
22  * All Rights Reserved
23  */
24 /*
25  * @EulaBegin@
26  *
27  * Unless otherwise stated explicitly, all materials contained are copyrighted
28  * and may not be used without RoadNarrows LLC's written consent,
29  * except as provided in these terms and conditions or in the copyright
30  * notice (documents and software) or other proprietary notice provided with
31  * the relevant materials.
32  *
33  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
34  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
35  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
36  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
37  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
38  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
41  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
42  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
43  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
44  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
45  *
46  * @EulaEnd@
47  */
48 ////////////////////////////////////////////////////////////////////////////////
49 
50 #include <stdio.h>
51 #include <unistd.h>
52 #include <pthread.h>
53 #include <math.h>
54 
55 #include <string>
56 #include <vector>
57 #include <map>
58 
59 #include "rnr/rnrconfig.h"
60 #include "rnr/units.h"
61 #include "rnr/log.h"
62 #include "rnr/i2c.h"
63 
64 #include "Dynamixel/Dynamixel.h"
65 #include "Dynamixel/DynaComm.h"
66 #include "Dynamixel/DynaServo.h"
67 #include "Dynamixel/DynaChain.h"
68 #include "Dynamixel/DynaBgThread.h"
69 #include "Dynamixel/DynaError.h"
70 
71 #include "Hekateros/hekateros.h"
72 #include "Hekateros/hekTune.h"
73 #include "Hekateros/hekUtils.h"
74 #include "Hekateros/hekOptical.h"
75 #include "Hekateros/hekMonitor.h"
76 #include "Hekateros/hekSpec.h"
77 #include "Hekateros/hekDesc.h"
78 #include "Hekateros/hekXmlTune.h"
79 #include "Hekateros/hekJoint.h"
80 #include "Hekateros/hekTraj.h"
81 #include "Hekateros/hekKin.h"
82 #include "Hekateros/hekState.h"
83 #include "Hekateros/hekRobot.h"
84 
85 using namespace std;
86 using namespace hekateros;
87 
88 /*!
89  * \brief Define if heketeros has RN system board.
90  */
91 #undef HEK_SYS_BOARD
92 
93 /*!
94  * \brief Test for no execute flag.
95  *
96  * Only works in HekRobot methods.
97  *
98  * \return On true, return with HEK_OK.
99  */
100 #define HEK_TRY_NO_EXEC() \
101  do \
102  { \
103  if( m_bNoExec ) \
104  { \
105  return HEK_OK; \
106  } \
107  } while(0)
108 
109 /*!
110  * \brief Convenience macro for trying to get a servo object from dynamixel
111  * chain.
112  *
113  * Failure is considered a software bug since the chain has already be
114  * verified.
115  *
116  * Only works in HekRobot methods.
117  *
118  * \param [in] nServoId Servo id.
119  * \param [out] pServo Pointer to associated servo object.
120  *
121  * \return On failure, forces return from calling function with the appropriate
122  * error code.
123  */
124 #define HEK_TRY_GET_SERVO(nServoId, pServo) \
125  do \
126  { \
127  if( (pServo = m_pDynaChain->GetServo(nServoId)) == NULL ) \
128  { \
129  LOGERROR("BUG: Servo %d: Cannot find in dynamixel chain.", nServoId); \
130  return -HEK_ECODE_INTERNAL; \
131  } \
132  } while(0)
133 
134 
135 /*!
136  * \brief Test for connection.
137  *
138  * Only works in HekRobot methods.
139  *
140  * \return On failure, forces return from calling function with the appropriate
141  * error code.
142  */
143 #define HEK_TRY_CONN() \
144  do \
145  { \
146  if( !isConnected() ) \
147  { \
148  LOGERROR("Robot is not connected."); \
149  return -HEK_ECODE_NO_EXEC; \
150  } \
151  } while(0)
152 
153 /*!
154  * \brief Test for calibration.
155  *
156  * Only works in HekRobot methods.
157  *
158  * \return On failure, forces return from calling function with the appropriate
159  * error code.
160  */
161 #define HEK_TRY_CALIB() \
162  do \
163  { \
164  if( m_eOpState != HekOpStateCalibrated ) \
165  { \
166  LOGERROR("Robot is not calibrated."); \
167  return -HEK_ECODE_NO_EXEC; \
168  } \
169  } while(0)
170 
171 /*!
172  * \brief Test for not estop.
173  *
174  * Only works in HekRobot methods.
175  *
176  * \return On failure, forces return from calling function with the appropriate
177  * error code.
178  */
179 #define HEK_TRY_NOT_ESTOP() \
180  do \
181  { \
182  if( m_bIsEStopped ) \
183  { \
184  LOGERROR("Robot is emergency stopped."); \
185  return -HEK_ECODE_NO_EXEC; \
186  } \
187  } while(0)
188 
189 
190 // -----------------------------------------------------------------------------
191 // Class HekRobot
192 // -----------------------------------------------------------------------------
193 
194 HekRobot::HekRobot(bool bNoExec)
195 {
196  // state
197  m_bNoExec = bNoExec;
198  m_eRobotMode = HekRobotModeAuto;
199  m_eOpState = HekOpStateUncalibrated;
200  m_bIsEStopped = false;
201  m_bAlarmState = false;
202  m_bAreServosPowered = false;
203  m_bAtBalancedPos = false;
204  m_bAtParkedPos = false;
205 
206  // dynamixel i/f
207  m_pDynaComm = NULL;
208  m_pDynaChain = NULL;
209  m_pDynaBgThread = NULL;
210 
211  // asynchronous task control and synchronization
212  m_eAsyncTaskState = HekAsyncTaskStateIdle;
213  m_rcAsyncTask = HEK_OK;
214  m_eAsyncTaskId = AsyncTaskIdNone;
215  m_pAsyncTaskArg = NULL;
216 
217  pthread_mutex_init(&m_mutex, NULL);
218 }
219 
220 HekRobot::~HekRobot()
221 {
222  disconnect();
223  pthread_mutex_destroy(&m_mutex);
224 }
225 
226 int HekRobot::connect(const string &strDevDynabus, int nBaudRateDynabus,
227  const string &strDevArduino, int nBaudRateArduino)
228 {
229  string strDevName; // real device name
230  int rc; // return code
231 
232  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
233  // Pre-connect requirements.
234  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
235 
236  //
237  // Need a robot description before preceeding. The controlling application,
238  // typically a ROS node, provides the description. The desription is normally
239  // the parsed data found in /etc/hekaeros/hekateros.conf.
240  //
241  if( !m_descHek.isDescribed() )
242  {
243  LOGERROR("Undefined Hekateros description - "
244  "don't know how to initialized properly.");
245  return -HEK_ECODE_BAD_OP;
246  }
247 
248 
249  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
250  // Dynabus communication and configuration.
251  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252 
253  // get the real device name, not a symbolic link
254  strDevName = getRealDeviceName(strDevDynabus);
255 
256  // open (proxied) serial device to dynamixel bus
257  m_pDynaComm = DynaComm::New(strDevName.c_str(), nBaudRateDynabus);
258 
259  if( m_pDynaComm == NULL )
260  {
261  LOGERROR("Failed to create dynamixel interface on '%s'@%d.",
262  strDevName.c_str(), nBaudRateDynabus);
263  return -HEK_ECODE_DYNA;
264  }
265  LOGDIAG2("Created dynamixel interface on '%s'@%d.",
266  strDevName.c_str(), nBaudRateDynabus);
267 
268  // create dynamixel bus chain
269  m_pDynaChain = new DynaChain(*m_pDynaComm);
270 
271  // scan Dynabus for all attached servos
272  if( (rc = scanDynaBus(3)) < 0 )
273  {
274  LOGERROR("Hekateros dynamixel bus scan failed.");
275  disconnect();
276  return rc;
277  }
278  LOGDIAG2("Scanned for servos.");
279 
280  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
281  // Build specifications, set tuning parameters, and configure.
282  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
283 
284  //
285  // Convert fixed specifications to joint operation descriptions. The
286  // specifications are compliled-in, product-specific link, joint, servo data.
287  //
288  // Required: product descriptions, scanned servos, and monitor object.
289  //
290  if( (rc = convertSpecs()) < 0 )
291  {
292  LOGERROR("Failed to convert product specifications to "
293  "operations parameters.");
294  disconnect();
295  return rc;
296  }
297  LOGDIAG2("Converted product specifications to operations parameters.");
298 
299  //
300  // Adjust tuning parameters from any defaults specified in the converted
301  // joint descriptions.
302  //
303  // Required: joint descriptions and tuning paramaters.
304  //
305  adjustTuningFromSpecs();
306 
307  //
308  // Override any tuning parameters from the optional, user-specified tuning
309  // XML file.
310  //
311  HekXmlTune xml;
312 
313  // parse tune XML file and set tuning parameter overrides
314  xml.load(m_tunes, HekSysCfgPath, HekEtcTune);
315 
316  //
317  // Configure servos EEPROM and RAM control tables for operation.
318  //
319  // Required: joint descriptions and scanned servos.
320  //
321  configServos();
322 
323  //
324  // Mark all joints for calibration.
325  //
326  resetCalibStateForAllJoints(true);
327 
328 
329  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
330  // Kinodynmics thread.
331  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
332 
333  // create active dynamics and kinematics chain
334  m_pKin = new HekKinematics(*m_pDynaChain, m_jointsArm, m_tunes);
335 
336  // run kinematics thread at the given Hertz
337  m_pKin->runThread(m_tunes.getKinematicsHz());
338 
339  LOGDIAG2("Kinematics thread started.");
340 
341  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
342  // Health and safety monitoring thread.
343  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
344 
345  // get the real device name, not a symbolic link
346  strDevName = getRealDeviceName(strDevArduino);
347 
348  // open all interfaces to monitoring hardware and create monitoring thread
349  if( (rc = m_monitor.open(getVersionNum(), strDevName, nBaudRateArduino)) < 0 )
350  {
351  LOGERROR("Hekateros monitor interface failed to open on '%s'@%d.",
352  strDevName.c_str(), nBaudRateArduino);
353  disconnect();
354  return rc;
355  }
356  LOGDIAG2("Hekateros monitor interface open on '%s'@%d.",
357  strDevName.c_str(), nBaudRateArduino);
358 
359  m_bAlarmState = false;
360  m_monitor.markAlarmCond(m_bAlarmState);
361 
362  // add chain to monitor
363  m_monitor.addServoChainToMonitor(m_pDynaChain);
364 
365  // add kinematics to monitor
366  m_monitor.addKinematicsToMonitor(m_pKin);
367 
368  // start robot monitoring health and safety thread
369  m_monitor.start();
370 
371  LOGDIAG2("Monitor thread started.");
372 
373 
374  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
375  // Final touches
376  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
377 
378  LOGDIAG1("Connected to Hekateros.");
379 
380  //
381  // DBG DANGER, WILL ROBINSON
382  //
383  // Uncomment the next line to circumvent calibration step. Make sure arm
384  // is at the zero point.
385  //
386  //fauxcalibrate();
387  //
388  // DBG DANGER, WILL ROBINSON
389  //
390 
391  return HEK_OK;
392 }
393 
394 int HekRobot::disconnect()
395 {
396  // close monitor
397  m_monitor.close();
398 
399  if( m_pKin != NULL )
400  {
401  delete m_pKin;
402  m_pKin = NULL;
403  }
404 
405  // delete dynamixel chain
406  if( m_pDynaChain != NULL )
407  {
408  m_pDynaChain->EStop(); // == force release of arm motors
409  delete m_pDynaChain;
410  m_pDynaChain = NULL;
411  }
412 
413  // close connection and delete dynamixel communication object
414  if( m_pDynaComm != NULL )
415  {
416  if( m_pDynaComm->IsOpen() )
417  {
418  m_pDynaComm->Close();
419  }
420  delete m_pDynaComm;
421  m_pDynaComm = NULL;
422  }
423 
424  // reset robot state
425  m_eRobotMode = HekRobotModeAuto;
426  m_eOpState = HekOpStateUncalibrated;
427  m_bIsEStopped = false;
428  m_bAlarmState = false;
429  m_bAreServosPowered = false;
430  m_bAtBalancedPos = false;
431  m_bAtParkedPos = false;
432 
433  LOGDIAG1("Disconnected from Hekateros.");
434 }
435 
436 int HekRobot::calibrate(bool bForceRecalib)
437 {
438  HekCalibStretch calib(*this);
439  int rc;
440 
441  HEK_TRY_NO_EXEC();
442  HEK_TRY_CONN();
443 
444  // lock the arm
445  freeze();
446 
447  // robot is now uncalibrated
448  m_eOpState = HekOpStateUncalibrated;
449 
450  // mark relevant joints for recalibration
451  resetCalibStateForAllJoints(bForceRecalib);
452 
453  // robot calibration started
454  m_eOpState = HekOpStateCalibrating;
455 
456  // now physically calibrate the arm
457  if( (rc = calib.calibrate()) < 0 )
458  {
459  LOGERROR("Failed to calibrate Hekateros.");
460  m_eOpState = HekOpStateUncalibrated;
461  return rc;
462  }
463 
464  //
465  // Should be all calibrated at this point.
466  //
467 
468  // synchronize robot operation state to collective joint operational states
469  if( (m_eOpState = determineRobotOpState()) != HekOpStateCalibrated )
470  {
471  LOGERROR("BUG: Failed to calibrate Hekateros.");
472  return -HEK_ECODE_INTERNAL;
473  }
474 
475  // arm is calibrated
476  gotoZeroPtPos();
477 
478  LOGDIAG1("Hekateros calibrated.");
479 
480  return HEK_OK;
481 }
482 
483 int HekRobot::calibrateAsync(bool bForceRecalib)
484 {
485  if( m_eAsyncTaskState != HekAsyncTaskStateIdle )
486  {
487  LOGERROR("Already executing asynchronous task.");
488  return -HEK_ECODE_NO_RSRC;
489  }
490  else
491  {
492  m_eAsyncTaskId = AsyncTaskIdCalibrate;
493  m_pAsyncTaskArg = (void *)bForceRecalib;
494 
495  return createAsyncThread();
496  }
497 }
498 
499 void HekRobot::reload()
500 {
501  HekXmlTune xml;
502 
503  // parse user tune parameter overrides
504  if( xml.load(m_tunes,HekSysCfgPath, HekEtcTune) == HEK_OK )
505  {
506  LOGDIAG2("User specified tuning parameters reloaded from XML file %s.",
507  HekEtcTune);
508 
509  m_pKin->reload(m_tunes);
510  }
511 }
512 
513 int HekRobot::gotoBalancedPos()
514 {
515  HekJointTrajectoryPoint trajPoint;
516  MapRobotJoints::iterator iter;
517 
518  int nMasterServoId;
519  HekRobotJoint *pJoint;
520  int rc;
521 
522  HEK_TRY_CONN();
523  HEK_TRY_CALIB();
525 
526  //
527  // Build trajoectory point.
528  //
529  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
530  {
531  nMasterServoId = iter->first;
532  pJoint = &(iter->second);
533 
534  switch( nMasterServoId )
535  {
536  case HekServoIdBase:
537  trajPoint.append(pJoint->m_strName, pJoint->m_fBalPosRads,
538  degToRad(60.0));
539  break;
540  case HekServoIdShoulderL:
541  trajPoint.append(pJoint->m_strName, pJoint->m_fBalPosRads,
542  degToRad(40.0));
543  break;
544  case HekServoIdElbow:
545  trajPoint.append(pJoint->m_strName, pJoint->m_fBalPosRads,
546  degToRad(35.0));
547  break;
548  case HekServoIdWristPitch:
549  trajPoint.append(pJoint->m_strName, pJoint->m_fBalPosRads,
550  degToRad(50.0));
551  break;
552  case HekServoIdWristRot:
553  trajPoint.append(pJoint->m_strName, pJoint->m_fBalPosRads,
554  degToRad(60.0));
555  break;
556  case HekServoIdGraboid:
557  trajPoint.append(pJoint->m_strName, pJoint->m_fBalPosRads,
558  degToRad(20.0));
559  break;
560  default:
561  break;
562  }
563  }
564 
565  if( (rc = moveArm(trajPoint)) < 0 )
566  {
567  LOGERROR("Move to pre-defined balanced position failed.");
568  }
569  else
570  {
571  m_bAtBalancedPos = true;
572  LOGDIAG2("Hekateros at balanced position.");
573  }
574 
575  return rc;
576 }
577 
578 int HekRobot::gotoParkedPos()
579 {
580  HekJointTrajectoryPoint trajPoint;
581  MapRobotJoints::iterator iter;
582 
583  int nMasterServoId;
584  HekRobotJoint *pJoint;
585  int rc;
586 
587  HEK_TRY_CONN();
588  HEK_TRY_CALIB();
590 
591  //
592  // Build trajoectory point.
593  //
594  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
595  {
596  nMasterServoId = iter->first;
597  pJoint = &(iter->second);
598 
599  switch( nMasterServoId )
600  {
601  case HekServoIdBase:
602  trajPoint.append(pJoint->m_strName, pJoint->m_fParkPosRads,
603  degToRad(60.0));
604  break;
605  case HekServoIdShoulderL:
606  trajPoint.append(pJoint->m_strName, pJoint->m_fParkPosRads,
607  degToRad(40.0));
608  break;
609  case HekServoIdElbow:
610  trajPoint.append(pJoint->m_strName, pJoint->m_fParkPosRads,
611  degToRad(35.0));
612  break;
613  case HekServoIdWristPitch:
614  trajPoint.append(pJoint->m_strName, pJoint->m_fParkPosRads,
615  degToRad(50.0));
616  break;
617  case HekServoIdWristRot:
618  trajPoint.append(pJoint->m_strName, pJoint->m_fParkPosRads,
619  degToRad(60.0));
620  break;
621  case HekServoIdGraboid:
622  trajPoint.append(pJoint->m_strName, pJoint->m_fParkPosRads,
623  degToRad(20.0));
624  break;
625  default:
626  break;
627  }
628  }
629 
630  if( (rc = moveArm(trajPoint)) < 0 )
631  {
632  LOGERROR("Move to pre-defined parked position failed.");
633  }
634  else
635  {
636  m_bAtParkedPos = true;
637  LOGDIAG2("Hekateros at parked position.");
638  }
639 
640  return rc;
641 }
642 
643 int HekRobot::gotoZeroPtPos()
644 {
645  HekJointTrajectoryPoint trajPoint;
646  MapRobotJoints::iterator iter;
647 
648  int nMasterServoId;
649  HekRobotJoint *pJoint;
650  int rc;
651 
652  HEK_TRY_CONN();
653  HEK_TRY_CALIB();
655 
656  //
657  // Build trajoectory point.
658  //
659  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
660  {
661  nMasterServoId = iter->first;
662  pJoint = &(iter->second);
663 
664  switch( nMasterServoId )
665  {
666  case HekServoIdBase:
667  trajPoint.append(pJoint->m_strName, pJoint->m_fCalibPosRads,
668  degToRad(60.0));
669  break;
670  case HekServoIdShoulderL:
671  trajPoint.append(pJoint->m_strName, pJoint->m_fCalibPosRads,
672  degToRad(30.0));
673  break;
674  case HekServoIdElbow:
675  trajPoint.append(pJoint->m_strName, pJoint->m_fCalibPosRads,
676  degToRad(25.0));
677  break;
678  case HekServoIdWristPitch:
679  trajPoint.append(pJoint->m_strName, pJoint->m_fCalibPosRads,
680  degToRad(50.0));
681  break;
682  case HekServoIdWristRot:
683  trajPoint.append(pJoint->m_strName, pJoint->m_fCalibPosRads,
684  degToRad(60.0));
685  break;
686  case HekServoIdGraboid:
687  trajPoint.append(pJoint->m_strName, pJoint->m_fCalibPosRads,
688  degToRad(20.0));
689  break;
690  default:
691  break;
692  }
693  }
694 
695  if( (rc = moveArm(trajPoint)) < 0 )
696  {
697  LOGERROR("Move to pre-defined calibrated zero point position failed.");
698  }
699  else
700  {
701  LOGDIAG2("Hekateros at zero point position.");
702  }
703 
704  return rc;
705 }
706 
707 int HekRobot::openGripper()
708 {
709  HekJointTrajectoryPoint trajPoint;
710 
711  HekRobotJoint *pJoint;
712  int rc;
713 
714  HEK_TRY_CONN();
715  HEK_TRY_CALIB();
717 
718  if( (pJoint = getArmJoint(HekServoIdGraboid)) == NULL )
719  {
720  LOGERROR("No gripper end effector found.");
721  return -HEK_ECODE_NO_RSRC;
722  }
723 
724  trajPoint.append(pJoint->m_strName, pJoint->m_fMaxSoftLimitRads,
725  degToRad(60.0));
726 
727  if( (rc = moveArm(trajPoint)) < 0 )
728  {
729  LOGERROR("Move to pre-defined gripper open position failed.");
730  }
731  else
732  {
733  LOGDIAG2("Hekateros gripper opened.");
734  }
735 
736  return rc;
737 }
738 
739 int HekRobot::closeGripper()
740 {
741  HekJointTrajectoryPoint trajPoint;
742 
743  HekRobotJoint *pJoint;
744  int rc;
745 
746  HEK_TRY_CONN();
747  HEK_TRY_CALIB();
749 
750  if( (pJoint = getArmJoint(HekServoIdGraboid)) == NULL )
751  {
752  LOGERROR("No gripper end effector found.");
753  return -HEK_ECODE_NO_RSRC;
754  }
755 
756  trajPoint.append(pJoint->m_strName, pJoint->m_fMinSoftLimitRads,
757  degToRad(60.0));
758 
759  if( (rc = moveArm(trajPoint)) < 0 )
760  {
761  LOGERROR("Move to pre-defined gripper closed position failed.");
762  }
763  else
764  {
765  LOGDIAG2("Hekateros gripper closed.");
766  }
767 
768  return rc;
769 }
770 
771 int HekRobot::estop()
772 {
773  HEK_TRY_NO_EXEC();
774  HEK_TRY_CONN();
775 
776  m_pKin->estop();
777 
778  m_bIsEStopped = true;
779  m_bAreServosPowered = false;
780 
781  m_monitor.markEStopCond(m_bIsEStopped);
782  m_monitor.markPoweredCond(m_bAreServosPowered);
783 
784  m_lastTrajArm.clear();
785 
786  m_bAlarmState = true;
787  m_monitor.markAlarmCond(m_bAlarmState);
788 
789  LOGDIAG1("Hekateros emergency stopped.");
790 
791  return HEK_OK;
792 }
793 
794 int HekRobot::freeze()
795 {
796  HEK_TRY_NO_EXEC();
797  HEK_TRY_CONN();
798 
799  m_bAreServosPowered = true;
800 
801  m_monitor.markPoweredCond(m_bAreServosPowered);
802 
803  m_lastTrajArm.clear();
804 
805  m_pKin->freeze();
806 
807  LOGDIAG2("Hekateros frozen at current position.");
808 
809  return HEK_OK;
810 }
811 
812 int HekRobot::release()
813 {
814  HEK_TRY_NO_EXEC();
815  HEK_TRY_CONN();
816 
817  m_bAreServosPowered = false;
818 
819  m_monitor.markPoweredCond(m_bAreServosPowered);
820 
821  m_lastTrajArm.clear();
822 
823  m_pKin->release();
824 
825  LOGDIAG2("Hekateros servo drives released.");
826 
827  return HEK_OK;
828 }
829 
830 int HekRobot::stop(const vector<string> &vecNames)
831 {
832  int n;
833 
834  HEK_TRY_NO_EXEC();
835  HEK_TRY_CONN();
837 
838  m_lastTrajArm.clear();
839 
840  n = m_pKin->stop(vecNames);
841 
842  LOGDIAG3("%d joints stopped.", n);
843 
844  return n;
845 }
846 
847 int HekRobot::clearAlarms()
848 {
849  int iter; // servo iterator
850  int nServoId; // servo id
851  DynaServo *pServo; // servo
852 
853  HEK_TRY_CONN();
854 
855  release();
856 
857  //
858  // Try to clear alarms for all servos.
859  //
860  for(nServoId = m_pDynaChain->IterStart(&iter);
861  nServoId != DYNA_ID_NONE;
862  nServoId = m_pDynaChain->IterNext(&iter))
863  {
864  pServo = m_pDynaChain->GetServo(nServoId);
865 
866  // over torque alarm zero's torque limit - reload from EEPROM
867  pServo->ReloadMaxTorqueLimit();
868  }
869 
870  //
871  // Clear hekateros alarm led to provide visual feedback to the user. The
872  // background check may relight the alarm led if alarms still persist.
873  //
874  m_bAlarmState = false;
875  m_monitor.markAlarmCond(m_bAlarmState);
876 
877  return HEK_OK;
878 }
879 
880 int HekRobot::moveArm(HekJointTrajectoryPoint &trajectoryPoint)
881 {
882  int rc;
883 
884  HEK_TRY_CONN();
885  HEK_TRY_CALIB();
887 
888  lock();
889 
890  if( !m_bAreServosPowered )
891  {
892  m_bAreServosPowered = true;
893 
894  m_monitor.markPoweredCond(m_bAreServosPowered);
895  }
896 
897  rc = m_pKin->move(trajectoryPoint);
898 
899  unlock();
900 
901  return rc >= 0? HEK_OK: rc;
902 }
903 
904 int HekRobot::getRobotState(HekRobotState &robotState)
905 {
906  static int TuneStoppedSpeed = 9; ///< stopped speed
907 
908  int iter; // servo iterator
909  int nServoId; // servo id
910  DynaServo *pServo; // servo
911  bool bIsMoving; // robot is [not] moving
912  HekServoHealth health; // servo health
913  bool bOldAlarmState; // old alarm state
914 
915  robotState.clear();
916 
917  bOldAlarmState = m_bAlarmState;
918  m_bAlarmState = m_monitor.getAlarmCond();
919 
920  robotState.m_eRobotMode = m_eRobotMode;
921  robotState.m_eIsEStopped = m_bIsEStopped?
922  HekTriStateTrue: HekTriStateFalse;
923  robotState.m_eIsCalibrated = m_eOpState == HekOpStateCalibrated?
924  HekTriStateTrue: HekTriStateFalse;
925  robotState.m_eAreDrivesPowered = m_bAreServosPowered?
926  HekTriStateTrue: HekTriStateFalse;
927  robotState.m_eIsMotionPossible = (m_eOpState == HekOpStateCalibrated) &&
928  !m_bAlarmState && !m_bNoExec?
929  HekTriStateTrue: HekTriStateFalse;
930 
931  robotState.m_eIsInError = HekTriStateFalse;
932  robotState.m_nErrorCode = HEK_OK;
933  bIsMoving = false;
934 
935  for(nServoId = m_pDynaChain->IterStart(&iter);
936  nServoId != DYNA_ID_NONE;
937  nServoId = m_pDynaChain->IterNext(&iter))
938  {
939  pServo = m_pDynaChain->GetServo(nServoId);
940 
941  health.m_nServoId = nServoId;
942  health.m_fTemperature = pServo->CvtRawTempToC(pServo->GetCurTemp());
943  health.m_fVoltage = pServo->CvtRawVoltToVolts(pServo->GetCurVolt());
944  health.m_uAlarms = pServo->GetAlarms();
945 
946  if( health.m_uAlarms != DYNA_ALARM_NONE )
947  {
948  robotState.m_eIsInError = HekTriStateTrue;
949  robotState.m_nErrorCode = -HEK_ECODE_ALARMED;
950  }
951 
952  if( iabs(pServo->GetCurSpeed()) > TuneStoppedSpeed )
953  {
954  bIsMoving = true;
955  }
956 
957  robotState.m_vecServoHealth.push_back(health);
958  }
959 
960  // estop overrides other alarms
961  if( m_bIsEStopped )
962  {
963  robotState.m_eIsInError = HekTriStateTrue;
964  robotState.m_nErrorCode = -HEK_ECODE_ESTOP;
965  }
966 
967  // new alarm state other than estop.
968  else if( m_bAlarmState && (m_bAlarmState != bOldAlarmState) )
969  {
970  robotState.m_eIsInError = HekTriStateTrue;
971  robotState.m_nErrorCode = -HEK_ECODE_ALARMED;
972  }
973 
974  robotState.m_eIsInMotion = bIsMoving? HekTriStateTrue: HekTriStateFalse;
975 
976  return HEK_OK;
977 }
978 
979 int HekRobot::getJointState(HekJointStatePoint &jointStatePoint)
980 {
981  MapRobotJoints::iterator iter; // kinematic chain iterator
982  int nMasterServoId; // master servo id
983  HekRobotJoint *pJoint; // robotic joint
984  DynaServo *pServo; // servo
985  HekJointState jointState; // working joint state
986  byte_t uMask; // working bit mask
987  int i; // working index
988 
989  HEK_TRY_CONN();
990 
991  jointStatePoint.clear();
992 
993  jointStatePoint.setKinematicChainName("arm");
994 
995  //
996  // Build joint state point.
997  //
998  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
999  {
1000  nMasterServoId = iter->first;
1001  pJoint = &(iter->second);
1002 
1003  HEK_TRY_GET_SERVO(nMasterServoId, pServo);
1004 
1005  // identifiers
1006  jointState.m_strName = pJoint->m_strName;
1007  jointState.m_eOpState = pJoint->m_eOpState;
1008  jointState.m_nMasterServoId = nMasterServoId;
1009  jointState.m_nSlaveServoId = pJoint->m_nSlaveServoId;
1010 
1011  // joint dynamics
1012  m_pKin->getFilteredJointCurPosVel(jointState.m_strName,
1013  jointState.m_fPosition,
1014  jointState.m_fVelocity);
1015 
1016  // servo dynamics
1017  jointState.m_nOdPos = pServo->GetOdometer();
1018  jointState.m_nEncPos = pServo->OdometerToEncoder(jointState.m_nOdPos);
1019  jointState.m_nSpeed = pServo->GetCurSpeed();
1020  jointState.m_fEffort = (double)pServo->GetCurLoad();
1021 
1022  // optical limit switch states
1023  for(int i=0; i<HekOptLimitMaxPerJoint; ++i)
1024  {
1025  jointState.m_eOptSwitch[i] = m_monitor.getJointLimitTriState(pJoint, i);
1026  }
1027 
1028  // add state
1029  jointStatePoint.append(jointState);
1030  }
1031 
1032  return HEK_OK;
1033 }
1034 
1035 int HekRobot::getTrajectoryState(HekJointTrajectoryFeedback &trajectoryFeedback)
1036 {
1037  HekJointStatePoint jointStatePoint;
1038  int iActual;
1039  int i;
1040  int rc;
1041 
1042  trajectoryFeedback.clear();
1043 
1044  // last issued trajectory is the desired trajectory
1045  trajectoryFeedback[HekJointTrajectoryFeedback::TRAJ_DESIRED] = m_lastTrajArm;
1046 
1047  // retrieve joint state
1048  if( (rc = getJointState(jointStatePoint)) < 0 )
1049  {
1050  LOGERROR("Cannot retrieve joint state data.");
1051  return rc;
1052  }
1053 
1054  // copy joint state to actual trajectory
1055  iActual = HekJointTrajectoryFeedback::TRAJ_ACTUAL;
1056 
1057  for(i=0; i<jointStatePoint.getNumPoints(); ++i)
1058  {
1059  trajectoryFeedback[iActual].append(jointStatePoint[i].m_strName,
1060  jointStatePoint[i].m_fPosition,
1061  jointStatePoint[i].m_fVelocity);
1062  }
1063 
1064  return HEK_OK;
1065 }
1066 
1067 bool HekRobot::isInMotion()
1068 {
1069  static int TuneStoppedSpeed = 9; ///< stopped speed
1070 
1071  int iter; // servo iterator
1072  int nServoId; // servo id
1073  DynaServo *pServo; // servo
1074 
1075  for(nServoId = m_pDynaChain->IterStart(&iter);
1076  nServoId != DYNA_ID_NONE;
1077  nServoId = m_pDynaChain->IterNext(&iter))
1078  {
1079  pServo = m_pDynaChain->GetServo(nServoId);
1080 
1081  if( iabs(pServo->GetCurSpeed()) > TuneStoppedSpeed )
1082  {
1083  return true;
1084  }
1085  }
1086 
1087  return false;
1088 }
1089 
1090 int HekRobot::scanDynaBus(int nMaxTries)
1091 {
1092  static uint_t usecTry = 500000;
1093 
1094  int nNumServosExpected; // number of expected and required servos
1095  int nNumServosScanned; // number of scanned servos
1096  int nNumServosMatched; // number of scanned and matched servos
1097  int nTries; // scan attempts
1098  int nServoId; // servo id
1099  int iter; // servo iterator
1100  int rc; // return code
1101 
1102  nNumServosExpected = m_descHek.getNumServos();
1103 
1104  //
1105  // Scan hardware.
1106  //
1107  for(nTries=0; nTries<nMaxTries; ++nTries)
1108  {
1109  LOGDIAG3("Scanning Hekateros hardware - attempt %d of %d.",
1110  nTries+1, nMaxTries);
1111 
1112  // scan for servos
1113  nNumServosScanned = m_pDynaChain->AddNewServosByScan();
1114 
1115  //
1116  // Scanned at least the required number.
1117  //
1118  if( nNumServosScanned >= nNumServosExpected )
1119  {
1120  // check scanned ids against required
1121  for(nServoId = m_pDynaChain->IterStart(&iter), nNumServosMatched=0;
1122  nServoId != DYNA_ID_NONE;
1123  nServoId = m_pDynaChain->IterNext(&iter))
1124  {
1125  // matched
1126  if( m_descHek.hasServo(nServoId) )
1127  {
1128  ++nNumServosMatched;
1129  }
1130 
1131  // unmathced
1132  else
1133  {
1134  LOGWARN("Servo %d unexpected - uncontrolled.", nServoId);
1135  }
1136  }
1137 
1138  // servos matched
1139  if( nNumServosMatched == nNumServosExpected )
1140  {
1141  rc = HEK_OK;
1142  break;
1143  }
1144 
1145  // some required servos are missing
1146  else
1147  {
1148  LOGERROR("Match %d scanned servo ids, expected %d required matches.",
1149  nNumServosMatched, nNumServosExpected);
1150  rc = -HEK_ECODE_FORMAT;
1151  }
1152  }
1153 
1154  //
1155  // Scan failed to detect the minimum number of servos.
1156  //
1157  else
1158  {
1159  LOGERROR("Scanned %d servos, expected %d.",
1160  nNumServosScanned, nNumServosExpected);
1161  rc = -HEK_ECODE_NO_RSRC;
1162  }
1163 
1164  usleep(usecTry);
1165  }
1166 
1167  if( rc == HEK_OK )
1168  {
1169  LOGDIAG3("Hekateros dynamixel bus hardware scanned successfully.");
1170  }
1171 
1172  return rc;
1173 }
1174 
1175 int HekRobot::convertSpecs()
1176 {
1177  HekDescArm *pDescArm;
1178  HekDescEE *pDescEE;
1179  HekSpecJoint_T *pSpecJoint;
1180  HekSpecServo_T *pSpecServo;
1181  int nServoId;
1182  HekRobotJoint *pJoint;
1183  int i;
1184  int rc;
1185 
1186  m_jointsArm.clear();
1187  m_jointsEquipDeck.clear();
1188  m_jointsAux.clear();
1189  m_imapJoints.clear();
1190 
1191  pDescArm = m_descHek.getArmDesc();
1192  pDescEE = m_descHek.getEEDesc();
1193 
1194  //
1195  // Build up arm kinematic chain.
1196  //
1197  for(i = 0; i < pDescArm->m_spec.m_nDoF; ++i)
1198  {
1199  // joint specification
1200  pSpecJoint = pDescArm->m_spec.getJointSpecAt(i);
1201 
1202  // master servo id associated with joint
1203  nServoId = pSpecJoint->m_nMasterServoId;
1204  pJoint = &m_jointsArm[nServoId];
1205 
1206  // servo specification
1207  if( (pSpecServo = pDescArm->m_spec.getServoSpec(nServoId)) == NULL )
1208  {
1209  LOGERROR("Servo %d: Cannot find servo specification.", nServoId);
1210  return -HEK_ECODE_NO_EXEC;
1211  }
1212 
1213  // add rebotic joint
1214  rc = addRobotJoint(pSpecJoint, pSpecServo, m_jointsArm, m_imapJoints);
1215  if( rc < 0 )
1216  {
1217  LOGERROR("Servo %d: Cannot add to kinematic chain.", nServoId);
1218  return rc;
1219  }
1220 
1221  // add any optical limit switches
1222  if( (rc = m_monitor.addJointLimitsToMonitor(pSpecJoint, pJoint)) < 0 )
1223  {
1224  LOGERROR("Servo %d: Cannot add to optical limit(s).", nServoId);
1225  return rc;
1226  }
1227  }
1228 
1229  //
1230  // Add end effector joints to arm kinematic chain.
1231  //
1232  for(i = 0; i < pDescEE->m_spec.m_nDoF; ++i)
1233  {
1234  // joint specification
1235  pSpecJoint = pDescEE->m_spec.getJointSpecAt(i);
1236 
1237  // master servo id associated with joint
1238  nServoId = pSpecJoint->m_nMasterServoId;
1239  pJoint = &m_jointsArm[nServoId];
1240 
1241  // servo specification
1242  if( (pSpecServo = pDescEE->m_spec.getServoSpec(nServoId)) == NULL )
1243  {
1244  LOGERROR("Servo %d: Cannot find servo specification.", nServoId);
1245  return -HEK_ECODE_NO_EXEC;
1246  }
1247 
1248  // add rebotic joint
1249  rc = addRobotJoint(pSpecJoint, pSpecServo, m_jointsArm, m_imapJoints);
1250  if( rc < 0 )
1251  {
1252  LOGERROR("Servo %d: Cannot add to kinematic chain.", nServoId);
1253  return rc;
1254  }
1255 
1256  // add any optical limit switches
1257  if( (rc = m_monitor.addJointLimitsToMonitor(pSpecJoint, pJoint)) < 0 )
1258  {
1259  LOGERROR("Servo %d: Cannot add to optical limit(s).", nServoId);
1260  return rc;
1261  }
1262  }
1263 
1264  //
1265  // TODO: Add equipment deck and auxiliary effector chains here.
1266  //
1267 
1268  return HEK_OK;
1269 }
1270 
1271 int HekRobot::addRobotJoint(HekSpecJoint_T *pSpecJoint,
1272  HekSpecServo_T *pSpecServo,
1273  MapRobotJoints &kin,
1274  IMapRobotJoints &imap)
1275 {
1276  int nMasterServoId; // master servo id
1277  DynaServo *pServo; // servo
1278  uint_t uTicks; // ticks
1279  double fAngleMin; // min angle(deg) in servo mode
1280  double fAngleMax; // max angle(deg) in servo mode
1281  double fMaxRpm; // max unloaded rpm
1282  double fDegrees; // working degrees
1283  double fRadians; // working radians
1284  HekRobotJoint joint; // robotic joint
1285  int i; // working index
1286 
1287  // master servo id associated with joint
1288  nMasterServoId = pSpecJoint->m_nMasterServoId;
1289 
1290  // dynamixel servo object in dynamixel chain
1291  if( (pServo = m_pDynaChain->GetServo(nMasterServoId)) == NULL )
1292  {
1293  LOGERROR("Servo %d: Cannot find servo in dynamixel chain.", nMasterServoId);
1294  return -HEK_ECODE_NO_EXEC;
1295  }
1296 
1297  //
1298  // Dynamixel servo specification loaded during scan.
1299  //
1300  uTicks = pServo->GetSpecification().m_uRawPosModulo;
1301  fAngleMin = pServo->GetSpecification().m_fAngleMin;
1302  fAngleMax = pServo->GetSpecification().m_fAngleMax;
1303  fMaxRpm = pServo->GetSpecification().m_fMaxSpeed;
1304 
1305  //
1306  // Servo rotation range.
1307  //
1308  fDegrees = pSpecServo->m_bIsContinuous? 360.0: fAngleMax - fAngleMin;
1309  fRadians = degToRad(fDegrees);
1310 
1311  //
1312  // Populate joint data.
1313  //
1314  // Some data, such as joint rotation limits may be refined during
1315  // calibration.
1316  //
1317  joint.m_strName = pSpecJoint->m_strName;
1318  joint.m_nMasterServoId = nMasterServoId;
1319  joint.m_nSlaveServoId = pSpecJoint->m_nSlaveServoId;
1320  joint.m_bIsServoContinuous = pSpecServo->m_bIsContinuous;
1321  joint.m_nMasterServoDir = pSpecServo->m_nDir;
1322  joint.m_eJointType = pSpecJoint->m_eJointType;
1323  joint.m_fGearRatio = pSpecJoint->m_fGearRatio;
1324  joint.m_fTicksPerServoRad = (double)uTicks / fRadians;
1326  pSpecJoint->m_fGearRatio;
1327  joint.m_fMaxServoRadsPerSec = fMaxRpm * M_TAU / 60.0;
1329  joint.m_fGearRatio;
1330  joint.m_fMinPhyLimitRads = degToRad(pSpecJoint->m_fMinPhyLimit);
1331  joint.m_fMaxPhyLimitRads = degToRad(pSpecJoint->m_fMaxPhyLimit);
1332  joint.m_nMinPhyLimitOd = (int)(joint.m_fTicksPerJointRad *
1333  joint.m_fMinPhyLimitRads);
1334  joint.m_nMaxPhyLimitOd = (int)(joint.m_fTicksPerJointRad *
1335  joint.m_fMaxPhyLimitRads );
1338  joint.m_nMinSoftLimitOd = joint.m_nMinPhyLimitOd;
1339  joint.m_nMaxSoftLimitOd = joint.m_nMaxPhyLimitOd;
1340  joint.m_fCalibPosRads = degToRad(pSpecJoint->m_fCalibPos);
1341  joint.m_fBalPosRads = degToRad(pSpecJoint->m_fBalancedPos);
1342  joint.m_fParkPosRads = degToRad(pSpecJoint->m_fParkedPos);
1343  joint.m_eLimitTypes = pSpecJoint->m_eLimitTypes;
1344 
1345  joint.m_fOverTorqueThDft = fcap(pSpecServo->m_fTorqueLimitPct,
1346  HekTuneOverTorqueThMin,
1347  HekTuneOverTorqueThMax) / 100.0;
1348 
1349  joint.m_eOpState = HekOpStateUncalibrated;
1350  joint.m_bStopAtOptLimits = false;
1351 
1352  for(i=0; i<HekOptLimitMaxPerJoint; ++i)
1353  {
1354  joint.m_byOptLimitMask[i] = pSpecJoint->m_limit[i].m_uBit;
1355  }
1356 
1357  //
1358  // Sanity checks.
1359  //
1360  joint.m_fCalibPosRads = fcap(joint.m_fCalibPosRads,
1361  joint.m_fMinPhyLimitRads,
1362  joint.m_fMaxPhyLimitRads);
1363  joint.m_fBalPosRads = fcap(joint.m_fBalPosRads,
1364  joint.m_fMinPhyLimitRads,
1365  joint.m_fMaxPhyLimitRads);
1366  joint.m_fParkPosRads = fcap(joint.m_fParkPosRads,
1367  joint.m_fMinPhyLimitRads,
1368  joint.m_fMaxPhyLimitRads);
1369 
1370  //
1371  // Add to kinematic chain.
1372  //
1373  kin[nMasterServoId] = joint; // kinematic chain
1374  imap[joint.m_strName] = nMasterServoId; // indirect map by joint name
1375 
1376  return HEK_OK;
1377 }
1378 
1379 void HekRobot::adjustTuningFromSpecs()
1380 {
1381  MapRobotJoints::iterator iter; // joint description iterator
1382  HekTunesJoint tunesJoint; // initialzed with default defaults
1383  string strJointName; // name of joint
1384 
1385  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
1386  {
1387  strJointName = iter->second.m_strName;
1388 
1389  // per joint defaults from compiled specs
1390  tunesJoint.m_fOverTorqueTh = iter->second.m_fOverTorqueThDft;
1391 
1392  // add
1393  m_tunes.m_mapJointTunes[strJointName] = tunesJoint;
1394  }
1395 }
1396 
1397 void HekRobot::fauxcalibrate()
1398 {
1399  MapRobotJoints::iterator iter;
1400 
1401  freeze();
1402 
1403  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
1404  {
1405  iter->second.m_eOpState = HekOpStateCalibrated;
1406  }
1407  m_pKin->resetServoOdometersForAllJoints();
1408  m_eOpState = HekOpStateCalibrated;
1409 }
1410 
1411 int HekRobot::configServos()
1412 {
1413  int rc;
1414 
1415  if( (rc = configEEPROMForAllServos(m_jointsArm)) < 0 )
1416  {
1417  LOGERROR("Failed to configure servo EEPROM for all servos.");
1418  return rc;
1419  }
1420 
1421  if( (rc = configRAMForAllServos(m_jointsArm)) < 0 )
1422  {
1423  LOGERROR("Failed to configure servo RAM for all servos.");
1424  return rc;
1425  }
1426 
1427  return HEK_OK;
1428 }
1429 
1430 int HekRobot::configEEPROMForAllServos(MapRobotJoints &kin)
1431 {
1432  MapRobotJoints::iterator iter;
1433 
1434  int nServoId;
1435  int rc;
1436 
1437  for(iter = kin.begin(); iter != kin.end(); ++iter)
1438  {
1439  nServoId = iter->second.m_nMasterServoId;
1440 
1441  if( (rc = configEEPROMForServo(nServoId, iter->second)) < 0 )
1442  {
1443  LOGERROR("Servo %d: Failed to configure servo EEPROM memory map.",
1444  nServoId);
1445  return rc;
1446  }
1447 
1448  nServoId = iter->second.m_nSlaveServoId;
1449 
1450  if( nServoId != DYNA_ID_NONE )
1451  {
1452  if( (rc = configEEPROMForServo(nServoId, iter->second)) < 0 )
1453  {
1454  LOGERROR("Servo %d: Failed to configure servo EEPROM memory map.",
1455  nServoId);
1456  return rc;
1457  }
1458  }
1459  }
1460 
1461  return HEK_OK;
1462 }
1463 
1464 int HekRobot::configEEPROMForServo(int nServoId, HekRobotJoint &joint)
1465 {
1466  DynaServo *pServo;
1467  uint_t uPosMin;
1468  uint_t uPosMax;
1469  uint_t uTorqueMax;
1470  uint_t uVal;
1471  uint_t uMask;
1472  int rc;
1473 
1474  // dynamixel servo object in dynamixel chain
1475  HEK_TRY_GET_SERVO(nServoId, pServo);
1476 
1477  uPosMin = pServo->GetSpecification().m_uRawPosMin;
1478  uPosMax = pServo->GetSpecification().m_uRawPosMax;
1479  uTorqueMax = pServo->GetSpecification().m_uRawTorqueMax;
1480 
1481  // --
1482  // Ensure servo is in the correct servo mode.
1483  // --
1484 
1485  // get servo must be in continuous mode
1486  if( joint.m_bIsServoContinuous &&
1487  (pServo->GetServoMode() != DYNA_MODE_CONTINUOUS))
1488  {
1489  if( (rc = pServo->CfgWriteServoModeContinuous()) < 0 )
1490  {
1491  LOGERROR("Servo %d: Cannot configure EEPROM for continuous mode.",
1492  nServoId);
1493  return -HEK_ECODE_DYNA;
1494  }
1495  }
1496 
1497  // servo must be in servo mode
1498  else if( !joint.m_bIsServoContinuous &&
1499  (pServo->GetServoMode() == DYNA_MODE_CONTINUOUS) )
1500  {
1501  if( (rc = pServo->CfgWriteServoMode(uPosMin, uPosMax)) < 0 )
1502  {
1503  LOGERROR("Servo %d: Cannot configure EEPROM for servo mode.", nServoId);
1504  return -HEK_ECODE_DYNA;
1505  }
1506  }
1507 
1508  // --
1509  // Ensure maximum torque limit reload value is at the maximum.
1510  // --
1511 
1512  // always set maximum torque limit
1513  if( (rc = pServo->CfgReadMaxTorqueLimit(&uVal)) < 0 )
1514  {
1515  LOGWARN("Servo %d: Cannot read EEPROM maximum torque limit.", nServoId);
1516  }
1517  else if( uVal < uTorqueMax )
1518  {
1519  if( (rc = pServo->CfgWriteMaxTorqueLimit(uTorqueMax)) < 0 )
1520  {
1521  LOGWARN("Servo %d: Cannot configure EEPROM maximum torque limit.",
1522  nServoId);
1523  }
1524  }
1525 
1526  // --
1527  // Ensure alarm shutdown mask as the correct values.
1528  // --
1529 
1530  // for servos with no torque limit, disable over-load alarms
1531  uMask = DYNA_ALARM_VOLTAGE | DYNA_ALARM_ANGLE | DYNA_ALARM_TEMP |
1532  DYNA_ALARM_LOAD;
1533 
1534  if( (rc = pServo->CfgReadAlarmShutdownMask(&uVal)) < 0 )
1535  {
1536  LOGWARN("Servo %d: Cannot read EEPROM alarm shutdown mask.", nServoId);
1537  }
1538  else if( uVal != uMask )
1539  {
1540  if( (rc = pServo->CfgWriteAlarmShutdownMask(uMask)) < 0 )
1541  {
1542  LOGWARN("Servo %d: Cannot configure EEPROM alarm shutdown mask.",
1543  nServoId);
1544  }
1545  }
1546 
1547  return HEK_OK;
1548 }
1549 
1550 int HekRobot::configRAMForAllServos(MapRobotJoints &kin)
1551 {
1552  MapRobotJoints::iterator iter;
1553  int nServoId;
1554  int rc;
1555 
1556  for(iter = kin.begin(); iter != kin.end(); ++iter)
1557  {
1558  nServoId = iter->second.m_nMasterServoId;
1559 
1560  if( (rc = configRAMForServo(nServoId, iter->second)) < 0 )
1561  {
1562  LOGERROR("Servo %d: Failed to configure servo RAM memory map.",
1563  nServoId);
1564  return rc;
1565  }
1566 
1567 
1568  // no slave configuration
1569  }
1570 
1571  return HEK_OK;
1572 }
1573 
1574 int HekRobot::configRAMForServo(int nServoId, HekRobotJoint &joint)
1575 {
1576  DynaServo *pServo;
1577  uint_t uTorqueMax;
1578  int rc;
1579 
1580  // get dynamixel servo object in dynamixel chain
1581  HEK_TRY_GET_SERVO(nServoId, pServo);
1582 
1583  uTorqueMax = pServo->GetSpecification().m_uRawTorqueMax;
1584 
1585  // --
1586  // Ensure running torque limit is at the maximum.
1587  // --
1588 
1589  if( (rc = pServo->WriteMaxTorqueLimit(uTorqueMax)) < 0 )
1590  {
1591  LOGWARN("Servo %d: Cannot write RAM alarm shutdown mask.", nServoId);
1592  }
1593 
1594  // --
1595  // Disable servo drive on start up.
1596  // --
1597 
1598  if( (rc = pServo->WriteTorqueEnable(false)) < 0 )
1599  {
1600  LOGERROR("Servo %d: Cannot enable servo drive.", nServoId);
1601  return -HEK_ECODE_DYNA;
1602  }
1603 
1604  return HEK_OK;
1605 }
1606 
1607 void HekRobot::resetCalibStateForAllJoints(bool bForceRecalib)
1608 {
1609  MapRobotJoints::iterator iter;
1610 
1611  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
1612  {
1613  if( bForceRecalib || (iter->second.m_eOpState != HekOpStateCalibrated) )
1614  {
1615  iter->second.m_eOpState = HekOpStateUncalibrated;
1616  }
1617  }
1618 }
1619 
1620 HekOpState HekRobot::determineRobotOpState()
1621 {
1622  MapRobotJoints::iterator iter;
1623 
1624  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
1625  {
1626  if( iter->second.m_eOpState != HekOpStateCalibrated )
1627  {
1628  return HekOpStateUncalibrated;
1629  }
1630  }
1631 
1632  return HekOpStateCalibrated;
1633 }
1634 
1635 int HekRobot::createAsyncThread()
1636 {
1637  int rc;
1638 
1639  m_eAsyncTaskState = HekAsyncTaskStateWorking;
1640  m_rcAsyncTask = HEK_OK;
1641 
1642  rc = pthread_create(&m_threadAsync, NULL, HekRobot::asyncThread, (void*)this);
1643 
1644  if( rc == 0 )
1645  {
1646  rc = HEK_OK;
1647  }
1648 
1649  else
1650  {
1651  m_eAsyncTaskState = HekAsyncTaskStateIdle;
1652  LOGSYSERROR("pthread_create()");
1653  m_rcAsyncTask = -HEK_ECODE_SYS;
1654  m_eAsyncTaskId = AsyncTaskIdNone;
1655  m_pAsyncTaskArg = NULL;
1656  rc = m_rcAsyncTask;
1657  }
1658 
1659  return rc;
1660 }
1661 
1662 void HekRobot::cancelAsyncTask()
1663 {
1664  MapRobotJoints::iterator iter;
1665 
1666  if( m_eAsyncTaskState != HekAsyncTaskStateIdle )
1667  {
1668  // cancel thread
1669  pthread_cancel(m_threadAsync);
1670  pthread_join(m_threadAsync, NULL);
1671 
1672  // cleanup
1673  switch( m_eAsyncTaskId )
1674  {
1675  case AsyncTaskIdCalibrate:
1676  freeze();
1677  for(iter = m_jointsArm.begin(); iter != m_jointsArm.end(); ++iter)
1678  {
1679  if( iter->second.m_eOpState != HekOpStateCalibrated )
1680  {
1681  iter->second.m_eOpState = HekOpStateUncalibrated;
1682  m_eOpState = HekOpStateUncalibrated;
1683  }
1684  }
1685  break;
1686  default:
1687  break;
1688  }
1689 
1690  // clear state
1691  m_eAsyncTaskId = AsyncTaskIdNone;
1692  m_pAsyncTaskArg = NULL;
1693  m_rcAsyncTask = -HEK_ECODE_INTR;
1694  m_eAsyncTaskState = HekAsyncTaskStateIdle;
1695  LOGDIAG3("Async task canceled.");
1696  }
1697 }
1698 
1699 HekAsyncTaskState HekRobot::getAsyncState()
1700 {
1701  return m_eAsyncTaskState;
1702 }
1703 
1704 int HekRobot::getAsyncRc()
1705 {
1706  return m_rcAsyncTask;
1707 }
1708 
1709 void *HekRobot::asyncThread(void *pArg)
1710 {
1711  HekRobot *pThis = (HekRobot *)pArg;
1712  int oldstate;
1713  int rc;
1714 
1715  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
1716  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
1717  //pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldstate);
1718 
1719  LOGDIAG3("Async robot task thread created.");
1720 
1721  //
1722  // Execute asychronous task.
1723  //
1724  // For now, only calibrate task is supported asynchronously.
1725  //
1726  switch( pThis->m_eAsyncTaskId )
1727  {
1728  // Calibrate the robot.
1729  case AsyncTaskIdCalibrate:
1730  {
1731  bool bForceRecalib = (bool)pThis->m_pAsyncTaskArg;
1732  rc = pThis->calibrate(bForceRecalib);
1733  }
1734  break;
1735 
1736  // Unknown task id.
1737  default:
1738  LOGERROR("Unknown async task id = %d.", (int)pThis->m_eAsyncTaskId);
1739  rc = -HEK_ECODE_BAD_VAL;
1740  break;
1741  }
1742 
1743  pThis->m_eAsyncTaskId = AsyncTaskIdNone;
1744  pThis->m_pAsyncTaskArg = NULL;
1745  pThis->m_rcAsyncTask = rc;
1746  pThis->m_eAsyncTaskState = HekAsyncTaskStateIdle;
1747 
1748  LOGDIAG3("Async robot task thread exited.");
1749 
1750  return NULL;
1751 }
int m_nSlaveServoId
linked slave servo id (if any)
Definition: hekJoint.h:151
HekSpecServo_T * getServoSpec(int nServoId)
Get servo spec associated with servo id.
Definition: hekSpec.cxx:290
void * m_pAsyncTaskArg
asynchronous argument
Definition: hekRobot.h:715
int m_nSlaveServoId
linked slave servo id, if any
Definition: hekSpec.h:176
double m_fCalibPos
joint calibrated position (degrees)
Definition: hekSpec.h:184
Robot overall state.
Definition: hekState.h:114
int m_nServoId
servo id
Definition: hekState.h:100
int m_nErrorCode
hekateros error code
Definition: hekState.h:160
HekOpticalLimit_T m_limit[HekOptLimitMaxPerJoint]
optical limits
Definition: hekSpec.h:182
Hekateros robotic manipulator calibration by stretching class.
std::string m_strName
joint name
Definition: hekSpec.h:174
int m_nMaxSoftLimitOd
joint max soft limit (odometer ticks)
Definition: hekJoint.h:169
byte_t m_uBit
i/o expander bit position
Definition: hekOptical.h:177
HekOpState m_eOpState
current operational state
Definition: hekJoint.h:179
HekDesc - Hekateros full robotic manipulator descripition class interface.
Joint trajectory feedback class.
Definition: hekTraj.h:313
double m_fMinSoftLimitRads
joint min soft limit (radians)
Definition: hekJoint.h:166
int m_nOdPos
current master servo odometer pos (ticks)
Definition: hekJoint.h:323
int m_eLimitTypes
joint limit types
Definition: hekJoint.h:173
#define HEK_TRY_NO_EXEC()
Define if heketeros has RN system board.
Definition: hekRobot.cxx:100
Joint trajectory point class.
Definition: hekTraj.h:180
Hekateros end effector tool description class.
Definition: hekDescEE.h:71
double m_fBalancedPos
joint balanced position (degrees)
Definition: hekSpec.h:185
Operational robotic joint description class.
Definition: hekJoint.h:80
double m_fGearRatio
joint gear ratio
Definition: hekSpec.h:178
int m_nSpeed
current master servo raw speed (unitless)
Definition: hekJoint.h:325
VecHealth m_vecServoHealth
servos&#39; health
Definition: hekState.h:161
void clear()
Clear data.
Definition: hekState.cxx:132
int m_rcAsyncTask
last async task return code
Definition: hekRobot.h:713
<b><i>Hekateros</i></b> optical limit switches.
void clear()
Clear all state data.
Definition: hekJoint.h:464
double m_fTicksPerJointRad
encoder/odom. ticks per joint radian
Definition: hekJoint.h:157
double m_fTicksPerServoRad
encoder/odom. ticks per servo radian
Definition: hekJoint.h:156
double m_fMaxServoRadsPerSec
maximum servo radians per second
Definition: hekJoint.h:158
int m_eJointType
joint type
Definition: hekJoint.h:154
HekTriState m_eIsInError
robot is [not] in error condition
Definition: hekState.h:159
double m_fMaxJointRadsPerSec
maximum joint radians per second
Definition: hekJoint.h:159
Hekateros tuning per joint data class.
Definition: hekTune.h:367
double m_fPosition
current joint position (radians)
Definition: hekJoint.h:320
size_t getNumPoints()
Get the number of joint states in joint state point.
Definition: hekJoint.h:410
double m_fVelocity
current joint velocity (% of max)
Definition: hekJoint.h:321
Joint points and trajectory class interfaces.
HekTriState m_eIsEStopped
robot is [not] emergency stopped
Definition: hekState.h:155
#define M_TAU
tau = 2 * pi
Definition: hekUtils.h:67
double fcap(double a, double min, double max)
Cap value within limits [min, max].
Definition: hekUtils.h:163
bool m_bIsContinuous
servo should [not] be configured in 360 mode
Definition: hekSpec.h:219
int m_nMinPhyLimitOd
joint min phys limit (odometer ticks)
Definition: hekJoint.h:164
int m_nMasterServoId
master servo id
Definition: hekJoint.h:150
map< std::string, int > IMapRobotJoints
Indirect map of robot joints.
Definition: hekRobot.h:99
HekOpState m_eOpState
joint operational state
Definition: hekJoint.h:317
double m_fTorqueLimitPct
torque limit(%). Set to 0 for no limit
Definition: hekSpec.h:221
float m_fTemperature
servo temperature (Celsius)
Definition: hekState.h:101
double m_fParkPosRads
joint parked position (radians)
Definition: hekJoint.h:172
Hekateros Robot State classes interface.
uint_t m_uAlarms
servo alarms
Definition: hekState.h:103
int m_eLimitTypes
joint limit types
Definition: hekSpec.h:181
#define HEK_TRY_NOT_ESTOP()
Test for not estop.
Definition: hekRobot.cxx:179
void append(const HekJointState &jointState)
Append joint state to end of joint state point.
Definition: hekJoint.h:429
int m_nMasterServoId
master servo id
Definition: hekJoint.h:318
double m_fCalibPosRads
joint calibrated position (radians)
Definition: hekJoint.h:170
double m_fOverTorqueTh
over torque conditon threshold (fraction)
Definition: hekTune.h:376
The Hekateros kinematics and dynamics class interface.
float m_fVoltage
servo voltage (volts)
Definition: hekState.h:102
HekSpec m_spec
fixed specification
Definition: hekDescArm.h:260
double m_fMinPhyLimitRads
joint min physical limit (radians)
Definition: hekJoint.h:162
Hekateros Monitor Class interface.
bool m_bIsServoContinuous
servo should [not] be continuous mode
Definition: hekJoint.h:152
HekRobotMode m_eRobotMode
robot operating mode
Definition: hekState.h:153
HekXmlTune <b><i>Hekateros</i></b> XML tuning class.
Definition: hekXmlTune.h:72
int m_nMinSoftLimitOd
joint min soft limit (odometer ticks)
Definition: hekJoint.h:168
double m_fMinPhyLimit
joint minimum physical limit (degrees)
Definition: hekSpec.h:179
Hekateros joint classes interfaces.
int m_nMaxPhyLimitOd
joint max phys limit (odometer ticks)
Definition: hekJoint.h:165
virtual int calibrate()
Calibrate the <b><i>Hekateros</i></b>&#39;s robotic arm.
byte_t m_byOptLimitMask[HekOptLimitMaxPerJoint]
optical limit mask array
Definition: hekJoint.h:175
HekSpecJoint_T * getJointSpecAt(int index)
Get joint spec at the given index.
Definition: hekSpec.h:347
Hekateros robotic arm (manipulator) description class.
Definition: hekDescArm.h:77
bool m_bStopAtOptLimits
do [not] stop at optical limits
Definition: hekJoint.h:180
int m_nMasterServoId
master servo id
Definition: hekSpec.h:175
HekRobot - Hekateros Robot Class interface.
void setKinematicChainName(std::string strKinName)
Set the kinematic chain name.
Definition: hekJoint.h:400
double m_fParkedPos
joint parked position (degrees)
Definition: hekSpec.h:186
int m_nDir
normalize cw/ccw direction.
Definition: hekSpec.h:220
double m_fMaxPhyLimit
joint maximum physical limit (degrees)
Definition: hekSpec.h:180
std::string m_strName
joint name
Definition: hekJoint.h:316
std::string m_strName
joint name
Definition: hekJoint.h:149
int iabs(int a)
Integer absolute value.
Definition: hekUtils.h:149
int m_nDoF
degrees of freedom
Definition: hekSpec.h:403
Top-level package include file.
double degToRad(double d)
Convert degrees to radians.
Definition: hekUtils.h:125
double m_fMaxSoftLimitRads
joint max soft limit (radians)
Definition: hekJoint.h:167
int m_eJointType
joint type
Definition: hekSpec.h:177
double m_fBalPosRads
joint balanced position (radians)
Definition: hekJoint.h:171
int calibrate(bool bForceRecalib=true)
Calibrate <b><i>Hekateros</i></b>&#39;s odometers and limit switch positions.
Definition: hekRobot.cxx:436
#define HEK_TRY_CONN()
Test for connection.
Definition: hekRobot.cxx:143
int m_nSlaveServoId
linked slave servo id (if any)
Definition: hekJoint.h:319
#define HEK_TRY_GET_SERVO(nServoId, pServo)
Convenience macro for trying to get a servo object from dynamixel chain.
Definition: hekRobot.cxx:124
int m_nMasterServoDir
master servo normalized direction
Definition: hekJoint.h:153
double m_fGearRatio
joint gear ratio
Definition: hekJoint.h:155
void append(const std::string &strName, double fPosition, double fVelocity, double fAcceleration=0.0)
Append joint point to end of trajectory.
Definition: hekTraj.h:264
Joint state class.
Definition: hekJoint.h:287
HekTriState m_eIsInMotion
robot is [not] moving
Definition: hekState.h:158
Joint state point class.
Definition: hekJoint.h:344
<b><i>Hekateros</i></b> product specification base classes.
AsyncTaskId m_eAsyncTaskId
asynchronous task id
Definition: hekRobot.h:714
#define HEK_TRY_CALIB()
Test for calibration.
Definition: hekRobot.cxx:161
std::string getRealDeviceName(const std::string &strDevName)
Get real device name.
Hekateros robotic manipulator plus accesories class.
Definition: hekRobot.h:88
Hekateros common utilities.
double m_fEffort
current joint effort (servo load)
Definition: hekJoint.h:322
double m_fMaxPhyLimitRads
joint max physical limit (radians)
Definition: hekJoint.h:163
virtual int load(HekTunes &tunes, const std::string &strSearchPath=HekSysCfgPath, const std::string &strXmlFileName=HekEtcTune, bool bAllInstances=false)
Load XML file into DOM and set the <b><i>Hekateros</i></b> tuning parameters.
Definition: hekXmlTune.cxx:72
Hekateros tuning.
HekAsyncTaskState m_eAsyncTaskState
asynchronous task state
Definition: hekRobot.h:712
HekSpec m_spec
fixed specification
Definition: hekDescEE.h:258
Robotic joint specification.
Definition: hekSpec.h:139
Robot servo health.
Definition: hekState.h:71
int m_nEncPos
current master servo encoder pos (ticks)
Definition: hekJoint.h:324
Robotic servo specification.
Definition: hekSpec.h:199
HekTriState m_eIsMotionPossible
motion is [not] possible
Definition: hekState.h:157
HekTriState m_eOptSwitch[HekOptLimitMaxPerJoint]
current state of optical switch(es)
Definition: hekJoint.h:326
HekTriState m_eAreDrivesPowered
servos are [not] powered
Definition: hekState.h:156
HekTriState m_eIsCalibrated
robot is [not] calibrated
Definition: hekState.h:154
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.
double m_fOverTorqueThDft
joint over torque th default (norm).
Definition: hekJoint.h:174