00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
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));
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;
00305 Vector vmax,amax;
00306 Vector pmin,pmax;
00307 Real tol=1e-4;
00308
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);
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