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>
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>
53 using namespace Eigen;
61 void RobotIK::onInitComponent()
63 _robotFile = getProperty<std::string>(
"RobotFileName").getValue();
65 if (!ArmarXDataPath::getAbsolutePath(_robotFile, _robotFile))
67 throw UserException(
"Could not find robot file " + _robotFile);
70 this->_robotModel = VirtualRobot::RobotIO::loadRobot(_robotFile, VirtualRobot::RobotIO::eStructure);
72 if (this->_robotModel)
82 _numIKTrials = getProperty<int>(
"NumIKTrials").getValue();
85 std::string spacesStr = getProperty<std::string>(
"InitialReachabilitySpaces").getValue();
86 std::vector<std::string> spaces =
armarx::Split(spacesStr,
";");
90 std::string spacesFolder = getProperty<std::string>(
"ReachabilitySpacesFolder").getValue();
92 for (
auto&
space : spaces)
94 ARMARX_INFO <<
"Initially loading reachability space '" << (spacesFolder +
"/" +
space) <<
"'";
96 std::string absolutePath;
98 if (!ArmarXDataPath::getAbsolutePath(spacesFolder +
"/" +
space, absolutePath))
100 ARMARX_ERROR <<
"Could not load reachability map '" << (spacesFolder +
"/" +
space) <<
"'";
104 loadReachabilitySpace(absolutePath);
108 usingProxy(getProperty<std::string>(
"RobotStateComponentName").getValue());
109 offeringTopic(
"DebugDrawerUpdates");
113 void RobotIK::onConnectComponent()
115 _robotStateComponentPrx = getProxy<RobotStateComponentInterfacePrx>(getProperty<std::string>(
"RobotStateComponentName").getValue());
117 std::string robFile_remote = _robotStateComponentPrx->getRobotFilename();
118 ArmarXDataPath::getAbsolutePath(robFile_remote, robFile_remote);
121 if (robFile_remote.compare(_robotFile) != 0)
123 ARMARX_WARNING <<
"The robot state component uses the robot model " << robFile_remote
124 <<
" This component, however, uses " << _robotFile <<
" Both models must be identical!";
127 _synchronizedRobot = _robotStateComponentPrx->getSynchronizedRobot();
128 debugDrawer = getTopic<armarx::DebugDrawerInterfacePrx>(
"DebugDrawerUpdates");
132 void RobotIK::onDisconnectComponent()
139 getConfigIdentifier()));
142 NameValueMap RobotIK::computeIKFramedPose(
const std::string& robotNodeSetName,
146 computeIK(robotNodeSetName, toGlobalPose(tcpPose), cs, ikSolution);
150 NameValueMap RobotIK::computeIKGlobalPose(
const std::string& robotNodeSetName,
154 Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
155 computeIK(robotNodeSetName, globalTcpPose.
toEigen(), cs, ikSolution);
159 ExtendedIKResult RobotIK::computeExtendedIKGlobalPose(
const std::string& robotNodeSetName,
162 ExtendedIKResult ikSolution;
163 Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
164 computeIK(robotNodeSetName, globalTcpPose.
toEigen(), cs, ikSolution);
168 NameValueMap RobotIK::computeCoMIK(
const std::string& robotNodeSetJoints,
const CoMIKDescriptor& desc,
const Ice::Current&)
171 if (!_robotModel->hasRobotNodeSet(robotNodeSetJoints))
176 if (!_robotModel->hasRobotNodeSet(desc.robotNodeSetBodies))
181 RobotNodePtr coordSystem = RobotNodePtr();
183 if (desc.coordSysName.size() > 0 && _robotModel->hasRobotNode(desc.coordSysName))
185 coordSystem = _robotModel->getRobotNode(desc.coordSysName);
189 RobotNodeSetPtr joints = _robotModel->getRobotNodeSet(robotNodeSetJoints);
190 CoMIK comIkSolver(joints, _robotModel->getRobotNodeSet(desc.robotNodeSetBodies), coordSystem);
191 Eigen::VectorXf goal(2);
194 comIkSolver.setGoal(goal, desc.tolerance);
197 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
198 bool success = comIkSolver.solveIK();
203 for (
auto& joint : joints->getAllRobotNodes())
205 NameValueMap::value_type jointPair(joint->getName(), joint->getJointValue());
206 result.insert(jointPair);
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&)
217 using PriorityJacobiProviderPair = std::pair<int, JacobiProviderPtr>;
218 auto lowerPriorityCompare = [](
const PriorityJacobiProviderPair &
a,
const PriorityJacobiProviderPair & b)
220 return a.first < b.first;
222 std::multiset<PriorityJacobiProviderPair, decltype(lowerPriorityCompare)> jacobiProviders(lowerPriorityCompare);
224 if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
226 throw UserException(
"Unknown robot node set " + robotNodeSetName);
231 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
233 for (DifferentialIKDescriptor
const& ikTask : iktasks)
235 if (!_robotModel->hasRobotNode(ikTask.tcpName))
237 throw UserException(
"Unknown TCP: " + ikTask.tcpName);
240 RobotNodePtr coordSystem = RobotNodePtr();
242 if (ikTask.coordSysName.size() > 0 && _robotModel->hasRobotNode(ikTask.coordSysName))
244 coordSystem = _robotModel->getRobotNode(ikTask.coordSysName);
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));
256 if (enableCenterOfMass)
258 if (!_robotModel->hasRobotNodeSet(comIK.robotNodeSetBodies))
260 throw UserException(
"Unknown robot node set for bodies: " + comIK.robotNodeSetBodies);
263 RobotNodePtr coordSystem = RobotNodePtr();
265 if (comIK.coordSysName.size() > 0 && _robotModel->hasRobotNode(comIK.coordSysName))
267 coordSystem = _robotModel->getRobotNode(comIK.coordSysName);
270 CoMIKPtr comIkSolver(
new CoMIK(rns, _robotModel->getRobotNodeSet(comIK.robotNodeSetBodies)));
271 Eigen::VectorXf goal(2);
274 comIkSolver->setGoal(goal, comIK.tolerance);
275 JacobiProviderPtr jacoProv = comIkSolver;
276 jacobiProviders.insert(PriorityJacobiProviderPair(comIK.priority, jacoProv));
279 std::vector<JacobiProviderPtr> jacobies;
280 for (PriorityJacobiProviderPair
const& pair : jacobiProviders)
282 jacobies.push_back(pair.second);
285 if (avoidJointLimits)
287 JointLimitAvoidanceJacobiPtr avoidanceJacobi(
new JointLimitAvoidanceJacobi(rns));
288 jacobies.push_back(avoidanceJacobi);
291 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
292 HierarchicalIK hik(rns);
293 Eigen::VectorXf delta = hik.computeStep(jacobies, stepSize);
297 for (RobotNodePtr
const& node : rns->getAllRobotNodes())
299 NameValueMap::value_type jointPair(node->getName(), delta(
index));
300 result.insert(jointPair);
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&)
309 std::lock_guard<std::recursive_mutex> cacheLock(_accessReachabilityCacheMutex);
311 if (_reachabilities.count(chainName) == 0)
313 if (!_robotModel->hasRobotNodeSet(chainName))
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};
323 std::lock_guard<std::recursive_mutex> robotLock(_modifyRobotModelMutex);
326 if (coordinateSystem.size() > 0)
328 if (!_robotModel->hasRobotNode(coordinateSystem))
330 ARMARX_ERROR <<
"Unknown coordinate system " << coordinateSystem;
334 reachability->initialize(_robotModel->getRobotNodeSet(chainName), stepTranslation, stepRotation, minBoundsArray, maxBoundsArray,
335 VirtualRobot::SceneObjectSetPtr(), VirtualRobot::SceneObjectSetPtr(), _robotModel->getRobotNode(coordinateSystem));
339 reachability->initialize(_robotModel->getRobotNodeSet(chainName), stepTranslation, stepRotation, minBoundsArray, maxBoundsArray);
340 ARMARX_WARNING <<
"Using global coordinate system to create reachability space.";
343 reachability->addRandomTCPPoses(numSamples);
344 _reachabilities.insert(ReachabilityCacheType::value_type(chainName, reachability));
350 bool RobotIK::defineRobotNodeSet(
const std::string& name,
const NodeNameList& nodes,
351 const std::string& tcpName,
const std::string& rootNodeName,
const Ice::Current&)
353 auto stringsCompareEqual = [](
const std::string &
a,
const std::string & b)
355 return a.compare(b) == 0;
357 auto stringsCompareSmaller = [](
const std::string &
a,
const std::string & b)
359 return a.compare(b) <= 0;
363 std::lock_guard<std::recursive_mutex> lock(_editRobotNodeSetsMutex);
365 if (_robotModel->hasRobotNodeSet(name))
368 bool setsIdentical =
true;
369 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(name);
371 RobotNodePtr tcpNode = rns->getTCP();
372 setsIdentical &= stringsCompareEqual(tcpNode->getName(), tcpName);
374 RobotNodePtr rootNode = rns->getKinematicRoot();
375 setsIdentical &= stringsCompareEqual(rootNode->getName(), rootNodeName);
377 std::vector<std::string> nodeNames;
378 for (RobotNodePtr
const& robotNode : rns->getAllRobotNodes())
380 nodeNames.push_back(robotNode->getName());
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();
390 return setsIdentical;
394 RobotNodeSetPtr rns = RobotNodeSet::createRobotNodeSet(_robotModel, name, nodes, rootNodeName, tcpName,
true);
395 return _robotModel->hasRobotNodeSet(name);
398 std::string RobotIK::getRobotFilename(
const Ice::Current&)
const
403 bool RobotIK::hasReachabilitySpace(
const std::string& chainName,
const Ice::Current&)
const
405 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
406 return _reachabilities.count(chainName) > 0;
409 bool RobotIK::isFramedPoseReachable(
const std::string& chainName,
const FramedPoseBasePtr& tcpPose,
const Ice::Current&)
const
411 return isReachable(chainName, toReachabilityMapFrame(tcpPose, chainName));
414 bool RobotIK::isPoseReachable(
const std::string& chainName,
const PoseBasePtr& tcpPose,
const Ice::Current&)
const
416 Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
417 return isReachable(chainName, globalTcpPose.
toEigen());
420 bool RobotIK::loadReachabilitySpace(
const std::string&
filename,
const Ice::Current&)
422 VirtualRobot::WorkspaceRepresentationPtr newSpace;
428 newSpace.reset(
new Manipulability(_robotModel));
443 newSpace.reset(
new Reachability(_robotModel));
462 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
463 std::string chainName = newSpace->getNodeSet()->getName();
465 if (_reachabilities.count(chainName) == 0)
467 _reachabilities.insert(ReachabilityCacheType::value_type(chainName, newSpace));
471 ARMARX_WARNING <<
"Reachability map for kinematic chain '" << chainName <<
"' already loaded";
483 bool RobotIK::saveReachabilitySpace(
const std::string& robotNodeSet,
const std::string&
filename,
const Ice::Current&)
const
485 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
488 if (_reachabilities.count(robotNodeSet) > 0)
490 ReachabilityCacheType::const_iterator it = _reachabilities.find(robotNodeSet);
494 std::filesystem::path savePath(
filename);
495 std::filesystem::create_directories(savePath.parent_path());
509 void RobotIK::computeIK(
const std::string& robotNodeSetName,
const Eigen::Matrix4f& tcpPose,
512 if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
514 throw UserException(
"The robot model does not contain the robot node set " + robotNodeSetName);
517 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
518 computeIK(rns, tcpPose, cs, ikSolution);
521 void RobotIK::computeIK(
const std::string& robotNodeSetName,
const Eigen::Matrix4f& tcpPose,
524 if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
526 throw UserException(
"The robot model does not contain the robot node set " + robotNodeSetName);
529 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
530 computeIK(rns, tcpPose, cs, ikSolution);
533 void RobotIK::computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
const Eigen::Matrix4f& tcpPose,
540 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
544 bool success = solveIK(tcpPose, cs, nodeSet);
553 const std::vector<RobotNodePtr> robotNodes = nodeSet->getAllRobotNodes();
554 for (RobotNodePtr
const& rnode : robotNodes)
556 NameValueMap::value_type jointPair(rnode->getName(), rnode->getJointValue());
557 ikSolution.insert(jointPair);
569 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
571 tcpPose.block<3, 1>(0, 3), convertCartesianSelection(cs)));
572 posConstraint->setOptimizationFunctionFactor(1);
575 tcpPose.block<3, 3>(0, 0), convertCartesianSelection(cs), VirtualRobot::MathTools::deg2rad(2)));
576 oriConstraint->setOptimizationFunctionFactor(1000);
578 Eigen::VectorXf jointConfig;
579 nodeSet->getJointValues(jointConfig);
580 VirtualRobot::ConstraintPtr referenceConfigConstraint(
new VirtualRobot::ReferenceConfigurationConstraint(_robotModel, nodeSet, jointConfig));
581 referenceConfigConstraint->setOptimizationFunctionFactor(0.1);
584 jointLimitAvoidanceConstraint->setOptimizationFunctionFactor(0.1);
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);
593 ikSolver.initialize();
594 bool success = ikSolver.solve();
597 VirtualRobot::ConstrainedOptimizationIK ikSolver(_robotModel, nodeSet, 0.5, 0.03);
598 ikSolver.addConstraint(posConstraint);
599 ikSolver.addConstraint(oriConstraint);
601 ikSolver.initialize();
607 void RobotIK::computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
const Eigen::Matrix4f& tcpPose,
610 ikSolution.jointAngles.clear();
613 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
617 bool success = solveIK(tcpPose, cs, nodeSet);
620 const std::vector<RobotNodePtr> robotNodes = nodeSet->getAllRobotNodes();
621 for (RobotNodePtr
const& rnode : robotNodes)
623 NameValueMap::value_type jointPair(rnode->getName(), rnode->getJointValue());
624 ikSolution.jointAngles.insert(jointPair);
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();
631 ikSolution.isReachable =
success;
636 Eigen::Matrix4f RobotIK::toGlobalPose(
const FramedPoseBasePtr& tcpPose)
const
638 FramedPose framedTcpPose(tcpPose->position, tcpPose->orientation, tcpPose->frame, tcpPose->agent);
639 FramedPosePtr globalTcpPose = framedTcpPose.toGlobal(_synchronizedRobot);
640 return globalTcpPose->toEigen();
643 Eigen::Matrix4f RobotIK::toReachabilityMapFrame(
const FramedPoseBasePtr& tcpPose,
const std::string& chainName)
const
648 debugDrawer->setPoseDebugLayerVisu(
"Grasp Pose", p_global);
650 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
652 if (_reachabilities.count(chainName))
654 ReachabilityCacheType::const_iterator it = _reachabilities.find(chainName);
656 p->changeFrame(_synchronizedRobot, it->second->getBaseNode()->getName());
660 ARMARX_WARNING <<
"Could not convert TCP pose to reachability map frame: Map not found.";
666 bool RobotIK::isReachable(
const std::string& setName,
const Eigen::Matrix4f& tcpPose)
const
668 ARMARX_INFO <<
"Checking reachability for kinematic chain '" << setName <<
"': " << tcpPose;
670 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
672 if (_reachabilities.count(setName))
674 ReachabilityCacheType::const_iterator it = _reachabilities.find(setName);
675 return it->second->isCovered(tcpPose);
679 ARMARX_WARNING <<
"Could not find reachability map for kinematic chain '" << setName <<
"'";
688 case armarx::CartesianSelection::eX:
689 return VirtualRobot::IKSolver::CartesianSelection::X;
691 case armarx::CartesianSelection::eY:
692 return VirtualRobot::IKSolver::CartesianSelection::Y;
694 case armarx::CartesianSelection::eZ:
695 return VirtualRobot::IKSolver::CartesianSelection::Z;
704 return VirtualRobot::IKSolver::CartesianSelection::All;
707 return VirtualRobot::IKSolver::CartesianSelection::All;
710 VirtualRobot::JacobiProvider::InverseJacobiMethod RobotIK::convertInverseJacobiMethod(armarx::InverseJacobiMethod aenum)
const
714 case armarx::InverseJacobiMethod::eSVD:
715 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVD;
717 case armarx::InverseJacobiMethod::eSVDDamped:
718 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVDDamped;
720 case armarx::InverseJacobiMethod::eTranspose:
721 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eTranspose;
724 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVD;
727 void RobotIK::synchRobot()
const
729 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
730 RemoteRobot::synchronizeLocalClone(_robotModel, _synchronizedRobot);