00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 #include <kinematics_cache/kinematics_cache.h>
00039 #include <fstream>
00040 #include <iostream>
00041 
00042 namespace kinematics_cache
00043 {
00044 KinematicsCache::KinematicsCache() : min_squared_distance_(1e6), max_squared_distance_(0.0)
00045 {
00046 }
00047 
00048 bool KinematicsCache::initialize(kinematics::KinematicsBaseConstPtr& kinematics_solver,
00049                                  const planning_models::RobotModelConstPtr& kinematic_model,
00050                                  const KinematicsCache::Options& opt)
00051 {
00052   options_ = opt;
00053   kinematics_solver_ = kinematics_solver;
00054   kinematic_model_ = kinematic_model;
00055   joint_model_group_ = kinematic_model_->getJointModelGroup(kinematics_solver_->getGroupName());
00056   kinematic_state_.reset(new planning_models::RobotState(kinematic_model));
00057   joint_state_group_.reset(
00058       new planning_models::RobotState* ::JointStateGroup(kinematic_state_.get(), joint_model_group_));
00059 
00060   setup(opt);
00061   return true;
00062 }
00063 
00064 void KinematicsCache::setup(const KinematicsCache::Options& opt)
00065 {
00066   cache_origin_ = opt.origin;
00067   cache_resolution_x_ = opt.resolution[0];
00068   cache_resolution_y_ = opt.resolution[1];
00069   cache_resolution_z_ = opt.resolution[2];
00070 
00071   cache_size_x_ = (unsigned int)(opt.workspace_size[0] / opt.resolution[0]);
00072   cache_size_y_ = (unsigned int)(opt.workspace_size[1] / opt.resolution[1]);
00073   cache_size_z_ = (unsigned int)(opt.workspace_size[2] / opt.resolution[2]);
00074   max_solutions_per_grid_location_ = std::max((unsigned int)1, opt.max_solutions_per_grid_location);
00075   solution_dimension_ = joint_model_group_->getVariableCount();
00076   size_grid_node_ = max_solutions_per_grid_location_ * solution_dimension_;
00077   kinematics_cache_size_ = cache_size_x_ * cache_size_y_ * cache_size_z_;
00078   kinematics_cache_points_with_solution_ = 0;
00079   kinematics_cache_vector_.resize(kinematics_cache_size_ * size_grid_node_, 0.0);
00080   num_solutions_vector_.resize(kinematics_cache_size_, 0);
00081   ROS_DEBUG("Origin: %f %f %f", cache_origin_.x, cache_origin_.y, cache_origin_.z);
00082   ROS_DEBUG("Cache size (num points x,y,z): %d %d %d", cache_size_x_, cache_size_y_, cache_size_z_);
00083   ROS_DEBUG("Cache resolution: %f %f %f", cache_resolution_x_, cache_resolution_y_, cache_resolution_z_);
00084   ROS_DEBUG("Solutions per grid location: %d", (int)max_solutions_per_grid_location_);
00085   ROS_DEBUG("Solution dimension: %d", (int)solution_dimension_);
00086 }
00087 
00088 bool KinematicsCache::generateCacheMap(double timeout)
00089 {
00090   ros::WallTime start_time = ros::WallTime::now();
00091   std::vector<std::string> fk_names;
00092   std::vector<double> fk_values;
00093   std::vector<geometry_msgs::Pose> poses;
00094 
00095   fk_names.push_back(kinematics_solver_->getTipFrame());
00096   fk_values.resize(kinematics_solver_->getJointNames().size(), 0.0);
00097   poses.resize(1);
00098 
00099   while ((ros::WallTime::now() - start_time).toSec() <= timeout &&
00100          kinematics_cache_points_with_solution_ <= kinematics_cache_size_)
00101   {
00102     joint_state_group_->setToRandomValues();
00103     joint_state_group_->getGroupStateValues(fk_values);
00104     if (!kinematics_solver_->getPositionFK(fk_names, fk_values, poses))
00105     {
00106       ROS_ERROR("Fk failed");
00107       return false;
00108     }
00109     if (!addToCache(poses[0], fk_values))
00110     {
00111       ROS_DEBUG("Adding to cache failed for: %f %f %f", poses[0].position.x, poses[0].position.y, poses[0].position.z);
00112     }
00113     ROS_DEBUG("Adding: %d", kinematics_cache_points_with_solution_);
00114   }
00115   ROS_INFO("Cache map generated with %d valid points", kinematics_cache_points_with_solution_);
00116   return true;
00117 }
00118 
00119 bool KinematicsCache::addToCache(const geometry_msgs::Pose& pose, const std::vector<double>& joint_values,
00120                                  bool overwrite)
00121 {
00122   unsigned int grid_index;
00123   if (!getGridIndex(pose, grid_index))
00124   {
00125     ROS_DEBUG("Failed to get grid index");
00126     return false;
00127   }
00128   unsigned int num_solutions = num_solutions_vector_[grid_index];
00129   if (!overwrite && num_solutions >= max_solutions_per_grid_location_)
00130   {
00131     ROS_DEBUG("Pose already has max number of solutions");
00132     return true;
00133   }
00134   if (num_solutions == 0)
00135     kinematics_cache_points_with_solution_++;
00136   if (overwrite && num_solutions >= max_solutions_per_grid_location_)
00137     num_solutions = 0;
00138   unsigned int start_index = getSolutionLocation(grid_index, num_solutions);
00139   for (unsigned int i = 0; i < joint_values.size(); ++i)
00140   {
00141     
00142     kinematics_cache_vector_[start_index + i] = joint_values[i];
00143   }
00144   if (num_solutions_vector_[grid_index] < max_solutions_per_grid_location_)
00145     num_solutions_vector_[grid_index]++;
00146   updateDistances(pose);
00147   return true;
00148 }
00149 
00150 bool KinematicsCache::getGridIndex(const geometry_msgs::Pose& pose, unsigned int& grid_index) const
00151 {
00152   int x_index = (int)((pose.position.x - cache_origin_.x) / cache_resolution_x_);
00153   int y_index = (int)((pose.position.y - cache_origin_.y) / cache_resolution_y_);
00154   int z_index = (int)((pose.position.z - cache_origin_.z) / cache_resolution_z_);
00155 
00156   if (x_index >= (int)cache_size_x_ || x_index < 0)
00157   {
00158     ROS_DEBUG("X position %f,%d lies outside grid: %d %d", pose.position.x, x_index, 0, cache_size_x_);
00159     return false;
00160   }
00161   if (y_index >= (int)cache_size_y_ || y_index < 0)
00162   {
00163     ROS_DEBUG("Y position %f,%d lies outside grid: %d %d", pose.position.y, y_index, 0, cache_size_y_);
00164     return false;
00165   }
00166   if (z_index >= (int)cache_size_z_ || z_index < 0)
00167   {
00168     ROS_DEBUG("Z position %f,%d lies outside grid: %d %d", pose.position.z, z_index, 0, cache_size_z_);
00169     return false;
00170   }
00171   ROS_DEBUG("Grid indices: %d %d %d", x_index, y_index, z_index);
00172   grid_index = (x_index + y_index * cache_size_x_ + z_index * cache_size_x_ * cache_size_y_);
00173   return true;
00174 }
00175 
00176 bool KinematicsCache::getNumSolutions(const geometry_msgs::Pose& pose, unsigned int& num_solutions) const
00177 {
00178   unsigned int grid_index;
00179   if (!getGridIndex(pose, grid_index))
00180     return false;
00181 
00182   num_solutions = num_solutions_vector_[grid_index];
00183   return true;
00184 }
00185 
00186 unsigned int KinematicsCache::getSolutionLocation(unsigned int& grid_index, unsigned int& solution_index) const
00187 {
00188   ROS_DEBUG("[Grid Index, Solution number location]: %d, %d", grid_index,
00189             grid_index * size_grid_node_ + solution_index * solution_dimension_);
00190   return (grid_index * size_grid_node_ + solution_index * solution_dimension_);
00191 }
00192 
00193 bool KinematicsCache::getSolution(const geometry_msgs::Pose& pose, unsigned int solution_index,
00194                                   std::vector<double>& solution) const
00195 {
00196   unsigned int grid_index;
00197   if (!getGridIndex(pose, grid_index))
00198     return false;
00199   if (solution_index >= max_solutions_per_grid_location_)
00200     return false;
00201   if (solution.size() < solution_dimension_)
00202     return false;
00203 
00204   solution = getSolution(grid_index, solution_index);
00205   return true;
00206 }
00207 
00208 bool KinematicsCache::getSolutions(const geometry_msgs::Pose& pose, std::vector<std::vector<double> >& solution) const
00209 {
00210   unsigned int grid_index;
00211   if (!getGridIndex(pose, grid_index))
00212     return false;
00213   if (solution.size() != num_solutions_vector_[grid_index])
00214     return false;
00215   for (unsigned int i = 0; i < solution.size(); i++)
00216   {
00217     if (solution[i].size() != solution_dimension_)
00218       return false;
00219     solution[i] = getSolution(grid_index, i);
00220   }
00221   return true;
00222 }
00223 
00224 std::vector<double> KinematicsCache::getSolution(unsigned int grid_index, unsigned int solution_index) const
00225 {
00226   std::vector<double> solution_local(solution_dimension_);
00227   unsigned int solution_location = getSolutionLocation(grid_index, solution_index);
00228   for (unsigned int i = 0; i < solution_dimension_; ++i)
00229     solution_local[i] = kinematics_cache_vector_[solution_location + i];
00230   return solution_local;
00231 }
00232 
00233 bool KinematicsCache::readFromFile(const std::string& filename)
00234 {
00235   std::ifstream file(filename.c_str());
00236   if (!file.is_open())
00237   {
00238     ROS_WARN("Could not open file: %s", filename.c_str());
00239     return false;
00240   }
00241   std::string group_name;
00242   std::getline(file, group_name);
00243   if (group_name.empty())
00244   {
00245     ROS_ERROR("Could not find group_name in file: %s", group_name.c_str());
00246     file.close();
00247     return false;
00248   }
00249   if (group_name != kinematics_solver_->getGroupName())
00250   {
00251     ROS_ERROR("Input file group name %s does not match solver group name %s", group_name.c_str(),
00252               kinematics_solver_->getGroupName().c_str());
00253     file.close();
00254     return false;
00255   }
00256 
00257   std::string line_string;
00258   std::getline(file, line_string);
00259   std::stringstream line_stream(line_string);
00260   line_stream >> options_.origin.x >> options_.origin.y >> options_.origin.z;
00261 
00262   std::getline(file, line_string);
00263   line_stream.clear();
00264   line_stream.str("");
00265   line_stream << line_string;
00266   line_stream >> options_.workspace_size[0] >> options_.workspace_size[1] >> options_.workspace_size[2];
00267 
00268   std::getline(file, line_string);
00269   line_stream.clear();
00270   line_stream.str("");
00271   line_stream << line_string;
00272   line_stream >> options_.resolution[0] >> options_.resolution[1] >> options_.resolution[2];
00273 
00274   std::getline(file, line_string);
00275   line_stream.clear();
00276   line_stream.str("");
00277   line_stream << line_string;
00278   line_stream >> options_.max_solutions_per_grid_location;
00279 
00280   setup(options_);
00281 
00282   std::getline(file, line_string);
00283   line_stream.clear();
00284   line_stream.str("");
00285   line_stream << line_string;
00286   line_stream >> min_squared_distance_;
00287 
00288   std::getline(file, line_string);
00289   line_stream.clear();
00290   line_stream.str("");
00291   line_stream << line_string;
00292   line_stream >> max_squared_distance_;
00293 
00294   std::vector<double> kinematics_cache_vector;
00295   std::vector<unsigned int> num_solutions_vector;
00296   std::getline(file, line_string);
00297   std::getline(file, line_string);
00298   line_stream.clear();
00299   line_stream.str("");
00300   line_stream << line_string;
00301   double d;
00302   while (line_stream >> d)
00303   {
00304     kinematics_cache_vector.push_back(d);
00305   }
00306 
00307   std::getline(file, line_string);
00308   std::getline(file, line_string);
00309   line_stream.clear();
00310   line_stream.str("");
00311   line_stream << line_string;
00312   unsigned int index;
00313   while (line_stream >> index)
00314   {
00315     num_solutions_vector.push_back(index);
00316   }
00317 
00318   file.close();
00319 
00320   kinematics_cache_vector_ = kinematics_cache_vector;
00321   num_solutions_vector_ = num_solutions_vector;
00322   ROS_DEBUG("Read %d total points from file: %s", (int)num_solutions_vector_.size(), filename.c_str());
00323   return true;
00324 }
00325 
00326 bool KinematicsCache::writeToFile(const std::string& filename)
00327 {
00328   ROS_DEBUG("Writing %d total points to file: %s", (int)num_solutions_vector_.size(), filename.c_str());
00329   std::ofstream file;
00330   file.open(filename.c_str());
00331   if (!file.is_open())
00332   {
00333     ROS_WARN("Could not open file: %s", filename.c_str());
00334     return false;
00335   }
00336   if (file.good())
00337   {
00338     std::string group_name = kinematics_solver_->getGroupName();
00339     file << group_name << std::endl;
00340 
00341     file << options_.origin.x << " " << options_.origin.y << " " << options_.origin.z << std::endl;
00342     file << options_.workspace_size[0] << " " << options_.workspace_size[1] << " " << options_.workspace_size[2]
00343          << std::endl;
00344     file << options_.resolution[0] << " " << options_.resolution[1] << " " << options_.resolution[2] << std::endl;
00345     file << options_.max_solutions_per_grid_location << std::endl;
00346     file << min_squared_distance_ << std::endl;
00347     file << max_squared_distance_ << std::endl;
00348     file << kinematics_cache_vector_.size() << std::endl;
00349     std::copy(kinematics_cache_vector_.begin(), kinematics_cache_vector_.end(),
00350               std::ostream_iterator<double>(file, " "));
00351     file << std::endl;
00352 
00353     file << num_solutions_vector_.size() << std::endl;
00354     std::copy(num_solutions_vector_.begin(), num_solutions_vector_.end(),
00355               std::ostream_iterator<unsigned int>(file, " "));
00356     file << std::endl;
00357   }
00358 
00359   file.close();
00360   return true;
00361 }
00362 
00363 std::pair<double, double> KinematicsCache::getMinMaxSquaredDistance()
00364 {
00365   return std::pair<double, double>(min_squared_distance_, max_squared_distance_);
00366 }
00367 
00368 void KinematicsCache::updateDistances(const geometry_msgs::Pose& pose)
00369 {
00370   double distance_squared =
00371       (pose.position.x * pose.position.x + pose.position.y * pose.position.y + pose.position.z * pose.position.z);
00372   min_squared_distance_ = std::min<double>(distance_squared, min_squared_distance_);
00373   max_squared_distance_ = std::max<double>(distance_squared, max_squared_distance_);
00374 }
00375 }