Tesseract
Motion Planning Environment
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1
26#ifndef TESSERACT_KINEMATICS_UTILS_H
27#define TESSERACT_KINEMATICS_UTILS_H
28
31#include <vector>
32#include <Eigen/Core>
33#include <Eigen/Geometry>
34#include <Eigen/Eigenvalues>
35#include <console_bridge/console.h>
38
41
43{
44template <typename FloatType>
45using VectorX = Eigen::Matrix<FloatType, Eigen::Dynamic, 1>;
46
55inline static void numericalJacobian(Eigen::Ref<Eigen::MatrixXd> jacobian,
56 const Eigen::Isometry3d& change_base,
58 const Eigen::Ref<const Eigen::VectorXd>& joint_values,
59 const std::string& link_name,
60 const Eigen::Ref<const Eigen::Vector3d>& link_point)
61{
62 Eigen::VectorXd njvals;
63 double delta = 1e-8;
64 tesseract_common::TransformMap poses = kin.calcFwdKin(joint_values);
65 Eigen::Isometry3d pose{ change_base * poses[link_name] };
66
67 for (int i = 0; i < static_cast<int>(joint_values.size()); ++i)
68 {
69 njvals = joint_values;
70 njvals[i] += delta;
71 Eigen::Isometry3d updated_pose = kin.calcFwdKin(njvals)[link_name];
72 updated_pose = change_base * updated_pose;
73
74 Eigen::Vector3d temp{ pose * link_point };
75 Eigen::Vector3d temp2{ updated_pose * link_point };
76 jacobian(0, i) = (temp2.x() - temp.x()) / delta;
77 jacobian(1, i) = (temp2.y() - temp.y()) / delta;
78 jacobian(2, i) = (temp2.z() - temp.z()) / delta;
79
80 Eigen::Vector3d omega = (pose.rotation() * tesseract_common::calcRotationalError(pose.rotation().transpose() *
81 updated_pose.rotation())) /
82 delta;
83 jacobian(3, i) = omega(0);
84 jacobian(4, i) = omega(1);
85 jacobian(5, i) = omega(2);
86 }
87}
88
97inline static void numericalJacobian(Eigen::Ref<Eigen::MatrixXd> jacobian,
99 const Eigen::Ref<const Eigen::VectorXd>& joint_values,
100 const std::string& link_name,
101 const Eigen::Ref<const Eigen::Vector3d>& link_point)
102{
103 Eigen::VectorXd njvals;
104 double delta = 1e-8;
106 Eigen::Isometry3d pose = poses[link_name];
107
108 for (int i = 0; i < static_cast<int>(joint_values.size()); ++i)
109 {
110 njvals = joint_values;
111 njvals[i] += delta;
113 Eigen::Isometry3d updated_pose = updated_poses[link_name];
114
115 Eigen::Vector3d temp = pose * link_point;
116 Eigen::Vector3d temp2 = updated_pose * link_point;
117 jacobian(0, i) = (temp2.x() - temp.x()) / delta;
118 jacobian(1, i) = (temp2.y() - temp.y()) / delta;
119 jacobian(2, i) = (temp2.z() - temp.z()) / delta;
120
121 Eigen::VectorXd omega = (pose.rotation() * tesseract_common::calcRotationalError(pose.rotation().transpose() *
122 updated_pose.rotation())) /
123 delta;
124 jacobian(3, i) = omega(0);
125 jacobian(4, i) = omega(1);
126 jacobian(5, i) = omega(2);
127 }
128}
129
138inline static bool solvePInv(const Eigen::Ref<const Eigen::MatrixXd>& A,
139 const Eigen::Ref<const Eigen::VectorXd>& b,
140 Eigen::Ref<Eigen::VectorXd> x)
141{
142 const double eps = 0.00001; // TODO: Turn into class member var
143 const double lambda = 0.01; // TODO: Turn into class member var
144
145 if ((A.rows() == 0) || (A.cols() == 0))
146 {
147 CONSOLE_BRIDGE_logError("Empty matrices not supported in solvePinv()");
148 return false;
149 }
150
151 if (A.rows() != b.size())
152 {
153 CONSOLE_BRIDGE_logError("Matrix size mismatch: A(%d, %d), b(%d)", A.rows(), A.cols(), b.size());
154 return false;
155 }
156
157 // Calculate A+ (pseudoinverse of A) = V S+ U*, where U* is Hermition of U (just transpose if all values of U are
158 // real)
159 // in order to solve Ax=b -> x*=A+ b
160 Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
161 const Eigen::MatrixXd& U = svd.matrixU();
162 const Eigen::VectorXd& Sv = svd.singularValues();
163 const Eigen::MatrixXd& V = svd.matrixV();
164
165 // calculate the reciprocal of Singular-Values
166 // damp inverse with lambda so that inverse doesn't oscillate near solution
167 long int nSv = Sv.size();
168 Eigen::VectorXd inv_Sv(nSv);
169 for (long int i = 0; i < nSv; ++i)
170 {
171 if (fabs(Sv(i)) > eps)
172 inv_Sv(i) = 1 / Sv(i);
173 else
174 inv_Sv(i) = Sv(i) / (Sv(i) * Sv(i) + lambda * lambda);
175 }
176 x = V * inv_Sv.asDiagonal() * U.transpose() * b;
177 return true;
178}
179
189inline static bool dampedPInv(const Eigen::Ref<const Eigen::MatrixXd>& A,
190 Eigen::Ref<Eigen::MatrixXd> P,
191 const double eps = 0.011,
192 const double lambda = 0.01)
193{
194 if ((A.rows() == 0) || (A.cols() == 0))
195 {
196 CONSOLE_BRIDGE_logError("Empty matrices not supported in dampedPInv()");
197 return false;
198 }
199
200 // Calculate A+ (pseudoinverse of A) = V S+ U*, where U* is Hermition of U (just transpose if all values of U are
201 // real)
202 // in order to solve Ax=b -> x*=A+ b
203 Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
204 const Eigen::MatrixXd& U = svd.matrixU();
205 const Eigen::VectorXd& Sv = svd.singularValues();
206 const Eigen::MatrixXd& V = svd.matrixV();
207
208 // calculate the reciprocal of Singular-Values
209 // damp inverse with lambda so that inverse doesn't oscillate near solution
210 long int nSv = Sv.size();
211 Eigen::VectorXd inv_Sv(nSv);
212 for (long int i = 0; i < nSv; ++i)
213 {
214 if (fabs(Sv(i)) > eps)
215 inv_Sv(i) = 1 / Sv(i);
216 else
217 {
218 inv_Sv(i) = Sv(i) / (Sv(i) * Sv(i) + lambda * lambda);
219 }
220 }
221 P = V * inv_Sv.asDiagonal() * U.transpose();
222 return true;
223}
224
233inline bool isNearSingularity(const Eigen::Ref<const Eigen::MatrixXd>& jacobian, double threshold = 0.01)
234{
235 Eigen::JacobiSVD<Eigen::MatrixXd> svd(jacobian, Eigen::ComputeThinU | Eigen::ComputeThinV);
236 const Eigen::VectorXd& sv = svd.singularValues();
237 return (sv.tail(1).value() < threshold);
238}
239
242{
243 // LCOV_EXCL_START
244 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
245 // LCOV_EXCL_STOP
246
248 Eigen::VectorXd eigen_values;
249
257 double measure{ 0 };
258
264 double condition{ 0 };
265
267 double volume{ 0 };
268};
269
272{
273 // LCOV_EXCL_START
274 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
275 // LCOV_EXCL_STOP
276
279
282
285
288
291
294};
295
301inline Manipulability calcManipulability(const Eigen::Ref<const Eigen::MatrixXd>& jacobian)
302{
303 Manipulability manip;
304 Eigen::MatrixXd jacob_linear = jacobian.topRows(3);
305 Eigen::MatrixXd jacob_angular = jacobian.bottomRows(3);
306
307 auto fn = [](const Eigen::MatrixXd& m) {
309 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> sm(m, Eigen::DecompositionOptions::EigenvaluesOnly);
310 data.eigen_values = sm.eigenvalues().real();
311
312 // Set eigenvalues near zero to zero. This also implies zero volume
313 for (Eigen::Index i = 0; i < data.eigen_values.size(); ++i)
314 {
316 data.eigen_values[i] = +0;
317 }
318
319 // If the minimum eigen value is approximately zero set measure and condition to max double
320 if (tesseract_common::almostEqualRelativeAndAbs(data.eigen_values.minCoeff(), 0))
321 {
322 data.measure = std::numeric_limits<double>::max();
323 data.condition = std::numeric_limits<double>::max();
324 }
325 else
326 {
327 data.condition = data.eigen_values.maxCoeff() / data.eigen_values.minCoeff();
328 data.measure = std::sqrt(data.condition);
329 }
330
331 data.volume = std::sqrt(data.eigen_values.prod());
332
333 return data;
334 };
335
336 Eigen::MatrixXd a = jacobian * jacobian.transpose();
337 Eigen::MatrixXd a_linear = jacob_linear * jacob_linear.transpose();
338 Eigen::MatrixXd a_angular = jacob_angular * jacob_angular.transpose();
339 manip.m = fn(a);
340 manip.m_linear = fn(a_linear);
341 manip.m_angular = fn(a_angular);
342
343 Eigen::MatrixXd a_inv = a.inverse();
344 Eigen::MatrixXd a_linear_inv = a_linear.inverse();
345 Eigen::MatrixXd a_angular_inv = a_angular.inverse();
346 manip.f = fn(a_inv);
347 manip.f_linear = fn(a_linear_inv);
348 manip.f_angular = fn(a_angular_inv);
349
350 return manip;
351}
352
357template <typename FloatType>
358inline void getRedundantSolutionsHelper(std::vector<VectorX<FloatType>>& redundant_sols,
359 const Eigen::Ref<const Eigen::VectorXd>& sol,
360 const Eigen::MatrixX2d& limits,
361 std::vector<Eigen::Index>::const_iterator current_index,
362 std::vector<Eigen::Index>::const_iterator end_index)
363{
364 double val{ 0 };
365 for (; current_index != end_index; ++current_index)
366 {
367 if (std::isinf(limits(*current_index, 0)))
368 {
369 std::stringstream ss;
370 ss << "Lower limit of joint " << *current_index << " is infinite; no redundant solutions will be generated"
371 << std::endl;
372 CONSOLE_BRIDGE_logWarn(ss.str().c_str());
373 }
374 else
375 {
376 val = sol[*current_index];
377 while ((val -= (2.0 * M_PI)) > limits(*current_index, 0) ||
379 {
380 // It not guaranteed that the provided solution is within limits so this check is needed
381 if (val < limits(*current_index, 1) ||
383 {
384 Eigen::VectorXd new_sol = sol;
385 new_sol[*current_index] = val;
386
388 {
390 redundant_sols.push_back(new_sol.template cast<FloatType>());
391 }
392
393 getRedundantSolutionsHelper<FloatType>(redundant_sols, new_sol, limits, current_index + 1, end_index);
394 }
395 }
396 }
397
398 if (std::isinf(limits(*current_index, 1)))
399 {
400 std::stringstream ss;
401 ss << "Upper limit of joint " << *current_index << " is infinite; no redundant solutions will be generated"
402 << std::endl;
403 CONSOLE_BRIDGE_logWarn(ss.str().c_str());
404 }
405 else
406 {
407 val = sol[*current_index];
408 while ((val += (2.0 * M_PI)) < limits(*current_index, 1) ||
410 {
411 // It not guaranteed that the provided solution is within limits so this check is needed
412 if (val > limits(*current_index, 0) ||
414 {
415 Eigen::VectorXd new_sol = sol;
416 new_sol[*current_index] = val;
417
419 {
421 redundant_sols.push_back(new_sol.template cast<FloatType>());
422 }
423
424 getRedundantSolutionsHelper<FloatType>(redundant_sols, new_sol, limits, current_index + 1, end_index);
425 }
426 }
427 }
428 }
429}
430
438template <typename FloatType>
439inline std::vector<VectorX<FloatType>> getRedundantSolutions(const Eigen::Ref<const VectorX<FloatType>>& sol,
440 const Eigen::MatrixX2d& limits,
441 const std::vector<Eigen::Index>& redundancy_capable_joints)
442{
443 if (redundancy_capable_joints.empty())
444 return {};
445
446 for (const Eigen::Index& idx : redundancy_capable_joints)
447 {
448 if (idx >= sol.size())
449 {
450 std::stringstream ss;
451 ss << "Redundant joint index " << idx << " is greater than or equal to the joint state size (" << sol.size()
452 << ")";
453 throw std::runtime_error(ss.str());
454 }
455 }
456
457 std::vector<VectorX<FloatType>> redundant_sols;
458 getRedundantSolutionsHelper<FloatType>(redundant_sols,
459 sol.template cast<double>(),
460 limits,
461 redundancy_capable_joints.begin(),
462 redundancy_capable_joints.end());
463 return redundant_sols;
464}
465
475template <typename FloatType>
476inline bool isValid(const std::array<FloatType, 6>& qs)
477{
478 for (const auto& q : qs)
479 if (!std::isfinite(q))
480 return false;
481
482 return true;
483}
484
490template <typename FloatType>
491inline void harmonizeTowardZero(Eigen::Ref<VectorX<FloatType>> qs,
492 const std::vector<Eigen::Index>& redundancy_capable_joints)
493{
494 const static auto pi = FloatType(M_PI);
495 const static auto two_pi = FloatType(2.0 * M_PI);
496
497 for (const auto& i : redundancy_capable_joints)
498 {
499 FloatType diff = std::fmod(qs[i] + pi, two_pi);
500 qs[i] = (diff < 0) ? (diff + pi) : (diff - pi);
501 }
502}
503
504} // namespace tesseract_kinematics
505#endif // TESSERACT_KINEMATICS_UTILS_H
Forward kinematics functions.
Definition: forward_kinematics.h:47
A Joint Group is defined by a list of joint_names.
Definition: joint_group.h:43
tesseract_common::TransformMap calcFwdKin(const Eigen::Ref< const Eigen::VectorXd > &joint_angles) const
Calculates tool pose of robot chain.
Definition: joint_group.cpp:115
CollisionMarginData data(default_margin)
Definition: collision_margin_data_unit.cpp:34
tesseract_common::PluginInfo pi
Definition: contact_managers_factory_unit.cpp:227
Forward kinematics functions.
A basic scene graph using boost.
A kinematic group with forward and inverse kinematics methods.
tesseract_kinematics::Manipulability m
Definition: kinematics_core_unit.cpp:179
q[0]
Definition: kinematics_core_unit.cpp:15
Eigen::MatrixXd jacobian
Definition: kinematics_core_unit.cpp:153
auto kin
Definition: kinematics_factory_unit.cpp:1165
Common Tesseract Macros.
#define TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
Definition: macros.h:71
Definition: create_convex_hull.cpp:36
template void enforcePositionLimits< double >(Eigen::Ref< Eigen::Matrix< double, Eigen::Dynamic, 1 > > joint_positions, const Eigen::Ref< const Eigen::Matrix< double, Eigen::Dynamic, 2 > > &position_limits)
template bool satisfiesPositionLimits< double >(const Eigen::Ref< const Eigen::Matrix< double, Eigen::Dynamic, 1 > > &joint_positions, const Eigen::Ref< const Eigen::Matrix< double, Eigen::Dynamic, 2 > > &position_limits, double max_diff, double max_rel_diff)
AlignedMap< std::string, Eigen::Isometry3d > TransformMap
Definition: types.h:66
Eigen::Vector3d calcRotationalError(const Eigen::Ref< const Eigen::Matrix3d > &R)
Calculate the rotation error vector given a rotation error matrix where the angle is between [-pi,...
Definition: utils.cpp:124
bool almostEqualRelativeAndAbs(double a, double b, double max_diff=1e-6, double max_rel_diff=std::numeric_limits< double >::epsilon())
Check if two double are relatively equal.
Definition: utils.cpp:393
Definition: forward_kinematics.h:44
void getRedundantSolutionsHelper(std::vector< VectorX< FloatType > > &redundant_sols, const Eigen::Ref< const Eigen::VectorXd > &sol, const Eigen::MatrixX2d &limits, std::vector< Eigen::Index >::const_iterator current_index, std::vector< Eigen::Index >::const_iterator end_index)
This a recursive function for calculating all permutations of the redundant solutions.
Definition: utils.h:358
static bool dampedPInv(const Eigen::Ref< const Eigen::MatrixXd > &A, Eigen::Ref< Eigen::MatrixXd > P, const double eps=0.011, const double lambda=0.01)
Calculate Damped Pseudoinverse Use this SVD to compute A+ (pseudoinverse of A). Weighting still TBD.
Definition: utils.h:189
bool isValid(const std::array< FloatType, 6 > &qs)
Given a vector of floats, this check if they are finite.
Definition: utils.h:476
std::vector< VectorX< FloatType > > getRedundantSolutions(const Eigen::Ref< const VectorX< FloatType > > &sol, const Eigen::MatrixX2d &limits, const std::vector< Eigen::Index > &redundancy_capable_joints)
Kinematics only return solution between PI and -PI. Provided the limits it will append redundant solu...
Definition: utils.h:439
static void numericalJacobian(Eigen::Ref< Eigen::MatrixXd > jacobian, const Eigen::Isometry3d &change_base, const tesseract_kinematics::ForwardKinematics &kin, const Eigen::Ref< const Eigen::VectorXd > &joint_values, const std::string &link_name, const Eigen::Ref< const Eigen::Vector3d > &link_point)
Numerically calculate a jacobian. This is mainly used for testing.
Definition: utils.h:55
void harmonizeTowardZero(Eigen::Ref< VectorX< FloatType > > qs, const std::vector< Eigen::Index > &redundancy_capable_joints)
This take an array of floats and modifies them in place to be between [-PI, PI].
Definition: utils.h:491
Eigen::Matrix< FloatType, Eigen::Dynamic, 1 > VectorX
Definition: utils.h:45
static bool solvePInv(const Eigen::Ref< const Eigen::MatrixXd > &A, const Eigen::Ref< const Eigen::VectorXd > &b, Eigen::Ref< Eigen::VectorXd > x)
Solve equation Ax=b for x Use this SVD to compute A+ (pseudoinverse of A). Weighting still TBD.
Definition: utils.h:138
Manipulability calcManipulability(const Eigen::Ref< const Eigen::MatrixXd > &jacobian)
Calculate manipulability data about the provided jacobian.
Definition: utils.h:301
bool isNearSingularity(const Eigen::Ref< const Eigen::MatrixXd > &jacobian, double threshold=0.01)
Check if the provided jacobian is near a singularity.
Definition: utils.h:233
Used to store Manipulability and Force Ellipsoid data.
Definition: utils.h:242
double volume
This is propotial to the volume.
Definition: utils.h:267
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Eigen::VectorXd eigen_values
The manipulability ellipsoid eigen values.
Definition: utils.h:248
double condition
The condition number of A.
Definition: utils.h:264
double measure
The ratio of longest and shortes axes of the manipulability ellipsoid.
Definition: utils.h:257
Contains both manipulability ellipsoid and force ellipsoid data.
Definition: utils.h:272
EIGEN_MAKE_ALIGNED_OPERATOR_NEW ManipulabilityEllipsoid m
Full Manipulability Ellipsoid.
Definition: utils.h:278
ManipulabilityEllipsoid f
Full Force Ellipsoid.
Definition: utils.h:287
ManipulabilityEllipsoid f_linear
Linear force manipulability ellipsoid.
Definition: utils.h:290
ManipulabilityEllipsoid f_angular
Angular momentum manipulability ellipsoid.
Definition: utils.h:293
ManipulabilityEllipsoid m_angular
Angular velocity manipulability ellipsoid.
Definition: utils.h:284
ManipulabilityEllipsoid m_linear
Linear velocity manipulability ellipsoid.
Definition: utils.h:281
auto pose
Definition: tesseract_environment_collision.cpp:118
joint_1 limits
Definition: tesseract_scene_graph_joint_unit.cpp:153
JointGroup joint_group
Definition: tesseract_srdf_unit.cpp:1805