CartesianVelocityController.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 ()
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
25
26#include <Eigen/Core>
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
36
38
39using namespace armarx;
40
42 const VirtualRobot::RobotNodeSetPtr& rns,
43 const VirtualRobot::RobotNodePtr& tcp,
44 const VirtualRobot::JacobiProvider::InverseJacobiMethod invJacMethod,
45 bool considerJointLimits) :
46 rns(rns), _considerJointLimits(considerJointLimits)
47{
48 //ARMARX_IMPORTANT << VAROUT(rns->getRobot()->getRootNode());
49 ik.reset(new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), invJacMethod));
50 _tcp = tcp ? tcp : rns->getTCP();
51
52 _cartesianMMRegularization = 100;
53 _cartesianRadianRegularization = 1;
54 _jointCosts = Eigen::VectorXf::Constant(rns->getSize(), 1);
55}
56
57void
58CartesianVelocityController::calculateJacobis(VirtualRobot::IKSolver::CartesianSelection mode)
59{
61 jacobi = ik->getJacobianMatrix(_tcp, mode);
62 _jacobiWithCosts = Eigen::MatrixXf(jacobi.rows(), jacobi.cols());
63 for (int r = 0; r < jacobi.rows(); r++)
64 {
65 for (int c = 0; c < jacobi.cols(); c++)
66 {
67 _jacobiWithCosts(r, c) = jacobi(r, c) / _jointCosts(c);
68 }
69 }
70 auto svd = Eigen::JacobiSVD(_jacobiWithCosts, Eigen::ComputeThinU | Eigen::ComputeThinV);
71 auto sv = svd.singularValues();
72 double minSigVal = sv(sv.rows() - 1, sv.cols() - 1);
73 double damping = minSigVal < 1e-2 ? 1e-2 : 1e-8;
74 ik->setDampedSvdLambda(damping);
75 _inv =
76 ik->computePseudoInverseJacobianMatrix(_jacobiWithCosts, ik->getJacobiRegularization(mode));
77}
78
79Eigen::VectorXf
80CartesianVelocityController::calculate(const Eigen::VectorXf& cartesianVel,
81 VirtualRobot::IKSolver::CartesianSelection mode)
82{
83 return calculate(cartesianVel, Eigen::VectorXf::Zero(0), mode);
84 /*calculateJacobis(mode);
85
86 if (_considerJointLimits)
87 {
88 clampJacobiAtJointLimits(mode, cartesianVel, _jacobiWithCosts, _inv);
89 }
90
91 Eigen::VectorXf jointVel = _inv * cartesianVel;
92 jointVel += nsv;
93 for (int r = 0; r < jointVel.rows(); r++)
94 {
95 jointVel(r) = jointVel(r) / _jointCosts(r);
96 }
97
98 if (maximumJointVelocities.rows() > 0)
99 {
100 jointVel = ::math::Helpers::LimitVectorLength(jointVel, maximumJointVelocities);
101 }
102
103 return jointVel;*/
104}
105
106Eigen::VectorXf
107CartesianVelocityController::calculate(const Eigen::VectorXf& cartesianVel,
108 float KpJointLimitAvoidanceScale,
109 VirtualRobot::IKSolver::CartesianSelection mode)
110{
111 Eigen::VectorXf nullspaceVel =
112 calculateNullspaceVelocity(cartesianVel, KpJointLimitAvoidanceScale, mode);
113 return calculate(cartesianVel, nullspaceVel, mode);
114}
115
116Eigen::VectorXf
117CartesianVelocityController::calculate(const Eigen::VectorXf& cartesianVel,
118 const Eigen::VectorXf& nullspaceVel,
119 VirtualRobot::IKSolver::CartesianSelection mode)
120{
122 calculateJacobis(mode);
123
124
125 Eigen::VectorXf nsv = Eigen::VectorXf::Zero(rns->getSize());
126
127 if (nullspaceVel.rows() > 0)
128 {
130 // ARMARX_IMPORTANT << "nullspaceVel " << nullspaceVel.transpose();
131 Eigen::FullPivLU<Eigen::MatrixXf> lu_decomp(_jacobiWithCosts);
132 //ARMARX_IMPORTANT << "The rank of the _jacobiWithCosts is " << lu_decomp.rank();
133 //ARMARX_IMPORTANT << "Null space: " << lu_decomp.kernel();
134 Eigen::MatrixXf nullspace = lu_decomp.kernel();
135
136 for (int i = 0; i < nullspace.cols(); i++)
137 {
138 float squaredNorm = nullspace.col(i).squaredNorm();
139 // Prevent division by zero
140 if (squaredNorm > 1.0e-32f)
141 {
142 nsv += nullspace.col(i) * nullspace.col(i).dot(nullspaceVel) /
143 nullspace.col(i).squaredNorm();
144 }
145 }
146 }
147
148
149 if (_considerJointLimits)
150 {
151 clampJacobiAtJointLimits(mode, cartesianVel, _jacobiWithCosts, _inv);
152 }
153
154
155 Eigen::VectorXf jointVel = _inv * cartesianVel;
156 jointVel += nsv;
157 for (int r = 0; r < jointVel.rows(); r++)
158 {
159 jointVel(r) = jointVel(r) / _jointCosts(r);
160 }
161
162 if (maximumJointVelocities.rows() > 0)
163 {
164 jointVel = ::math::Helpers::LimitVectorLength(jointVel, maximumJointVelocities);
165 }
166
167 return jointVel;
168}
169
170Eigen::VectorXf
172{
173 Eigen::VectorXf r(rns->getSize());
174 for (size_t i = 0; i < rns->getSize(); i++)
175 {
176 VirtualRobot::RobotNodePtr rn = rns->getNode(i);
177 if (rn->isLimitless())
178 {
179 r(i) = 0;
180 }
181 else
182 {
183 float f = math::MathUtils::ILerp(
184 rn->getJointLimitLo(), rn->getJointLimitHi(), rn->getJointValue());
185 r(i) = cos(f * M_PI);
186 //r(i) = math::MathUtils::Lerp(1.f, -1.f, f);
187 }
188 }
189 return r;
190}
191
192/**
193 * @brief CartesianVelocityController::calculateJointLimitAvoidanceWithMargins
194 * @param margins Vector with same size as rns. Values between 0 (no margin) and 1 (50% low and 50% high margin).
195 * @return
196 */
197Eigen::VectorXf
199{
200 Eigen::VectorXf r(rns->getSize());
201 for (size_t i = 0; i < rns->getSize(); i++)
202 {
203 VirtualRobot::RobotNodePtr rn = rns->getNode(i);
204 //ARMARX_IMPORTANT << "rn " << i << "is limitless: " << rn->isLimitless();
205 if (rn->isLimitless() || margins(i) <= 0)
206 {
207 r(i) = 0;
208 }
209 else
210 {
211 float lo = rn->getJointLimitLo();
212 float hi = rn->getJointLimitHi();
213 float range = hi - lo;
214 float mrg = math::MathUtils::LimitMinMax(0.f, 1.f, margins(i) * range / 2);
215 r(i) = math::MathUtils::ILerpClamp(lo + mrg, lo, rn->getJointValue()) +
216 math::MathUtils::ILerpClamp(hi, hi - mrg, rn->getJointValue());
217 }
218 }
219 return r;
220}
221
222Eigen::VectorXf
224 const Eigen::VectorXf& cartesianVel,
225 float KpScale,
226 VirtualRobot::IKSolver::CartesianSelection mode)
227{
228 Eigen::VectorXf regularization = calculateRegularization(mode);
229 // Eigen does not allow product between two column vectors (this fails in Debug mode)
230 // In Release this causes cartesianVel to be only multiplied by the first element of regularization
231 // Eigen::VectorXf vel = cartesianVel * regularization;
232 Eigen::VectorXf vel = cartesianVel.cwiseProduct(regularization);
233
234 return KpScale * vel.norm() * calculateJointLimitAvoidance();
235}
236
237void
239 float cartesianRadianRegularization)
240{
241 _cartesianMMRegularization = cartesianMMRegularization;
242 _cartesianRadianRegularization = cartesianRadianRegularization;
243}
244
245Eigen::VectorXf
247 VirtualRobot::IKSolver::CartesianSelection mode)
248{
249 Eigen::VectorXf regularization(6);
250
251 int i = 0;
252
253 if (mode & VirtualRobot::IKSolver::X)
254 {
255 regularization(i++) = 1 / _cartesianMMRegularization;
256 }
257
258 if (mode & VirtualRobot::IKSolver::Y)
259 {
260 regularization(i++) = 1 / _cartesianMMRegularization;
261 }
262
263 if (mode & VirtualRobot::IKSolver::Z)
264 {
265 regularization(i++) = 1 / _cartesianMMRegularization;
266 }
267
268 if (mode & VirtualRobot::IKSolver::Orientation)
269 {
270 regularization(i++) = 1 / _cartesianRadianRegularization;
271 regularization(i++) = 1 / _cartesianRadianRegularization;
272 regularization(i++) = 1 / _cartesianRadianRegularization;
273 }
274 return regularization.topRows(i);
275}
276
277bool
278CartesianVelocityController::clampJacobiAtJointLimits(
279 VirtualRobot::IKSolver::CartesianSelection mode,
280 const Eigen::VectorXf& cartesianVel,
281 Eigen::MatrixXf& jacobi,
282 Eigen::MatrixXf& inv,
283 float jointLimitCheckAccuracy)
284{
285 bool modifiedJacobi = false;
286
287 Eigen::VectorXf jointVel = inv * cartesianVel;
288 size_t size = rns->getSize();
289
290 for (size_t i = 0; i < size; ++i)
291 {
292 auto& node = rns->getNode(static_cast<int>(i));
293
294 if (node->isLimitless() || // limitless joint cannot be out of limits
295 std::abs(jointVel(i)) <
296 0.001f // If it the jacobi doesnt want this joint to move anyway, there is no point in recalculating the inverse jacobi
297 )
298 {
299 continue;
300 }
301
302 if ((node->getJointValue() >= node->getJointLimitHigh() - jointLimitCheckAccuracy &&
303 jointVel(i) > 0) ||
304 (node->getJointValue() <= node->getJointLimitLow() + jointLimitCheckAccuracy &&
305 jointVel(i) < 0))
306 {
307 for (int k = 0; k < jacobi.rows(); ++k) // memory allocation free resetting of column
308 {
309 jacobi(k, i) = 0.0f;
310 }
311 modifiedJacobi = true;
312 }
313 }
314 if (modifiedJacobi)
315 {
316 auto svd = Eigen::JacobiSVD(jacobi, Eigen::ComputeThinU | Eigen::ComputeThinV);
317 auto sv = svd.singularValues();
318 double minSigVal = sv(sv.rows() - 1, sv.cols() - 1);
319 double damping = minSigVal < 1e-2 ? 1e-2 : 1e-8;
320 ik->setDampedSvdLambda(damping);
321 inv = ik->computePseudoInverseJacobianMatrix(jacobi, ik->getJacobiRegularization(mode));
322 }
323
324
325 return modifiedJacobi;
326}
327
328bool
330{
331 return _considerJointLimits;
332}
333
334void
336{
337 _considerJointLimits = value;
338}
339
340void
341CartesianVelocityController::setJointCosts(const std::vector<float>& jointCosts)
342{
343 ARMARX_CHECK((int)jointCosts.size() == _jointCosts.rows());
344 for (size_t i = 0; i < jointCosts.size(); i++)
345 {
346 _jointCosts(i) = jointCosts.at(i);
347 }
348}
#define lo(x)
#define hi(x)
#define M_PI
Definition MathTools.h:17
constexpr T c
Eigen::VectorXf calculateRegularization(VirtualRobot::IKSolver::CartesianSelection mode)
void setJointCosts(const std::vector< float > &_jointCosts)
Eigen::VectorXf calculateJointLimitAvoidanceWithMargins(const Eigen::VectorXf &margins)
CartesianVelocityController::calculateJointLimitAvoidanceWithMargins.
Eigen::VectorXf calculate(const Eigen::VectorXf &cartesianVel, VirtualRobot::IKSolver::CartesianSelection mode)
CartesianVelocityController(const VirtualRobot::RobotNodeSetPtr &rns, const VirtualRobot::RobotNodePtr &tcp=nullptr, const VirtualRobot::JacobiProvider::InverseJacobiMethod invJacMethod=VirtualRobot::JacobiProvider::eSVDDamped, bool _considerJointLimits=true)
void setCartesianRegularization(float cartesianMMRegularization, float cartesianRadianRegularization)
Eigen::VectorXf calculateNullspaceVelocity(const Eigen::VectorXf &cartesianVel, float KpScale, VirtualRobot::IKSolver::CartesianSelection mode)
static float ILerp(float a, float b, float f)
Definition MathUtils.h:197
static int LimitMinMax(int min, int max, int value)
Definition MathUtils.h:43
static float ILerpClamp(float a, float b, float f)
Definition MathUtils.h:203
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
This file offers overloads of toIce() and fromIce() functions for STL container types.
#define ARMARX_TRACE
Definition trace.h:77