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>
54 using namespace Eigen;
61 RobotIK::onInitComponent()
63 _robotFile = getProperty<std::string>(
"RobotFileName").getValue();
65 if (!ArmarXDataPath::getAbsolutePath(_robotFile, _robotFile))
67 throw UserException(
"Could not find robot file " + _robotFile);
71 VirtualRobot::RobotIO::loadRobot(_robotFile, VirtualRobot::RobotIO::eStructure);
73 if (this->_robotModel)
83 _numIKTrials = getProperty<int>(
"NumIKTrials").getValue();
86 std::string spacesStr = getProperty<std::string>(
"InitialReachabilitySpaces").getValue();
87 std::vector<std::string> spaces =
armarx::Split(spacesStr,
";");
91 std::string spacesFolder =
92 getProperty<std::string>(
"ReachabilitySpacesFolder").getValue();
94 for (
auto&
space : spaces)
96 ARMARX_INFO <<
"Initially loading reachability space '"
97 << (spacesFolder +
"/" +
space) <<
"'";
99 std::string absolutePath;
101 if (!ArmarXDataPath::getAbsolutePath(spacesFolder +
"/" +
space, absolutePath))
104 << (spacesFolder +
"/" +
space) <<
"'";
108 loadReachabilitySpace(absolutePath);
112 usingProxy(getProperty<std::string>(
"RobotStateComponentName").getValue());
113 offeringTopic(
"DebugDrawerUpdates");
117 RobotIK::onConnectComponent()
119 _robotStateComponentPrx = getProxy<RobotStateComponentInterfacePrx>(
120 getProperty<std::string>(
"RobotStateComponentName").getValue());
122 std::string robFile_remote = _robotStateComponentPrx->getRobotFilename();
123 ArmarXDataPath::getAbsolutePath(robFile_remote, robFile_remote);
126 if (robFile_remote.compare(_robotFile) != 0)
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!";
133 _synchronizedRobot = _robotStateComponentPrx->getSynchronizedRobot();
134 debugDrawer = getTopic<armarx::DebugDrawerInterfacePrx>(
"DebugDrawerUpdates");
138 RobotIK::onDisconnectComponent()
143 RobotIK::createPropertyDefinitions()
149 RobotIK::computeIKFramedPose(
const std::string& robotNodeSetName,
150 const FramedPoseBasePtr& tcpPose,
155 computeIK(robotNodeSetName, toGlobalPose(tcpPose), cs, ikSolution);
160 RobotIK::computeIKGlobalPose(
const std::string& robotNodeSetName,
161 const PoseBasePtr& tcpPose,
166 Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
167 computeIK(robotNodeSetName, globalTcpPose.
toEigen(), cs, ikSolution);
172 RobotIK::computeExtendedIKGlobalPose(
const std::string& robotNodeSetName,
173 const PoseBasePtr& tcpPose,
177 ExtendedIKResult ikSolution;
178 Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
179 computeIK(robotNodeSetName, globalTcpPose.
toEigen(), cs, ikSolution);
184 RobotIK::computeCoMIK(
const std::string& robotNodeSetJoints,
185 const CoMIKDescriptor& desc,
189 if (!_robotModel->hasRobotNodeSet(robotNodeSetJoints))
194 if (!_robotModel->hasRobotNodeSet(desc.robotNodeSetBodies))
199 RobotNodePtr coordSystem = RobotNodePtr();
201 if (desc.coordSysName.size() > 0 && _robotModel->hasRobotNode(desc.coordSysName))
203 coordSystem = _robotModel->getRobotNode(desc.coordSysName);
207 RobotNodeSetPtr joints = _robotModel->getRobotNodeSet(robotNodeSetJoints);
209 joints, _robotModel->getRobotNodeSet(desc.robotNodeSetBodies), coordSystem);
210 Eigen::VectorXf goal(2);
213 comIkSolver.setGoal(goal, desc.tolerance);
216 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
217 bool success = comIkSolver.solveIK();
222 for (
auto& joint : joints->getAllRobotNodes())
224 NameValueMap::value_type jointPair(joint->getName(), joint->getJointValue());
225 result.insert(jointPair);
233 RobotIK::computeHierarchicalDeltaIK(
const std::string& robotNodeSetName,
234 const IKTasks& iktasks,
235 const CoMIKDescriptor& comIK,
237 bool avoidJointLimits,
238 bool enableCenterOfMass,
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);
248 if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
250 throw UserException(
"Unknown robot node set " + robotNodeSetName);
255 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
257 for (DifferentialIKDescriptor
const& ikTask : iktasks)
259 if (!_robotModel->hasRobotNode(ikTask.tcpName))
261 throw UserException(
"Unknown TCP: " + ikTask.tcpName);
264 RobotNodePtr coordSystem = RobotNodePtr();
266 if (ikTask.coordSysName.size() > 0 && _robotModel->hasRobotNode(ikTask.coordSysName))
268 coordSystem = _robotModel->getRobotNode(ikTask.coordSysName);
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));
281 if (enableCenterOfMass)
283 if (!_robotModel->hasRobotNodeSet(comIK.robotNodeSetBodies))
285 throw UserException(
"Unknown robot node set for bodies: " +
286 comIK.robotNodeSetBodies);
289 RobotNodePtr coordSystem = RobotNodePtr();
291 if (comIK.coordSysName.size() > 0 && _robotModel->hasRobotNode(comIK.coordSysName))
293 coordSystem = _robotModel->getRobotNode(comIK.coordSysName);
296 CoMIKPtr comIkSolver(
297 new CoMIK(rns, _robotModel->getRobotNodeSet(comIK.robotNodeSetBodies)));
298 Eigen::VectorXf goal(2);
301 comIkSolver->setGoal(goal, comIK.tolerance);
302 JacobiProviderPtr jacoProv = comIkSolver;
303 jacobiProviders.insert(PriorityJacobiProviderPair(comIK.priority, jacoProv));
306 std::vector<JacobiProviderPtr> jacobies;
307 for (PriorityJacobiProviderPair
const& pair : jacobiProviders)
309 jacobies.push_back(pair.second);
312 if (avoidJointLimits)
314 JointLimitAvoidanceJacobiPtr avoidanceJacobi(
new JointLimitAvoidanceJacobi(rns));
315 jacobies.push_back(avoidanceJacobi);
318 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
319 HierarchicalIK hik(rns);
320 Eigen::VectorXf delta = hik.computeStep(jacobies, stepSize);
324 for (RobotNodePtr
const& node : rns->getAllRobotNodes())
326 NameValueMap::value_type jointPair(node->getName(), delta(
index));
327 result.insert(jointPair);
334 RobotIK::createReachabilitySpace(
const std::string& chainName,
335 const std::string& coordinateSystem,
336 float stepTranslation,
338 const WorkspaceBounds& minBounds,
339 const WorkspaceBounds& maxBounds,
343 std::lock_guard<std::recursive_mutex> cacheLock(_accessReachabilityCacheMutex);
345 if (_reachabilities.count(chainName) == 0)
347 if (!_robotModel->hasRobotNodeSet(chainName))
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};
359 std::lock_guard<std::recursive_mutex> robotLock(_modifyRobotModelMutex);
362 if (coordinateSystem.size() > 0)
364 if (!_robotModel->hasRobotNode(coordinateSystem))
366 ARMARX_ERROR <<
"Unknown coordinate system " << coordinateSystem;
370 reachability->initialize(_robotModel->getRobotNodeSet(chainName),
375 VirtualRobot::SceneObjectSetPtr(),
376 VirtualRobot::SceneObjectSetPtr(),
377 _robotModel->getRobotNode(coordinateSystem));
381 reachability->initialize(_robotModel->getRobotNodeSet(chainName),
386 ARMARX_WARNING <<
"Using global coordinate system to create reachability space.";
389 reachability->addRandomTCPPoses(numSamples);
390 _reachabilities.insert(ReachabilityCacheType::value_type(chainName, reachability));
397 RobotIK::defineRobotNodeSet(
const std::string& name,
398 const NodeNameList& nodes,
399 const std::string& tcpName,
400 const std::string& rootNodeName,
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; };
409 std::lock_guard<std::recursive_mutex> lock(_editRobotNodeSetsMutex);
411 if (_robotModel->hasRobotNodeSet(name))
414 bool setsIdentical =
true;
415 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(name);
417 RobotNodePtr tcpNode = rns->getTCP();
418 setsIdentical &= stringsCompareEqual(tcpNode->getName(), tcpName);
420 RobotNodePtr rootNode = rns->getKinematicRoot();
421 setsIdentical &= stringsCompareEqual(rootNode->getName(), rootNodeName);
423 std::vector<std::string> nodeNames;
424 for (RobotNodePtr
const& robotNode : rns->getAllRobotNodes())
426 nodeNames.push_back(robotNode->getName());
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>
434 mismatch = std::mismatch(
435 nodeNames.begin(), nodeNames.end(), inputNodeNames.begin(), stringsCompareEqual);
437 mismatch.first == nodeNames.end() && mismatch.second == inputNodeNames.end();
439 return setsIdentical;
443 RobotNodeSetPtr rns =
444 RobotNodeSet::createRobotNodeSet(_robotModel, name, nodes, rootNodeName, tcpName,
true);
445 return _robotModel->hasRobotNodeSet(name);
449 RobotIK::getRobotFilename(
const Ice::Current&)
const
455 RobotIK::hasReachabilitySpace(
const std::string& chainName,
const Ice::Current&)
const
457 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
458 return _reachabilities.count(chainName) > 0;
462 RobotIK::isFramedPoseReachable(
const std::string& chainName,
463 const FramedPoseBasePtr& tcpPose,
464 const Ice::Current&)
const
466 return isReachable(chainName, toReachabilityMapFrame(tcpPose, chainName));
470 RobotIK::isPoseReachable(
const std::string& chainName,
471 const PoseBasePtr& tcpPose,
472 const Ice::Current&)
const
474 Pose globalTcpPose(tcpPose->position, tcpPose->orientation);
475 return isReachable(chainName, globalTcpPose.
toEigen());
479 RobotIK::loadReachabilitySpace(
const std::string&
filename,
const Ice::Current&)
481 VirtualRobot::WorkspaceRepresentationPtr newSpace;
487 newSpace.reset(
new Manipulability(_robotModel));
502 newSpace.reset(
new Reachability(_robotModel));
521 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
522 std::string chainName = newSpace->getNodeSet()->getName();
524 if (_reachabilities.count(chainName) == 0)
526 _reachabilities.insert(ReachabilityCacheType::value_type(chainName, newSpace));
530 ARMARX_WARNING <<
"Reachability map for kinematic chain '" << chainName
531 <<
"' already loaded";
544 RobotIK::saveReachabilitySpace(
const std::string& robotNodeSet,
546 const Ice::Current&)
const
548 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
551 if (_reachabilities.count(robotNodeSet) > 0)
553 ReachabilityCacheType::const_iterator it = _reachabilities.find(robotNodeSet);
557 std::filesystem::path savePath(
filename);
558 std::filesystem::create_directories(savePath.parent_path());
573 RobotIK::computeIK(
const std::string& robotNodeSetName,
578 if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
580 throw UserException(
"The robot model does not contain the robot node set " +
584 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
585 computeIK(rns, tcpPose, cs, ikSolution);
589 RobotIK::computeIK(
const std::string& robotNodeSetName,
592 ExtendedIKResult& ikSolution)
594 if (!_robotModel->hasRobotNodeSet(robotNodeSetName))
596 throw UserException(
"The robot model does not contain the robot node set " +
600 RobotNodeSetPtr rns = _robotModel->getRobotNodeSet(robotNodeSetName);
601 computeIK(rns, tcpPose, cs, ikSolution);
605 RobotIK::computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
614 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
618 bool success = solveIK(tcpPose, cs, nodeSet);
627 const std::vector<RobotNodePtr> robotNodes = nodeSet->getAllRobotNodes();
628 for (RobotNodePtr
const& rnode : robotNodes)
630 NameValueMap::value_type jointPair(rnode->getName(), rnode->getJointValue());
631 ikSolution.insert(jointPair);
641 VirtualRobot::RobotNodeSetPtr nodeSet)
646 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
648 new VirtualRobot::PositionConstraint(_robotModel,
651 tcpPose.block<3, 1>(0, 3),
652 convertCartesianSelection(cs)));
653 posConstraint->setOptimizationFunctionFactor(1);
656 new VirtualRobot::OrientationConstraint(_robotModel,
659 tcpPose.block<3, 3>(0, 0),
660 convertCartesianSelection(cs),
661 VirtualRobot::MathTools::deg2rad(2)));
662 oriConstraint->setOptimizationFunctionFactor(1000);
664 Eigen::VectorXf jointConfig;
665 nodeSet->getJointValues(jointConfig);
667 new VirtualRobot::ReferenceConfigurationConstraint(_robotModel, nodeSet, jointConfig));
668 referenceConfigConstraint->setOptimizationFunctionFactor(0.1);
671 new VirtualRobot::JointLimitAvoidanceConstraint(_robotModel, nodeSet));
672 jointLimitAvoidanceConstraint->setOptimizationFunctionFactor(0.1);
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);
681 ikSolver.initialize();
682 bool success = ikSolver.solve();
685 VirtualRobot::ConstrainedOptimizationIK ikSolver(_robotModel, nodeSet, 0.5, 0.03);
686 ikSolver.addConstraint(posConstraint);
687 ikSolver.addConstraint(oriConstraint);
689 ikSolver.initialize();
696 RobotIK::computeIK(VirtualRobot::RobotNodeSetPtr nodeSet,
699 ExtendedIKResult& ikSolution)
701 ikSolution.jointAngles.clear();
704 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
708 bool success = solveIK(tcpPose, cs, nodeSet);
711 const std::vector<RobotNodePtr> robotNodes = nodeSet->getAllRobotNodes();
712 for (RobotNodePtr
const& rnode : robotNodes)
714 NameValueMap::value_type jointPair(rnode->getName(), rnode->getJointValue());
715 ikSolution.jointAngles.insert(jointPair);
719 ikSolution.errorPosition =
720 (nodeSet->getTCP()->getGlobalPose().block<3, 1>(0, 3) - tcpPose.block<3, 1>(0, 3))
722 ikSolution.errorOrientation =
723 Eigen::AngleAxisf(nodeSet->getTCP()->getGlobalPose().block<3, 3>(0, 0) *
724 tcpPose.block<3, 3>(0, 0).inverse())
727 ikSolution.isReachable =
success;
732 RobotIK::toGlobalPose(
const FramedPoseBasePtr& tcpPose)
const
735 tcpPose->position, tcpPose->orientation, tcpPose->frame, tcpPose->agent);
736 FramedPosePtr globalTcpPose = framedTcpPose.toGlobal(_synchronizedRobot);
737 return globalTcpPose->toEigen();
741 RobotIK::toReachabilityMapFrame(
const FramedPoseBasePtr& tcpPose,
742 const std::string& chainName)
const
747 debugDrawer->setPoseDebugLayerVisu(
"Grasp Pose", p_global);
749 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
751 if (_reachabilities.count(chainName))
753 ReachabilityCacheType::const_iterator it = _reachabilities.find(chainName);
755 p->changeFrame(_synchronizedRobot, it->second->getBaseNode()->getName());
760 <<
"Could not convert TCP pose to reachability map frame: Map not found.";
767 RobotIK::isReachable(
const std::string& setName,
const Eigen::Matrix4f& tcpPose)
const
769 ARMARX_INFO <<
"Checking reachability for kinematic chain '" << setName <<
"': " << tcpPose;
771 std::lock_guard<std::recursive_mutex> lock(_accessReachabilityCacheMutex);
773 if (_reachabilities.count(setName))
775 ReachabilityCacheType::const_iterator it = _reachabilities.find(setName);
776 return it->second->isCovered(tcpPose);
780 ARMARX_WARNING <<
"Could not find reachability map for kinematic chain '" << setName
791 case armarx::CartesianSelection::eX:
792 return VirtualRobot::IKSolver::CartesianSelection::X;
794 case armarx::CartesianSelection::eY:
795 return VirtualRobot::IKSolver::CartesianSelection::Y;
797 case armarx::CartesianSelection::eZ:
798 return VirtualRobot::IKSolver::CartesianSelection::Z;
807 return VirtualRobot::IKSolver::CartesianSelection::All;
810 return VirtualRobot::IKSolver::CartesianSelection::All;
813 VirtualRobot::JacobiProvider::InverseJacobiMethod
814 RobotIK::convertInverseJacobiMethod(armarx::InverseJacobiMethod aenum)
const
818 case armarx::InverseJacobiMethod::eSVD:
819 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVD;
821 case armarx::InverseJacobiMethod::eSVDDamped:
822 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVDDamped;
824 case armarx::InverseJacobiMethod::eTranspose:
825 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eTranspose;
828 return VirtualRobot::JacobiProvider::InverseJacobiMethod::eSVD;
832 RobotIK::synchRobot()
const
834 std::lock_guard<std::recursive_mutex> lock(_modifyRobotModelMutex);
835 RemoteRobot::synchronizeLocalClone(_robotModel, _synchronizedRobot);