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