moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
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>
45
46namespace kinematics_metrics
47{
48namespace
49{
50rclcpp::Logger getLogger()
51{
52 return moveit::getLogger("moveit.core.kinematics_metrics");
53}
54} // namespace
55
56double 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
105bool 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
180bool 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
214bool 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....
std::vector< VariableBounds > Bounds
The datatype for the joint bounds.
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
Namespace for kinematics metrics.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:79