CompositeDiffIK.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
5 * Karlsruhe Institute of Technology (KIT), all rights reserved.
6 *
7 * ArmarX is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * ArmarX is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Simon Ottenhaus (simon dot ottenhaus at kit dot edu)
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24#include "CompositeDiffIK.h"
25
26#include <cfloat>
27
28#include <VirtualRobot/IK/DifferentialIK.h>
29#include <VirtualRobot/Nodes/RobotNode.h>
30#include <VirtualRobot/Robot.h>
31#include <VirtualRobot/RobotNodeSet.h>
32#include <VirtualRobot/math/Helpers.h>
33
35
36using namespace armarx;
37
38CompositeDiffIK::CompositeDiffIK(const VirtualRobot::RobotNodeSetPtr& rns) : rns(rns)
39{
40 ik.reset(new VirtualRobot::DifferentialIK(
41 rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
42}
43
44void
46{
47 targets.emplace_back(target);
48}
49
51CompositeDiffIK::addTarget(const VirtualRobot::RobotNodePtr& tcp,
52 const Eigen::Matrix4f& target,
53 VirtualRobot::IKSolver::CartesianSelection mode)
54{
55 TargetPtr t = std::make_shared<Target>(rns, tcp, target, mode);
56 addTarget(t);
57 return t;
58}
59
60void
62{
63 nullspaceGradients.emplace_back(gradient);
64}
65
67CompositeDiffIK::addNullspacePositionTarget(const VirtualRobot::RobotNodePtr& tcp,
68 const Eigen::Vector3f& target)
69{
71 rns,
72 tcp,
73 math::Helpers::CreatePose(target, Eigen::Matrix3f::Identity()),
74 VirtualRobot::IKSolver::CartesianSelection::Position));
76 return nst;
77}
78
81{
82 //ARMARX_IMPORTANT << "###";
83 //ARMARX_IMPORTANT << VAROUT(rns->getJointValuesEigen().transpose());
84 if (params.resetRnsValues)
85 {
86 for (VirtualRobot::RobotNodePtr rn : rns->getAllRobotNodes())
87 {
88 if (rn->isLimitless())
89 {
90 rn->setJointValue(0);
91 }
92 else
93 {
94 rn->setJointValue((rn->getJointLimitHi() + rn->getJointLimitLo()) / 2);
95 }
96 }
97 }
98 //ARMARX_IMPORTANT << VAROUT(rns->getJointValuesEigen().transpose());
99
100 SolveState s;
101
102 s.rows = 0;
103 s.cols = rns->getSize();
104
105 for (const TargetPtr& target : targets)
106 {
107 s.rows += CartesianSelectionToSize(target->mode);
108 }
109
110 s.jointRegularization = Eigen::VectorXf::Zero(s.cols);
111 for (size_t i = 0; i < rns->getSize(); i++)
112 {
113 s.jointRegularization(i) = rns->getNode(i)->isTranslationalJoint()
116 }
117
118 s.cartesianRegularization = Eigen::VectorXf::Zero(s.rows);
119 {
121 int row = 0;
122 for (const TargetPtr& target : targets)
123 {
124 int h = CartesianSelectionToSize(target->mode);
125 target->jacobi = Eigen::MatrixXf::Zero(h, s.cols);
126 s.cartesianRegularization.block(row, 0, h, 1) =
127 tmpVC.calculateRegularization(target->mode);
128 row += h;
129 }
130 }
131 //ARMARX_IMPORTANT << "START";
132 //ARMARX_INFO << VAROUT(regularization.transpose());
133
134 s.jointValues = rns->getJointValuesEigen();
135
136 for (size_t i = 0; i <= params.steps; i++)
137 {
138 step(params, s, i);
139 }
140
141 bool allReached = true;
142 for (const TargetPtr& target : targets)
143 {
144 allReached = allReached &&
145 target->pCtrl.reached(
146 target->target, target->mode, target->maxPosError, target->maxOriError);
147 }
148
149 //ARMARX_IMPORTANT << "END";
150
151
152 //ARMARX_IMPORTANT << ss.str();
153
154 Result result;
155 result.jointValues = rns->getJointValuesEigen();
156 result.reached = allReached;
157 result.jointLimitMargins = Eigen::VectorXf::Zero(rns->getSize());
158 result.minimumJointLimitMargin = FLT_MAX;
159 for (size_t i = 0; i < rns->getSize(); i++)
160 {
161 VirtualRobot::RobotNodePtr rn = rns->getNode(i);
162 if (rn->isLimitless())
163 {
164 result.jointLimitMargins(i) = M_PI;
165 }
166 else
167 {
168 result.jointLimitMargins(i) = std::min(rn->getJointValue() - rn->getJointLimitLo(),
169 rn->getJointLimitHi() - rn->getJointValue());
171 std::min(result.minimumJointLimitMargin, result.jointLimitMargins(i));
172 }
173 }
174
175 return result;
176}
177
178Eigen::MatrixXf
179CompositeDiffIK::CalculateNullspaceSVD(const Eigen::Matrix4f& jacobi)
180{
181 Eigen::FullPivLU<Eigen::MatrixXf> lu_decomp(jacobi);
182 Eigen::MatrixXf nullspaceLU = lu_decomp.kernel();
183 return nullspaceLU;
184}
185
186Eigen::MatrixXf
187CompositeDiffIK::CalculateNullspaceLU(const Eigen::Matrix4f& jacobi)
188{
189 // cols >= rows
190 int rows = jacobi.rows();
191 int cols = jacobi.cols();
192 Eigen::JacobiSVD<Eigen::MatrixXf> svd(jacobi, Eigen::ComputeFullU | Eigen::ComputeFullV);
193 ///
194 /// \brief V contains right singular vector and nullspace:
195 /// V.shape: (cols,cols)
196 /// singular vectors: V[:,0:rows]
197 /// nullspace: V[:,rows:cols-rows]
198 ///
199 Eigen::MatrixXf V = svd.matrixV();
200 Eigen::MatrixXf nullspaceSVD = V.block(0, rows, cols, cols - rows);
201 return nullspaceSVD;
202}
203
204void
206{
207 //ARMARX_IMPORTANT << VAROUT(i);
208 s.jacobi = Eigen::MatrixXf::Zero(s.rows, s.cols);
209 s.invJac = Eigen::MatrixXf::Zero(s.cols, s.rows);
210
211 Eigen::VectorXf cartesianVel = Eigen::VectorXf::Zero(s.rows);
212 {
213 int row = 0;
214 for (const TargetPtr& target : targets)
215 {
216 ik->updateJacobianMatrix(target->jacobi, target->tcp, target->mode);
217 int h = CartesianSelectionToSize(target->mode);
218 s.jacobi.block(row, 0, h, s.cols) = target->jacobi;
219 Eigen::VectorXf cv = target->pCtrl.calculate(target->target, target->mode);
220 //ARMARX_INFO << VAROUT(cv.transpose());
221 cartesianVel.block(row, 0, h, 1) = cv;
222 row += h;
223 if (params.returnIKSteps)
224 {
226 step.tcpPose = target->tcp->getPoseInRootFrame();
227 step.cartesianVel = cv;
228 step.posDiff = target->pCtrl.getPositionDiff(target->target);
229 step.oriDiff = target->pCtrl.getOrientationDiff(target->target);
230 target->ikSteps.emplace_back(step);
231 }
232 }
233 }
234 //ARMARX_INFO << VAROUT(cartesianVel.transpose());
235 if (stepNr == 0)
236 {
237 //ARMARX_IMPORTANT << VAROUT(s.jacobi);
238 }
239
240 for (int row = 0; row < s.rows; row++)
241 {
242 s.jacobi.block(row, 0, 1, s.cols) =
243 s.jacobi.block(row, 0, 1, s.cols).cwiseProduct(s.jointRegularization.transpose());
244 }
245 if (stepNr == 0)
246 {
247 //ARMARX_IMPORTANT << VAROUT(s.jacobi);
248 }
249
250 ik->updatePseudoInverseJacobianMatrix(s.invJac, s.jacobi, 0, s.cartesianRegularization);
251
252 Eigen::VectorXf nullspaceVel = Eigen::VectorXf::Zero(s.cols);
253
254 for (const NullspaceGradientPtr& nsGradient : nullspaceGradients)
255 {
256 Eigen::VectorXf nsgrad = nsGradient->kP * nsGradient->getGradient(params);
257 //ARMARX_INFO << VAROUT(nsgrad.transpose());
258 nullspaceVel += nsgrad;
259 if (stepNr == 0)
260 {
261 //ARMARX_IMPORTANT << VAROUT(nsgrad.transpose());
262 }
263 }
264 //LimitInfNormTo(nullspaceVel, params.maxJointAngleStep);
265
266
267 Eigen::JacobiSVD<Eigen::MatrixXf> svd(s.jacobi, Eigen::ComputeFullU | Eigen::ComputeFullV);
268 Eigen::MatrixXf V = svd.matrixV();
269 Eigen::MatrixXf nullspaceSVD = V.block(0, s.rows, s.cols, s.cols - s.rows);
270
271 s.nullspace = nullspaceSVD; // CalculateNullspaceSVD(s.jacobi);
272
273 Eigen::VectorXf nsv = Eigen::VectorXf::Zero(s.cols);
274 for (int i = 0; i < s.nullspace.cols(); i++)
275 {
276 float squaredNorm = s.nullspace.col(i).squaredNorm();
277 // Prevent division by zero
278 if (squaredNorm > 1.0e-32f)
279 {
280 nsv += s.nullspace.col(i) * s.nullspace.col(i).dot(nullspaceVel) /
281 s.nullspace.col(i).squaredNorm();
282 }
283 }
284
285 Eigen::VectorXf jv = s.invJac * cartesianVel;
286 //ARMARX_INFO << VAROUT(jv.transpose());
287 //ARMARX_INFO << VAROUT(nsv.transpose());
288 jv = jv + nsv;
289 jv = jv * params.stepSize;
290 jv = LimitInfNormTo(jv, params.maxJointAngleStep);
291 jv = jv.cwiseProduct(s.jointRegularization);
292
293 //ARMARX_INFO << VAROUT(jv.transpose());
294
295 Eigen::VectorXf newJointValues = s.jointValues + jv;
296 if (stepNr == 0)
297 {
298 //ARMARX_IMPORTANT << VAROUT(cartesianVel.transpose());
299 //ARMARX_IMPORTANT << VAROUT(nullspaceVel.transpose());
300
301 //ARMARX_IMPORTANT << VAROUT(currentJointValues.transpose());
302 //ARMARX_IMPORTANT << VAROUT(newJointValues.transpose());
303 }
304 rns->setJointValues(newJointValues);
305 s.jointValues = newJointValues;
306}
307
308int
309CompositeDiffIK::CartesianSelectionToSize(VirtualRobot::IKSolver::CartesianSelection mode)
310{
311 switch (mode)
312 {
313 case VirtualRobot::IKSolver::CartesianSelection::Position:
314 return 3;
315 case VirtualRobot::IKSolver::CartesianSelection::Orientation:
316 return 3;
317 case VirtualRobot::IKSolver::CartesianSelection::All:
318 return 6;
319 default:
320 throw LocalException("mode not supported: ") << mode;
321 }
322}
323
324CompositeDiffIK::Target::Target(const VirtualRobot::RobotNodeSetPtr& rns,
325 const VirtualRobot::RobotNodePtr& tcp,
326 const Eigen::Matrix4f& target,
327 VirtualRobot::IKSolver::CartesianSelection mode) :
329{
330 jacobi = Eigen::MatrixXf::Zero(0, 0);
331}
332
333CompositeDiffIK::NullspaceTarget::NullspaceTarget(const VirtualRobot::RobotNodeSetPtr& rns,
334 const VirtualRobot::RobotNodePtr& tcp,
335 const Eigen::Matrix4f& target,
336 VirtualRobot::IKSolver::CartesianSelection mode) :
337 tcp(tcp), target(target), mode(mode), pCtrl(tcp), vCtrl(rns, tcp)
338{
339}
340
341void
346
347Eigen::VectorXf
349{
350 Eigen::VectorXf cv = pCtrl.calculate(target, mode);
351 Eigen::VectorXf jv = vCtrl.calculate(cv, mode);
352 if (params.returnIKSteps)
353 {
355 step.tcpPose = tcp->getPoseInRootFrame();
356 step.posDiff = pCtrl.getPositionDiff(target);
357 step.oriDiff = pCtrl.getOrientationDiff(target);
358 step.cartesianVel = cv;
359 step.jointVel = jv;
360 ikSteps.emplace_back(step);
361 }
362 return jv;
363}
364
365Eigen::VectorXf
366CompositeDiffIK::LimitInfNormTo(Eigen::VectorXf vec, float maxValue)
367{
368 float infNorm = vec.lpNorm<Eigen::Infinity>();
369 if (infNorm > maxValue)
370 {
371 vec = vec / infNorm * maxValue;
372 }
373 return vec;
374}
375
377 const VirtualRobot::RobotNodeSetPtr& rns) :
378 rns(rns), target(rns->getJointValuesEigen()), weight(Eigen::VectorXf::Zero(rns->getSize()))
379{
380}
381
383 const VirtualRobot::RobotNodeSetPtr& rns,
384 const Eigen::VectorXf& target,
385 const Eigen::VectorXf& weight) :
387{
388}
389
390void
392{
393 this->target(index) = target;
394 this->weight(index) = weight;
395}
396
397void
398CompositeDiffIK::NullspaceJointTarget::set(const std::string& jointName, float target, float weight)
399{
400 int index = rns->getRobotNodeIndex(jointName);
401 if (index < 0)
402 {
403 throw LocalException("RobotNodeSet has no joint ") << jointName;
404 }
406}
407
408void
409CompositeDiffIK::NullspaceJointTarget::set(const VirtualRobot::RobotNodePtr& rn,
410 float target,
411 float weight)
412{
413 int index = rns->getRobotNodeIndex(rn);
414 if (index < 0)
415 {
416 throw LocalException("RobotNodeSet has no joint ") << rn->getName();
417 }
419}
420
421void
425
426Eigen::VectorXf
428{
429 return (target - rns->getJointValuesEigen()).cwiseProduct(weight);
430}
431
433 const VirtualRobot::RobotNodeSetPtr& rns) :
434 rns(rns), weight(Eigen::VectorXf::Constant(rns->getSize(), 1))
435{
436}
437
439 const VirtualRobot::RobotNodeSetPtr& rns,
440 const Eigen::VectorXf& weight) :
442{
443}
444
445void
450
451void
453{
454 int index = rns->getRobotNodeIndex(jointName);
455 if (index < 0)
456 {
457 throw LocalException("RobotNodeSet has no joint ") << jointName;
458 }
460}
461
462void
464 float weight)
465{
466 int index = rns->getRobotNodeIndex(rn);
467 if (index < 0)
468 {
469 throw LocalException("RobotNodeSet has no joint ") << rn->getName();
470 }
472}
473
474void
476 float weight)
477{
478 for (const VirtualRobot::RobotNodePtr& rn : rns->getAllRobotNodes())
479 {
480 setWeight(rn, weight);
481 }
482}
483
484void
488
489Eigen::VectorXf
491{
492 Eigen::VectorXf r(rns->getSize());
493 for (size_t i = 0; i < rns->getSize(); i++)
494 {
495 VirtualRobot::RobotNodePtr rn = rns->getNode(i);
496 if (rn->isLimitless())
497 {
498 r(i) = 0;
499 }
500 else
501 {
502 float f = math::Helpers::ILerp(
503 rn->getJointLimitLo(), rn->getJointLimitHi(), rn->getJointValue());
504 r(i) = cos(f * M_PI);
505 //r(i) = math::MathUtils::Lerp(1.f, -1.f, f);
506 }
507 }
508 return r.cwiseProduct(weight);
509}
510
511Eigen::Matrix4f
513{
514 return tcp->getPoseInRootFrame().inverse() * target;
515}
516
517Eigen::Vector3f
519{
520 return (tcp->getPoseInRootFrame().inverse() * target).topRightCorner<3, 1>();
521}
522
523auto
525{
526 return simox::math::delta_angle(tcp->getPoseInRootFrame(), target);
527}
uint8_t index
#define M_PI
Definition MathTools.h:17
Eigen::VectorXf calculateRegularization(VirtualRobot::IKSolver::CartesianSelection mode)
Eigen::VectorXf getGradient(Parameters &params) override
void setWeights(const VirtualRobot::RobotNodeSetPtr &rns, float weight)
NullspaceJointLimitAvoidance(const VirtualRobot::RobotNodeSetPtr &rns)
Eigen::VectorXf getGradient(Parameters &params) override
NullspaceJointTarget(const VirtualRobot::RobotNodeSetPtr &rns)
void set(int index, float target, float weight)
NullspaceTarget(const VirtualRobot::RobotNodeSetPtr &rns, const VirtualRobot::RobotNodePtr &tcp, const Eigen::Matrix4f &target, VirtualRobot::IKSolver::CartesianSelection mode)
Eigen::VectorXf getGradient(Parameters &params) override
VirtualRobot::IKSolver::CartesianSelection mode
std::vector< NullspaceTargetStep > ikSteps
Target(const VirtualRobot::RobotNodeSetPtr &rns, const VirtualRobot::RobotNodePtr &tcp, const Eigen::Matrix4f &target, VirtualRobot::IKSolver::CartesianSelection mode)
VirtualRobot::IKSolver::CartesianSelection mode
Eigen::Matrix4f getPoseError() const
CartesianPositionController pCtrl
Eigen::Vector3f getPosError() const
VirtualRobot::RobotNodePtr tcp
int CartesianSelectionToSize(VirtualRobot::IKSolver::CartesianSelection mode)
Result solve(Parameters params)
static Eigen::MatrixXf CalculateNullspaceLU(const Eigen::Matrix4f &jacobi)
std::shared_ptr< class NullspaceGradient > NullspaceGradientPtr
void addTarget(const TargetPtr &target)
static Eigen::MatrixXf CalculateNullspaceSVD(const Eigen::Matrix4f &jacobi)
NullspaceTargetPtr addNullspacePositionTarget(const VirtualRobot::RobotNodePtr &tcp, const Eigen::Vector3f &target)
std::shared_ptr< class NullspaceTarget > NullspaceTargetPtr
void addNullspaceGradient(const NullspaceGradientPtr &gradient)
void step(Parameters &params, SolveState &s, int stepNr)
CompositeDiffIK(const VirtualRobot::RobotNodeSetPtr &rns)
static Eigen::VectorXf LimitInfNormTo(Eigen::VectorXf vec, float maxValue)
std::shared_ptr< Target > TargetPtr
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition helper.h:35