moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
ikfast61_moveit_plugin_template.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#include <cmath>
45#include <list>
46#include <vector>
47#include <limits>
48#include <complex>
49
50#include <rclcpp/rclcpp.hpp>
53#include <Eigen/Geometry>
54#include <tf2_kdl/tf2_kdl.hpp>
55#include <tf2_eigen/tf2_eigen.hpp>
57#include <_PACKAGE_NAME_/ikfast_kinematics_parameters.hpp>
58
59using namespace moveit::core;
60
61// Need a floating point tolerance when checking joint limits, in case the joint starts at limit
62const double LIMIT_TOLERANCE = .0000001;
69
70namespace _NAMESPACE_
71{
72namespace
73{
74rclcpp::Logger getLogger()
75{
76 return moveit::getLogger("moveit.core._ROBOT_NAME___GROUP_NAME__ikfast_solver");
77}
78} // namespace
79
80#define IKFAST_NO_MAIN // Don't include main() from IKFast
81
88{
90 IKP_Transform6D = 0x67000001,
91 IKP_Rotation3D = 0x34000002,
92 IKP_Translation3D = 0x33000003,
93 IKP_Direction3D = 0x23000004,
94 IKP_Ray4D = 0x46000005,
95 IKP_Lookat3D = 0x23000006,
99 IKP_TranslationXY2D = 0x22000008,
104
114
127
129
131 0x00008000,
148
149 IKP_UniqueIdMask = 0x0000ffff,
150 IKP_CustomDataBit = 0x00010000,
152};
153
154// struct for storing and sorting solutions
156{
157 std::vector<double> value;
159
160 bool operator<(const LimitObeyingSol& a) const
161 {
163 }
164};
165
166// Code generated by IKFast56/61
167#include "_ROBOT_NAME___GROUP_NAME__ikfast_solver.cpp"
168
170{
171 std::vector<std::string> joint_names_;
172 std::vector<double> joint_min_vector_;
173 std::vector<double> joint_max_vector_;
174 std::vector<bool> joint_has_limits_vector_;
175 std::vector<std::string> link_names_;
176 const size_t num_joints_;
177 std::vector<int> free_params_;
178
179 std::shared_ptr<ikfast_kinematics::ParamListener> param_listener_;
180 ikfast_kinematics::Params params_;
181
182 // The ikfast and base frame are the start and end of the kinematic chain for which the
183 // IKFast analytic solution was generated.
184 const std::string IKFAST_TIP_FRAME_ = "_EEF_LINK_";
185 const std::string IKFAST_BASE_FRAME_ = "_BASE_LINK_";
186
187 // The transform tip and base bool are set to true if this solver is used with a kinematic
188 // chain that extends beyond the ikfast tip and base frame. The solution will be valid so
189 // long as there are no active, passive, or mimic joints between either the ikfast_tip_frame
190 // and the tip_frame of the group or the ikfast_base_frame and the base_frame for the group.
191 bool tip_transform_required_;
192 bool base_transform_required_;
193
194 // We store the transform from the ikfast_base_frame to the group base_frame as well as the
195 // ikfast_tip_frame to the group tip_frame to transform input poses into the solver frame.
196 Eigen::Isometry3d chain_base_to_group_base_;
197 Eigen::Isometry3d group_tip_to_chain_tip_;
198
199 bool initialized_; // Internal variable that indicates whether solvers are configured and ready
200
201 const std::vector<std::string>& getJointNames() const override
202 {
203 return joint_names_;
204 }
205 const std::vector<std::string>& getLinkNames() const override
206 {
207 return link_names_;
208 }
209
210public:
221
230
231 // Returns the IK solution that is within joint limits closest to ik_seed_state
232 bool
233 getPositionIK(const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state,
234 std::vector<double>& solution, moveit_msgs::msg::MoveItErrorCodes& error_code,
236
252 bool getPositionIK(const std::vector<geometry_msgs::msg::Pose>& ik_poses, const std::vector<double>& ik_seed_state,
253 std::vector<std::vector<double>>& solutions, kinematics::KinematicsResult& result,
254 const kinematics::KinematicsQueryOptions& options) const override;
255
264 bool searchPositionIK(
265 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
266 std::vector<double>& solution, moveit_msgs::msg::MoveItErrorCodes& error_code,
268
278 bool searchPositionIK(
279 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
280 const std::vector<double>& consistency_limits, std::vector<double>& solution,
281 moveit_msgs::msg::MoveItErrorCodes& error_code,
283
292 bool searchPositionIK(
293 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
294 std::vector<double>& solution, const IKCallbackFn& solution_callback,
295 moveit_msgs::msg::MoveItErrorCodes& error_code,
297
308 bool searchPositionIK(
309 const geometry_msgs::msg::Pose& ik_pose, const std::vector<double>& ik_seed_state, double timeout,
310 const std::vector<double>& consistency_limits, std::vector<double>& solution,
311 const IKCallbackFn& solution_callback, moveit_msgs::msg::MoveItErrorCodes& error_code,
313
322 bool getPositionFK(const std::vector<std::string>& link_names, const std::vector<double>& joint_angles,
323 std::vector<geometry_msgs::msg::Pose>& poses) const override;
324
334 void setSearchDiscretization(const std::map<unsigned int, double>& discretization);
335
339 bool setRedundantJoints(const std::vector<unsigned int>& redundant_joint_indices) override;
340
341private:
342 bool initialize(const rclcpp::Node::SharedPtr& node, const moveit::core::RobotModel& robot_model,
343 const std::string& group_name, const std::string& base_frame,
344 const std::vector<std::string>& tip_frames, double search_discretization) override;
345
350 size_t solve(KDL::Frame& pose_frame, const std::vector<double>& vfree, IkSolutionList<IkReal>& solutions) const;
351
355 void getSolution(const IkSolutionList<IkReal>& solutions, int i, std::vector<double>& solution) const;
356
360 void getSolution(const IkSolutionList<IkReal>& solutions, const std::vector<double>& ik_seed_state, int i,
361 std::vector<double>& solution) const;
362
366 double enforceLimits(double val, double min, double max) const;
367
368 void fillFreeParams(int count, int* array);
369 bool getCount(int& count, int max_count, int min_count) const;
370
377 bool sampleRedundantJoint(kinematics::DiscretizationMethod method, std::vector<double>& sampled_joint_vals) const;
378
380 bool computeRelativeTransform(const std::string& from, const std::string& to, Eigen::Isometry3d& transform,
381 bool& differs_from_identity);
388 void transformToChainFrame(const geometry_msgs::msg::Pose& ik_pose, KDL::Frame& ik_pose_chain) const;
389}; // end class
390
391bool IKFastKinematicsPlugin::computeRelativeTransform(const std::string& from, const std::string& to,
392 Eigen::Isometry3d& transform, bool& differs_from_identity)
393{
394 RobotStatePtr robot_state;
395 robot_state = std::make_shared<RobotState>(robot_model_);
396 robot_state->setToDefaultValues();
397
398 bool has_link; // to suppress RCLCPP_ERRORs for non-existent frames
399 auto* from_link = robot_model_->getLinkModel(from, &has_link);
400 auto* to_link = robot_model_->getLinkModel(to, &has_link);
401 if (!from_link || !to_link)
402 return false;
403
404 if (robot_model_->getRigidlyConnectedParentLinkModel(from_link) !=
405 robot_model_->getRigidlyConnectedParentLinkModel(to_link))
406 {
407 RCLCPP_ERROR_STREAM(getLogger(), "Link frames " << from << " and " << to << " are not rigidly connected.");
408 return false;
409 }
410
411 transform = robot_state->getGlobalLinkTransform(from_link).inverse() * robot_state->getGlobalLinkTransform(to_link);
412 differs_from_identity = !transform.matrix().isIdentity();
413 return true;
414}
415
416bool IKFastKinematicsPlugin::initialize(const rclcpp::Node::SharedPtr& node,
417 const moveit::core::RobotModel& robot_model, const std::string& group_name,
418 const std::string& base_frame, const std::vector<std::string>& tip_frames,
419 double search_discretization)
420{
421 if (tip_frames.size() != 1)
422 {
423 RCLCPP_ERROR(getLogger(), "Expecting exactly one tip frame.");
424 return false;
425 }
426
427 // Get Solver Parameters
428 std::string kinematics_param_prefix = "robot_description_kinematics." + group_name;
429 param_listener_ = std::make_shared<ikfast_kinematics::ParamListener>(node, kinematics_param_prefix);
430 params_ = param_listener_->get_params();
431
432 storeValues(robot_model, group_name, base_frame, tip_frames, search_discretization);
433
434 RCLCPP_INFO_STREAM(getLogger(), "Using link_prefix: '" << params_.link_prefix << '\'');
435
436 // verbose error output. subsequent checks in computeRelativeTransform return false then
437 if (!robot_model.hasLinkModel(tip_frames_[0]))
438 RCLCPP_ERROR_STREAM(getLogger(), "tip frame '" << tip_frames_[0] << "' does not exist.");
439 if (!robot_model.hasLinkModel(base_frame_))
440 RCLCPP_ERROR_STREAM(getLogger(), "base_frame '" << base_frame_ << "' does not exist.");
441
442 if (!robot_model.hasLinkModel(params_.link_prefix + IKFAST_TIP_FRAME_))
443 RCLCPP_ERROR_STREAM(getLogger(), "prefixed tip frame '" << params_.link_prefix + IKFAST_TIP_FRAME_
444 << "' does not exist. "
445 "Please check your link_prefix parameter.");
446 if (!robot_model.hasLinkModel(params_.link_prefix + IKFAST_BASE_FRAME_))
447 RCLCPP_ERROR_STREAM(getLogger(), "prefixed base frame '" << params_.link_prefix + IKFAST_BASE_FRAME_
448 << "' does not exist. "
449 "Please check your link_prefix parameter.");
450 // This IKFast solution was generated with IKFAST_TIP_FRAME_ and IKFAST_BASE_FRAME_.
451 // It is often the case that fixed joints are added to these links to model things like
452 // a robot mounted on a table or a robot with an end effector attached to the last link.
453 // To support these use cases, we store the transform from the IKFAST_BASE_FRAME_ to the
454 // base_frame_ and IKFAST_TIP_FRAME_ the tip_frame_ and transform to the input pose accordingly
455 if (!computeRelativeTransform(tip_frames_[0], params_.link_prefix + IKFAST_TIP_FRAME_, group_tip_to_chain_tip_,
456 tip_transform_required_) ||
457 !computeRelativeTransform(params_.link_prefix + IKFAST_BASE_FRAME_, base_frame_, chain_base_to_group_base_,
458 base_transform_required_))
459 {
460 return false;
461 }
462
463 // IKFast56/61
464 fillFreeParams(GetNumFreeParameters(), GetFreeParameters());
465
466 if (free_params_.size() > 1)
467 {
468 RCLCPP_ERROR(getLogger(), "Only one free joint parameter supported!");
469 return false;
470 }
471 else if (free_params_.size() == 1)
472 {
474 redundant_joint_indices_.push_back(free_params_[0]);
475 KinematicsBase::setSearchDiscretization(search_discretization);
476 }
477
478 const moveit::core::JointModelGroup* jmg = robot_model_->getJointModelGroup(group_name);
479 if (!jmg)
480 {
481 RCLCPP_ERROR_STREAM(getLogger(), "Unknown planning group: " << group_name);
482 return false;
483 }
484
485 RCLCPP_DEBUG(getLogger(), "Registering joints and links");
486 const moveit::core::LinkModel* link = robot_model_->getLinkModel(tip_frames_[0]);
487 const moveit::core::LinkModel* base_link = robot_model_->getLinkModel(base_frame_);
488 while (link && link != base_link)
489 {
490 RCLCPP_DEBUG_STREAM(getLogger(), "Link " << link->getName());
491 link_names_.push_back(link->getName());
492 const moveit::core::JointModel* joint = link->getParentJointModel();
493 if (joint->getType() != joint->UNKNOWN && joint->getType() != joint->FIXED && joint->getVariableCount() == 1)
494 {
495 RCLCPP_DEBUG_STREAM(getLogger(), "Adding joint " << joint->getName());
496
497 joint_names_.push_back(joint->getName());
498 const moveit::core::VariableBounds& bounds = joint->getVariableBounds()[0];
499 joint_has_limits_vector_.push_back(bounds.position_bounded_);
500 joint_min_vector_.push_back(bounds.min_position_);
501 joint_max_vector_.push_back(bounds.max_position_);
502 }
503 link = link->getParentLinkModel();
504 }
505
506 if (joint_names_.size() != num_joints_)
507 {
508 RCLCPP_FATAL(getLogger(), "Joint numbers of RobotModel (%zd) and IKFast solver (%zd) do not match",
509 joint_names_.size(), num_joints_);
510 return false;
511 }
512
513 std::reverse(link_names_.begin(), link_names_.end());
514 std::reverse(joint_names_.begin(), joint_names_.end());
515 std::reverse(joint_min_vector_.begin(), joint_min_vector_.end());
516 std::reverse(joint_max_vector_.begin(), joint_max_vector_.end());
517 std::reverse(joint_has_limits_vector_.begin(), joint_has_limits_vector_.end());
518
519 for (size_t joint_id = 0; joint_id < num_joints_; ++joint_id)
520 RCLCPP_DEBUG_STREAM(getLogger(), joint_names_[joint_id] << ' ' << joint_min_vector_[joint_id] << ' '
521 << joint_max_vector_[joint_id] << ' '
522 << joint_has_limits_vector_[joint_id]);
523
524 initialized_ = true;
525 return true;
526}
527
528void IKFastKinematicsPlugin::setSearchDiscretization(const std::map<unsigned int, double>& discretization)
529{
530 if (discretization.empty())
531 {
532 RCLCPP_ERROR(getLogger(), "The 'discretization' map is empty");
533 return;
534 }
535
536 if (redundant_joint_indices_.empty())
537 {
538 RCLCPP_ERROR(getLogger(), "This group's solver doesn't support redundant joints");
539 return;
540 }
541
542 if (discretization.begin()->first != redundant_joint_indices_[0])
543 {
544 std::string redundant_joint = joint_names_[free_params_[0]];
545 RCLCPP_ERROR_STREAM(getLogger(), "Attempted to discretize a non-redundant joint "
546 << discretization.begin()->first << ", only joint '" << redundant_joint
547 << "' with index " << redundant_joint_indices_[0] << " is redundant.");
548 return;
549 }
550
551 if (discretization.begin()->second <= 0.0)
552 {
553 RCLCPP_ERROR_STREAM(getLogger(), "Discretization can not takes values that are <= 0");
554 return;
555 }
556
558 redundant_joint_discretization_[redundant_joint_indices_[0]] = discretization.begin()->second;
559}
560
561bool IKFastKinematicsPlugin::setRedundantJoints(const std::vector<unsigned int>& redundant_joint_indices)
562{
563 RCLCPP_ERROR(getLogger(), "Changing the redundant joints isn't permitted by this group's solver ");
564 return false;
565}
566
567size_t IKFastKinematicsPlugin::solve(KDL::Frame& pose_frame, const std::vector<double>& vfree,
568 IkSolutionList<IkReal>& solutions) const
569{
570 // IKFast56/61
571 solutions.Clear();
572
573 double trans[3];
574 trans[0] = pose_frame.p[0]; //-.18;
575 trans[1] = pose_frame.p[1];
576 trans[2] = pose_frame.p[2];
577
578 KDL::Rotation mult;
579 KDL::Vector direction;
580
581 switch (GetIkType())
582 {
583 case IKP_Transform6D:
585 // For **Transform6D**, eerot is 9 values for the 3x3 rotation matrix. For **Translation3D**, these are ignored.
586
587 mult = pose_frame.M;
588
589 double vals[9];
590 vals[0] = mult(0, 0);
591 vals[1] = mult(0, 1);
592 vals[2] = mult(0, 2);
593 vals[3] = mult(1, 0);
594 vals[4] = mult(1, 1);
595 vals[5] = mult(1, 2);
596 vals[6] = mult(2, 0);
597 vals[7] = mult(2, 1);
598 vals[8] = mult(2, 2);
599
600 // IKFast56/61
601 ComputeIk(trans, vals, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
602 return solutions.GetNumSolutions();
603
604 case IKP_Direction3D:
605 case IKP_Ray4D:
607 // For **Direction3D**, **Ray4D**, and **TranslationDirection5D**, the first 3 values represent the target
608 // direction.
609
610 direction = pose_frame.M * KDL::Vector(0, 0, 1);
611 ComputeIk(trans, direction.data, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
612 return solutions.GetNumSolutions();
613
615 // For **TranslationLocalGlobal6D**, the diagonal elements ([0],[4],[8]) are the local translation inside the end
616 // effector coordinate system.
617 RCLCPP_ERROR(getLogger(), "IK for this IkParameterizationType not implemented yet.");
618 return 0;
619
621 ComputeIk(trans, direction.data, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
622 return solutions.GetNumSolutions();
623
624 case IKP_Rotation3D:
625 case IKP_Lookat3D:
627 RCLCPP_ERROR(getLogger(), "IK for this IkParameterizationType not implemented yet.");
628 return 0;
629
631 // For *TranslationXAxisAngle4D*, *TranslationYAxisAngle4D*, *TranslationZAxisAngle4D* - end effector origin
632 // reaches desired 3D translation, manipulator direction makes a specific angle with x/y/z-axis (defined in the
633 // manipulator base link's coordinate system)
635 double roll, pitch, yaw;
636 // For **TranslationXAxisAngleZNorm4D** - end effector origin reaches desired 3D translation, manipulator
637 // direction needs to be orthogonal to z axis and be rotated at a certain angle starting from the x axis (defined
638 // in the manipulator base link’s coordinate system)
639 pose_frame.M.GetRPY(roll, pitch, yaw);
640 ComputeIk(trans, &yaw, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
641 return solutions.GetNumSolutions();
642
645 // For **TranslationYAxisAngleXNorm4D** - end effector origin reaches desired 3D translation, manipulator
646 // direction needs to be orthogonal to x axis and be rotated at a certain angle starting from the y axis (defined
647 // in the manipulator base link’s coordinate system)
648 pose_frame.M.GetRPY(roll, pitch, yaw);
649 ComputeIk(trans, &roll, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
650 return solutions.GetNumSolutions();
651
654 // For **TranslationZAxisAngleYNorm4D** - end effector origin reaches desired 3D translation, manipulator
655 // direction needs to be orthogonal to y axis and be rotated at a certain angle starting from the z axis (defined
656 // in the manipulator base link’s coordinate system)
657 pose_frame.M.GetRPY(roll, pitch, yaw);
658 ComputeIk(trans, &pitch, vfree.size() > 0 ? &vfree[0] : nullptr, solutions);
659 return solutions.GetNumSolutions();
660
661 default:
662 RCLCPP_ERROR(getLogger(), "Unknown IkParameterizationType! "
663 "Was the solver generated with an incompatible version of Openrave?");
664 return 0;
665 }
666}
667
668void IKFastKinematicsPlugin::getSolution(const IkSolutionList<IkReal>& solutions, int i,
669 std::vector<double>& solution) const
670{
671 solution.clear();
672 solution.resize(num_joints_);
673
674 // IKFast56/61
675 const IkSolutionBase<IkReal>& sol = solutions.GetSolution(i);
676 std::vector<IkReal> vsolfree(sol.GetFree().size());
677 sol.GetSolution(&solution[0], vsolfree.size() > 0 ? &vsolfree[0] : nullptr);
678
679 for (std::size_t joint_id = 0; joint_id < num_joints_; ++joint_id)
680 {
681 if (joint_has_limits_vector_[joint_id])
682 {
683 solution[joint_id] = enforceLimits(solution[joint_id], joint_min_vector_[joint_id], joint_max_vector_[joint_id]);
684 }
685 }
686}
687
688void IKFastKinematicsPlugin::getSolution(const IkSolutionList<IkReal>& solutions,
689 const std::vector<double>& ik_seed_state, int i,
690 std::vector<double>& solution) const
691{
692 solution.clear();
693 solution.resize(num_joints_);
694
695 // IKFast56/61
696 const IkSolutionBase<IkReal>& sol = solutions.GetSolution(i);
697 std::vector<IkReal> vsolfree(sol.GetFree().size());
698 sol.GetSolution(&solution[0], vsolfree.size() > 0 ? &vsolfree[0] : nullptr);
699
700 // rotate joints by +/-360° where it is possible and useful
701 for (std::size_t i = 0; i < num_joints_; ++i)
702 {
703 if (joint_has_limits_vector_[i])
704 {
705 solution[i] = enforceLimits(solution[i], joint_min_vector_[i], joint_max_vector_[i]);
706 double signed_distance = solution[i] - ik_seed_state[i];
707 while (signed_distance > M_PI && solution[i] - 2 * M_PI > (joint_min_vector_[i] - LIMIT_TOLERANCE))
708 {
709 signed_distance -= 2 * M_PI;
710 solution[i] -= 2 * M_PI;
711 }
712 while (signed_distance < -M_PI && solution[i] + 2 * M_PI < (joint_max_vector_[i] + LIMIT_TOLERANCE))
713 {
714 signed_distance += 2 * M_PI;
715 solution[i] += 2 * M_PI;
716 }
717 }
718 }
719}
720
721double IKFastKinematicsPlugin::enforceLimits(double joint_value, double min, double max) const
722{
723 // If the joint_value is greater than max subtract 2 * PI until it is less than the max
724 while (joint_value > max)
725 {
726 joint_value -= 2 * M_PI;
727 }
728
729 // If the joint_value is less than the min, add 2 * PI until it is more than the min
730 while (joint_value < min)
731 {
732 joint_value += 2 * M_PI;
733 }
734 return joint_value;
735}
736
737void IKFastKinematicsPlugin::fillFreeParams(int count, int* array)
738{
739 free_params_.clear();
740 for (int i = 0; i < count; ++i)
741 free_params_.push_back(array[i]);
742}
743
744bool IKFastKinematicsPlugin::getCount(int& count, int max_count, int min_count) const
745{
746 if (count > 0)
747 {
748 if (-count >= min_count)
749 {
750 count = -count;
751 return true;
752 }
753 else if (count + 1 <= max_count)
754 {
755 count = count + 1;
756 return true;
757 }
758 else
759 {
760 return false;
761 }
762 }
763 else
764 {
765 if (1 - count <= max_count)
766 {
767 count = 1 - count;
768 return true;
769 }
770 else if (count - 1 >= min_count)
771 {
772 count = count - 1;
773 return true;
774 }
775 else
776 return false;
777 }
778}
779
780bool IKFastKinematicsPlugin::getPositionFK(const std::vector<std::string>& link_names,
781 const std::vector<double>& joint_angles,
782 std::vector<geometry_msgs::msg::Pose>& poses) const
783{
784 if (GetIkType() != IKP_Transform6D)
785 {
786 // ComputeFk() is the inverse function of ComputeIk(), so the format of
787 // eerot differs depending on IK type. The Transform6D IK type is the only
788 // one for which a 3x3 rotation matrix is returned, which means we can only
789 // compute FK for that IK type.
790 RCLCPP_ERROR(getLogger(), "Can only compute FK for Transform6D IK type!");
791 return false;
792 }
793
794 KDL::Frame p_out;
795 if (link_names.size() == 0)
796 {
797 RCLCPP_WARN_STREAM(getLogger(), "Link names with nothing");
798 return false;
799 }
800
801 if (link_names.size() != 1 || link_names[0] != getTipFrame())
802 {
803 RCLCPP_ERROR(getLogger(), "Can compute FK for %s only", getTipFrame().c_str());
804 return false;
805 }
806
807 bool valid = true;
808
809 IkReal eerot[9], eetrans[3];
810
811 if (joint_angles.size() != num_joints_)
812 {
813 RCLCPP_ERROR(getLogger(), "Unexpected number of joint angles");
814 return false;
815 }
816
817#ifdef __clang__
818#pragma clang diagnostic push
819#pragma clang diagnostic ignored "-Wvla-cxx-extension"
820#endif
821 IkReal angles[num_joints_];
822#ifdef __clang__
823#pragma clang diagnostic pop
824#endif
825 for (unsigned char i = 0; i < num_joints_; ++i)
826 angles[i] = joint_angles[i];
827
828 // IKFast56/61
829 ComputeFk(angles, eetrans, eerot);
830
831 for (int i = 0; i < 3; ++i)
832 p_out.p.data[i] = eetrans[i];
833
834 for (int i = 0; i < 9; ++i)
835 p_out.M.data[i] = eerot[i];
836
837 poses.resize(1);
838 poses[0] = tf2::toMsg(p_out);
839
840 return valid;
841}
842
843bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
844 const std::vector<double>& ik_seed_state, double timeout,
845 std::vector<double>& solution,
846 moveit_msgs::msg::MoveItErrorCodes& error_code,
847 const kinematics::KinematicsQueryOptions& options) const
848{
849 std::vector<double> consistency_limits;
850 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, IKCallbackFn(), error_code,
851 options);
852}
853
854bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
855 const std::vector<double>& ik_seed_state, double timeout,
856 const std::vector<double>& consistency_limits,
857 std::vector<double>& solution,
858 moveit_msgs::msg::MoveItErrorCodes& error_code,
859 const kinematics::KinematicsQueryOptions& options) const
860{
861 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, IKCallbackFn(), error_code,
862 options);
863}
864
865bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
866 const std::vector<double>& ik_seed_state, double timeout,
867 std::vector<double>& solution, const IKCallbackFn& solution_callback,
868 moveit_msgs::msg::MoveItErrorCodes& error_code,
869 const kinematics::KinematicsQueryOptions& options) const
870{
871 std::vector<double> consistency_limits;
872 return searchPositionIK(ik_pose, ik_seed_state, timeout, consistency_limits, solution, solution_callback, error_code,
873 options);
874}
875
876bool IKFastKinematicsPlugin::searchPositionIK(const geometry_msgs::msg::Pose& ik_pose,
877 const std::vector<double>& ik_seed_state, double timeout,
878 const std::vector<double>& consistency_limits,
879 std::vector<double>& solution, const IKCallbackFn& solution_callback,
880 moveit_msgs::msg::MoveItErrorCodes& error_code,
881 const kinematics::KinematicsQueryOptions& options) const
882{
883 // "SEARCH_MODE" is fixed during code generation
884 SEARCH_MODE search_mode = _SEARCH_MODE_;
885
886 // Check if there are no redundant joints
887 if (free_params_.size() == 0)
888 {
889 RCLCPP_DEBUG_STREAM(getLogger(), "No need to search since no free params/redundant joints");
890
891 std::vector<geometry_msgs::msg::Pose> ik_poses(1, ik_pose);
892 std::vector<std::vector<double>> solutions;
893 kinematics::KinematicsResult kinematic_result;
894 // Find all IK solutions within joint limits
895 if (!getPositionIK(ik_poses, ik_seed_state, solutions, kinematic_result, options))
896 {
897 RCLCPP_DEBUG(getLogger(), "No solution whatsoever");
898 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
899 return false;
900 }
901
902 // sort solutions by their distance to the seed
903 std::vector<LimitObeyingSol> solutions_obey_limits;
904 for (std::size_t i = 0; i < solutions.size(); ++i)
905 {
906 double dist_from_seed = 0.0;
907 for (std::size_t j = 0; j < ik_seed_state.size(); ++j)
908 {
909 dist_from_seed += fabs(ik_seed_state[j] - solutions[i][j]);
910 }
911
912 solutions_obey_limits.push_back({ solutions[i], dist_from_seed });
913 }
914 std::sort(solutions_obey_limits.begin(), solutions_obey_limits.end());
915
916 // check for collisions if a callback is provided
917 if (solution_callback)
918 {
919 for (std::size_t i = 0; i < solutions_obey_limits.size(); ++i)
920 {
921 solution_callback(ik_pose, solutions_obey_limits[i].value, error_code);
922 if (error_code.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
923 {
924 solution = solutions_obey_limits[i].value;
925 RCLCPP_DEBUG(getLogger(), "Solution passes callback");
926 return true;
927 }
928 }
929
930 RCLCPP_DEBUG_STREAM(getLogger(), "Solution has error code " << error_code.val);
931 return false;
932 }
933 else
934 {
935 solution = solutions_obey_limits[0].value;
936 error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
937 return true; // no collision check callback provided
938 }
939 }
940
941 // -------------------------------------------------------------------------------------------------
942 // Error Checking
943 if (!initialized_)
944 {
945 RCLCPP_ERROR(getLogger(), "Kinematics not active");
946 error_code.val = error_code.NO_IK_SOLUTION;
947 return false;
948 }
949
950 if (ik_seed_state.size() != num_joints_)
951 {
952 RCLCPP_ERROR_STREAM(getLogger(),
953 "Seed state must have size " << num_joints_ << " instead of size " << ik_seed_state.size());
954 error_code.val = error_code.NO_IK_SOLUTION;
955 return false;
956 }
957
958 if (!consistency_limits.empty() && consistency_limits.size() != num_joints_)
959 {
960 RCLCPP_ERROR_STREAM(getLogger(), "Consistency limits be empty or must have size "
961 << num_joints_ << " instead of size " << consistency_limits.size());
962 error_code.val = error_code.NO_IK_SOLUTION;
963 return false;
964 }
965
966 // -------------------------------------------------------------------------------------------------
967 // Initialize
968
969 KDL::Frame frame;
970 transformToChainFrame(ik_pose, frame);
971
972 std::vector<double> vfree(free_params_.size());
973
974 int counter = 0;
975
976 double initial_guess = ik_seed_state[free_params_[0]];
977 vfree[0] = initial_guess;
978
979 // -------------------------------------------------------------------------------------------------
980 // Handle consistency limits if needed
981 int num_positive_increments;
982 int num_negative_increments;
983 double search_discretization = redundant_joint_discretization_.at(free_params_[0]);
984
985 if (!consistency_limits.empty())
986 {
987 // MoveIt replaced consistency_limit (scalar) w/ consistency_limits (vector)
988 // Assume [0]th free_params element for now. Probably wrong.
989 double max_limit = fmin(joint_max_vector_[free_params_[0]], initial_guess + consistency_limits[free_params_[0]]);
990 double min_limit = fmax(joint_min_vector_[free_params_[0]], initial_guess - consistency_limits[free_params_[0]]);
991
992 num_positive_increments = static_cast<int>((max_limit - initial_guess) / search_discretization);
993 num_negative_increments = static_cast<int>((initial_guess - min_limit) / search_discretization);
994 }
995 else // no consistency limits provided
996 {
997 num_positive_increments = (joint_max_vector_[free_params_[0]] - initial_guess) / search_discretization;
998 num_negative_increments = (initial_guess - joint_min_vector_[free_params_[0]]) / search_discretization;
999 }
1000
1001 // -------------------------------------------------------------------------------------------------
1002 // Begin searching
1003
1004 RCLCPP_DEBUG_STREAM(getLogger(), "Free param is " << free_params_[0] << " initial guess is " << initial_guess
1005 << ", # positive increments: " << num_positive_increments
1006 << ", # negative increments: " << num_negative_increments);
1007 if ((search_mode & OPTIMIZE_MAX_JOINT) && (num_positive_increments + num_negative_increments) > 1000)
1008 RCLCPP_WARN_STREAM_ONCE(getLogger(), "Large search space, consider increasing the search discretization");
1009
1010 double best_costs = -1.0;
1011 std::vector<double> best_solution;
1012 int nattempts = 0, nvalid = 0;
1013
1014 while (true)
1015 {
1016 IkSolutionList<IkReal> solutions;
1017 size_t numsol = solve(frame, vfree, solutions);
1018
1019 RCLCPP_DEBUG_STREAM(getLogger(), "Found " << numsol << " solutions from IKFast");
1020
1021 if (numsol > 0)
1022 {
1023 for (size_t s = 0; s < numsol; ++s)
1024 {
1025 nattempts++;
1026 std::vector<double> sol;
1027 getSolution(solutions, ik_seed_state, s, sol);
1028
1029 bool obeys_limits = true;
1030 for (size_t i = 0; i < sol.size(); ++i)
1031 {
1032 if (joint_has_limits_vector_[i] && (sol[i] < joint_min_vector_[i] || sol[i] > joint_max_vector_[i]))
1033 {
1034 obeys_limits = false;
1035 break;
1036 }
1037 // RCLCPP_INFO_STREAM(getLogger(),"Num " << i << " value " << sol[i] << " has limits " <<
1038 // joint_has_limits_vector_[i] << " " << joint_min_vector_[i] << " " << joint_max_vector_[i]);
1039 }
1040 if (obeys_limits)
1041 {
1042 getSolution(solutions, ik_seed_state, s, solution);
1043
1044 // This solution is within joint limits, now check if in collision (if callback provided)
1045 if (solution_callback)
1046 {
1047 solution_callback(ik_pose, solution, error_code);
1048 }
1049 else
1050 {
1051 error_code.val = error_code.SUCCESS;
1052 }
1053
1054 if (error_code.val == error_code.SUCCESS)
1055 {
1056 nvalid++;
1057 if (search_mode & OPTIMIZE_MAX_JOINT)
1058 {
1059 // Costs for solution: Largest joint motion
1060 double costs = 0.0;
1061 for (unsigned int i = 0; i < solution.size(); ++i)
1062 {
1063 double d = fabs(ik_seed_state[i] - solution[i]);
1064 if (d > costs)
1065 costs = d;
1066 }
1067 if (costs < best_costs || best_costs == -1.0)
1068 {
1069 best_costs = costs;
1070 best_solution = solution;
1071 }
1072 }
1073 else
1074 // Return first feasible solution
1075 return true;
1076 }
1077 }
1078 }
1079 }
1080
1081 if (!getCount(counter, num_positive_increments, -num_negative_increments))
1082 {
1083 // Everything searched
1084 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
1085 break;
1086 }
1087
1088 vfree[0] = initial_guess + search_discretization * counter;
1089 // RCLCPP_DEBUG_STREAM(getLogger(),"Attempt " << counter << " with 0th free joint having value " << vfree[0]);
1090 }
1091
1092 RCLCPP_DEBUG_STREAM(getLogger(), "Valid solutions: " << nvalid << '/' << nattempts);
1093
1094 if ((search_mode & OPTIMIZE_MAX_JOINT) && best_costs != -1.0)
1095 {
1096 solution = best_solution;
1097 error_code.val = error_code.SUCCESS;
1098 return true;
1099 }
1100
1101 // No solution found
1102 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
1103 return false;
1104}
1105
1106// Used when there are no redundant joints - aka no free params
1107bool IKFastKinematicsPlugin::getPositionIK(const geometry_msgs::msg::Pose& ik_pose,
1108 const std::vector<double>& ik_seed_state, std::vector<double>& solution,
1109 moveit_msgs::msg::MoveItErrorCodes& error_code,
1110 const kinematics::KinematicsQueryOptions& options) const
1111{
1112 RCLCPP_DEBUG_STREAM(getLogger(), "getPositionIK");
1113
1114 if (!initialized_)
1115 {
1116 RCLCPP_ERROR(getLogger(), "kinematics not active");
1117 return false;
1118 }
1119
1120 if (ik_seed_state.size() < num_joints_)
1121 {
1122 RCLCPP_ERROR_STREAM(getLogger(), "ik_seed_state only has " << ik_seed_state.size()
1123 << " entries, this ikfast solver requires "
1124 << num_joints_);
1125 return false;
1126 }
1127
1128 // Check if seed is in bound
1129 for (std::size_t i = 0; i < ik_seed_state.size(); ++i)
1130 {
1131 // Add tolerance to limit check
1132 if (joint_has_limits_vector_[i] && ((ik_seed_state[i] < (joint_min_vector_[i] - LIMIT_TOLERANCE)) ||
1133 (ik_seed_state[i] > (joint_max_vector_[i] + LIMIT_TOLERANCE))))
1134 {
1135 RCLCPP_DEBUG_STREAM(getLogger(), "IK seed not in limits! " << static_cast<int>(i) << " value " << ik_seed_state[i]
1136 << " has limit: " << joint_has_limits_vector_[i]
1137 << " being " << joint_min_vector_[i] << " to "
1138 << joint_max_vector_[i]);
1139 return false;
1140 }
1141 }
1142
1143 std::vector<double> vfree(free_params_.size());
1144 for (std::size_t i = 0; i < free_params_.size(); ++i)
1145 {
1146 int p = free_params_[i];
1147 RCLCPP_ERROR(getLogger(), "%u is %f", p, ik_seed_state[p]); // DTC
1148 vfree[i] = ik_seed_state[p];
1149 }
1150
1151 KDL::Frame frame;
1152 transformToChainFrame(ik_pose, frame);
1153
1154 IkSolutionList<IkReal> solutions;
1155 size_t numsol = solve(frame, vfree, solutions);
1156 RCLCPP_DEBUG_STREAM(getLogger(), "Found " << numsol << " solutions from IKFast");
1157
1158 std::vector<LimitObeyingSol> solutions_obey_limits;
1159
1160 if (numsol)
1161 {
1162 std::vector<double> solution_obey_limits;
1163 for (std::size_t s = 0; s < numsol; ++s)
1164 {
1165 std::vector<double> sol;
1166 getSolution(solutions, ik_seed_state, s, sol);
1167 RCLCPP_DEBUG(getLogger(), "Sol %d: %e %e %e %e %e %e", static_cast<int>(s), sol[0], sol[1], sol[2],
1168 sol[3], sol[4], sol[5]);
1169
1170 bool obeys_limits = true;
1171 for (std::size_t i = 0; i < sol.size(); ++i)
1172 {
1173 // Add tolerance to limit check
1174 if (joint_has_limits_vector_[i] && ((sol[i] < (joint_min_vector_[i] - LIMIT_TOLERANCE)) ||
1175 (sol[i] > (joint_max_vector_[i] + LIMIT_TOLERANCE))))
1176 {
1177 // One element of solution is not within limits
1178 obeys_limits = false;
1179 RCLCPP_DEBUG_STREAM(getLogger(), "Not in limits! " << static_cast<int>(i) << " value " << sol[i]
1180 << " has limit: " << joint_has_limits_vector_[i]
1181 << " being " << joint_min_vector_[i] << " to "
1182 << joint_max_vector_[i]);
1183 break;
1184 }
1185 }
1186 if (obeys_limits)
1187 {
1188 // All elements of this solution obey limits
1189 getSolution(solutions, ik_seed_state, s, solution_obey_limits);
1190 double dist_from_seed = 0.0;
1191 for (std::size_t i = 0; i < ik_seed_state.size(); ++i)
1192 {
1193 dist_from_seed += fabs(ik_seed_state[i] - solution_obey_limits[i]);
1194 }
1195
1196 solutions_obey_limits.push_back({ solution_obey_limits, dist_from_seed });
1197 }
1198 }
1199 }
1200 else
1201 {
1202 RCLCPP_DEBUG(getLogger(), "No IK solution");
1203 }
1204
1205 // Sort the solutions under limits and find the one that is closest to ik_seed_state
1206 if (!solutions_obey_limits.empty())
1207 {
1208 std::sort(solutions_obey_limits.begin(), solutions_obey_limits.end());
1209 solution = solutions_obey_limits[0].value;
1210 error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
1211 return true;
1212 }
1213
1214 error_code.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
1215 return false;
1216}
1217
1218bool IKFastKinematicsPlugin::getPositionIK(const std::vector<geometry_msgs::msg::Pose>& ik_poses,
1219 const std::vector<double>& ik_seed_state,
1220 std::vector<std::vector<double>>& solutions,
1222 const kinematics::KinematicsQueryOptions& options) const
1223{
1224 RCLCPP_DEBUG_STREAM(getLogger(), "getPositionIK with multiple solutions");
1225
1226 if (!initialized_)
1227 {
1228 RCLCPP_ERROR(getLogger(), "kinematics not active");
1230 return false;
1231 }
1232
1233 if (ik_poses.empty())
1234 {
1235 RCLCPP_ERROR(getLogger(), "ik_poses is empty");
1237 return false;
1238 }
1239
1240 if (ik_poses.size() > 1)
1241 {
1242 RCLCPP_ERROR(getLogger(), "ik_poses contains multiple entries, only one is allowed");
1244 return false;
1245 }
1246
1247 if (ik_seed_state.size() < num_joints_)
1248 {
1249 RCLCPP_ERROR_STREAM(getLogger(), "ik_seed_state only has " << ik_seed_state.size()
1250 << " entries, this ikfast solver requires "
1251 << num_joints_);
1252 return false;
1253 }
1254
1255 KDL::Frame frame;
1256 transformToChainFrame(ik_poses[0], frame);
1257
1258 // solving ik
1259 std::vector<IkSolutionList<IkReal>> solution_set;
1260 IkSolutionList<IkReal> ik_solutions;
1261 std::vector<double> vfree;
1262 int numsol = 0;
1263 std::vector<double> sampled_joint_vals;
1264 if (!redundant_joint_indices_.empty())
1265 {
1266 // initializing from seed
1267 sampled_joint_vals.push_back(ik_seed_state[redundant_joint_indices_[0]]);
1268
1269 // checking joint limits when using no discretization
1270 if (options.discretization_method == kinematics::DiscretizationMethods::NO_DISCRETIZATION &&
1271 joint_has_limits_vector_[redundant_joint_indices_.front()])
1272 {
1273 double joint_min = joint_min_vector_[redundant_joint_indices_.front()];
1274 double joint_max = joint_max_vector_[redundant_joint_indices_.front()];
1275
1276 double jv = sampled_joint_vals[0];
1277 if (!((jv > (joint_min - LIMIT_TOLERANCE)) && (jv < (joint_max + LIMIT_TOLERANCE))))
1278 {
1280 RCLCPP_ERROR_STREAM(getLogger(), "ik seed is out of bounds");
1281 return false;
1282 }
1283 }
1284
1285 // computing all solutions sets for each sampled value of the redundant joint
1286 if (!sampleRedundantJoint(options.discretization_method, sampled_joint_vals))
1287 {
1289 return false;
1290 }
1291
1292 for (unsigned int i = 0; i < sampled_joint_vals.size(); ++i)
1293 {
1294 vfree.clear();
1295 vfree.push_back(sampled_joint_vals[i]);
1296 numsol += solve(frame, vfree, ik_solutions);
1297 solution_set.push_back(ik_solutions);
1298 }
1299 }
1300 else
1301 {
1302 // computing for single solution set
1303 numsol = solve(frame, vfree, ik_solutions);
1304 solution_set.push_back(ik_solutions);
1305 }
1306
1307 RCLCPP_DEBUG_STREAM(getLogger(), "Found " << numsol << " solutions from IKFast");
1308 bool solutions_found = false;
1309 if (numsol > 0)
1310 {
1311 /*
1312 Iterating through all solution sets and storing those that do not exceed joint limits.
1313 */
1314 for (unsigned int r = 0; r < solution_set.size(); ++r)
1315 {
1316 ik_solutions = solution_set[r];
1317 numsol = ik_solutions.GetNumSolutions();
1318 for (int s = 0; s < numsol; ++s)
1319 {
1320 std::vector<double> sol;
1321 getSolution(ik_solutions, ik_seed_state, s, sol);
1322
1323 bool obeys_limits = true;
1324 for (unsigned int i = 0; i < sol.size(); ++i)
1325 {
1326 // Add tolerance to limit check
1327 if (joint_has_limits_vector_[i] && ((sol[i] < (joint_min_vector_[i] - LIMIT_TOLERANCE)) ||
1328 (sol[i] > (joint_max_vector_[i] + LIMIT_TOLERANCE))))
1329 {
1330 // One element of solution is not within limits
1331 obeys_limits = false;
1332 RCLCPP_DEBUG_STREAM(getLogger(), "Not in limits! " << i << " value " << sol[i]
1333 << " has limit: " << joint_has_limits_vector_[i]
1334 << " being " << joint_min_vector_[i] << " to "
1335 << joint_max_vector_[i]);
1336 break;
1337 }
1338 }
1339 if (obeys_limits)
1340 {
1341 // All elements of solution obey limits
1342 solutions_found = true;
1343 solutions.push_back(sol);
1344 }
1345 }
1346 }
1347
1348 if (solutions_found)
1349 {
1351 return true;
1352 }
1353 }
1354 else
1355 {
1356 RCLCPP_DEBUG_STREAM(getLogger(), "No IK solution");
1357 }
1358
1360 return false;
1361}
1362
1363bool IKFastKinematicsPlugin::sampleRedundantJoint(kinematics::DiscretizationMethod method,
1364 std::vector<double>& sampled_joint_vals) const
1365{
1366 int index = redundant_joint_indices_.front();
1367 double joint_dscrt = redundant_joint_discretization_.at(index);
1368 double joint_min = joint_min_vector_[index];
1369 double joint_max = joint_max_vector_[index];
1370
1371 switch (method)
1372 {
1374 {
1375 size_t steps = std::ceil((joint_max - joint_min) / joint_dscrt);
1376 for (size_t i = 0; i < steps; ++i)
1377 {
1378 sampled_joint_vals.push_back(joint_min + joint_dscrt * i);
1379 }
1380 sampled_joint_vals.push_back(joint_max);
1381 }
1382 break;
1384 {
1385 int steps = std::ceil((joint_max - joint_min) / joint_dscrt);
1386 steps = steps > 0 ? steps : 1;
1387 double diff = joint_max - joint_min;
1388 for (int i = 0; i < steps; ++i)
1389 {
1390 sampled_joint_vals.push_back(((diff * std::rand()) / (static_cast<double>(RAND_MAX))) + joint_min);
1391 }
1392 }
1393
1394 break;
1396
1397 break;
1398 default:
1399 RCLCPP_ERROR_STREAM(getLogger(), "Discretization method " << method << " is not supported");
1400 return false;
1401 }
1402
1403 return true;
1404}
1405
1406void IKFastKinematicsPlugin::transformToChainFrame(const geometry_msgs::msg::Pose& ik_pose,
1407 KDL::Frame& ik_pose_chain) const
1408{
1409 if (tip_transform_required_ || base_transform_required_)
1410 {
1411 Eigen::Isometry3d ik_eigen_pose;
1412 tf2::fromMsg(ik_pose, ik_eigen_pose);
1413 if (tip_transform_required_)
1414 ik_eigen_pose = ik_eigen_pose * group_tip_to_chain_tip_;
1415
1416 if (base_transform_required_)
1417 ik_eigen_pose = chain_base_to_group_base_ * ik_eigen_pose;
1418
1419 tf2::fromMsg(tf2::toMsg(ik_eigen_pose), ik_pose_chain);
1420 }
1421 else
1422 {
1423 tf2::fromMsg(ik_pose, ik_pose_chain);
1424 }
1425}
1426
1427} // namespace _NAMESPACE_
1428
1429// register IKFastKinematicsPlugin as a KinematicsBase implementation
1430#include <pluginlib/class_list_macros.hpp>
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.
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.
void setSearchDiscretization(const std::map< unsigned int, double > &discretization)
Sets the discretization value for the redundant joint.
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.
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.
PLUGINLIB_EXPORT_CLASS(_NAMESPACE_::IKFastKinematicsPlugin, kinematics::KinematicsBase)
const double LIMIT_TOLERANCE
SEARCH_MODE
Search modes for searchPositionIK(), see there.
IkParameterizationType
The types of inverse kinematics parameterizations supported.
@ IKP_Ray4D
ray on end effector coordinate system reaches desired global ray
@ IKP_Direction3D
direction on end effector coordinate system reaches desired direction
@ IKP_VelocityDataBit
bit is set if the data represents the time-derivate velocity of an IkParameterization
@ IKP_Translation3D
end effector origin reaches desired 3D translation
@ IKP_UniqueIdMask
the mask for the unique ids
@ IKP_Transform6D
end effector reaches desired 6D transformation
@ IKP_NumberOfParameterizations
number of parameterizations (does not count IKP_None)
@ IKP_TranslationLocalGlobal6D
local point on end effector origin reaches desired 3D global point
@ IKP_TranslationXY2D
2D translation along XY plane
@ IKP_Rotation3D
end effector reaches desired 3D rotation
@ IKP_Lookat3D
direction on end effector coordinate system points to desired 3D position
DiscretizationMethods::DiscretizationMethod DiscretizationMethod
Core components of MoveIt.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:106
IKFAST_API int * GetFreeParameters()
IKFAST_API int GetNumJoints()
IKFAST_API int GetIkType()
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)
IKFAST_API int GetNumFreeParameters()
bool operator<(const LimitObeyingSol &a) const
A set of options for the kinematics solver.