38 #include <kdl/chainfksolverpos_recursive.hpp>
39 #include <kdl/chainiksolverpos_lma.hpp>
41 #include <tf2_kdl/tf2_kdl.hpp>
42 #include <kdl_parser/kdl_parser.hpp>
43 #include <kdl/frames_io.hpp>
44 #include <kdl/kinfam_io.hpp>
47 #include <class_loader/class_loader.hpp>
52 static const rclcpp::Logger LOGGER = rclcpp::get_logger(
"moveit_lma_kinematics_plugin.lma_kinematics_plugin");
58 void LMAKinematicsPlugin::getRandomConfiguration(Eigen::VectorXd& jnt_array)
const
60 state_->setToRandomPositions(joint_model_group_);
61 state_->copyJointGroupPositions(joint_model_group_, &jnt_array[0]);
64 void LMAKinematicsPlugin::getRandomConfiguration(
const Eigen::VectorXd& seed_state,
65 const std::vector<double>& consistency_limits,
66 Eigen::VectorXd& jnt_array)
const
69 &seed_state[0], consistency_limits);
72 bool LMAKinematicsPlugin::checkConsistency(
const Eigen::VectorXd& seed_state,
73 const std::vector<double>& consistency_limits,
74 const Eigen::VectorXd& solution)
const
76 for (std::size_t i = 0; i < dimension_; ++i)
77 if (fabs(seed_state(i) - solution(i)) > consistency_limits[i])
83 const std::string& group_name,
const std::string& base_frame,
84 const std::vector<std::string>& tip_frames,
double search_discretization)
87 storeValues(robot_model, group_name, base_frame, tip_frames, search_discretization);
88 joint_model_group_ =
robot_model_->getJointModelGroup(group_name);
89 if (!joint_model_group_)
92 if (!joint_model_group_->
isChain())
94 RCLCPP_ERROR(
LOGGER,
"Group '%s' is not a chain", group_name.c_str());
99 RCLCPP_ERROR(
LOGGER,
"Group '%s' includes joints that have more than 1 DOF", group_name.c_str());
105 if (!kdl_parser::treeFromUrdfModel(*robot_model.
getURDF(), kdl_tree))
107 RCLCPP_ERROR(
LOGGER,
"Could not initialize tree object");
112 RCLCPP_ERROR(
LOGGER,
"Could not initialize chain object");
120 joints_.push_back(jm);
121 joint_names_.push_back(jm->getName());
124 dimension_ = joints_.size();
127 lookupParam(node_,
"max_solver_iterations", max_solver_iterations_, 500);
129 lookupParam(node_,
"orientation_vs_position", orientation_vs_position_weight_, 0.01);
132 lookupParam(node_,
"position_only_ik", position_ik,
false);
134 orientation_vs_position_weight_ = 0.0;
135 if (orientation_vs_position_weight_ == 0.0)
136 RCLCPP_INFO(
LOGGER,
"Using position only ik");
139 state_ = std::make_shared<moveit::core::RobotState>(
robot_model_);
141 fk_solver_ = std::make_unique<KDL::ChainFkSolverPos_recursive>(kdl_chain_);
144 RCLCPP_DEBUG(
LOGGER,
"LMA solver initialized");
148 bool LMAKinematicsPlugin::timedOut(
const rclcpp::Time& start_time,
double duration)
const
150 return ((node_->now() - start_time).seconds() >= duration);
154 const std::vector<double>& ik_seed_state, std::vector<double>& solution,
155 moveit_msgs::msg::MoveItErrorCodes& error_code,
158 std::vector<double> consistency_limits;
166 const std::vector<double>& ik_seed_state,
double timeout,
167 std::vector<double>& solution,
168 moveit_msgs::msg::MoveItErrorCodes& error_code,
171 std::vector<double> consistency_limits;
178 const std::vector<double>& ik_seed_state,
double timeout,
179 const std::vector<double>& consistency_limits, std::vector<double>& solution,
180 moveit_msgs::msg::MoveItErrorCodes& error_code,
188 const std::vector<double>& ik_seed_state,
double timeout,
189 std::vector<double>& solution,
const IKCallbackFn& solution_callback,
190 moveit_msgs::msg::MoveItErrorCodes& error_code,
193 std::vector<double> consistency_limits;
194 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, solution_callback, error_code,
198 void LMAKinematicsPlugin::harmonize(Eigen::VectorXd& values)
const
201 for (
auto* jm : joints_)
202 jm->harmonizePosition(&values[i++]);
205 bool LMAKinematicsPlugin::obeysLimits(
const Eigen::VectorXd& values)
const
208 for (
const auto& jm : joints_)
209 if (!jm->satisfiesPositionBounds(&values[i++]))
215 const std::vector<double>& ik_seed_state,
double timeout,
216 const std::vector<double>& consistency_limits, std::vector<double>& solution,
218 moveit_msgs::msg::MoveItErrorCodes& error_code,
221 rclcpp::Time start_time = node_->now();
224 RCLCPP_ERROR(
LOGGER,
"kinematics solver not initialized");
225 error_code.val = error_code.NO_IK_SOLUTION;
229 if (ik_seed_state.size() != dimension_)
231 RCLCPP_ERROR(
LOGGER,
"Seed state must have size %d instead of size %zu", dimension_, ik_seed_state.size());
232 error_code.val = error_code.NO_IK_SOLUTION;
236 if (!consistency_limits.empty() && consistency_limits.size() != dimension_)
238 RCLCPP_ERROR_STREAM(
LOGGER,
"Consistency limits be empty or must have size " << dimension_ <<
" instead of size "
239 << consistency_limits.size());
240 error_code.val = error_code.NO_IK_SOLUTION;
244 Eigen::Matrix<double, 6, 1> cartesian_weights;
245 cartesian_weights(0) = 1;
246 cartesian_weights(1) = 1;
247 cartesian_weights(2) = 1;
248 cartesian_weights(3) = orientation_vs_position_weight_;
249 cartesian_weights(4) = orientation_vs_position_weight_;
250 cartesian_weights(5) = orientation_vs_position_weight_;
252 KDL::JntArray jnt_seed_state(dimension_);
253 KDL::JntArray jnt_pos_in(dimension_);
254 KDL::JntArray jnt_pos_out(dimension_);
255 jnt_seed_state.data = Eigen::Map<const Eigen::VectorXd>(ik_seed_state.data(), ik_seed_state.size());
256 jnt_pos_in = jnt_seed_state;
258 KDL::ChainIkSolverPos_LMA ik_solver_pos(kdl_chain_, cartesian_weights, epsilon_, max_solver_iterations_);
259 solution.resize(dimension_);
261 KDL::Frame pose_desired;
262 tf2::fromMsg(ik_pose, pose_desired);
264 RCLCPP_DEBUG_STREAM(
LOGGER,
"searchPositionIK2: Position request pose is "
265 << ik_pose.position.x <<
" " << ik_pose.position.y <<
" " << ik_pose.position.z <<
" "
266 << ik_pose.orientation.x <<
" " << ik_pose.orientation.y <<
" "
267 << ik_pose.orientation.z <<
" " << ik_pose.orientation.w);
268 unsigned int attempt = 0;
274 if (!consistency_limits.empty())
275 getRandomConfiguration(jnt_seed_state.data, consistency_limits, jnt_pos_in.data);
277 getRandomConfiguration(jnt_pos_in.data);
278 RCLCPP_DEBUG_STREAM(
LOGGER,
"New random configuration (" << attempt <<
"): " << jnt_pos_in);
281 int ik_valid = ik_solver_pos.CartToJnt(jnt_pos_in, pose_desired, jnt_pos_out);
282 if (ik_valid == 0 ||
options.return_approximate_solution)
284 harmonize(jnt_pos_out.data);
285 if (!consistency_limits.empty() && !checkConsistency(jnt_seed_state.data, consistency_limits, jnt_pos_out.data))
287 if (!obeysLimits(jnt_pos_out.data))
290 Eigen::Map<Eigen::VectorXd>(solution.data(), solution.size()) = jnt_pos_out.data;
291 if (solution_callback)
293 solution_callback(ik_pose, solution, error_code);
294 if (error_code.val != error_code.SUCCESS)
299 error_code.val = error_code.SUCCESS;
300 RCLCPP_DEBUG_STREAM(
LOGGER,
"Solved after " << (node_->now() - start_time).seconds() <<
" < " << timeout
301 <<
"s and " << attempt <<
" attempts");
304 }
while (!timedOut(start_time, timeout));
306 RCLCPP_DEBUG_STREAM(
LOGGER,
"IK timed out after " << (node_->now() - start_time).seconds() <<
" > " << timeout
307 <<
"s and " << attempt <<
" attempts");
308 error_code.val = error_code.TIMED_OUT;
313 const std::vector<double>& joint_angles,
314 std::vector<geometry_msgs::msg::Pose>& poses)
const
318 RCLCPP_ERROR(
LOGGER,
"kinematics solver not initialized");
321 poses.resize(link_names.size());
322 if (joint_angles.size() != dimension_)
324 RCLCPP_ERROR(
LOGGER,
"Joint angles vector must have size: %d", dimension_);
329 KDL::JntArray jnt_pos_in(dimension_);
330 jnt_pos_in.data = Eigen::Map<const Eigen::VectorXd>(joint_angles.data(), joint_angles.size());
333 for (
unsigned int i = 0; i < poses.size(); ++i)
335 if (fk_solver_->JntToCart(jnt_pos_in, p_out) >= 0)
337 poses[i] = tf2::toMsg(p_out);
341 RCLCPP_ERROR(
LOGGER,
"Could not compute FK for %s", link_names[i].c_str());
Provides an interface for kinematics solvers.
void storeValues(const moveit::core::RobotModel &robot_model, const std::string &group_name, const std::string &base_frame, const std::vector< std::string > &tip_frames, double search_discretization)
virtual const std::string & getTipFrame() const
Return the name of the tip frame of the chain on which the solver is operating. This is usually a lin...
static const rclcpp::Logger LOGGER
bool lookupParam(const rclcpp::Node::SharedPtr &node, const std::string ¶m, T &val, const T &default_val) const
Enables kinematics plugins access to parameters that are defined for the private namespace and inside...
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....
std::function< void(const geometry_msgs::msg::Pose &, const std::vector< double > &, moveit_msgs::msg::MoveItErrorCodes &)> IKCallbackFn
Signature for a callback to validate an IK solution. Typically used for collision checking.
moveit::core::RobotModelConstPtr robot_model_
Implementation of kinematics using Levenberg-Marquardt (LMA) solver from KDL. This version supports a...
const std::vector< std::string > & getJointNames() const override
Return all the joint names in the order they are used internally.
LMAKinematicsPlugin()
Default constructor.
bool initialize(const rclcpp::Node::SharedPtr &node, const moveit::core::RobotModel &robot_model, const std::string &group_name, const std::string &base_frame, const std::vector< std::string > &tip_frames, double search_discretization) override
Initialization function for the kinematics, for use with kinematic chain IK solvers.
bool getPositionIK(const geometry_msgs::msg::Pose &ik_pose, const std::vector< double > &ik_seed_state, std::vector< double > &solution, moveit_msgs::msg::MoveItErrorCodes &error_code, const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions()) const override
Given a desired pose of the end-effector, compute the joint angles to reach it.
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.
bool searchPositionIK(const geometry_msgs::msg::Pose &ik_pose, const std::vector< double > &ik_seed_state, double timeout, std::vector< double > &solution, moveit_msgs::msg::MoveItErrorCodes &error_code, const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions()) const override
Given a desired pose of the end-effector, search for the joint angles required to reach it....
const std::vector< std::string > & getLinkNames() const override
Return all the link names in the order they are represented internally.
bool isChain() const
Check if this group is a linear chain.
void getVariableRandomPositionsNearBy(random_numbers::RandomNumberGenerator &rng, double *values, const double *near, const double distance) const
Compute random values for the state of the joint group.
const std::vector< const JointModel * > & getJointModels() const
Get all the joints in this group (including fixed and mimic joints).
bool isSingleDOFJoints() const
Return true if the group consists only of joints that are single DOF.
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
const urdf::ModelInterfaceSharedPtr & getURDF() const
Get the parsed URDF model.
A set of options for the kinematics solver.
CLASS_LOADER_REGISTER_CLASS(trajopt_interface::TrajOptPlannerManager, planning_interface::PlannerManager)