RobotIK.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2015-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * 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, see <http://www.gnu.org/licenses/>.
17  *
18  * @package RobotComponents::ArmarXObjects::RobotIK
19  * @author Joshua Haustein ( joshua dot haustein at gmail dot com ), Nikolaus Vahrenkamp
20  * @date 2015
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 #include "RobotIK.h"
26 
27 #include <algorithm>
28 #include <filesystem>
29 #include <set>
30 
31 #include <VirtualRobot/IK/CoMIK.h>
32 #include <VirtualRobot/IK/ConstrainedOptimizationIK.h>
33 #include <VirtualRobot/IK/HierarchicalIK.h>
34 #include <VirtualRobot/IK/JointLimitAvoidanceJacobi.h>
35 #include <VirtualRobot/IK/constraints/JointLimitAvoidanceConstraint.h>
36 #include <VirtualRobot/IK/constraints/OrientationConstraint.h>
37 #include <VirtualRobot/IK/constraints/PoseConstraint.h>
38 #include <VirtualRobot/IK/constraints/PositionConstraint.h>
39 #include <VirtualRobot/MathTools.h>
40 #include <VirtualRobot/Nodes/RobotNode.h>
41 #include <VirtualRobot/RobotNodeSet.h>
42 #include <VirtualRobot/Workspace/Manipulability.h>
43 #include <VirtualRobot/Workspace/Reachability.h>
44 #include <VirtualRobot/XML/RobotIO.h>
45 
49 
52 
53 using namespace VirtualRobot;
54 using namespace Eigen;
55 using namespace Ice;
56 
57 namespace armarx
58 {
59 
60  void
61  RobotIK::onInitComponent()
62  {
63  _robotFile = getProperty<std::string>("RobotFileName").getValue();
64 
65  if (!ArmarXDataPath::getAbsolutePath(_robotFile, _robotFile))
66  {
67  throw UserException("Could not find robot file " + _robotFile);
68  }
69 
70  this->_robotModel =
71  VirtualRobot::RobotIO::loadRobot(_robotFile, VirtualRobot::RobotIO::eStructure);
72 
73  if (this->_robotModel)
74  {
75  ARMARX_VERBOSE << "Loaded robot from file " << _robotFile;
76  }
77  else
78  {
79  ARMARX_VERBOSE << "Failed loading robot from file " << _robotFile;
80  }
81 
82  // Get number of ik trials
83  _numIKTrials = getProperty<int>("NumIKTrials").getValue();
84 
85  // Load initial reachability maps (if configured)
86  std::string spacesStr = getProperty<std::string>("InitialReachabilitySpaces").getValue();
87  std::vector<std::string> spaces = armarx::Split(spacesStr, ";");
88 
89  if (spacesStr != "")
90  {
91  std::string spacesFolder =
92  getProperty<std::string>("ReachabilitySpacesFolder").getValue();
93 
94  for (auto& space : spaces)
95  {
96  ARMARX_INFO << "Initially loading reachability space '"
97  << (spacesFolder + "/" + space) << "'";
98 
99  std::string absolutePath;
100 
101  if (!ArmarXDataPath::getAbsolutePath(spacesFolder + "/" + space, absolutePath))
102  {
103  ARMARX_ERROR << "Could not load reachability map '"
104  << (spacesFolder + "/" + space) << "'";
105  continue;
106  }
107 
108  loadReachabilitySpace(absolutePath);
109  }
110  }
111 
112  usingProxy(getProperty<std::string>("RobotStateComponentName").getValue());
113  offeringTopic("DebugDrawerUpdates");
114  }
115 
116  void
117  RobotIK::onConnectComponent()
118  {
119  _robotStateComponentPrx = getProxy<RobotStateComponentInterfacePrx>(
120  getProperty<std::string>("RobotStateComponentName").getValue());
121 
122  std::string robFile_remote = _robotStateComponentPrx->getRobotFilename();
123  ArmarXDataPath::getAbsolutePath(robFile_remote, robFile_remote);
124 
125 
126  if (robFile_remote.compare(_robotFile) != 0)
127  {
128  ARMARX_WARNING << "The robot state component uses the robot model " << robFile_remote
129  << " This component, however, uses " << _robotFile
130  << " Both models must be identical!";
131  }
132 
133  _synchronizedRobot = _robotStateComponentPrx->getSynchronizedRobot();
134  debugDrawer = getTopic<armarx::DebugDrawerInterfacePrx>("DebugDrawerUpdates");
135  }
136 
137  void
138  RobotIK::onDisconnectComponent()
139  {
140  }
141 
143  RobotIK::createPropertyDefinitions()
144  {
145  return PropertyDefinitionsPtr(new RobotIKPropertyDefinitions(getConfigIdentifier()));
146  }
147 
149  RobotIK::computeIKFramedPose(const std::string& robotNodeSetName,
150  const FramedPoseBasePtr& tcpPose,
152  const Ice::Current&)
153  {
154  NameValueMap ikSolution;
155  computeIK(robotNodeSetName, toGlobalPose(tcpPose), cs, ikSolution);
156  return ikSolution;
157  }
158 
160  RobotIK::computeIKGlobalPose(const std::string& robotNodeSetName,
161  const PoseBasePtr& tcpPose,
163  const Ice::Current&)
164  {
165  NameValueMap ikSolution;
166  Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
167  computeIK(robotNodeSetName, globalTcpPose.toEigen(), cs, ikSolution);
168  return ikSolution;
169  }
170 
171  ExtendedIKResult
172  RobotIK::computeExtendedIKGlobalPose(const std::string& robotNodeSetName,
173  const PoseBasePtr& tcpPose,
175  const Ice::Current&)
176  {
177  ExtendedIKResult ikSolution;
178  Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
179  computeIK(robotNodeSetName, globalTcpPose.toEigen(), cs, ikSolution);
180  return ikSolution;
181  }
182 
184  RobotIK::computeCoMIK(const std::string& robotNodeSetJoints,
185  const CoMIKDescriptor& desc,
186  const Ice::Current&)
187  {
188  // Make sure we have valid input parameters
189  if (!_robotModel->hasRobotNodeSet(robotNodeSetJoints))
190  {
191  return NameValueMap();
192  }
193 
194  if (!_robotModel->hasRobotNodeSet(desc.robotNodeSetBodies))
195  {
196  return NameValueMap();
197  }
198 
199  RobotNodePtr coordSystem = RobotNodePtr();
200 
201  if (desc.coordSysName.size() > 0 && _robotModel->hasRobotNode(desc.coordSysName))
202  {
203  coordSystem = _robotModel->getRobotNode(desc.coordSysName);
204  }
205 
206  // Create and initialize ik solver
207  RobotNodeSetPtr joints = _robotModel->getRobotNodeSet(robotNodeSetJoints);
208  CoMIK comIkSolver(
209  joints, _robotModel->getRobotNodeSet(desc.robotNodeSetBodies), coordSystem);
210  Eigen::VectorXf goal(2);
211  goal(0) = desc.gx;
212  goal(1) = desc.gy;
213  comIkSolver.setGoal(goal, desc.tolerance);
214 
215  // Solve
216  std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
217  bool success = comIkSolver.solveIK();
218  NameValueMap result;
219 
220  if (success)
221  {
222  for (auto& joint : joints->getAllRobotNodes())
223  {
224  NameValueMap::value_type jointPair(joint->getName(), joint->getJointValue());
225  result.insert(jointPair);
226  }
227  }
228 
229  return result;
230  }
231 
233  RobotIK::computeHierarchicalDeltaIK(const std::string& robotNodeSetName,
234  const IKTasks& iktasks,
235  const CoMIKDescriptor& comIK,
236  float stepSize,
237  bool avoidJointLimits,
238  bool enableCenterOfMass,
239  const Ice::Current&)
240  {
241  using PriorityJacobiProviderPair = std::pair<int, JacobiProviderPtr>;
242  auto lowerPriorityCompare =
243  [](const PriorityJacobiProviderPair& a, const PriorityJacobiProviderPair& b)
244  { return a.first < b.first; };
245  std::multiset<PriorityJacobiProviderPair, decltype(lowerPriorityCompare)> jacobiProviders(
246  lowerPriorityCompare);
247 
248  if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
249  {
250  throw UserException("Unknown robot node set " + robotNodeSetName);
251  }
252 
253  synchRobot();
254 
255  RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
256  // First add all ik tasks
257  for (DifferentialIKDescriptor const& ikTask : iktasks)
258  {
259  if (!_robotModel->hasRobotNode(ikTask.tcpName))
260  {
261  throw UserException("Unknown TCP: " + ikTask.tcpName);
262  }
263 
264  RobotNodePtr coordSystem = RobotNodePtr();
265 
266  if (ikTask.coordSysName.size() > 0 && _robotModel->hasRobotNode(ikTask.coordSysName))
267  {
268  coordSystem = _robotModel->getRobotNode(ikTask.coordSysName);
269  }
270 
271  DifferentialIKPtr diffIK(
272  new DifferentialIK(rns, coordSystem, convertInverseJacobiMethod(ikTask.ijm)));
273  Pose globalTcpPose(ikTask.tcpGoal->position, ikTask.tcpGoal->orientation);
274  RobotNodePtr tcp = _robotModel->getRobotNode(ikTask.tcpName);
275  diffIK->setGoal(globalTcpPose.toEigen(), tcp, convertCartesianSelection(ikTask.csel));
276  JacobiProviderPtr jacoProv = diffIK;
277  jacobiProviders.insert(PriorityJacobiProviderPair(ikTask.priority, jacoProv));
278  }
279 
280  // Now add the center of mass task
281  if (enableCenterOfMass)
282  {
283  if (!_robotModel->hasRobotNodeSet(comIK.robotNodeSetBodies))
284  {
285  throw UserException("Unknown robot node set for bodies: " +
286  comIK.robotNodeSetBodies);
287  }
288 
289  RobotNodePtr coordSystem = RobotNodePtr();
290 
291  if (comIK.coordSysName.size() > 0 && _robotModel->hasRobotNode(comIK.coordSysName))
292  {
293  coordSystem = _robotModel->getRobotNode(comIK.coordSysName);
294  }
295 
296  CoMIKPtr comIkSolver(
297  new CoMIK(rns, _robotModel->getRobotNodeSet(comIK.robotNodeSetBodies)));
298  Eigen::VectorXf goal(2);
299  goal(0) = comIK.gx;
300  goal(1) = comIK.gy;
301  comIkSolver->setGoal(goal, comIK.tolerance);
302  JacobiProviderPtr jacoProv = comIkSolver;
303  jacobiProviders.insert(PriorityJacobiProviderPair(comIK.priority, jacoProv));
304  }
305 
306  std::vector<JacobiProviderPtr> jacobies;
307  for (PriorityJacobiProviderPair const& pair : jacobiProviders)
308  {
309  jacobies.push_back(pair.second);
310  }
311 
312  if (avoidJointLimits)
313  {
314  JointLimitAvoidanceJacobiPtr avoidanceJacobi(new JointLimitAvoidanceJacobi(rns));
315  jacobies.push_back(avoidanceJacobi);
316  }
317 
318  std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
319  HierarchicalIK hik(rns);
320  Eigen::VectorXf delta = hik.computeStep(jacobies, stepSize);
321  NameValueMap result;
322 
323  int index = 0;
324  for (RobotNodePtr const& node : rns->getAllRobotNodes())
325  {
326  NameValueMap::value_type jointPair(node->getName(), delta(index));
327  result.insert(jointPair);
328  ++index;
329  }
330  return result;
331  }
332 
333  bool
334  RobotIK::createReachabilitySpace(const std::string& chainName,
335  const std::string& coordinateSystem,
336  float stepTranslation,
337  float stepRotation,
338  const WorkspaceBounds& minBounds,
339  const WorkspaceBounds& maxBounds,
340  int numSamples,
341  const Ice::Current&)
342  {
343  std::lock_guard<std::recursive_mutex> cacheLock(_accessReachabilityCacheMutex);
344 
345  if (_reachabilities.count(chainName) == 0)
346  {
347  if (!_robotModel->hasRobotNodeSet(chainName))
348  {
349  return false;
350  }
351 
352  //VirtualRobot::WorkspaceRepresentationPtr reachability(new Reachability(_robotModel));
353  VirtualRobot::WorkspaceRepresentationPtr reachability(new Manipulability(_robotModel));
354  float minBoundsArray[] = {
355  minBounds.x, minBounds.y, minBounds.z, minBounds.ro, minBounds.pi, minBounds.ya};
356  float maxBoundsArray[] = {
357  maxBounds.x, maxBounds.y, maxBounds.z, maxBounds.ro, maxBounds.pi, maxBounds.ya};
358 
359  std::lock_guard<std::recursive_mutex> robotLock(_modifyRobotModelMutex);
360 
361  // TODO add collision checks
362  if (coordinateSystem.size() > 0)
363  {
364  if (!_robotModel->hasRobotNode(coordinateSystem))
365  {
366  ARMARX_ERROR << "Unknown coordinate system " << coordinateSystem;
367  return false;
368  }
369 
370  reachability->initialize(_robotModel->getRobotNodeSet(chainName),
371  stepTranslation,
372  stepRotation,
373  minBoundsArray,
374  maxBoundsArray,
375  VirtualRobot::SceneObjectSetPtr(),
376  VirtualRobot::SceneObjectSetPtr(),
377  _robotModel->getRobotNode(coordinateSystem));
378  }
379  else
380  {
381  reachability->initialize(_robotModel->getRobotNodeSet(chainName),
382  stepTranslation,
383  stepRotation,
384  minBoundsArray,
385  maxBoundsArray);
386  ARMARX_WARNING << "Using global coordinate system to create reachability space.";
387  }
388 
389  reachability->addRandomTCPPoses(numSamples);
390  _reachabilities.insert(ReachabilityCacheType::value_type(chainName, reachability));
391  }
392 
393  return true;
394  }
395 
396  bool
397  RobotIK::defineRobotNodeSet(const std::string& name,
398  const NodeNameList& nodes,
399  const std::string& tcpName,
400  const std::string& rootNodeName,
401  const Ice::Current&)
402  {
403  auto stringsCompareEqual = [](const std::string& a, const std::string& b)
404  { return a.compare(b) == 0; };
405  auto stringsCompareSmaller = [](const std::string& a, const std::string& b)
406  { return a.compare(b) <= 0; };
407  // First check if there is already a set with the given name
408  // We need to lock here, to make sure we are not adding similar named sets at the same time.
409  std::lock_guard<std::recursive_mutex> lock(_editRobotNodeSetsMutex);
410 
411  if (_robotModel->hasRobotNodeSet(name))
412  {
413  // If so, check if the set is identical to the one we plan to add
414  bool setsIdentical = true;
415  RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(name);
416  // Check TCP node
417  RobotNodePtr tcpNode = rns->getTCP();
418  setsIdentical &= stringsCompareEqual(tcpNode->getName(), tcpName);
419  // Check Root node
420  RobotNodePtr rootNode = rns->getKinematicRoot();
421  setsIdentical &= stringsCompareEqual(rootNode->getName(), rootNodeName);
422  // Check remaining nodes
423  std::vector<std::string> nodeNames;
424  for (RobotNodePtr const& robotNode : rns->getAllRobotNodes())
425  {
426  nodeNames.push_back(robotNode->getName());
427  }
428  // TODO check if sorting actually makes sense here
429  std::sort(nodeNames.begin(), nodeNames.end(), stringsCompareSmaller);
430  std::vector<std::string> inputNodeNames(nodes);
431  std::sort(inputNodeNames.begin(), inputNodeNames.end(), stringsCompareSmaller);
432  std::pair<std::vector<std::string>::iterator, std::vector<std::string>::iterator>
433  mismatch;
434  mismatch = std::mismatch(
435  nodeNames.begin(), nodeNames.end(), inputNodeNames.begin(), stringsCompareEqual);
436  setsIdentical &=
437  mismatch.first == nodeNames.end() && mismatch.second == inputNodeNames.end();
438 
439  return setsIdentical;
440  }
441 
442  // Else we can add the new robot node set
443  RobotNodeSetPtr rns =
444  RobotNodeSet::createRobotNodeSet(_robotModel, name, nodes, rootNodeName, tcpName, true);
445  return _robotModel->hasRobotNodeSet(name);
446  }
447 
448  std::string
449  RobotIK::getRobotFilename(const Ice::Current&) const
450  {
451  return _robotFile;
452  }
453 
454  bool
455  RobotIK::hasReachabilitySpace(const std::string& chainName, const Ice::Current&) const
456  {
457  std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
458  return _reachabilities.count(chainName) > 0;
459  }
460 
461  bool
462  RobotIK::isFramedPoseReachable(const std::string& chainName,
463  const FramedPoseBasePtr& tcpPose,
464  const Ice::Current&) const
465  {
466  return isReachable(chainName, toReachabilityMapFrame(tcpPose, chainName));
467  }
468 
469  bool
470  RobotIK::isPoseReachable(const std::string& chainName,
471  const PoseBasePtr& tcpPose,
472  const Ice::Current&) const
473  {
474  Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
475  return isReachable(chainName, globalTcpPose.toEigen());
476  }
477 
478  bool
479  RobotIK::loadReachabilitySpace(const std::string& filename, const Ice::Current&)
480  {
481  VirtualRobot::WorkspaceRepresentationPtr newSpace;
482  bool success = false;
483 
484  // 1st try to load as manipulability file
485  try
486  {
487  newSpace.reset(new Manipulability(_robotModel));
488  newSpace->load(filename);
489  success = true;
490 
491  ARMARX_INFO << "Map '" << filename << "' loaded as Manipulability map";
492  }
493  catch (...)
494  {
495  }
496 
497  // 2nd try to load as reachability file
498  if (!success)
499  {
500  try
501  {
502  newSpace.reset(new Reachability(_robotModel));
503  newSpace->load(filename);
504  success = true;
505 
506  ARMARX_INFO << "Map '" << filename << "' loaded as Reachability map";
507  }
508  catch (...)
509  {
510  }
511  }
512 
513  if (!success)
514  {
515  ARMARX_ERROR << "Failed to load map '" << filename << "'";
516  return false;
517  }
518 
519  try
520  {
521  std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
522  std::string chainName = newSpace->getNodeSet()->getName();
523 
524  if (_reachabilities.count(chainName) == 0)
525  {
526  _reachabilities.insert(ReachabilityCacheType::value_type(chainName, newSpace));
527  }
528  else
529  {
530  ARMARX_WARNING << "Reachability map for kinematic chain '" << chainName
531  << "' already loaded";
532  return false;
533  }
534  }
535  catch (Exception&)
536  {
537  throw;
538  }
539 
540  return true;
541  }
542 
543  bool
544  RobotIK::saveReachabilitySpace(const std::string& robotNodeSet,
545  const std::string& filename,
546  const Ice::Current&) const
547  {
548  std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
549  bool success = false;
550 
551  if (_reachabilities.count(robotNodeSet) > 0)
552  {
553  ReachabilityCacheType::const_iterator it = _reachabilities.find(robotNodeSet);
554 
555  try
556  {
557  std::filesystem::path savePath(filename);
558  std::filesystem::create_directories(savePath.parent_path());
559  it->second->save(filename);
560  success = true;
561  }
562  catch (Exception&)
563  {
564  // no need to unlock, this is done automatically once we leave this context
565  throw;
566  }
567  }
568 
569  return success;
570  }
571 
572  void
573  RobotIK::computeIK(const std::string& robotNodeSetName,
574  const Eigen::Matrix4f& tcpPose,
576  NameValueMap& ikSolution)
577  {
578  if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
579  {
580  throw UserException("The robot model does not contain the robot node set " +
581  robotNodeSetName);
582  }
583 
584  RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
585  computeIK(rns, tcpPose, cs, ikSolution);
586  }
587 
588  void
589  RobotIK::computeIK(const std::string& robotNodeSetName,
590  const Eigen::Matrix4f& tcpPose,
592  ExtendedIKResult& ikSolution)
593  {
594  if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
595  {
596  throw UserException("The robot model does not contain the robot node set " +
597  robotNodeSetName);
598  }
599 
600  RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
601  computeIK(rns, tcpPose, cs, ikSolution);
602  }
603 
604  void
605  RobotIK::computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
606  const Eigen::Matrix4f& tcpPose,
608  NameValueMap& ikSolution)
609  {
610 
611  ikSolution.clear();
612  // For the rest of this function we need to lock access to the robot,
613  // because we need to make sure we read the correct result from the robot node set.
614  std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
615  // Synch the internal robot state with that of the robot state component
616  synchRobot();
617 
618  bool success = solveIK(tcpPose, cs, nodeSet);
619 
620 
621  // GenericIKSolver ikSolver(nodeSet, JacobiProvider::eSVDDamped);
622  // bool success = ikSolver.solve(tcpPose, convertCartesianSelection(cs), _numIKTrials);
623 
624  // Read solution from node set
625  if (success)
626  {
627  const std::vector<RobotNodePtr> robotNodes = nodeSet->getAllRobotNodes();
628  for (RobotNodePtr const& rnode : robotNodes)
629  {
630  NameValueMap::value_type jointPair(rnode->getName(), rnode->getJointValue());
631  ikSolution.insert(jointPair);
632  }
633  }
634 
635  // Lock is automatically released
636  }
637 
638  bool
639  RobotIK::solveIK(const Eigen::Matrix4f& tcpPose,
641  VirtualRobot::RobotNodeSetPtr nodeSet)
642  {
643  // VirtualRobot::ConstraintPtr poseConstraint(new VirtualRobot::PoseConstraint(_robotModel, nodeSet, nodeSet->getTCP(),
644  // tcpPose, convertCartesianSelection(cs)));
645 
646  std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
647  VirtualRobot::ConstraintPtr posConstraint(
648  new VirtualRobot::PositionConstraint(_robotModel,
649  nodeSet,
650  nodeSet->getTCP(),
651  tcpPose.block<3, 1>(0, 3),
652  convertCartesianSelection(cs)));
653  posConstraint->setOptimizationFunctionFactor(1);
654 
655  VirtualRobot::ConstraintPtr oriConstraint(
656  new VirtualRobot::OrientationConstraint(_robotModel,
657  nodeSet,
658  nodeSet->getTCP(),
659  tcpPose.block<3, 3>(0, 0),
660  convertCartesianSelection(cs),
661  VirtualRobot::MathTools::deg2rad(2)));
662  oriConstraint->setOptimizationFunctionFactor(1000);
663 
664  Eigen::VectorXf jointConfig;
665  nodeSet->getJointValues(jointConfig);
666  VirtualRobot::ConstraintPtr referenceConfigConstraint(
667  new VirtualRobot::ReferenceConfigurationConstraint(_robotModel, nodeSet, jointConfig));
668  referenceConfigConstraint->setOptimizationFunctionFactor(0.1);
669 
670  VirtualRobot::ConstraintPtr jointLimitAvoidanceConstraint(
671  new VirtualRobot::JointLimitAvoidanceConstraint(_robotModel, nodeSet));
672  jointLimitAvoidanceConstraint->setOptimizationFunctionFactor(0.1);
673 
674  // Instantiate solver and generate IK solution
675  VirtualRobot::ConstrainedOptimizationIK ikSolver(_robotModel, nodeSet, 0.5, 0.03);
676  ikSolver.addConstraint(posConstraint);
677  ikSolver.addConstraint(oriConstraint);
678  ikSolver.addConstraint(jointLimitAvoidanceConstraint);
679  ikSolver.addConstraint(referenceConfigConstraint);
680 
681  ikSolver.initialize();
682  bool success = ikSolver.solve();
683  if (!success) // try again with no soft-constraints, which distract the optimizer
684  {
685  VirtualRobot::ConstrainedOptimizationIK ikSolver(_robotModel, nodeSet, 0.5, 0.03);
686  ikSolver.addConstraint(posConstraint);
687  ikSolver.addConstraint(oriConstraint);
688 
689  ikSolver.initialize();
690  success = ikSolver.solve();
691  }
692  return success;
693  }
694 
695  void
696  RobotIK::computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
697  const Eigen::Matrix4f& tcpPose,
699  ExtendedIKResult& ikSolution)
700  {
701  ikSolution.jointAngles.clear();
702  // For the rest of this function we need to lock access to the robot,
703  // because we need to make sure we read the correct result from the robot node set.
704  std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
705  // Synch the internal robot state with that of the robot state component
706  synchRobot();
707 
708  bool success = solveIK(tcpPose, cs, nodeSet);
709 
710  // Read solution from node set
711  const std::vector<RobotNodePtr> robotNodes = nodeSet->getAllRobotNodes();
712  for (RobotNodePtr const& rnode : robotNodes)
713  {
714  NameValueMap::value_type jointPair(rnode->getName(), rnode->getJointValue());
715  ikSolution.jointAngles.insert(jointPair);
716  }
717 
718  //Calculate error
719  ikSolution.errorPosition =
720  (nodeSet->getTCP()->getGlobalPose().block<3, 1>(0, 3) - tcpPose.block<3, 1>(0, 3))
721  .norm();
722  ikSolution.errorOrientation =
723  Eigen::AngleAxisf(nodeSet->getTCP()->getGlobalPose().block<3, 3>(0, 0) *
724  tcpPose.block<3, 3>(0, 0).inverse())
725  .angle();
726 
727  ikSolution.isReachable = success;
728  // Lock is automatically released
729  }
730 
732  RobotIK::toGlobalPose(const FramedPoseBasePtr& tcpPose) const
733  {
734  FramedPose framedTcpPose(
735  tcpPose->position, tcpPose->orientation, tcpPose->frame, tcpPose->agent);
736  FramedPosePtr globalTcpPose = framedTcpPose.toGlobal(_synchronizedRobot);
737  return globalTcpPose->toEigen();
738  }
739 
741  RobotIK::toReachabilityMapFrame(const FramedPoseBasePtr& tcpPose,
742  const std::string& chainName) const
743  {
744  FramedPosePtr p = FramedPosePtr::dynamicCast(tcpPose);
745 
746  PosePtr p_global(new Pose(toGlobalPose(tcpPose)));
747  debugDrawer->setPoseDebugLayerVisu("Grasp Pose", p_global);
748 
749  std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
750 
751  if (_reachabilities.count(chainName))
752  {
753  ReachabilityCacheType::const_iterator it = _reachabilities.find(chainName);
754 
755  p->changeFrame(_synchronizedRobot, it->second->getBaseNode()->getName());
756  }
757  else
758  {
760  << "Could not convert TCP pose to reachability map frame: Map not found.";
761  }
762 
763  return p->toEigen();
764  }
765 
766  bool
767  RobotIK::isReachable(const std::string& setName, const Eigen::Matrix4f& tcpPose) const
768  {
769  ARMARX_INFO << "Checking reachability for kinematic chain '" << setName << "': " << tcpPose;
770 
771  std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
772 
773  if (_reachabilities.count(setName))
774  {
775  ReachabilityCacheType::const_iterator it = _reachabilities.find(setName);
776  return it->second->isCovered(tcpPose);
777  }
778  else
779  {
780  ARMARX_WARNING << "Could not find reachability map for kinematic chain '" << setName
781  << "'";
782  return false;
783  }
784  }
785 
787  RobotIK::convertCartesianSelection(armarx::CartesianSelection cs) const
788  {
789  switch (cs)
790  {
791  case armarx::CartesianSelection::eX:
792  return VirtualRobot::IKSolver::CartesianSelection::X;
793 
794  case armarx::CartesianSelection::eY:
795  return VirtualRobot::IKSolver::CartesianSelection::Y;
796 
797  case armarx::CartesianSelection::eZ:
798  return VirtualRobot::IKSolver::CartesianSelection::Z;
799 
802 
805 
807  return VirtualRobot::IKSolver::CartesianSelection::All;
808  }
809 
810  return VirtualRobot::IKSolver::CartesianSelection::All;
811  }
812 
813  VirtualRobot::JacobiProvider::InverseJacobiMethod
814  RobotIK::convertInverseJacobiMethod(armarx::InverseJacobiMethod aenum) const
815  {
816  switch (aenum)
817  {
818  case armarx::InverseJacobiMethod::eSVD:
819  return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVD;
820 
821  case armarx::InverseJacobiMethod::eSVDDamped:
822  return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVDDamped;
823 
824  case armarx::InverseJacobiMethod::eTranspose:
825  return VirtualRobot::JacobiProvider::InverseJacobiMethod::eTranspose;
826  }
827 
828  return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVD;
829  }
830 
831  void
832  RobotIK::synchRobot() const
833  {
834  std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
835  RemoteRobot::synchronizeLocalClone(_robotModel, _synchronizedRobot);
836  }
837 
838 } // namespace armarx
RemoteRobot.h
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
Eigen
Definition: Elements.h:32
GfxTL::Orientation
ScalarT Orientation(const VectorXD< 2, ScalarT > &p1, const VectorXD< 2, ScalarT > &p2, const VectorXD< 2, ScalarT > &c)
Definition: Orientation.h:10
armarx::navigation::core::Pose
Eigen::Isometry3f Pose
Definition: basic_types.h:31
index
uint8_t index
Definition: EtherCATFrame.h:59
armarx::VariantType::FramedPose
const VariantTypeId FramedPose
Definition: FramedPose.h:36
ArmarXManager.h
VirtualRobot
Definition: FramedPose.h:42
armarx::PosePtr
IceInternal::Handle< Pose > PosePtr
Definition: Pose.h:306
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
armarx::FramedPosePtr
IceInternal::Handle< FramedPose > FramedPosePtr
Definition: FramedPose.h:272
armarx::Split
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelperTemplates.h:36
armarx::NJointTaskSpaceDMPControllerMode::ePosition
@ ePosition
Definition: ControllerInterface.ice:36
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
space
std::string space
Definition: OrientedTactileSensorUnit.cpp:371
FramedPose.h
armarx::RobotIKPropertyDefinitions
Definition: RobotIK.h:47
armarx::NJointTaskSpaceDMPControllerMode::CartesianSelection
CartesianSelection
Definition: ControllerInterface.ice:34
RobotIK.h
armarx::Pose::toEigen
virtual Eigen::Matrix4f toEigen() const
Definition: Pose.cpp:334
filename
std::string filename
Definition: VisualizationRobot.cpp:86
ArmarXObjectScheduler.h
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::control::njoint_controller::platform::platform_follower_controller::NameValueMap
std::map< std::string, float > NameValueMap
Definition: PlatformFollowerController.h:88
armarx::Pose
The Pose class.
Definition: Pose.h:242
Ice
Definition: DBTypes.cpp:63
armarx::NJointTaskSpaceDMPControllerMode::eAll
@ eAll
Definition: ControllerInterface.ice:38
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
armarx::NJointTaskSpaceDMPControllerMode::eOrientation
@ eOrientation
Definition: ControllerInterface.ice:37
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::navigation::core::Position
Eigen::Vector3f Position
Definition: basic_types.h:36
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:35
ArmarXDataPath.h
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::status::success
@ success
armarx::control::njoint_mp_controller::task_space::ConstraintPtr
std::shared_ptr< Constraint1 > ConstraintPtr
Definition: KVILImpedanceController.h:56
norm
double norm(const Point &a)
Definition: point.hpp:102