moveit2
The MoveIt Motion Planning Framework for ROS 2.
kinematics_metrics.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Sachin Chitta */
36 
37 #include <Eigen/Dense>
38 #include <Eigen/Eigenvalues>
39 #include <limits>
40 #include <math.h>
42 #include <rclcpp/logger.hpp>
43 #include <rclcpp/logging.hpp>
44 #include <moveit/utils/logger.hpp>
45 
46 namespace kinematics_metrics
47 {
48 namespace
49 {
50 rclcpp::Logger getLogger()
51 {
52  return moveit::getLogger("moveit.core.kinematics_metrics");
53 }
54 } // namespace
55 
56 double KinematicsMetrics::getJointLimitsPenalty(const moveit::core::RobotState& state,
57  const moveit::core::JointModelGroup* joint_model_group) const
58 {
59  if (fabs(penalty_multiplier_) <= std::numeric_limits<double>::min())
60  return 1.0;
61  double joint_limits_multiplier(1.0);
62  const std::vector<const moveit::core::JointModel*>& joint_model_vector = joint_model_group->getJointModels();
63  for (const moveit::core::JointModel* joint_model : joint_model_vector)
64  {
65  if (joint_model->getType() == moveit::core::JointModel::REVOLUTE)
66  {
67  const moveit::core::RevoluteJointModel* revolute_model =
68  static_cast<const moveit::core::RevoluteJointModel*>(joint_model);
69  if (revolute_model->isContinuous())
70  continue;
71  }
72  if (joint_model->getType() == moveit::core::JointModel::PLANAR)
73  {
74  const moveit::core::JointModel::Bounds& bounds = joint_model->getVariableBounds();
75  if (bounds[0].min_position_ == -std::numeric_limits<double>::max() ||
76  bounds[0].max_position_ == std::numeric_limits<double>::max() ||
77  bounds[1].min_position_ == -std::numeric_limits<double>::max() ||
78  bounds[1].max_position_ == std::numeric_limits<double>::max() || bounds[2].min_position_ == -M_PI ||
79  bounds[2].max_position_ == M_PI)
80  continue;
81  }
82  if (joint_model->getType() == moveit::core::JointModel::FLOATING)
83  {
84  // Joint limits are not well-defined for floating joints
85  continue;
86  }
87  const double* joint_values = state.getJointPositions(joint_model);
88  const moveit::core::JointModel::Bounds& bounds = joint_model->getVariableBounds();
89  std::vector<double> lower_bounds, upper_bounds;
90  for (const moveit::core::VariableBounds& bound : bounds)
91  {
92  lower_bounds.push_back(bound.min_position_);
93  upper_bounds.push_back(bound.max_position_);
94  }
95  double lower_bound_distance = joint_model->distance(joint_values, &lower_bounds[0]);
96  double upper_bound_distance = joint_model->distance(joint_values, &upper_bounds[0]);
97  double range = lower_bound_distance + upper_bound_distance;
98  if (range <= std::numeric_limits<double>::min())
99  continue;
100  joint_limits_multiplier *= (lower_bound_distance * upper_bound_distance / (range * range));
101  }
102  return (1.0 - exp(-penalty_multiplier_ * joint_limits_multiplier));
103 }
104 
105 bool KinematicsMetrics::getManipulabilityIndex(const moveit::core::RobotState& state, const std::string& group_name,
106  double& manipulability_index, bool translation) const
107 {
108  const moveit::core::JointModelGroup* joint_model_group = robot_model_->getJointModelGroup(group_name);
109  if (joint_model_group)
110  {
111  return getManipulabilityIndex(state, joint_model_group, manipulability_index, translation);
112  }
113  else
114  {
115  return false;
116  }
117 }
118 
120  const moveit::core::JointModelGroup* joint_model_group,
121  double& manipulability_index, bool translation) const
122 {
123  // state.getJacobian() only works for chain groups.
124  if (!joint_model_group->isChain())
125  {
126  return false;
127  }
128 
129  Eigen::MatrixXd jacobian = state.getJacobian(joint_model_group);
130  // Get joint limits penalty
131  double penalty = getJointLimitsPenalty(state, joint_model_group);
132  if (translation)
133  {
134  if (jacobian.cols() < 6)
135  {
136  Eigen::JacobiSVD<Eigen::MatrixXd> svdsolver(jacobian.topLeftCorner(3, jacobian.cols()));
137  Eigen::MatrixXd singular_values = svdsolver.singularValues();
138  manipulability_index = 1.0;
139  for (unsigned int i = 0; i < singular_values.rows(); ++i)
140  {
141  RCLCPP_DEBUG(getLogger(), "Singular value: %d %f", i, singular_values(i, 0));
142  manipulability_index *= singular_values(i, 0);
143  }
144  // Get manipulability index
145  manipulability_index = penalty * manipulability_index;
146  }
147  else
148  {
149  Eigen::MatrixXd jacobian_2 = jacobian.topLeftCorner(3, jacobian.cols());
150  Eigen::MatrixXd matrix = jacobian_2 * jacobian_2.transpose();
151  // Get manipulability index
152  manipulability_index = penalty * sqrt(matrix.determinant());
153  }
154  }
155  else
156  {
157  if (jacobian.cols() < 6)
158  {
159  Eigen::JacobiSVD<Eigen::MatrixXd> svdsolver(jacobian);
160  Eigen::MatrixXd singular_values = svdsolver.singularValues();
161  manipulability_index = 1.0;
162  for (unsigned int i = 0; i < singular_values.rows(); ++i)
163  {
164  RCLCPP_DEBUG(getLogger(), "Singular value: %d %f", i, singular_values(i, 0));
165  manipulability_index *= singular_values(i, 0);
166  }
167  // Get manipulability index
168  manipulability_index = penalty * manipulability_index;
169  }
170  else
171  {
172  Eigen::MatrixXd matrix = jacobian * jacobian.transpose();
173  // Get manipulability index
174  manipulability_index = penalty * sqrt(matrix.determinant());
175  }
176  }
177  return true;
178 }
179 
180 bool KinematicsMetrics::getManipulabilityEllipsoid(const moveit::core::RobotState& state, const std::string& group_name,
181  Eigen::MatrixXcd& eigen_values,
182  Eigen::MatrixXcd& eigen_vectors) const
183 {
184  const moveit::core::JointModelGroup* joint_model_group = robot_model_->getJointModelGroup(group_name);
185  if (joint_model_group)
186  {
187  return getManipulabilityEllipsoid(state, joint_model_group, eigen_values, eigen_vectors);
188  }
189  else
190  {
191  return false;
192  }
193 }
194 
196  const moveit::core::JointModelGroup* joint_model_group,
197  Eigen::MatrixXcd& eigen_values,
198  Eigen::MatrixXcd& eigen_vectors) const
199 {
200  // state.getJacobian() only works for chain groups.
201  if (!joint_model_group->isChain())
202  {
203  return false;
204  }
205 
206  Eigen::MatrixXd jacobian = state.getJacobian(joint_model_group);
207  Eigen::MatrixXd matrix = jacobian * jacobian.transpose();
208  Eigen::EigenSolver<Eigen::MatrixXd> eigensolver(matrix.block(0, 0, 3, 3));
209  eigen_values = eigensolver.eigenvalues();
210  eigen_vectors = eigensolver.eigenvectors();
211  return true;
212 }
213 
214 bool KinematicsMetrics::getManipulability(const moveit::core::RobotState& state, const std::string& group_name,
215  double& manipulability, bool translation) const
216 {
217  const moveit::core::JointModelGroup* joint_model_group = robot_model_->getJointModelGroup(group_name);
218  if (joint_model_group)
219  {
220  return getManipulability(state, joint_model_group, manipulability, translation);
221  }
222  else
223  {
224  return false;
225  }
226 }
227 
229  const moveit::core::JointModelGroup* joint_model_group,
230  double& manipulability, bool translation) const
231 {
232  // state.getJacobian() only works for chain groups.
233  if (!joint_model_group->isChain())
234  {
235  return false;
236  }
237  // Get joint limits penalty
238  double penalty = getJointLimitsPenalty(state, joint_model_group);
239  if (translation)
240  {
241  Eigen::MatrixXd jacobian = state.getJacobian(joint_model_group);
242  Eigen::JacobiSVD<Eigen::MatrixXd> svdsolver(jacobian.topLeftCorner(3, jacobian.cols()));
243  Eigen::MatrixXd singular_values = svdsolver.singularValues();
244  for (int i = 0; i < singular_values.rows(); ++i)
245  {
246  RCLCPP_DEBUG(getLogger(), "Singular value: %d %f", i, singular_values(i, 0));
247  }
248 
249  manipulability = penalty * singular_values.minCoeff() / singular_values.maxCoeff();
250  }
251  else
252  {
253  Eigen::MatrixXd jacobian = state.getJacobian(joint_model_group);
254  Eigen::JacobiSVD<Eigen::MatrixXd> svdsolver(jacobian);
255  Eigen::MatrixXd singular_values = svdsolver.singularValues();
256  for (int i = 0; i < singular_values.rows(); ++i)
257  {
258  RCLCPP_DEBUG(getLogger(), "Singular value: %d %f", i, singular_values(i, 0));
259  }
260  manipulability = penalty * singular_values.minCoeff() / singular_values.maxCoeff();
261  }
262  return true;
263 }
264 
265 } // end of namespace kinematics_metrics
bool getManipulability(const moveit::core::RobotState &state, const std::string &group_name, double &condition_number, bool translation=false) const
Get the manipulability = sigma_min/sigma_max where sigma_min and sigma_max are the smallest and large...
bool getManipulabilityIndex(const moveit::core::RobotState &state, const std::string &group_name, double &manipulability_index, bool translation=false) const
Get the manipulability for a given group at a given joint configuration.
moveit::core::RobotModelConstPtr robot_model_
bool getManipulabilityEllipsoid(const moveit::core::RobotState &state, const std::string &group_name, Eigen::MatrixXcd &eigen_values, Eigen::MatrixXcd &eigen_vectors) const
Get the (translation) manipulability ellipsoid for a given group at a given joint configuration.
bool isChain() const
Check if this group is a linear chain.
const std::vector< const JointModel * > & getJointModels() const
Get all the joints in this group (including fixed and mimic joints).
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
Definition: joint_model.h:117
std::vector< VariableBounds > Bounds
The datatype for the joint bounds.
Definition: joint_model.h:131
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a variable. Throw an exception if the variable was not found.
bool isContinuous() const
Check if this joint wraps around.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
bool getJacobian(const JointModelGroup *group, const LinkModel *link, const Eigen::Vector3d &reference_point_position, Eigen::MatrixXd &jacobian, bool use_quaternion_representation=false) const
Compute the Jacobian with reference to a particular point on a given link, for a specified group.
const double * getJointPositions(const std::string &joint_name) const
Definition: robot_state.h:543
Namespace for kinematics metrics.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition: logger.cpp:79