ik_cache.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2017, Rice University
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the Rice University nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Mark Moll */
36 
37 #include <boost/filesystem/fstream.hpp>
38 #include <numeric>
39 
41 
43 {
45 {
46  // set distance function for nearest-neighbor queries
47  ik_nn_.setDistanceFunction([](const IKEntry* entry1, const IKEntry* entry2) {
48  double dist = 0.;
49  for (unsigned int i = 0; i < entry1->first.size(); ++i)
50  dist += entry1->first[i].distance(entry2->first[i]);
51  return dist;
52  });
53 }
54 
56 {
57  if (!ik_cache_.empty())
58  saveCache();
59 }
60 
61 void IKCache::initializeCache(const std::string& robot_id, const std::string& group_name, const std::string& cache_name,
62  const unsigned int num_joints, const Options& opts)
63 {
64  // read ROS parameters
65  max_cache_size_ = opts.max_cache_size;
66  ik_cache_.reserve(max_cache_size_);
67  min_pose_distance_ = opts.min_pose_distance;
68  min_config_distance2_ = opts.min_joint_config_distance;
70  std::string cached_ik_path = opts.cached_ik_path;
71 
72  // use mutex lock for rest of initialization
73  std::lock_guard<std::mutex> slock(lock_);
74  // determine cache file name
75  boost::filesystem::path prefix(!cached_ik_path.empty() ? cached_ik_path : boost::filesystem::current_path());
76  // create cache directory if necessary
77  boost::filesystem::create_directories(prefix);
78 
79  cache_file_name_ = prefix / (robot_id + group_name + "_" + cache_name + "_" + std::to_string(max_cache_size_) + "_" +
80  std::to_string(min_pose_distance_) + "_" +
81  std::to_string(std::sqrt(min_config_distance2_)) + ".ikcache");
82 
83  ik_cache_.clear();
84  ik_nn_.clear();
86  if (boost::filesystem::exists(cache_file_name_))
87  {
88  // read cache
89  boost::filesystem::ifstream cache_file(cache_file_name_, std::ios_base::binary | std::ios_base::in);
90  cache_file.read((char*)&last_saved_cache_size_, sizeof(unsigned int));
91  unsigned int num_dofs;
92  cache_file.read((char*)&num_dofs, sizeof(unsigned int));
93  unsigned int num_tips;
94  cache_file.read((char*)&num_tips, sizeof(unsigned int));
95 
96  ROS_INFO_NAMED("cached_ik", "Found %d IK solutions for a %d-dof system with %d end effectors in %s",
97  last_saved_cache_size_, num_dofs, num_tips, cache_file_name_.string().c_str());
98 
99  unsigned int position_size = 3 * sizeof(tf2Scalar);
100  unsigned int orientation_size = 4 * sizeof(tf2Scalar);
101  unsigned int pose_size = position_size + orientation_size;
102  unsigned int config_size = num_dofs * sizeof(double);
103  unsigned int offset_conf = pose_size * num_tips;
104  unsigned int bufsize = offset_conf + config_size;
105  char* buffer = new char[bufsize];
106  IKEntry entry;
107  entry.first.resize(num_tips);
108  entry.second.resize(num_dofs);
110 
111  for (unsigned i = 0; i < last_saved_cache_size_; ++i)
112  {
113  unsigned int j = 0;
114  cache_file.read(buffer, bufsize);
115  for (auto& pose : entry.first)
116  {
117  memcpy(&pose.position[0], buffer + j * pose_size, position_size);
118  memcpy(&pose.orientation[0], buffer + j * pose_size + position_size, orientation_size);
119  ++j;
120  }
121  memcpy(&entry.second[0], buffer + offset_conf, config_size);
122  ik_cache_.push_back(entry);
123  }
124  ROS_INFO_NAMED("cached_ik", "freeing buffer");
125  delete[] buffer;
126  ROS_INFO_NAMED("cached_ik", "freed buffer");
127  std::vector<IKEntry*> ik_entry_ptrs(last_saved_cache_size_);
128  for (unsigned int i = 0; i < last_saved_cache_size_; ++i)
129  ik_entry_ptrs[i] = &ik_cache_[i];
130  ik_nn_.add(ik_entry_ptrs);
131  }
132 
133  num_joints_ = num_joints;
134 
135  ROS_INFO_NAMED("cached_ik", "cache file %s initialized!", cache_file_name_.string().c_str());
136 }
137 
138 double IKCache::configDistance2(const std::vector<double>& config1, const std::vector<double>& config2) const
139 {
140  double dist = 0., diff;
141  for (unsigned int i = 0; i < config1.size(); ++i)
142  {
143  diff = config1[i] - config2[i];
144  dist += diff * diff;
145  }
146  return dist;
147 }
148 
149 const IKCache::IKEntry& IKCache::getBestApproximateIKSolution(const Pose& pose) const
150 {
151  if (ik_cache_.empty())
152  {
153  static IKEntry dummy = std::make_pair(std::vector<Pose>(1, pose), std::vector<double>(num_joints_, 0.));
154  return dummy;
155  }
156  IKEntry query = std::make_pair(std::vector<Pose>(1, pose), std::vector<double>());
157  return *ik_nn_.nearest(&query);
158 }
159 
160 const IKCache::IKEntry& IKCache::getBestApproximateIKSolution(const std::vector<Pose>& poses) const
161 {
162  if (ik_cache_.empty())
163  {
164  static IKEntry dummy = std::make_pair(poses, std::vector<double>(num_joints_, 0.));
165  return dummy;
166  }
167  IKEntry query = std::make_pair(poses, std::vector<double>());
168  return *ik_nn_.nearest(&query);
169 }
170 
171 void IKCache::updateCache(const IKEntry& nearest, const Pose& pose, const std::vector<double>& config) const
172 {
173  if (ik_cache_.size() < ik_cache_.capacity() && (nearest.first[0].distance(pose) > min_pose_distance_ ||
174  configDistance2(nearest.second, config) > min_config_distance2_))
175  {
176  std::lock_guard<std::mutex> slock(lock_);
177  ik_cache_.emplace_back(std::vector<Pose>(1u, pose), config);
178  ik_nn_.add(&ik_cache_.back());
179  if (ik_cache_.size() >= last_saved_cache_size_ + 500u || ik_cache_.size() == max_cache_size_)
180  saveCache();
181  }
182 }
183 
184 void IKCache::updateCache(const IKEntry& nearest, const std::vector<Pose>& poses,
185  const std::vector<double>& config) const
186 {
187  if (ik_cache_.size() < ik_cache_.capacity())
188  {
189  bool add_to_cache = configDistance2(nearest.second, config) > min_config_distance2_;
190  if (!add_to_cache)
191  {
192  double dist = 0.;
193  for (unsigned int i = 0; i < poses.size(); ++i)
194  {
195  dist += nearest.first[i].distance(poses[i]);
196  if (dist > min_pose_distance_)
197  {
198  add_to_cache = true;
199  break;
200  }
201  }
202  }
203  if (add_to_cache)
204  {
205  std::lock_guard<std::mutex> slock(lock_);
206  ik_cache_.emplace_back(poses, config);
207  ik_nn_.add(&ik_cache_.back());
208  if (ik_cache_.size() >= last_saved_cache_size_ + 500u || ik_cache_.size() == max_cache_size_)
209  saveCache();
210  }
211  }
212 }
213 
214 void IKCache::saveCache() const
215 {
216  if (cache_file_name_.empty())
217  ROS_ERROR_NAMED("cached_ik", "can't save cache before initialization");
218 
219  ROS_INFO_NAMED("cached_ik", "writing %ld IK solutions to %s", ik_cache_.size(), cache_file_name_.string().c_str());
220 
221  boost::filesystem::ofstream cache_file(cache_file_name_, std::ios_base::binary | std::ios_base::out);
222  unsigned int position_size = 3 * sizeof(tf2Scalar);
223  unsigned int orientation_size = 4 * sizeof(tf2Scalar);
224  unsigned int pose_size = position_size + orientation_size;
225  unsigned int num_tips = ik_cache_[0].first.size();
226  unsigned int config_size = ik_cache_[0].second.size() * sizeof(double);
227  unsigned int offset_conf = num_tips * pose_size;
228  unsigned int bufsize = offset_conf + config_size;
229  char* buffer = new char[bufsize];
230 
231  // write number of IK entries and size of each configuration first
233  cache_file.write((char*)&last_saved_cache_size_, sizeof(unsigned int));
234  unsigned int sz = ik_cache_[0].second.size();
235  cache_file.write((char*)&sz, sizeof(unsigned int));
236  cache_file.write((char*)&num_tips, sizeof(unsigned int));
237  for (const auto& entry : ik_cache_)
238  {
239  for (unsigned int i = 0; i < num_tips; ++i)
240  {
241  memcpy(buffer + i * pose_size, &entry.first[i].position[0], position_size);
242  memcpy(buffer + i * pose_size + position_size, &entry.first[i].orientation[0], orientation_size);
243  }
244  memcpy(buffer + offset_conf, &entry.second[0], config_size);
245  cache_file.write(buffer, bufsize);
246  }
247  delete[] buffer;
248 }
249 
251 {
252  const std::vector<std::string>& tip_names(fk.getTipFrames());
253  std::vector<geometry_msgs::Pose> poses(tip_names.size());
254  double error, max_error = 0.;
255 
256  for (const auto& entry : ik_cache_)
257  {
258  fk.getPositionFK(tip_names, entry.second, poses);
259  error = 0.;
260  for (unsigned int i = 0; i < poses.size(); ++i)
261  error += entry.first[i].distance(poses[i]);
262  if (!poses.empty())
263  error /= (double)poses.size();
264  if (error > max_error)
265  max_error = error;
266  if (error > 1e-4)
267  ROS_ERROR_NAMED("cached_ik", "Cache entry is invalid, error = %g", error);
268  }
269  ROS_INFO_NAMED("cached_ik", "Max. error in cache entries is %g", max_error);
270 }
271 
272 IKCache::Pose::Pose(const geometry_msgs::Pose& pose)
273 {
274  position.setX(pose.position.x);
275  position.setY(pose.position.y);
276  position.setZ(pose.position.z);
277  orientation = tf2::Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
278 }
279 
280 double IKCache::Pose::distance(const Pose& pose) const
281 {
282  return (position - pose.position).length() + (orientation.angleShortestPath(pose.orientation));
283 }
284 
285 IKCacheMap::IKCacheMap(const std::string& robot_description, const std::string& group_name, unsigned int num_joints)
286  : robot_description_(robot_description), group_name_(group_name), num_joints_(num_joints)
287 {
288 }
289 
291 {
292  for (auto& cache : *this)
293  delete cache.second;
294 }
295 
296 const IKCache::IKEntry& IKCacheMap::getBestApproximateIKSolution(const std::vector<std::string>& fixed,
297  const std::vector<std::string>& active,
298  const std::vector<Pose>& poses) const
299 {
300  auto key(getKey(fixed, active));
301  auto it = find(key);
302  if (it != end())
303  return it->second->getBestApproximateIKSolution(poses);
304  else
305  {
306  static IKEntry dummy = std::make_pair(poses, std::vector<double>(num_joints_, 0.));
307  return dummy;
308  }
309 }
310 
311 void IKCacheMap::updateCache(const IKEntry& nearest, const std::vector<std::string>& fixed,
312  const std::vector<std::string>& active, const std::vector<Pose>& poses,
313  const std::vector<double>& config)
314 {
315  auto key(getKey(fixed, active));
316  auto it = find(key);
317  if (it != end())
318  it->second->updateCache(nearest, poses, config);
319  else
320  {
321  value_type val = std::make_pair(key, nullptr);
322  auto it = insert(val).first;
323  it->second = new IKCache;
325  }
326 }
327 
328 std::string IKCacheMap::getKey(const std::vector<std::string>& fixed, const std::vector<std::string>& active) const
329 {
330  std::string key;
331  std::accumulate(fixed.begin(), fixed.end(), key);
332  key += '_';
333  std::accumulate(active.begin(), active.end(), key);
334  return key;
335 }
336 } // namespace cached_ik_kinematics_plugin
cached_ik_kinematics_plugin::IKCache::Pose::Pose
Pose()=default
cached_ik_kinematics_plugin::IKCache::initializeCache
void initializeCache(const std::string &robot_id, const std::string &group_name, const std::string &cache_name, const unsigned int num_joints, const Options &opts=Options())
Definition: ik_cache.cpp:93
cached_ik_kinematics_plugin::IKCache::IKCache
IKCache()
Definition: ik_cache.cpp:76
cached_ik_kinematics_plugin
Definition: cached_ik_kinematics_plugin-inl.h:40
cached_ik_kinematics_plugin.h
cached_ik_kinematics_plugin::IKCacheMap::~IKCacheMap
~IKCacheMap()
Definition: ik_cache.cpp:322
cached_ik_kinematics_plugin::NearestNeighborsGNAT::add
void add(const _T &data) override
Add an element to the datastructure.
Definition: NearestNeighborsGNAT.h:208
cached_ik_kinematics_plugin::IKCacheMap::updateCache
void updateCache(const IKEntry &nearest, const std::vector< std::string > &fixed, const std::vector< std::string > &active, const std::vector< Pose > &poses, const std::vector< double > &config)
Definition: ik_cache.cpp:343
cached_ik_kinematics_plugin::IKCache::min_config_distance2_
double min_config_distance2_
Definition: cached_ik_kinematics_plugin.h:191
cached_ik_kinematics_plugin::IKCache::Pose
class to represent end effector pose
Definition: cached_ik_kinematics_plugin.h:138
cached_ik_kinematics_plugin::IKCache::ik_nn_
NearestNeighborsGNAT< IKEntry * > ik_nn_
Definition: cached_ik_kinematics_plugin.h:205
cached_ik_kinematics_plugin::IKCacheMap::num_joints_
unsigned int num_joints_
Definition: cached_ik_kinematics_plugin.h:208
cached_ik_kinematics_plugin::IKCache::Pose::distance
double distance(const Pose &pose) const
Definition: ik_cache.cpp:312
cached_ik_kinematics_plugin::IKCache
A cache of inverse kinematic solutions.
Definition: cached_ik_kinematics_plugin.h:85
cached_ik_kinematics_plugin::IKCache::max_cache_size_
unsigned int max_cache_size_
Definition: cached_ik_kinematics_plugin.h:193
cached_ik_kinematics_plugin::IKCacheMap::IKCacheMap
IKCacheMap(const std::string &robot_description, const std::string &group_name, unsigned int num_joints)
Definition: ik_cache.cpp:317
cached_ik_kinematics_plugin::IKCache::configDistance2
double configDistance2(const std::vector< double > &config1, const std::vector< double > &config2) const
Definition: ik_cache.cpp:170
cached_ik_kinematics_plugin::IKCacheMap::getBestApproximateIKSolution
const IKEntry & getBestApproximateIKSolution(const std::vector< std::string > &fixed, const std::vector< std::string > &active, const std::vector< Pose > &poses) const
Definition: ik_cache.cpp:328
ROS_ERROR_NAMED
#define ROS_ERROR_NAMED(name,...)
cached_ik_kinematics_plugin::IKCache::updateCache
void updateCache(const IKEntry &nearest, const Pose &pose, const std::vector< double > &config) const
Definition: ik_cache.cpp:203
cached_ik_kinematics_plugin::IKCache::num_joints_
unsigned int num_joints_
Definition: cached_ik_kinematics_plugin.h:186
cached_ik_kinematics_plugin::NearestNeighborsGNAT::setDistanceFunction
void setDistanceFunction(const typename NearestNeighbors< _T >::DistanceFunction &distFun) override
Definition: NearestNeighborsGNAT.h:182
kdl_kinematics_plugin::KDLKinematicsPlugin::getPositionFK
bool getPositionFK(const std::vector< std::string > &link_names, const std::vector< double > &joint_angles, std::vector< geometry_msgs::Pose > &poses) const override
Definition: kdl_kinematics_plugin.cpp:554
cached_ik_kinematics_plugin::NearestNeighborsGNAT::clear
void clear() override
Clear the datastructure.
Definition: NearestNeighborsGNAT.h:190
ROS_INFO_NAMED
#define ROS_INFO_NAMED(name,...)
cached_ik_kinematics_plugin::IKCache::saveCache
void saveCache() const
Definition: ik_cache.cpp:246
kinematics::KinematicsBase::getTipFrames
virtual const std::vector< std::string > & getTipFrames() const
cached_ik_kinematics_plugin::NearestNeighborsGNAT::nearest
_T nearest(const _T &data) const override
Get the nearest neighbor of a point.
Definition: NearestNeighborsGNAT.h:268
cached_ik_kinematics_plugin::IKCacheMap::group_name_
std::string group_name_
Definition: cached_ik_kinematics_plugin.h:207
cached_ik_kinematics_plugin::IKCache::getBestApproximateIKSolution
const IKEntry & getBestApproximateIKSolution(const Pose &pose) const
Definition: ik_cache.cpp:181
kdl_kinematics_plugin::KDLKinematicsPlugin
Specific implementation of kinematics using KDL. This version supports any kinematic chain,...
Definition: kdl_kinematics_plugin.h:72
cached_ik_kinematics_plugin::IKCache::Pose::orientation
tf2::Quaternion orientation
Definition: cached_ik_kinematics_plugin.h:143
cached_ik_kinematics_plugin::IKCache::cache_file_name_
boost::filesystem::path cache_file_name_
Definition: cached_ik_kinematics_plugin.h:195
cached_ik_kinematics_plugin::IKCache::last_saved_cache_size_
unsigned int last_saved_cache_size_
Definition: cached_ik_kinematics_plugin.h:207
cached_ik_kinematics_plugin::IKCache::lock_
std::mutex lock_
Definition: cached_ik_kinematics_plugin.h:209
cached_ik_kinematics_plugin::IKCache::ik_cache_
std::vector< IKEntry > ik_cache_
Definition: cached_ik_kinematics_plugin.h:203
tf2::Quaternion
cached_ik_kinematics_plugin::IKCache::~IKCache
~IKCache()
Definition: ik_cache.cpp:87
cached_ik_kinematics_plugin::IKCache::IKEntry
std::pair< std::vector< Pose >, std::vector< double > > IKEntry
Definition: cached_ik_kinematics_plugin.h:153
cached_ik_kinematics_plugin::IKCache::verifyCache
void verifyCache(kdl_kinematics_plugin::KDLKinematicsPlugin &fk) const
Definition: ik_cache.cpp:282
tf2Scalar
double tf2Scalar
cached_ik_kinematics_plugin::IKCache::Pose::position
tf2::Vector3 position
Definition: cached_ik_kinematics_plugin.h:142
cached_ik_kinematics_plugin::IKCache::min_pose_distance_
double min_pose_distance_
Definition: cached_ik_kinematics_plugin.h:189
cached_ik_kinematics_plugin::IKCacheMap::getKey
std::string getKey(const std::vector< std::string > &fixed, const std::vector< std::string > &active) const
Definition: ik_cache.cpp:360
cached_ik_kinematics_plugin::IKCacheMap::robot_description_
std::string robot_description_
Definition: cached_ik_kinematics_plugin.h:206


moveit_kinematics
Author(s): Dave Coleman , Ioan Sucan , Sachin Chitta
autogenerated on Sat Apr 27 2024 02:26:15