Hekateros  3.4.3
RoadNarrows Robotics Robot Arm Project
hekKin.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Hekateros
4 //
5 // Library: libhekateros
6 //
7 // File: hekKin.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-05-15 12:50:46 -0600 (Fri, 15 May 2015) $
12  * $Rev: 3988 $
13  *
14  * \brief The Hekateros kinematics and dynamics class implemenation.
15  *
16  * \copyright
17  * \h_copy 2014-2017. RoadNarrows LLC.\n
18  * http://www.roadnarrows.com\n
19  * All Rights Reserved
20  */
21 /*
22  * @EulaBegin@
23  *
24  * Unless otherwise stated explicitly, all materials contained are copyrighted
25  * and may not be used without RoadNarrows LLC's written consent,
26  * except as provided in these terms and conditions or in the copyright
27  * notice (documents and software) or other proprietary notice provided with
28  * the relevant materials.
29  *
30  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
31  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
32  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
33  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
34  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
35  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
38  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
39  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
40  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
41  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
42  *
43  * @EulaEnd@
44  */
45 ////////////////////////////////////////////////////////////////////////////////
46 
47 #include <sys/time.h>
48 #include <time.h>
49 #include <limits.h>
50 #include <unistd.h>
51 #include <stdio.h>
52 #include <pthread.h>
53 #include <sched.h>
54 #include <math.h>
55 
56 #include <vector>
57 #include <map>
58 
59 #include "rnr/rnrconfig.h"
60 #include "rnr/log.h"
61 
62 #include "Dynamixel/Dynamixel.h"
63 #include "Dynamixel/DynaError.h"
64 #include "Dynamixel/DynaServo.h"
65 #include "Dynamixel/DynaChain.h"
66 
67 #include "Hekateros/hekateros.h"
68 #include "Hekateros/hekTune.h"
69 #include "Hekateros/hekJoint.h"
70 #include "Hekateros/hekTraj.h"
71 #include "Hekateros/hekKinJoint.h"
72 #include "Hekateros/hekKin.h"
73 #include "Hekateros/hekUtils.h"
74 
75 using namespace std;
76 using namespace hekateros;
77 
78 
79 // ---------------------------------------------------------------------------
80 // Private Interface
81 // ---------------------------------------------------------------------------
82 
83 // ---------------------------------------------------------------------------
84 // HekKinematics Class
85 // ---------------------------------------------------------------------------
86 
87 HekKinematics::HekKinematics(DynaChain &dynaChain,
88  MapRobotJoints &kinJointDesc,
89  const HekTunes &tunes) :
90  m_dynaChain(dynaChain)
91 {
92  MapRobotJoints::iterator iter;
93  string strJointName;
94  HekRobotJoint *pJoint;
95  int nServoId;
96  DynaServo *pServo;
97 
99  m_nNumJoints = (int)kinJointDesc.size();
100  m_nNumServos = m_dynaChain.GetNumberInChain();
102 
103  for(iter=kinJointDesc.begin(); iter!=kinJointDesc.end(); ++iter)
104  {
105  pJoint = &iter->second;
106  strJointName = pJoint->getJointName();
107  nServoId = pJoint->getMasterServoId();
108  pServo = m_dynaChain.GetServo(nServoId);
109 
110  if( strJointName == "wrist_rot" )
111  {
112  m_kinChain[strJointName] = new HekKinJointWristRot(pJoint, pServo, tunes);
113  }
114  else
115  {
116  m_kinChain[strJointName] = new HekKinJoint(pJoint, pServo, tunes);
117  }
118  }
119 
120  //
121  // Coupled wrist joints.
122  //
123  if( (m_kinChain.find("wrist_rot") != m_kinChain.end()) &&
124  (m_kinChain.find("wrist_pitch") != m_kinChain.end()) )
125  {
126  m_kinChain["wrist_rot"]->coupleJoint(m_kinChain["wrist_pitch"]);
127  }
128 
129  buildTaskList();
130 
131 #ifdef HEK_KIN_EXEC_ALG_INDIV
132  m_iterTask = m_taskList.begin();
133 #endif // HEK_KIN_EXEC_ALG_INDIV
134 
136 
137  pthread_mutex_init(&m_mutexSync, NULL);
138  pthread_cond_init(&m_condSync, NULL);
139 
140  // create kinematics thread
141  createThread();
142 
143  m_bIsControlling = false;
144 
145 #ifdef HEK_KIN_EXEC_ALG_SYNC
146  m_bWaitOneCycle = false;
147 #endif // HEK_KIN_EXEC_ALG_SYNC
148 
149  LOGDIAG3("Registered kinematic chain of %d joints and %d servos.",
151 }
152 
154 {
155  KinChain::iterator iter; // kinematics chain iterator
156 
157  terminateThread();
158 
159  pthread_cond_destroy(&m_condSync);
160  pthread_mutex_destroy(&m_mutexSync);
161 
162  for(iter = m_kinChain.begin(); iter != m_kinChain.end(); ++iter)
163  {
164  if( iter->second != NULL )
165  {
166  delete iter->second;
167  iter->second = NULL;
168  }
169  }
170  m_kinChain.clear();
171 }
172 
173 // major hack
175 {
176  m_taskList.empty();
177 
178  // 4DOF arms have no rotating base
179  if( m_kinChain.find("base_rot") != m_kinChain.end() )
180  {
181  m_taskList.push_back("base_rot");
182  }
183 
184  m_taskList.push_back("shoulder");
185  m_taskList.push_back("elbow");
186  m_taskList.push_back("wrist_pitch");
187 
188  // wrist rot coupled with pitch, keep close
189  m_taskList.push_back("wrist_rot");
190 
191  // default gripper
192  if( m_kinChain.find("grip") != m_kinChain.end() )
193  {
194  m_taskList.push_back("grip");
195  }
196 
197 #ifdef HEK_KIN_EXEC_ALG_INDIV
198  // servo health task
199  m_taskList.push_back("health");
200 
201  if( m_taskList.size() != m_kinChain.size()+1 )
202  {
203  LOGERROR("WTF: Task list not matching kinematic chain.");
204  }
205 #endif // HEK_KIN_EXEC_ALG_INDIV
206 }
207 
208 void HekKinematics::reload(const HekTunes &tunes)
209 {
210  KinChain::iterator iter; // kinematics chain iterator
211 
212  for(iter = m_kinChain.begin(); iter != m_kinChain.end(); ++iter)
213  {
214  iter->second->reload(tunes);
215  }
216 
217  setHz(tunes.m_fKinematicsHz);
218 }
219 
221 {
222  KinChain::iterator iter; // kinematics chain iterator
223  int n; // number of actual joints reset
224 
225  lock();
226 
227  for(iter = m_kinChain.begin(), n = 0; iter != m_kinChain.end(); ++iter)
228  {
229  if( iter->second->resetServoOdometer() == HEK_OK )
230  {
231  ++n;
232  }
233  }
234 
235  unlock();
236 
237  waitOneCycle();
238 
239  return n;
240 }
241 
242 void HekKinematics::getJointCurPosVel(const std::string &strJointName,
243  double &fJointCurPos,
244  double &fJointCurVel)
245 {
246  KinChain::iterator pos;
247 
248  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
249  {
250  pos->second->getJointCurPosVel(fJointCurPos, fJointCurVel);
251  }
252 }
253 
254 void HekKinematics::getFilteredJointCurPosVel(const std::string &strJointName,
255  double &fJointCurPos,
256  double &fJointCurVel)
257 {
258  KinChain::iterator pos;
259 
260  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
261  {
262  pos->second->getFilteredJointCurPosVel(fJointCurPos, fJointCurVel);
263  }
264 }
265 
266 void HekKinematics::getServoCurPosSpeed(const std::string &strJointName,
267  int &nServoCurPos,
268  int &nServoCurSpeed)
269 {
270  KinChain::iterator pos;
271 
272  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
273  {
274  pos->second->getServoCurPosSpeed(nServoCurPos, nServoCurSpeed);
275  }
276 }
277 
278 int HekKinematics::jointPosToServoPos(const std::string &strJointName,
279  const double fPos)
280 {
281  KinChain::iterator pos;
282 
283  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
284  {
285  return pos->second->jointPosToServoPos(fPos);
286  }
287  else
288  {
289  return 0;
290  }
291 }
292 
293 double HekKinematics::servoPosToJointPos(const std::string &strJointName,
294  const int nOdPos)
295 {
296  KinChain::iterator pos;
297 
298  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
299  {
300  return pos->second->servoPosToJointPos(nOdPos);
301  }
302  else
303  {
304  return 0.0;
305  }
306 }
307 
308 bool HekKinematics::isStopped(const std::string &strJointName)
309 {
310  KinChain::iterator pos;
311 
312  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
313  {
314  return pos->second->isStopped();
315  }
316  else // non-existent joints don't move
317  {
318  return true;
319  }
320 }
321 
322 bool HekKinematics::hasOverTorqueCondition(const std::string &strJointName)
323 {
324  KinChain::iterator pos;
325 
326  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
327  {
328  return pos->second->hasOverTorqueCondition();
329  }
330  else // non-existent joints have no torque issues
331  {
332  return false;
333  }
334 }
335 
336 int HekKinematics::resetServoOdometer(const string &strJointName)
337 {
338  KinChain::iterator pos; // kinematics chain position
339  int rc; // return code
340 
341  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
342  {
343  rc = pos->second->resetServoOdometer();
344  }
345  else
346  {
347  LOGWARN("Joint %s: Not found in kinematic chain.", strJointName.c_str());
348  rc = -HEK_ECODE_BAD_VAL;
349  }
350 
351  waitOneCycle();
352 
353  return rc;
354 }
355 
357 {
358  if( m_bIsControlling )
359  {
360  stop();
361  waitForAllStop(1.0);
362  }
363 
364  lock();
365 
366  m_bIsControlling = false;
367 
368  m_dynaChain.EStop();
369 
370  unlock();
371 }
372 
374 {
375  m_bIsControlling = true;
376 
377  stop();
378 
379  waitForAllStop(5.0);
380 }
381 
383 {
384  if( m_bIsControlling )
385  {
386  stop();
387  waitForAllStop(5.0);
388  }
389 
390  lock();
391 
392  m_bIsControlling = false;
393 
394  m_dynaChain.Release();
395 
396  unlock();
397 }
398 
400 {
401  KinChain::iterator iter;
402 
403  if( !m_bIsControlling )
404  {
405  return -HEK_ECODE_BAD_OP;
406  }
407 
408  for(iter=m_kinChain.begin(); iter!=m_kinChain.end(); ++iter)
409  {
410  iter->second->stop();
411  }
412 
413  return HEK_OK;
414 }
415 
416 int HekKinematics::stop(const vector<string> &vecJointNames)
417 {
418  vector<string>::const_iterator iter; // joint name iterator
419 
420  KinChain::iterator pos; // kinematics chain position
421  int n; // number of actual joints stopped
422 
423  if( !m_bIsControlling )
424  {
425  return -HEK_ECODE_BAD_OP;
426  }
427 
428  for(iter = vecJointNames.begin(), n = 0; iter != vecJointNames.end(); ++iter)
429  {
430  if( (pos = m_kinChain.find(*iter)) != m_kinChain.end() )
431  {
432  if( pos->second->stop() == HEK_OK )
433  {
434  ++n;
435  }
436  }
437  }
438  return n;
439 }
440 
441 int HekKinematics::stop(const string &strJointName)
442 {
443  KinChain::iterator pos; // kinematics chain position
444  int rc; // return code
445 
446  if( !m_bIsControlling )
447  {
448  return -HEK_ECODE_BAD_OP;
449  }
450 
451  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
452  {
453  rc = pos->second->stop();
454  }
455  else
456  {
457  LOGWARN("Joint %s: Not found in kinematic chain.", strJointName.c_str());
458  rc = -HEK_ECODE_BAD_VAL;
459  }
460 
461  return rc;
462 }
463 
464 int HekKinematics::waitForAllStop(double fSeconds)
465 {
466  static const useconds_t WaitDt = 100; // usec wait between tests
467 
468  KinChain::iterator iter;
469 
470  int nMaxTries = (int)ceil(fSeconds * MILLION / (double)WaitDt);
471  int nMoveCnt;
472 
473  for(int i = 0; i < nMaxTries; ++i)
474  {
475  nMoveCnt = 0;
476 
477  for(iter = m_kinChain.begin(); iter != m_kinChain.end(); ++iter)
478  {
479  if( !iter->second->isStopped() )
480  {
481  ++nMoveCnt;
482  break;
483  }
484  }
485 
486  if( nMoveCnt == 0 )
487  {
488  return HEK_OK;
489  }
490 
491  usleep(WaitDt);
492  }
493 
494  LOGERROR("Timed out waiting for %.2lf seconds for all joints to stop.",
495  fSeconds);
496 
497  return -HEK_ECODE_TIMEDOUT;
498 }
499 
501 {
502  int i; // trajectory point iterator
503  int nNumPts; // number of actual points
504  string strJointName; // joint name
505  double fJointGoalPos; // goal joint position (radians)
506  double fJointGoalVel; // goal joint velocity (rads/sec)
507  double fJointGoalAcc; // goal joint acceleration (N/A)
508  KinChain::iterator pos; // kinematics chain position
509 
510  lock();
511 
512  for(i=0, nNumPts=0; i<trajectoryPoint.getNumPoints(); ++i)
513  {
514  //
515  // Joint point data: joint name, goal position, velocity, and acceleration.
516  //
517  trajectoryPoint[i].get(strJointName, fJointGoalPos,
518  fJointGoalVel, fJointGoalAcc);
519 
520  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
521  {
522  pos->second->specifyMove(fJointGoalPos, fJointGoalVel);
523  ++nNumPts;
524  }
525  else
526  {
527  LOGWARN("Joint %s: Not found in kinematic chain.", strJointName.c_str());
528  continue;
529  }
530  }
531 
532  if( nNumPts > 0 )
533  {
534  m_bIsControlling = true;
535  }
536 
537  unlock();
538 
539  return nNumPts;
540 }
541 
542 int HekKinematics::move(const std::string &strJointName,
543  const double fJointGoalPos,
544  const double fJointGoalVel)
545 {
546  KinChain::iterator pos; // kinematics chain position
547  int rc; // return code
548 
549  lock();
550 
551  if( (pos = m_kinChain.find(strJointName)) != m_kinChain.end() )
552  {
553  rc = pos->second->specifyMove(fJointGoalPos, fJointGoalVel);
554  m_bIsControlling = true;
555  }
556  else
557  {
558  LOGWARN("Joint %s: Not found in kinematic chain.", strJointName.c_str());
559  rc = -HEK_ECODE_BAD_VAL;
560  }
561 
562  unlock();
563 
564  return rc;
565 }
566 
568 {
569  TaskList::iterator iter;
570 
571  for(iter = m_taskList.begin(); iter != m_taskList.end(); ++iter)
572  {
573  m_kinChain[*iter]->senseDynamics(m_bIsControlling);
574  }
575 }
576 
578 {
579  TaskList::iterator iter;
580 
581  for(iter = m_taskList.begin(); iter != m_taskList.end(); ++iter)
582  {
583  m_kinChain[*iter]->react(m_bIsControlling, m_msgs);
584  }
585 }
586 
588 {
589  TaskList::iterator iter;
590 
591  for(iter = m_taskList.begin(); iter != m_taskList.end(); ++iter)
592  {
593  m_kinChain[*iter]->senseDynamics(m_bIsControlling);
594  m_kinChain[*iter]->react(m_bIsControlling, m_msgs);
595  }
596 }
597 
599 {
600  TaskList::iterator iter;
601 
602  for(iter = m_taskList.begin(); iter != m_taskList.end(); ++iter)
603  {
604  m_kinChain[*iter]->planMotion(m_bIsControlling, m_msgs);
605  }
606 }
607 
609 {
610  uint_t uCount;
611  int rc;
612 
613  if( !m_bIsControlling )
614  {
615  return HEK_OK;
616  }
617 
618  if( (uCount = m_msgs.getSpeedTupleCount()) > 0 )
619  {
620  rc = m_dynaChain.SyncWriteGoalSpeed(m_msgs.getSpeedTuples(), uCount);
621  }
622 
623  if( (rc == DYNA_OK) && ((uCount = m_msgs.getOdPosTupleCount()) > 0) )
624  {
625  rc = m_dynaChain.SyncWriteGoalPos(m_msgs.getOdPosTuples(), uCount);
626  }
627 
628  rc = rc < 0? -HEK_ECODE_DYNA: HEK_OK;
629 
630  return rc;
631 }
632 
634 {
635  DynaServo *pServo;
636  uint_t uAlarms;
637  int nCurLoad;
638  uint_t uCurVolt;
639  uint_t uCurTemp;
640 
641  pServo = m_dynaChain.GetServo(m_nHealthServoId);
642 
643  if( (m_nHealthServoId = m_dynaChain.IterNext(&m_iterHealth)) == DYNA_ID_NONE )
644  {
646  }
647 
648  LOGDIAG4("Kinematics Thread: Monitoring health for servo %d.",
649  pServo->GetServoId());
650 
651  pServo->ReadHealth(&uAlarms, &nCurLoad, &uCurVolt, &uCurTemp);
652 }
653 
654 #ifdef HEK_KIN_EXEC_ALG_SYNC
655 
656 void HekKinematics::exec()
657 {
658  lock();
659 
660  // clear previous synchronous move messages
661  m_msgs.clear();
662 
663  // sense-react on sensed state
664  sense_react();
665 
666  // plan motions
667  plan();
668 
669  // act on planned motions
670  act();
671 
672  // monitor servo's health
673  monitorHealth();
674 
675  // caller blocked waiting one execution cycle - signal to unblock
676  if( m_bWaitOneCycle )
677  {
678  m_bWaitOneCycle = false;
679  pthread_cond_signal(&m_condSync);
680  }
681 
682  unlock();
683 }
684 
685 #else // HEK_KIN_EXEC_ALG_INDIV
686 
688 {
689  lock();
690 
691  string strTask = *m_iterTask++;
692 
693  if( m_iterTask == m_taskList.end() )
694  {
695  m_iterTask = m_taskList.begin();
696  }
697 
698 #ifdef DBG
699  if( !m_strTaskOneCycle.empty() )
700  {
701  fprintf(stderr, "DBG: %s(): task=%s\n", LOGFUNCNAME, strTask.c_str());
702  }
703 #endif // DBG
704 
705  if( strTask == m_strTaskOneCycle )
706  {
707  m_strTaskOneCycle.clear();
708  pthread_cond_signal(&m_condSync);
709  }
710 
711 
712  // health monitor task
713  if( strTask == "health" )
714  {
715  monitorHealth();
716  }
717 
718  // joint sense and control tasks
719  else
720  {
721  HekKinJoint *pKinJoint = m_kinChain[strTask];
722 
723  pKinJoint->senseDynamics(m_bIsControlling);
724 
725  if( m_bIsControlling )
726  {
727  pKinJoint->act();
728  }
729  }
730 
731  unlock();
732 }
733 
734 #endif // HEK_KIN_EXEC_ALG_SYNC
735 
736 void *HekKinematics::thread(void *pArg)
737 {
738  HekKinematics *pThis = (HekKinematics *)pArg;
739  int oldstate;
740  int rc;
741 
742  LOGDIAG3("Kinematics thread created - ready to run.");
743 
744  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
745  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
746 
747  pThis->m_eState = ThreadStateReady;
748 
749  //
750  // Loop forever until exit
751  //
752  while( (pThis->m_eState != ThreadStateExit) )
753  {
754  switch( pThis->m_eState )
755  {
756  //
757  // Blocked on Ready "queue"
758  //
759  case ThreadStateReady:
760  pThis->readyWait();
761 
762  // ready -> running
763  if( pThis->m_eState == ThreadStateRunning )
764  {
765 #ifdef HEK_KIN_EXEC_ALG_SYNC
766  LOGDIAG3("Kinematics thread started - running at %.1lf Hz.",
767  pThis->m_fHz);
768 #else // HEK_KIN_EXEC_ALG_INDIV
769  LOGDIAG3("Kinematics thread started - "
770  "running at %.1lf Hz, %lf seconds/task.",
771  pThis->m_fHz, pThis->m_fTExec);
772 #endif // HEK_KIN_EXEC_ALG_SYNC
773 
774  // force immediately execution of first task
775  clock_gettime(CLOCK_REALTIME, &pThis->m_tsSched);
776  }
777  break;
778 
779  //
780  // Run wait,execute subcycle
781  //
782  case ThreadStateRunning:
783  pThis->schedWait();
784  if( pThis->m_eState == ThreadStateRunning )
785  {
786  pThis->exec();
787  }
788  break;
789 
790  //
791  // Exit
792  //
793  case ThreadStateExit:
794  break;
795 
796  default:
797  LOGERROR("%d: Unexpected dynamixel background thread state.",
798  pThis->m_eState);
799  pThis->m_eState = ThreadStateExit;
800  break;
801  }
802  }
803 
804  LOGDIAG3("Kinematics thread exited.");
805 
806  return NULL;
807 }
808 
810 {
811  pthread_attr_t attr;
812  struct sched_param parm;
813  int rc;
814 
815  // Initialize thread attributes.
816  pthread_attr_init(&attr);
817 
818  //
819  // Set thread scheduling policy.
820  // SCHED_FIFO:
821  // + preemptive priority scheduling
822  // + highest priority thread runs until it choses to block/sleep
823  // + when it unblock/wakes it goes to the end of the queue for its priority
824  //
825  pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
826 
827  //
828  // Get the system's maximum priority and set this thread to the
829  // next-to-the-highest priority.
830  parm.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
831  pthread_attr_setschedparam(&attr, &parm);
832 
833  // Create kinematics thread.
834  rc = pthread_create(&m_thread, &attr, HekKinematics::thread, (void *)this);
835 
836  // wait for thread to initialize
837  if( rc == 0 )
838  {
839  lock();
840  pthread_cond_wait(&m_condSync, &m_mutexSync);
841  unlock();
842  }
843  else
844  {
845  LOGSYSERROR("pthread_create()");
847  }
848 }
849 
850 void HekKinematics::setHz(const double fHz)
851 {
852  m_fHz = fHz;
853 
854  if( m_fHz < HekTuneKinHzMin )
855  {
857  }
858 
859 #ifdef HEK_KIN_EXEC_ALG_SYNC
860  m_fTExec = 1.0 / m_fHz;
861 #else // !HEK_KIN_EXEC_ALG_INDIV
862  m_fTExec = 1.0 / (m_fHz * (double)m_taskList.size());
863 #endif // HEK_KIN_EXEC_ALG_SYNC
864 
865  m_tsExecPeriod.tv_sec = (long)floor(m_fTExec);
866  m_tsExecPeriod.tv_nsec = (long)fcap(
867  (m_fTExec-floor(m_fTExec)) * (double)BILLION,
868  0.0, (double)(BILLION-1) );
869 }
870 
872 {
873  int rc; // return code
874 
875  setHz(fHz);
876 
877  switch( m_eState )
878  {
879  case ThreadStateReady:
881  rc = HEK_OK;
882  break;
883 
884  case ThreadStateRunning:
885  case ThreadStateExit:
886  default:
887  rc = -HEK_ECODE_GEN;
888  LOGERROR("Kinematics thread in invalid state %d to run.", m_eState);
889  break;
890  }
891 
892  return rc;
893 }
894 
896 {
898  pthread_join(m_thread, NULL);
899 }
900 
901 #ifdef HEK_KIN_EXEC_ALG_SYNC
903 {
904  lock();
905 
906  m_bWaitOneCycle = true;
907 
908  pthread_cond_wait(&m_condSync, &m_mutexSync);
909 
910  unlock();
911 }
912 
913 #else // HEK_KIN_EXEC_ALG_INDIV
914 
916 {
917  lock();
918 
919  if( m_iterTask == m_taskList.begin() )
920  {
921  m_strTaskOneCycle = m_taskList.back();
922  }
923  else
924  {
925  TaskList::iterator prev = m_iterTask - 1;
926  m_strTaskOneCycle = *prev;
927  }
928 
929 #ifdef DBG
930  fprintf(stderr, "DBG: %s(): taskonecycle=%s\n", LOGFUNCNAME,
931  strTaskOneCycle.c_str());
932 #endif // DBG
933 
934  pthread_cond_wait(&m_condSync, &m_mutexSync);
935 
936  unlock();
937 }
938 
939 #endif // HEK_KIN_EXEC_ALG_SYNC
940 
942 {
943  lock();
944 
945  // signal calling thread that created kinematics thread.
946  pthread_cond_signal(&m_condSync);
947 
948  while( m_eState == ThreadStateReady )
949  {
950  pthread_cond_wait(&m_condSync, &m_mutexSync);
951  }
952 
953  unlock();
954 }
955 
956 void HekKinematics::timedWait(const struct timespec &tsTimeout)
957 {
958  lock();
959 
960  pthread_cond_timedwait(&m_condSync, &m_mutexSync, &tsTimeout);
961 
962  unlock();
963 }
964 
966 {
967  static bool bLogWarnings = false; // true to debug scheduling overloading
968  struct timespec tsNow; // now
969  struct timespec tsSlip; // any slippage
970 
971  // now
972  clock_gettime(CLOCK_REALTIME, &tsNow);
973 
974  if( m_tsSched < tsNow )
975  {
976  tsSlip = tsNow - m_tsSched;
977  }
978  else
979  {
980  tsSlip.tv_sec = tsSlip.tv_nsec = 0;
981  }
982 
983  // block wait for next execute cycle
984  if( tsNow < m_tsSched )
985  {
987  clock_gettime(CLOCK_REALTIME, &tsNow);
988  m_tsSched = tsNow + m_tsExecPeriod;
989  }
990 
991  // slipped by less than two execution cycles - try to make up the time
992  else if( tsSlip < m_tsExecPeriod )
993  {
994  m_tsSched = tsNow + m_tsExecPeriod - tsSlip;
995  }
996 
997  // slipped a bunch
998  else
999  {
1000  m_tsSched = tsNow + m_tsExecPeriod;
1001 
1002  // debug logging
1003  if( bLogWarnings )
1004  {
1005 #ifdef HEK_KIN_EXEC_ALG_SYNC
1006  LOGWARN("Kinematics thread: "
1007  "Execution slipped by %ld.%09ld seconds.",
1008  tsSlip.tv_sec, tsSlip.tv_nsec);
1009 #else // HEK_KIN_EXEC_ALG_INDIV
1010  LOGWARN("Kinematics thread: "
1011  "Scheduled task %s slipped by %ld.%09ld seconds.",
1012  m_iterTask->c_str(), tsSlip.tv_sec, tsSlip.tv_nsec);
1013 #endif // HEK_KIN_EXEC_ALG_SYNC
1014  }
1015  }
1016 }
int getMasterServoId() const
Get master servo id.
Definition: hekJoint.h:122
virtual int stop()
Stop kinematics chain at the current position.
Definition: hekKin.cxx:399
virtual void freeze()
Freeze kinematics chain at the current position.
Definition: hekKin.cxx:373
virtual int waitForAllStop(double fSeconds)
Wait for all joints to stop.
Definition: hekKin.cxx:464
virtual void sense()
Sense the state of all joints.
Definition: hekKin.cxx:567
virtual void getJointCurPosVel(const std::string &strJointName, double &fJointCurPos, double &fJointCurVel)
Get the current instantaneous joint position and velocity.
Definition: hekKin.cxx:242
static const int HEK_OK
not an error, success
Definition: hekateros.h:70
double m_fHz
thread run rate (Hertz)
Definition: hekKin.h:453
virtual bool isStopped(const std::string &strJointName)
Test if joint is moving.
Definition: hekKin.cxx:308
virtual void react()
React to any necessary time-critical joint events.
Definition: hekKin.cxx:577
Joint trajectory point class.
Definition: hekTraj.h:180
Operational robotic joint description class.
Definition: hekJoint.h:80
static void * thread(void *pArg)
The kinematics thread.
Definition: hekKin.cxx:736
bool m_bIsControlling
[not] actively controlling joints
Definition: hekKin.h:459
TaskList m_taskList
list of tasks to exec per cycle
Definition: hekKin.h:460
ThreadState m_eState
thread state
Definition: hekKin.h:441
Joint points and trajectory class interfaces.
static const int HEK_ECODE_TIMEDOUT
operation timed out error
Definition: hekateros.h:80
thread created and ready to run
Definition: hekKin.h:146
double fcap(double a, double min, double max)
Cap value within limits [min, max].
Definition: hekUtils.h:163
void lock()
Lock the kinematics thread.
Definition: hekKin.h:483
Hekateros tuning data class.
Definition: hekTune.h:408
std::string getJointName() const
Get joint name.
Definition: hekJoint.h:112
static const int HEK_ECODE_BAD_OP
invalid operation error
Definition: hekateros.h:79
virtual int resetServoOdometersForAllJoints()
Reset all joints&#39; master servos odometers to the current respective encoder positions.
Definition: hekKin.cxx:220
KinChain m_kinChain
kinematic chain
Definition: hekKin.h:448
static const double HekTuneKinHzMin
Minimum kinematics thread cycle rate (Hertz).
Definition: hekTune.h:100
Hekateros powered joint dynamics and kinematics control class.
Definition: hekKinJoint.h:387
The Hekateros kinematics and dynamics class interface.
void createThread()
Create the kinematics thread.
Definition: hekKin.cxx:809
void unlock()
Unlock the kinematics thread.
Definition: hekKin.h:497
void waitOneCycle()
Wait one full cycle.
Definition: hekKin.cxx:915
int runThread(const double fHz=HekTuneKinHzDft)
Run the kinematics thread.
Definition: hekKin.cxx:871
double m_fKinematicsHz
kinematic thread rate (hertz)
Definition: hekTune.h:415
virtual ~HekKinematics()
Desctructor.
Definition: hekKin.cxx:153
Hekateros joint classes interfaces.
virtual void monitorHealth()
Monitor servo health thread task.
Definition: hekKin.cxx:633
virtual int act()
Move all joints.
Definition: hekKin.cxx:608
std::string m_strTaskOneCycle
task name one cycle away
Definition: hekKin.h:466
void terminateThread()
Terminate the kinematics thread.
Definition: hekKin.cxx:895
virtual void plan()
Plan motions for all joints.
Definition: hekKin.cxx:598
int m_nNumServos
number of servos to monitor
Definition: hekKin.h:450
virtual int resetServoOdometer(const std::string &strJointName)
Reset joint&#39;s master servo odometer to the current encoder position.
Definition: hekKin.cxx:336
thread created but unitialized
Definition: hekKin.h:145
static const int HEK_ECODE_DYNA
dynamixel error
Definition: hekateros.h:86
pthread_t m_thread
pthread identifier
Definition: hekKin.h:444
size_t getNumPoints()
Get the number of joint points in trajectory.
Definition: hekTraj.h:251
Top-level package include file.
struct timespec m_tsSched
working scheduler time stamp
Definition: hekKin.h:456
pthread_mutex_t m_mutexSync
synchonization mutex
Definition: hekKin.h:442
int jointPosToServoPos(const std::string &strJointName, const double fPos)
Convert joint position to the equivalent servo position.
Definition: hekKin.cxx:278
virtual bool hasOverTorqueCondition(const std::string &strJointName)
Test if joint is in an over torque condition.
Definition: hekKin.cxx:322
virtual void sense_react()
Sense-react the state of all joints.
Definition: hekKin.cxx:587
virtual void exec()
Execute kinematics task(s).
Definition: hekKin.cxx:687
struct timespec m_tsExecPeriod
task execution period (converted)
Definition: hekKin.h:455
void schedWait()
Block kinematics thread until the next subcycle task is to be run.
Definition: hekKin.cxx:965
virtual int senseDynamics(bool bIsControlling)
Sense (read) the current servo dynamics and transform to useful state.
virtual void setHz(const double fHz)
Set thread run rate and ancillary data.
Definition: hekKin.cxx:850
void changeState(ThreadState eNewState)
Change the kinematics thread state.
Definition: hekKin.h:598
pthread_cond_t m_condSync
synchonization condition
Definition: hekKin.h:443
Hekateros common utilities.
virtual void release()
Release kinematics chain.
Definition: hekKin.cxx:382
static const int HEK_ECODE_GEN
general, unspecified error
Definition: hekateros.h:72
virtual void getFilteredJointCurPosVel(const std::string &strJointName, double &fJointCurPos, double &fJointCurVel)
Get the smoothed (filtered) current joint position and velocity.
Definition: hekKin.cxx:254
Hekateros tuning.
virtual void estop()
Emergency stop the kinematics chain.
Definition: hekKin.cxx:356
static const int HEK_ECODE_BAD_VAL
bad value general error
Definition: hekateros.h:75
virtual int move(HekJointTrajectoryPoint &trajectoryPoint)
Move kinematic chain through a trajectory point.
Definition: hekKin.cxx:500
void getServoCurPosSpeed(const std::string &strJointName, int &nServoCurPos, int &nServoCurSpeed)
Get the current servo position and speed.
Definition: hekKin.cxx:266
Hekateros powered joint kinematics and dynamics control class interface.
virtual void buildTaskList()
Build ordered list of tasks to execute.
Definition: hekKin.cxx:174
virtual int act()
Act (write) to effect the servo dynamics for torque and motion control.
DynaChain & m_dynaChain
dynamixel chain
Definition: hekKin.h:447
double m_fTExec
task execution period (seconds)
Definition: hekKin.h:454
int m_iterHealth
servo health iterator
Definition: hekKin.h:468
void timedWait(const struct timespec &tsTimeout)
Timed wait until state change or time out.
Definition: hekKin.cxx:956
virtual void reload(const HekTunes &tunes)
Reload configuration tuning parameters for all joints.
Definition: hekKin.cxx:208
Special wrist rotation joint kinematics and dynamics class.
Definition: hekKinJoint.h:1143
TaskList::iterator m_iterTask
task iterator
Definition: hekKin.h:465
The <b><i>Hekateros</i></b> namespace encapsulates all <b><i>Hekateros</i></b> related constructs...
Definition: hekateros.h:56
double servoPosToJointPos(const std::string &strJointName, const int nOdPos)
Convert servo position to the equivalent joint position.
Definition: hekKin.cxx:293
int m_nHealthServoId
health monitoring servo id
Definition: hekKin.h:469
void readyWait()
Wait indefinitely while in the ready state.
Definition: hekKin.cxx:941
int m_nNumJoints
number of joints to control
Definition: hekKin.h:449