chomp_optimizer.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00037 #include <chomp_motion_planner/chomp_optimizer.h>
00038 #include <ros/ros.h>
00039 #include <visualization_msgs/MarkerArray.h>
00040 #include <chomp_motion_planner/chomp_utils.h>
00041 #include <planning_models/kinematic_model.h>
00042 #include <eigen3/Eigen/LU>
00043 #include <eigen3/Eigen/Core>
00044 #include <ros/console.h>
00045 using namespace std;
00046 using namespace Eigen;
00047 using namespace planning_models;
00048 using namespace collision_proximity;
00049 using namespace arm_navigation_msgs;
00050 using namespace trajectory_msgs;
00051 
00052 namespace chomp
00053 {
00054   double getRandomDouble()
00055   {
00056     return ((double)random() / (double)RAND_MAX);
00057   }
00058 
00059   ChompOptimizer::ChompOptimizer(ChompTrajectory *trajectory, KinematicModel *robot_model,
00060                                  const string& planning_group,const ChompParameters *parameters, const ros::Publisher& vis_marker_array_publisher,
00061                                  const ros::Publisher& vis_marker_publisher, CollisionProximitySpace *collision_space) :
00062     full_trajectory_(trajectory), robot_model_(robot_model), planning_group_(planning_group), parameters_(parameters),
00063         collision_space_(collision_space), group_trajectory_(*full_trajectory_, planning_group_, DIFF_RULE_LENGTH),
00064         vis_marker_array_pub_(vis_marker_array_publisher), vis_marker_pub_(vis_marker_publisher)
00065   {
00066     initialize();
00067   }
00068 
00069   void ChompOptimizer::initialize()
00070   {
00071     robot_state_ = collision_space_->getCollisionModelsInterface()->getPlanningSceneState();
00072     // init some variables:
00073     num_vars_free_ = group_trajectory_.getNumFreePoints();
00074     num_vars_all_ = group_trajectory_.getNumPoints();
00075     num_joints_ = group_trajectory_.getNumJoints();
00076 
00077     free_vars_start_ = group_trajectory_.getStartIndex();
00078     free_vars_end_ = group_trajectory_.getEndIndex();
00079 
00080     vector<GradientInfo> infos;
00081     collision_space_->getStateGradients(infos);
00082 
00083     num_collision_points_ = 0;
00084     for(size_t i = 0; i < infos.size(); i++)
00085     {
00086       GradientInfo& info = infos[i];
00087       num_collision_points_ += info.sphere_locations.size();
00088 
00089     }
00090 
00091     // set up the joint costs:
00092     joint_costs_.reserve(num_joints_);
00093 
00094     double max_cost_scale = 0.0;
00095     ros::NodeHandle nh("~");
00096 
00097     map<string, KinematicModel::JointModelGroup*> jointMap = robot_model_->getJointModelGroupMap();
00098     KinematicModel::JointModelGroup* jointModelGroup = jointMap[planning_group_];
00099     vector<const KinematicModel::JointModel*> jointModels = jointModelGroup->getJointModels();
00100     for(size_t i = 0; i < jointModels.size(); i++)
00101     {
00102       const KinematicModel::JointModel* model = jointModels[i];
00103       double joint_cost = 1.0;
00104       string joint_name = model->getName();
00105       nh.param("joint_costs/" + joint_name, joint_cost, 1.0);
00106       vector<double> derivative_costs(3);
00107       derivative_costs[0] = joint_cost * parameters_->getSmoothnessCostVelocity();
00108       derivative_costs[1] = joint_cost * parameters_->getSmoothnessCostAcceleration();
00109       derivative_costs[2] = joint_cost * parameters_->getSmoothnessCostJerk();
00110 
00111       joint_costs_.push_back(ChompCost(group_trajectory_, i, derivative_costs, parameters_->getRidgeFactor()));
00112       double cost_scale = joint_costs_[i].getMaxQuadCostInvValue();
00113       if(max_cost_scale < cost_scale)
00114         max_cost_scale = cost_scale;
00115     }
00116 
00117     // scale the smoothness costs
00118     for(int i = 0; i < num_joints_; i++)
00119     {
00120       joint_costs_[i].scale(max_cost_scale);
00121     }
00122 
00123     // allocate memory for matrices:
00124     smoothness_increments_ = MatrixXd::Zero(num_vars_free_, num_joints_);
00125     collision_increments_ = MatrixXd::Zero(num_vars_free_, num_joints_);
00126     final_increments_ = MatrixXd::Zero(num_vars_free_, num_joints_);
00127     smoothness_derivative_ = VectorXd::Zero(num_vars_all_);
00128     jacobian_ = MatrixXd::Zero(3, num_joints_);
00129     jacobian_pseudo_inverse_ = MatrixXd::Zero(num_joints_, 3);
00130     jacobian_jacobian_tranpose_ = MatrixXd::Zero(3, 3);
00131     random_state_ = VectorXd::Zero(num_joints_);
00132     joint_state_velocities_ = VectorXd::Zero(num_joints_);
00133 
00134     group_trajectory_backup_ = group_trajectory_.getTrajectory();
00135     best_group_trajectory_ = group_trajectory_.getTrajectory();
00136 
00137     collision_point_joint_names_.resize(num_vars_all_, vector<string>(num_collision_points_));
00138     collision_point_pos_eigen_.resize(num_vars_all_, vector<Vector3d>(num_collision_points_));
00139     collision_point_vel_eigen_.resize(num_vars_all_, vector<Vector3d>(num_collision_points_));
00140     collision_point_acc_eigen_.resize(num_vars_all_, vector<Vector3d>(num_collision_points_));
00141     joint_axes_.resize(num_vars_all_, vector<tf::Vector3>(num_joints_));
00142     joint_positions_.resize(num_vars_all_, vector<tf::Vector3>(num_joints_));
00143 
00144     collision_point_potential_.resize(num_vars_all_, vector<double>(num_collision_points_));
00145     collision_point_vel_mag_.resize(num_vars_all_, vector<double>(num_collision_points_));
00146     collision_point_potential_gradient_.resize(num_vars_all_, vector<Vector3d>(num_collision_points_));
00147 
00148     collision_free_iteration_ = 0;
00149     is_collision_free_ = false;
00150     state_is_in_collision_.resize(num_vars_all_);
00151     point_is_in_collision_.resize(num_vars_all_, vector<int>(num_collision_points_));
00152 
00153     last_improvement_iteration_ = -1;
00154 
00155     // HMC initialization:
00156     momentum_ = MatrixXd::Zero(num_vars_free_, num_joints_);
00157     random_momentum_ = MatrixXd::Zero(num_vars_free_, num_joints_);
00158     random_joint_momentum_ = VectorXd::Zero(num_vars_free_);
00159     multivariate_gaussian_.clear();
00160     stochasticity_factor_ = 1.0;
00161     for(int i = 0; i < num_joints_; i++)
00162     {
00163       multivariate_gaussian_.push_back(
00164                                        MultivariateGaussian(VectorXd::Zero(num_vars_free_),
00165                                                             joint_costs_[i].getQuadraticCostInverse()));
00166     }
00167 
00168     map<string, KinematicModel::JointModelGroup*> groupMap = robot_model_->getJointModelGroupMap();
00169     KinematicModel::JointModelGroup* modelGroup = groupMap[planning_group_];
00170     map<string, string> fixedLinkResolutionMap;
00171     for(int i = 0; i < num_joints_; i++)
00172     {
00173       joint_names_.push_back(modelGroup->getJointModels()[i]->getName());
00174       ROS_INFO("Got joint %s", joint_names_[i].c_str());
00175       registerParents(modelGroup->getJointModels()[i]);
00176       fixedLinkResolutionMap[joint_names_[i]] = joint_names_[i];
00177     }
00178 
00179     for(size_t i = 0; i < modelGroup->getFixedJointModels().size(); i ++)
00180     {
00181       const KinematicModel::JointModel* model = modelGroup->getFixedJointModels()[i];
00182       fixedLinkResolutionMap[model->getName()] = model->getParentLinkModel()->getParentJointModel()->getName();
00183     }
00184 
00185     for(size_t i = 0; i < modelGroup->getUpdatedLinkModels().size(); i ++)
00186     {
00187       if(fixedLinkResolutionMap.find(modelGroup->getUpdatedLinkModels()[i]->getParentJointModel()->getName()) == fixedLinkResolutionMap.end())
00188       {
00189         const KinematicModel::JointModel* parentModel = NULL;
00190         bool foundRoot = false;
00191 
00192         while(!foundRoot)
00193         {
00194           if(parentModel == NULL)
00195           {
00196             parentModel = modelGroup->getUpdatedLinkModels()[i]->getParentJointModel();
00197           }
00198           else
00199           {
00200             parentModel = parentModel->getParentLinkModel()->getParentJointModel();
00201             for(size_t j = 0; j < joint_names_.size(); j++)
00202             {
00203               if(parentModel->getName() == joint_names_[j])
00204               {
00205                 foundRoot = true;
00206               }
00207             }
00208           }
00209         }
00210         fixedLinkResolutionMap[modelGroup->getUpdatedLinkModels()[i]->getParentJointModel()->getName()] = parentModel->getName();
00211       }
00212     }
00213 
00214     for(map<string, map<string, bool> >::iterator it = joint_parent_map_.begin(); it != joint_parent_map_.end(); it++)
00215     {
00216       stringstream ss;
00217       ss << it->first << " Parents : {";
00218 
00219       for(map<string, bool>::iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
00220       {
00221         ss << it2->first << ",";
00222       }
00223       ss << "}";
00224       ROS_INFO("%s",ss.str().c_str());
00225     }
00226 
00227     int start = free_vars_start_;
00228     int end = free_vars_end_;
00229     vector<GradientInfo> gradients;
00230     collision_space_->getStateGradients(gradients);
00231     for(int i = start; i <= end; ++i)
00232     {
00233       size_t j = 0;
00234       for(size_t g = 0; g < gradients.size(); g++)
00235       {
00236         GradientInfo& info = gradients[g];
00237 
00238         for(size_t k = 0; k < info.sphere_locations.size(); k++)
00239         {
00240           if(fixedLinkResolutionMap.find(info.joint_name) != fixedLinkResolutionMap.end())
00241           {
00242             collision_point_joint_names_[i][j] = fixedLinkResolutionMap[info.joint_name];
00243           }
00244           else
00245           {
00246             ROS_ERROR("Couldn't find joint %s!", info.joint_name.c_str());
00247           }
00248           j++;
00249         }
00250       }
00251     }
00252   }
00253 
00254   ChompOptimizer::~ChompOptimizer()
00255   {
00256     destroy();
00257   }
00258 
00259   void ChompOptimizer::registerParents(const KinematicModel::JointModel* model)
00260   {
00261     const KinematicModel::JointModel* parentModel = NULL;
00262     bool foundRoot = false;
00263 
00264     if(model == robot_model_->getRoot()) return;
00265 
00266     while(!foundRoot)
00267     {
00268       if(parentModel == NULL)
00269       { 
00270         if(model->getParentLinkModel() == NULL) {
00271           ROS_ERROR_STREAM("Model " << model->getName() << " not root but has NULL link model parent");
00272           return;
00273         } else if(model->getParentLinkModel()->getParentJointModel() == NULL) {
00274           ROS_ERROR_STREAM("Model " << model->getName() << " not root but has NULL joint model parent");
00275           return;
00276         }
00277         parentModel = model->getParentLinkModel()->getParentJointModel();
00278       } else
00279       {
00280         if(parentModel == robot_model_->getRoot())
00281         {
00282           foundRoot = true;
00283         } else {
00284           parentModel = parentModel->getParentLinkModel()->getParentJointModel();
00285         }
00286       }
00287       joint_parent_map_[model->getName()][parentModel->getName()] = true;
00288     }
00289   }
00290 
00291   void ChompOptimizer::optimize()
00292   {
00293     ros::WallTime start_time = ros::WallTime::now();
00294     double averageCostVelocity = 0.0;
00295     int currentCostIter = 0;
00296     int costWindow = 10;
00297     vector<double>costs(costWindow, 0.0);
00298     double minimaThreshold = 0.05;
00299     bool shouldBreakOut = false;
00300 
00301     if(parameters_->getAnimatePath())
00302     {
00303       animatePath();
00304     }
00305 
00306     // iterate
00307     for(iteration_ = 0; iteration_ < parameters_->getMaxIterations(); iteration_++)
00308     {
00309       ros::WallTime for_time = ros::WallTime::now();
00310       performForwardKinematics();
00311       ROS_DEBUG_STREAM("Forward kinematics took " << (ros::WallTime::now()-for_time));
00312       double cCost = getCollisionCost();
00313       double sCost = getSmoothnessCost();
00314       double cost = cCost + sCost;
00315 
00316       if(parameters_->getAddRandomness() && currentCostIter != -1)
00317       {
00318         costs[currentCostIter] = cCost;
00319         currentCostIter++;
00320 
00321         if(currentCostIter >= costWindow)
00322         {
00323           for(int i = 1; i < costWindow; i++)
00324           {
00325             averageCostVelocity += (costs.at(i) - costs.at(i - 1));
00326           }
00327 
00328           averageCostVelocity /= (double)(costWindow);
00329           currentCostIter = -1;
00330         }
00331       }
00332       if(iteration_ == 0)
00333       {
00334         best_group_trajectory_ = group_trajectory_.getTrajectory();
00335         best_group_trajectory_cost_ = cost;
00336       }
00337       else
00338       {
00339         if(cost < best_group_trajectory_cost_)
00340         {
00341           best_group_trajectory_ = group_trajectory_.getTrajectory();
00342           best_group_trajectory_cost_ = cost;
00343           last_improvement_iteration_ = iteration_;
00344         }
00345       }
00346       calculateSmoothnessIncrements();
00347       ros::WallTime coll_time = ros::WallTime::now();
00348       calculateCollisionIncrements();
00349       ROS_DEBUG_STREAM("Collision increments took " << (ros::WallTime::now()-coll_time));
00350       calculateTotalIncrements();
00351 
00352       if(!parameters_->getUseHamiltonianMonteCarlo())
00353       {
00354         // non-stochastic version:
00355         addIncrementsToTrajectory();
00356       }
00357       else
00358       {
00359         // hamiltonian monte carlo updates:
00360         getRandomMomentum();
00361         updateMomentum();
00362         updatePositionFromMomentum();
00363         stochasticity_factor_ *= parameters_->getHmcAnnealingFactor();
00364       }
00365       handleJointLimits();
00366       updateFullTrajectory();
00367 
00368       if(iteration_ % 10 == 0)
00369       {
00370         ROS_DEBUG("Trajectory cost: %f (s=%f, c=%f)", getTrajectoryCost(), getSmoothnessCost(), getCollisionCost());
00371         CollisionProximitySpace::TrajectorySafety safety = checkCurrentIterValidity();
00372         if(safety == CollisionProximitySpace::MeshToMeshSafe) 
00373         {
00374           num_collision_free_iterations_ = 0;
00375           ROS_INFO("Chomp Got mesh to mesh safety at iter %d. Breaking out early.", iteration_);
00376           is_collision_free_ = true;
00377           iteration_++;
00378           shouldBreakOut = true;
00379         } else if(safety == CollisionProximitySpace::InCollisionSafe) {
00380           num_collision_free_iterations_ = parameters_->getMaxIterationsAfterCollisionFree();
00381           ROS_INFO("Chomp Got in collision safety at iter %d. Breaking out soon.", iteration_);
00382           is_collision_free_ = true;
00383           iteration_++;
00384           shouldBreakOut = true;
00385         }
00386         else
00387         {
00388           is_collision_free_ = false;
00389         }
00390       }
00391 
00392       if(!parameters_->getFilterMode())
00393       {
00394         if(cCost < parameters_->getCollisionThreshold())
00395         {
00396           is_collision_free_ = true;
00397           iteration_++;
00398           shouldBreakOut = true;
00399         }
00400       }
00401 
00402 
00403       if((ros::WallTime::now() - start_time).toSec() > parameters_->getPlanningTimeLimit() && !parameters_->getAnimatePath() && !parameters_->getAnimateEndeffector())
00404       {
00405         ROS_WARN("Breaking out early due to time limit constraints.");
00406         break;
00407       }
00408 
00409       if(fabs(averageCostVelocity) < minimaThreshold && currentCostIter == -1 && !is_collision_free_ && parameters_->getAddRandomness())
00410       {
00411         ROS_INFO("Detected local minima. Attempting to break out!");
00412         int iter = 0;
00413         bool success = false;
00414         while(iter < 20 && !success)
00415         {
00416           performForwardKinematics();
00417           double original_cost = getTrajectoryCost();
00418           group_trajectory_backup_ = group_trajectory_.getTrajectory();
00419           perturbTrajectory();
00420           handleJointLimits();
00421           updateFullTrajectory();
00422           performForwardKinematics();
00423           double new_cost = getTrajectoryCost();
00424           iter ++;
00425           if(new_cost < original_cost)
00426           {
00427             ROS_INFO("Got out of minimum in %d iters!", iter);
00428             averageCostVelocity = 0.0;
00429             currentCostIter = 0;
00430             success = true;
00431           }
00432           else
00433           {
00434             group_trajectory_.getTrajectory() = group_trajectory_backup_;
00435             updateFullTrajectory();
00436             currentCostIter = 0;
00437             averageCostVelocity = 0.0;
00438             success = false;
00439           }
00440 
00441         }
00442 
00443         if(!success)
00444         {
00445           ROS_INFO("Failed to exit minimum!");
00446         }
00447       }
00448       else if(currentCostIter == -1)
00449       {
00450         currentCostIter = 0;
00451         averageCostVelocity = 0.0;
00452       }
00453 
00454       if(parameters_->getAnimateEndeffector())
00455       {
00456         animateEndeffector();
00457       }
00458 
00459       if(parameters_->getAnimatePath() && iteration_ % 25 == 0)
00460       {
00461         animatePath();
00462       }
00463 
00464       if(shouldBreakOut)
00465       {
00466         collision_free_iteration_++;
00467         if(num_collision_free_iterations_ == 0) {
00468           break;
00469         } else if(collision_free_iteration_ > num_collision_free_iterations_)
00470         {
00471           CollisionProximitySpace::TrajectorySafety safety = checkCurrentIterValidity();
00472           if(safety != CollisionProximitySpace::MeshToMeshSafe &&
00473              safety != CollisionProximitySpace::InCollisionSafe) {
00474             ROS_WARN_STREAM("Apparently regressed");
00475           }
00476           break;
00477         }
00478       }
00479     }
00480 
00481     if(is_collision_free_)
00482     {
00483       ROS_INFO("Chomp path is collision free");
00484     }
00485     else
00486     {
00487       ROS_ERROR("Chomp path is not collision free!");
00488     }
00489 
00490     if(parameters_->getAnimatePath())
00491     {
00492       animatePath();
00493     }
00494 
00495     group_trajectory_.getTrajectory() = best_group_trajectory_;
00496     updateFullTrajectory();
00497 
00498     if(parameters_->getAnimatePath())
00499       animatePath();
00500 
00501     ROS_INFO("Terminated after %d iterations, using path from iteration %d", iteration_, last_improvement_iteration_);
00502     ROS_INFO("Optimization core finished in %f sec", (ros::WallTime::now() - start_time).toSec() );
00503     ROS_INFO_STREAM("Time per iteration " << (ros::WallTime::now() - start_time).toSec()/(iteration_*1.0));
00504   }
00505 
00506 CollisionProximitySpace::TrajectorySafety ChompOptimizer::checkCurrentIterValidity()
00507 {
00508     JointTrajectory jointTrajectory;
00509     jointTrajectory.joint_names = joint_names_;
00510     jointTrajectory.header.frame_id = collision_space_->getCollisionModelsInterface()->getRobotFrameId();
00511     jointTrajectory.header.stamp = ros::Time::now();
00512     Constraints goalConstraints;
00513     Constraints pathConstraints;
00514     ArmNavigationErrorCodes errorCode;
00515     vector<ArmNavigationErrorCodes> trajectoryErrorCodes;
00516     for(int i = 0; i < group_trajectory_.getNumPoints(); i++)
00517     {
00518       JointTrajectoryPoint point;
00519       for(int j = 0; j < group_trajectory_.getNumJoints(); j++)
00520       {
00521         point.positions.push_back(best_group_trajectory_(i, j));
00522       }
00523       jointTrajectory.points.push_back(point);
00524     }
00525 
00526     return collision_space_->isTrajectorySafe(jointTrajectory, goalConstraints, pathConstraints, planning_group_);
00527     /*
00528     bool valid = collision_space_->getCollisionModelsInterface()->isJointTrajectoryValid(*robot_state_,
00529                                                                                          jointTrajectory,
00530                                                                                          goalConstraints,
00531                                                                                          pathConstraints, errorCode,
00532                                                                                          trajectoryErrorCodes, false);
00533                                                                                          */
00534 
00535   }
00536 
00537   void ChompOptimizer::calculateSmoothnessIncrements()
00538   {
00539     for(int i = 0; i < num_joints_; i++)
00540     {
00541       joint_costs_[i].getDerivative(group_trajectory_.getJointTrajectory(i), smoothness_derivative_);
00542       smoothness_increments_.col(i)
00543          = -smoothness_derivative_.segment(group_trajectory_.getStartIndex(), num_vars_free_);
00544     }
00545   }
00546 
00547   void ChompOptimizer::calculateCollisionIncrements()
00548   {
00549     double potential;
00550     double vel_mag_sq;
00551     double vel_mag;
00552     Vector3d potential_gradient;
00553     Vector3d normalized_velocity;
00554     Matrix3d orthogonal_projector;
00555     Vector3d curvature_vector;
00556     Vector3d cartesian_gradient;
00557 
00558 
00559     collision_increments_.setZero(num_vars_free_, num_joints_);
00560 
00561     int startPoint = 0;
00562     int endPoint = free_vars_end_;
00563 
00564     // In stochastic descent, simply use a random point in the trajectory, rather than all the trajectory points.
00565     // This is faster and guaranteed to converge, but it may take more iterations in the worst case.
00566     if(parameters_->getUseStochasticDescent())
00567     {
00568       startPoint =  (int)(((double)random() / (double)RAND_MAX)*(free_vars_end_ - free_vars_start_) + free_vars_start_);
00569       if(startPoint < free_vars_start_) startPoint = free_vars_start_;
00570       if(startPoint > free_vars_end_) startPoint = free_vars_end_;
00571       endPoint = startPoint;
00572     }
00573     else
00574     {
00575       startPoint = free_vars_start_;
00576     }
00577 
00578     for(int i = startPoint; i <= endPoint; i++)
00579     {
00580       for(int j = 0; j < num_collision_points_; j++)
00581       {
00582         potential = collision_point_potential_[i][j];
00583 
00584         if(potential < 0.0001)
00585           continue;
00586 
00587         potential_gradient = -collision_point_potential_gradient_[i][j];
00588 
00589         vel_mag = collision_point_vel_mag_[i][j];
00590         vel_mag_sq = vel_mag * vel_mag;
00591 
00592         // all math from the CHOMP paper:
00593 
00594         normalized_velocity = collision_point_vel_eigen_[i][j] / vel_mag;
00595         orthogonal_projector = Matrix3d::Identity() - (normalized_velocity * normalized_velocity.transpose());
00596         curvature_vector = (orthogonal_projector * collision_point_acc_eigen_[i][j]) / vel_mag_sq;
00597         cartesian_gradient = vel_mag * (orthogonal_projector * potential_gradient - potential * curvature_vector);
00598 
00599         // pass it through the jacobian transpose to get the increments
00600         getJacobian(i, collision_point_pos_eigen_[i][j], collision_point_joint_names_[i][j] ,jacobian_);
00601 
00602         if(parameters_->getUsePseudoInverse())
00603         {
00604           calculatePseudoInverse();
00605           collision_increments_.row(i - free_vars_start_).transpose() -= jacobian_pseudo_inverse_ * cartesian_gradient;
00606         }
00607         else
00608         {
00609           collision_increments_.row(i - free_vars_start_).transpose() -= jacobian_.transpose() * cartesian_gradient;
00610         }
00611 
00612         /*
00613         if(point_is_in_collision_[i][j])
00614         {
00615           break;
00616         }
00617         */
00618       }
00619     }
00620     //cout << collision_increments_ << endl;
00621   }
00622 
00623   void ChompOptimizer::calculatePseudoInverse()
00624   {
00625     jacobian_jacobian_tranpose_ = jacobian_ * jacobian_.transpose() + MatrixXd::Identity(3, 3)
00626         * parameters_->getPseudoInverseRidgeFactor();
00627     jacobian_pseudo_inverse_ = jacobian_.transpose() * jacobian_jacobian_tranpose_.inverse();
00628   }
00629 
00630   void ChompOptimizer::calculateTotalIncrements()
00631   {
00632     for(int i = 0; i < num_joints_; i++)
00633     {
00634       final_increments_.col(i) = parameters_->getLearningRate() * (joint_costs_[i].getQuadraticCostInverse()
00635           * (parameters_->getSmoothnessCostWeight() * smoothness_increments_.col(i)
00636               + parameters_->getObstacleCostWeight() * collision_increments_.col(i)));
00637     }
00638 
00639   }
00640 
00641   void ChompOptimizer::addIncrementsToTrajectory()
00642   {
00643     map<string, KinematicModel::JointModelGroup*> modelGroups = robot_model_->getJointModelGroupMap();
00644     string group = planning_group_;
00645     const KinematicModel::JointModelGroup* modelGroup = modelGroups[group];
00646     const vector<const KinematicModel::JointModel*>& jointModels = modelGroup->getJointModels();
00647 
00648     for(size_t i = 0; i < jointModels.size(); i++)
00649     {
00650       double scale = 1.0;
00651       double max = final_increments_.col(i).maxCoeff();
00652       double min = final_increments_.col(i).minCoeff();
00653       double max_scale =  parameters_->getJointUpdateLimit() / fabs(max);
00654       double min_scale = parameters_->getJointUpdateLimit() / fabs(min);
00655       if(max_scale < scale)
00656         scale = max_scale;
00657       if(min_scale < scale)
00658         scale = min_scale;
00659       group_trajectory_.getFreeTrajectoryBlock().col(i) += scale * final_increments_.col(i);
00660     }
00661     //ROS_DEBUG("Scale: %f",scale);
00662     //group_trajectory_.getFreeTrajectoryBlock() += scale * final_increments_;
00663   }
00664 
00665   void ChompOptimizer::updateFullTrajectory()
00666   {
00667     full_trajectory_->updateFromGroupTrajectory(group_trajectory_);
00668   }
00669 
00670   void ChompOptimizer::debugCost()
00671   {
00672     double cost = 0.0;
00673     for(int i = 0; i < num_joints_; i++)
00674       cost += joint_costs_[i].getCost(group_trajectory_.getJointTrajectory(i));
00675     cout << "Cost = " << cost << endl;
00676   }
00677 
00678   double ChompOptimizer::getTrajectoryCost()
00679   {
00680     return getSmoothnessCost() + getCollisionCost();
00681   }
00682 
00683   double ChompOptimizer::getSmoothnessCost()
00684   {
00685     double smoothness_cost = 0.0;
00686     // joint costs:
00687     for(int i = 0; i < num_joints_; i++)
00688       smoothness_cost += joint_costs_[i].getCost(group_trajectory_.getJointTrajectory(i));
00689 
00690     return parameters_->getSmoothnessCostWeight() * smoothness_cost;
00691   }
00692 
00693   double ChompOptimizer::getCollisionCost()
00694   {
00695     double collision_cost = 0.0;
00696 
00697     double worst_collision_cost = 0.0;
00698     worst_collision_cost_state_ = -1;
00699 
00700     // collision costs:
00701     for(int i = free_vars_start_; i <= free_vars_end_; i++)
00702     {
00703       double state_collision_cost = 0.0;
00704       for(int j = 0; j < num_collision_points_; j++)
00705       {
00706         state_collision_cost += collision_point_potential_[i][j] * collision_point_vel_mag_[i][j];
00707       }
00708       collision_cost += state_collision_cost;
00709       if(state_collision_cost > worst_collision_cost)
00710       {
00711         worst_collision_cost = state_collision_cost;
00712         worst_collision_cost_state_ = i;
00713       }
00714     }
00715 
00716     return parameters_->getObstacleCostWeight() * collision_cost;
00717   }
00718 
00719   void ChompOptimizer::computeJointProperties(int trajectoryPoint)
00720   {
00721     tf::Transform inverseWorldTransform = collision_space_->getInverseWorldTransform(*robot_state_);
00722      for(int j = 0; j < num_joints_; j++)
00723      {
00724        string jointName = joint_names_[j];
00725        const KinematicState::JointState* jointState = robot_state_->getJointState(jointName);
00726        const KinematicModel::JointModel* jointModel = jointState->getJointModel();
00727        const KinematicModel::RevoluteJointModel* revoluteJoint = dynamic_cast<const KinematicModel::RevoluteJointModel*>(jointModel);
00728        const KinematicModel::PrismaticJointModel* prismaticJoint = dynamic_cast<const KinematicModel::PrismaticJointModel*>(jointModel);
00729 
00730        string parentLinkName = jointModel->getParentLinkModel()->getName();
00731        string childLinkName = jointModel->getChildLinkModel()->getName();
00732        tf::Transform jointTransform =
00733            robot_state_->getLinkState(parentLinkName)->getGlobalLinkTransform()
00734            * (robot_model_->getLinkModel(childLinkName)->getJointOriginTransform()
00735                * (robot_state_->getJointState(jointModel->getName())->getVariableTransform()));
00736 
00737 
00738        jointTransform = inverseWorldTransform * jointTransform;
00739        tf::Vector3 axis;
00740 
00741 
00742        if(revoluteJoint != NULL)
00743        {
00744          axis = revoluteJoint->axis_;
00745        }
00746        else if(prismaticJoint != NULL)
00747        {
00748          axis = prismaticJoint->axis_;
00749        }
00750 
00751        axis = jointTransform * axis;
00752 
00753        joint_axes_[trajectoryPoint][j] = axis;
00754        joint_positions_[trajectoryPoint][j] = jointTransform.getOrigin();
00755      }
00756   }
00757 
00758   template<typename Derived>
00759   void ChompOptimizer::getJacobian(int trajectoryPoint, Vector3d& collision_point_pos, string& jointName,
00760                                    MatrixBase<Derived>& jacobian) const
00761   {
00762     for(int j = 0; j < num_joints_; j++)
00763     {
00764       if(isParent(jointName, joint_names_[j]))
00765       {
00766         tf::Vector3 column = joint_axes_[trajectoryPoint][j].cross(tf::Vector3(collision_point_pos(0),
00767                                                                            collision_point_pos(1),
00768                                                                            collision_point_pos(2))
00769                                                                      - joint_positions_[trajectoryPoint][j]);
00770 
00771         jacobian.col(j)[0] = column.x();
00772         jacobian.col(j)[1] = column.y();
00773         jacobian.col(j)[2] = column.z();
00774       }
00775       else
00776       {
00777         jacobian.col(j)[0] = 0.0;
00778         jacobian.col(j)[1] = 0.0;
00779         jacobian.col(j)[2] = 0.0;
00780       }
00781     }
00782   }
00783 
00784   void ChompOptimizer::handleJointLimits()
00785   {
00786     map<string, KinematicModel::JointModelGroup*> modelGroups = robot_model_->getJointModelGroupMap();
00787     string group = planning_group_;
00788     KinematicModel::JointModelGroup* modelGroup = modelGroups[group];
00789 
00790     for(int joint = 0; joint < num_joints_; joint++)
00791     {
00792       const string& jointName = joint_names_[joint];
00793       const KinematicModel::JointModel* jointModel = modelGroup->getJointModel(jointName);
00794       const KinematicModel::RevoluteJointModel* revoluteJoint = dynamic_cast<const KinematicModel::RevoluteJointModel*>(jointModel);
00795 
00796       if(revoluteJoint->continuous_)
00797       {
00798         continue;
00799       }
00800       map<string, pair<double,double> > bounds = jointModel->getAllVariableBounds();
00801 
00802       double joint_max = -10000;
00803       double joint_min = 10000;
00804 
00805       for(map<string,pair<double,double> >::iterator it = bounds.begin(); it != bounds.end(); it ++)
00806       {
00807         if(it->second.first < joint_min)
00808         {
00809           joint_min = it->second.first;
00810         }
00811 
00812         if(it->second.second > joint_max)
00813         {
00814           joint_max = it->second.second;
00815         }
00816       }
00817 
00818 
00819       int count = 0;
00820 
00821       bool violation = false;
00822       do
00823       {
00824         double max_abs_violation = 1e-6;
00825         double max_violation = 0.0;
00826         int max_violation_index = 0;
00827         violation = false;
00828         for(int i = free_vars_start_; i <= free_vars_end_; i++)
00829         {
00830           double amount = 0.0;
00831           double absolute_amount = 0.0;
00832           if(group_trajectory_(i, joint) > joint_max)
00833           {
00834             amount = joint_max - group_trajectory_(i, joint);
00835             absolute_amount = fabs(amount);
00836           }
00837           else if(group_trajectory_(i, joint) < joint_min)
00838           {
00839             amount = joint_min - group_trajectory_(i, joint);
00840             absolute_amount = fabs(amount);
00841           }
00842           if(absolute_amount > max_abs_violation)
00843           {
00844             max_abs_violation = absolute_amount;
00845             max_violation = amount;
00846             max_violation_index = i;
00847             violation = true;
00848           }
00849         }
00850 
00851         if(violation)
00852         {
00853           int free_var_index = max_violation_index - free_vars_start_;
00854           double multiplier = max_violation / joint_costs_[joint].getQuadraticCostInverse()(free_var_index,
00855                                                                                             free_var_index);
00856           group_trajectory_.getFreeJointTrajectoryBlock(joint) += multiplier
00857               * joint_costs_[joint].getQuadraticCostInverse().col(free_var_index);
00858         }
00859         if(++count > 10)
00860           break;
00861       }
00862       while(violation);
00863     }
00864   }
00865 
00866   void ChompOptimizer::performForwardKinematics()
00867   {
00868     double invTime = 1.0 / group_trajectory_.getDiscretization();
00869     double invTimeSq = invTime * invTime;
00870 
00871     // calculate the forward kinematics for the fixed states only in the first iteration:
00872     int start = free_vars_start_;
00873     int end = free_vars_end_;
00874     if(iteration_ == 0)
00875     {
00876       start = 0;
00877       end = num_vars_all_ - 1;
00878     }
00879 
00880     is_collision_free_ = true;
00881 
00882     // for each point in the trajectory
00883     for(int i = start; i <= end; ++i)
00884     {
00885       // Set Robot state from trajectory point...
00886       setRobotStateFromPoint(group_trajectory_, i);
00887       computeJointProperties(i);
00888       state_is_in_collision_[i] = false;
00889 
00890       vector<GradientInfo> gradients;
00891       collision_space_->getStateGradients(gradients);
00892       //Keep vars in scope
00893       {
00894         size_t j = 0;
00895         for(size_t g = 0; g < gradients.size(); g++)
00896         {
00897           GradientInfo& info = gradients[g];
00898 
00899           for(size_t k = 0; k < info.sphere_locations.size(); k++)
00900           {
00901             collision_point_pos_eigen_[i][j][0] = info.sphere_locations[k].x();
00902             collision_point_pos_eigen_[i][j][1] = info.sphere_locations[k].y();
00903             collision_point_pos_eigen_[i][j][2] = info.sphere_locations[k].z();
00904 
00905             collision_point_potential_[i][j] = getPotential(info.distances[k], info.sphere_radii[k], parameters_->getMinClearence());
00906             collision_point_potential_gradient_[i][j][0] = info.gradients[k].x();
00907             collision_point_potential_gradient_[i][j][1] = info.gradients[k].y();
00908             collision_point_potential_gradient_[i][j][2] = info.gradients[k].z();
00909 
00910             point_is_in_collision_[i][j] = (info.distances[k] - info.sphere_radii[k] < info.sphere_radii[k]);
00911 
00912             if(point_is_in_collision_[i][j])
00913             {
00914               state_is_in_collision_[i] = true;
00915               is_collision_free_ = false;
00916             }
00917             j ++;
00918           }
00919         }
00920       }
00921     }
00922 
00923     // now, get the vel and acc for each collision point (using finite differencing)
00924     for(int i = free_vars_start_; i <= free_vars_end_; i++)
00925     {
00926       for(int j = 0; j < num_collision_points_; j++)
00927       {
00928         collision_point_vel_eigen_[i][j] = Vector3d(0,0,0);
00929         collision_point_acc_eigen_[i][j] = Vector3d(0,0,0);
00930         for(int k = -DIFF_RULE_LENGTH / 2; k <= DIFF_RULE_LENGTH / 2; k++)
00931         {
00932           collision_point_vel_eigen_[i][j] += (invTime * DIFF_RULES[0][k + DIFF_RULE_LENGTH / 2]) * collision_point_pos_eigen_[i
00933               + k][j];
00934           collision_point_acc_eigen_[i][j] += (invTimeSq * DIFF_RULES[1][k + DIFF_RULE_LENGTH / 2]) * collision_point_pos_eigen_[i
00935               + k][j];
00936         }
00937 
00938         // get the norm of the velocity:
00939         collision_point_vel_mag_[i][j] = collision_point_vel_eigen_[i][j].norm();
00940       }
00941     }
00942   }
00943 
00944   void ChompOptimizer::setRobotStateFromPoint(ChompTrajectory& group_trajectory, int i)
00945   {
00946     const MatrixXd::RowXpr& point = group_trajectory.getTrajectoryPoint(i);
00947 
00948     vector<double> jointStates;
00949     for(int j = 0; j < group_trajectory.getNumJoints(); j ++)
00950     {
00951       jointStates.push_back(point(0,j));
00952     }
00953 
00954     ros::WallTime timer = ros::WallTime::now();
00955     KinematicState::JointStateGroup* group = (KinematicState::JointStateGroup*)(robot_state_->getJointStateGroup(planning_group_));
00956     group->setKinematicState(jointStates);
00957     timer = ros::WallTime::now();
00958     collision_space_->setCurrentGroupState(*robot_state_);
00959   }
00960 
00961   void ChompOptimizer::perturbTrajectory()
00962   {
00963     //int mid_point = (free_vars_start_ + free_vars_end_) / 2;
00964     if(worst_collision_cost_state_ < 0)
00965       return;
00966     int mid_point = worst_collision_cost_state_;
00967     getRandomState(robot_state_, planning_group_, random_state_);
00968 
00969     // convert the state into an increment
00970     random_state_ -= group_trajectory_.getTrajectoryPoint(mid_point).transpose();
00971 
00972     // project the increment orthogonal to joint velocities
00973     group_trajectory_.getJointVelocities(mid_point, joint_state_velocities_);
00974     joint_state_velocities_.normalize();
00975     random_state_ = (MatrixXd::Identity(num_joints_, num_joints_) - joint_state_velocities_
00976         * joint_state_velocities_.transpose()) * random_state_;
00977 
00978     int mp_free_vars_index = mid_point - free_vars_start_;
00979     for(int i = 0; i < num_joints_; i++)
00980     {
00981       group_trajectory_.getFreeJointTrajectoryBlock(i)
00982           += joint_costs_[i].getQuadraticCostInverse().col(mp_free_vars_index) * random_state_(i);
00983     }
00984   }
00985 
00986   void ChompOptimizer::getRandomState(const KinematicState* currentState, const string& groupName, VectorXd& state_vec)
00987   {
00988     const vector<KinematicState::JointState*>& jointStates =
00989         currentState->getJointStateGroup(groupName)->getJointStateVector();
00990     for(size_t i = 0; i < jointStates.size(); i++)
00991     {
00992 
00993       bool continuous = false;
00994       
00995       KinematicState::JointState* jointState = jointStates[i];
00996       const KinematicModel::RevoluteJointModel* revolute_joint 
00997         = dynamic_cast<const KinematicModel::RevoluteJointModel*>(jointState->getJointModel());
00998       if(revolute_joint && revolute_joint->continuous_) {
00999         continuous = true;
01000       }
01001       
01002       map<string, pair<double, double> > bounds = jointState->getJointModel()->getAllVariableBounds();
01003       int j = 0;
01004       for(map<string, pair<double, double> >::iterator it = bounds.begin(); it != bounds.end(); it++)
01005       {
01006         double randVal = jointState->getJointStateValues()[j] + (getRandomDouble()
01007                                                                  * (parameters_->getRandomJumpAmount()) - getRandomDouble() * (parameters_->getRandomJumpAmount()));
01008 
01009         if(!continuous) 
01010         {
01011           if(randVal > it->second.second)
01012           {
01013             randVal = it->second.second;
01014           }
01015           else if(randVal < it->second.first)
01016           {
01017             randVal = it->second.first;
01018           }
01019         }
01020 
01021         ROS_DEBUG_STREAM("Joint " << it->first << " old value " << jointState->getJointStateValues()[j] << " new value " << randVal);
01022         state_vec(i) = randVal;
01023         
01024         j++;
01025       }
01026     }
01027   }
01028 
01029   void ChompOptimizer::getRandomMomentum()
01030   {
01031     if(is_collision_free_)
01032       random_momentum_.setZero(num_vars_free_, num_joints_);
01033     else
01034       for(int i = 0; i < num_joints_; ++i)
01035       {
01036         multivariate_gaussian_[i].sample(random_joint_momentum_);
01037         random_momentum_.col(i) = stochasticity_factor_ * random_joint_momentum_;
01038       }
01039   }
01040 
01041   void ChompOptimizer::updateMomentum()
01042   {
01043     //double alpha = 1.0 - parameters_->getHmcStochasticity();
01044     double eps = parameters_->getHmcDiscretization();
01045     if(iteration_ > 0)
01046       momentum_ = (momentum_ + eps * final_increments_);
01047     else
01048       momentum_ = random_momentum_;
01049     //momentum_ = alpha * (momentum_ + eps*final_increments_) + sqrt(1.0-alpha*alpha)*random_momentum_;
01050   }
01051 
01052   void ChompOptimizer::updatePositionFromMomentum()
01053   {
01054     double eps = parameters_->getHmcDiscretization();
01055     group_trajectory_.getFreeTrajectoryBlock() += eps * momentum_;
01056   }
01057 
01058   void ChompOptimizer::animatePath()
01059   {
01060     for(int i = free_vars_start_; i <= free_vars_end_; i++)
01061     {
01062       visualizeState(i);
01063       //ros::WallDuration(group_trajectory_.getDiscretization()).sleep();
01064       ros::WallDuration(.05).sleep();
01065     }
01066   }
01067 
01068   void ChompOptimizer::animateEndeffector()
01069   {
01070     visualization_msgs::Marker msg;
01071     msg.points.resize(num_vars_free_);
01072     // int joint_index = planning_group_->chomp_joints_[num_joints_-1].kdl_joint_index_;
01073     int sn = (int)(num_collision_points_ - 1);
01074     for(int i = 0; i < num_vars_free_; ++i)
01075     {
01076       int j = i + free_vars_start_;
01077       msg.points[i].x = collision_point_pos_eigen_[j][sn][0];
01078       msg.points[i].y = collision_point_pos_eigen_[j][sn][1];
01079       msg.points[i].z = collision_point_pos_eigen_[j][sn][2];
01080     }
01081     msg.header.frame_id = collision_space_->getCollisionModelsInterface()->getRobotFrameId();
01082     msg.header.stamp = ros::Time();
01083     msg.ns = "chomp_endeffector";
01084     msg.id = 0;
01085     msg.type = visualization_msgs::Marker::SPHERE_LIST;
01086     msg.action = visualization_msgs::Marker::ADD;
01087     double scale = 0.05;
01088     msg.scale.x = scale;
01089     msg.scale.y = scale;
01090     msg.scale.z = scale;
01091     msg.color.a = 0.6;
01092     msg.color.r = 0.5;
01093     msg.color.g = 1.0;
01094     msg.color.b = 0.3;
01095     vis_marker_pub_.publish(msg);
01096     ros::WallDuration(0.1).sleep();
01097 
01098   }
01099 
01100   void ChompOptimizer::visualizeState(int index)
01101   {
01102 
01103     visualization_msgs::MarkerArray msg;
01104     msg.markers.resize(num_collision_points_ + num_joints_);
01105     int num_arrows = 0;
01106     double potential_threshold = 1e-10;
01107     for(int i = 0; i < num_collision_points_; i++)
01108     {
01109       msg.markers[i].header.frame_id = collision_space_->getCollisionModelsInterface()->getRobotFrameId();
01110       msg.markers[i].header.stamp = ros::Time();
01111       msg.markers[i].ns = "chomp_collisions";
01112       msg.markers[i].id = i;
01113       msg.markers[i].type = visualization_msgs::Marker::SPHERE;
01114       msg.markers[i].action = visualization_msgs::Marker::ADD;
01115       msg.markers[i].pose.position.x = collision_point_pos_eigen_[index][i][0];
01116       msg.markers[i].pose.position.y = collision_point_pos_eigen_[index][i][1];
01117       msg.markers[i].pose.position.z = collision_point_pos_eigen_[index][i][2];
01118       msg.markers[i].pose.orientation.x = 0.0;
01119       msg.markers[i].pose.orientation.y = 0.0;
01120       msg.markers[i].pose.orientation.z = 0.0;
01121       msg.markers[i].pose.orientation.w = 1.0;
01122       double scale = 0.1;
01123       msg.markers[i].scale.x = scale;
01124       msg.markers[i].scale.y = scale;
01125       msg.markers[i].scale.z = scale;
01126       msg.markers[i].color.a = 0.6;
01127       msg.markers[i].color.r = 0.5;
01128       msg.markers[i].color.g = 1.0;
01129       msg.markers[i].color.b = 0.3;
01130       if(collision_point_potential_[index][i] > potential_threshold)
01131         num_arrows++;
01132     }
01133 
01134     vis_marker_array_pub_.publish(msg);
01135 
01136     // publish arrows for distance field:
01137     msg.markers.resize(0);
01138     msg.markers.resize(num_collision_points_);
01139     for(int i = 0; i < num_collision_points_; i++)
01140     {
01141       msg.markers[i].header.frame_id = collision_space_->getCollisionModelsInterface()->getRobotFrameId();
01142       msg.markers[i].header.stamp = ros::Time();
01143       msg.markers[i].ns = "chomp_arrows";
01144       msg.markers[i].id = i;
01145       msg.markers[i].type = visualization_msgs::Marker::ARROW;
01146       msg.markers[i].action = visualization_msgs::Marker::ADD;
01147       msg.markers[i].points.resize(2);
01148       msg.markers[i].points[0].x = collision_point_pos_eigen_[index][i](0);
01149       msg.markers[i].points[0].y = collision_point_pos_eigen_[index][i](1);
01150       msg.markers[i].points[0].z = collision_point_pos_eigen_[index][i](2);
01151       msg.markers[i].points[1] = msg.markers[i].points[0];
01152       double scale = 0.25f;
01153       if(collision_point_potential_[index][i] <= potential_threshold)
01154         scale = 0.0;
01155       msg.markers[i].points[1].x += scale * collision_point_potential_gradient_[index][i](0);
01156       msg.markers[i].points[1].y += scale * collision_point_potential_gradient_[index][i](1);
01157       msg.markers[i].points[1].z += scale * collision_point_potential_gradient_[index][i](2);
01158       msg.markers[i].scale.x = 0.01;
01159       msg.markers[i].scale.y = 0.03;
01160       msg.markers[i].color.a = 0.5;
01161       msg.markers[i].color.r = 0.5;
01162       msg.markers[i].color.g = 0.5;
01163       msg.markers[i].color.b = 1.0;
01164     }
01165     vis_marker_array_pub_.publish(msg);
01166 
01167   }
01168 
01169 } // namespace chomp


chomp_motion_planner
Author(s): Mrinal Kalakrishnan / mail@mrinal.net
autogenerated on Thu Dec 12 2013 11:08:58