polynomial.cpp
Go to the documentation of this file.
00001 
00027 #include <stomp_moveit/utils/polynomial.h>
00028 #include <ros/console.h>
00029 
00033 namespace stomp_moveit
00034 {
00035 
00039 namespace utils
00040 {
00041 
00045 namespace polynomial
00046 {
00047 
00048 
00049 PolyFitResults polyFit(const PolyFitRequest &request)
00050 {
00051 
00052 // Unconstrained Least Squares
00053 // |p|=|A*A'|^-1 * |A*y|
00054 //
00055 // Constrained Least Squares
00056 //  |p| - | 2*A*A', C |^-1 * | 2*A*b |
00057 //  |z| - |     C', 0 |      |     d |
00058 //
00059 //  Variable Description:
00060 //    x_t         (A) - Is the Vandermonde matrix of all (constrained and unconstrained) domain values
00061 //    a_t         (C) - Is the Vandermonde matrix of the constrained domain values
00062 //    y           (b) - An array of the values to perform the fit on
00063 //    yf          (d) - An array of the values corresponding to the constrained domain values
00064 //    poly_params (p) - An array of the polynomial coefficients solved for.
00065 
00066   PolyFitResults result;
00067 
00068   int num_r = request.d + 1;
00069   Eigen::MatrixXd x_t(num_r, request.xy.cols());
00070   if (!request.hasConstraints())
00071   {
00072     for (auto r = 0; r < num_r; r++)
00073       x_t.row(r) = request.xy.row(0).array().pow(r);
00074 
00075     Eigen::MatrixXd mat = x_t * x_t.transpose();
00076     Eigen::VectorXd vec = x_t * request.xy.row(1);
00077 
00078     result.p = mat.lu().solve(vec).head(num_r);
00079   }
00080   else
00081   {
00082     int num_constraints = request.xyfp.cols() + request.xyfs.cols();
00083 
00084     Eigen::MatrixXd a_t(num_r, num_constraints);
00085     Eigen::MatrixXd a_tp(num_r, request.xyfp.cols());
00086     Eigen::MatrixXd a_ts(num_r, request.xyfs.cols());
00087 
00088     for (auto r = 0; r < num_r; r++)
00089     {
00090       x_t.row(r) = request.xy.row(0).array().pow(r);
00091 
00092       if (request.hasPositionConstraints())
00093         a_tp.row(r) = request.xyfp.row(0).array().pow(r);
00094 
00095       if (request.hasSlopeConstraints())
00096         if (r == 0)
00097           a_ts.row(r) = request.xyfs.row(0).array() * 0.0;
00098         else
00099           a_ts.row(r) = request.xyfs.row(0).array().pow(r - 1) / r;
00100 
00101     }
00102 
00103     Eigen::MatrixXd top(num_r, num_r + num_constraints);
00104     Eigen::MatrixXd bot(num_constraints, num_r + num_constraints);
00105     Eigen::MatrixXd mat(num_r + num_constraints, num_r + num_constraints);
00106     Eigen::VectorXd vec(num_r + num_constraints);
00107 
00108     if (request.hasPositionConstraints() && request.hasSlopeConstraints())
00109     {
00110       a_t << a_tp, a_ts;
00111       vec << 2*x_t*request.xy.row(1).transpose(), request.xyfp.row(1).transpose(), request.xyfs.row(1).transpose();
00112     }
00113     else if (request.hasPositionConstraints())
00114     {
00115       a_t << a_tp;
00116       vec << 2*x_t*request.xy.row(1).transpose(), request.xyfp.row(1).transpose();
00117     }
00118     else if (request.hasSlopeConstraints())
00119     {
00120       a_t << a_ts;
00121       vec << 2*x_t*request.xy.row(1).transpose(), request.xyfs.row(1).transpose();
00122     }
00123 
00124     top << 2*x_t*x_t.transpose(), a_t;
00125     bot << a_t.transpose(), Eigen::MatrixXd::Zero(num_constraints, num_constraints);
00126     mat << top,
00127            bot;
00128 
00129     result.p = mat.lu().solve(vec).head(num_r);
00130   }
00131 
00132   if (request.output_domain.size() == 0)
00133   {
00134     result.x = request.xy.row(0);
00135     result.y = x_t.transpose() * result.p;
00136     result.successful = true;
00137     return result;
00138   }
00139   else
00140   {
00141     result.x = request.output_domain;
00142     fillVandermondeMatrix(result.x, request.d, x_t);
00143     result.y = x_t.transpose() * result.p;
00144     result.successful = true;
00145     return result;
00146   }
00147 }
00148 
00149 void fillVandermondeMatrix(const Eigen::ArrayXd &domain_vals, const int &order, Eigen::MatrixXd &v)
00150 {
00151   v = Eigen::MatrixXd::Ones(order+1, domain_vals.size());
00152   for(auto p = 1u; p <=  order; p++)
00153     v.row(p) = domain_vals.pow(p);
00154 }
00155 
00156 void generateMinimumDomainValues(const std::vector<const  moveit::core::JointModel *> joint_models,
00157                                  const Eigen::MatrixXd &parameters,Eigen::VectorXd &domain_values)
00158 {
00159   Eigen::VectorXd distance(parameters.rows());
00160   Eigen::VectorXd velocity(parameters.rows());
00161   Eigen::VectorXd t(parameters.rows());
00162   Eigen::VectorXd domain_dist(parameters.cols());
00163   double max_t = 0;
00164 
00165   domain_values.resize(parameters.cols());
00166   for(auto r = 0; r < parameters.rows(); r++)
00167   {
00168     moveit::core::VariableBounds bound = joint_models[r]->getVariableBounds()[0];
00169     velocity(r) = bound.max_velocity_;
00170     distance(r) = 0.0;
00171     domain_dist(0) = 0.0;
00172     for(auto c = 1; c < parameters.cols(); c++)
00173     {
00174       distance(r) += std::abs((parameters(r, c)) - (parameters(r, c - 1)));
00175       domain_dist(c) = distance(r);
00176     }
00177 
00178     t(r) = distance(r)/velocity(r);
00179     if (t(r) > max_t)
00180     {
00181       max_t = t(r);
00182       domain_values = domain_dist/velocity(r);
00183     }
00184   }
00185 }
00186 
00187 bool applyPolynomialSmoothing(moveit::core::RobotModelConstPtr robot_model, const std::string& group_name, Eigen::MatrixXd& parameters,
00188                               int poly_order, double joint_limit_margin)
00189 {
00190   using namespace Eigen;
00191   using namespace moveit::core;
00192 
00193   const std::vector<const JointModel*> &joint_models = robot_model->getJointModelGroup(group_name)->getActiveJointModels();
00194   PolyFitRequest request;
00195   int num_timesteps = parameters.cols();
00196 
00197   VectorXd domain_vals;
00198   domain_vals.setLinSpaced(num_timesteps,0,1);
00199 
00200   request.d = poly_order;
00201   request.xy.resize(2, num_timesteps);
00202   request.xy.row(0) = domain_vals;
00203   for(auto r = 0; r < parameters.rows(); r++)
00204   {
00205     request.xy.row(1) = parameters.row(r);
00206     request.xyfp.resize(2, 2);
00207     request.xyfp(0, 0) = request.xy(0, 0);
00208     request.xyfp(1, 0) = request.xy(1, 0);
00209     request.xyfp(0, 1) = request.xy(0, num_timesteps - 1);
00210     request.xyfp(1, 1) = request.xy(1, num_timesteps - 1);
00211 
00212     PolyFitResults results;
00213     results = polyFit(request);
00214     for(auto i = 0; i < results.y.size(); ++i)
00215       joint_models[r]->enforcePositionBounds(&results.y[i]);
00216 
00217     //  Now check if joint trajectory is within joint limits
00218     bool finished;
00219     double min = results.y.minCoeff();
00220     double max = results.y.maxCoeff();
00221     finished = joint_models[r]->satisfiesPositionBounds(&min, joint_limit_margin) &&
00222                joint_models[r]->satisfiesPositionBounds(&max, joint_limit_margin);
00223 
00224     if ((results.p.array() != results.p.array()).any())
00225     {
00226       ROS_ERROR("Smoother, joint %s polynomial fit failed!", joint_models[r]->getName().c_str());
00227       return false;
00228     }
00229 
00230     if(!finished)
00231     {
00232       ROS_ERROR("Smoother, joint %s not within limits, Min: %f, Max: %f", joint_models[r]->getName().c_str(), min, max);
00233       return false;
00234     }
00235 
00236     parameters.row(r) = results.y;
00237   }
00238 
00239   return true;
00240 }
00241 
00242 } // end of namespace smoothing
00243 } // end of namespace utils
00244 } // end of namespace stomp_moveit
00245 
00246 
00247 
00248 


stomp_moveit
Author(s): Jorge Nicho
autogenerated on Sat Jun 8 2019 19:24:01