39 #include <pluginlib/class_loader.hpp>
40 #include <rclcpp/logger.hpp>
41 #include <rclcpp/logging.hpp>
42 #include <rclcpp/parameter.hpp>
43 #include <rclcpp/parameter_value.hpp>
52 rclcpp::Logger
LOGGER = rclcpp::get_logger(
"kinematics_plugin_loader");
54 template <rclcpp::ParameterType ParamType>
55 rclcpp::Parameter
declare_parameter(
const rclcpp::Node::SharedPtr& node,
const std::string& parameter_name)
57 if (!node->has_parameter(parameter_name))
58 node->declare_parameter(parameter_name, ParamType);
59 rclcpp::Parameter parameter;
60 if (!node->get_parameter(parameter_name, parameter))
61 RCLCPP_DEBUG_STREAM(
LOGGER,
"Parameter `" << parameter_name <<
"` doesn't exists");
75 const std::map<std::string, std::vector<std::string>>& possible_kinematics_solvers,
76 const std::map<std::string, std::vector<double>>& search_res,
77 const std::map<std::string, std::vector<std::string>>& iksolver_to_tip_links)
79 , robot_description_(robot_description)
80 , possible_kinematics_solvers_(possible_kinematics_solvers)
81 , search_res_(search_res)
82 , iksolver_to_tip_links_(iksolver_to_tip_links)
87 std::make_shared<pluginlib::ClassLoader<kinematics::KinematicsBase>>(
"moveit_core",
"kinematics::"
90 catch (pluginlib::PluginlibException& e)
92 RCLCPP_ERROR(
LOGGER,
"Unable to construct kinematics loader. Error: %s", e.what());
103 std::vector<std::string> tips;
104 std::map<std::string, std::vector<std::string>>::const_iterator ik_it = iksolver_to_tip_links_.find(jmg->
getName());
107 if (ik_it != iksolver_to_tip_links_.end())
111 "Choosing tip frame of kinematic solver for group %s"
112 "based on values in rosparam server.",
114 tips = ik_it->second;
120 "Choosing tip frame of kinematic solver for group %s"
121 "based on last link in chain",
130 RCLCPP_ERROR(
LOGGER,
"Error choosing kinematic solver tip frame(s).");
134 std::stringstream tip_debug;
135 tip_debug <<
"Planning group '" << jmg->
getName() <<
"' has tip(s): ";
136 for (
const auto& tip : tips)
137 tip_debug << tip <<
", ";
138 RCLCPP_DEBUG_STREAM(
LOGGER, tip_debug.str());
145 kinematics::KinematicsBasePtr result;
146 if (!kinematics_loader_)
148 RCLCPP_ERROR(
LOGGER,
"Invalid kinematics loader.");
153 RCLCPP_ERROR(
LOGGER,
"Specified group is nullptr. Cannot allocate kinematics solver.");
156 const std::vector<const moveit::core::LinkModel*>& links = jmg->
getLinkModels();
159 RCLCPP_ERROR(
LOGGER,
"No links specified for group '%s'. Cannot allocate kinematics solver.",
164 RCLCPP_DEBUG(
LOGGER,
"Trying to allocate kinematics solver for group '%s'", jmg->
getName().c_str());
166 std::map<std::string, std::vector<std::string>>::const_iterator it =
167 possible_kinematics_solvers_.find(jmg->
getName());
168 if (it == possible_kinematics_solvers_.end())
170 RCLCPP_DEBUG(
LOGGER,
"No kinematics solver available for this group");
174 const std::string& base = links.front()->getParentJointModel()->getParentLinkModel() ?
175 links.front()->getParentJointModel()->getParentLinkModel()->getName() :
179 std::scoped_lock slock(lock_);
180 for (std::size_t i = 0; !result && i < it->second.size(); ++i)
184 result = kinematics_loader_->createUniqueInstance(it->second[i]);
191 double search_res = search_res_.find(jmg->
getName())->second[i];
194 (base.empty() || base[0] !=
'/') ? base : base.substr(1), tips, search_res))
196 RCLCPP_ERROR(
LOGGER,
"Kinematics solver of type '%s' could not be initialized for group '%s'",
197 it->second[i].c_str(), jmg->
getName().c_str());
204 "Successfully allocated and initialized a kinematics solver of type '%s' with search "
205 "resolution %lf for group '%s' at address %p",
206 it->second[i].c_str(), search_res, jmg->
getName().c_str(), result.get());
210 catch (pluginlib::PluginlibException& e)
212 RCLCPP_ERROR(
LOGGER,
"The kinematics plugin (%s) failed to load. Error: %s", it->first.c_str(), e.what());
218 RCLCPP_DEBUG(
LOGGER,
"No usable kinematics solver was found for this group.\n"
219 "Did you load kinematics.yaml into your node's namespace?");
229 std::scoped_lock slock(cache_lock_);
230 kinematics::KinematicsBasePtr& cached = instances_[jmg];
232 return std::move(cached);
241 for (std::map<std::string, std::vector<std::string>>::const_iterator it = possible_kinematics_solvers_.begin();
242 it != possible_kinematics_solvers_.end(); ++it)
244 for (std::size_t i = 0; i < it->second.size(); ++i)
246 RCLCPP_INFO(
LOGGER,
"Solver for group '%s': '%s' (search resolution = %lf)", it->first.c_str(),
247 it->second[i].c_str(), search_res_.at(it->first)[i]);
253 const rclcpp::Node::SharedPtr node_;
254 std::string robot_description_;
255 std::map<std::string, std::vector<std::string>> possible_kinematics_solvers_;
256 std::map<std::string, std::vector<double>> search_res_;
257 std::map<std::string, std::vector<std::string>> iksolver_to_tip_links_;
259 std::shared_ptr<pluginlib::ClassLoader<kinematics::KinematicsBase>> kinematics_loader_;
260 std::map<const moveit::core::JointModelGroup*, kinematics::KinematicsBasePtr> instances_;
262 std::mutex cache_lock_;
270 RCLCPP_INFO(
LOGGER,
"Loader function was never required");
277 return loader.allocKinematicsSolverWithCache(jmg);
289 RCLCPP_DEBUG(
LOGGER,
"Configuring kinematics solvers");
292 std::map<std::string, std::vector<std::string>> possible_kinematics_solvers;
293 std::map<std::string, std::vector<double>> search_res;
294 std::map<std::string, std::vector<std::string>> iksolver_to_tip_links;
298 const std::vector<srdf::Model::Group>& known_groups = srdf_model->getGroups();
299 if (default_search_resolution_ <= std::numeric_limits<double>::epsilon())
302 if (default_solver_plugin_.empty())
304 RCLCPP_DEBUG(
LOGGER,
"Loading settings for kinematics solvers from the ROS param server ...");
306 for (
const srdf::Model::Group& known_group : known_groups)
308 std::string base_param_name = known_group.name_;
309 std::string ksolver_param_name = base_param_name +
".kinematics_solver";
310 RCLCPP_DEBUG(
LOGGER,
"Looking for param %s ", ksolver_param_name.c_str());
311 rclcpp::Parameter ksolver_param =
312 declare_parameter<rclcpp::ParameterType::PARAMETER_STRING>(node_, ksolver_param_name);
313 if (ksolver_param.get_type() == rclcpp::ParameterType::PARAMETER_NOT_SET)
315 base_param_name = robot_description_ +
"_kinematics." + known_group.name_;
316 ksolver_param_name = base_param_name +
".kinematics_solver";
317 RCLCPP_DEBUG(
LOGGER,
"Looking for param %s ", ksolver_param_name.c_str());
318 ksolver_param = declare_parameter<rclcpp::ParameterType::PARAMETER_STRING>(node_, ksolver_param_name);
320 if (ksolver_param.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
322 RCLCPP_DEBUG(
LOGGER,
"Found param %s", ksolver_param_name.c_str());
324 const auto& ksolver = ksolver_param.as_string();
325 std::stringstream ss(ksolver);
327 while (ss.good() && !ss.eof())
332 groups_.push_back(known_group.name_);
335 ss >> solver >> std::ws;
336 possible_kinematics_solvers[known_group.name_].push_back(solver);
337 RCLCPP_DEBUG(
LOGGER,
"Using kinematics solver '%s' for group '%s'.", solver.c_str(),
338 known_group.name_.c_str());
342 std::string ksolver_timeout_param_name = base_param_name +
".kinematics_solver_timeout";
343 rclcpp::Parameter ksolver_timeout_param =
344 declare_parameter<rclcpp::ParameterType::PARAMETER_DOUBLE>(node_, ksolver_timeout_param_name);
345 if (ksolver_timeout_param.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
347 if (ksolver_timeout_param.get_type() == rclcpp::ParameterType::PARAMETER_DOUBLE)
349 ik_timeout_[known_group.name_] = ksolver_timeout_param.as_double();
351 else if (ksolver_timeout_param.get_type() == rclcpp::ParameterType::PARAMETER_INTEGER)
353 ik_timeout_[known_group.name_] = ksolver_timeout_param.as_int();
357 std::string ksolver_res_param_name = base_param_name +
".kinematics_solver_search_resolution";
358 rclcpp::Parameter ksolver_res_param =
359 declare_parameter<rclcpp::ParameterType::PARAMETER_DOUBLE>(node_, ksolver_res_param_name);
360 if (ksolver_res_param.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
362 if (ksolver_res_param.get_type() == rclcpp::ParameterType::PARAMETER_STRING)
364 const auto& ksolver_res = ksolver_res_param.as_string();
365 std::stringstream ss(ksolver_res);
366 while (ss.good() && !ss.eof())
369 ss >> res >> std::ws;
370 search_res[known_group.name_].push_back(res);
374 else if (ksolver_res_param.get_type() == rclcpp::ParameterType::PARAMETER_DOUBLE)
376 search_res[known_group.name_].push_back(ksolver_res_param.as_double());
378 else if (ksolver_res_param.get_type() == rclcpp::ParameterType::PARAMETER_INTEGER)
380 search_res[known_group.name_].push_back(ksolver_res_param.as_int());
385 std::string ksolver_ik_links_param_name = base_param_name +
".kinematics_solver_ik_links";
386 rclcpp::Parameter ksolver_ik_links_param =
387 declare_parameter<rclcpp::ParameterType::PARAMETER_STRING_ARRAY>(node_, ksolver_ik_links_param_name);
388 if (ksolver_ik_links_param.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
390 if (ksolver_ik_links_param.get_type() == rclcpp::ParameterType::PARAMETER_STRING_ARRAY)
392 const auto& ksolver_ik_links = ksolver_ik_links_param.as_string_array();
393 for (
auto& ksolver_ik_link : ksolver_ik_links)
395 RCLCPP_DEBUG(
LOGGER,
"found tip %s for group %s", ksolver_ik_link.c_str(), known_group.name_.c_str());
396 iksolver_to_tip_links[known_group.name_].push_back(ksolver_ik_link);
401 RCLCPP_WARN(
LOGGER,
"the parameter '%s' needs to be of type 'STRING_ARRAY'",
402 ksolver_ik_links_param_name.c_str());
408 while (search_res[known_group.name_].size() < possible_kinematics_solvers[known_group.name_].size())
409 search_res[known_group.name_].push_back(default_search_resolution_);
414 RCLCPP_DEBUG(
LOGGER,
"Using specified default settings for kinematics solvers ...");
415 for (
const srdf::Model::Group& known_group : known_groups)
417 possible_kinematics_solvers[known_group.name_].resize(1, default_solver_plugin_);
418 search_res[known_group.name_].resize(1, default_search_resolution_);
419 ik_timeout_[known_group.name_] = default_solver_timeout_;
420 groups_.push_back(known_group.name_);
425 loader_ = std::make_shared<KinematicsLoaderImpl>(node_, robot_description_, possible_kinematics_solvers, search_res,
426 iksolver_to_tip_links);
430 return loader.allocKinematicsSolverWithCache(jmg);
static const double DEFAULT_SEARCH_DISCRETIZATION
std::vector< std::string > chooseTipFrames(const moveit::core::JointModelGroup *jmg)
Helper function to decide which, and how many, tip frames a planning group has.
kinematics::KinematicsBasePtr allocKinematicsSolverWithCache(const moveit::core::JointModelGroup *jmg)
KinematicsLoaderImpl(const rclcpp::Node::SharedPtr &node, const std::string &robot_description, const std::map< std::string, std::vector< std::string >> &possible_kinematics_solvers, const std::map< std::string, std::vector< double >> &search_res, const std::map< std::string, std::vector< std::string >> &iksolver_to_tip_links)
Pimpl Implementation of KinematicsLoader.
kinematics::KinematicsBasePtr allocKinematicsSolver(const moveit::core::JointModelGroup *jmg)
moveit::core::SolverAllocatorFn getLoaderFunction()
Get a function pointer that allocates and initializes a kinematics solver. If not previously called,...
double getDefaultIKTimeout() const
Get the default IK timeout.
const std::string & getName() const
Get the name of the joint group.
const std::vector< const LinkModel * > & getLinkModels() const
Get the links that are part of this joint group.
const RobotModel & getParentModel() const
Get the kinematic model this group is part of.
const std::string & getModelFrame() const
Get the frame in which the transforms for this model are computed (when using a RobotState)....
const srdf::ModelSharedPtr & getSRDF() const
Get the parsed SRDF model.
const std::string & getRobotDescription() const
Get the resolved parameter name for the robot description.
rclcpp::Parameter declare_parameter(const rclcpp::Node::SharedPtr &node, const std::string ¶meter_name)
std::function< kinematics::KinematicsBasePtr(const JointModelGroup *)> SolverAllocatorFn
Function type that allocates a kinematics solver for a particular group.