50 for (
unsigned int i = 0; i < entry1->first.size(); ++i)
51 dist += entry1->first[i].distance(entry2->first[i]);
63 const unsigned int num_joints,
const Options& opts)
74 std::lock_guard<std::mutex> slock(
lock_);
76 std::filesystem::path prefix(!cached_ik_path.empty() ? std::filesystem::path(cached_ik_path) :
77 std::filesystem::current_path());
79 std::filesystem::create_directories(prefix);
91 std::ifstream cache_file(
cache_file_name_, std::ios_base::binary | std::ios_base::in);
93 unsigned int num_dofs;
94 cache_file.read((
char*)&num_dofs,
sizeof(
unsigned int));
95 unsigned int num_tips;
96 cache_file.read((
char*)&num_tips,
sizeof(
unsigned int));
98 RCLCPP_INFO(LOGGER,
"Found %d IK solutions for a %d-dof system with %d end effectors in %s",
last_saved_cache_size_,
101 unsigned int position_size = 3 *
sizeof(tf2Scalar);
102 unsigned int orientation_size = 4 *
sizeof(tf2Scalar);
103 unsigned int pose_size = position_size + orientation_size;
104 unsigned int config_size = num_dofs *
sizeof(double);
105 unsigned int offset_conf = pose_size * num_tips;
106 unsigned int bufsize = offset_conf + config_size;
107 char* buffer =
new char[bufsize];
109 entry.first.resize(num_tips);
110 entry.second.resize(num_dofs);
116 cache_file.read(buffer, bufsize);
117 for (
auto& pose : entry.first)
119 memcpy(&pose.position[0], buffer + j * pose_size, position_size);
120 memcpy(&pose.orientation[0], buffer + j * pose_size + position_size, orientation_size);
123 memcpy(&entry.second[0], buffer + offset_conf, config_size);
126 RCLCPP_INFO(LOGGER,
"freeing buffer");
128 RCLCPP_INFO(LOGGER,
"freed buffer");
137 RCLCPP_INFO(LOGGER,
"cache file %s initialized!",
cache_file_name_.string().c_str());
142 double dist = 0., diff;
143 for (
unsigned int i = 0; i < config1.size(); ++i)
145 diff = config1[i] - config2[i];
155 static IKEntry dummy = std::make_pair(std::vector<Pose>(1, pose), std::vector<double>(
num_joints_, 0.));
158 IKEntry query = std::make_pair(std::vector<Pose>(1, pose), std::vector<double>());
169 IKEntry query = std::make_pair(poses, std::vector<double>());
178 std::lock_guard<std::mutex> slock(
lock_);
179 ik_cache_.emplace_back(std::vector<Pose>(1u, pose), config);
187 const std::vector<double>& config)
const
195 for (
unsigned int i = 0; i < poses.size(); ++i)
197 dist += nearest.first[i].distance(poses[i]);
207 std::lock_guard<std::mutex> slock(
lock_);
219 RCLCPP_ERROR(LOGGER,
"can't save cache before initialization");
223 std::ofstream cache_file(
cache_file_name_, std::ios_base::binary | std::ios_base::out);
224 unsigned int position_size = 3 *
sizeof(tf2Scalar);
225 unsigned int orientation_size = 4 *
sizeof(tf2Scalar);
226 unsigned int pose_size = position_size + orientation_size;
227 unsigned int num_tips =
ik_cache_[0].first.size();
228 unsigned int config_size =
ik_cache_[0].second.size() *
sizeof(double);
229 unsigned int offset_conf = num_tips * pose_size;
230 unsigned int bufsize = offset_conf + config_size;
231 char* buffer =
new char[bufsize];
236 unsigned int sz =
ik_cache_[0].second.size();
237 cache_file.write((
char*)&sz,
sizeof(
unsigned int));
238 cache_file.write((
char*)&num_tips,
sizeof(
unsigned int));
241 for (
unsigned int i = 0; i < num_tips; ++i)
243 memcpy(buffer + i * pose_size, &entry.first[i].position[0], position_size);
244 memcpy(buffer + i * pose_size + position_size, &entry.first[i].orientation[0], orientation_size);
246 memcpy(buffer + offset_conf, &entry.second[0], config_size);
247 cache_file.write(buffer, bufsize);
254 const std::vector<std::string>& tip_names(fk.
getTipFrames());
255 std::vector<geometry_msgs::msg::Pose> poses(tip_names.size());
256 double error, max_error = 0.;
262 for (
unsigned int i = 0; i < poses.size(); ++i)
263 error += entry.first[i].distance(poses[i]);
265 error /= (double)poses.size();
266 if (error > max_error)
269 RCLCPP_ERROR(LOGGER,
"Cache entry is invalid, error = %g", error);
271 RCLCPP_INFO(LOGGER,
"Max. error in cache entries is %g", max_error);
279 orientation = tf2::Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
284 return (position - pose.
position).length() + (orientation.angleShortestPath(pose.
orientation));
288 : robot_description_(robot_description), group_name_(group_name),
num_joints_(num_joints)
294 for (
auto& cache : *
this)
299 const std::vector<std::string>& active,
300 const std::vector<Pose>& poses)
const
302 auto key(
getKey(fixed, active));
305 return it->second->getBestApproximateIKSolution(poses);
314 const std::vector<std::string>& active,
const std::vector<Pose>& poses,
315 const std::vector<double>& config)
317 auto key(
getKey(fixed, active));
320 it->second->updateCache(nearest, poses, config);
323 value_type val = std::make_pair(key,
nullptr);
324 auto it = insert(val).first;
330 std::string
IKCacheMap::getKey(
const std::vector<std::string>& fixed,
const std::vector<std::string>& active)
const
333 std::accumulate(fixed.begin(), fixed.end(), key);
335 std::accumulate(active.begin(), active.end(), key);
const IKEntry & getBestApproximateIKSolution(const std::vector< std::string > &fixed, const std::vector< std::string > &active, const std::vector< Pose > &poses) const
std::string getKey(const std::vector< std::string > &fixed, const std::vector< std::string > &active) const
std::string robot_description_
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)
IKCacheMap(const std::string &robot_description, const std::string &group_name, unsigned int num_joints)
A cache of inverse kinematic solutions.
double min_pose_distance_
unsigned int max_cache_size_
const IKEntry & getBestApproximateIKSolution(const Pose &pose) const
std::pair< std::vector< Pose >, std::vector< double > > IKEntry
unsigned int last_saved_cache_size_
void verifyCache(kdl_kinematics_plugin::KDLKinematicsPlugin &fk) const
NearestNeighborsGNAT< IKEntry * > ik_nn_
double configDistance2(const std::vector< double > &config1, const std::vector< double > &config2) const
std::filesystem::path cache_file_name_
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())
double min_config_distance2_
void updateCache(const IKEntry &nearest, const Pose &pose, const std::vector< double > &config) const
std::vector< IKEntry > ik_cache_
void setDistanceFunction(const typename NearestNeighbors< _T >::DistanceFunction &distFun) override
void add(const _T &data) override
Add an element to the datastructure.
void clear() override
Clear the datastructure.
_T nearest(const _T &data) const override
Get the nearest neighbor of a point.
Specific implementation of kinematics using KDL. This version supports any kinematic chain,...
bool getPositionFK(const std::vector< std::string > &link_names, const std::vector< double > &joint_angles, std::vector< geometry_msgs::msg::Pose > &poses) const override
Given a set of joint angles and a set of links, compute their pose.
virtual const std::vector< std::string > & getTipFrames() const
Return the names of the tip frames of the kinematic tree on which the solver is operating....
double min_joint_config_distance
std::string cached_ik_path
unsigned int max_cache_size
class to represent end effector pose
double distance(const Pose &pose) const
tf2::Quaternion orientation