Dynamixel  2.9.5
RoadNarrows Robotics Dynamixel Package
DynaChain.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Dynamixel
4 //
5 // Library: libDynamixel
6 //
7 // File: DynaChain.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-01-12 11:54:07 -0700 (Mon, 12 Jan 2015) $
12  * $Rev: 3846 $
13  *
14  * \brief Dynamixel Chain class.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \copyright
19  * \h_copy 2011-2017. RoadNarrows LLC.\n
20  * http://www.roadnarrows.com\n
21  * All Rights Reserved
22  */
23 /*
24  * @EulaBegin@
25  *
26  * Unless otherwise stated explicitly, all materials contained are copyrighted
27  * and may not be used without RoadNarrows LLC's written consent,
28  * except as provided in these terms and conditions or in the copyright
29  * notice (documents and software) or other proprietary notice provided with
30  * the relevant materials.
31  *
32  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
33  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
34  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
35  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
36  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
37  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
40  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
41  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
42  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
43  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
44  *
45  * @EulaEnd@
46  */
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <libgen.h>
52 #include <string.h>
53 
54 #include "rnr/rnrconfig.h"
55 #include "rnr/log.h"
56 #include "rnr/new.h"
57 #include "rnr/units.h"
58 
59 #include "Dynamixel/Dynamixel.h"
60 #include "Dynamixel/DynaError.h"
61 #include "Dynamixel/DynaComm.h"
62 #include "Dynamixel/DynaServo.h"
63 #include "Dynamixel/DynaChain.h"
64 #include "Dynamixel/DynaOlio.h"
65 
66 #include "DynaLibInternal.h"
67 
68 
69 // ---------------------------------------------------------------------------
70 // Private Interface
71 // ---------------------------------------------------------------------------
72 
73 
74 // ---------------------------------------------------------------------------
75 // DynaChain Class
76 // ---------------------------------------------------------------------------
77 
78 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79 // Constructors and Destructors
80 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81 
82 DynaChain::DynaChain(DynaComm &comm) : m_comm(comm)
83 {
84  Init();
85 }
86 
88 {
89  int nServoId;
90 
91  for(nServoId=DYNA_ID_MIN; nServoId<DYNA_ID_NUMOF; ++nServoId)
92  {
93  if( m_pChain[nServoId] != NULL )
94  {
95  delete m_pChain[nServoId];
96  }
97  }
98 }
99 
100 
101 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
102 // Attribute Functions
103 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
104 
105 int DynaChain::LinkServos(int nServoIdMaster,
106  int nServoIdSlave,
107  bool bIsReversed)
108 {
109  DynaServo *pServoM;
110  DynaServo *pServoS;
111  int rc;
112 
113  DYNA_TRY_SERVO_IN_CHAIN(this, nServoIdMaster);
114  DYNA_TRY_SERVO_IN_CHAIN(this, nServoIdSlave);
115 
116  DYNA_TRY_EXPR(((m_links[nServoIdMaster].m_uLinkType == DYNA_LINK_NONE) &&
117  (m_links[nServoIdSlave].m_uLinkType == DYNA_LINK_NONE)),
119  "Servos %d and/or %d: Already have linkage.",
120  nServoIdMaster, nServoIdSlave);
121 
122  pServoM = m_pChain[nServoIdMaster];
123  pServoS = m_pChain[nServoIdSlave];
124 
125  if( pServoM->GetModelNumber() != pServoS->GetModelNumber() )
126  {
127  rc = -DYNA_ECODE_LINKED;
128  DYNA_LOG_ERROR(rc, "Cannot link unmatched servos: "
129  "servo %d model %s(%d) != servo %d model %s(%d).",
130  nServoIdMaster, pServoM->GetModelName(), pServoM->GetModelNumber(),
131  nServoIdSlave, pServoS->GetModelName(), pServoS->GetModelNumber());
132  return rc;
133  }
134 
135  pServoM->Link(DYNA_LINK_MASTER, pServoS, bIsReversed);
136  pServoS->Link(DYNA_LINK_SLAVE, pServoM, bIsReversed);
137 
138  SetLinkData(nServoIdMaster, DYNA_LINK_MASTER, nServoIdSlave, bIsReversed);
139  SetLinkData(nServoIdSlave, DYNA_LINK_SLAVE, nServoIdMaster, bIsReversed);
140 
142 
143  return DYNA_OK;
144 }
145 
146 int DynaChain::UnlinkServos(int nServoIdMaster)
147 {
148  int nServoIdSlave;
149  DynaServo *pServoM;
150  DynaServo *pServoS;
151  int rc;
152 
153  DYNA_TRY_SERVO_IN_CHAIN(this, nServoIdMaster);
154 
155  pServoM = m_pChain[nServoIdMaster];
156 
157  nServoIdSlave = m_links[nServoIdMaster].m_nServoIdMate;
158 
159  DYNA_TRY_SERVO_IN_CHAIN(this, nServoIdSlave);
160 
161  pServoS = m_pChain[nServoIdSlave];
162 
164  ((m_links[nServoIdMaster].m_uLinkType != DYNA_LINK_NONE) &&
165  (m_links[nServoIdSlave].m_uLinkType != DYNA_LINK_NONE) &&
166  (m_links[nServoIdSlave].m_nServoIdMate == nServoIdMaster)),
168  "Servos %d and/or %d: Not linked.",
169  nServoIdMaster, nServoIdSlave);
170 
171  pServoM->Unlink();
172  pServoS->Unlink();
173 
174  ClearLinkData(nServoIdMaster);
175  ClearLinkData(nServoIdSlave);
176 
178 
179  return DYNA_OK;
180 }
181 
183 {
184  int i;
185  int nServoId;
186 
188 
189  for(i=0; i<(int)m_uNumInChain; ++i)
190  {
191  nServoId = m_nIIdx[i];
192 
193  if( (nServoId != DYNA_ID_NONE) && IsMaster(nServoId) )
194  {
196  }
197  }
198 
199  return m_uNumMastersInChain;
200 }
201 
202 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
203 // Chain Servo Add/Remove Functions
204 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
205 
206 int DynaChain::AddNewServo(int nServoId)
207 {
208  int rc;
209 
211  DYNA_TRY_SERVO_ID(nServoId);
212 
213  // Ping the servo
214  if( !DynaServo::Ping(m_comm, nServoId) )
215  {
216  rc = -DYNA_ECODE_NO_SERVO;
217  DYNA_LOG_ERROR(rc, "Pinging servo %d failed. Cannot add.", nServoId);
218  }
219 
220  // create and insert chain entry
221  else if( (rc = ChainEntryNew(nServoId)) == DYNA_OK )
222  {
223  AuditLinks();
224  }
225 
226  return rc;
227 }
228 
230 {
231  int nServoId;
232  int nNumAdded;
233 
235 
236  // remove and delete all servos
237  for(nServoId=DYNA_ID_MIN; nServoId<DYNA_ID_NUMOF; ++nServoId)
238  {
239  ChainEntryDelete(nServoId);
240  }
241 
242  // add all by scan
243  for(nServoId=DYNA_ID_MIN, nNumAdded=0; nServoId<DYNA_ID_NUMOF; ++nServoId)
244  {
245  if( DynaServo::Ping(m_comm, nServoId) )
246  {
247  if( ChainEntryNew(nServoId) == DYNA_OK )
248  {
249  ++nNumAdded;
250  }
251  }
252  }
253 
254  AuditLinks();
255 
256  return nNumAdded;
257 }
258 
259 int DynaChain::AddNewServoForced(int nServoId, uint_t uModelNum)
260 {
261  /*! \todo TODO force add servo to chain */
262  return -DYNA_ECODE_NOT_SUPP;
263 }
264 
265 int DynaChain::RemoveServo(int nServoId)
266 {
267  DYNA_TRY_SERVO_IN_CHAIN(this, nServoId);
268 
269  ChainEntryDelete(nServoId);
270  AuditLinks();
271 
272  return DYNA_OK;
273 }
274 
276 {
277  int nServoId;
278 
279  for(nServoId=DYNA_ID_MIN; nServoId<DYNA_ID_NUMOF; ++nServoId)
280  {
281  if( m_pChain[nServoId] != NULL )
282  {
283  ChainEntryDelete(nServoId);
284  }
285  }
286 
287  AuditLinks();
288 
289  return DYNA_OK;
290 }
291 
292 
293 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
294 // Protected Interface
295 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
296 
298 {
299  int nServoId;
300 
301  m_uNumInChain = 0;
303 
304  for(nServoId=DYNA_ID_MIN; nServoId<DYNA_ID_NUMOF; ++nServoId)
305  {
306  m_pChain[nServoId] = NULL;
307  m_nIIdx[nServoId] = DYNA_ID_NONE;
308  ClearLinkData(nServoId);
309  }
310 }
311 
312 int DynaChain::ChainEntryNew(int nServoId)
313 {
314  DynaServo *pServo;
315  int rc;
316 
318  DYNA_TRY_SERVO_ID(nServoId);
319 
320  // create derived servo object
321  pServo = DynaServo::New(m_comm, nServoId);
322 
323  if( pServo == NULL )
324  {
325  rc = -DYNA_ECODE_NO_SERVO;
326  DYNA_LOG_ERROR(rc, "Failed to create servo %d. Cannot add.", nServoId);
327  return rc;
328  }
329 
330  // remove any existing servo with the same id
331  if( m_pChain[nServoId] != NULL )
332  {
333  ChainEntryDelete(nServoId);
334  }
335 
336  // insert into chain
337  m_pChain[nServoId] = pServo;
338  m_nIIdx[m_uNumInChain++] = nServoId;
339 
340  LOGDIAG3("%s servo %d (model number 0x%04x) added to chain.",
341  pServo->GetModelName(), nServoId, pServo->GetModelNumber());
342 
343  return DYNA_OK;
344 }
345 
347 {
348  DynaServo *pServo;
349  uint_t i, j;
350 
351  DYNA_TRY_SERVO_ID(nServoId);
352 
353  // okay not to be in chain
354  if( (pServo = m_pChain[nServoId]) == NULL )
355  {
356  return DYNA_OK;
357  }
358 
359  // remove from indirect index list
360  for(i=0; i<m_uNumInChain; ++i)
361  {
362  if( m_nIIdx[i] == nServoId )
363  {
364  m_nIIdx[i] = DYNA_ID_NONE;
365  m_uNumInChain--;
366  break;
367  }
368  }
369 
370  // compress indirect index list
371  for(j=i; j<m_uNumInChain; ++j)
372  {
373  m_nIIdx[j] = m_nIIdx[j+1];
374  m_nIIdx[j+1] = DYNA_ID_NONE;
375  }
376 
377  LOGDIAG3("%s servo %d (model number 0x%04x) removed from chain.",
378  pServo->GetModelName(), nServoId, pServo->GetModelNumber());
379 
380  // delete from chain
381  delete m_pChain[nServoId];
382 
383  m_pChain[nServoId] = NULL;
384 
385  return DYNA_OK;
386 }
387 
389 {
390  int nServoIdThis;
391  uint_t uLinkType;
392  int nServoIdMate;
393  bool bRotReversed;
394  DynaServo *pServoThis;
395  DynaServo *pServoMate;
396 
397  for(nServoIdThis=DYNA_ID_MIN; nServoIdThis<DYNA_ID_NUMOF; ++nServoIdThis)
398  {
399  uLinkType = m_links[nServoIdThis].m_uLinkType;
400  nServoIdMate = m_links[nServoIdThis].m_nServoIdMate;
401  bRotReversed = m_links[nServoIdThis].m_bRotReversed;
402  pServoThis = m_pChain[nServoIdThis];
403 
404  // this servo is not present in the chain
405  if( pServoThis == NULL )
406  {
407  ClearLinkData(nServoIdThis);
408  }
409 
410  // this link is either the master or slave servo
411  else if( (uLinkType == DYNA_LINK_MASTER) || (uLinkType == DYNA_LINK_SLAVE) )
412  {
413  // no linked mate
414  if( (nServoIdMate < DYNA_ID_MIN) ||
415  (nServoIdMate > DYNA_ID_MAX) ||
416  ((pServoMate = m_pChain[nServoIdMate]) == NULL) )
417  {
418  pServoThis->Unlink();
419  ClearLinkData(nServoIdThis);
420  }
421 
422  // linked servos mismatch
423  else if(pServoThis->GetModelNumber() != pServoMate->GetModelNumber())
424  {
425  pServoThis->Unlink();
426  pServoMate->Unlink();
427  ClearLinkData(nServoIdThis);
428  }
429 
430  // this link is the master servo
431  else if( uLinkType == DYNA_LINK_MASTER )
432  {
433  pServoThis->Link(DYNA_LINK_MASTER, pServoMate, bRotReversed);
434  pServoMate->Link(DYNA_LINK_SLAVE, pServoThis, bRotReversed);
435  SetLinkData(nServoIdMate, DYNA_LINK_SLAVE, nServoIdThis, bRotReversed);
436  }
437 
438  // this link is the slave servo
439  else
440  {
441  pServoThis->Link(DYNA_LINK_SLAVE, pServoMate, bRotReversed);
442  pServoMate->Link(DYNA_LINK_MASTER, pServoThis, bRotReversed);
443  SetLinkData(nServoIdMate, DYNA_LINK_MASTER, nServoIdThis, bRotReversed);
444  }
445  }
446 
447  // this servo has no link
448  else // DYNA_LINK_NONE
449  {
450  pServoThis->Unlink();
451  ClearLinkData(nServoIdThis);
452  }
453  }
454 
456 }
457 
458 void DynaChain::SetLinkData(int nServoId,
459  uint_t uLinkType,
460  int nServoIdMate,
461  bool bRotReversed)
462 {
463  m_links[nServoId].m_uLinkType = uLinkType;
464  m_links[nServoId].m_nServoIdMate = nServoIdMate;
465  m_links[nServoId].m_bRotReversed = bRotReversed;
466 }
467 
468 void DynaChain::ClearLinkData(int nServoId)
469 {
470  m_links[nServoId].m_uLinkType = DYNA_LINK_NONE;
471  m_links[nServoId].m_nServoIdMate = DYNA_ID_NONE;
472  m_links[nServoId].m_bRotReversed = false;
473 }
474 
475 
476 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
477 // Master and Synchronous Move Functions
478 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
479 
480 int DynaChain::MoveTo(int nServoId, int nGoalOdPos)
481 {
482  DynaServo *pServo;
483 
485  DYNA_TRY_SERVO_IN_CHAIN(this, nServoId);
486 
487  pServo = m_pChain[nServoId];
488 
489  DYNA_TRY_IS_MASTER(pServo);
490 
491  return pServo->MoveTo(nGoalOdPos);
492 }
493 
494 int DynaChain::vSyncMoveTo(uint_t uCount, ...)
495 {
496  DynaPosTuple_T tuplesPos[DYNA_ID_NUMOF];
497  va_list ap;
498  int i;
499 
500  va_start(ap, uCount);
501 
502  for(i=0; i<uCount && i<DYNA_ID_NUMOF; ++i)
503  {
504  tuplesPos[i].m_nServoId = va_arg(ap, int);
505  tuplesPos[i].m_nPos = va_arg(ap, int);
506  }
507 
508  va_end(ap);
509 
510  return SyncMoveTo(tuplesPos, (uint_t)i);
511 }
512 
513 int DynaChain::SyncMoveTo(DynaPosTuple_T tuplesPos[], uint_t uCount)
514 {
515  DynaServo *pServo;
517  int i;
518  int j;
519  int rc;
520 
522 
523  for(i=0, j=0, rc=DYNA_OK;
524  i<(int)uCount && i<DYNA_ID_NUMOF && rc==DYNA_OK;
525  ++i)
526  {
527  DYNA_TRY_SERVO_IN_CHAIN(this, tuplesPos[i].m_nServoId);
528 
529  pServo = m_pChain[tuplesPos[i].m_nServoId];
530 
531  DYNA_TRY_IS_MASTER(pServo);
533 
534  //
535  // In continuous mode: Start host controlled positioning.
536  //
537  if( pServo->GetServoMode() == DYNA_MODE_CONTINUOUS )
538  {
539  rc = pServo->MoveTo(tuplesPos[i].m_nPos);
540  }
541  //
542  // Let Dynmixel firmware take control of the move.
543  else
544  {
545  tuple[j].m_nServoId = tuplesPos[i].m_nServoId;
546  tuple[j].m_nPos = tuplesPos[i].m_nPos;
547  ++j;
548  }
549  }
550 
551  if( (rc == DYNA_OK) && (j > 0) )
552  {
553  rc = SyncWriteGoalPos(tuplesPos, (uint_t)j);
554  }
555 
556  return rc;
557 }
558 
559 int DynaChain::MoveAtSpeedTo(int nServoId, int nGoalSpeed, int nGoalOdPos)
560 {
561  DynaServo *pServo;
562 
564  DYNA_TRY_SERVO_IN_CHAIN(this, nServoId);
565 
566  pServo = m_pChain[nServoId];
567 
568  DYNA_TRY_IS_MASTER(pServo);
570 
571  return pServo->MoveAtSpeedTo(nGoalSpeed, nGoalOdPos);
572 }
573 
574 int DynaChain::vSyncMoveAtSpeedTo(uint_t uCount, ...)
575 {
576  DynaSpeedPosTuple_T tuplesSpeedPos[DYNA_ID_NUMOF];
577  va_list ap;
578  int i;
579 
581 
582  va_start(ap, uCount);
583 
584  for(i=0; i<uCount && i<DYNA_ID_NUMOF; ++i)
585  {
586  tuplesSpeedPos[i].m_nServoId = va_arg(ap, int);
587  tuplesSpeedPos[i].m_nSpeed = va_arg(ap, int);
588  tuplesSpeedPos[i].m_nPos = va_arg(ap, int);
589  }
590 
591  va_end(ap);
592 
593  return SyncMoveAtSpeedTo(tuplesSpeedPos, (uint_t)i);
594 }
595 
597  uint_t uCount)
598 {
599  DynaSpeedTuple_T tuplesSpeed[DYNA_ID_NUMOF];
600  DynaPosTuple_T tuplesPos[DYNA_ID_NUMOF];
601  DynaServo *pServo;
602  int i, j;
603  int rc;
604 
606 
607  for(i=0, j=0, rc=DYNA_OK;
608  i<(int)uCount && i<DYNA_ID_NUMOF && rc==DYNA_OK;
609  ++i)
610  {
611  DYNA_TRY_SERVO_IN_CHAIN(this, tuplesSpeedPos[i].m_nServoId);
612 
613  pServo = m_pChain[tuplesSpeedPos[i].m_nServoId];
614 
615  DYNA_TRY_IS_MASTER(pServo);
617 
618  //
619  // In continuous mode: Start host controlled positioning.
620  //
621  if( pServo->HasAgent() )
622  {
623  rc = pServo->MoveAtSpeedTo(tuplesSpeedPos[i].m_nSpeed,
624  tuplesSpeedPos[i].m_nPos);
625  }
626 
627  //
628  // Servo controlled move.
629  //
630  else
631  {
632  tuplesSpeed[j].m_nServoId = tuplesSpeedPos[i].m_nServoId;
633  tuplesSpeed[j].m_nSpeed = tuplesSpeedPos[i].m_nSpeed;
634 
635  tuplesPos[j].m_nServoId = tuplesSpeedPos[i].m_nServoId;
636  tuplesPos[j].m_nPos = tuplesSpeedPos[i].m_nPos;
637 
638  ++j;
639  }
640  }
641 
642  if( (j > 0) && (rc == DYNA_OK) )
643  {
644  rc = SyncWriteGoalSpeed(tuplesSpeed, (uint_t)j);
645 
646  if( rc == DYNA_OK )
647  {
648  rc = SyncWriteGoalPos(tuplesPos, (uint_t)j);
649  }
650  }
651 
652  return rc;
653 }
654 
655 int DynaChain::MoveAtSpeed(int nServoId, int nGoalSpeed)
656 {
657  DynaServo *pServo;
658 
660  DYNA_TRY_SERVO_IN_CHAIN(this, nServoId);
661 
662  pServo = m_pChain[nServoId];
663 
664  DYNA_TRY_IS_MASTER(pServo);
665 
666  return pServo->MoveAtSpeed(nGoalSpeed);
667 }
668 
669 int DynaChain::vSyncMoveAtSpeed(uint_t uCount, ...)
670 {
671  DynaSpeedTuple_T tuplesSpeed[DYNA_ID_NUMOF];
672  va_list ap;
673  int i;
674 
676 
677  va_start(ap, uCount);
678 
679  for(i=0; i<uCount && i<DYNA_ID_NUMOF; ++i)
680  {
681  tuplesSpeed[i].m_nServoId = va_arg(ap, int);
682  tuplesSpeed[i].m_nSpeed = va_arg(ap, int);
683 
684  DYNA_TRY_SERVO_IN_CHAIN(this, tuplesSpeed[i].m_nServoId);
685  DYNA_TRY_IS_MASTER(m_pChain[tuplesSpeed[i].m_nServoId]);
686  DYNA_TRY_SERVO_IN_MODE(m_pChain[tuplesSpeed[i].m_nServoId],
688  }
689 
690  va_end(ap);
691 
692  return SyncWriteGoalSpeed(tuplesSpeed, (uint_t)i);
693 }
694 
696  uint_t uCount)
697 {
698  int i;
699  int rc;
700 
702 
703  for(i=0; i<(int)uCount && i<DYNA_ID_NUMOF; ++i)
704  {
705  DYNA_TRY_SERVO_IN_CHAIN(this, tuplesSpeed[i].m_nServoId);
706  DYNA_TRY_IS_MASTER(m_pChain[tuplesSpeed[i].m_nServoId]);
707  DYNA_TRY_SERVO_IN_MODE(m_pChain[tuplesSpeed[i].m_nServoId],
709  }
710 
711  return SyncWriteGoalSpeed(tuplesSpeed, (uint_t)i);
712 }
713 
715 {
716  int nMaxTries = 3;
717  int nTries;
718  int rc;
719 
721 
722  for(nTries=0; nTries<nMaxTries; ++nTries)
723  {
724  if( (rc = SyncWriteTorqueEnable(false)) == DYNA_OK )
725  {
726  break;
727  }
728  }
729 
730  return rc;
731 }
732 
734 {
735  int nServoId; // working servo id
736  int iter; // iterator
737  int rc; // return code
738 
740 
741  for(nServoId=IterStartMaster(&iter);
742  nServoId!=DYNA_ID_NONE;
743  nServoId=IterNextMaster(&iter))
744  {
745  rc = m_pChain[nServoId]->Stop();
746  }
747 
748  return rc;
749 }
750 
752 {
753  int rc_tmp; // temporary return code
754  int rc; // return code
755 
757 
758  rc = SyncWriteTorqueEnable(true);
759 
760  rc_tmp = Stop();
761 
762  if( rc == DYNA_OK )
763  {
764  rc = rc_tmp;
765  }
766 
767  return rc;
768 }
769 
771 {
773 
774  return SyncWriteTorqueEnable(false);
775 }
776 
777 
778 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
779 // Master and Synchronous Read/Write Functions
780 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
781 
783 {
784  uint_t uVal;
785  int nServoId;
786  int iter;
788  uint_t uCount;
789  int rc;
790 
792 
793  uVal = bState? DYNA_TORQUE_EN_ON: DYNA_TORQUE_EN_OFF;
794 
795  for(nServoId=IterStart(&iter), uCount=0;
796  nServoId!=DYNA_ID_NONE;
797  nServoId=IterNext(&iter), ++uCount)
798  {
799  tuples[uCount].m_nServoId = nServoId;
800  tuples[uCount].m_uVal = uVal;
801  }
802 
803  rc = m_comm.SyncWrite(DYNA_ADDR_TORQUE_EN, 1, tuples, uCount);
804 
805  if( rc == DYNA_OK )
806  {
807  for(iter=0; iter<(int)uCount; ++iter)
808  {
809  m_pChain[tuples[iter].m_nServoId]->m_state.m_bTorqueEnabled = bState;
810  }
811  }
812 
813  return rc;
814 }
815 
816 int DynaChain::vSyncWriteGoalPos(uint_t uCount, ...)
817 {
818  DynaPosTuple_T tuplesPos[DYNA_ID_NUMOF];
819  va_list ap;
820  int i;
821 
823 
824  va_start(ap, uCount);
825 
826  for(i=0; i<uCount && i<DYNA_ID_NUMOF; ++i)
827  {
828  tuplesPos[i].m_nServoId = va_arg(ap, int);
829  tuplesPos[i].m_nPos = va_arg(ap, int);
830  }
831 
832  va_end(ap);
833 
834  return SyncWriteGoalPos(tuplesPos, (uint_t)i);
835 }
836 
837 int DynaChain::SyncWriteGoalPos(DynaPosTuple_T tuplesPos[], uint_t uCount)
838 {
839  DynaSyncWriteTuple_T tuples[DYNA_ID_NUMOF]; // servo_id, enc_pos tuples
840  int nServoIdM; // master servo id
841  int nServoIdS; // slave servo id
842  DynaServo *pServoM; // master servo
843  DynaServo *pServoS; // slave servo
844  int nGoalOdPosM; // master goal odometer position
845  int nGoalOdPosS; // slave goal odometer position
846  int nEncPos; // working encoder position
847  bool bRotReversed; // slave rotation is reverse
848  int i, j; // working indices
849  int rc; // return code
850 
852 
853  //
854  // Loop through tuples.
855  //
856  for(i=0, j=0; (i<(int)uCount) && (j<DYNA_ID_NUMOF-1); ++i)
857  {
858  nServoIdM = tuplesPos[i].m_nServoId;
859  nGoalOdPosM = tuplesPos[i].m_nPos;
860 
861  DYNA_TRY_SERVO_IN_CHAIN(this, nServoIdM);
862 
863  pServoM = m_pChain[nServoIdM];
864 
865  DYNA_TRY_IS_MASTER(pServoM);
866 
867  nEncPos = pServoM->OdometerToEncoder(nGoalOdPosM);
868 
869  if( pServoM->GetServoMode() == DYNA_MODE_SERVO )
870  {
871  DYNA_TRY_EXPR(((nEncPos >= pServoM->m_spec.m_uRawPosMin) &&
872  (nEncPos <= pServoM->m_spec.m_uRawPosMax)),
874  "Master servo %d: Goal odometer position %d(encoder=%d): Out of range.",
875  pServoM->GetServoId(), nGoalOdPosM, nEncPos);
876  }
877 
878  tuples[j].m_nServoId = nServoIdM;
879  tuples[j].m_uVal = (uint_t)nEncPos;
880 
881  j++;
882 
883  // master-slave linked servos
884  if( m_links[nServoIdM].m_uLinkType == DYNA_LINK_MASTER )
885  {
886  nServoIdS = m_links[nServoIdM].m_nServoIdMate;
887 
888  DYNA_TRY_SERVO_IN_CHAIN(this, nServoIdS);
889 
890  pServoS = m_pChain[nServoIdS];
891 
892  rc = pServoM->CalcMatesGoalPos(nGoalOdPosM, &nGoalOdPosS);
893 
894  DYNA_TRY_RC(rc, "Slave servo %d: Failed.", nServoIdS);
895 
896  nEncPos = pServoS->OdometerToEncoder(nGoalOdPosS);
897 
898  tuples[j].m_nServoId = nServoIdS;
899  tuples[j].m_uVal = (uint_t)nEncPos;
900 
901  j++;
902  }
903  }
904 
905  // sync write
906  rc = m_comm.SyncWrite(DYNA_ADDR_GOAL_POS_LSB, 2, tuples, (uint_t)j);
907 
908  if( rc == DYNA_OK )
909  {
910  for(i=0; i<j; ++i)
911  {
912  m_pChain[tuples[i].m_nServoId]->m_state.m_uGoalPos = tuples[i].m_uVal;
913  }
914  }
915 
916  return rc;
917 }
918 
919 int DynaChain::vSyncWriteGoalSpeed(uint_t uCount, ...)
920 {
921  DynaSpeedTuple_T tuplesSpeed[DYNA_ID_NUMOF];
922  va_list ap;
923  int i;
924 
926 
927  va_start(ap, uCount);
928 
929  for(i=0; i<uCount && i<DYNA_ID_NUMOF; ++i)
930  {
931  tuplesSpeed[i].m_nServoId = va_arg(ap, int);
932  tuplesSpeed[i].m_nSpeed = va_arg(ap, int);
933  }
934 
935  va_end(ap);
936 
937  return SyncWriteGoalSpeed(tuplesSpeed, (uint_t)i);
938 }
939 
940 int DynaChain::SyncWriteGoalSpeed(DynaSpeedTuple_T tuplesSpeed[], uint_t uCount)
941 {
943  int nServoIdM;
944  int nServoIdS;
945  DynaServo *pServoM;
946  DynaServo *pServoS;
947  DynaServo *pServo;
948  int nGoalSpeedM;
949  int nGoalSpeedS;
950  int i, j;
951  int rc;
952 
954 
955  for(i=0, j=0; (i<(int)uCount) && (j<DYNA_ID_NUMOF-1); ++i)
956  {
957  nServoIdM = tuplesSpeed[i].m_nServoId;
958  nGoalSpeedM = tuplesSpeed[i].m_nSpeed;
959 
960  DYNA_TRY_SERVO_IN_CHAIN(this, nServoIdM);
961 
962  pServoM = m_pChain[tuplesSpeed[i].m_nServoId];
963 
964  DYNA_TRY_IS_MASTER(pServoM);
965 
966  DYNA_TRY_EXPR( (iabs(nGoalSpeedM) <= pServoM->m_spec.m_uRawSpeedMax),
968  "Master servo %d: Goal speed %d: Out of range.",
969  pServoM->GetServoId(), nGoalSpeedM);
970 
971  tuples[j].m_nServoId = nServoIdM;
972  tuples[j].m_uVal = pServoM->PackGoalSpeed(nGoalSpeedM);
973  j++;
974 
975  // master-slave linked servos
976  if( m_links[nServoIdM].m_uLinkType == DYNA_LINK_MASTER )
977  {
978  nServoIdS = m_links[nServoIdM].m_nServoIdMate;
979  pServoS = m_pChain[nServoIdS];
980 
981  nGoalSpeedS = pServoM->CalcMatesGoalSpeed(nGoalSpeedM);
982 
983  tuples[j].m_nServoId = nServoIdS;
984  tuples[j].m_uVal = pServoS->PackGoalSpeed(nGoalSpeedS);
985  j++;
986  }
987  }
988 
989  rc = m_comm.SyncWrite(DYNA_ADDR_GOAL_SPEED_LSB, 2, tuples, (uint_t)j);
990 
991  if( rc == DYNA_OK )
992  {
993  for(i=0; i<j; ++i)
994  {
995  pServo = m_pChain[tuples[i].m_nServoId];
996  pServo->m_state.m_nGoalSpeed = pServo->UnpackGoalSpeed(tuples[i].m_uVal);
997  }
998  }
999 
1000  return rc;
1001 }
1002 
1003 
1004 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1005 // Chain Iterators
1006 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1007 
1008 int DynaChain::IterStart(int *pIter)
1009 {
1010  if( m_uNumInChain == 0 )
1011  {
1012  return DYNA_ID_NONE;
1013  }
1014 
1015  *pIter = 1;
1016 
1017  return m_nIIdx[0];
1018 }
1019 
1020 int DynaChain::IterNext(int *pIter)
1021 {
1022  int i;
1023 
1024  i = *pIter;
1025 
1026  if( (i >= (int)m_uNumInChain) || (m_nIIdx[i] == DYNA_ID_NONE) )
1027  {
1028  return DYNA_ID_NONE;
1029  }
1030 
1031  *pIter = i + 1;
1032 
1033  return m_nIIdx[i];
1034 }
1035 
1037 {
1038  int i;
1039  int nServoId;
1040 
1041  for(i=0; i<(int)m_uNumInChain; ++i)
1042  {
1043  nServoId = m_nIIdx[i];
1044  if( nServoId == DYNA_ID_NONE )
1045  {
1046  return DYNA_ID_NONE;
1047  }
1048  else if( m_pChain[nServoId]->IsMaster() )
1049  {
1050  *pIter = i + 1;
1051  return nServoId;
1052  }
1053  }
1054 
1055  return DYNA_ID_NONE;
1056 }
1057 
1059 {
1060  int i;
1061  int nServoId;
1062 
1063  for(i = *pIter; i<(int)m_uNumInChain; ++i)
1064  {
1065  nServoId = m_nIIdx[i];
1066  if( nServoId == DYNA_ID_NONE )
1067  {
1068  return DYNA_ID_NONE;
1069  }
1070  else if( m_pChain[nServoId]->IsMaster() )
1071  {
1072  *pIter = i + 1;
1073  return nServoId;
1074  }
1075  }
1076 
1077  return DYNA_ID_NONE;
1078 }
1079 
1080 
1081 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1082 // Operators
1083 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1084 
1085 const DynaServo *DynaChain::operator[](int nServoId)
1086 {
1087  if( (nServoId >= DYNA_ID_MIN) && (nServoId <= DYNA_ID_MAX) )
1088  {
1089  return m_pChain[nServoId];
1090  }
1091  else
1092  {
1093  return NULL;
1094  }
1095 }
RoadNarrows Dynamixel Bus Communications Abstract Base Class Interface.
virtual uint_t GetServoMode() const
Get the servo operational mode.
Definition: DynaServo.h:165
Synchronous Write Speed Tuple Structure.
Definition: DynaTypes.h:314
Synchronous Write Speed-Position Tuple Structure.
Definition: DynaTypes.h:324
virtual int SyncWriteGoalSpeed(DynaSpeedTuple_T tuplesSpeed[], uint_t uCount)
Synchronous write new goal speed for servos.
Definition: DynaChain.cxx:940
#define DYNA_TRY_SERVO_ID(id)
Testing if the servo id is in range exception macro.
#define DYNA_OK
not an error, success
Definition: Dynamixel.h:78
#define DYNA_TORQUE_EN_OFF
disable power drive to the motor
Definition: Dynamixel.h:676
virtual int SyncMoveTo(DynaPosTuple_T tuplesPos[], uint_t uCount)
Synchronous move servos to new goal positions in tuple list.
Definition: DynaChain.cxx:513
virtual ~DynaChain()
Destructor.
Definition: DynaChain.cxx:87
virtual int Freeze()
Freeze all servos at current position.
Definition: DynaChain.cxx:751
#define DYNA_ADDR_GOAL_SPEED_LSB
goal speed lsb (RW)
Definition: Dynamixel.h:940
#define DYNA_MODE_SERVO
servo mode with limited rotation
Definition: Dynamixel.h:170
virtual int MoveAtSpeedTo(int nServoId, int nGoalSpeed, int nGoalOdPos)
Move at speed to the goal postition.
Definition: DynaChain.cxx:559
virtual int vSyncMoveTo(uint_t uCount,...)
Synchronous move servos to new goal positions.
Definition: DynaChain.cxx:494
virtual int MoveAtSpeed(int nServoId, int nGoalSpeed)
Move at speed.
Definition: DynaChain.cxx:655
int m_nIIdx[DYNA_ID_NUMOF]
indirect index
Definition: DynaChain.h:714
uint_t m_uRawPosMin
minimum raw position value (servo mode)
Definition: DynaTypes.h:101
const DynaServo * operator[](int nServoId)
Subscript operator.
Definition: DynaChain.cxx:1085
uint_t m_uRawSpeedMax
maximum raw speed magnitude value
Definition: DynaTypes.h:105
#define DYNA_TRY_EXPR(expr, ecode, efmt,...)
Test if the servo is in the required mode(s) exception macro.
int m_nServoId
servo id
Definition: DynaTypes.h:296
DynaComm & m_comm
bus communication instance
Definition: DynaChain.h:712
void Init()
Initialize chain class instance.
Definition: DynaChain.cxx:297
virtual uint_t GetNumberOfMastersInChain()
Get the number of servos currently in chain.
Definition: DynaChain.cxx:182
virtual int vSyncWriteGoalPos(uint_t uCount,...)
Synchronous write new goal positions for servos.
Definition: DynaChain.cxx:816
RoadNarrows Dynamixel Servo Chain Container Base Class Interface.
virtual int vSyncMoveAtSpeed(uint_t uCount,...)
Synchronous move servos at the given speeds.
Definition: DynaChain.cxx:669
INLINE_IN_H int iabs(int a)
Return absolute value of a.
Definition: DynaOlio.h:91
#define DYNA_ECODE_NO_SERVO
no servo found
Definition: Dynamixel.h:86
virtual int MoveTo(int nServoId, int nGoalOdPos)
Move to the goal postition.
Definition: DynaChain.cxx:480
virtual int ChainEntryDelete(int nServoId)
Remove servo from chain and delete.
Definition: DynaChain.cxx:346
uint_t m_uNumInChain
number of servos in chain
Definition: DynaChain.h:716
#define DYNA_ID_MIN
minimum servo id
Definition: Dynamixel.h:146
virtual bool HasAgent()
Tests if servo has a registered agent.
Definition: DynaServo.h:604
virtual int vSyncWriteGoalSpeed(uint_t uCount,...)
Synchronous write new goal speed for for servos.
Definition: DynaChain.cxx:919
#define DYNA_TRY_IS_MASTER(pservo)
Test if the servo is a master servo.
#define DYNA_ECODE_NOT_SUPP
feature/function not supported
Definition: Dynamixel.h:97
virtual int IterStartMaster(int *pIter)
Start iteration master servos over of entire servo chain.
Definition: DynaChain.cxx:1036
#define DYNA_ID_NUMOF
number of unique servo id&#39;s
Definition: Dynamixel.h:148
virtual int ChainEntryNew(int nServoId)
Create new dervied DyanServo object and insert into chain.
Definition: DynaChain.cxx:312
Miscellaneous collection of useful utilities.
virtual int IterNextMaster(int *pIter)
Next iteration of master servos over of entire servo chain.
Definition: DynaChain.cxx:1058
virtual int LinkServos(int nServoIdMaster, int nServoIdSlave, bool bIsReversed)
Software link two unlinked servos in a master-slave configuration.
Definition: DynaChain.cxx:105
DynaServoLink_T m_links[DYNA_ID_NUMOF]
servo linked info
Definition: DynaChain.h:715
Dynamixel Servo Abstract Base Class.
Definition: DynaServo.h:78
int m_nSpeed
speed
Definition: DynaTypes.h:327
virtual void ClearLinkData(int nServoId)
Clear local link data for the given servo.
Definition: DynaChain.cxx:468
virtual int AddNewServosByScan()
Scan and add all discovered and created servos to the Dynamixel chain.
Definition: DynaChain.cxx:229
virtual int AddNewServoForced(int nServoId, uint_t uModelNum)
Force create and add a servo to the Dynamixel chain.
Definition: DynaChain.cxx:259
#define DYNA_LOG_ERROR(ecode, efmt,...)
Log Error.
bool_t m_bTorqueEnabled
torque [not] enabled
Definition: DynaTypes.h:197
#define DYNA_ID_MAX
maximum servo id
Definition: Dynamixel.h:147
virtual int SyncMoveAtSpeed(DynaSpeedTuple_T tuplesSpeed[], uint_t uCount)
Synchronous move servos at the given speeds.
Definition: DynaChain.cxx:695
virtual int SyncWriteTorqueEnable(bool bState)
Synchronous write to all of the servos in the chain to enable/disable applied torque.
Definition: DynaChain.cxx:782
The libDynamixel internal declarations.
static DynaServo * New(DynaComm &comm, int nServoId)
Archetype constructor to create a new Dynamixel servo instance.
Definition: DynaServo.cxx:102
virtual void Link(uint_t uLinkType, DynaServo *pServoMate, bool bRotReversed)
Link this servo to another.
Definition: DynaServo.h:277
int m_nPos
position
Definition: DynaTypes.h:328
uint_t m_uVal
write value
Definition: DynaTypes.h:297
virtual int Stop()
Stop all servos.
Definition: DynaChain.cxx:733
virtual int vSyncMoveAtSpeedTo(uint_t uCount,...)
Synchronous move servos to new goal positions at the given speeds.
Definition: DynaChain.cxx:574
virtual int Release()
Release all servos from any applied torque.
Definition: DynaChain.cxx:770
virtual int RemoveAllServos()
Remove all servos from chain and delete.
Definition: DynaChain.cxx:275
DynaServo * m_pChain[DYNA_ID_NUMOF]
chain of servos
Definition: DynaChain.h:713
virtual int IterStart(int *pIter)
Start iteration over of entire servo chain.
Definition: DynaChain.cxx:1008
#define DYNA_MODE_CONTINUOUS
continuous mode with/without position
Definition: Dynamixel.h:171
virtual void Unlink()
Unlink this servo.
Definition: DynaServo.h:287
int m_nGoalSpeed
goal speed (raw)
Definition: DynaTypes.h:201
int m_nSpeed
speed
Definition: DynaTypes.h:317
virtual int SyncWriteGoalPos(DynaPosTuple_T tuplesPos[], uint_t uCount)
Synchronous write new goal positions for servos.
Definition: DynaChain.cxx:837
int m_nServoId
servo id
Definition: DynaTypes.h:306
virtual void AuditLinks()
Audit servo links and repair or delete.
Definition: DynaChain.cxx:388
RoadNarrows Dynamixel Archetype Servo Abstract Base Class.
#define DYNA_TRY_SERVO_HAS_POS_CTL(pservo)
Test if the servo has positiion control.
virtual int RemoveServo(int nServoId)
Remove from chain and delete.
Definition: DynaChain.cxx:265
int m_nServoId
servo id
Definition: DynaTypes.h:316
int m_nPos
position
Definition: DynaTypes.h:307
virtual int SyncWrite(uint_t uAddr, uint_t uValSize, DynaSyncWriteTuple_T tuples[], uint_t uCount)=0
Synchronous Write 8/16-bit values to a list of Dynamixel servos.
int OdometerToEncoder(int nOdPos)
Convert virtual odometer units to servo encoder units.
Definition: DynaServo.h:367
RoadNarrows Dynamixel Top-Level Package Header File.
int m_nServoId
servo id
Definition: DynaTypes.h:326
virtual uint_t GetModelNumber() const
Get servo model number.
Definition: DynaServo.h:125
virtual uint_t GetServoId() const
Get servo id.
Definition: DynaServo.h:155
DynaChain(DynaComm &comm)
Default initialization constructor.
Definition: DynaChain.cxx:82
virtual bool IsMaster(int nServoId) const
Test if the servo is a master.
Definition: DynaChain.h:180
uint_t m_uNumMastersInChain
num of master servos in chain
Definition: DynaChain.h:717
DynaServoState_T m_state
servo shadowed RAM state
Definition: DynaServo.h:839
#define DYNA_ECODE_LINKED
linked servos error
Definition: Dynamixel.h:98
#define DYNA_ID_NONE
no servo id
Definition: Dynamixel.h:145
DynaServoSpec_T m_spec
servo specification
Definition: DynaServo.h:837
uint_t m_uGoalPos
goal position (encoder ticks)
Definition: DynaTypes.h:200
#define DYNA_TORQUE_EN_ON
enable power drive to the motor
Definition: Dynamixel.h:677
virtual int AddNewServo(int nServoId)
Create a new servo and add it to the Dynamixel chain.
Definition: DynaChain.cxx:206
virtual int EStop()
Emergency stop all servos.
Definition: DynaChain.cxx:714
virtual int UnlinkServos(int nServoIdMaster)
Unlink two software linked servos.
Definition: DynaChain.cxx:146
virtual int IterNext(int *pIter)
Next iteration over of entire servo chain.
Definition: DynaChain.cxx:1020
virtual void SetLinkData(int nServoId, uint_t uLinkType, int nServoIdMate, bool bRotReversed)
Set local link data for the given servo.
Definition: DynaChain.cxx:458
#define DYNA_ADDR_GOAL_POS_LSB
goal position lsb (RW)
Definition: Dynamixel.h:909
#define DYNA_ECODE_BAD_VAL
bad value
Definition: Dynamixel.h:85
virtual const char * GetModelName() const
Get servo model name string.
Definition: DynaServo.h:145
Position Tuple Structure.
Definition: DynaTypes.h:304
#define DYNA_ADDR_TORQUE_EN
torque enable (RW)
Definition: Dynamixel.h:672
#define DYNA_TRY_SERVO_IN_CHAIN(pchain, id)
Test if the servo id is valid and present in chain exception macro.
#define DYNA_TRY_SERVO_IN_MODE(pservo, mode)
Test if the servo is in the given mode.
virtual int SyncMoveAtSpeedTo(DynaSpeedPosTuple_T tuplesSpeedPos[], uint_t uCount)
Synchronous move servos to new goal positions at the given speeds.
Definition: DynaChain.cxx:596
#define DYNA_TRY_RC(rc, fmt,...)
Test if Dynamixel return code is not an error.
RoadNarrows Dynamixel Library Error and Logging Routines.
Dynamixel Bus Communications Abstract Base Class.
Definition: DynaComm.h:80
#define DYNA_TRY_COMM(comm)
Test if bus communication is available exception macro.