Hekateros  3.4.3
RoadNarrows Robotics Robot Arm Project
hekKinJoint.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Hekateros
4 //
5 // Library: libhekateros
6 //
7 // File: hekKinJoint.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-02-10 13:39:03 -0700 (Tue, 10 Feb 2015) $
12  * $Rev: 3866 $
13  *
14  * \brief The Hekateros powered joint kinematics and dynamics class
15  * implemenation.
16  *
17  * \copyright
18  * \h_copy 2014-2018. RoadNarrows LLC.\n
19  * http://www.roadnarrows.com\n
20  * All Rights Reserved
21  */
22 /*
23  * @EulaBegin@
24  *
25  * Unless otherwise stated explicitly, all materials contained are copyrighted
26  * and may not be used without RoadNarrows LLC's written consent,
27  * except as provided in these terms and conditions or in the copyright
28  * notice (documents and software) or other proprietary notice provided with
29  * the relevant materials.
30  *
31  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
32  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
33  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
34  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
35  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  *
38  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
39  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
40  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
41  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
42  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
43  *
44  * @EulaEnd@
45  */
46 ////////////////////////////////////////////////////////////////////////////////
47 
48 #include <sys/time.h>
49 #include <time.h>
50 #include <limits.h>
51 #include <unistd.h>
52 #include <stdio.h>
53 #include <pthread.h>
54 
55 #include <vector>
56 #include <deque>
57 
58 #include "rnr/rnrconfig.h"
59 #include "rnr/log.h"
60 
61 #include "Dynamixel/Dynamixel.h"
62 #include "Dynamixel/DynaError.h"
63 #include "Dynamixel/DynaTypes.h"
64 #include "Dynamixel/DynaPid.h"
65 #include "Dynamixel/DynaServo.h"
66 
67 #include "Hekateros/hekateros.h"
68 #include "Hekateros/hekTune.h"
69 #include "Hekateros/hekSpec.h"
70 #include "Hekateros/hekJoint.h"
71 #include "Hekateros/hekPid.h"
72 #include "Hekateros/hekKinJoint.h"
73 #include "Hekateros/hekUtils.h"
74 
75 using namespace std;
76 using namespace hekateros;
77 
78 // ---------------------------------------------------------------------------
79 // SyncMoveMsgs Class
80 // ---------------------------------------------------------------------------
81 
82 SyncMoveMsgs::SyncMoveMsgs()
83 {
84  for(int i=0; i<DYNA_ID_NUMOF; ++i)
85  {
86  m_tupSpeed[i].m_nServoId = DYNA_ID_NONE;
87  m_tupSpeed[i].m_nSpeed = 0;
88  m_tupOdPos[i].m_nServoId = DYNA_ID_NONE;
89  m_tupOdPos[i].m_nPos = 0;
90  }
91 
92  m_uSpeedTupCount = 0;
93  m_uOdPosTupCount = 0;
94 }
95 
96 void SyncMoveMsgs::clear()
97 {
98  m_tupSpeed[0].m_nServoId = DYNA_ID_NONE;
99  m_tupSpeed[0].m_nSpeed = 0;
100  m_uSpeedTupCount = 0;
101 
102  m_tupOdPos[0].m_nServoId = DYNA_ID_NONE;
103  m_tupOdPos[0].m_nPos = 0;
104  m_uOdPosTupCount = 0;
105 }
106 
107 int SyncMoveMsgs::addSpeed(int nServoId, int nServoSpeed)
108 {
109  int index;
110 
111  if( m_uSpeedTupCount < DYNA_ID_NONE )
112  {
113  index = (int)m_uSpeedTupCount++;
114  m_tupSpeed[index].m_nServoId = nServoId;
115  m_tupSpeed[index].m_nSpeed = nServoSpeed;
116  }
117  else
118  {
119  index = -1;
120  }
121 
122  return index;
123 }
124 
125 int SyncMoveMsgs::addOdPos(int nServoId, int nServoPos)
126 {
127  int index;
128 
129  if( m_uOdPosTupCount < DYNA_ID_NONE )
130  {
131  index = (int)m_uOdPosTupCount++;
132  m_tupOdPos[index].m_nServoId = nServoId;
133  m_tupOdPos[index].m_nPos = nServoPos;
134  }
135  else
136  {
137  index = -1;
138  }
139 
140  return index;
141 }
142 
143 
144 // ---------------------------------------------------------------------------
145 // VelSpeedTuple Class
146 // ---------------------------------------------------------------------------
147 
148 VelSpeedTuple::VelSpeedTuple()
149 {
150  m_fJointVel = 0.0;
151  m_nServoSpeed = 0;
152 }
153 
154 VelSpeedTuple::VelSpeedTuple(const double fJointVel, const int nServoSpeed)
155 {
156  m_fJointVel = fJointVel;
157  m_nServoSpeed = nServoSpeed;
158 }
159 
160 VelSpeedTuple::VelSpeedTuple(const VelSpeedTuple &src)
161 {
162  m_fJointVel = src.m_fJointVel;
163  m_nServoSpeed = src.m_nServoSpeed;
164 }
165 
166 VelSpeedTuple VelSpeedTuple::operator=(const VelSpeedTuple &rhs)
167 {
168  m_fJointVel = rhs.m_fJointVel;
169  m_nServoSpeed = rhs.m_nServoSpeed;
170 
171  return *this;
172 }
173 
174 
175 // ---------------------------------------------------------------------------
176 // VelSpeedLookupTbl Class
177 // ---------------------------------------------------------------------------
178 
179 VelSpeedLookupTbl::VelSpeedLookupTbl()
180 {
181  m_fBucketSize = 1.0;
182  m_nMaxIndex = 0;
183  m_nNumEntries = 0;
184  m_bDbg = false;
185 }
186 
187 VelSpeedLookupTbl VelSpeedLookupTbl::operator=(const VelSpeedLookupTbl &rhs)
188 {
189  m_fBucketSize = rhs.m_fBucketSize;
190  m_nMaxIndex = rhs.m_nMaxIndex;
191  m_nNumEntries = rhs.m_nNumEntries;
192  m_tbl = rhs.m_tbl;
193  m_strDbgId = rhs.m_strDbgId;
194  m_bDbg = rhs.m_bDbg;
195 }
196 
197 void VelSpeedLookupTbl::create(double fJointMaxVel, double fBucketSize)
198 {
199  size_t nElems;
200  VelSpeedTuple noentry(0.0, NO_ENTRY);
201 
202  fJointMaxVel = fabs(fJointMaxVel);
203  m_fBucketSize = fabs(fBucketSize);
204 
205  nElems = (int)(fJointMaxVel / m_fBucketSize);
206  if( (double)nElems * m_fBucketSize < fJointMaxVel )
207  {
208  ++nElems; // round up
209  }
210  ++nElems; // include zero entry
211 
212  m_tbl.insert(m_tbl.begin(), nElems, noentry);
213 
214  m_nMaxIndex = (int)m_tbl.size() - 1;
215 
216  m_tbl[0] = VelSpeedTuple(0.0, 0);
217  m_tbl[m_nMaxIndex] = VelSpeedTuple(fJointMaxVel, DYNA_SPEED_MAX_RAW);
218 
219  m_nNumEntries = 2;
220 
221  if( m_bDbg )
222  {
223  fprintf(stderr, "DBG: %s(): %s: tbl_size=%zu, num_entries=%d\n",
224  LOGFUNCNAME,
225  m_strDbgId.c_str(), m_tbl.size(), m_nNumEntries);
226  }
227 }
228 
229 int VelSpeedLookupTbl::hash(double fJointVel)
230 {
231  int index = (int)(fabs(fJointVel)/m_fBucketSize);
232  return cap(index, 0, m_nMaxIndex);
233 }
234 
235 void VelSpeedLookupTbl::update(double fJointVel, int nServoSpeed)
236 {
237  int index = hash(fJointVel);
238 
239  if( (index > 0) && (index < m_nMaxIndex) )
240  {
241  int nOldCnt = m_nNumEntries;
242 
243  if( m_tbl[index].m_nServoSpeed == NO_ENTRY )
244  {
245  ++m_nNumEntries;
246  }
247 
248  m_tbl[index].m_fJointVel = fabs(fJointVel);
249  m_tbl[index].m_nServoSpeed = iabs(nServoSpeed);
250  if( m_tbl[index].m_nServoSpeed < MIN_NON_ZERO_SPEED )
251  {
252  m_tbl[index].m_nServoSpeed = MIN_NON_ZERO_SPEED;
253  }
254 
255  if( m_bDbg && (m_nNumEntries != nOldCnt) )
256  {
257  fprintf(stderr, "DBG: %s(): %s: "
258  "num_entries=%d, index=%d, vel=%lf, speed=%d\n",
259  LOGFUNCNAME,
260  m_strDbgId.c_str(), m_nNumEntries, index,
261  radToDeg(m_tbl[index].m_fJointVel), m_tbl[index].m_nServoSpeed);
262  }
263  }
264 }
265 
266 int VelSpeedLookupTbl::estimate(double fJointGoalVel)
267 {
268  double fJointAbsVel = fabs(fJointGoalVel);
269 
270  // zero is 0
271  if( fJointAbsVel == 0.0 )
272  {
273  return m_tbl[0].m_nServoSpeed;
274  }
275  // maximum velocity
276  else if( fJointAbsVel >= m_tbl[m_nMaxIndex].m_fJointVel )
277  {
278  return m_tbl[m_nMaxIndex].m_nServoSpeed;
279  }
280 
281  double fMinVel;
282  int nMinSpeed;
283  double fMaxVel;
284  int nMaxSpeed;
285 
286  int index = hash(fJointAbsVel);
287 
288  // no entry at hashed location
289  if( m_tbl[index].m_nServoSpeed == NO_ENTRY )
290  {
291  nMinSpeed = NO_ENTRY;
292  nMaxSpeed = NO_ENTRY;
293  }
294  // go lucky - no interpolation needed
295  else if( m_tbl[index].m_fJointVel == fJointAbsVel )
296  {
297  return m_tbl[index].m_nServoSpeed;
298  }
299  // hashed location is minimum neighbor
300  else if( m_tbl[index].m_fJointVel < fJointAbsVel )
301  {
302  fMinVel = m_tbl[index].m_fJointVel;
303  nMinSpeed = m_tbl[index].m_nServoSpeed;
304  nMaxSpeed = NO_ENTRY;
305  }
306  // hashed location is maximum neighbor
307  else
308  {
309  nMinSpeed = NO_ENTRY;
310  fMaxVel = m_tbl[index].m_fJointVel;
311  nMaxSpeed = m_tbl[index].m_nServoSpeed;
312  }
313 
314  // no minimum neighbor - search downward
315  if( nMinSpeed == NO_ENTRY )
316  {
317  for(int i = index-1; i >= 0; --i)
318  {
319  if( m_tbl[i].m_nServoSpeed == NO_ENTRY )
320  {
321  continue;
322  }
323  else if( m_tbl[i].m_fJointVel < fJointAbsVel )
324  {
325  fMinVel = m_tbl[i].m_fJointVel;
326  nMinSpeed = m_tbl[i].m_nServoSpeed;
327  break;
328  }
329  }
330  }
331  if( nMinSpeed == NO_ENTRY )
332  {
333  return m_tbl[0].m_nServoSpeed;
334  }
335 
336  // no maximum neighbor - search upward
337  if( nMaxSpeed == NO_ENTRY )
338  {
339  for(int i = index+1; i <= m_nMaxIndex; ++i)
340  {
341  if( m_tbl[i].m_nServoSpeed == NO_ENTRY )
342  {
343  continue;
344  }
345  else if( m_tbl[i].m_fJointVel > fJointAbsVel )
346  {
347  fMaxVel = m_tbl[i].m_fJointVel;
348  nMaxSpeed = m_tbl[i].m_nServoSpeed;
349  break;
350  }
351  }
352  }
353  if( nMaxSpeed == NO_ENTRY )
354  {
355  return m_tbl[m_nMaxIndex].m_nServoSpeed;
356  }
357 
358  // interpolate
359  return (int)((double)nMinSpeed + fabs(nMaxSpeed - nMinSpeed) *
360  (fJointAbsVel - fMinVel) / (fMaxVel - fMinVel));
361 }
362 
363 void VelSpeedLookupTbl::enableDebugging(const std::string &strId)
364 {
365  m_strDbgId = strId;
366  m_bDbg = true;
367 }
368 
369 void VelSpeedLookupTbl::disableDebugging()
370 {
371  m_bDbg = false;
372 }
373 
374 void VelSpeedLookupTbl::dumpTable(const std::string &strId)
375 {
376  fprintf(stderr, "DBG: %s: bucket_size=%.2lf deg, lookup table[%zu] =\n{\n",
377  strId.c_str(), radToDeg(m_fBucketSize), m_tbl.size());
378 
379  for(int i=0; i<m_tbl.size(); ++i)
380  {
381  if( m_tbl[i].m_nServoSpeed != NO_ENTRY )
382  {
383  fprintf(stderr, " [%3d]: vel=%7.3lf (%6.2lf deg), speed=%4d\n",
384  i, m_tbl[i].m_fJointVel, radToDeg(m_tbl[i].m_fJointVel),
385  m_tbl[i].m_nServoSpeed);
386  }
387  }
388  fprintf(stderr, "}\n");
389 }
390 
391 // ---------------------------------------------------------------------------
392 // HekKinJoint Class
393 // ---------------------------------------------------------------------------
394 
395 const double HekKinJoint::SLOW_DERATE_DELTA_V = 1.0;
396 
397 HekKinJoint::HekKinJoint() :
398  m_pJoint(NULL), m_pServo(NULL),
399  m_pid(HekTunePidKpDft, HekTunePidKiDft, HekTunePidKdDft),
400  m_histPosIn(POS_WIN_SIZE, 0.0),
401  m_histDtIn(DT_WIN_SIZE, 0.0),
402  m_histVelIn(VEL_WIN_SIZE, 0.0),
403  m_histTorqueIn(TORQUE_WIN_SIZE, 0.0)
404 {
406 
407  pthread_mutex_init(&m_mutexSync, NULL);
408 
412 
413  m_fJointRadPerTick = 1.0;
414  m_fJointGoalPos = 0.0;
415  m_nServoGoalPos = 0;
416  m_fJointCurPos = 0.0;
417  m_nServoCurPos = 0;
418  m_fJointPrevPos = 0.0;
419  m_nServoPrevPos = 0;
420  m_fJointPosOut = 0.0;
421 
422  m_fDt = 0.0;
423  clock_gettime(CLOCK_REALTIME, &m_tsPrev);
424  m_fDtAvg = 0.0;
425 
426  m_fJointGoalVel = 0.0;
427  m_fJointCurVel = 0.0;
428  m_nServoCurSpeed = 0;
430  m_fJointVelOut = 0.0;
431 
432  m_fJointTgtVel = 0.0;
433  m_nServoTgtSpeed = 0;
434 
435  m_bOverTorqueCond = false;
436  m_fOverTorqueTh = 0.0;
437  m_fClearTorqueTh = 0.0;
438  m_fTorqueOut = 0.0;
439 }
440 
442  DynaServo *pServo,
443  const HekTunes &tunes) :
444  m_pJoint(pJoint), m_pServo(pServo),
446  m_histDtIn(DT_WIN_SIZE, 0.0),
449 {
450  double fKp, fKi, fKd;
451  double fMaxDeltaV;
452  double fRawMaxTorque;
453 
455 
456  pthread_mutex_init(&m_mutexSync, NULL);
457 
458  // joint tolerance tuning parameters (normalized)
460 
461  // joint position and velocity PID tuning parameters
462  tunes.getPidKParams(pJoint->m_strName, fKp, fKi, fKd);
463 
464  // pid constants
465  setPidKParams(fKp, fKi, fKd);
466 
467  // joint pid maximum delta velocity tuning paramter
468  fMaxDeltaV = tunes.getPidMaxDeltaV(m_pJoint->m_strName);
469 
470  // maximum PID output delta v (radians/second)
471  setPidMaxDeltaVParam(fMaxDeltaV);
472 
473  // stop velocity maximum velocity
474  m_fStopVelTh = SLOW_DERATE_DELTA_V * fMaxDeltaV;
475 
476  // position state
478  m_fJointGoalPos = 0.0;
479  m_nServoGoalPos = 0;
480  m_fJointCurPos = 0.0;
481  m_nServoCurPos = 0;
482  m_fJointPrevPos = 0.0;
483  m_nServoPrevPos = 0;
484  m_fJointPosOut = 0.0;
485 
486  // clock
487  m_fDt = 0.0;
488  clock_gettime(CLOCK_REALTIME, &m_tsPrev);
489  m_fDtAvg = 0.0;
490 
491  // velocity state
492  m_fJointGoalVel = 0.0;
493  m_fJointCurVel = 0.0;
494  m_nServoCurSpeed = 0;
495  m_fVelDerate = tunes.getVelocityDerate(); // tuning parameter (norm)
496  m_fJointVelOut = 0.0;
497 
498  m_fJointTgtVel = 0.0;
499  m_nServoTgtSpeed = 0;
500 
501  // To debug any joint(s).
502  //if( m_pJoint->m_strName == "base_rot")
503  //{
504  // m_tblVelSpeed.enableDebugging(m_pJoint->m_strName);
505  //}
506 
508 
509  // normalized joint torque tuning parameters
511 
512  // convert to raw theshold values
513  m_bOverTorqueCond = false;
514  fRawMaxTorque = (double)pServo->GetSpecification().m_uRawTorqueMax;
515  m_fOverTorqueTh *= fRawMaxTorque;
516  m_fClearTorqueTh *= fRawMaxTorque;
517  m_fTorqueOut = 0.0;
518 }
519 
521 {
522  m_eState = rhs.m_eState;
523  m_pJoint = rhs.m_pJoint;
524  m_pServo = rhs.m_pServo;
525 
526  m_fTolPos = rhs.m_fTolPos;
527  m_fTolVel = rhs.m_fTolVel;
529  m_pid = rhs.m_pid;
530 
539  m_histPosIn = rhs.m_histPosIn;
540 
541  m_fDt = rhs.m_fDt;
542  m_tsPrev = rhs.m_tsPrev;
543  m_fDtAvg = rhs.m_fDtAvg;
544  m_histDtIn = rhs.m_histDtIn;
545 
551  m_histVelIn = rhs.m_histVelIn;
552 
555 
561 
562  return *this;
563 }
564 
565 void HekKinJoint::reload(const HekTunes &tunes)
566 {
567  double fKp, fKi, fKd;
568  double fMaxDeltaV;
569  double fRawMaxTorque;
570 
571  lock();
572 
573  // joint tolerance tuning parameters (normalized)
575 
576  // joint position and velocity PID tuning parameters
577  tunes.getPidKParams(m_pJoint->m_strName, fKp, fKi, fKd);
578 
579  // set classic pid parameters
580  setPidKParams(fKp, fKi, fKd);
581 
582  // joint pid maximum delta velocity tuning paramter
583  fMaxDeltaV = tunes.getPidMaxDeltaV(m_pJoint->m_strName);
584 
585  // maximum PID output delta v (radians/second)
586  setPidMaxDeltaVParam(fMaxDeltaV);
587 
588  // stop velocity maximum velocity
589  m_fStopVelTh = SLOW_DERATE_DELTA_V * fMaxDeltaV;
590 
591  // velocity derate
593 
594  // normalized joint torque tuning parameters
596 
597  // convert to raw theshold values
598  fRawMaxTorque = (double)m_pServo->GetSpecification().m_uRawTorqueMax;
599  m_fOverTorqueTh *= fRawMaxTorque;
600  m_fClearTorqueTh *= fRawMaxTorque;
601 
602  unlock();
603 }
604 
606 {
607  uint_t uEncZeroPt; // encoder position mapping to new odometer zero pt
608  bool bIsReverse; // odometer is [not] reverse to that of encoder
609  int rc; // return code
610 
611  if( m_pServo == NULL )
612  {
613  return HEK_OK;
614  }
615 
616  lock();
617 
618  // must be stopped
619  nlstop();
620 
621  // read encoder position (note: should add libDynamixel function)
622  if( (rc = m_pServo->Read(DYNA_ADDR_CUR_POS_LSB, &uEncZeroPt)) != DYNA_OK )
623  {
624  LOGERROR("Joint %s (servo=%d): Cannot read current encoder position.",
626  rc = -HEK_ECODE_DYNA;
627  }
628 
629  else
630  {
631  bIsReverse = m_pJoint->m_nMasterServoDir == DYNA_DIR_CCW? false: true;
632 
633  // reset soft odometer
634  m_pServo->ResetOdometer((int)uEncZeroPt, bIsReverse);
635 
636  LOGDIAG3("Joint %s (servo=%d): Odometer reset at encoder=%u, reverse=%s.",
638  uEncZeroPt, boolstr(bIsReverse));
639 
640  m_fJointGoalPos = 0.0;
641  m_nServoGoalPos = 0;
642  m_fJointCurPos = 0.0;
643  m_nServoCurPos = 0;
644  m_fJointPrevPos = 0.0;
645  m_nServoPrevPos = 0;
646 
647  m_fJointGoalVel = 0.0;
648  m_fJointCurVel = 0.0;
649  m_nServoCurSpeed = 0;
650 
651  m_fJointTgtVel = 0.0;
652  m_nServoTgtSpeed = 0;
653 
654  rc = HEK_OK;
655  }
656 
657  unlock();
658 
659  return rc;
660 }
661 
662 int HekKinJoint::specifyMove(const double fGoalPos, const double fGoalVel)
663 {
664  int rc;
665 
666  lock();
667 
668  rc = nlspecifyMove(fGoalPos, fGoalVel);
669 
670  unlock();
671 
672  return rc;
673 }
674 
675 int HekKinJoint::nlspecifyMove(const double fGoalPos, const double fGoalVel)
676 {
677  // new goal position
678  m_fJointGoalPos = fGoalPos;
679 
680  //
681  // Check for goal position out of range condition and cap as necessary.
682  //
683  // Note: Only check if the joint has been calibrated. If calibrated, assume
684  // a calibration routine is calling the function and "it knows what
685  // it is doing".
686  //
688  {
690  {
691  if( m_fJointGoalPos < m_pJoint->m_fMinSoftLimitRads )
692  {
693  LOGDIAG3("Joint %s (servo=%d): "
694  "Goal position %.02lf < %.02lf degree limit - capping.",
697 
699  }
701  {
702  LOGDIAG3("Joint %s (servo=%d): "
703  "Goal position %.02lf > %.02lf degree limit - capping.",
706 
708  }
709  }
710  }
711 
712  // joint position to odometer position
714 
715  //
716  // Joint current and goal positions dictate sign of velocity.
717  //
718  m_fJointGoalVel = fabs(fGoalVel);
720  {
722  }
723 
724  // derate
726 
727  // new move
728  //if( fabs(m_fJointGoalPos-m_fJointCurPos) > m_fTolPos )
729  //{
732  //}
733 
734  return HEK_OK;
735 }
736 
738 {
739  int nSign = m_pServo->IsOdometerReversed()? -1: 1;
740 
741  return (m_nServoGoalPos-m_pServo->GetOdometer()) >= 0? nSign: -1 * nSign;
742 }
743 
744 int HekKinJoint::getPlannedDir(int nServoTgtSpeed)
745 {
746  return nServoTgtSpeed >= 0? 1: -1;
747 }
748 
750 {
751  return !m_bOverTorqueCond || (getGoalDir() == DYNA_GET_DIR(m_nServoCurLoad));
752 }
753 
754 bool HekKinJoint::canMoveInPlannedDir(int nServoTgtSpeed)
755 {
756  return !m_bOverTorqueCond ||
757  (getPlannedDir(nServoTgtSpeed) == DYNA_GET_DIR(m_nServoCurLoad));
758 }
759 
760 int HekKinJoint::senseDynamics(bool bIsControlling)
761 {
762  int nServoDejitPos;
763  int rc;
764 
765  if( m_pServo == NULL )
766  {
767  return HEK_OK;
768  }
769 
770  lock();
771 
772  // save current servo position as the new previous position
774 
775  // Read the servo dynamics.
776  rc = m_pServo->ReadDynamics(&m_nServoCurPos,
778  &m_nServoCurLoad);
779 
780  // sanity check
783  m_pJoint->m_fTicksPerServoRad * M_PI) )
784  {
785  LOGWARN("Large jump in servo position: prev_odpos=%d, cur_odpos=%d.",
787  }
788 
789  //
790  // Transform.
791  //
792  if( rc == DYNA_OK )
793  {
794  // delta time
795  m_fDt = delta_t();
796 
797  // running average of delta times (not used for now)
798  //m_fDtAvg = averageDt(m_fDtAvg, m_fDt);
799 
800  // de-jitter servo odometer (encoder) position
802 
803  // current joint position (radians)
805  m_fJointCurPos = servoPosToJointPos(nServoDejitPos);
806 
807  // low-pass band filter current positions
809 
810  // current joint velocity (radians/second)
812 
813  // update joint instantaneous velocity-servo speed lookup table
814  if( bIsControlling )
815  {
817  }
818 
819  // low-pass band filter current velocities
821 
822  // low-pass band filter torque (raw unitless load)
824 
825  // set over torque limit condition
826  if( fabs(m_fTorqueOut) > m_fOverTorqueTh )
827  {
828  if( !m_bOverTorqueCond && bIsControlling )
829  {
830  LOGWARN("Joint %s (servo=%d): Entered over-torque condition. "
831  "Load=%lf.",
832  m_pJoint->m_strName.c_str(), m_pServo->GetServoId(), m_fTorqueOut);
833  }
834  m_bOverTorqueCond = true;
835  }
836 
837  // clear over torque limit condition
838  else if( fabs(m_fTorqueOut) < m_fClearTorqueTh )
839  {
840  if( m_bOverTorqueCond && bIsControlling )
841  {
842  LOGDIAG2("Joint %s (servo=%d): Cleared over-torque condition.",
843  m_pJoint->m_strName.c_str(), m_pServo->GetServoId());
844  }
845  m_bOverTorqueCond = false;
846  }
847  }
848 
849  unlock();
850 
851  return rc == DYNA_OK? HEK_OK: -HEK_ECODE_DYNA;
852 }
853 
854 int HekKinJoint::react(bool bIsControlling, SyncMoveMsgs &msgs)
855 {
856  if( !bIsControlling )
857  {
858  return HEK_OK;
859  }
860 
861  lock();
862 
863  //
864  // Joint is slowing to a stop.
865  //
866  if( isStopping() )
867  {
868  nlslowToStop(msgs);
869  }
870 
871  //
872  // Joint has moved close enough to goal position, and is slow enough to stop.
873  // Otherwise let the PID do its thing.
874  //
875  else if( isMovingToGoal() &&
877  canStopNow() )
878  {
879  nlstop();
880  }
881 
882  //
883  // In over torque condition, apply torque control.
884  //
885  if( m_bOverTorqueCond )
886  {
888  }
889 
890  unlock();
891 
892  return HEK_OK;
893 }
894 
896  SyncMoveMsgs &msgs)
897 {
898  if( m_pServo == NULL )
899  {
900  return MoveStateIdle;
901  }
902  else if( !bIsControlling )
903  {
904  return m_eState;
905  }
906 
907  lock();
908 
909  if( isMovingToGoal() )
910  {
911  // PID target velocity and corresponding target servo speed estimate
914 
915  // still away from goal position
916  if( (fabs(m_fJointGoalPos-m_fJointCurPos) > m_fTolPos) &&
918  {
919  // new move - make it happen
920  if( m_eState == MoveStateNewMove )
921  {
923  }
924 
925  // subsequent changes of servo speed - only if sufficently different
926  else if( fabs(m_fJointTgtVel-m_fJointCurVel) > m_fTolVel )
927  {
929  }
930  }
931  }
932 
933  unlock();
934 
935  return m_eState;
936 }
937 
939 {
940  lock();
941 
942  //
943  // Actively moving joint and there is no over torque condition or the goal
944  // direction will naturally ease the torque.
945  //
946  if( isMovingToGoal() && canMoveInGoalDir() )
947  {
948  nlmove();
949  }
950 
951  //
952  // In over torque condition, apply torque control.
953  //
954  else if( m_bOverTorqueCond )
955  {
957  }
958 
959  unlock();
960 
961  return HEK_OK;
962 }
963 
965 {
966  int rc;
967 
968  if( m_pServo == NULL )
969  {
970  return HEK_OK;
971  }
972 
973  lock();
974 
975  rc = nlapplyTorqueControl();
976 
977  unlock();
978 
979  return rc;
980 }
981 
983 {
984  static const int TuneMaxIters = 5; // max iterations to ease torque
985  static const useconds_t TuneWait = 100; // wait between iterations
986 
987  int nSign;
988  int nOffSpeed;
989  int nOffPos;
990 
991  if( fabs(m_fTorqueOut) > m_fOverTorqueTh )
992  {
993  LOGDIAG4("Executing torque control for servo %d.", m_pServo->GetServoId());
994 
995  nSign = DYNA_GET_DIR(m_nServoCurLoad);
996  nOffSpeed = TORQUE_CTL_BACKOFF_SPEED;
997 
998  switch( m_pServo->GetServoMode() )
999  {
1000  case DYNA_MODE_CONTINUOUS:
1001  nOffSpeed *= nSign;
1002  m_pServo->WriteGoalSpeed(nOffSpeed);
1003  for(int i = 0; i < TuneMaxIters; ++i)
1004  {
1005  usleep(TuneWait);
1006  m_pServo->ReadCurLoad(&m_nServoCurLoad);
1008  if( fabs(m_fTorqueOut) <= m_fOverTorqueTh )
1009  {
1010  break;
1011  }
1012  }
1013  m_pServo->Stop();
1014  break;
1015 
1016  case DYNA_MODE_SERVO:
1017  default:
1018  nOffPos = nSign * TORQUE_CTL_BACKOFF_POS;
1019  m_pServo->WriteGoalSpeed(nOffSpeed);
1020  m_pServo->WriteGoalPos(nOffPos);
1021  break;
1022  }
1023  }
1024 
1025  return HEK_OK;
1026 }
1027 
1029 {
1030  MoveState eState;
1031 
1032  if( m_pServo == NULL )
1033  {
1034  return MoveStateIdle;
1035  }
1036 
1037  lock();
1038 
1039  eState = nlmove();
1040 
1041  unlock();
1042 
1043  return eState;
1044 }
1045 
1047 {
1048  if( isMovingToGoal() )
1049  {
1050  // still away from goal position
1052  {
1053  // PID target velocity and corresponding target servo speed estimate
1056 
1057  // new move - make it happen
1058  if( m_eState == MoveStateNewMove )
1059  {
1061  }
1062 
1063  // subsequent changes of servo speed - only if sufficently different
1064  else if( fabs(m_fJointTgtVel-m_fJointCurVel) > m_fTolVel )
1065  {
1067  }
1068  }
1069 
1070  // at goal position
1071  else
1072  {
1073  nlstop();
1074  }
1075  }
1076 
1077  return m_eState;
1078 }
1079 
1080 void HekKinJoint::moveServo(int nServoGoalSpeed, int nServoGoalPos)
1081 {
1082  //
1083  // Annoying Dynamixel subtleties are outlined here.
1084  //
1085  // In continuous mode:
1086  // When writing to the goal speed, the servo will immediately begin
1087  // movement. Servo goal position has no effect. A value of 0 will
1088  // stop the servo. The speeds are signed values.
1089  //
1090  // In servo mode:
1091  // When writing the goal position, if different from the current
1092  // position, the servo will immediately move at the goal speed
1093  // loaded in its control table. So always write goal speed first,
1094  // then goal position. The value of 0 cause the servo to go ape shit,
1095  // moving at its maximum speed with no servo control. Avoid this value
1096  // like the Ebola. To stop the servo, write the current position as
1097  // its goal position. One final nit, no negative speeds.
1098  //
1099  if( m_pServo->GetServoMode() == DYNA_MODE_CONTINUOUS )
1100  {
1101  nServoGoalSpeed = cap(nServoGoalSpeed, -DYNA_SPEED_MAX_RAW,
1102  DYNA_SPEED_MAX_RAW);
1103  m_pServo->WriteGoalSpeed(nServoGoalSpeed);
1104  }
1105  else
1106  {
1107  nServoGoalSpeed = cap(iabs(nServoGoalSpeed), DYNA_SPEED_MIN_CTL,
1108  DYNA_SPEED_MAX_RAW);
1109  m_pServo->WriteGoalSpeed(nServoGoalSpeed);
1110  if( m_eState == MoveStateNewMove )
1111  {
1112  m_pServo->WriteGoalPos(nServoGoalPos);
1114  }
1115  }
1116 }
1117 
1119  int nServoTgtSpeed,
1120  int nServoGoalPos)
1121 {
1122  //
1123  // See discussion in moveServo() for Dynamixel nuances.
1124  //
1125  if( m_pServo->GetServoMode() == DYNA_MODE_CONTINUOUS )
1126  {
1127  nServoTgtSpeed = cap(nServoTgtSpeed, -DYNA_SPEED_MAX_RAW,
1128  DYNA_SPEED_MAX_RAW);
1129  msgs.addSpeed(m_pServo->GetServoId(), nServoTgtSpeed);
1130  }
1131  else
1132  {
1133  m_nServoTgtSpeed = cap(iabs(nServoTgtSpeed), DYNA_SPEED_MIN_CTL,
1134  DYNA_SPEED_MAX_RAW);
1135  msgs.addSpeed(m_pServo->GetServoId(), nServoTgtSpeed);
1136  if( m_eState == MoveStateNewMove )
1137  {
1138  msgs.addOdPos(m_pServo->GetServoId(), nServoGoalPos);
1140  }
1141  }
1142 }
1143 
1145 {
1146  int rc;
1147 
1148  if( m_pServo == NULL )
1149  {
1150  return -HEK_ECODE_DYNA;
1151  }
1152 
1153  lock();
1154 
1155  rc = nlstop();
1156 
1157  unlock();
1158 
1159  return rc;
1160 }
1161 
1163 {
1164 #ifdef HEK_KIN_EXEC_ALG_SYNC
1165  //
1166  // Test if moving too fast. If true, use a fast ramp down to slow to a
1167  // stopping speed. The ramp is defined by the maximum delta velocity tune
1168  // parameter.
1169  //
1170  // Note: During calibration stop means stop.
1171  //
1172  if( !canStopNow() )
1173  {
1174  //fprintf(stderr, "DBG: %s() MOVING TO FAST TO STOP: "
1175  // "curvel=%lf, stopvelth=%lf\n",
1176  // LOGFUNCNAME, radToDeg(m_fJointCurVel), radToDeg(m_fStopVelTh));
1177 
1179  return HEK_OK;
1180  }
1181 #endif // HEK_KIN_EXEC_ALG_SYNC
1182 
1183  m_pServo->Stop();
1184 
1185  if( m_pServo->ReadCurPos(&m_nServoCurPos) == DYNA_OK )
1186  {
1188  }
1189 
1192 
1193  m_fJointCurVel = 0.0;
1194  m_nServoCurSpeed = 0;
1195 
1198  m_fJointGoalVel = 0.0;
1199 
1200  m_fJointTgtVel = 0.0;
1201  m_nServoTgtSpeed = 0;
1202 
1204 
1205  //fprintf(stderr, "DBG: STOP: %s\n", m_pJoint->m_strName.c_str());
1206 
1207  return HEK_OK;
1208 }
1209 
1211 {
1212  double fJointStopVel;
1213  int nServoStopSpeed;
1214 
1215  if( (fabs(m_fJointCurVel) <= m_fStopVelTh) )
1216  {
1217  //fprintf(stderr, "DBG: %s() SLOWED ENOUGH: curvel=%lf\n",
1218  // LOGFUNCNAME, radToDeg(m_fJointCurVel));
1219 
1220  return nlstop();
1221  }
1222  else
1223  {
1224  if( m_fJointCurVel > 0.0 )
1225  {
1226  fJointStopVel = m_fJointCurVel - m_fStopVelTh;
1227  }
1228  else
1229  {
1230  fJointStopVel = m_fJointCurVel + m_fStopVelTh;
1231  }
1232 
1233  nServoStopSpeed = estimateServoTgtSpeed(fJointStopVel);
1234 
1235  addServoMsgEntries(msgs, nServoStopSpeed, m_nServoGoalPos);
1236 
1237  //fprintf(stderr, "DBG: %s() SLOWING TO: curvel=%lf, stopvel=%lf\n",
1238  // LOGFUNCNAME, radToDeg(m_fJointCurVel), radToDeg(fJointStopVel));
1239 
1240  return HEK_OK;
1241  }
1242 }
1243 
1244 int HekKinJoint::jointPosToServoPos(const double fPos)
1245 {
1246  return (int)(fPos * m_pJoint->m_fTicksPerJointRad);
1247 }
1248 
1249 double HekKinJoint::servoPosToJointPos(const int nOdPos)
1250 {
1251  return (double)nOdPos / m_pJoint->m_fTicksPerJointRad;
1252 }
1253 
1254 double HekKinJoint::jointVelocity(double fPos1, double fPos0, double fDt)
1255 {
1256  return fDt > 0.0? (fPos1 - fPos0) / fDt: 0.0;
1257 }
1258 
1259 void HekKinJoint::updateAssoc(double fJointVel, int nServoSpeed)
1260 {
1261  m_tblVelSpeed.update(fJointVel, nServoSpeed);
1262 }
1263 
1264 int HekKinJoint::estimateServoTgtSpeed(double fJointTgtVel)
1265 {
1266  int nSign = (int)signof(fJointTgtVel);
1267 
1268  if( m_pServo->IsOdometerReversed() )
1269  {
1270  nSign = -nSign;
1271  }
1272 
1273  return nSign * m_tblVelSpeed.estimate(fJointTgtVel);
1274 }
1275 
1277 {
1278  double r;
1279  int nSpeedEst;
1280 
1281  r = fJointTgtVel / m_pJoint->m_fMaxJointRadsPerSec;
1282  nSpeedEst = (int)(DYNA_SPEED_MAX_RAW * r);
1283  nSpeedEst = cap(nSpeedEst, 0, DYNA_SPEED_MAX_RAW) * getGoalDir();
1284 
1285  return nSpeedEst;
1286 }
1287 
1289 {
1290  struct timespec tsNow;
1291  double deltaTime;
1292 
1293  // now
1294  clock_gettime(CLOCK_REALTIME, &tsNow);
1295 
1296  // delta time in seconds
1297  deltaTime = hekateros::dt(tsNow, m_tsPrev);
1298 
1299  // new previous
1300  m_tsPrev = tsNow;
1301 
1302  return deltaTime;
1303 }
1304 
1305 double HekKinJoint::averageDt(double fDtAvg, double fDt)
1306 {
1307  double fDt0;
1308  double fDtK;
1309 
1310  fDt0 = fDt / (double)DT_WIN_SIZE;
1311  fDtK = m_histDtIn.back();
1312  m_histDtIn.pop_back();
1313  m_histDtIn.push_front(fDt0);
1314 
1315  return fDtAvg - fDtK + fDt0;
1316 }
1317 
1318 int HekKinJoint::dejitterServoPos(int nServoCurPos, int nServoPrevPos)
1319 {
1320  // Same position over two sense cycles - accept new position.
1321  if( nServoCurPos == nServoPrevPos )
1322  {
1323  return nServoCurPos;
1324  }
1325 
1326  // Sufficiently large jump in position, probably not jitter.
1327  else if( hekateros::iabs(nServoCurPos-nServoPrevPos) > 1 )
1328  {
1329  return nServoCurPos;
1330  }
1331 
1332  // Small change is position, treat as sampling and/or random jitter.
1333  else
1334  {
1335  return nServoPrevPos;
1336  }
1337 }
1338 
1339 double HekKinJoint::filterPositions(double fPosAvg, double fJointPos)
1340 {
1341  double fPos0;
1342  double fPosK;
1343 
1344  fPos0 = fJointPos / (double)POS_WIN_SIZE;
1345  fPosK = m_histPosIn.back();
1346  m_histPosIn.pop_back();
1347  m_histPosIn.push_front(fPos0);
1348 
1349  return fPosAvg - fPosK + fPos0;
1350 }
1351 
1352 double HekKinJoint::filterVelocities(double fVelAvg, double fJointVel)
1353 {
1354  double fVel0;
1355  double fVelK;
1356 
1357  fVel0 = fJointVel / (double)VEL_WIN_SIZE;
1358  fVelK = m_histVelIn.back();
1359  m_histVelIn.pop_back();
1360  m_histVelIn.push_front(fVel0);
1361 
1362  return fVelAvg - fVelK + fVel0;
1363 }
1364 
1365 double HekKinJoint::filterTorques(double fTorqueAvg, int nServoLoad)
1366 {
1367  double fTorque0;
1368  double fTorqueK;
1369 
1370  fTorque0 = (double)nServoLoad / (double)TORQUE_WIN_SIZE;
1371  fTorqueK = m_histTorqueIn.back();
1372  m_histTorqueIn.pop_back();
1373  m_histTorqueIn.push_front(fTorque0);
1374 
1375  return fTorqueAvg - fTorqueK + fTorque0;
1376 }
1377 
1378 
1379 // ---------------------------------------------------------------------------
1380 // HekKinJointWristRot Class
1381 // ---------------------------------------------------------------------------
1382 
1383 int HekKinJointWristRot::react(bool bIsControlling, SyncMoveMsgs &msgs)
1384 {
1385  if( !bIsControlling )
1386  {
1387  return HEK_OK;
1388  }
1389 
1390  lock();
1391 
1392  HekKinJoint::MoveState eStatePrev = m_eStateWristPitch;
1393 
1394  m_eStateWristPitch = getCoupledJointState();
1395 
1396  //
1397  // Wrist rotation is not moving and wrist pitch has transitioned from moving
1398  // to stop. Respecify wrist rotation goal move to avoid minor wrist rotation
1399  // drift.
1400  //
1401  if( isStopped() )
1402  {
1403  if( isCoupledJointStopped() && (eStatePrev != MoveStateIdle) )
1404  {
1405  //fprintf(stderr, "DBG: %s() isStopped - respecify move\n", LOGFUNCNAME);
1407  }
1408  }
1409 
1410  //
1411  // Joint is slowing to a stop.
1412  //
1413  else if( isStopping() )
1414  {
1415  //fprintf(stderr, "DBG: %s() isStopping\n", LOGFUNCNAME);
1416  nlslowToStop(msgs);
1417  }
1418 
1419  //
1420  // Joint has moved close enough to goal position, and is slow enough to stop.
1421  // Otherwise let the PID do its thing.
1422  //
1423  else if( isMovingToGoal() &&
1425  canStopNow() )
1426  {
1427  nlstop();
1428  //fprintf(stderr, "DBG: %s() stop\n", LOGFUNCNAME);
1429  }
1430 
1431  //
1432  // In over torque condition, apply torque control.
1433  //
1434  if( m_bOverTorqueCond )
1435  {
1437  }
1438 
1439  unlock();
1440 
1441  return HEK_OK;
1442 }
1443 
1445  SyncMoveMsgs &msgs)
1446 {
1447  double fAdjustVel;
1448  int fAdjustSpeed;
1449 
1450  if( m_pServo == NULL )
1451  {
1452  return MoveStateIdle;
1453  }
1454  else if( !bIsControlling )
1455  {
1456  return m_eState;
1457  }
1458 
1459  lock();
1460 
1461  m_eStateWristPitch = getCoupledJointState();
1462 
1463  if( isCoupledJointMoving() )
1464  {
1465  m_pKinJointWristPitch->getTgtVelSpeed(fAdjustVel, fAdjustSpeed);
1466  }
1467  else
1468  {
1469  fAdjustVel = 0.0;
1470  fAdjustSpeed = 0;
1471  }
1472 
1473  if( isMovingToGoal() || isCoupledJointMoving() )
1474  {
1475  // servo goal od position can change with coupled joints - recalculate
1477 
1478  if( isMovingToGoal() )
1479  {
1480  // PID target velocity
1482 
1483  // estimate corresponding target servo speed
1485  }
1486  else
1487  {
1488  m_fJointTgtVel = 0.0;
1489  m_nServoTgtSpeed = 0;
1490  }
1491 
1492  m_nServoTgtSpeed -= fAdjustSpeed;
1493 
1494  // still away from goal position
1495  if( ( (fabs(m_fJointGoalPos-m_fJointCurPos) > m_fTolPos) ||
1496  isCoupledJointMoving() ) &&
1498  {
1499  // new move - make it happen
1500  if( (m_eState == MoveStateNewMove) ||
1501  (m_eStateWristPitch == MoveStateNewMove) )
1502  {
1504  }
1505 
1506  // subsequent changes of servo speed - only if sufficently different
1507  else if( fabs(m_fJointTgtVel-m_fJointCurVel) > m_fTolVel )
1508  {
1510  }
1511  }
1512  }
1513 
1514  unlock();
1515 
1516  return m_eState;
1517 }
1518 
1520 {
1521  lock();
1522 
1523  HekKinJoint::MoveState eStatePrev = m_eStateWristPitch;
1524 
1525  m_eStateWristPitch = getCoupledJointState();
1526 
1527  if( isStopped() && isCoupledJointStopped() &&
1528  (eStatePrev != MoveStateIdle) )
1529  {
1531  }
1532 
1533  //
1534  // Actively moving wrist rotation and/or wrist pitch and there is no over
1535  // torque condition or the goal direction will naturally ease the torque.
1536  //
1537  if( isMovingToGoal() || isCoupledJointMoving() && canMoveInGoalDir() )
1538  {
1539  nlmove();
1540  }
1541 
1542  //
1543  // In over torque condition, apply torque control.
1544  //
1545  else if( m_bOverTorqueCond )
1546  {
1548  }
1549 
1550  unlock();
1551 
1552  return HEK_OK;
1553 }
1554 
1556 {
1557  double fAdjustVel;
1558  int fAdjustSpeed;
1559 
1560  if( m_eStateWristPitch != MoveStateIdle )
1561  {
1562  m_pKinJointWristPitch->getTgtVelSpeed(fAdjustVel, fAdjustSpeed);
1563  }
1564  else
1565  {
1566  fAdjustVel = 0.0;
1567  fAdjustSpeed = 0;
1568  }
1569 
1570  if( isMovingToGoal() || isCoupledJointMoving() )
1571  {
1572  // still away from goal position
1573  if( (fabs(m_fJointGoalPos-m_fJointCurPos) > m_fTolPos) ||
1574  (m_eStateWristPitch != MoveStateIdle) )
1575  {
1576  // servo goal od position can change with coupled joints - recalculate
1578 
1579  if( isMovingToGoal() )
1580  {
1581  // PID target velocity
1583 
1584  // estimate corresponding target servo speed
1586  }
1587  else
1588  {
1589  m_fJointTgtVel = 0.0;
1590  m_nServoTgtSpeed = 0;
1591  }
1592 
1593  m_nServoTgtSpeed -= fAdjustSpeed;
1594 
1595  // new move - make it happen
1596  if( m_eState == MoveStateNewMove )
1597  {
1599  }
1600 
1601  // subsequent changes of servo speed - only if sufficently different
1602  else if( fabs(m_fJointTgtVel-m_fJointCurVel) > m_fTolVel )
1603  {
1605  }
1606  }
1607 
1608  // at goal position
1609  else
1610  {
1611  nlstop();
1612  }
1613  }
1614 
1615  return m_eState;
1616 }
1617 
1619 {
1620  double fAdjustVel;
1621  int fAdjustSpeed;
1622  double fJointStopVel;
1623  int nServoStopSpeed;
1624 
1625  if( (fabs(m_fJointCurVel) <= m_fStopVelTh) )
1626  {
1627  //fprintf(stderr, "DBG: %s() SLOWED ENOUGH: curvel=%lf\n",
1628  // LOGFUNCNAME, radToDeg(m_fJointCurVel));
1629 
1630  return nlstop();
1631  }
1632  else
1633  {
1634  if( m_fJointCurVel > 0.0 )
1635  {
1636  fJointStopVel = m_fJointCurVel - m_fStopVelTh;
1637  }
1638  else
1639  {
1640  fJointStopVel = m_fJointCurVel + m_fStopVelTh;
1641  }
1642 
1643  nServoStopSpeed = estimateServoTgtSpeed(fJointStopVel);
1644 
1645  if( isCoupledJointMoving() )
1646  {
1647  m_pKinJointWristPitch->getTgtVelSpeed(fAdjustVel, fAdjustSpeed);
1648  }
1649  else
1650  {
1651  fAdjustVel = 0.0;
1652  fAdjustSpeed = 0;
1653  }
1654 
1655  nServoStopSpeed -= fAdjustSpeed;
1656 
1657  addServoMsgEntries(msgs, nServoStopSpeed, m_nServoGoalPos);
1658 
1659  //fprintf(stderr, "DBG: %s() SLOWING TO: curvel=%lf, stopvel=%lf\n",
1660  // LOGFUNCNAME, radToDeg(m_fJointCurVel), radToDeg(fJointStopVel));
1661 
1662  return HEK_OK;
1663  }
1664 }
1665 
1667 {
1668  int nAdjustPos = 0, nAdjustSpeed = 0;
1669  int nServoPos;
1670 
1671  if( m_pKinJointWristPitch != NULL )
1672  {
1673  m_pKinJointWristPitch->getServoCurPosSpeed(nAdjustPos, nAdjustSpeed);
1674  }
1675 
1676  nServoPos = (int)(fPos * m_pJoint->m_fTicksPerJointRad);
1677 
1678  return nServoPos + nAdjustPos;
1679 }
1680 
1682 {
1683  double fAdjustPos = 0, fAdjustVel = 0;
1684  double fJointPos;
1685 
1686  if( m_pKinJointWristPitch != NULL )
1687  {
1688  m_pKinJointWristPitch->getJointCurPosVel(fAdjustPos, fAdjustVel);
1689  }
1690 
1691  fJointPos = (double)nOdPos * m_fJointRadPerTick;
1692 
1693  return fJointPos - fAdjustPos;
1694 }
1695 
1696 void HekKinJointWristRot::updateAssoc(double fJointVel, int nServoSpeed)
1697 {
1698  double fAdjustPos = 0.0, fAdjustVel = 0.0;
1699 
1700  if( m_pKinJointWristPitch != NULL )
1701  {
1702  m_pKinJointWristPitch->getJointCurPosVel(fAdjustPos, fAdjustVel);
1703  }
1704 
1705  // pure wrist rotation move only
1706  if( (fAdjustVel == 0.0) && (getCoupledJointState() == MoveStateIdle) )
1707  {
1708  m_tblVelSpeed.update(fJointVel, nServoSpeed);
1709  }
1710 }
1711 
1713 {
1714  if( m_pKinJointWristPitch != NULL )
1715  {
1716  return m_pKinJointWristPitch->getMoveState();
1717  }
1718  else
1719  {
1720  return MoveStateIdle;
1721  }
1722 }
virtual double servoPosToJointPos(int nOdPos)
Convert servo position to the equivalent joint position.
const char * boolstr(bool b)
Boolean to string.
Definition: hekUtils.h:108
virtual void updateAssoc(double fJointVel, int nServoSpeed)
Update joint velocity - servo speed association.
int addSpeed(int nServoId, int nServoSpeed)
Add servo speed to speed tuple array.
double filterPositions(double fPosAvg, double fJointPos)
Apply a low-pass band filter on the joint positions (radians).
virtual int jointPosToServoPos(double fPos)
Convert joint position to the equivalent servo position.
virtual int estimateServoTgtSpeed(double fJointTgtVel)
Estimate of target servo speed from target joint velocity.
int specifyMove(const double fGoalPos, const double fGoalVel)
Specify a new joint goal position and velocity move.
int estimate(double fJointGoalVel)
Estimate servo goal speed.
virtual int jointPosToServoPos(const double fPos)
Convert joint position to the equivalent servo position.
double m_fOverTorqueTh
set over torque condition threshold
Definition: hekKinJoint.h:855
int dejitterServoPos(int nServoCurPos, int nServoPrevPos)
De-jitter servo odometer position.
static const int TORQUE_CTL_BACKOFF_SPEED
Torque control backoff speed (raw unitless)
Definition: hekKinJoint.h:422
void getToleranceParams(const std::string &strJointName, double &fTolPos, double &fTolVel) const
Get joint tolerance tune parameters.
Definition: hekTune.cxx:101
static const int HEK_OK
not an error, success
Definition: hekateros.h:70
VelSpeedTbl m_tbl
dynamic interpolation table
Definition: hekKinJoint.h:366
HekOpState m_eOpState
current operational state
Definition: hekJoint.h:179
virtual int nlapplyTorqueControl()
Apply torque limit control (no lock version).
double m_fMinSoftLimitRads
joint min soft limit (radians)
Definition: hekJoint.h:166
double m_fVelDerate
joint velocity derate (normalized)
Definition: hekKinJoint.h:844
int m_nServoCurLoad
servo current load (raw unitless)
Definition: hekKinJoint.h:857
std::deque< double > m_histPosIn
recent history of joint positions
Definition: hekKinJoint.h:832
virtual MoveState move()
Move joint using joint PID controller.
double m_fStopVelTh
joint velocity threshold to safely stop move
Definition: hekKinJoint.h:820
HekRobotJoint * m_pJoint
joint description
Definition: hekKinJoint.h:814
double getPidMaxDeltaV(const std::string &strJointName) const
Get joint PID maximum delta v (radians/second) tune parameter.
Definition: hekTune.cxx:137
virtual int nlstop()
Stop movement and move control of the joint (no lock version).
int m_nServoCurPos
servo current position (odometer ticks)
Definition: hekKinJoint.h:828
Operational robotic joint description class.
Definition: hekJoint.h:80
static const double SLOW_DERATE_DELTA_V
Stop delta v as a fraction of max_delta_v tune parameter.
Definition: hekKinJoint.h:411
DynaServo * m_pServo
joint master servo control
Definition: hekKinJoint.h:815
double signof(double a)
Sign of a.
Definition: hekUtils.h:187
int m_nNumEntries
number of populated table entries.
Definition: hekKinJoint.h:365
double m_fJointVelOut
low-pass filtered joint cur velocity
Definition: hekKinJoint.h:846
virtual MoveState planMotion(bool bIsControlling, SyncMoveMsgs &msgs)
Plan motion.
int m_nServoCurSpeed
current motor speed (raw unitless)
Definition: hekKinJoint.h:843
double m_fTicksPerJointRad
encoder/odom. ticks per joint radian
Definition: hekJoint.h:157
int m_nServoGoalPos
servo goal position (odometer ticks)
Definition: hekKinJoint.h:826
double dt(struct timeval &t1, struct timeval &t0)
Calculate delta time.
double m_fTicksPerServoRad
encoder/odom. ticks per servo radian
Definition: hekJoint.h:156
int m_eJointType
joint type
Definition: hekJoint.h:154
virtual int nlslowToStop(SyncMoveMsgs &msg)
Slow to stop (no lock version).
std::deque< double > m_histTorqueIn
recent history of joint torques
Definition: hekKinJoint.h:859
double m_fMaxJointRadsPerSec
maximum joint radians per second
Definition: hekJoint.h:159
bool canMoveInPlannedDir(int nServoTgtSpeed)
Test if joint can move in planned direction.
static const double HekTunePidMaxDeltaVDft
Maximum PID delta V output (degrees/second)
Definition: hekTune.h:314
void update(double fJointVel, int nServoSpeed)
Update lookup table entry.
double m_fTolPos
joint position &plusmn; tolerance (rads)
Definition: hekKinJoint.h:818
int m_nMaxIndex
maximum index into table
Definition: hekKinJoint.h:364
double getVelocityDerate() const
Get derated velocity tune parameter (normalized).
Definition: hekTune.h:451
void lock()
Lock the joint kinematics.
Definition: hekKinJoint.h:874
virtual int applyTorqueControl()
Apply torque limit control.
double radToDeg(double r)
Convert radians to degrees.
Definition: hekUtils.h:137
int addOdPos(int nServoId, int nServoPos)
Add servo position to position tuple array.
virtual void specifySetPoint(double fJointGoalPos, double fJointGoalVel)
Specify the PID set point.
Definition: hekPid.cxx:71
int m_nMasterServoId
master servo id
Definition: hekJoint.h:150
std::string m_strDbgId
debugging id
Definition: hekKinJoint.h:367
pthread_mutex_t m_mutexSync
synchonization mutex
Definition: hekKinJoint.h:813
double delta_t()
Calculate the delta time between calls to this.
void unlock()
Unlock the joint kinematics.
Definition: hekKinJoint.h:888
virtual void reload(const HekTunes &tunes)
Reload configuration tuning parameters.
virtual double jointVelocity(double fPos1, double fPos0, double fDt)
Calculate the joint velocity from delta servo positions.
Hekateros tuning data class.
Definition: hekTune.h:408
static const size_t POS_WIN_SIZE
Position sliding window size for low-pass band filtering of input positions.
Definition: hekKinJoint.h:394
MoveState m_eState
joint control state
Definition: hekKinJoint.h:812
int cap(int a, int min, int max)
Cap value within limits [min, max].
Definition: hekUtils.h:177
Container class to hold Dynamixel synchronous messages data.
Definition: hekKinJoint.h:93
int getPlannedDir(int nServoTgtSpeed)
Get the planned target rotation direction.
int m_nServoTgtSpeed
target motor speed (raw unitless)
Definition: hekKinJoint.h:851
void setPidKParams(const double fKp, const double fKi, const double fKd)
Set the joint&#39;s position and velocity PID K parameters.
Definition: hekKinJoint.h:589
Hekateros powered joint dynamics and kinematics control class.
Definition: hekKinJoint.h:387
continuous rotation
Definition: hekSpec.h:78
virtual int react(bool bIsControlling, SyncMoveMsgs &msgs)
React to recently read sensor data.
double m_fDt
delta time between positions reads
Definition: hekKinJoint.h:835
static const size_t DT_WIN_SIZE
Delta t sliding window size for low-pass band filtering of input delta times.
Definition: hekKinJoint.h:400
void create(double fJointMaxVel, double fBucketSize)
Create lookup table.
double m_fJointGoalPos
joint goal position (radians)
Definition: hekKinJoint.h:825
void getTorqueParams(const std::string &strJointName, double &fOverTorqueTh, double &fClearTorqueTh) const
Get joint torque parameters.
Definition: hekTune.cxx:151
virtual int stop()
Stop movement and move control of the joint.
double m_fBucketSize
table entry size (degrees/second)
Definition: hekKinJoint.h:363
Joint velocity/ servo speed lookup table class.
Definition: hekKinJoint.h:249
virtual int nlslowToStop(SyncMoveMsgs &msg)
Slow to stop (no lock version).
Hekateros joint classes interfaces.
virtual double control(double fJointCurPos, double fJointCurVel, double fDt)
Apply PID control.
Definition: hekPid.h:203
double m_fJointPrevPos
joint current position (radians)
Definition: hekKinJoint.h:829
double m_fJointPosOut
low-pass filtered joint cur position
Definition: hekKinJoint.h:831
void moveServo(int nServoGoalSpeed, int nServoGoalPos)
Move servo.
static const double HekTuneVelDerateDft
Default Hekateros robot velocity derate (% of goal velocities).
Definition: hekTune.h:206
double m_fTorqueOut
low-pass filtered torque
Definition: hekKinJoint.h:858
std::deque< double > m_histDtIn
sliding window of delta t&#39;s
Definition: hekKinJoint.h:838
int m_nServoPrevPos
servo previous pos (odometer ticks)
Definition: hekKinJoint.h:830
double m_fJointRadPerTick
joint radians / odometer tick
Definition: hekKinJoint.h:824
static const size_t VEL_WIN_SIZE
Velocity sliding window size for low-pass band filtering of input Velocities.
Definition: hekKinJoint.h:406
double m_fJointCurPos
joint current position (radians)
Definition: hekKinJoint.h:827
double filterVelocities(double fVelAvg, double fJointVel)
Apply a low-pass band filter on the joint velocities (radians/second).
std::deque< double > m_histVelIn
sliding window of current velocities
Definition: hekKinJoint.h:847
double m_fJointVel
joint velocity (radians/second)
Definition: hekKinJoint.h:198
std::string m_strName
joint name
Definition: hekJoint.h:149
int iabs(int a)
Integer absolute value.
Definition: hekUtils.h:149
The Hekateros joint position and velocity PID class interface.
static const int HEK_ECODE_DYNA
dynamixel error
Definition: hekateros.h:86
static const double HekTuneTolVelDft
Default joint velocity control tolerance (degrees/second).
Definition: hekTune.h:268
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
void addServoMsgEntries(SyncMoveMsgs &msg, int nServoGoalSpeed, int nServoGoalPos)
Add servo to synchronous move message(s).
static const size_t TORQUE_WIN_SIZE
Torque sliding window size for low-pass band filtering of input torques.
Definition: hekKinJoint.h:417
bool isMovingToGoal()
Test if actively moving joint to goal.
Definition: hekKinJoint.h:521
static const double HekTuneTolPosDft
Default joint position control tolerance (degrees).
Definition: hekTune.h:239
no active goal or stopping control
Definition: hekKinJoint.h:437
struct timespec m_tsPrev
previous time mark
Definition: hekKinJoint.h:836
void setPidMaxDeltaVParam(const double fMaxDeltaV)
Set joint PID maximum delta v (radians/second) parameter.
Definition: hekKinJoint.h:609
virtual int nlspecifyMove(const double fGoalPos, const double fGoalVel)
Specify a new joint goal position and velocity move (no lock version).
HekPid m_pid
joint position and velocity PID
Definition: hekKinJoint.h:821
virtual bool isStopped()
Test if joint is stopped (i.e. control is not active).
Definition: hekKinJoint.h:551
int m_nServoSpeed
associated servo speed (raw unitless)
Definition: hekKinJoint.h:199
double m_fJointCurVel
joint current velocity (radians/second)
Definition: hekKinJoint.h:842
virtual int senseDynamics(bool bIsControlling)
Sense (read) the current servo dynamics and transform to useful state.
int m_nMasterServoDir
master servo normalized direction
Definition: hekJoint.h:153
VelSpeedLookupTbl m_tblVelSpeed
dynamic velocity/speed lookup table
Definition: hekKinJoint.h:845
virtual MoveState nlmove()
Move joint using joint PID controller (no lock version).
double m_fJointGoalVel
joint goal velocity (radians/second)
Definition: hekKinJoint.h:841
HekKinJoint & operator=(const HekKinJoint &rhs)
Assignment operator.
HekKinJoint()
Default constructor.
<b><i>Hekateros</i></b> product specification base classes.
double m_fJointTgtVel
joint target velocity (radians/second)
Definition: hekKinJoint.h:850
virtual int resetServoOdometer()
Reset servo odometer zero point to the current encoder position.
virtual void updateAssoc(double fJointVel, int nServoSpeed)
Update joint velocity - servo speed association.
virtual int react(bool bIsControlling, SyncMoveMsgs &msgs)
React to recently read sensor data.
static const int TORQUE_CTL_BACKOFF_POS
Torque control backoff positon (odometer ticks)
Definition: hekKinJoint.h:427
Hekateros common utilities.
bool canMoveInGoalDir()
Test if joint can move in direction of goal position.
double averageDt(double fDtAvg, double fDt)
Apply a running average for the delta times (seconds).
Hekateros tuning.
Hekateros powered joint kinematics and dynamics control class interface.
double m_fDtAvg
average delta t
Definition: hekKinJoint.h:837
virtual int act()
Act (write) to effect the servo dynamics for torque and motion control.
bool m_bDbg
enable [disable] debugging
Definition: hekKinJoint.h:368
double m_fTolVel
joint velocity &plusmn; tolerance (rads/s)
Definition: hekKinJoint.h:819
virtual MoveState planMotion(bool bIsControlling, SyncMoveMsgs &msgs)
Plan motion.
Joint velocity to servo speed tuple class.
Definition: hekKinJoint.h:195
virtual int act()
Act (write) to effect the servo dynamics for torque and motion control.
bool canStopNow()
Test if can stop now without slowing down.
Definition: hekKinJoint.h:561
bool isStopping()
Test if actively stopping joint.
Definition: hekKinJoint.h:531
MoveState getCoupledJointState()
Get coupled joint&#39;s move state.
virtual double servoPosToJointPos(const int nOdPos)
Convert servo position to the equivalent joint position.
bool m_bOverTorqueCond
is [not] in torque overload condition
Definition: hekKinJoint.h:854
double m_fClearTorqueTh
clear over torque condition threshold
Definition: hekKinJoint.h:856
MoveState
Kinedynamics joint position and velocity control states.
Definition: hekKinJoint.h:435
void getPidKParams(const std::string &strJointName, double &fKp, double &fKi, double &fKd) const
Get joint PID K tune parameters.
Definition: hekTune.cxx:118
int getGoalDir()
Get the current goal rotation direction.
virtual int estimateServoTgtSpeedSimple(double fJointTgtVel)
Simple estimate of target servo speed from target joint velocity.
The <b><i>Hekateros</i></b> namespace encapsulates all <b><i>Hekateros</i></b> related constructs...
Definition: hekateros.h:56
double filterTorques(double fTorqueAvg, int nServoLoad)
Apply a low-pass band filter on the sensed torques (loads).
virtual MoveState nlmove()
Move joint using joint PID controller (no lock version).