trajectory_spline_sampler.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  *  Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2014, Fetch Robotics Inc.
00005  *  Copyright (c) 2013, Unbounded Robotics Inc.
00006  *  Copyright (c) 2009, Willow Garage, Inc.
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of Unbounded Robotics, Willow Garage nor the names
00020  *     of their contributors may be used to endorse or promote products
00021  *     derived from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *********************************************************************/
00036 
00037 // Portions are based on splines.h of arm_navigation
00038 // Author: Michael Ferguson, Mrinal Kalakrishnan (splines.h)
00039 
00040 #ifndef ROBOT_CONTROLLERS_TRAJECTORY_SPLINE_SAMPLER_H_
00041 #define ROBOT_CONTROLLERS_TRAJECTORY_SPLINE_SAMPLER_H_
00042 
00043 #include <robot_controllers/trajectory.h>
00044 
00045 namespace robot_controllers
00046 {
00047 
00049 struct Spline
00050 {
00051   double coef[6];
00052 };
00053 
00054 enum SplineType
00055 {
00056   QUINTIC,
00057   CUBIC,
00058   LINEAR
00059 };
00060 
00062 static inline void generatePowers(int n, double x, double* powers)
00063 {
00064   powers[0] = 1.0;
00065   for (int i=1; i<=n; i++)
00066   {
00067     powers[i] = powers[i-1]*x;
00068   }
00069 }
00070 
00082 static void QuinticSpline(double p0, double v0, double a0,
00083                           double p1, double v1, double a1,
00084                           double t, Spline& s)
00085 {
00086   if (t == 0.0)
00087   {
00088     s.coef[0] = p1;
00089     s.coef[1] = v1;
00090     s.coef[2] = 0.5*a1;
00091     s.coef[3] = 0.0;
00092     s.coef[4] = 0.0;
00093     s.coef[5] = 0.0;
00094   }
00095   else
00096   {
00097     double T[6];
00098     generatePowers(5, t, T);
00099 
00100     s.coef[0] = p0;
00101     s.coef[1] = v0;
00102     s.coef[2] = 0.5*a0;
00103     s.coef[3] = (-20.0*p0 + 20.0*p1 - 3.0*a0*T[2] + a1*T[2] -
00104                  12.0*v0*T[1] - 8.0*v1*T[1]) / (2.0*T[3]);
00105     s.coef[4] = (30.0*p0 - 30.0*p1 + 3.0*a0*T[2] - 2.0*a1*T[2] +
00106                  16.0*v0*T[1] + 14.0*v1*T[1]) / (2.0*T[4]);
00107     s.coef[5] = (-12.0*p0 + 12.0*p1 - a0*T[2] + a1*T[2] -
00108                  6.0*v0*T[1] - 6.0*v1*T[1]) / (2.0*T[5]);
00109   }
00110 }
00111 
00115 static void sampleQuinticSpline(Spline& s, double t,
00116                                 double& position, double& velocity, double& acceleration)
00117 {
00118   double T[6];
00119   generatePowers(5, t, T);
00120 
00121   position = T[0]*s.coef[0] +
00122              T[1]*s.coef[1] +
00123              T[2]*s.coef[2] +
00124              T[3]*s.coef[3] +
00125              T[4]*s.coef[4] +
00126              T[5]*s.coef[5];
00127 
00128   velocity = T[0]*s.coef[1] +
00129          2.0*T[1]*s.coef[2] +
00130          3.0*T[2]*s.coef[3] +
00131          4.0*T[3]*s.coef[4] +
00132          5.0*T[4]*s.coef[5];
00133 
00134   acceleration = 2.0*T[0]*s.coef[2] +
00135                  6.0*T[1]*s.coef[3] +
00136                 12.0*T[2]*s.coef[4] +
00137                 20.0*T[3]*s.coef[5];
00138 }
00139 
00149 static void CubicSpline(double p0, double v0, double p1, double v1, double t, Spline& s)
00150 {
00151   if (t == 0.0)
00152   {
00153     s.coef[0] = p1;
00154     s.coef[1] = v1;
00155     s.coef[2] = 0.0;
00156     s.coef[3] = 0.0;
00157   }
00158   else
00159   {
00160     double T[4];
00161     generatePowers(3, t, T);
00162 
00163     s.coef[0] = p0;
00164     s.coef[1] = v0;
00165     s.coef[2] = (3.0 * p1 - 3.0 * p0 - 2.0 *v0*T[1] - v1*T[1]) / T[2];
00166     s.coef[3] = (-2.0 * p1 + 2.0 * p0 + v0*T[1] + v1*T[1]) / T[3];
00167   }
00168 }
00169 
00173 static void sampleCubicSpline(Spline s, double t, double& position, double& velocity)
00174 {
00175   double T[4];
00176   generatePowers(3, t, T);
00177 
00178   position = T[0]*s.coef[0] +
00179              T[1]*s.coef[1] +
00180              T[2]*s.coef[2] +
00181              T[3]*s.coef[3];
00182 
00183   velocity = T[0]*s.coef[1] +
00184          2.0*T[1]*s.coef[2] +
00185          3.0*T[2]*s.coef[3];
00186 }
00187 
00188 static void LinearSpline(double p0, double p1, double t, Spline& s)
00189 {
00190   s.coef[0] = p0;
00191   s.coef[1] = p1 - p0;
00192   s.coef[2] = t;
00193 }
00194 
00195 static void sampleLinearSpline(Spline& s, double t, double& position)
00196 {
00197   position = s.coef[0] + (s.coef[1] * t/s.coef[2]);
00198 }
00199 
00203 class SplineTrajectorySampler : public TrajectorySampler
00204 {
00205   struct Segment
00206   {
00207     double start_time;
00208     double end_time;
00209     int type;  
00210     std::vector<Spline> splines;  
00211   };
00212 
00213 public:
00215   SplineTrajectorySampler(const Trajectory& trajectory) :
00216     trajectory_(trajectory)
00217   {
00218     // Check for invalid trajectory size
00219     if (trajectory.size() == 0)
00220     {
00221       throw 0;
00222     }
00223 
00224     // Check for number of joints
00225     size_t num_joints = trajectory.points[0].q.size();
00226 
00227     // Trajectory length one is special
00228     if (trajectory.size() == 1)
00229     {
00230       segments_.resize(1);
00231       segments_[0].start_time = segments_[0].end_time = trajectory.points[0].time;
00232 
00233       // Set up spline
00234       segments_[0].splines.resize(num_joints);
00235       for (size_t j = 0; j < num_joints; ++j)
00236       {
00237         LinearSpline(trajectory.points[0].q[j],
00238                      trajectory.points[0].q[j],
00239                      0.0,
00240                      segments_[0].splines[j]);
00241       }
00242       segments_[0].type = LINEAR;
00243       result.q.resize(num_joints);
00244     }
00245     else
00246     {
00247       // We put a segment in between each pair of points
00248       segments_.resize(trajectory.size()-1);
00249 
00250       // Setup up the segments
00251       for (size_t p = 0; p < segments_.size(); ++p)
00252       {
00253         // This segment is from p to p+1
00254         segments_[p].start_time = trajectory.points[p].time;
00255         segments_[p].end_time = trajectory.points[p+1].time;
00256 
00257         // Set up spline
00258         segments_[p].splines.resize(num_joints);
00259         if (trajectory.points[p].qdd.size() == trajectory.points[p].q.size())
00260         {
00261           result.q.resize(num_joints);
00262           result.qd.resize(num_joints);
00263           result.qdd.resize(num_joints);
00264 
00265           // Have accelerations, will use Quintic.
00266           for (size_t j = 0; j < num_joints; ++j)
00267           {
00268             QuinticSpline(trajectory.points[p].q[j],
00269                           trajectory.points[p].qd[j],
00270                           trajectory.points[p].qdd[j],
00271                           trajectory.points[p+1].q[j],
00272                           trajectory.points[p+1].qd[j],
00273                           trajectory.points[p+1].qdd[j],
00274                           segments_[p].end_time - segments_[p].start_time,
00275                           segments_[p].splines[j]);
00276           }
00277           segments_[p].type = QUINTIC;
00278         }
00279         else if (trajectory.points[p].qd.size() == trajectory.points[p].q.size())
00280         {
00281           result.q.resize(num_joints);
00282           result.qd.resize(num_joints);
00283 
00284           // Velocities + Positions, do Cubic.
00285           for (size_t j = 0; j < num_joints; ++j)
00286           {
00287             CubicSpline(trajectory.points[p].q[j],
00288                         trajectory.points[p].qd[j],
00289                         trajectory.points[p+1].q[j],
00290                         trajectory.points[p+1].qd[j],
00291                         segments_[p].end_time - segments_[p].start_time,
00292                         segments_[p].splines[j]);
00293           }
00294           segments_[p].type = CUBIC;
00295         }
00296         else
00297         {
00298           result.q.resize(num_joints);
00299  
00300           // Lame -- only positions do linear
00301           for (size_t j = 0; j < num_joints; ++j)
00302           {
00303             LinearSpline(trajectory.points[p].q[j],
00304                          trajectory.points[p+1].q[j],
00305                          segments_[p].end_time - segments_[p].start_time,
00306                          segments_[p].splines[j]);
00307           }
00308           segments_[p].type = LINEAR;
00309         }
00310       }
00311     }
00312     seg_ = -1;
00313   }
00314 
00316   virtual TrajectoryPoint sample(double time)
00317   {
00318     // Which segment to sample from.
00319     while ((seg_ + 1 < int(segments_.size())) &&
00320            (segments_[seg_ + 1].start_time < time))
00321     {
00322       ++seg_;
00323     }
00324 
00325     // Check beginning of trajectory, return empty trajectory point if not started.
00326     if (seg_ == -1)
00327       return TrajectoryPoint();
00328 
00329     // Check end of trajectory, restrict time.
00330     if (time > end_time())
00331       time = end_time();
00332 
00333     // Sample segment for each joint.
00334     for (size_t i = 0; i < segments_[seg_].splines.size(); ++i)
00335     {
00336       if (segments_[seg_].type == QUINTIC)
00337       {
00338         sampleQuinticSpline(segments_[seg_].splines[i], time - segments_[seg_].start_time,
00339                             result.q[i], result.qd[i], result.qdd[i]);
00340       }
00341       else if(segments_[seg_].type == CUBIC)
00342       {
00343         sampleCubicSpline(segments_[seg_].splines[i], time - segments_[seg_].start_time,
00344                           result.q[i], result.qd[i]);
00345       }
00346       else
00347       {
00348         sampleLinearSpline(segments_[seg_].splines[i], time - segments_[seg_].start_time,
00349                            result.q[i]);
00350       }
00351     }
00352 
00353     result.time = time;
00354     return result;
00355   }
00356 
00358   virtual double end_time()
00359   {
00360     return segments_[segments_.size()-1].end_time;
00361   }
00362 
00364   virtual Trajectory getTrajectory()
00365   {
00366     return trajectory_;
00367   }
00368 
00369 private:
00370   std::vector<Segment> segments_;
00371   Trajectory trajectory_;
00372   TrajectoryPoint result;
00373   int seg_;
00374 };
00375 
00376 }  // namespace robot_controllers
00377 
00378 #endif  // ROBOT_CONTROLLERS_TRAJECTORY_SPLINE_SAMPLER_H_


robot_controllers
Author(s): Michael Ferguson
autogenerated on Wed Jun 14 2017 04:09:10