moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
prbt_manipulator_ikfast_moveit_plugin.cpp
Go to the documentation of this file.
1/*********************************************************************
2 *
3 * Software License Agreement (BSD License)
4 *
5 * Copyright (c) 2013, Dave Coleman, CU Boulder; Jeremy Zoss, SwRI; David Butterworth, KAIST; Mathias Lüdtke, Fraunhofer
6 *IPA
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * * Neither the name of the all of the author's companies nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 *********************************************************************/
35
36/*
37 * IKFast Kinematics Solver Plugin for MoveIt wrapping an ikfast solver from OpenRAVE.
38 *
39 * AUTO-GENERATED by create_ikfast_moveit_plugin.py in moveit_kinematics package.
40 *
41 * This file, including the ikfast cpp from OpenRAVE below, forms a MoveIt kinematics plugin.
42 */
43
44
45#include <cmath>
46#include <list>
47#include <vector>
48#include <limits>
49#include <complex>
50
51#include <Eigen/Geometry>
52#include <rclcpp/logger.hpp>
53#include <rclcpp/logging.hpp>
54#include <rclcpp/node.hpp>
55#include <rclcpp/parameter_value.hpp>
56#include <tf2_eigen/tf2_eigen.hpp>
57#include <tf2_eigen_kdl/tf2_eigen_kdl.hpp>
58#include <tf2_kdl/tf2_kdl.hpp>
61#include <moveit_resources_prbt_ikfast_manipulator_plugin/prbt_ikfast_kinematics_parameters.hpp>
63using namespace moveit::core;
64
65// Need a floating point tolerance when checking joint limits, in case the joint starts at limit
66const double LIMIT_TOLERANCE = .0000001;
73
75{
76#define IKFAST_NO_MAIN // Don't include main() from IKFast
77
86 IKP_Transform6D = 0x67000001,
87 IKP_Rotation3D = 0x34000002,
88 IKP_Translation3D = 0x33000003,
89 IKP_Direction3D = 0x23000004,
90 IKP_Ray4D = 0x46000005,
91 IKP_Lookat3D = 0x23000006,
95 IKP_TranslationXY2D = 0x22000008,
100
110
113 /// certain angle starting from the x-axis (defined in the manipulator
114 /// base link's coordinate system)
120 /// direction needs to be orthogonal to y-axis and be rotated at a
121 /// certain angle starting from the z-axis (defined in the manipulator
122 /// base link's coordinate system)
123
125
127 0x00008000,
145 IKP_UniqueIdMask = 0x0000ffff,
146 IKP_CustomDataBit = 0x00010000,
148};
149
150// struct for storing and sorting solutions
152{
153 std::vector<double> value;
155
156 bool operator<(const LimitObeyingSol& a) const
157 {
159 }
162static const rclcpp::Logger LOGGER = rclcpp::get_logger("ikfast");
164// Code generated by IKFast56/61
169{
170 std::vector<std::string> joint_names_;
171 std::vector<double> joint_min_vector_;
172 std::vector<double> joint_max_vector_;
173 std::vector<bool> joint_has_limits_vector_;
174 std::vector<std::string> link_names_;
175 const size_t num_joints_;
176 std::vector<int> free_params_;
177
178 std::shared_ptr<prbt_ikfast_kinematics::ParamListener> param_listener_;
179 prbt_ikfast_kinematics::Params params_;
180
181 // The ikfast and base frame are the start and end of the kinematic chain for which the
182 // IKFast analytic solution was generated.
183 const std::string IKFAST_TIP_FRAME_ = "flange";
184 const std::string IKFAST_BASE_FRAME_ = "base_link";
185
186 // The transform tip and base bool are set to true if this solver is used with a kinematic
187 // chain that extends beyond the ikfast tip and base frame. The solution will be valid so
188 // long as there are no active, passive, or mimic joints between either the ikfast_tip_frame
189 // and the tip_frame of the group or the ikfast_base_frame and the base_frame for the group.
190 bool tip_transform_required_;
191 bool base_transform_required_;
192
193 // We store the transform from the ikfast_base_frame to the group base_frame as well as the
194 // ikfast_tip_frame to the group tip_frame to transform input poses into the solver frame.
195 Eigen::Isometry3d chain_base_to_group_base_;
196 Eigen::Isometry3d group_tip_to_chain_tip_;
197
198 bool initialized_; // Internal variable that indicates whether solvers are configured and ready
200 const std::vector<std::string>& getJointNames() const override
201 {
202 return joint_names_;
204 const std::vector<std::string>& getLinkNames() const override
205 {
206 return link_names_;
207 }
208
209public:
213 IKFastKinematicsPlugin() : num_joints_(GetNumJoints()), initialized_(false)
214 {
215 srand(time(nullptr));
226
227 * @return True if a valid solution was found, false otherwise
228 */
229
230 // Returns the IK solution that is within joint limits closest to ik_seed_state
231 bool getPositionIK(
232 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, std::vector<double>& solution,
233 moveit_msgs::msg::MoveItErrorCodes& error_code,
235
236
239 * This is a default implementation that returns only one solution and so its result is equivalent to calling
240 * 'getPositionIK(...)' with a zero initialized seed.
241 *
242 * @param ik_poses The desired pose of each tip link
243 * @param ik_seed_state an initial guess solution for the inverse kinematics
244 * @param solutions A vector of vectors where each entry is a valid joint solution
245 * @param result A struct that reports the results of the query
246 * @param options An option struct which contains the type of redundancy discretization used. This default
247 * implementation only supports the KinmaticSearches::NO_DISCRETIZATION method; requesting any
248 * other will result in failure.
249 * @return True if a valid set of solutions was found, false otherwise.
250 */
251 bool getPositionIK(const std::vector<geometry_msgs::msg::Pose>& ik_poses, const std::vector<double>& ik_seed_state,
252 std::vector<std::vector<double>>& solutions, kinematics::KinematicsResult& result,
253 const kinematics::KinematicsQueryOptions& options) const override;
254
263 bool searchPositionIK(
264 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
265 std::vector<double>& solution, moveit_msgs::msg::MoveItErrorCodes& error_code,
267
277 bool searchPositionIK(
278 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
279 const std::vector<double>& consistency_limits, std::vector<double>& solution,
280 moveit_msgs::msg::MoveItErrorCodes& error_code,
282
288
292 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
293 std::vector<double>& solution, const IKCallbackFn& solution_callback, moveit_msgs::msg::MoveItErrorCodes& error_code,
295
306 bool searchPositionIK(
307 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
308 const std::vector<double>& consistency_limits, std::vector<double>& solution,
309 const IKCallbackFn& solution_callback, moveit_msgs::msg::MoveItErrorCodes& error_code,
311
320 bool getPositionFK(const std::vector<std::string>& link_names, const std::vector<double>& joint_angles,
321 std::vector<geometry_msgs::msg::Pose>& poses) const override;
322
332 void setSearchDiscretization(const std::map<unsigned int, double>& discretization);
333
337 bool setRedundantJoints(const std::vector<unsigned int>& redundant_joint_indices) override;
338
339private:
340 bool initialize(const rclcpp::Node::SharedPtr& node, const moveit::core::RobotModel& robot_model, const std::string& group_name,
341 const std::string& base_frame, const std::vector<std::string>& tip_frames,
342 double search_discretization) override;
343
348 size_t solve(KDL::Frame& pose_frame, const std::vector<double>& vfree, IkSolutionList<IkReal>& solutions) const;
349
353 void getSolution(const IkSolutionList<IkReal>& solutions, int i, std::vector<double>& solution) const;
354
355
358 void getSolution(const IkSolutionList<IkReal>& solutions, const std::vector<double>& ik_seed_state, int i,
359 std::vector<double>& solution) const;
364 double enforceLimits(double val, double min, double max) const;
365
366 void fillFreeParams(int count, int* array);
367 bool getCount(int& count, int max_count, int min_count) const;
368
371 * @param method An enumeration flag indicating the discretization method to be used
372 * @param sampled_joint_vals Sampled joint values for the redundant joint
373 * @return True if sampling succeeded.
374 */
375 bool sampleRedundantJoint(kinematics::DiscretizationMethod method, std::vector<double>& sampled_joint_vals) const;
376
378 bool computeRelativeTransform(const std::string& from, const std::string& to, Eigen::Isometry3d& transform,
379 bool& differs_from_identity);
386 void transformToChainFrame(const geometry_msgs::msg::Pose& ik_pose, KDL::Frame& ik_pose_chain) const;
387}; // end class
388
389bool IKFastKinematicsPlugin::computeRelativeTransform(const std::string& from, const std::string& to,
390 Eigen::Isometry3d& transform, bool& differs_from_identity)
391{
392 RobotStatePtr robot_state = std::make_shared<RobotState>(robot_model_);
393 robot_state->setToDefaultValues();
394
395 auto* from_link = robot_model_->getLinkModel(from);
396 auto* to_link = robot_model_->getLinkModel(to);
397 if (!from_link || !to_link)
398 return false;
399
400 if (robot_model_->getRigidlyConnectedParentLinkModel(from_link) !=
401 robot_model_->getRigidlyConnectedParentLinkModel(to_link))
402 {
403 RCLCPP_ERROR_STREAM(LOGGER, "Link frames " << from << " and " << to << " are not rigidly connected.");
404 return false;
405 }
406
407 transform = robot_state->getGlobalLinkTransform(from_link).inverse() * robot_state->getGlobalLinkTransform(to_link);
408 differs_from_identity = !transform.matrix().isIdentity();
409 return true;
410}
411
412bool IKFastKinematicsPlugin::initialize(const rclcpp::Node::SharedPtr& node, const moveit::core::RobotModel& robot_model, const std::string& group_name,
413 const std::string& base_frame, const std::vector<std::string>& tip_frames,
414 double search_discretization)
415{
416 if (tip_frames.size() != 1)
417 {
418 RCLCPP_ERROR(LOGGER, "Expecting exactly one tip frame.");
419 return false;
420 }
421
422 std::string kinematics_param_prefix = "robot_description_kinematics." + group_name;
423 param_listener_ = std::make_shared<prbt_ikfast_kinematics::ParamListener>(node, kinematics_param_prefix);
424 params_ = param_listener_->get_params();
425
426 storeValues(robot_model, group_name, base_frame, tip_frames, search_discretization);
427
428 RCLCPP_INFO_STREAM(LOGGER, "Using link_prefix: '" << params_.link_prefix << '\'');
429
430 // verbose error output. subsequent checks in computeRelativeTransform return false then
431 if (!robot_model.hasLinkModel(tip_frames_[0]))
432 RCLCPP_ERROR_STREAM(LOGGER, "tip frame '" << tip_frames_[0] << "' does not exist.");
433 if (!robot_model.hasLinkModel(base_frame_))
434 RCLCPP_ERROR_STREAM(LOGGER, "base_frame '" << base_frame_ << "' does not exist.");
435
436 if (!robot_model.hasLinkModel(params_.link_prefix + IKFAST_TIP_FRAME_)) {
437 RCLCPP_ERROR_STREAM(LOGGER, "prefixed tip frame '" << params_.link_prefix + IKFAST_TIP_FRAME_
438 << "' does not exist. "
439 "Please check your link_prefix parameter.");
440 }
441 if (!robot_model.hasLinkModel(params_.link_prefix + IKFAST_BASE_FRAME_)) {
442 RCLCPP_ERROR_STREAM(LOGGER, "prefixed base frame '" << params_.link_prefix + IKFAST_BASE_FRAME_
443 << "' does not exist. "
444 "Please check your link_prefix parameter.");
445 }
446 // This IKFast solution was generated with IKFAST_TIP_FRAME_ and IKFAST_BASE_FRAME_.
447 // It is often the case that fixed joints are added to these links to model things like
448 // a robot mounted on a table or a robot with an end effector attached to the last link.
449 // To support these use cases, we store the transform from the IKFAST_BASE_FRAME_ to the
450 // base_frame_ and IKFAST_TIP_FRAME_ the tip_frame_ and transform to the input pose accordingly
451 if (!computeRelativeTransform(tip_frames_[0], params_.link_prefix + IKFAST_TIP_FRAME_, group_tip_to_chain_tip_,
452 tip_transform_required_) ||
453 !computeRelativeTransform(params_.link_prefix + IKFAST_BASE_FRAME_, base_frame_, chain_base_to_group_base_,
454 base_transform_required_))
455 {
456 return false;
457 }
458
459 // IKFast56/61
460 fillFreeParams(GetNumFreeParameters(), GetFreeParameters());
461
462 if (free_params_.size() > 1)
463 {
464 RCLCPP_ERROR(LOGGER, "Only one free joint parameter supported!");
465 return false;
466 }
467 else if (free_params_.size() == 1)
468 {
470 redundant_joint_indices_.push_back(free_params_[0]);
471 KinematicsBase::setSearchDiscretization(search_discretization);
472 }
473
474 const moveit::core::JointModelGroup* jmg = robot_model_->getJointModelGroup(group_name);
475 if (!jmg)
476 {
477 RCLCPP_ERROR_STREAM(LOGGER, "Unknown planning group: " << group_name);
478 return false;
479 }
480
481 RCLCPP_DEBUG_STREAM(LOGGER, "Registering joints and links");
482 const moveit::core::LinkModel* link = robot_model_->getLinkModel(tip_frames_[0]);
483 const moveit::core::LinkModel* base_link = robot_model_->getLinkModel(base_frame_);
484 while (link && link != base_link)
485 {
486 RCLCPP_DEBUG_STREAM(LOGGER, "Link " << link->getName());
487 link_names_.push_back(link->getName());
488 const moveit::core::JointModel* joint = link->getParentJointModel();
489 if (joint->getType() != joint->UNKNOWN && joint->getType() != joint->FIXED && joint->getVariableCount() == 1)
490 {
491 RCLCPP_DEBUG_STREAM(LOGGER, "Adding joint " << joint->getName());
492
493 joint_names_.push_back(joint->getName());
494 const moveit::core::VariableBounds& bounds = joint->getVariableBounds()[0];
495 joint_has_limits_vector_.push_back(bounds.position_bounded_);
496 joint_min_vector_.push_back(bounds.min_position_);
497 joint_max_vector_.push_back(bounds.max_position_);
498 }
499 link = link->getParentLinkModel();
500 }
501
502 if (joint_names_.size() != num_joints_)
503 {
504 RCLCPP_FATAL(LOGGER, "Joint numbers of RobotModel (%zd) and IKFast solver (%zd) do not match", joint_names_.size(),
505 num_joints_);
506 return false;
507 }
508
509 std::reverse(link_names_.begin(), link_names_.end());
510 std::reverse(joint_names_.begin(), joint_names_.end());
511 std::reverse(joint_min_vector_.begin(), joint_min_vector_.end());
512 std::reverse(joint_max_vector_.begin(), joint_max_vector_.end());
513 std::reverse(joint_has_limits_vector_.begin(), joint_has_limits_vector_.end());
514
515 for (size_t joint_id = 0; joint_id < num_joints_; ++joint_id) {
516 RCLCPP_DEBUG_STREAM(LOGGER, joint_names_[joint_id] << ' ' << joint_min_vector_[joint_id] << ' '
517 << joint_max_vector_[joint_id] << ' '
518 << joint_has_limits_vector_[joint_id]);
519 }
520
521 initialized_ = true;
522 return true;
523}
524
525void IKFastKinematicsPlugin::setSearchDiscretization(const std::map<unsigned int, double>& discretization)
526{
527 if (discretization.empty())
528 {
529 RCLCPP_ERROR(LOGGER, "The 'discretization' map is empty");
530 return;
531 }
532
533 if (redundant_joint_indices_.empty())
534 {
535 RCLCPP_ERROR_STREAM(LOGGER, "This group's solver doesn't support redundant joints");
536 return;
537 }
538
539 if (discretization.begin()->first != redundant_joint_indices_[0])
540 {
541 std::string redundant_joint = joint_names_[free_params_[0]];
542 RCLCPP_ERROR_STREAM(LOGGER, "Attempted to discretize a non-redundant joint "
543 << discretization.begin()->first << ", only joint '" << redundant_joint
544 << "' with index " << redundant_joint_indices_[0] << " is redundant.");
545 return;
546 }
547
548 if (discretization.begin()->second <= 0.0)
549 {
550 RCLCPP_ERROR_STREAM(LOGGER, "Discretization can not takes values that are <= 0");
551 return;
552 }
553
555 redundant_joint_discretization_[redundant_joint_indices_[0]] = discretization.begin()->second;
556}
557
558bool IKFastKinematicsPlugin::setRedundantJoints(const std::vector<unsigned int>& /* unused */)
559{
560 RCLCPP_ERROR_STREAM(LOGGER, "Changing the redundant joints isn't permitted by this group's solver ");
561 return false;
562}
563
564size_t IKFastKinematicsPlugin::solve(KDL::Frame& pose_frame, const std::vector<double>& vfree,
565 IkSolutionList<IkReal>& solutions) const
566{
567 // IKFast56/61
568 solutions.Clear();
569
570 double trans[3];
571 trans[0] = pose_frame.p[0]; //-.18;
572 trans[1] = pose_frame.p[1];
573 trans[2] = pose_frame.p[2];
574
575 KDL::Rotation mult;
576 KDL::Vector direction;
577
578 switch (GetIkType())
579 {
580 case IKP_Transform6D:
582 // For **Transform6D**, eerot is 9 values for the 3x3 rotation matrix. For **Translation3D**, these are ignored.
583
584 mult = pose_frame.M;
585
586 double vals[9];
587 vals[0] = mult(0, 0);
588 vals[1] = mult(0, 1);
589 vals[2] = mult(0, 2);
590 vals[3] = mult(1, 0);
591 vals[4] = mult(1, 1);
592 vals[5] = mult(1, 2);
593 vals[6] = mult(2, 0);
594 vals[7] = mult(2, 1);
595 vals[8] = mult(2, 2);
596
597 // IKFast56/61
598 ComputeIk(trans, vals, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
599 return solutions.GetNumSolutions();
600
601 case IKP_Direction3D:
602 case IKP_Ray4D:
604 // For **Direction3D**, **Ray4D**, and **TranslationDirection5D**, the first 3 values represent the target
605 // direction.
606
607 direction = pose_frame.M * KDL::Vector(0, 0, 1);
608 ComputeIk(trans, direction.data, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
609 return solutions.GetNumSolutions();
610
614 // For *TranslationXAxisAngle4D*, *TranslationYAxisAngle4D*, *TranslationZAxisAngle4D* - end effector origin
615 // reaches desired 3D translation, manipulator direction makes a specific angle with x/y/z-axis (defined in the
616 // manipulator base link’s coordinate system)
617 RCLCPP_ERROR(LOGGER, "IK for this IkParameterizationType not implemented yet.");
618 return 0;
619
621 // For **TranslationLocalGlobal6D**, the diagonal elements ([0],[4],[8]) are the local translation inside the end
622 // effector coordinate system.
623 RCLCPP_ERROR(LOGGER, "IK for this IkParameterizationType not implemented yet.");
624 return 0;
625
626 case IKP_Rotation3D:
627 case IKP_Lookat3D:
630 RCLCPP_ERROR(LOGGER, "IK for this IkParameterizationType not implemented yet.");
631 return 0;
632
634 double roll, pitch, yaw;
635 // For **TranslationXAxisAngleZNorm4D** - end effector origin reaches desired 3D translation, manipulator
636 // direction needs to be orthogonal to z axis and be rotated at a certain angle starting from the x axis (defined
637 // in the manipulator base link’s coordinate system)
638 pose_frame.M.GetRPY(roll, pitch, yaw);
639 ComputeIk(trans, &yaw, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
640 return solutions.GetNumSolutions();
641
643 // For **TranslationYAxisAngleXNorm4D** - end effector origin reaches desired 3D translation, manipulator
644 // direction needs to be orthogonal to x axis and be rotated at a certain angle starting from the y axis (defined
645 // in the manipulator base link’s coordinate system)
646 pose_frame.M.GetRPY(roll, pitch, yaw);
647 ComputeIk(trans, &roll, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
648 return solutions.GetNumSolutions();
649
651 // For **TranslationZAxisAngleYNorm4D** - end effector origin reaches desired 3D translation, manipulator
652 // direction needs to be orthogonal to y axis and be rotated at a certain angle starting from the z axis (defined
653 // in the manipulator base link’s coordinate system)
654 pose_frame.M.GetRPY(roll, pitch, yaw);
655 ComputeIk(trans, &pitch, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
656 return solutions.GetNumSolutions();
657
658 default:
659 RCLCPP_ERROR(LOGGER, "Unknown IkParameterizationType! "
660 "Was the solver generated with an incompatible version of Openrave?");
661 return 0;
662 }
663}
664
665void IKFastKinematicsPlugin::getSolution(const IkSolutionList<IkReal>& solutions, int i,
666 std::vector<double>& solution) const
667{
668 solution.clear();
669 solution.resize(num_joints_);
670
671 // IKFast56/61
672 const IkSolutionBase<IkReal>& sol = solutions.GetSolution(i);
673 std::vector<IkReal> vsolfree(sol.GetFree().size());
674 sol.GetSolution(&solution[0], vsolfree.size() > 0 ? &vsolfree[0] : nullptr);
675
676 for (std::size_t joint_id = 0; joint_id < num_joints_; ++joint_id)
677 {
678 if (joint_has_limits_vector_[joint_id])
679 {
680 solution[joint_id] = enforceLimits(solution[joint_id], joint_min_vector_[joint_id], joint_max_vector_[joint_id]);
681 }
682 }
683}
684
685void IKFastKinematicsPlugin::getSolution(const IkSolutionList<IkReal>& solutions,
686 const std::vector<double>& ik_seed_state, int i,
687 std::vector<double>& solution) const
688{
689 solution.clear();
690 solution.resize(num_joints_);
691
692 // IKFast56/61
693 const IkSolutionBase<IkReal>& sol = solutions.GetSolution(i);
694 std::vector<IkReal> vsolfree(sol.GetFree().size());
695 sol.GetSolution(&solution[0], vsolfree.size() > 0 ? &vsolfree[0] : nullptr);
696
697 // rotate joints by +/-360° where it is possible and useful
698 for (std::size_t i = 0; i < num_joints_; ++i)
699 {
700 if (joint_has_limits_vector_[i])
701 {
702 solution[i] = enforceLimits(solution[i], joint_min_vector_[i], joint_max_vector_[i]);
703 double signed_distance = solution[i] - ik_seed_state[i];
704 while (signed_distance > M_PI && solution[i] - 2 * M_PI > (joint_min_vector_[i] - LIMIT_TOLERANCE))
705 {
706 signed_distance -= 2 * M_PI;
707 solution[i] -= 2 * M_PI;
708 }
709 while (signed_distance < -M_PI && solution[i] + 2 * M_PI < (joint_max_vector_[i] + LIMIT_TOLERANCE))
710 {
711 signed_distance += 2 * M_PI;
712 solution[i] += 2 * M_PI;
713 }
714 }
715 }
716}
717
718double IKFastKinematicsPlugin::enforceLimits(double joint_value, double min, double max) const
719{
720 // If the joint_value is greater than max subtract 2 * PI until it is less than the max
721 while (joint_value > max)
722 {
723 joint_value -= 2 * M_PI;
724 }
725
726 // If the joint_value is less than the min, add 2 * PI until it is more than the min
727 while (joint_value < min)
728 {
729 joint_value += 2 * M_PI;
730 }
731 return joint_value;
732}
733
734void IKFastKinematicsPlugin::fillFreeParams(int count, int* array)
735{
736 free_params_.clear();
737 for (int i = 0; i < count; ++i)
738 free_params_.push_back(array[i]);
739}
740
741bool IKFastKinematicsPlugin::getCount(int& count, int max_count, int min_count) const
742{
743 if (count > 0)
744 {
745 if (-count >= min_count)
746 {
747 count = -count;
748 return true;
749 }
750 else if (count + 1 <= max_count)
751 {
752 count = count + 1;
753 return true;
754 }
755 else
756 {
757 return false;
758 }
759 }
760 else
761 {
762 if (1 - count <= max_count)
763 {
764 count = 1 - count;
765 return true;
766 }
767 else if (count - 1 >= min_count)
768 {
769 count = count - 1;
770 return true;
771 }
772 else
773 return false;
774 }
775}
776
777bool IKFastKinematicsPlugin::getPositionFK(const std::vector<std::string>& link_names,
778 const std::vector<double>& joint_angles,
779 std::vector<geometry_msgs::msg::Pose>& poses) const
780{
781 if (GetIkType() != IKP_Transform6D)
782 {
783 // ComputeFk() is the inverse function of ComputeIk(), so the format of
784 // eerot differs depending on IK type. The Transform6D IK type is the only
785 // one for which a 3x3 rotation matrix is returned, which means we can only
786 // compute FK for that IK type.
787 RCLCPP_ERROR(LOGGER, "Can only compute FK for Transform6D IK type!");
788 return false;
789 }
790
791 KDL::Frame p_out;
792 if (link_names.size() == 0)
793 {
794 RCLCPP_WARN_STREAM(LOGGER, "Link names with nothing");
795 return false;
796 }
797
798 if (link_names.size() != 1 || link_names[0] != getTipFrame())
799 {
800 RCLCPP_ERROR(LOGGER, "Can compute FK for %s only", getTipFrame().c_str());
801 return false;
802 }
803
804 bool valid = true;
805
806 IkReal eerot[9], eetrans[3];
807
808 if (joint_angles.size() != num_joints_)
809 {
810 RCLCPP_ERROR(LOGGER, "Unexpected number of joint angles");
811 return false;
812 }
813
814 std::vector<IkReal> angles(num_joints_, 0);
815 for (unsigned char i = 0; i < num_joints_; i++)
816 angles[i] = joint_angles[i];
817
818 // IKFast56/61
819 ComputeFk(angles.data(), eetrans, eerot);
820
821 for (int i = 0; i < 3; ++i)
822 p_out.p.data[i] = eetrans[i];
823
824 for (int i = 0; i < 9; ++i)
825 p_out.M.data[i] = eerot[i];
826
827 poses.resize(1);
828 poses[0] = tf2::toMsg(p_out);
829
830 return valid;
831}
832
833bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
834 const std::vector<double>& ik_seed_state, double timeout,
835 std::vector<double>& solution, moveit_msgs::msg::MoveItErrorCodes& error_code,
836 const kinematics::KinematicsQueryOptions& options) const
837{
838 std::vector<double> consistency_limits;
839 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, IKCallbackFn(), error_code,
840 options);
841}
842
843bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
844 const std::vector<double>& ik_seed_state, double timeout,
845 const std::vector<double>& consistency_limits,
846 std::vector<double>& solution, moveit_msgs::msg::MoveItErrorCodes& error_code,
847 const kinematics::KinematicsQueryOptions& options) const
848{
849 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, IKCallbackFn(), error_code,
850 options);
851}
852
853bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
854 const std::vector<double>& ik_seed_state, double timeout,
855 std::vector<double>& solution, const IKCallbackFn& solution_callback,
856 moveit_msgs::msg::MoveItErrorCodes& error_code,
857 const kinematics::KinematicsQueryOptions& options) const
858{
859 std::vector<double> consistency_limits;
860 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, solution_callback, error_code,
861 options);
862}
863
864bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
865 const std::vector<double>& ik_seed_state, double /* unused */,
866 const std::vector<double>& consistency_limits,
867 std::vector<double>& solution, const IKCallbackFn& solution_callback,
868 moveit_msgs::msg::MoveItErrorCodes& error_code,
869 const kinematics::KinematicsQueryOptions& options) const
870{
871 // "SEARCH_MODE" is fixed during code generation
872 SEARCH_MODE search_mode = OPTIMIZE_MAX_JOINT;
873
874 // Check if there are no redundant joints
875 if (free_params_.size() == 0)
876 {
877 RCLCPP_DEBUG_STREAM(LOGGER, "No need to search since no free params/redundant joints");
878
879 std::vector<geometry_msgs::msg::Pose> ik_poses(1, ik_pose);
880 std::vector<std::vector<double>> solutions;
881 kinematics::KinematicsResult kinematic_result;
882 // Find all IK solutions within joint limits
883 if (!getPositionIK(ik_poses, ik_seed_state, solutions, kinematic_result, options))
884 {
885 RCLCPP_DEBUG_STREAM(LOGGER, "No solution whatsoever");
886 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
887 return false;
888 }
889
890 // sort solutions by their distance to the seed
891 std::vector<LimitObeyingSol> solutions_obey_limits;
892 for (std::size_t i = 0; i < solutions.size(); ++i)
893 {
894 double dist_from_seed = 0.0;
895 for (std::size_t j = 0; j < ik_seed_state.size(); ++j)
896 {
897 dist_from_seed += fabs(ik_seed_state[j] - solutions[i][j]);
898 }
899
900 solutions_obey_limits.push_back({ solutions[i], dist_from_seed });
901 }
902 std::sort(solutions_obey_limits.begin(), solutions_obey_limits.end());
903
904 // check for collisions if a callback is provided
905 if (solution_callback)
906 {
907 for (std::size_t i = 0; i < solutions_obey_limits.size(); ++i)
908 {
909 solution_callback(ik_pose, solutions_obey_limits[i].value, error_code);
910 if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
911 {
912 solution = solutions_obey_limits[i].value;
913 RCLCPP_DEBUG_STREAM(LOGGER, "Solution passes callback");
914 return true;
915 }
916 }
917
918 RCLCPP_DEBUG_STREAM(LOGGER, "Solution has error code " << error_code.val);
919 return false;
920 }
921 else
922 {
923 solution = solutions_obey_limits[0].value;
924 error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
925 return true; // no collision check callback provided
926 }
927 }
928
929 // -------------------------------------------------------------------------------------------------
930 // Error Checking
931 if (!initialized_)
932 {
933 RCLCPP_ERROR_STREAM(LOGGER, "Kinematics not active");
934 error_code.val = error_code.NO_IK_SOLUTION;
935 return false;
936 }
937
938 if (ik_seed_state.size() != num_joints_)
939 {
940 RCLCPP_ERROR_STREAM(LOGGER,
941 "Seed state must have size " << num_joints_ << " instead of size " << ik_seed_state.size());
942 error_code.val = error_code.NO_IK_SOLUTION;
943 return false;
944 }
945
946 if (!consistency_limits.empty() && consistency_limits.size() != num_joints_)
947 {
948 RCLCPP_ERROR_STREAM(LOGGER, "Consistency limits be empty or must have size " << num_joints_ << " instead of size "
949 << consistency_limits.size());
950 error_code.val = error_code.NO_IK_SOLUTION;
951 return false;
952 }
953
954 // -------------------------------------------------------------------------------------------------
955 // Initialize
956
957 KDL::Frame frame;
958 transformToChainFrame(ik_pose, frame);
959
960 std::vector<double> vfree(free_params_.size());
961
962 int counter = 0;
963
964 double initial_guess = ik_seed_state[free_params_[0]];
965 vfree[0] = initial_guess;
966
967 // -------------------------------------------------------------------------------------------------
968 // Handle consistency limits if needed
969 int num_positive_increments;
970 int num_negative_increments;
971 double search_discretization = redundant_joint_discretization_.at(free_params_[0]);
972
973 if (!consistency_limits.empty())
974 {
975 // MoveIt replaced consistency_limit (scalar) w/ consistency_limits (vector)
976 // Assume [0]th free_params element for now. Probably wrong.
977 double max_limit = fmin(joint_max_vector_[free_params_[0]], initial_guess + consistency_limits[free_params_[0]]);
978 double min_limit = fmax(joint_min_vector_[free_params_[0]], initial_guess - consistency_limits[free_params_[0]]);
979
980 num_positive_increments = static_cast<int>((max_limit - initial_guess) / search_discretization);
981 num_negative_increments = static_cast<int>((initial_guess - min_limit) / search_discretization);
982 }
983 else // no consistency limits provided
984 {
985 num_positive_increments = (joint_max_vector_[free_params_[0]] - initial_guess) / search_discretization;
986 num_negative_increments = (initial_guess - joint_min_vector_[free_params_[0]]) / search_discretization;
987 }
988
989 // -------------------------------------------------------------------------------------------------
990 // Begin searching
991
992 RCLCPP_DEBUG_STREAM(LOGGER, "Free param is " << free_params_[0] << " initial guess is " << initial_guess
993 << ", # positive increments: " << num_positive_increments
994 << ", # negative increments: " << num_negative_increments);
995 if ((search_mode & OPTIMIZE_MAX_JOINT) && (num_positive_increments + num_negative_increments) > 1000)
996 RCLCPP_WARN_STREAM_ONCE(LOGGER, "Large search space, consider increasing the search discretization");
997
998 double best_costs = -1.0;
999 std::vector<double> best_solution;
1000 int nattempts = 0, nvalid = 0;
1001
1002 while (true)
1003 {
1004 IkSolutionList<IkReal> solutions;
1005 size_t numsol = solve(frame, vfree, solutions);
1006
1007 RCLCPP_DEBUG_STREAM(LOGGER, "Found " << numsol << " solutions from IKFast");
1008
1009 if (numsol > 0)
1010 {
1011 for (size_t s = 0; s < numsol; ++s)
1012 {
1013 nattempts++;
1014 std::vector<double> sol;
1015 getSolution(solutions, ik_seed_state, s, sol);
1016
1017 bool obeys_limits = true;
1018 for (size_t i = 0; i < sol.size(); i++)
1019 {
1020 if (joint_has_limits_vector_[i] && (sol[i] < joint_min_vector_[i] || sol[i] > joint_max_vector_[i]))
1021 {
1022 obeys_limits = false;
1023 break;
1024 }
1025 // RCLCPP_INFO_STREAM(LOGGER,"Num " << i << " value " << sol[i] << " has limits " <<
1026 // joint_has_limits_vector_[i] << " " << joint_min_vector_[i] << " " << joint_max_vector_[i]);
1027 }
1028 if (obeys_limits)
1029 {
1030 getSolution(solutions, ik_seed_state, s, solution);
1031
1032 // This solution is within joint limits, now check if in collision (if callback provided)
1033 if (solution_callback)
1034 {
1035 solution_callback(ik_pose, solution, error_code);
1036 }
1037 else
1038 {
1039 error_code.val = error_code.SUCCESS;
1040 }
1041
1042 if (error_code.val == error_code.SUCCESS)
1043 {
1044 nvalid++;
1045 if (search_mode & OPTIMIZE_MAX_JOINT)
1046 {
1047 // Costs for solution: Largest joint motion
1048 double costs = 0.0;
1049 for (unsigned int i = 0; i < solution.size(); i++)
1050 {
1051 double d = fabs(ik_seed_state[i] - solution[i]);
1052 if (d > costs)
1053 costs = d;
1054 }
1055 if (costs < best_costs || best_costs == -1.0)
1056 {
1057 best_costs = costs;
1058 best_solution = solution;
1059 }
1060 }
1061 else {
1062 // Return first feasible solution
1063 return true;
1064 }
1065 }
1066 }
1067 }
1068 }
1069
1070 if (!getCount(counter, num_positive_increments, -num_negative_increments))
1071 {
1072 // Everything searched
1073 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
1074 break;
1075 }
1076
1077 vfree[0] = initial_guess + search_discretization * counter;
1078 // RCLCPP_DEBUG_STREAM(LOGGER,"Attempt " << counter << " with 0th free joint having value " << vfree[0]);
1079 }
1080
1081 RCLCPP_DEBUG_STREAM(LOGGER, "Valid solutions: " << nvalid << '/' << nattempts);
1082
1083 if ((search_mode & OPTIMIZE_MAX_JOINT) && best_costs != -1.0)
1084 {
1085 solution = best_solution;
1086 error_code.val = error_code.SUCCESS;
1087 return true;
1088 }
1089
1090 // No solution found
1091 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
1092 return false;
1093}
1094
1095// Used when there are no redundant joints - aka no free params
1096bool IKFastKinematicsPlugin::getPositionIK(const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state,
1097 std::vector<double>& solution, moveit_msgs::msg::MoveItErrorCodes& error_code,
1098 const kinematics::KinematicsQueryOptions& /* unused */) const
1099{
1100 RCLCPP_DEBUG_STREAM(LOGGER, "getPositionIK");
1101
1102 if (!initialized_)
1103 {
1104 RCLCPP_ERROR(LOGGER, "kinematics not active");
1105 return false;
1106 }
1107
1108 if (ik_seed_state.size() < num_joints_)
1109 {
1110 RCLCPP_ERROR_STREAM(LOGGER, "ik_seed_state only has " << ik_seed_state.size()
1111 << " entries, this ikfast solver requires " << num_joints_);
1112 return false;
1113 }
1114
1115 // Check if seed is in bound
1116 for (std::size_t i = 0; i < ik_seed_state.size(); i++)
1117 {
1118 // Add tolerance to limit check
1119 if (joint_has_limits_vector_[i] && ((ik_seed_state[i] < (joint_min_vector_[i] - LIMIT_TOLERANCE)) ||
1120 (ik_seed_state[i] > (joint_max_vector_[i] + LIMIT_TOLERANCE))))
1121 {
1122 RCLCPP_DEBUG_STREAM(LOGGER, "IK seed not in limits! " << static_cast<int>(i) << " value " << ik_seed_state[i]
1123 << " has limit: " << joint_has_limits_vector_[i] << " being "
1124 << joint_min_vector_[i] << " to " << joint_max_vector_[i]);
1125 return false;
1126 }
1127 }
1128
1129 std::vector<double> vfree(free_params_.size());
1130 for (std::size_t i = 0; i < free_params_.size(); ++i)
1131 {
1132 int p = free_params_[i];
1133 RCLCPP_ERROR(LOGGER, "%u is %f", p, ik_seed_state[p]); // DTC
1134 vfree[i] = ik_seed_state[p];
1135 }
1136
1137 KDL::Frame frame;
1138 transformToChainFrame(ik_pose, frame);
1139
1140 IkSolutionList<IkReal> solutions;
1141 size_t numsol = solve(frame, vfree, solutions);
1142 RCLCPP_DEBUG_STREAM(LOGGER, "Found " << numsol << " solutions from IKFast");
1143
1144 std::vector<LimitObeyingSol> solutions_obey_limits;
1145
1146 if (numsol)
1147 {
1148 std::vector<double> solution_obey_limits;
1149 for (std::size_t s = 0; s < numsol; ++s)
1150 {
1151 std::vector<double> sol;
1152 getSolution(solutions, ik_seed_state, s, sol);
1153 RCLCPP_DEBUG(LOGGER, "Sol %d: %e %e %e %e %e %e", static_cast<int>(s), sol[0], sol[1], sol[2], sol[3],
1154 sol[4], sol[5]);
1155
1156 bool obeys_limits = true;
1157 for (std::size_t i = 0; i < sol.size(); i++)
1158 {
1159 // Add tolerance to limit check
1160 if (joint_has_limits_vector_[i] && ((sol[i] < (joint_min_vector_[i] - LIMIT_TOLERANCE)) ||
1161 (sol[i] > (joint_max_vector_[i] + LIMIT_TOLERANCE))))
1162 {
1163 // One element of solution is not within limits
1164 obeys_limits = false;
1165 RCLCPP_DEBUG_STREAM(LOGGER, "Not in limits! " << static_cast<int>(i) << " value " << sol[i]
1166 << " has limit: " << joint_has_limits_vector_[i] << " being "
1167 << joint_min_vector_[i] << " to " << joint_max_vector_[i]);
1168 break;
1169 }
1170 }
1171 if (obeys_limits)
1172 {
1173 // All elements of this solution obey limits
1174 getSolution(solutions, ik_seed_state, s, solution_obey_limits);
1175 double dist_from_seed = 0.0;
1176 for (std::size_t i = 0; i < ik_seed_state.size(); ++i)
1177 {
1178 dist_from_seed += fabs(ik_seed_state[i] - solution_obey_limits[i]);
1179 }
1180
1181 solutions_obey_limits.push_back({ solution_obey_limits, dist_from_seed });
1182 }
1183 }
1184 }
1185 else
1186 {
1187 RCLCPP_DEBUG_STREAM(LOGGER, "No IK solution");
1188 }
1189
1190 // Sort the solutions under limits and find the one that is closest to ik_seed_state
1191 if (!solutions_obey_limits.empty())
1192 {
1193 std::sort(solutions_obey_limits.begin(), solutions_obey_limits.end());
1194 solution = solutions_obey_limits[0].value;
1195 error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
1196 return true;
1197 }
1198
1199 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
1200 return false;
1201}
1202
1203bool IKFastKinematicsPlugin::getPositionIK(const std::vector<geometry_msgs::msg::Pose>& ik_poses,
1204 const std::vector<double>& ik_seed_state,
1205 std::vector<std::vector<double>>& solutions,
1207 const kinematics::KinematicsQueryOptions& options) const
1208{
1209 RCLCPP_DEBUG_STREAM(LOGGER, "getPositionIK with multiple solutions");
1210
1211 if (!initialized_)
1212 {
1213 RCLCPP_ERROR(LOGGER, "kinematics not active");
1215 return false;
1216 }
1217
1218 if (ik_poses.empty())
1219 {
1220 RCLCPP_ERROR(LOGGER, "ik_poses is empty");
1222 return false;
1223 }
1224
1225 if (ik_poses.size() > 1)
1226 {
1227 RCLCPP_ERROR(LOGGER, "ik_poses contains multiple entries, only one is allowed");
1229 return false;
1230 }
1231
1232 if (ik_seed_state.size() < num_joints_)
1233 {
1234 RCLCPP_ERROR_STREAM(LOGGER, "ik_seed_state only has " << ik_seed_state.size()
1235 << " entries, this ikfast solver requires " << num_joints_);
1236 return false;
1237 }
1238
1239 KDL::Frame frame;
1240 transformToChainFrame(ik_poses[0], frame);
1241
1242 // solving ik
1243 std::vector<IkSolutionList<IkReal>> solution_set;
1244 IkSolutionList<IkReal> ik_solutions;
1245 std::vector<double> vfree;
1246 int numsol = 0;
1247 std::vector<double> sampled_joint_vals;
1248 if (!redundant_joint_indices_.empty())
1249 {
1250 // initializing from seed
1251 sampled_joint_vals.push_back(ik_seed_state[redundant_joint_indices_[0]]);
1252
1253 // checking joint limits when using no discretization
1254 if (options.discretization_method == kinematics::DiscretizationMethods::NO_DISCRETIZATION &&
1255 joint_has_limits_vector_[redundant_joint_indices_.front()])
1256 {
1257 double joint_min = joint_min_vector_[redundant_joint_indices_.front()];
1258 double joint_max = joint_max_vector_[redundant_joint_indices_.front()];
1259
1260 double jv = sampled_joint_vals[0];
1261 if (!((jv > (joint_min - LIMIT_TOLERANCE)) && (jv < (joint_max + LIMIT_TOLERANCE))))
1262 {
1264 RCLCPP_ERROR_STREAM(LOGGER, "ik seed is out of bounds");
1265 return false;
1266 }
1267 }
1268
1269 // computing all solutions sets for each sampled value of the redundant joint
1270 if (!sampleRedundantJoint(options.discretization_method, sampled_joint_vals))
1271 {
1273 return false;
1274 }
1275
1276 for (unsigned int i = 0; i < sampled_joint_vals.size(); i++)
1277 {
1278 vfree.clear();
1279 vfree.push_back(sampled_joint_vals[i]);
1280 numsol += solve(frame, vfree, ik_solutions);
1281 solution_set.push_back(ik_solutions);
1282 }
1283 }
1284 else
1285 {
1286 // computing for single solution set
1287 numsol = solve(frame, vfree, ik_solutions);
1288 solution_set.push_back(ik_solutions);
1289 }
1290
1291 RCLCPP_DEBUG_STREAM(LOGGER, "Found " << numsol << " solutions from IKFast");
1292 bool solutions_found = false;
1293 if (numsol > 0)
1294 {
1295 /*
1296 Iterating through all solution sets and storing those that do not exceed joint limits.
1297 */
1298 for (unsigned int r = 0; r < solution_set.size(); r++)
1299 {
1300 ik_solutions = solution_set[r];
1301 numsol = ik_solutions.GetNumSolutions();
1302 for (int s = 0; s < numsol; ++s)
1303 {
1304 std::vector<double> sol;
1305 getSolution(ik_solutions, ik_seed_state, s, sol);
1306
1307 bool obeys_limits = true;
1308 for (unsigned int i = 0; i < sol.size(); i++)
1309 {
1310 // Add tolerance to limit check
1311 if (joint_has_limits_vector_[i] && ((sol[i] < (joint_min_vector_[i] - LIMIT_TOLERANCE)) ||
1312 (sol[i] > (joint_max_vector_[i] + LIMIT_TOLERANCE))))
1313 {
1314 // One element of solution is not within limits
1315 obeys_limits = false;
1316 RCLCPP_DEBUG_STREAM(LOGGER, "Not in limits! " << i << " value " << sol[i]
1317 << " has limit: " << joint_has_limits_vector_[i] << " being "
1318 << joint_min_vector_[i] << " to " << joint_max_vector_[i]);
1319 break;
1320 }
1321 }
1322 if (obeys_limits)
1323 {
1324 // All elements of solution obey limits
1325 solutions_found = true;
1326 solutions.push_back(sol);
1327 }
1328 }
1329 }
1330
1331 if (solutions_found)
1332 {
1334 return true;
1335 }
1336 }
1337 else
1338 {
1339 RCLCPP_DEBUG_STREAM(LOGGER, "No IK solution");
1340 }
1341
1343 return false;
1344}
1345
1346bool IKFastKinematicsPlugin::sampleRedundantJoint(kinematics::DiscretizationMethod method,
1347 std::vector<double>& sampled_joint_vals) const
1348{
1349 int index = redundant_joint_indices_.front();
1350 double joint_dscrt = redundant_joint_discretization_.at(index);
1351 double joint_min = joint_min_vector_[index];
1352 double joint_max = joint_max_vector_[index];
1353
1354 switch (method)
1355 {
1357 {
1358 size_t steps = std::ceil((joint_max - joint_min) / joint_dscrt);
1359 for (size_t i = 0; i < steps; i++)
1360 {
1361 sampled_joint_vals.push_back(joint_min + joint_dscrt * i);
1362 }
1363 sampled_joint_vals.push_back(joint_max);
1364 }
1365 break;
1367 {
1368 int steps = std::ceil((joint_max - joint_min) / joint_dscrt);
1369 steps = steps > 0 ? steps : 1;
1370 double diff = joint_max - joint_min;
1371 for (int i = 0; i < steps; i++)
1372 {
1373 sampled_joint_vals.push_back(((diff * std::rand()) / (static_cast<double>(RAND_MAX))) + joint_min);
1374 }
1375 }
1376
1377 break;
1379
1380 break;
1381 default:
1382 RCLCPP_ERROR_STREAM(LOGGER, "Discretization method " << method << " is not supported");
1383 return false;
1384 }
1385
1386 return true;
1387}
1388
1389void IKFastKinematicsPlugin::transformToChainFrame(const geometry_msgs::msg::Pose& ik_pose, KDL::Frame& ik_pose_chain) const
1390{
1391 if (tip_transform_required_ || base_transform_required_)
1392 {
1393 Eigen::Isometry3d ik_eigen_pose;
1394 tf2::fromMsg(ik_pose, ik_eigen_pose);
1395 if (tip_transform_required_)
1396 ik_eigen_pose = ik_eigen_pose * group_tip_to_chain_tip_;
1397
1398 if (base_transform_required_)
1399 ik_eigen_pose = chain_base_to_group_base_ * ik_eigen_pose;
1400
1401 tf2::transformEigenToKDL(ik_eigen_pose, ik_pose_chain);
1402 }
1403 else
1404 {
1405 tf2::fromMsg(ik_pose, ik_pose_chain);
1406 }
1407}
1408
1409} // namespace prbt_manipulator
1410
1411// register IKFastKinematicsPlugin as a KinematicsBase implementation
1412#include <pluginlib/class_list_macros.hpp>
virtual const std::vector< int > & GetFree() const =0
Gets the indices of the configuration space that have to be preset before a full solution can be retu...
virtual void GetSolution(T *solution, const T *freevalues) const =0
gets a concrete solution
Default implementation of IkSolutionListBase.
Definition ikfast.h:273
virtual const IkSolutionBase< T > & GetSolution(size_t index) const
returns the solution pointer
Definition ikfast.h:282
virtual size_t GetNumSolutions() const
returns the number of solutions stored
Definition ikfast.h:293
virtual void Clear()
clears all current solutions, note that any memory addresses returned from GetSolution will be invali...
Definition ikfast.h:298
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)
std::map< int, double > redundant_joint_discretization_
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.
std::vector< unsigned int > redundant_joint_indices_
virtual const std::vector< std::string > & getLinkNames() const =0
Return all the link names in the order they are represented internally.
std::vector< DiscretizationMethod > supported_methods_
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...
std::vector< std::string > tip_frames_
moveit::core::RobotModelConstPtr robot_model_
virtual const std::vector< std::string > & getJointNames() const =0
Return all the joint names in the order they are used internally.
std::size_t getVariableCount() const
Get the number of variables that describe this joint.
const std::string & getName() const
Get the name of the joint.
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a variable. Throw an exception if the variable was not found.
JointType getType() const
Get the type of joint.
const std::string & getName() const
The name of this link.
const JointModel * getParentJointModel() const
Get the joint model whose child this link is. There will always be a parent joint.
const LinkModel * getParentLinkModel() const
Get the link model whose child this link is (through some joint). There may not always be a parent li...
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
bool hasLinkModel(const std::string &name) const
Check if a link exists. Return true if it does.
void setSearchDiscretization(const std::map< unsigned int, double > &discretization)
Sets the discretization value for the redundant joint.
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....
bool setRedundantJoints(const std::vector< unsigned int > &redundant_joint_indices) override
Overrides the default method to prevent changing the redundant joints.
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.
IKFastKinematicsPlugin()
Interface for an IKFast kinematics plugin.
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.
const double LIMIT_TOLERANCE
SEARCH_MODE
Search modes for searchPositionIK(), see there.
DiscretizationMethods::DiscretizationMethod DiscretizationMethod
Core components of MoveIt.
IKFAST_API void ComputeFk(const IkReal *j, IkReal *eetrans, IkReal *eerot)
IKFAST_API bool ComputeIk(const IkReal *eetrans, const IkReal *eerot, const IkReal *pfree, IkSolutionListBase< IkReal > &solutions)
IkParameterizationType
The types of inverse kinematics parameterizations supported.
@ IKP_Direction3D
direction on end effector coordinate system reaches desired direction
@ IKP_UniqueIdMask
the mask for the unique ids
@ IKP_TranslationXY2D
2D translation along XY plane
@ IKP_NumberOfParameterizations
number of parameterizations (does not count IKP_None)
@ IKP_TranslationLocalGlobal6D
local point on end effector origin reaches desired 3D global point
@ IKP_Ray4D
ray on end effector coordinate system reaches desired global ray
@ IKP_Translation3D
end effector origin reaches desired 3D translation
@ IKP_Rotation3D
end effector reaches desired 3D rotation
@ IKP_VelocityDataBit
bit is set if the data represents the time-derivate velocity of an IkParameterization
@ IKP_Transform6D
end effector reaches desired 6D transformation
@ IKP_Lookat3D
direction on end effector coordinate system points to desired 3D position
PLUGINLIB_EXPORT_CLASS(prbt_manipulator::IKFastKinematicsPlugin, kinematics::KinematicsBase)
A set of options for the kinematics solver.