58 for (
unsigned int i = 0; i < entry1->first.size(); ++i)
59 dist += entry1->first[i].distance(entry2->first[i]);
71 const unsigned int num_joints,
const Options& opts)
82 std::lock_guard<std::mutex> slock(
lock_);
84 std::filesystem::path prefix(!cached_ik_path.empty() ? std::filesystem::path(cached_ik_path) :
85 std::filesystem::current_path());
87 std::filesystem::create_directories(prefix);
99 std::ifstream cache_file(
cache_file_name_, std::ios_base::binary | std::ios_base::in);
101 unsigned int num_dofs;
102 cache_file.read(
reinterpret_cast<char*
>(&num_dofs),
sizeof(
unsigned int));
103 unsigned int num_tips;
104 cache_file.read(
reinterpret_cast<char*
>(&num_tips),
sizeof(
unsigned int));
106 RCLCPP_INFO(getLogger(),
"Found %d IK solutions for a %d-dof system with %d end effectors in %s",
109 unsigned int position_size = 3 *
sizeof(tf2Scalar);
110 unsigned int orientation_size = 4 *
sizeof(tf2Scalar);
111 unsigned int pose_size = position_size + orientation_size;
112 unsigned int config_size = num_dofs *
sizeof(double);
113 unsigned int offset_conf = pose_size * num_tips;
114 unsigned int bufsize = offset_conf + config_size;
115 char* buffer =
new char[bufsize];
117 entry.first.resize(num_tips);
118 entry.second.resize(num_dofs);
124 cache_file.read(buffer, bufsize);
125 for (
auto& pose : entry.first)
127 memcpy(&pose.position[0], buffer + j * pose_size, position_size);
128 memcpy(&pose.orientation[0], buffer + j * pose_size + position_size, orientation_size);
131 memcpy(&entry.second[0], buffer + offset_conf, config_size);
134 RCLCPP_INFO(getLogger(),
"freeing buffer");
136 RCLCPP_INFO(getLogger(),
"freed buffer");
145 RCLCPP_INFO(getLogger(),
"cache file %s initialized!",
cache_file_name_.string().c_str());
150 double dist = 0., diff;
151 for (
unsigned int i = 0; i < config1.size(); ++i)
153 diff = config1[i] - config2[i];
163 static IKEntry dummy = std::make_pair(std::vector<Pose>(1, pose), std::vector<double>(
num_joints_, 0.));
166 IKEntry query = std::make_pair(std::vector<Pose>(1, pose), std::vector<double>());
177 IKEntry query = std::make_pair(poses, std::vector<double>());
186 std::lock_guard<std::mutex> slock(
lock_);
187 ik_cache_.emplace_back(std::vector<Pose>(1u, pose), config);
195 const std::vector<double>& config)
const
203 for (
unsigned int i = 0; i < poses.size(); ++i)
205 dist += nearest.first[i].distance(poses[i]);
215 std::lock_guard<std::mutex> slock(
lock_);
227 RCLCPP_ERROR(getLogger(),
"can't save cache before initialization");
231 std::ofstream cache_file(
cache_file_name_, std::ios_base::binary | std::ios_base::out);
232 unsigned int position_size = 3 *
sizeof(tf2Scalar);
233 unsigned int orientation_size = 4 *
sizeof(tf2Scalar);
234 unsigned int pose_size = position_size + orientation_size;
235 unsigned int num_tips =
ik_cache_[0].first.size();
236 unsigned int config_size =
ik_cache_[0].second.size() *
sizeof(double);
237 unsigned int offset_conf = num_tips * pose_size;
238 unsigned int bufsize = offset_conf + config_size;
239 char* buffer =
new char[bufsize];
244 unsigned int sz =
ik_cache_[0].second.size();
245 cache_file.write(
reinterpret_cast<char*
>(&sz),
sizeof(
unsigned int));
246 cache_file.write(
reinterpret_cast<char*
>(&num_tips),
sizeof(
unsigned int));
249 for (
unsigned int i = 0; i < num_tips; ++i)
251 memcpy(buffer + i * pose_size, &entry.first[i].position[0], position_size);
252 memcpy(buffer + i * pose_size + position_size, &entry.first[i].orientation[0], orientation_size);
254 memcpy(buffer + offset_conf, &entry.second[0], config_size);
255 cache_file.write(buffer, bufsize);
262 const std::vector<std::string>& tip_names(fk.
getTipFrames());
263 std::vector<geometry_msgs::msg::Pose> poses(tip_names.size());
264 double error, max_error = 0.;
270 for (
unsigned int i = 0; i < poses.size(); ++i)
271 error += entry.first[i].distance(poses[i]);
273 error /=
static_cast<double>(poses.size());
274 if (error > max_error)
277 RCLCPP_ERROR(getLogger(),
"Cache entry is invalid, error = %g", error);
279 RCLCPP_INFO(getLogger(),
"Max. error in cache entries is %g", max_error);
287 orientation = tf2::Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w);
292 return (position - pose.
position).length() + (orientation.angleShortestPath(pose.
orientation));
296 : robot_description_(robot_description), group_name_(group_name),
num_joints_(num_joints)
302 for (
auto& cache : *
this)
307 const std::vector<std::string>& active,
308 const std::vector<Pose>& poses)
const
310 auto key(
getKey(fixed, active));
314 return it->second->getBestApproximateIKSolution(poses);
324 const std::vector<std::string>& active,
const std::vector<Pose>& poses,
325 const std::vector<double>& config)
327 auto key(
getKey(fixed, active));
331 it->second->updateCache(nearest, poses, config);
335 value_type val = std::make_pair(key,
nullptr);
336 auto it = insert(val).first;
342std::string
IKCacheMap::getKey(
const std::vector<std::string>& fixed,
const std::vector<std::string>& active)
const
345 std::accumulate(fixed.begin(), fixed.end(), key);
347 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....
rclcpp::Logger getLogger()
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
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