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