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