phyicubhelpers.cpp
1 /********************************************************************************
2  * WorldSim -- library for robot simulations *
3  * Copyright (C) 2008-2011 Gianluca Massera <emmegian@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 
20 #ifdef FARSA_USE_YARP_AND_ICUB
21 
22 #ifdef __GNUC__
23  #warning ================================================================================================================================================================================================================= PENSARE A DIVIDERE wVector IN UNA CLASSE PER I VETTORI (QUARTO ELEMENTO = 0) E UNA PER I PUNTI (QUARTO ELEMENTO = 1) =================================================================================================================================================================================================================
24 #endif
25 
26 #include "phyicubhelpers.h"
27 #include "phyicub.h"
28 #include "phybox.h"
29 #include "phycylinder.h"
30 #include "physphere.h"
31 #include "phyfixed.h"
32 #include "phyhinge.h"
33 #include "phyuniversal.h"
34 #include "phycompoundobject.h"
35 #include "motorcontrollers.h"
36 #include "wcamera.h"
37 
38 #ifdef __GNUC__
39 #pragma GCC diagnostic ignored "-Wunused-parameter"
40 #endif
41  #include "yarp/os/ResourceFinder.h"
42  #include "yarp/os/Bottle.h"
43  #include "yarp/os/Property.h"
44  #include "yarp/dev/PolyDriverList.h"
45  #include "yarp/dev/Wrapper.h"
46  #include "yarp/os/RateThread.h"
47  #include "yarp/os/Network.h"
48 #ifdef __GNUC__
49 #pragma GCC diagnostic warning "-Wunused-parameter"
50 #endif
51 
52 using namespace yarp::os;
53 using namespace yarp::dev;
54 using namespace iCub::iKin;
55 
56 #include <iostream>
57 
58 namespace farsa {
59  // Perhaps we should move this function and the next one into wMatrix.h and wVector.h
60  std::ostream& operator<<(std::ostream &os, const wMatrix &m)
61  {
62  os.precision(3);
63  os.setf(std::ostream::fixed);
64  os.unsetf(std::ostream::scientific);
65  os << std::endl
66  << "\t" << m[0][0] << "\t" << m[0][1] << "\t" << m[0][2] << "\t" << m[0][3] << std::endl
67  << "\t" << m[1][0] << "\t" << m[1][1] << "\t" << m[1][2] << "\t" << m[1][3] << std::endl
68  << "\t" << m[2][0] << "\t" << m[2][1] << "\t" << m[2][2] << "\t" << m[2][3] << std::endl
69  << "\t" << m[3][0] << "\t" << m[3][1] << "\t" << m[3][2] << "\t" << m[3][3] << std::endl;
70 
71  return os;
72  }
73 
74  std::ostream& operator<<(std::ostream &os, const wVector &v)
75  {
76  os.precision(3);
77  os.setf(std::ostream::fixed);
78  os.unsetf(std::ostream::scientific);
79  os << "[" << v.x << ", " << v.y << ", " << v.z << ", " << v.w << "]";
80 
81  return os;
82  }
83 
84  void convertYarpMatrixToWorldMatrix(const yarp::sig::Matrix &y, wMatrix &w)
85  {
86  // Extremely ugly, but works for sure... Yarp matrix are in conventional
87  // order, wMatrix are like openGL matrices
88  w[0][0] = y[0][0];
89  w[0][1] = y[1][0];
90  w[0][2] = y[2][0];
91  w[0][3] = y[3][0];
92  w[1][0] = y[0][1];
93  w[1][1] = y[1][1];
94  w[1][2] = y[2][1];
95  w[1][3] = y[3][1];
96  w[2][0] = y[0][2];
97  w[2][1] = y[1][2];
98  w[2][2] = y[2][2];
99  w[2][3] = y[3][2];
100  w[3][0] = y[0][3];
101  w[3][1] = y[1][3];
102  w[3][2] = y[2][3];
103  w[3][3] = y[3][3];
104  }
105 
106  void convertWorldMatrixToYarpMatrix(const wMatrix &w, yarp::sig::Matrix &y)
107  {
108  // Extremely ugly, but works for sure... Yarp matrix are in conventional
109  // order, wMatrix are like openGL matrices
110  y[0][0] = w[0][0];
111  y[0][1] = w[1][0];
112  y[0][2] = w[2][0];
113  y[0][3] = w[3][0];
114  y[1][0] = w[0][1];
115  y[1][1] = w[1][1];
116  y[1][2] = w[2][1];
117  y[1][3] = w[3][1];
118  y[2][0] = w[0][2];
119  y[2][1] = w[1][2];
120  y[2][2] = w[2][2];
121  y[2][3] = w[3][2];
122  y[3][0] = w[0][3];
123  y[3][1] = w[1][3];
124  y[3][2] = w[2][3];
125  y[3][3] = w[3][3];
126  }
127 
128  DOFStatusListener::DOFStatusListener(const PhyDOF* dof, Qt::ConnectionType connType) :
129  QObject(NULL),
130  m_dof(dof),
131  m_curPosition(dof->position()),
132  m_desideredPosition(dof->desiredPosition()),
133  m_velocity(dof->desiredVelocity()),
134  m_motionMode(dof->motion())
135  {
136  // Connecting our slots to those of the PhyDOF object
137  connect(m_dof, SIGNAL(changedPosition(real)), this, SLOT(setLinkAngle(real)), connType);
138  connect(m_dof, SIGNAL(changedDesiredPosition(real)), this, SLOT(setDesideredPosition(real)), connType);
139  connect(m_dof, SIGNAL(changedDesiredVelocity(real)), this, SLOT(setDesideredVelocity(real)), connType);
140  }
141 
143  {
144  // Nothing to do here
145  }
146 
148  {
149  switch (m_motionMode) {
150  case PhyDOF::force:
151  {
152  // Not supported (never will)
153  }
154  break;
155  case PhyDOF::vel:
156  {
157  // When setting the new position we also have to check limits here (ramp simply
158  // clamps the position within limits)
159  real lowLimit, highLimit;
160  m_dof->limits(lowLimit, highLimit);
161  m_curPosition = ramp(lowLimit, highLimit, m_curPosition + m_velocity * m_dof->joint()->world()->timeStep());
162  m_motionMode = PhyDOF::off;
163  }
164  break;
165  case PhyDOF::pos:
166  {
168  m_motionMode = PhyDOF::off;
169  }
170  break;
171  case PhyDOF::off:
172  {
173  // Nothing to do, here
174  }
175  break;
176  }
177  }
178 
179  void DOFStatusListener::setLinkAngle(real newAngle)
180  {
181  m_curPosition = newAngle;
182  }
183 
184  void DOFStatusListener::setDesideredPosition(real desideredAngle)
185  {
186  m_desideredPosition = desideredAngle;
187  m_motionMode = PhyDOF::pos;
188  }
189 
190  void DOFStatusListener::setDesideredVelocity(real velocity)
191  {
192  m_velocity = velocity;
193  m_motionMode = PhyDOF::vel;
194  }
195 
196  PhyObjectsGroup::PhyObjectsGroup(PhyObject* headObject, World* world, QString name) :
197  WObject(world, name),
198  m_headObject(headObject),
199  m_objects(),
200  m_joints()
201  {
202  // Setting the transformation matrix equal to the object matrix
203  tm = m_headObject->matrix();
204  }
205 
207  {
208  // Deleting all joint listeners
209  for (QMap<ChainIDType, QVector<DOFAndListener> >::iterator it = m_joints.begin(); it != m_joints.end(); it++) {
210  for (int i = 0; i < it.value().size(); i++) {
211  delete it.value()[i].listener;
212  }
213  }
214  }
215 
217  {
218  // Storing matrix for the object relative to the head object frame of reference
219  wMatrix invHeadMatrix = m_headObject->matrix().inverse();
220  m_objects[chainID].push_back(ObjectAndMatrix(obj, obj->matrix() * invHeadMatrix));
221 
222  return (m_objects[chainID].size() - 1);
223  }
224 
226  {
227  Q_ASSERT_X(joint->numDofs() > dofID, "PhyObjectsGroup::addJointDOF", "Joint has not the given dof");
228  m_joints[chainID].push_back(DOFAndListener(joint, dofID, new DOFStatusListener(joint->dofs()[0])));
229 
230  return (m_joints[chainID].size() - 1);
231  }
232 
234  {
235  // Calling setKinematic on all objects
236  m_headObject->setKinematic(b);
237  for (QMap<ChainIDType, QVector<ObjectAndMatrix> >::iterator it = m_objects.begin(); it != m_objects.end(); it++) {
238  for (int i = 0; i < it.value().size(); i++) {
239  it.value()[i].object->setKinematic(b);
240  }
241  }
242  }
243 
245  {
246  // Calling setStatic on all objects
247  m_headObject->setStatic(b);
248  for (QMap<ChainIDType, QVector<ObjectAndMatrix> >::iterator it = m_objects.begin(); it != m_objects.end(); it++) {
249  for (int i = 0; i < it.value().size(); i++) {
250  it.value()[i].object->setStatic(b);
251  }
252  }
253  }
254 
256  {
257  // Calling enable on all joints
258  for (QMap<ChainIDType, QVector<DOFAndListener> >::iterator it = m_joints.begin(); it != m_joints.end(); it++) {
259  for (int i = 0; i < it.value().size(); i++) {
260  it.value()[i].joint->enable(b);
261  }
262  }
263  }
264 
266  {
267  // Storing matrix for all objects relative to the head object frame of reference
268  wMatrix invHeadMatrix = m_headObject->matrix().inverse();
269  for (QMap<ChainIDType, QVector<ObjectAndMatrix> >::iterator it = m_objects.begin(); it != m_objects.end(); it++) {
270  for (int i = 0; i < it.value().size(); i++) {
271  it.value()[i].matrix = it.value()[i].object->matrix() * invHeadMatrix;
272  }
273  }
274  }
275 
277  {
278  // First checking the joint and its child object exist (these are all asserts for performance reasons)
279  Q_ASSERT_X(m_joints.contains(chainID), "PhyObjectsGroup::setDOFPosition", "No joint chain with the given ID");
280  Q_ASSERT_X(m_joints[chainID].size() > dof, "PhyObjectsGroup::setDOFPosition", "No joint with the given ID in the given chain");
281  Q_ASSERT_X(m_joints[chainID][dof].joint->dofs()[m_joints[chainID][dof].dofID]->rotate(), "PhyObjectsGroup::setDOFPosition", "Linear joints are not supported");
282  Q_ASSERT_X(m_objects.contains(chainID), "PhyObjectsGroup::setDOFPosition", "No object chain with the given ID");
283  Q_ASSERT_X(m_objects[chainID].size() > dof, "PhyObjectsGroup::setDOFPosition", "No object with the given ID in the given chain");
284 
285  QVector<ObjectAndMatrix>& objChain = m_objects[chainID];
286  QVector<DOFAndListener>& jointChain = m_joints[chainID];
287  PhyDOF* phydof = jointChain[dof].joint->dofs()[m_joints[chainID][dof].dofID];
288 
289  // Computing the new matrix relative to the head object for all elements after the given joint
290  for (ElementIDType i = dof; i < objChain.size(); i++) {
291  const wMatrix newMatrixWorldCoordinate = objChain[i].object->matrix().rotateAround(-phydof->axis(), phydof->centre(), pos - phydof->position());
292  objChain[i].matrix = newMatrixWorldCoordinate * matrix().inverse();
293  }
294 
295  // Also updating joint and moving object (first objects, then joints because joints
296  // need both the parent and the child in the correct position)
297  for (ElementIDType i = dof; i < objChain.size(); i++) {
298  objChain[i].object->setMatrix(objChain[i].matrix * matrix());
299  }
300  for (ElementIDType i = dof; i < jointChain.size(); i++) {
301  jointChain[i].joint->updateJointInfo();
302  }
303  }
304 
306  {
307  // This could be made a bit more efficient if there was a function like setDOFPosition
308  // taking pointer to objects instead of their indexes. However most of the work is in
309  // computing matrix multiplication, so for the moment it is ok this way
310 
311  // Here we simply cycle through the list dofs for each kinematic chain and call setDOFPosition
312  for (QMap<ChainIDType, QVector<DOFAndListener> >::iterator it = m_joints.begin(); it != m_joints.end(); it++) {
313  for (int i = 0; i < it.value().size(); i++) {
314  it.value()[i].listener->update();
315  setDOFPosition(it.value()[i].listener->position(), it.key(), i);
316  }
317  }
318  }
319 
321  {
322  }
323 
325  {
326  }
327 
328  void PhyObjectsGroup::changedMatrix()
329  {
330  // First of all setting the transformation matrix for the head object to the
331  // matrix for this object
332  m_headObject->setMatrix(matrix());
333 
334  // Now setting transformation matrices for all other objects
335  for (QMap<ChainIDType, QVector<ObjectAndMatrix> >::iterator it = m_objects.begin(); it != m_objects.end(); it++) {
336  for (int i = 0; i < it.value().size(); i++) {
337  it.value()[i].object->setMatrix(it.value()[i].matrix * matrix());
338  }
339  }
340 
341  // Finally updating all joints
342  for (QMap<ChainIDType, QVector<DOFAndListener> >::iterator it = m_joints.begin(); it != m_joints.end(); it++) {
343  for (int i = 0; i < it.value().size(); i++) {
344  it.value()[i].joint->updateJointInfo();
345  }
346  }
347  }
348 
350  QObject(),
351  m_buddies(),
352  m_isMasterBuddy(true),
353  m_chain(NULL),
354  m_linkID(0),
355  m_wObject(NULL),
356  m_objectMatrix(wMatrix::identity()),
357  m_axis(),
358  m_bottom(),
359  m_top(),
360  m_height(0.0),
361  m_worldTm(&s_identityMatrix),
362  m_phyJoint(NULL),
363  m_phyJointDOF(0),
364  m_invertedJointAxis(true),
365  m_nextAngle(0.0),
366  m_velocity(0.0),
367  m_motionMode(PhyDOF::off),
368  m_linkAngleUpdated(true)
369  {
370  }
371 
372  KinematicLinkInfo::KinematicLinkInfo(iCub::iKin::iKinLimb* chain, unsigned int linkID) :
373  QObject(),
374  m_buddies(),
375  m_isMasterBuddy(true),
376  m_chain(chain),
377  m_linkID(linkID),
378  m_wObject(NULL),
379  m_objectMatrix(wMatrix::identity()),
380  m_axis(),
381  m_bottom(),
382  m_top(),
383  m_height(0.0),
384  m_worldTm(&s_identityMatrix),
385  m_phyJoint(NULL),
386  m_phyJointDOF(0),
387  m_invertedJointAxis(true),
388  m_nextAngle(0.0),
389  m_velocity(0.0),
390  m_motionMode(PhyDOF::off),
391  m_linkAngleUpdated(true)
392  {
394  }
395 
397  QObject(),
398  m_buddies(other.m_buddies),
399  m_isMasterBuddy(other.m_isMasterBuddy),
400  m_chain(other.m_chain),
401  m_linkID(other.m_linkID),
402  m_wObject(other.m_wObject),
403  m_objectMatrix(other.m_objectMatrix),
404  m_axis(other.m_axis),
405  m_bottom(other.m_bottom),
406  m_top(other.m_top),
407  m_height(other.m_height),
408  m_worldTm(other.m_worldTm),
409  m_phyJoint(other.m_phyJoint),
410  m_phyJointDOF(other.m_phyJointDOF),
411  m_invertedJointAxis(other.m_invertedJointAxis),
412  m_nextAngle(other.m_nextAngle),
413  m_velocity(other.m_velocity),
414  m_motionMode(other.m_motionMode),
415  m_linkAngleUpdated(other.m_linkAngleUpdated)
416  {
417  // Adding the object we are copying in the list of our buddies and removing ourself
418  m_buddies.insert(const_cast<KinematicLinkInfo*>(&other));
419  m_buddies.remove(this);
420 
421  // Now adding ourself to our buddies' buddies
422  foreach (KinematicLinkInfo* buddy, m_buddies) {
423  buddy->m_buddies.insert(this);
424  }
425  }
426 
428  {
429  if (&other == this) {
430  return *this;
431  }
432 
433  m_chain = other.m_chain;
434  m_isMasterBuddy = other.m_isMasterBuddy;
435  m_linkID = other.m_linkID;
436  m_wObject = other.m_wObject;
437  m_objectMatrix = other.m_objectMatrix;
438  m_axis = other.m_axis;
439  m_bottom = other.m_bottom;
440  m_top = other.m_top;
441  m_height = other.m_height;
442  m_worldTm = other.m_worldTm;
443  m_phyJoint = other.m_phyJoint;
444  m_phyJointDOF = other.m_phyJointDOF;
445  m_invertedJointAxis = other.m_invertedJointAxis;
446  m_nextAngle = other.m_nextAngle;
447  m_velocity = other.m_velocity;
448  m_motionMode = other.m_motionMode;
449  m_linkAngleUpdated = other.m_linkAngleUpdated;
450 
451  // Copying and updating the list of buddies
452  m_buddies = other.m_buddies;
453 
454  // Adding the object we are copying in the list of our buddies and removing ourself
455  m_buddies.insert(const_cast<KinematicLinkInfo*>(&other));
456  m_buddies.remove(this);
457 
458  // Now adding ourself to our buddies' buddies
459  foreach (KinematicLinkInfo* buddy, m_buddies) {
460  buddy->m_buddies.insert(this);
461  }
462 
463  return *this;
464  }
465 
467  {
468  // Removing ourself from all buddies
469  foreach (KinematicLinkInfo* buddy, m_buddies) {
470  buddy->m_buddies.remove(this);
471  }
472  }
473 
474  void KinematicLinkInfo::setBuddies(QSet<KinematicLinkInfo*> buddies)
475  {
476  m_buddies = buddies;
477  m_isMasterBuddy = true;
478 
479  // Making sure we are not in the list of our buddies (to avoid
480  // infinite recursion)
481  m_buddies.remove(this);
482 
483  // Setting the buddy list to all buddies
484  foreach (KinematicLinkInfo *buddy, m_buddies) {
485  buddy->m_buddies = m_buddies;
486  buddy->m_isMasterBuddy = false;
487 
488  // Removing buddy from its list and adding ourself
489  buddy->m_buddies.remove(buddy);
490  buddy->m_buddies.insert(this);
491 
492  // Now syncing buddy to my values
493  buddy->m_wObject = m_wObject;
494  buddy->m_objectMatrix = m_objectMatrix;
495  buddy->m_axis = m_axis;
496  buddy->m_bottom = m_bottom;
497  buddy->m_top = m_top;
498  buddy->m_height = m_height;
499  buddy->m_worldTm = m_worldTm;
500  buddy->m_phyJoint = m_phyJoint;
501  buddy->m_phyJointDOF = m_phyJointDOF;
502  buddy->m_invertedJointAxis = m_invertedJointAxis;
503  buddy->m_nextAngle = m_nextAngle;
504  buddy->m_velocity = m_velocity;
505  buddy->m_motionMode = m_motionMode;
506  buddy->m_linkAngleUpdated = m_linkAngleUpdated;
507  }
508  }
509 
511  {
512  // Calling the "NoBuddies" version for me and all buddies
513  setWObject_NB(wObject, m);
514  foreach (KinematicLinkInfo *buddy, m_buddies) {
515  buddy->setWObject_NB(wObject, m);
516  }
517 
518  // Now also updating wObject matrix
520  }
521 
523  {
524  // Calling the "NoBuddies" version for me and all buddies
525  setWorldMatrix_NB(mtr);
526  foreach (KinematicLinkInfo *buddy, m_buddies) {
527  buddy->setWorldMatrix_NB(mtr);
528  }
529 
530  // Now also updating wObject matrix
532  }
533 
535  {
536  // Calling the "NoBuddies" version for me and all buddies
537  updateInformationFromiKin_NB();
538  foreach (KinematicLinkInfo *buddy, m_buddies) {
539  buddy->updateInformationFromiKin_NB();
540  }
541  }
542 
544  {
545  // Calling the "NoBuddies" version for me and all buddies
546  updateMatrixFromiKin_NB();
547  foreach (KinematicLinkInfo *buddy, m_buddies) {
548  buddy->updateMatrixFromiKin_NB();
549  }
550  }
551 
552  void KinematicLinkInfo::setJoint(PhyJoint *joint, bool invertedJointAxis, unsigned int dof, bool doConnection, Qt::ConnectionType connType)
553  {
554  // Calling the "NoBuddies" version for me and all buddies
555  setJoint_NB(joint, invertedJointAxis, dof, doConnection, connType);
556  foreach (KinematicLinkInfo *buddy, m_buddies) {
557  // Here we don't connect the signal, as when my setLinkAngle is
558  // called, I take care of updating all buddies
559  buddy->setJoint_NB(joint, invertedJointAxis, dof, false);
560  }
561  }
562 
564  {
565  // Calling the "NoBuddies" version for me and all buddies.
566  setLinkAngle_NB(newAngle);
567  foreach (KinematicLinkInfo *buddy, m_buddies) {
568  buddy->setLinkAngle_NB(newAngle);
569  }
570  }
571 
572  void KinematicLinkInfo::setDesideredPosition(real desideredAngle)
573  {
574  // Calling the "NoBuddies" version for me and all buddies
575  setDesideredPosition_NB(desideredAngle);
576  foreach (KinematicLinkInfo *buddy, m_buddies) {
577  buddy->setDesideredPosition_NB(desideredAngle);
578  }
579  }
580 
582  {
583  // Calling the "NoBuddies" version for me and all buddies
584  setDesideredVelocity_NB(velocity);
585  foreach (KinematicLinkInfo *buddy, m_buddies) {
586  buddy->setDesideredVelocity_NB(velocity);
587  }
588  }
589 
591  {
592  // Calling the "NoBuddies" version for me and all buddies
593  setiKinLinkLimits_NB(min, max);
594  foreach (KinematicLinkInfo *buddy, m_buddies) {
595  buddy->setiKinLinkLimits_NB(min, max);
596  }
597  }
598 
600  {
601  // Calling the "NoBuddies" version for me and all buddies.
602  updateLink_NB();
603  foreach (KinematicLinkInfo *buddy, m_buddies) {
604  buddy->updateLink_NB();
605  }
606  }
607 
608  void KinematicLinkInfo::setWObject_NB(WObject* wObject, const wMatrix &m)
609  {
610  m_wObject = wObject;
611  m_objectMatrix = m;
612  }
613 
614  void KinematicLinkInfo::setWorldMatrix_NB(const wMatrix *mtr)
615  {
616  if (mtr == NULL) {
617  m_worldTm = &s_identityMatrix;
618  } else {
619  m_worldTm = mtr;
620  }
621  }
622 
623  void KinematicLinkInfo::updateInformationFromiKin_NB()
624  {
625  // Updating world matrix and other structures
626 
627  // Getting our frame of reference
628  wMatrix thisMatrix;
629  convertYarpMatrixToWorldMatrix(m_chain->getH(m_linkID, true), thisMatrix);
630 
631  // Getting the frame of reference for the previous link (we need it to
632  // compute other stuffs)
633  wMatrix prevLinkMatrix;
634  if (m_linkID == 0) {
635  convertYarpMatrixToWorldMatrix(m_chain->getH0(), prevLinkMatrix);
636  } else {
637  convertYarpMatrixToWorldMatrix(m_chain->getH(m_linkID - 1, true), prevLinkMatrix);
638  }
639 
640  // Computing link information
641  m_bottom = prevLinkMatrix.w_pos;
642  m_top = thisMatrix.w_pos;
643  m_axis = m_top - m_bottom;
644  m_height = m_axis.norm();
645  m_rotAxis = thisMatrix.unrotateVector(prevLinkMatrix.z_ax);
646  m_rotCenter = thisMatrix.untransformVector(prevLinkMatrix.w_pos);
647  }
648 
649  void KinematicLinkInfo::updateMatrixFromiKin_NB()
650  {
651  if ((m_isMasterBuddy) && (m_wObject != NULL)) {
652  // Updating our frame of reference
653  wMatrix thisMatrix;
654  convertYarpMatrixToWorldMatrix(m_chain->getH(m_linkID, true), thisMatrix);
655  thisMatrix = m_objectMatrix * thisMatrix * (*m_worldTm);
656  m_wObject->setMatrix(thisMatrix);
657  }
658  }
659 
660  void KinematicLinkInfo::setJoint_NB(PhyJoint *joint, bool invertedJointAxis, unsigned int dof, bool doConnection, Qt::ConnectionType connType)
661  {
662  // First disconnecting signal from the previous joint dof (if we were connected)
663  if (m_phyJoint != NULL) {
664  disconnect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedPosition(real)), this, SLOT(setLinkAngle(real)));
665  disconnect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedDesiredPosition(real)), this, SLOT(setDesideredPosition(real)));
666  disconnect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setDesideredVelocity(real)));
667  disconnect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedLimits(real, real)), this, SLOT(setiKinLinkLimits(real, real)));
668  }
669 
670  m_phyJoint = joint;
671  m_phyJointDOF = dof;
672  m_invertedJointAxis = invertedJointAxis;
673 
674  if (doConnection) {
675  connect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedPosition(real)), this, SLOT(setLinkAngle(real)), connType);
676  connect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedDesiredPosition(real)), this, SLOT(setDesideredPosition(real)), connType);
677  connect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedDesiredVelocity(real)), this, SLOT(setDesideredVelocity(real)), connType);
678  connect(m_phyJoint->dofs()[m_phyJointDOF], SIGNAL(changedLimits(real, real)), this, SLOT(setiKinLinkLimits(real, real)), connType);
679  }
680  }
681 
682  void KinematicLinkInfo::setLinkAngle_NB(real newAngle)
683  {
684  if (!m_invertedJointAxis) {
685  newAngle = -newAngle;
686  }
687  (*(m_chain->asChain()))[m_linkID].setAng(newAngle);
688  // Resetting m_nextAngle
689  m_nextAngle = newAngle;
690  }
691 
692  void KinematicLinkInfo::setDesideredPosition_NB(real desideredAngle)
693  {
694  // Saving the desidered angle and setting the motion mode
695  if (m_invertedJointAxis) {
696  m_nextAngle = desideredAngle;
697  } else {
698  m_nextAngle = -desideredAngle;
699  }
700  m_motionMode = PhyDOF::pos;
701  m_linkAngleUpdated = false;
702  }
703 
704  void KinematicLinkInfo::setDesideredVelocity_NB(real velocity)
705  {
706  // Checking the velocity is not grater than the highest possible velocity
707  if (fabs(velocity) > fabs(m_phyJoint->dofs()[m_phyJointDOF]->maxVelocity())) {
708  velocity = (velocity > 0) ? fabs(m_phyJoint->dofs()[m_phyJointDOF]->maxVelocity()) : -fabs(m_phyJoint->dofs()[m_phyJointDOF]->maxVelocity());
709  }
710  // Saving the desidered angle and setting the motion mode
711  if (m_invertedJointAxis) {
712  m_velocity = velocity;
713  } else {
714  m_velocity = -velocity;
715  }
716  m_motionMode = PhyDOF::vel;
717  m_linkAngleUpdated = false;
718  }
719 
720  void KinematicLinkInfo::setiKinLinkLimits_NB(real min, real max)
721  {
722  if (m_invertedJointAxis) {
723  (*(m_chain->asChain()))[m_linkID].setMin(min);
724  (*(m_chain->asChain()))[m_linkID].setMax(max);
725  } else {
726  (*(m_chain->asChain()))[m_linkID].setMin(-max);
727  (*(m_chain->asChain()))[m_linkID].setMax(-min);
728  }
729  }
730 
731  void KinematicLinkInfo::updateLink_NB()
732  {
733  // It is ok to do this because the motor control calls setDesideredVelocity
734  // at each time step (otherwise we would only do one step and then stop)
735  if (m_linkAngleUpdated) {
736  return;
737  }
738 
739  // Here we also update the DOF velocity and position
740  real velocity = 0.0;
741  real position = (*(m_chain->asChain()))[m_linkID].getAng();
742  switch (m_motionMode) {
743  case PhyDOF::force:
744  {
745  // Not supported (never will)
746  }
747  break;
748  case PhyDOF::vel:
749  {
750  // Here we have to invert the angle if the axis is not inverted to balance the
751  // inversion done in the setLinkAngle function (this is to avoid having two versions
752  // of setLinkAngle, one that inverts the angle if it has to, and another that
753  // never inverts angles). We also have to multiply velocity by the timestep to have the
754  // actual delta angle
755  const real deltaAngle = m_velocity * m_phyJoint->world()->timeStep();
756  velocity = m_velocity;
757  position = (*(m_chain->asChain()))[m_linkID].getAng() + deltaAngle;
758  if (m_invertedJointAxis) {
759  setLinkAngle_NB(position);
760  } else {
761  setLinkAngle_NB(-position);
762  }
763  }
764  break;
765  case PhyDOF::pos:
766  {
767  // Here we have to invert the angle if the axis is not inverted to balance the
768  // inversion done in the setLinkAngle function (this is to avoid having two versions
769  // of setLinkAngle, one that inverts the angle if it has to, and another that
770  // never inverts angles)
771  velocity = (m_nextAngle - (*(m_chain->asChain()))[m_linkID].getAng()) / m_phyJoint->world()->timeStep();
772  position = m_nextAngle;
773  if (m_invertedJointAxis) {
774  setLinkAngle_NB(position);
775  } else {
776  setLinkAngle_NB(-position);
777  }
778  }
779  break;
780  case PhyDOF::off:
781  {
782  // Nothing to do, here
783  }
784  break;
785  }
786 
787  // Updating velocity and position
788  m_phyJoint->dofs()[m_phyJointDOF]->setPosition(position);
789  m_phyJoint->dofs()[m_phyJointDOF]->setVelocity(velocity);
790  m_linkAngleUpdated = true;
791  }
792 
793  const wMatrix KinematicLinkInfo::s_identityMatrix(wMatrix::identity());
794 } // end namespace farsa
795 
796 #endif // FARSA_USE_YARP_AND_ICUB