dmp.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2012, Scott Niekum
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Willow Garage nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *********************************************************************/
00036 
00042 #include "dmp/dmp.h"
00043 using namespace std;
00044 
00045 namespace dmp{
00046 
00047 #define MAX_PLAN_LENGTH 1000
00048 
00049 double alpha = -log(0.01); //Ensures 99% phase convergence at t=tau
00050 
00057 double calcPhase(double curr_time, double tau)
00058 {
00059         return exp(-(alpha/tau)*curr_time);
00060 }
00061 
00062 
00071 void learnFromDemo(const DMPTraj &demo,
00072                                    const vector<double> &k_gains,
00073                                    const vector<double> &d_gains,
00074                                    const int &num_bases,
00075                                    vector<DMPData> &dmp_list)
00076 {
00077         //Determine traj length and dim
00078         int n_pts = demo.points.size();
00079         if(n_pts < 1){
00080                 ROS_ERROR("Empty trajectory passed to learn_dmp_from_demo service!");
00081                 return;
00082         }
00083         int dims = demo.points[0].positions.size();
00084         double tau = demo.times[n_pts-1];
00085 
00086         double *x_demo = new double[n_pts];
00087         double *v_demo = new double[n_pts];
00088         double *v_dot_demo = new double[n_pts];
00089         double *f_domain = new double[n_pts];
00090         double *f_targets = new double[n_pts];
00091         FunctionApprox *f_approx = new FourierApprox(num_bases);
00092 
00093         //Compute the DMP weights for each DOF separately
00094         for(int d=0; d<dims; d++){
00095                 double curr_k = k_gains[d];
00096                 double curr_d = d_gains[d];
00097                 double x_0 = demo.points[0].positions[d];
00098                 double goal = demo.points[n_pts-1].positions[d];
00099                 x_demo[0] = demo.points[0].positions[d];
00100                 v_demo[0] = 0;
00101                 v_dot_demo[0] = 0;
00102 
00103                 //Calculate the demonstration v and v dot by assuming constant acceleration over a time period
00104                 for(int i=1; i<n_pts; i++){
00105                         x_demo[i] = demo.points[i].positions[d];
00106                         double dx = x_demo[i] - x_demo[i-1];
00107                         double dt = demo.times[i] - demo.times[i-1];
00108                         v_demo[i] = dx/dt;
00109                         v_dot_demo[i] = (v_demo[i] - v_demo[i-1]) / dt;
00110                 }
00111 
00112                 //Calculate the target pairs so we can solve for the weights
00113                 for(int i=0; i<n_pts; i++){
00114                         double phase = calcPhase(demo.times[i],tau);
00115                         f_domain[i] = demo.times[i]/tau;  //Scaled time is cleaner than phase for spacing reasons
00116                         f_targets[i] = ((tau*tau*v_dot_demo[i] + curr_d*tau*v_demo[i]) / curr_k) - (goal-x_demo[i]) + ((goal-x_0)*phase);
00117                         f_targets[i] /= phase; // Do this instead of having fxn approx scale its output based on phase
00118                 }
00119 
00120                 //Solve for weights
00121                 f_approx->leastSquaresWeights(f_domain, f_targets, n_pts);
00122 
00123                 //Create the DMP structures
00124                 DMPData *curr_dmp = new DMPData();
00125                 curr_dmp->weights = f_approx->getWeights();
00126                 curr_dmp->k_gain = curr_k;
00127                 curr_dmp->d_gain = curr_d;
00128                 dmp_list.push_back(*curr_dmp);
00129         }
00130 
00131         delete[] x_demo;
00132         delete[] v_demo;
00133         delete[] v_dot_demo;
00134         delete[] f_domain;
00135         delete[] f_targets;
00136         delete f_approx;
00137 }
00138 
00139 
00140 
00156 void generatePlan(const vector<DMPData> &dmp_list,
00157                                   const vector<double> &x_0,
00158                                   const vector<double> &x_dot_0,
00159                                   const double &t_0,
00160                                   const vector<double> &goal,
00161                                   const vector<double> &goal_thresh,
00162                                   const double &seg_length,
00163                                   const double &tau,
00164                                   const double &total_dt,
00165                                   const int &integrate_iter,
00166                                   DMPTraj &plan,
00167                                   uint8_t &at_goal)
00168 {
00169         plan.points.clear();
00170         plan.times.clear();
00171         at_goal = false;
00172 
00173         int dims = dmp_list.size();
00174         int n_pts = 0;
00175         double dt = total_dt / integrate_iter;
00176 
00177         vector<double> *x_vecs, *x_dot_vecs;
00178         vector<double> t_vec;
00179         x_vecs = new vector<double>[dims];
00180         x_dot_vecs = new vector<double>[dims];
00181         FunctionApprox **f = new FunctionApprox*[dims];
00182 
00183         for(int i=0; i<dims; i++)
00184                 f[i] = new FourierApprox(dmp_list[i].weights);
00185         
00186         double t = 0;
00187         double f_eval;
00188 
00189         //Plan for at least tau seconds.  After that, plan until goal_thresh is satisfied.
00190         //Cut off if plan exceeds MAX_PLAN_LENGTH seconds, in case of overshoot / oscillation
00191         //Only plan for seg_length seconds if specified
00192         bool seg_end = false;
00193         while(((t+t_0) < tau || (!at_goal && t<MAX_PLAN_LENGTH)) && !seg_end){
00194                 //Check if we've planned to the segment end yet
00195                 if(seg_length > 0){
00196                         if (t > seg_length) seg_end = true;
00197                 }
00198 
00199                 //Plan in each dimension
00200                 for(int i=0; i<dims; i++){
00201             double x,v;
00202             if(n_pts==0){
00203                 x = x_0[i];
00204                 v = x_dot_0[i];
00205             }
00206             else{                       
00207                 x = x_vecs[i][n_pts-1];
00208                             v = x_dot_vecs[i][n_pts-1] * tau;
00209             }
00210 
00211                         //Numerically integrate to get new x and v
00212                         for(int iter=0; iter<integrate_iter; iter++)
00213                         {
00214                                 //Compute the phase and the log of the phase to assist with some numerical issues
00215                                 //Then, evaluate the function approximator at the log of the phase
00216                                 double s = calcPhase((t+t_0) + (dt*iter), tau);
00217                                 double log_s = (t+t_0)/tau;
00218                                 if(log_s >= 1.0){
00219                                         f_eval = 0;
00220                                 }
00221                                 else{
00222                                         f_eval = f[i]->evalAt(log_s) * s;
00223                                 }
00224 
00225                                 //Update v dot and x dot based on DMP differential equations
00226                                 double v_dot = (dmp_list[i].k_gain*((goal[i]-x) - (goal[i]-x_0[i])*s + f_eval) - dmp_list[i].d_gain*v) / tau;
00227                                 double x_dot = v/tau;
00228 
00229                                 //Update state variables
00230                                 v += v_dot * dt;
00231                                 x += x_dot * dt;
00232                         }
00233 
00234                         //Add current state to the plan
00235                         x_vecs[i].push_back(x);
00236                         x_dot_vecs[i].push_back(v/tau);
00237                 }
00238                 t += total_dt;
00239                 t_vec.push_back(t);
00240                 n_pts++;
00241 
00242                 //If plan is at least minimum length, check to see if we are close enough to goal
00243                 if((t+t_0) >= tau){
00244                         at_goal = true;
00245                         for(int i=0; i<dims; i++){
00246                                 if(goal_thresh[i] > 0){
00247                                         if(fabs(x_vecs[i][n_pts-1] - goal[i]) > goal_thresh[i])
00248                                                 at_goal = false;
00249                                 }
00250                         }
00251                 }
00252         }
00253 
00254         //Create a plan from the generated trajectories
00255         plan.points.resize(n_pts);
00256         for(int j=0; j<n_pts; j++){
00257                 plan.points[j].positions.resize(dims);
00258                 plan.points[j].velocities.resize(dims);
00259         }
00260         for(int i=0; i<dims; i++){
00261                 for(int j=0; j<n_pts; j++){
00262                         plan.points[j].positions[i] = x_vecs[i][j];
00263                         plan.points[j].velocities[i] = x_dot_vecs[i][j];
00264                 }
00265         }
00266         plan.times = t_vec;
00267 
00268         //Clean up
00269         for(int i=0; i<dims; i++){
00270                 delete f[i];
00271         }
00272         delete[] f;
00273         delete[] x_vecs;
00274         delete[] x_dot_vecs;
00275 }
00276 
00277 }
00278 


dmp
Author(s): Scott Niekum
autogenerated on Fri Jan 3 2014 11:19:23