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