$search
00001 00009 /***************************************************************************** 00010 ** Includes 00011 *****************************************************************************/ 00012 00013 #include <ecl/linear_algebra.hpp> // has to be first (eigen stdvector defn). 00014 #include "../../include/ecl/manipulators/waypoint.hpp" 00015 #include "../../include/ecl/manipulators/trajectory.hpp" 00016 #include <ecl/geometry/function_math.hpp> 00017 #include <ecl/geometry/polynomial.hpp> 00018 #include <ecl/math/simple.hpp> 00019 00020 /***************************************************************************** 00021 ** Debug Macros 00022 *****************************************************************************/ 00023 00024 //#define DEBUG_LINEAR_INTERPOLATION 00025 00026 /***************************************************************************** 00027 ** Namespaces 00028 *****************************************************************************/ 00029 00030 namespace ecl { 00031 00032 /***************************************************************************** 00033 ** Implementation [Trajectory][QuinticTensionSplineInterpolation] 00034 *****************************************************************************/ 00035 00036 void Trajectory<JointAngles>::tensionSplineInterpolation(const double &tension) ecl_assert_throw_decl(StandardException) 00037 { 00038 bool result; 00039 unsigned int n = waypoints.size()-1; // n = number of segments 00040 00041 // who the hell made the constraint that this should be 5, shouldn't we only need 3 since we calculate 2 more pseudo points? 00042 ecl_assert_throw( n+1 >= 5, StandardException(LOC,ConfigurationError,"Not enough waypoints for a tension spline interpolation (must be >= 5).") ); 00043 00044 result = validateWaypoints(5); 00045 ecl_assert_throw( result, StandardException(LOC,ConfigurationError,"Not all the waypoint maximum rates have been specified correctly (must be > 0.0).") ); 00046 00047 result = initialiseWaypointDurations(); 00048 ecl_assert_throw( result, StandardException(LOC,ConfigurationError,"A waypoint was configured with a zero duration.") ); 00049 00050 00051 /****************************************** 00052 ** Reserve Spline Storage Space 00053 *******************************************/ 00054 clearSplines(); // Clean up any pre-existing definition. 00055 for ( unsigned int j = 0; j < dimension(); ++j ) { 00056 spline_functions[j].resize(3, NULL); 00057 } 00058 Array<TensionSpline> tension_splines(dimension()); 00059 Array<QuinticPolynomial> leading_quintics(dimension()), trailing_quintics(dimension()); 00060 00061 /****************************************** 00062 ** Roughly Generate Tension Spline 00063 *******************************************/ 00064 bool splines_constrained = false; 00065 while ( !splines_constrained ) { 00066 tension_splines = generateTensionSplines(tension,0.0); 00067 /********************* 00068 ** Check Max Accel 00069 **********************/ 00070 Array<double> domain = tension_splines[0].domain(); 00071 splines_constrained = true; // This changes to false if we break the max accel constraint 00072 // - tension splines have high accelerations at the joins. 00073 // - inbetween the joins, the acceleration goes towards zero. 00074 // - so we just check the size of the acceleration at the joins to find trouble spots. 00075 for ( unsigned int i = 1; i < domain.size()-1; ++i ) { // Natural spline, first and last accelerations are always zero, so dont worry about them 00076 for ( unsigned int j = 0; j < dimension(); ++j ) { 00077 double accel = fabs(tension_splines[j].dderivative(domain[i])); 00078 /********************* 00079 ** Debugging 00080 **********************/ 00081 // std::cout << "Accel checking" << std::endl; 00082 // std::cout << " Domain: " << domain << std::endl; 00083 // std::cout << " Accel[" << i << "," << j << "]: " << accel << std::endl; 00084 // sleep(1); 00085 00086 if ( accel > max_accelerations[j] ) { 00087 splines_constrained = false; 00088 double slope_before = fabs( ( waypoints[i].angles()[j]-waypoints[i-1].angles()[j] )/waypoints[i-1].duration() ); 00089 double slope_after = fabs( ( waypoints[i+1].angles()[j]-waypoints[i].angles()[j] )/waypoints[i].duration() ); 00090 // std::cout << " Slope_Before[" << i << "," << j << "]: " << slope_before << std::endl; 00091 // std::cout << " Slope_After [" << i << "," << j << "]: " << slope_after << std::endl; 00092 if ( slope_before > slope_after ) { 00093 waypoints[i-1].duration(waypoints[i-1].duration()*1.1); // 10% increase 00094 } else { 00095 waypoints[i].duration(waypoints[i].duration()*1.1); // 10% increase 00096 } 00097 // i = domain.size(); // Force it to restart <-- This doesn't actually work so well - dampen the whole curve at once instead of gradually from one end! 00098 break; 00099 } 00100 } 00101 } 00102 } 00103 /****************************************** 00104 ** Check rates are set for head/tail 00105 *******************************************/ 00106 // Note that we may yet change values[1] and values[n+1] when fixing the pseudo points below 00107 // Set them all to zero (default option, i.e. starting at rest). 00108 if ( !waypoints[0].rates_configured() ) { 00109 waypoints[0].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[0].dimension(),0.0); 00110 } 00111 if ( !waypoints[n].rates_configured() ) { 00112 waypoints[n].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[n].dimension(),0.0); 00113 } 00114 00115 /****************************************** 00116 ** Make the pre pseudo point. 00117 *******************************************/ 00118 double leading_quintic_time = 0.0; 00119 bool quintic_constrained = false; 00120 while (!quintic_constrained) { 00121 quintic_constrained = true; 00122 for (unsigned int i = 1; i <= 5; ++i ) { 00123 double t = i*waypoints[0].duration()/10; 00124 // move the tension spline to the right, i.e. give us some space to insert a quintic 00125 tension_splines = generateTensionSplines(tension,t); // t <-- is the initial time to start the tension spline 00126 for ( unsigned int j = 0; j < dimension(); ++j) { 00127 // find the right side boundary conditions for the quintic we want to insert 00128 double y_dot = tension_splines[j].derivative(2*t); 00129 double y = tension_splines[j](2*t); 00130 // the left side boundary conditions for the quintic 00131 double y_0 = waypoints[0].angles()[j]; 00132 double y_0_dot = waypoints[0].rates()[j]; 00133 leading_quintics[j] = QuinticPolynomial::Interpolation(0.0,y_0,y_0_dot,0.0,2*t,y,y_dot,0.0); 00134 00135 /********************* 00136 ** Debugging 00137 **********************/ 00138 // std::cout << "Pre Pseudo Point" << std::endl; 00139 // std::cout << " Domain: " << tension_splines[0].domain() << std::endl; 00140 // std::cout << " y[" << i << "," << j << "] : " << y << std::endl; 00141 // std::cout << " y_dot[" << i << "," << j << "] : " << ydot << std::endl; 00142 // double accel_max = fabs( Maximum<CubicPolynomial>()(0.0,2*t,leading_quintics[j].derivative().derivative())); 00143 // if ( accel_max < fabs( Minimum<CubicPolynomial>()(0.0,2*t,leading_quintics[j].derivative().derivative())) ) { 00144 // accel_max = fabs( Minimum<CubicPolynomial>()(0.0,2*t,leading_quintics[j].derivative().derivative())); 00145 // } 00146 // std::cout << " accel[" << i << "," << j << "] : " << accel_max << std::endl; 00147 // sleep(1); 00148 00149 if ( ( fabs( ecl::Maximum<CubicPolynomial>()(0.0,2*t,leading_quintics[j].derivative().derivative())) < fabs(max_accelerations[j]) ) && 00150 ( fabs( ecl::Minimum<CubicPolynomial>()(0.0,2*t,leading_quintics[j].derivative().derivative())) < fabs(max_accelerations[j]) ) ) { 00151 if ( j == dimension() - 1 ) { // all joints are constrained, great! 00152 leading_quintic_time = 2*t; 00153 // Everything done, force it to completely bail out of these loops. 00154 quintic_constrained = true; 00155 i = 5; 00156 } 00157 } else { // failed to constrain for this i value. 00158 if ( i == 5 ) { // If we get here, even up to half the length of the segment has failed. 00159 quintic_constrained = false; 00160 } 00161 break; 00162 } 00163 } 00164 if ( !quintic_constrained ) { // give up, go back to start of while loop with increased duration 00165 // std::cout << "Quintic unconstrained, increasing the first duration : " << waypoints[0].duration() << std::endl; 00166 waypoints[0].duration(waypoints[0].duration()*1.1); // 10% increase 00167 break; // from the for loop 00168 } 00169 } 00170 } 00171 00172 /****************************************** 00173 ** Make the post pseudo point. 00174 *******************************************/ 00175 double trailing_quintic_time_0 = 0.0; 00176 double trailing_quintic_time_f = 0.0; 00177 quintic_constrained = false; 00178 while (!quintic_constrained) { 00179 quintic_constrained = true; 00180 tension_splines = generateTensionSplines(tension,leading_quintic_time/2); 00181 for (unsigned int i = 1; i <= 5; ++i ) { 00182 double t = i*waypoints[n-1].duration()/10; 00183 double t_f = tension_splines[0].domain().back(); 00184 for ( unsigned int j = 0; j < dimension(); ++j) { 00185 double y_dot = tension_splines[j].derivative(t_f-t); 00186 double y = tension_splines[j](t_f-t); 00187 double y_f = waypoints[n].angles()[j]; 00188 double y_f_dot = waypoints[n].rates()[j]; 00189 trailing_quintics[j] = QuinticPolynomial::Interpolation(t_f-t,y,y_dot,0.0,t_f+t,y_f,y_f_dot,0.0); 00190 00191 /********************* 00192 ** Debugging 00193 **********************/ 00194 // std::cout << "Post Pseudo Point" << std::endl; 00195 // std::cout << " Domain: " << tension_splines[0].domain() << std::endl; 00196 // std::cout << " y[" << i << "," << j << "] : " << y << std::endl; 00197 // std::cout << " y_dot[" << i << "," << j << "] : " << ydot << std::endl; 00198 // double accel_max = fabs( Maximum<CubicPolynomial>()(t_f-t,t_f+t,trailing_quintics[j].derivative().derivative())); 00199 // if ( accel_max < fabs( Minimum<CubicPolynomial>()(t_f-t,t_f+t,trailing_quintics[j].derivative().derivative())) ) { 00200 // accel_max = fabs( Minimum<CubicPolynomial>()(t_f-t,t_f+t,trailing_quintics[j].derivative().derivative())); 00201 // } 00202 // std::cout << " accel[" << i << "," << j << "] : " << accel_max << std::endl; 00203 // sleep(1); 00204 00205 if ( ( fabs( Maximum<CubicPolynomial>()(t_f-t,t_f+t,trailing_quintics[j].derivative().derivative())) < fabs(max_accelerations[j]) ) && 00206 ( fabs( Minimum<CubicPolynomial>()(t_f-t,t_f+t,trailing_quintics[j].derivative().derivative())) < fabs(max_accelerations[j]) ) ) { 00207 if ( j == dimension() - 1 ) { // all joints are constrained, great! 00208 trailing_quintic_time_0 = tension_splines[j].domain().back()-t; 00209 trailing_quintic_time_f = tension_splines[j].domain().back()+t; 00210 // Everything done, force it to completely bail out of these loops. 00211 quintic_constrained = true; 00212 i = 5; 00213 } 00214 } else { // failed to constrain for this i value. 00215 if ( i == 5 ) { // If we get here, even up to half the length of the segment has failed. 00216 quintic_constrained = false; 00217 } 00218 break; 00219 } 00220 } 00221 if ( !quintic_constrained ) { // give up, go back to start of while loop with increased duration 00222 waypoints[n-1].duration(waypoints[n-1].duration()*1.1); // 10% increase 00223 break; 00224 } 00225 } 00226 } 00227 00228 /********************* 00229 ** Debugging 00230 **********************/ 00231 // std::cout << "Leading Quintic Time :" << leading_quintic_time << std::endl; 00232 // std::cout << "Trailing Quintic Time:" << trailing_quintic_time_0 << " " << trailing_quintic_time_f << std::endl; 00233 00234 /****************************************** 00235 ** Finalise 00236 *******************************************/ 00237 trajectory_duration = trailing_quintic_time_f; 00238 for ( unsigned int j = 0; j < dimension(); ++j) { 00239 spline_functions[j][0] = new SplineFunction<QuinticPolynomial>(0.0, leading_quintic_time, leading_quintics[j]); 00240 spline_functions[j][1] = new SplineFunction<TensionSpline>(leading_quintic_time, trailing_quintic_time_0, tension_splines[j]); 00241 spline_functions[j][2] = new SplineFunction<QuinticPolynomial>(trailing_quintic_time_0, trailing_quintic_time_f, trailing_quintics[j]); 00242 } 00243 } 00244 00245 void Trajectory<JointAngles>::linearSplineInterpolation() throw(StandardException) { 00246 00247 if ( !validateWaypoints(2) ) { 00248 throw StandardException(LOC,ConfigurationError,"Not all the waypoint maximum rates have been specified correctly (must be > 0.0)."); 00249 } 00250 if( !initialiseWaypointDurations() ) { 00251 throw StandardException(LOC,ConfigurationError,"A waypoint was configured with a zero duration."); 00252 } 00253 00254 /****************************************** 00255 ** Reserve Spline Storage Space 00256 *******************************************/ 00257 clearSplines(); // Clean up any pre-existing definition. 00258 for ( unsigned int j = 0; j < dimension(); ++j ) { 00259 spline_functions[j].resize(1, NULL); 00260 } 00261 Array<SmoothLinearSpline> splines(dimension()); 00262 00263 /****************************************** 00264 ** Generate Splines 00265 *******************************************/ 00266 bool splines_constrained = false; 00267 int n = waypoints.size() - 1; 00268 while ( !splines_constrained ) { 00269 try { 00270 splines = generateLinearSplines(); 00271 splines_constrained = true; 00272 #ifdef DEBUG_LINEAR_INTERPOLATION 00273 std::cout << "Linear Interpolation: spline generation success" << std::endl; 00274 #endif 00275 } catch ( DataException<int> &e ) { 00276 /********************* 00277 ** Stretch Waypoints 00278 **********************/ 00279 if ( e.data() <= 0 ) { 00280 #ifdef DEBUG_LINEAR_INTERPOLATION 00281 std::cout << "Linear Interpolation: spline generation failed trying to create pre-pseudo, stretching first segment" << std::endl; 00282 #endif 00283 waypoints[0].duration(waypoints[0].duration()*1.1); // 10% increase to w_{0}-w_{1} duration 00284 } else if ( e.data() == 1 ) { // error at corner prepseudo-w0-w1 00285 #ifdef DEBUG_LINEAR_INTERPOLATION 00286 std::cout << "Linear Interpolation: spline generation failed, stretching at corner " << e.data() << std::endl; 00287 #endif 00288 waypoints[0].duration(waypoints[0].duration()*1.1); // 10% increase to w_{0}-w_{1} duration 00289 } else if ( e.data() >= n+1 ) { // error at corner w_{n-1}-w_{n}-postpseudo 00290 #ifdef DEBUG_LINEAR_INTERPOLATION 00291 std::cout << "Linear Interpolation: spline generation failed, stretching at corner " << e.data() << std::endl; 00292 #endif 00293 waypoints[n-1].duration(waypoints[n-1].duration()*1.1); // 10% increase to w_{n-1}-w_{n} duration 00294 } else if ( e.data() >= n+2 ) { 00295 // occurs when trying to create the post-pseudo point 00296 waypoints[n-1].duration(waypoints[n-1].duration()*1.1); // 10% increase to w_{n-1}-w_{n} duration 00297 #ifdef DEBUG_LINEAR_INTERPOLATION 00298 std::cout << "Linear Interpolation: spline generation failed trying to create post-pseudo, stretching last segment" << std::endl; 00299 #endif 00300 } else { 00301 #ifdef DEBUG_LINEAR_INTERPOLATION 00302 std::cout << "Linear Interpolation: spline generation failed, stretching at corner " << e.data() << std::endl; 00303 #endif 00304 waypoints[e.data()-2].duration(waypoints[e.data()-2].duration()*1.05); // 5% increase on either side 00305 waypoints[e.data()-1].duration(waypoints[e.data()-1].duration()*1.05); // 5% increase on either side 00306 } 00307 } 00308 } 00309 00310 /****************************************** 00311 ** Finalise 00312 *******************************************/ 00313 trajectory_duration = splines[0].domain().back()- splines[0].domain().front(); 00314 for ( unsigned int j = 0; j < dimension(); ++j) { 00315 spline_functions[j][0] = new SplineFunction<SmoothLinearSpline>(0.0, splines[j].domain().back(), splines[j]); 00316 } 00317 } 00318 00319 /***************************************************************************** 00320 ** Implementation [Trajectory][Access] 00321 *****************************************************************************/ 00322 00323 double Trajectory<JointAngles>::operator ()(const unsigned int& joint, const double& time ) ecl_assert_throw_decl(StandardException) { 00324 00325 double t_f = spline_functions[joint][spline_functions[joint].size()-1]->domain()[1]; 00326 ecl_assert_throw( ( time >= 0.0 ) && ( time <= t_f + 0.0001 ), StandardException(LOC,OutOfRangeError) ); 00327 unsigned int i; 00328 for (i = 0; i < spline_functions[joint].size(); ++i ) { 00329 if ( time <= spline_functions[joint][i]->domain()[1] ) { 00330 return (*(spline_functions[joint][i]))(time); 00331 } 00332 } 00333 // Sometimes machine precision can kill off some of the inequality arguments above (like e^{-16} error). Fallback: 00334 return (*(spline_functions[joint][spline_functions[joint].size()-1]))(t_f); 00335 } 00336 00337 00338 double Trajectory<JointAngles>::derivative(const unsigned int& joint, const double& time ) ecl_assert_throw_decl(StandardException) { 00339 00340 double t_f = spline_functions[joint][spline_functions[joint].size()-1]->domain()[1]; 00341 ecl_assert_throw( ( time >= 0.0 ) && ( time <= t_f + 0.0001 ), StandardException(LOC,OutOfRangeError) ); 00342 unsigned int i; 00343 for (i = 0; i < spline_functions[joint].size(); ++i ) { 00344 if ( time <= spline_functions[joint][i]->domain()[1] ) { 00345 return spline_functions[joint][i]->derivative(time); 00346 break; 00347 } 00348 } 00349 // Sometimes machine precision can kill off some of the inequality arguments above (like e^{-16} error). Fallback: 00350 return spline_functions[joint][spline_functions[joint].size()-1]->derivative(t_f); 00351 } 00352 00353 double Trajectory<JointAngles>::dderivative(const unsigned int& joint, const double& time ) ecl_assert_throw_decl(StandardException) { 00354 00355 00356 double t_f = spline_functions[joint][spline_functions[joint].size()-1]->domain()[1]; 00357 ecl_assert_throw( ( time >= 0.0 ) && ( time <= t_f + 0.0001 ), StandardException(LOC,OutOfRangeError) ); 00358 unsigned int i; 00359 for (i = 0; i < spline_functions[joint].size(); ++i ) { 00360 if ( time <= spline_functions[joint][i]->domain()[1] ) { 00361 return spline_functions[joint][i]->dderivative(time); 00362 break; 00363 } 00364 } 00365 // Sometimes machine precision can kill off some of the inequality arguments above (like e^{-16} error). Fallback: 00366 return spline_functions[joint][spline_functions[joint].size()-1]->dderivative(t_f); 00367 } 00368 00369 /***************************************************************************** 00370 ** Implementation [Trajectory][Private] 00371 *****************************************************************************/ 00372 00373 00374 bool Trajectory<JointAngles>::validateWaypoints(unsigned int min_no_waypoints) { 00375 00376 unsigned int n = waypoints.size()-1; // n = number of segments 00377 if ( n+1 < min_no_waypoints ) { 00378 return false; 00379 } 00380 00381 for (unsigned int i = 0; i < n; ++i ) { // Dont care about the last waypoint w_n 00382 for (unsigned int j = 0; j < waypoints[i].nominalRates().size(); ++j ) { 00383 if ( waypoints[i].nominalRates()[j] <= 0.0 ) { 00384 return false; 00385 } 00386 } 00387 } 00388 return true; 00389 } 00390 00391 bool Trajectory<JointAngles>::initialiseWaypointDurations() { 00392 00393 unsigned int n = waypoints.size()-1; // n = number of segments 00394 00395 // Waypoint durations are often not configured and default to 0.0 00396 00397 // Here we check the nominal rates and angle differences to automatically guess a 00398 // duration. If the checks are ok, and this is bigger than the configured 00399 // waypoint duration, then replace the waypoint duration with this calculation. 00400 for (unsigned int i = 0; i < n; ++i ) { // Dont need to worry about the w_n's duration. 00401 double max_duration = 0.0; 00402 for (unsigned int j = 0; j < dimension(); ++j ) { 00403 double distance = fabs(waypoints[i+1].angles()[j] - waypoints[i].angles()[j]); 00404 if ( waypoints[i].nominalRates()[j] != 0.0 ) { 00405 double segment_duration = distance/waypoints[i].nominalRates()[j]; // Time = Distance/Velocity 00406 if ( segment_duration > max_duration ) { 00407 max_duration = segment_duration; 00408 } 00409 } 00410 } 00411 if ( max_duration > waypoints[i].duration() ) { 00412 waypoints[i].duration(max_duration); 00413 } 00414 if ( waypoints[i].duration() == 0.0 ) { return false; } 00415 } 00416 return true; 00417 } 00418 00419 void Trajectory<JointAngles>::clearSplines() { 00420 for (unsigned int joint = 0; joint < dimension(); ++joint ) { 00421 for (unsigned int function = 0; function < spline_functions[joint].size(); ++function ) { 00422 if ( spline_functions[joint][function] != NULL ) { 00423 delete spline_functions[joint][function]; 00424 spline_functions[joint][function] = NULL; 00425 } 00426 } 00427 spline_functions[joint].clear(); 00428 } 00429 } 00430 00431 void Trajectory<JointAngles>::updateDuration() { 00432 double total_time = 0.0; 00433 // std::cout << "Durations: "; 00434 for ( unsigned int i = 0; i < waypoints.size()-1; ++i ) { 00435 total_time += waypoints[i].duration(); 00436 // std::cout << waypoints[i].duration() << " "; 00437 } 00438 // std::cout << std::endl; 00439 trajectory_duration = total_time; 00440 } 00441 00442 Array<SmoothLinearSpline> Trajectory<JointAngles>::generateLinearSplines() throw(DataException<int>) { 00443 00444 // n = number of segments 00445 // n+1 = number of input waypoints 00446 // n+3 = number of waypoints (inc. pre-post pseudo) 00447 00448 // This is a bit different from the cubic as we don't use this in a combo interpolater. 00449 Array<SmoothLinearSpline> splines(dimension()); 00450 unsigned int n = waypoints.size()-1; // n = number of segments 00451 Array<double> waypoint_times(n+3), values(n+3); // Including pre and post points 00452 00453 /****************************************** 00454 ** Check rates are set for head/tail 00455 *******************************************/ 00456 // Note that we may yet change values[1] and values[n+1] when fixing the pseudo points below 00457 // Set them all to zero (default option, i.e. starting at rest). 00458 if ( !waypoints[0].rates_configured() ) { 00459 waypoints[0].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[0].dimension(),0.0); 00460 } 00461 if ( !waypoints[n].rates_configured() ) { 00462 waypoints[n].rates() = WayPoint<JointAngles>::JointDataArray::Constant(waypoints[n].dimension(),0.0); 00463 } 00464 00465 /****************************************** 00466 ** Make the pre pseudo point. 00467 *******************************************/ 00468 /* 00469 * Pull back the first waypoint, find intersection of initial tangent line and the nominal rate line. 00470 * Why? This lets us ensure the first segment is of the specified velocity, and the second segment will 00471 * fall the correct between nominal rates required to get to w_1. 00472 * 00473 * x_ 00474 * ^ \__ 00475 * / \ 00476 * o ------ o 00477 * / 00478 * / 00479 * x 00480 * 00481 * - diagonal lines : nominal rate slopes 00482 * - x : possible pseudo waypoints (at intersection of initial velocity line and nominal rate line) 00483 * 00484 * Basic process: 00485 * 00486 * - pullback a bit 00487 * - get intersections as above 00488 * - find minimum time intersection time (t_first_duration) 00489 * - synchronise a pseudo waypoint at that time on the initial tangents for each joint (only 1 of these will be an actual intersection point) 00490 * - check acceleration constraints of quintics for this waypoint at each joint 00491 * - if fail, pullback again, if success, done! 00492 */ 00493 std::vector <LinearFunction> initial_tangents; // these are the lines from potential pseudo point to w_1, our eventual pseudo point must lie on it. 00494 std::vector <double> initial_angles, initial_rates; 00495 for ( unsigned int j = 0; j < dimension(); ++j ) { 00496 initial_angles.push_back(waypoints[0].angles()[j]); 00497 initial_rates.push_back(waypoints[0].rates()[j]); 00498 initial_tangents.push_back(LinearFunction::PointSlopeForm(0, initial_angles[j], initial_rates[j])); 00499 } 00500 std::vector< CartesianPoint2d,Eigen::aligned_allocator<CartesianPoint2d> > pseudo_points(dimension()); 00501 std::vector<LinearFunction> nominal_rate_lines(dimension()); 00502 double t_first_duration, t_pullback = 0.0; 00503 unsigned int max_pull = 15; // should there be a bound to this? 00504 WayPoint<JointAngles> pre_pseudo_waypoint( dimension() ); 00505 for ( unsigned int i = 1; i <= max_pull; ++i ) { 00506 double t = i*waypoints[0].duration()/10; 00507 // establish t_first_duration as the minimum time to the intersection of initial tangent and nominal rate line 00508 t_first_duration = 1000.0; 00509 for ( unsigned int j = 0; j < dimension(); ++j ) { 00510 LinearFunction nominal_rate_line = LinearFunction::PointSlopeForm(t, initial_angles[j], -1 * ecl::psign(initial_rates[j]) * waypoints[0].nominalRates()[j]); 00511 CartesianPoint2d pseudo_point = LinearFunction::Intersection(initial_tangents[j], nominal_rate_line); 00512 if ( pseudo_point.x() < t_first_duration ) { 00513 t_first_duration = pseudo_point.x(); 00514 } 00515 nominal_rate_lines[j] = nominal_rate_line; 00516 } 00517 bool acceleration_constraint_broken = false; 00518 for ( unsigned int j = 0; j < dimension(); ++j ) { 00519 CartesianPoint2d pseudo_point(t_first_duration, initial_tangents[j](t_first_duration)); 00520 double pseudo_point_duration = t + waypoints[0].duration() - t_first_duration; 00521 for ( unsigned int i = 1; i <= 5; ++i ) { 00522 double t_l = t_first_duration - i*t_first_duration/5.0; 00523 double t_r = t_first_duration + i*pseudo_point_duration/10.0; 00524 LinearFunction segment = LinearFunction::Interpolation(pseudo_point.x(), pseudo_point.y(), t + waypoints[0].duration(), waypoints[1].angles()[j]); 00525 double y_0 = initial_tangents[j](t_l); 00526 double y_0_dot = initial_tangents[j].derivative(t_l); 00527 double y = segment(t_r); 00528 double y_dot = segment.derivative(t_r); // slope 00529 QuinticPolynomial quintic = QuinticPolynomial::Interpolation(t_l,y_0,y_0_dot,0.0,t_r,y,y_dot,0.0); 00530 if ( ( fabs( CubicPolynomial::Maximum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j]) ) && 00531 ( fabs( CubicPolynomial::Minimum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j]) ) ) { 00532 break; // we're good, get out and continue through all the joints 00533 } 00534 if ( i == 5 ) { 00535 #ifdef DEBUG_LINEAR_INTERPOLATION 00536 std::cout << "Linear Interpolation: pre psuedo point failed with acceleration checks [" << t_first_duration << "][" << t << "]" << std::endl; 00537 #endif 00538 acceleration_constraint_broken = true; 00539 break; // failure, get completely out 00540 } 00541 } 00542 if ( acceleration_constraint_broken ) { 00543 break; // don't continue through the joints, get out and go back to the pullback loop 00544 } 00545 } 00546 if ( !acceleration_constraint_broken ) { 00547 t_pullback = t; // we have a working solution. 00548 break; 00549 } 00550 if ( i == max_pull ) { 00551 throw DataException<int>(LOC,ConstructorError,"Max acceleration bound broken by pre pseudo point.",0); 00552 } 00553 } 00554 pre_pseudo_waypoint.duration(t_pullback + waypoints[0].duration() - t_first_duration); 00555 for ( unsigned int j = 0; j < dimension(); ++j) { 00556 pre_pseudo_waypoint.angles()[j] = initial_tangents[j](t_first_duration); 00557 } 00558 #ifdef DEBUG_LINEAR_INTERPOLATION 00559 std::cout << "Linear Interpolation: pre psuedo point done!" << std::endl; 00560 std::cout << " : angles " << pre_pseudo_waypoint.angles() << std::endl; 00561 std::cout << " : pre pseudo duration " << t_first_duration << std::endl; 00562 std::cout << " : modified first waypoint duration " << pre_pseudo_waypoint.duration() << std::endl; 00563 #endif 00564 00565 /****************************************** 00566 ** Make the post pseudo point. 00567 *******************************************/ 00568 // std::vector <LinearFunction> nominal_rate_lines; // reuse from above 00569 // std::vector<CartesianPoint2d> pseudo_points(dimension()); 00570 std::vector <double> final_angles, final_rates; 00571 for ( unsigned int j = 0; j < dimension(); ++j ) { 00572 final_angles.push_back(waypoints[n].angles()[j]); 00573 final_rates.push_back(waypoints[n].rates()[j]); 00574 nominal_rate_lines[j] = LinearFunction::PointSlopeForm(0, final_angles[j], -1*ecl::psign(final_rates[j]) * waypoints[n-1].nominalRates()[j]); 00575 } 00576 00577 std::vector<LinearFunction> final_tangents(dimension()); 00578 double t_final, t_pullforward = 0.0; 00579 WayPoint<JointAngles> post_pseudo_waypoint( dimension() ); 00580 for ( unsigned int i = 1; i <= max_pull; ++i ) { 00581 double t = i*waypoints[n-1].duration()/10; 00582 00583 // establish t_final as the maximum time to the intersection of final tangent and nominal rate line 00584 t_final = 0.0; 00585 for ( unsigned int j = 0; j < dimension(); ++j ) { 00586 LinearFunction final_tangent = LinearFunction::PointSlopeForm(t, final_angles[j], final_rates[j]); 00587 final_tangents[j] = final_tangent; 00588 CartesianPoint2d pseudo_point = LinearFunction::Intersection(final_tangents[j], nominal_rate_lines[j]); 00589 if ( pseudo_point.x() > t_final ) { 00590 t_final = pseudo_point.x(); 00591 } 00592 } 00593 // check acceleration constraints 00594 bool acceleration_constraint_broken = false; 00595 for ( unsigned int j = 0; j < dimension(); ++j ) { 00596 CartesianPoint2d pseudo_point(t_final, final_tangents[j](t_final)); 00597 double pseudo_point_duration = t - t_final; 00598 for ( unsigned int i = 1; i <= 5; ++i ) { 00599 double t_l = t_final - i*(waypoints[n-1].duration()+t_final)/10.0; 00600 double t_r = t_final + i*pseudo_point_duration/5.0; 00601 LinearFunction segment = LinearFunction::Interpolation(-waypoints[n-1].duration(), waypoints[n-1].angles()[j], pseudo_point.x(), pseudo_point.y()); 00602 double y_0 = segment(t_l); 00603 double y_0_dot = segment.derivative(t_l); 00604 double y = final_tangents[j](t_r); 00605 double y_dot = final_tangents[j].derivative(t_r); 00606 QuinticPolynomial quintic = QuinticPolynomial::Interpolation(t_l,y_0,y_0_dot,0.0,t_r,y,y_dot,0.0); 00607 if ( ( fabs( CubicPolynomial::Maximum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j]) ) && 00608 ( fabs( CubicPolynomial::Minimum(t_l, t_r, quintic.derivative().derivative())) < fabs(max_accelerations[j]) ) ) { 00609 break; // we're good, get out and continue through all the joints 00610 } 00611 if ( i == 5 ) { 00612 #ifdef DEBUG_LINEAR_INTERPOLATION 00613 std::cout << "Linear Interpolation: post psuedo point failed with acceleration checks [" << pseudo_point_duration << "][" << t << "]" << std::endl; 00614 #endif 00615 acceleration_constraint_broken = true; 00616 break; // failure, get completely out 00617 } 00618 } 00619 if ( acceleration_constraint_broken ) { 00620 break; // don't continue through the joints, get out and go back to the pullback loop 00621 } 00622 } 00623 if ( !acceleration_constraint_broken ) { 00624 t_pullforward = t; // we have a working solution. 00625 break; 00626 } 00627 if ( i == max_pull ) { 00628 throw DataException<int>(LOC,ConstructorError,"Max acceleration bound broken by post pseudo point.",n+2); 00629 } 00630 } 00631 post_pseudo_waypoint.duration(t_pullforward - t_final); 00632 for ( unsigned int j = 0; j < dimension(); ++j) { 00633 post_pseudo_waypoint.angles()[j] = final_tangents[j](t_final); 00634 } 00635 #ifdef DEBUG_LINEAR_INTERPOLATION 00636 std::cout << "Linear Interpolation: post psuedo point done!" << std::endl; 00637 std::cout << " : angles " << post_pseudo_waypoint.angles() << std::endl; 00638 std::cout << " : modified last point duration " << waypoints[n-1].duration() + t_final << std::endl; 00639 std::cout << " : post pseudo duration " << post_pseudo_waypoint.duration() << std::endl; 00640 #endif 00641 00642 /********************* 00643 ** Waypoint Times 00644 **********************/ 00645 // n+3 points (w_0...w_n + pre and post pseudos) 00646 // n+3 waypoint_times 00647 waypoint_times[0] = 0.0; 00648 waypoint_times[1] = t_first_duration; 00649 waypoint_times[2] = t_first_duration + pre_pseudo_waypoint.duration(); 00650 for ( unsigned int i = 2; i < n; ++i ) { 00651 waypoint_times[i+1] = waypoint_times[i]+waypoints[i-1].duration(); 00652 } 00653 waypoint_times[n+1] = waypoint_times[n] + waypoints[n-1].duration() + t_final; 00654 waypoint_times[n+2] = waypoint_times[n+1] + post_pseudo_waypoint.duration(); 00655 00656 #ifdef DEBUG_LINEAR_INTERPOLATION 00657 std::cout << "Linear Interpolation: waypoint time estimates before interpolation: " << waypoint_times << std::endl; 00658 #endif 00659 00660 for ( unsigned int j = 0; j < dimension(); ++j) { 00661 /****************************************** 00662 ** Set Values 00663 *******************************************/ 00664 values[0] = waypoints[0].angles()[j]; 00665 values[1] = pre_pseudo_waypoint.angles()[j]; 00666 for ( unsigned int i = 2; i <= n; ++i ) { 00667 values[i] = waypoints[i-1].angles()[j]; 00668 } 00669 values[n+1] = post_pseudo_waypoint.angles()[j]; 00670 values[n+2] = waypoints[n].angles()[j]; 00671 #ifdef DEBUG_LINEAR_INTERPOLATION 00672 std::cout << "Linear Interpolation: values[" << j << "]: " << values << std::endl; 00673 #endif 00674 00675 /****************************************** 00676 ** Generate Spline 00677 *******************************************/ 00678 try { 00679 splines[j] = SmoothLinearSpline::Interpolation(waypoint_times, values, max_accelerations[j]); 00680 } catch ( DataException<int> &e ) { 00681 throw DataException<int>(LOC,e); 00682 } 00683 } 00684 #ifdef DEBUG_LINEAR_INTERPOLATION 00685 for ( unsigned int j = 0; j < dimension(); ++j) { 00686 std::cout << "Linear Interpolation: discretised domain [" << j << "]: " << splines[j].domain() << std::endl; 00687 } 00688 #endif 00689 00690 return splines; 00691 } 00692 00693 Array<TensionSpline> Trajectory<JointAngles>::generateTensionSplines(const double& tension, const double initial_time) { 00694 00695 Array<TensionSpline> tension_splines(dimension()); 00696 unsigned int n = waypoints.size()-1; // n = number of segments 00697 // Include all waypoints (even w_0 and w_n). We set up pre and post pseudo points later. 00698 Array<double> waypoint_times(n+1), values(n+1); 00699 waypoint_times[0] = initial_time; 00700 for ( unsigned int i = 1; i < n + 1; ++i ) { 00701 waypoint_times[i] = waypoint_times[i-1]+waypoints[i-1].duration(); 00702 } 00703 00704 for ( unsigned int j = 0; j < dimension(); ++j) { 00705 for ( unsigned int i = 0; i < n + 1; ++i ) { 00706 values[i] = waypoints[i].angles()[j]; 00707 } 00708 tension_splines[j] = TensionSpline::Natural(waypoint_times, values, tension); 00709 } 00710 return tension_splines; 00711 } 00712 00713 00714 } // namespace ecl