parabolic_blend_shortcutter.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00037 #ifndef PARABOLIC_BLEND_SHORT_CUTTER_H_
00038 #define PARABOLIC_BLEND_SHORT_CUTTER_H_
00039 
00040 #include <ros/ros.h>
00041 #include <tf/tf.h>
00042 #include <spline_smoother/spline_smoother.h>
00043 #include <spline_smoother/cubic_trajectory.h>
00044 #include <planning_environment/models/collision_models_interface.h>
00045 #include <planning_environment/models/model_utils.h>
00046 #include <arm_navigation_msgs/RobotState.h>
00047 #include <arm_navigation_msgs/ArmNavigationErrorCodes.h>
00048 #include <arm_navigation_msgs/LinkPadding.h>
00049 
00050 #include <trajectory_msgs/JointTrajectoryPoint.h>
00051 
00052 #include <constraint_aware_spline_smoother/ParabolicPathSmooth/Math.h>
00053 #include <constraint_aware_spline_smoother/ParabolicPathSmooth/DynamicPath.h>
00054 
00055 
00056 using namespace ParabolicRamp;
00057 
00058 namespace constraint_aware_spline_smoother
00059 {
00060 static const double MIN_DELTA = 0.01;
00061 static const double DEFAULT_VEL_MAX = 1000.0;
00062 static const double DEFAULT_ACC_MAX = 1000.0;
00063 static const double DEFAULT_POS_MAX = 1000.0;
00064 static const double DEFAULT_POS_MIN = -1000.0;
00065 
00066 class FeasibilityChecker : public FeasibilityCheckerBase
00067 {
00068 public: 
00069   FeasibilityChecker();
00070   virtual bool ConfigFeasible(const ParabolicRamp::Vector& x);
00071   virtual bool SegmentFeasible(const Vector& a,const Vector& b);
00072   bool setInitial(const trajectory_msgs::JointTrajectory &trajectory,
00073                   const std::string& group_name, 
00074                   const arm_navigation_msgs::RobotState& start_state, 
00075                   const arm_navigation_msgs::Constraints &path_constraints);
00076   void resetRequest();
00077   bool isActive();
00078   void initialize();
00079 private:
00080   std::vector<std::string> joint_names_;
00081   bool active_;
00082   double discretization_;
00083   ros::NodeHandle node_handle_;
00084   bool setupCollisionEnvironment();
00085   planning_environment::CollisionModelsInterface *collision_models_interface_;
00086   void discretizeTrajectory(const trajectory_msgs::JointTrajectory &trajectory, 
00087                             trajectory_msgs::JointTrajectory &trajectory_out);
00088   arm_navigation_msgs::Constraints path_constraints_;
00089 };
00090 
00091 FeasibilityChecker::FeasibilityChecker() : FeasibilityCheckerBase(), node_handle_("~")
00092 {
00093   initialize();
00094 }
00095 
00096 bool FeasibilityChecker::isActive()
00097 {
00098   return active_;
00099 }
00100 
00101 void FeasibilityChecker::initialize()
00102 {
00103   if(!setupCollisionEnvironment())
00104   {
00105     ROS_ERROR("Could not setup collision environment");
00106     active_ = false;
00107   }
00108   else
00109   {
00110     ROS_INFO("Setup collision environment");
00111     active_ = true;
00112   }
00113 }
00114 
00115 bool FeasibilityChecker::setInitial(const trajectory_msgs::JointTrajectory &trajectory,
00116                                     const std::string& group_name, 
00117                                     const arm_navigation_msgs::RobotState &start_state,
00118                                     const arm_navigation_msgs::Constraints &path_constraints)
00119 {
00120   std::vector<std::string> child_links;
00121   arm_navigation_msgs::ArmNavigationErrorCodes error_code;
00122   arm_navigation_msgs::OrderedCollisionOperations operations;
00123 
00124   joint_names_ = trajectory.joint_names;
00125 
00126   if(!collision_models_interface_->isPlanningSceneSet()) {
00127     ROS_INFO("Planning scene not set, can't do anything");
00128     return false;
00129   }
00130 
00131   collision_models_interface_->disableCollisionsForNonUpdatedLinks(group_name);
00132   
00133   planning_environment::setRobotStateAndComputeTransforms(start_state,
00134                                                          *collision_models_interface_->getPlanningSceneState());
00135 
00136   path_constraints_ = path_constraints;
00137 
00138   return true;
00139 }
00140 
00141 void FeasibilityChecker::resetRequest()
00142 {
00143 }
00144 
00145 bool FeasibilityChecker::setupCollisionEnvironment()
00146 {
00147   bool use_collision_map;
00148   node_handle_.param<bool>("use_collision_map", use_collision_map, true);
00149   
00150   // monitor robot
00151   collision_models_interface_ = new planning_environment::CollisionModelsInterface("robot_description");
00152 
00153   return true;
00154 }
00155 
00156 void FeasibilityChecker::discretizeTrajectory(const trajectory_msgs::JointTrajectory &trajectory, 
00157                                               trajectory_msgs::JointTrajectory &trajectory_out)
00158 {    
00159   trajectory_out.joint_names = trajectory.joint_names;
00160   for(unsigned int i=1; i < trajectory.points.size(); i++)
00161   {
00162     double diff = 0.0;      
00163     for(unsigned int j=0; j < trajectory.points[i].positions.size(); j++)
00164     {
00165       double start = trajectory.points[i-1].positions[j];
00166       double end   = trajectory.points[i].positions[j];
00167       if(fabs(end-start) > diff)
00168         diff = fabs(end-start);        
00169     }
00170     int num_intervals =(int) (diff/MIN_DELTA+1.0);
00171       
00172     for(unsigned int k=0; k < (unsigned int) num_intervals; k++)
00173     {
00174       trajectory_msgs::JointTrajectoryPoint point;
00175       for(unsigned int j=0; j < trajectory.points[i].positions.size(); j++)
00176       {
00177         double start = trajectory.points[i-1].positions[j];
00178         double end   = trajectory.points[i].positions[j];
00179         point.positions.push_back(start + (end-start)*k/num_intervals);
00180       }
00181       point.time_from_start = ros::Duration(trajectory.points[i].time_from_start.toSec() + k* (trajectory.points[i].time_from_start - trajectory.points[i-1].time_from_start).toSec()/num_intervals);
00182       trajectory_out.points.push_back(point);
00183     }
00184   }
00185   trajectory_out.points.push_back(trajectory.points.back());
00186 }
00187 
00188 bool FeasibilityChecker::ConfigFeasible(const Vector& x)
00189 {
00190   arm_navigation_msgs::ArmNavigationErrorCodes error_code;
00191   std::vector<arm_navigation_msgs::ArmNavigationErrorCodes> trajectory_error_codes;
00192 
00193   trajectory_msgs::JointTrajectory joint_traj;
00194   joint_traj.joint_names = joint_names_;
00195   joint_traj.header.stamp = ros::Time::now();
00196   joint_traj.points.resize(1);
00197   joint_traj.points[0].positions = x;
00198 
00199   arm_navigation_msgs::Constraints empty_goal_constraints;
00200   
00201   return(collision_models_interface_->isJointTrajectoryValid(*collision_models_interface_->getPlanningSceneState(),
00202                                                              joint_traj,
00203                                                              empty_goal_constraints,
00204                                                              path_constraints_,
00205                                                              error_code,
00206                                                              trajectory_error_codes,
00207                                                              false));
00208 }
00209 
00210 bool FeasibilityChecker::SegmentFeasible(const Vector& a,const Vector& b)
00211 {
00212   arm_navigation_msgs::ArmNavigationErrorCodes error_code;
00213   std::vector<arm_navigation_msgs::ArmNavigationErrorCodes> trajectory_error_codes;
00214  
00215   trajectory_msgs::JointTrajectory joint_traj_in, joint_traj;
00216   joint_traj_in.joint_names = joint_names_;
00217   joint_traj.header.stamp = ros::Time::now();
00218   joint_traj_in.points.resize(2);
00219   joint_traj_in.points[0].positions = a;
00220   joint_traj_in.points[1].positions = b;
00221   joint_traj.joint_names = joint_traj_in.joint_names;
00222   discretizeTrajectory(joint_traj_in,joint_traj);
00223 
00224   arm_navigation_msgs::Constraints empty_goal_constraints;
00225   return(collision_models_interface_->isJointTrajectoryValid(*collision_models_interface_->getPlanningSceneState(),
00226                                                              joint_traj,
00227                                                              empty_goal_constraints,
00228                                                              path_constraints_,
00229                                                              error_code,
00230                                                              trajectory_error_codes,
00231                                                              false));
00232 }
00233 
00237 template <typename T>
00238 class ParabolicBlendShortCutter: public spline_smoother::SplineSmoother<T>
00239 {
00240 public:
00244   ParabolicBlendShortCutter();
00245   virtual ~ParabolicBlendShortCutter();
00246   virtual bool smooth(const T& trajectory_in, 
00247                       T& trajectory_out) const;
00250   virtual bool configure();
00251 private:
00252   int num_iterations_;
00253   double discretization_;
00254   bool active_;
00255   boost::shared_ptr<FeasibilityChecker> feasibility_checker_;
00256 };
00257 
00258 template <typename T>
00259 bool ParabolicBlendShortCutter<T>::configure()
00260 {
00261   if (!spline_smoother::SplineSmoother<T>::getParam("discretization", discretization_))
00262   {
00263     ROS_ERROR("Spline smoother, \"%s\", params has no attribute discretization.", spline_smoother::SplineSmoother<T>::getName().c_str());
00264     return false;
00265   }
00266   if (!spline_smoother::SplineSmoother<T>::getParam("num_iterations", num_iterations_))
00267   {
00268     ROS_ERROR("Spline smoother, \"%s\", params has no attribute num_iterations.", spline_smoother::SplineSmoother<T>::getName().c_str());
00269     return false;
00270   }
00271   ROS_INFO("Configuring parabolic blend short cutter");
00272   ROS_INFO("Using a discretization value of %f",discretization_);
00273   ROS_INFO("Using num_iterations value of %d",(int)num_iterations_);
00274   feasibility_checker_.reset(new constraint_aware_spline_smoother::FeasibilityChecker());
00275   return true;
00276 };
00277 
00278 template <typename T>
00279 ParabolicBlendShortCutter<T>::ParabolicBlendShortCutter()
00280 {
00281   ROS_INFO("Setting up parabolic blend short cutter");
00282 }
00283 
00284 template <typename T>
00285 ParabolicBlendShortCutter<T>::~ParabolicBlendShortCutter()
00286 {
00287 }
00288 
00289 template <typename T>
00290 bool ParabolicBlendShortCutter<T>::smooth(const T& trajectory_in, 
00291                                           T& trajectory_out) const
00292 {
00293   srand(time(NULL)); // initialize random seed: 
00294   if(!feasibility_checker_->isActive())
00295   {
00296     ROS_ERROR("Smoother is not active");
00297     return false;
00298   }
00299   
00300   feasibility_checker_->setInitial(trajectory_in.request.trajectory,
00301                                    trajectory_in.request.group_name,
00302                                    trajectory_in.request.start_state,
00303                                    trajectory_in.request.path_constraints);
00304   std::vector<Vector> path;        //the sequence of milestones
00305   Vector vmax,amax;           //velocity and acceleration bounds, respectively
00306   Vector pmin,pmax;           //joint position bounds
00307   Real tol=1e-4;              //if a point is feasible, any point within tol is considered acceptable
00308   //TODO: compute milestones, velocity and acceleration bounds
00309 
00310   vmax.resize(trajectory_in.request.limits.size());
00311   amax.resize(trajectory_in.request.limits.size());
00312   pmin.resize(trajectory_in.request.limits.size());
00313   pmax.resize(trajectory_in.request.limits.size());
00314 
00315   for(unsigned int i=0; i < trajectory_in.request.limits.size(); i++)
00316   {
00317     if( trajectory_in.request.limits[i].has_velocity_limits )
00318     {
00319       vmax[i] = trajectory_in.request.limits[i].max_velocity;
00320     }
00321     else
00322     {
00323       vmax[i] = DEFAULT_VEL_MAX;
00324     }
00325 
00326     if( trajectory_in.request.limits[i].has_acceleration_limits )
00327     {
00328       amax[i] = trajectory_in.request.limits[i].max_acceleration;
00329     }
00330     else
00331     {
00332       amax[i] = DEFAULT_ACC_MAX;
00333     }
00334 
00335     if( trajectory_in.request.limits[i].has_position_limits )
00336     {
00337       pmin[i] = trajectory_in.request.limits[i].min_position;
00338       pmax[i] = trajectory_in.request.limits[i].max_position;
00339     }
00340     else
00341     {
00342       pmin[i] = DEFAULT_POS_MIN;
00343       pmax[i] = DEFAULT_POS_MAX;
00344     }
00345 
00346     ROS_ERROR("joint %s min_pos=%f max_pos=%f", trajectory_in.request.limits[i].joint_name.c_str(),
00347       trajectory_in.request.limits[i].min_position, trajectory_in.request.limits[i].max_position);
00348   }
00349 
00350   for(unsigned int i=0; i<trajectory_in.request.trajectory.points.size(); i++)
00351   {
00352     path.push_back(trajectory_in.request.trajectory.points[i].positions);
00353   }                   
00354 
00355   DynamicPath traj;
00356   traj.Init(vmax,amax);
00357   traj.SetJointLimits(pmin,pmax);
00358   traj.SetMilestones(path);   //now the trajectory starts and stops at every milestone
00359   ROS_DEBUG("Initial path duration: %g\n",(double)traj.GetTotalTime());
00360   RampFeasibilityChecker check(feasibility_checker_.get(),tol);
00361   int res=traj.Shortcut(num_iterations_,check);
00362   ROS_DEBUG("After shortcutting: duration %g\n",(double)traj.GetTotalTime());
00363   unsigned int num_points = (unsigned int)(traj.GetTotalTime()/discretization_+0.5) + 1;
00364   double totalTime = (double) traj.GetTotalTime();
00365   for(unsigned int i=0; i < num_points; i++)
00366   {
00367     Vector x, dx;
00368     double t = i*totalTime/(num_points-1);
00369     traj.Evaluate(t,x);
00370     traj.Derivative(t,dx);
00371     trajectory_msgs::JointTrajectoryPoint point;
00372     point.positions = x;
00373     point.velocities = dx;
00374     point.time_from_start = ros::Duration(t);
00375     trajectory_out.request.trajectory.points.push_back(point);
00376   }
00377   trajectory_out.request.trajectory.joint_names = trajectory_in.request.trajectory.joint_names;
00378   feasibility_checker_->resetRequest();
00379   return res;
00380 }
00381 
00382 }
00383 
00384 #endif /* CUBIC_SPLINE_SMOOTHER_H_ */


constraint_aware_spline_smoother
Author(s): Sachin Chitta
autogenerated on Thu Dec 12 2013 11:10:27