00001
00026 #include <iostream>
00027 #include <Eigen/Dense>
00028 #include <gtest/gtest.h>
00029 #include "stomp_core/stomp.h"
00030 #include "stomp_core/task.h"
00031
00032 using Trajectory = Eigen::MatrixXd;
00034 const std::size_t NUM_DIMENSIONS = 3;
00035 const std::size_t NUM_TIMESTEPS = 20;
00036 const double DELTA_T = 0.1;
00037 const std::vector<double> START_POS = {1.4, 1.4, 0.5};
00038 const std::vector<double> END_POS = {-1.25, 1.0, -0.26};
00039 const std::vector<double> BIAS_THRESHOLD = {0.050,0.050,0.050};
00040 const std::vector<double> STD_DEV = {1.0, 1.0, 1.0};
00043 using namespace stomp_core;
00044
00046 class DummyTask: public Task
00047 {
00048 public:
00055 DummyTask(const Trajectory& parameters_bias,
00056 const std::vector<double>& bias_thresholds,
00057 const std::vector<double>& std_dev):
00058 parameters_bias_(parameters_bias),
00059 bias_thresholds_(bias_thresholds),
00060 std_dev_(std_dev)
00061 {
00062
00063
00064 int num_timesteps = parameters_bias.cols();
00065 generateSmoothingMatrix(num_timesteps,1.0,smoothing_M_);
00066 srand(1);
00067
00068 }
00069
00071 bool generateNoisyParameters(const Eigen::MatrixXd& parameters,
00072 std::size_t start_timestep,
00073 std::size_t num_timesteps,
00074 int iteration_number,
00075 int rollout_number,
00076 Eigen::MatrixXd& parameters_noise,
00077 Eigen::MatrixXd& noise) override
00078 {
00079 double rand_noise;
00080 for(std::size_t d = 0; d < parameters.rows(); d++)
00081 {
00082 for(std::size_t t = 0; t < parameters.cols(); t++)
00083 {
00084 rand_noise = static_cast<double>(rand()%RAND_MAX)/static_cast<double>(RAND_MAX - 1);
00085 rand_noise = 2*(0.5 - rand_noise);
00086 noise(d,t) = rand_noise*std_dev_[d];
00087 }
00088 }
00089
00090 parameters_noise = parameters + noise;
00091
00092 return true;
00093 }
00094
00095 bool computeCosts(const Trajectory& parameters,
00096 std::size_t start_timestep,
00097 std::size_t num_timesteps,
00098 int iteration_number,
00099 Eigen::VectorXd& costs,
00100 bool& validity) override
00101 {
00102 return computeNoisyCosts(parameters,start_timestep,num_timesteps,iteration_number,-1,costs,validity);
00103 }
00104
00105 bool computeNoisyCosts(const Trajectory& parameters,
00106 std::size_t start_timestep,
00107 std::size_t num_timesteps,
00108 int iteration_number,
00109 int rollout_number,
00110 Eigen::VectorXd& costs,
00111 bool& validity) override
00112 {
00113 costs.setZero(num_timesteps);
00114 double diff;
00115 double cost = 0.0;
00116 validity = true;
00117
00118 for(std::size_t t = 0u; t < num_timesteps; t++)
00119 {
00120 cost = 0;
00121 for(std::size_t d = 0u; d < parameters.rows() ; d++)
00122 {
00123
00124 diff = std::abs(parameters(d,t) - parameters_bias_(d,t));
00125 if( diff > std::abs(bias_thresholds_[d]))
00126 {
00127 cost += diff;
00128 validity = false;
00129 }
00130 }
00131
00132 costs(t) = cost;
00133 }
00134
00135 return true;
00136 }
00137
00138
00139 bool filterParameterUpdates(std::size_t start_timestep,
00140 std::size_t num_timesteps,
00141 int iteration_number,
00142 const Eigen::MatrixXd& parameters,
00143 Eigen::MatrixXd& updates) override
00144 {
00145 return smoothParameterUpdates(start_timestep,num_timesteps,iteration_number,updates);
00146 }
00147
00148
00149 protected:
00150
00159 bool smoothParameterUpdates(std::size_t start_timestep,
00160 std::size_t num_timesteps,
00161 int iteration_number,
00162 Eigen::MatrixXd& updates)
00163 {
00164
00165 for(auto d = 0u; d < updates.rows(); d++)
00166 {
00167 updates.row(d).transpose() = smoothing_M_*(updates.row(d).transpose());
00168 }
00169
00170 return true;
00171 }
00172
00173 protected:
00174
00175 Trajectory parameters_bias_;
00176 std::vector<double> bias_thresholds_;
00177 std::vector<double> std_dev_;
00178 Eigen::MatrixXd smoothing_M_;
00179 };
00180
00188 bool compareDiff(const Trajectory& optimized, const Trajectory& desired,
00189 const std::vector<double>& thresholds)
00190 {
00191 auto num_dimensions = optimized.rows();
00192 Trajectory diff = Trajectory::Zero(num_dimensions,optimized.cols());
00193 for(auto d = 0u;d < num_dimensions ; d++)
00194 {
00195 diff.row(d) = optimized.row(d)- desired.row(d);
00196 diff.row(d).cwiseAbs();
00197 if((diff.row(d).array() > thresholds[d] ).any() )
00198 {
00199 return false;
00200 }
00201 }
00202
00203 return true;
00204 }
00205
00210 StompConfiguration create3DOFConfiguration()
00211 {
00212 StompConfiguration c;
00213 c.num_timesteps = NUM_TIMESTEPS;
00214 c.num_iterations = 40;
00215 c.num_dimensions = NUM_DIMENSIONS;
00216 c.delta_t = DELTA_T;
00217 c.control_cost_weight = 0.0;
00218 c.initialization_method = TrajectoryInitializations::LINEAR_INTERPOLATION;
00219 c.num_iterations_after_valid = 0;
00220 c.num_rollouts = 20;
00221 c.max_rollouts = 20;
00222
00223 return c;
00224 }
00225
00233 void interpolate(const std::vector<double>& start, const std::vector<double>& end,
00234 std::size_t num_timesteps, Trajectory& traj)
00235 {
00236 auto dimensions = start.size();
00237 traj = Eigen::MatrixXd::Zero(dimensions,num_timesteps);
00238 for(auto d = 0u; d < dimensions; d++)
00239 {
00240 double delta = (end[d] - start[d])/(num_timesteps - 1);
00241 for(auto t = 0u; t < num_timesteps; t++)
00242 {
00243 traj(d,t) = start[d] + t*delta;
00244 }
00245 }
00246 }
00247
00249 TEST(Stomp3DOF,construction)
00250 {
00251 Trajectory trajectory_bias;
00252 interpolate(START_POS,END_POS,NUM_TIMESTEPS,trajectory_bias);
00253 TaskPtr task(new DummyTask(trajectory_bias,BIAS_THRESHOLD,STD_DEV));
00254
00255 Stomp stomp(create3DOFConfiguration(),task);
00256 }
00257
00259 TEST(Stomp3DOF,solve_default)
00260 {
00261 Trajectory trajectory_bias;
00262 interpolate(START_POS,END_POS,NUM_TIMESTEPS,trajectory_bias);
00263 TaskPtr task(new DummyTask(trajectory_bias,BIAS_THRESHOLD,STD_DEV));
00264
00265 StompConfiguration config = create3DOFConfiguration();
00266 Stomp stomp(config,task);
00267
00268 Trajectory optimized;
00269 stomp.solve(START_POS,END_POS,optimized);
00270
00271 EXPECT_EQ(optimized.rows(),NUM_DIMENSIONS);
00272 EXPECT_EQ(optimized.cols(),NUM_TIMESTEPS);
00273 EXPECT_TRUE(compareDiff(optimized,trajectory_bias,BIAS_THRESHOLD));
00274
00275
00276 Trajectory diff;
00277 diff = trajectory_bias - optimized;
00278
00279 std::string line_separator = "\n------------------------------------------------------\n";
00280 std::cout<<line_separator;
00281 std::cout<<stomp_core::toString(trajectory_bias);
00282 std::cout<<line_separator;
00283 std::cout<<toString(optimized)<<"\n";
00284 std::cout<<"Differences"<<"\n"<<toString(diff)<<line_separator;
00285 }
00286
00288 TEST(Stomp3DOF,solve_interpolated_initial)
00289 {
00290 Trajectory trajectory_bias;
00291 interpolate(START_POS,END_POS,NUM_TIMESTEPS,trajectory_bias);
00292 TaskPtr task(new DummyTask(trajectory_bias,BIAS_THRESHOLD,STD_DEV));
00293
00294 StompConfiguration config = create3DOFConfiguration();
00295 config.initialization_method = TrajectoryInitializations::LINEAR_INTERPOLATION;
00296 Stomp stomp(config,task);
00297
00298 Trajectory optimized;
00299 stomp.solve(trajectory_bias,optimized);
00300
00301 EXPECT_EQ(optimized.rows(),NUM_DIMENSIONS);
00302 EXPECT_EQ(optimized.cols(),NUM_TIMESTEPS);
00303 EXPECT_TRUE(compareDiff(optimized,trajectory_bias,BIAS_THRESHOLD));
00304
00305
00306 Trajectory diff;
00307 diff = trajectory_bias - optimized;
00308
00309 std::string line_separator = "\n------------------------------------------------------\n";
00310 std::cout<<line_separator;
00311 std::cout<<stomp_core::toString(trajectory_bias);
00312 std::cout<<line_separator;
00313 std::cout<<toString(optimized)<<"\n";
00314 std::cout<<"Differences"<<"\n"<<toString(diff)<<line_separator;
00315 }
00316
00318 TEST(Stomp3DOF,solve_cubic_polynomial_initial)
00319 {
00320 Trajectory trajectory_bias;
00321 interpolate(START_POS,END_POS,NUM_TIMESTEPS,trajectory_bias);
00322 TaskPtr task(new DummyTask(trajectory_bias,BIAS_THRESHOLD,STD_DEV));
00323
00324 StompConfiguration config = create3DOFConfiguration();
00325 config.initialization_method = TrajectoryInitializations::CUBIC_POLYNOMIAL_INTERPOLATION;
00326 Stomp stomp(config,task);
00327
00328 Trajectory optimized;
00329 stomp.solve(trajectory_bias,optimized);
00330
00331 EXPECT_EQ(optimized.rows(),NUM_DIMENSIONS);
00332 EXPECT_EQ(optimized.cols(),NUM_TIMESTEPS);
00333 EXPECT_TRUE(compareDiff(optimized,trajectory_bias,BIAS_THRESHOLD));
00334
00335
00336 Trajectory diff;
00337 diff = trajectory_bias - optimized;
00338
00339 std::string line_separator = "\n------------------------------------------------------\n";
00340 std::cout<<line_separator;
00341 std::cout<<stomp_core::toString(trajectory_bias);
00342 std::cout<<line_separator;
00343 std::cout<<toString(optimized)<<"\n";
00344 std::cout<<"Differences"<<"\n"<<toString(diff)<<line_separator;
00345 }
00346
00348 TEST(Stomp3DOF,solve_min_control_cost_initial)
00349 {
00350 Trajectory trajectory_bias;
00351 interpolate(START_POS,END_POS,NUM_TIMESTEPS,trajectory_bias);
00352 TaskPtr task(new DummyTask(trajectory_bias,BIAS_THRESHOLD,STD_DEV));
00353
00354 StompConfiguration config = create3DOFConfiguration();
00355 config.initialization_method = TrajectoryInitializations::MININUM_CONTROL_COST;
00356 Stomp stomp(config,task);
00357
00358 Trajectory optimized;
00359 stomp.solve(trajectory_bias,optimized);
00360
00361 EXPECT_EQ(optimized.rows(),NUM_DIMENSIONS);
00362 EXPECT_EQ(optimized.cols(),NUM_TIMESTEPS);
00363 EXPECT_TRUE(compareDiff(optimized,trajectory_bias,BIAS_THRESHOLD));
00364
00365
00366 Trajectory diff;
00367 diff = trajectory_bias - optimized;
00368
00369 std::string line_separator = "\n------------------------------------------------------\n";
00370 std::cout<<line_separator;
00371 std::cout<<stomp_core::toString(trajectory_bias);
00372 std::cout<<line_separator;
00373 std::cout<<toString(optimized)<<"\n";
00374 std::cout<<"Differences"<<"\n"<<toString(diff)<<line_separator;
00375 }
00376
00378 TEST(Stomp3DOF,solve_40_timesteps)
00379 {
00380 Trajectory trajectory_bias;
00381 int num_timesteps = 40;
00382 interpolate(START_POS,END_POS,num_timesteps,trajectory_bias);
00383 TaskPtr task(new DummyTask(trajectory_bias,BIAS_THRESHOLD,STD_DEV));
00384
00385 StompConfiguration config = create3DOFConfiguration();
00386 config.initialization_method = TrajectoryInitializations::LINEAR_INTERPOLATION;
00387 config.num_iterations = 100;
00388 config.num_timesteps = num_timesteps;
00389 Stomp stomp(config,task);
00390
00391 Trajectory optimized;
00392 stomp.solve(START_POS,END_POS,optimized);
00393
00394 EXPECT_EQ(optimized.rows(),NUM_DIMENSIONS);
00395 EXPECT_EQ(optimized.cols(),num_timesteps);
00396 EXPECT_TRUE(compareDiff(optimized,trajectory_bias,BIAS_THRESHOLD));
00397
00398
00399 Trajectory diff;
00400 diff = trajectory_bias - optimized;
00401
00402 std::string line_separator = "\n------------------------------------------------------\n";
00403 std::cout<<line_separator;
00404 std::cout<<stomp_core::toString(trajectory_bias);
00405 std::cout<<line_separator;
00406 std::cout<<toString(optimized)<<"\n";
00407 std::cout<<"Differences"<<"\n"<<toString(diff)<<line_separator;
00408 }
00409
00411 TEST(Stomp3DOF,solve_60_timesteps)
00412 {
00413 Trajectory trajectory_bias;
00414 int num_timesteps = 60;
00415 interpolate(START_POS,END_POS,num_timesteps,trajectory_bias);
00416 TaskPtr task(new DummyTask(trajectory_bias,BIAS_THRESHOLD,STD_DEV));
00417
00418 StompConfiguration config = create3DOFConfiguration();
00419
00420 config.num_iterations = 100;
00421 config.num_timesteps = num_timesteps;
00422 Stomp stomp(config,task);
00423
00424 Trajectory optimized;
00425 stomp.solve(START_POS,END_POS,optimized);
00426
00427 EXPECT_EQ(optimized.rows(),NUM_DIMENSIONS);
00428 EXPECT_EQ(optimized.cols(),num_timesteps);
00429 EXPECT_TRUE(compareDiff(optimized,trajectory_bias,BIAS_THRESHOLD));
00430
00431
00432 Trajectory diff;
00433 diff = trajectory_bias - optimized;
00434
00435 std::string line_separator = "\n------------------------------------------------------\n";
00436 std::cout<<line_separator;
00437 std::cout<<stomp_core::toString(trajectory_bias);
00438 std::cout<<line_separator;
00439 std::cout<<toString(optimized)<<"\n";
00440 std::cout<<"Differences"<<"\n"<<toString(diff)<<line_separator;
00441 }
00442