41#include <geometric_shapes/check_isometry.h>
42#include <rclcpp/logger.hpp>
43#include <rclcpp/logging.hpp>
44#include <rcpputils/asserts.hpp>
53static const std::size_t MIN_STEPS_FOR_JUMP_THRESH = 10;
63bool validateAndImproveInterval(
const RobotState& start_state,
const RobotState& end_state,
64 const Eigen::Isometry3d& start_pose,
const Eigen::Isometry3d& end_pose,
65 std::vector<RobotStatePtr>& traj,
double& percentage,
const double width,
66 const JointModelGroup* group,
const LinkModel* link,
70 const Eigen::Isometry3d& link_offset)
73 RobotState mid_state(start_state.getRobotModel());
74 start_state.interpolate(end_state, 0.5, mid_state);
75 Eigen::Isometry3d fk_pose = mid_state.getGlobalLinkTransform(link) * link_offset;
78 Eigen::Isometry3d mid_pose(Eigen::Quaterniond(start_pose.linear()).slerp(0.5, Eigen::Quaterniond(end_pose.linear())));
79 mid_pose.translation() = 0.5 * (start_pose.translation() + end_pose.translation());
82 double linear_distance = (mid_pose.translation() - fk_pose.translation()).norm();
83 double angular_distance = Eigen::Quaterniond(mid_pose.linear()).angularDistance(Eigen::Quaterniond(fk_pose.linear()));
84 if (linear_distance <= precision.translational && angular_distance <= precision.rotational)
86 traj.push_back(std::make_shared<moveit::core::RobotState>(end_state));
90 if (width < precision.max_resolution)
94 if (!mid_state.setFromIK(group, mid_pose * link_offset.inverse(), link->getName(), 0.0, validCallback, options,
99 const auto half_width = width / 2.0;
100 const auto old_percentage = percentage;
101 percentage = percentage - half_width;
102 if (!validateAndImproveInterval(start_state, mid_state, start_pose, mid_pose, traj, percentage, half_width, group,
103 link, precision, validCallback, options, cost_function, link_offset))
106 percentage = old_percentage;
107 return validateAndImproveInterval(mid_state, end_state, mid_pose, end_pose, traj, percentage, half_width, group, link,
108 precision, validCallback, options, cost_function, link_offset);
111std::optional<int> hasRelativeJointSpaceJump(
const std::vector<moveit::core::RobotStatePtr>& waypoints,
114 if (waypoints.size() < MIN_STEPS_FOR_JUMP_THRESH)
117 "The computed path is too short to detect jumps in joint-space. "
118 "Need at least %zu steps, only got %zu. Try a lower max_step.",
119 MIN_STEPS_FOR_JUMP_THRESH, waypoints.size());
122 std::vector<double> dist_vector;
123 dist_vector.reserve(waypoints.size() - 1);
124 double total_dist = 0.0;
125 for (std::size_t i = 1; i < waypoints.size(); ++i)
127 const double dist_prev_point = waypoints[i]->distance(*waypoints[i - 1], &group);
128 dist_vector.push_back(dist_prev_point);
129 total_dist += dist_prev_point;
133 double thres = jump_threshold_factor * (total_dist /
static_cast<double>(dist_vector.size()));
134 for (std::size_t i = 0; i < dist_vector.size(); ++i)
136 if (dist_vector[i] > thres)
145std::optional<int> hasAbsoluteJointSpaceJump(
const std::vector<moveit::core::RobotStatePtr>& waypoints,
147 double prismatic_threshold)
149 const bool check_revolute = revolute_threshold > 0.0;
150 const bool check_prismatic = prismatic_threshold > 0.0;
153 for (std::size_t i = 1; i < waypoints.size(); ++i)
155 for (
const auto& joint : joints)
157 const double distance = waypoints[i]->distance(*waypoints[i - 1], joint);
158 switch (joint->getType())
161 if (check_revolute && distance > revolute_threshold)
167 if (check_prismatic && distance > prismatic_threshold)
174 "Joint %s has not supported type %s. \n"
175 "hasAbsoluteJointSpaceJump only supports prismatic and revolute joints. Skipping joint jump "
176 "check for this joint.",
177 joint->getName().c_str(), joint->getTypeName().c_str());
188 const RobotState* start_state,
const JointModelGroup* group, std::vector<RobotStatePtr>& traj,
189 const LinkModel* link,
const Eigen::Vector3d& translation,
bool global_reference_frame,
const MaxEEFStep& max_step,
193 const double distance = translation.norm();
195 Eigen::Isometry3d pose = start_state->getGlobalLinkTransform(link);
198 pose.translation() += global_reference_frame ? translation : pose.linear() * translation;
201 return CartesianInterpolator::Distance(distance) *
computeCartesianPath(start_state, group, traj, link, pose,
true,
202 max_step, precision, validCallback, options,
208 const LinkModel* link,
const Eigen::Isometry3d& target,
bool global_reference_frame,
const MaxEEFStep& max_step,
211 const Eigen::Isometry3d& link_offset)
214 ASSERT_ISOMETRY(target)
215 ASSERT_ISOMETRY(link_offset)
226 Eigen::Isometry3d inv_offset = link_offset.inverse();
229 Eigen::Isometry3d rotated_target = global_reference_frame ? target : start_pose * target;
231 Eigen::Quaterniond start_quaternion(start_pose.linear());
232 Eigen::Quaterniond target_quaternion(rotated_target.linear());
234 double rotation_distance = start_quaternion.angularDistance(target_quaternion);
235 double translation_distance = (rotated_target.translation() - start_pose.translation()).norm();
238 std::size_t translation_steps = 0;
240 translation_steps = floor(translation_distance / max_step.
translation);
242 std::size_t rotation_steps = 0;
244 rotation_steps = floor(rotation_distance / max_step.
rotation);
245 std::size_t steps = std::max(translation_steps, rotation_steps) + 1;
248 traj.push_back(std::make_shared<moveit::core::RobotState>(*start_state));
250 double last_valid_percentage = 0.0;
251 Eigen::Isometry3d prev_pose = start_pose;
253 for (std::size_t i = 1; i <= steps; ++i)
255 double percentage =
static_cast<double>(i) /
static_cast<double>(steps);
257 Eigen::Isometry3d pose(start_quaternion.slerp(percentage, target_quaternion));
258 pose.translation() = percentage * rotated_target.translation() + (1 - percentage) * start_pose.translation();
260 if (!state.
setFromIK(group, pose * inv_offset, link->
getName(), 0.0, validCallback, options, cost_function) ||
261 !validateAndImproveInterval(prev_state, state, prev_pose, pose, traj, percentage,
262 1.0 /
static_cast<double>(steps), group, link, precision, validCallback, options,
263 cost_function, link_offset))
268 last_valid_percentage = percentage;
271 return last_valid_percentage;
276 const LinkModel* link,
const EigenSTL::vector_Isometry3d& waypoints,
bool global_reference_frame,
279 const Eigen::Isometry3d& link_offset)
281 double percentage_solved = 0.0;
282 for (std::size_t i = 0; i < waypoints.size(); ++i)
284 std::vector<RobotStatePtr> waypoint_traj;
285 double wp_percentage_solved =
286 computeCartesianPath(start_state, group, waypoint_traj, link, waypoints[i], global_reference_frame, max_step,
287 precision, validCallback, options, cost_function, link_offset);
289 std::vector<RobotStatePtr>::iterator start = waypoint_traj.begin();
290 if (i > 0 && !waypoint_traj.empty())
291 std::advance(start, 1);
292 traj.insert(traj.end(), start, waypoint_traj.end());
294 if (fabs(wp_percentage_solved - 1.0) < std::numeric_limits<double>::epsilon())
296 percentage_solved =
static_cast<double>(i + 1) /
static_cast<double>(waypoints.size());
300 percentage_solved += wp_percentage_solved /
static_cast<double>(waypoints.size());
303 start_state = traj.back().get();
306 return percentage_solved;
325 rcpputils::require_true(
revolute > 0.0);
326 rcpputils::require_true(
prismatic > 0.0);
346 const Eigen::Vector3d& translation,
bool global_reference_frame,
const MaxEEFStep& max_step,
350 const double distance = translation.norm();
355 pose.translation() += global_reference_frame ? translation : pose.linear() * translation;
357#pragma GCC diagnostic push
358#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
361 max_step, jump_threshold, validCallback,
362 options, cost_function);
363#pragma GCC diagnostic pop
368 const Eigen::Isometry3d& target,
bool global_reference_frame,
const MaxEEFStep& max_step,
371 const Eigen::Isometry3d& link_offset)
374 ASSERT_ISOMETRY(target)
375 ASSERT_ISOMETRY(link_offset)
380 start_state->enforceBounds(joint);
384 Eigen::Isometry3d offset = link_offset.inverse();
387 Eigen::Isometry3d rotated_target = global_reference_frame ? target : start_pose * target;
389 Eigen::Quaterniond start_quaternion(start_pose.linear());
390 Eigen::Quaterniond target_quaternion(rotated_target.linear());
394 RCLCPP_ERROR(getLogger(),
395 "Invalid MaxEEFStep passed into computeCartesianPath. Both the MaxEEFStep.rotation and "
396 "MaxEEFStep.translation components must be non-negative and at least one component must be "
397 "greater than zero");
401 double rotation_distance = start_quaternion.angularDistance(target_quaternion);
402 double translation_distance = (rotated_target.translation() - start_pose.translation()).norm();
405 std::size_t translation_steps = 0;
407 translation_steps = floor(translation_distance / max_step.
translation);
409 std::size_t rotation_steps = 0;
411 rotation_steps = floor(rotation_distance / max_step.
rotation);
414 std::size_t steps = std::max(translation_steps, rotation_steps) + 1;
415 if (jump_threshold.
relative_factor > 0 && steps < MIN_STEPS_FOR_JUMP_THRESH)
416 steps = MIN_STEPS_FOR_JUMP_THRESH;
419 std::vector<double> consistency_limits;
422 for (
const JointModel* jm : group->getActiveJointModels())
425 switch (jm->getType())
437 limit = jm->getMaximumExtent();
438 consistency_limits.push_back(limit);
443 path.push_back(std::make_shared<moveit::core::RobotState>(*start_state));
445 double last_valid_percentage = 0.0;
446 for (std::size_t i = 1; i <= steps; ++i)
448 double percentage =
static_cast<double>(i) /
static_cast<double>(steps);
450 Eigen::Isometry3d pose(start_quaternion.slerp(percentage, target_quaternion));
451 pose.translation() = percentage * rotated_target.translation() + (1 - percentage) * start_pose.translation();
455 if (start_state->
setFromIK(group, pose * offset, link->
getName(), consistency_limits, 0.0, validCallback, options,
458 path.push_back(std::make_shared<moveit::core::RobotState>(*start_state));
465 last_valid_percentage = percentage;
470 return CartesianInterpolator::Percentage(last_valid_percentage);
474 RobotState* start_state,
const JointModelGroup* group, std::vector<RobotStatePtr>& path,
const LinkModel* link,
475 const EigenSTL::vector_Isometry3d& waypoints,
bool global_reference_frame,
const MaxEEFStep& max_step,
478 const Eigen::Isometry3d& link_offset)
480 double percentage_solved = 0.0;
481 for (std::size_t i = 0; i < waypoints.size(); ++i)
485 std::vector<RobotStatePtr> waypoint_path;
486#pragma GCC diagnostic push
487#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
488 double wp_percentage_solved =
489 computeCartesianPath(start_state, group, waypoint_path, link, waypoints[i], global_reference_frame, max_step,
490 NO_JOINT_SPACE_JUMP_TEST, validCallback, options, cost_function, link_offset);
491#pragma GCC diagnostic pop
493 std::vector<RobotStatePtr>::iterator start = waypoint_path.begin();
494 if (i > 0 && !waypoint_path.empty())
495 std::advance(start, 1);
496 path.insert(path.end(), start, waypoint_path.end());
498 if (fabs(wp_percentage_solved - 1.0) < std::numeric_limits<double>::epsilon())
500 percentage_solved =
static_cast<double>((i + 1)) /
static_cast<double>(waypoints.size());
504 percentage_solved += wp_percentage_solved /
static_cast<double>(waypoints.size());
511 return CartesianInterpolator::Percentage(percentage_solved);
515 std::vector<RobotStatePtr>& path,
520 double percentage_solved = 1.0;
521 if (jump_index.has_value())
523 percentage_solved =
static_cast<double>(*jump_index) /
static_cast<double>(path.size());
525 path.resize(jump_index.value());
535 if (waypoints.size() <= 1)
542 return hasRelativeJointSpaceJump(waypoints, group, jump_threshold.
relative_factor);
547 return hasAbsoluteJointSpaceJump(waypoints, group, jump_threshold.
revolute, jump_threshold.
prismatic);
std::function< double(const geometry_msgs::msg::Pose &, const moveit::core::RobotState &, const moveit::core::JointModelGroup *, const std::vector< double > &)> IKCostFn
Signature for a cost function used to evaluate IK solutions.
static Percentage checkJointSpaceJump(const JointModelGroup *group, std::vector< std::shared_ptr< RobotState > > &path, const JumpThreshold &jump_threshold)
Checks if a path has a joint-space jump, and truncates the path at the jump.
static Distance computeCartesianPath(const RobotState *start_state, const JointModelGroup *group, std::vector< std::shared_ptr< RobotState > > &traj, const LinkModel *link, const Eigen::Vector3d &translation, bool global_reference_frame, const MaxEEFStep &max_step, const CartesianPrecision &precision, const GroupStateValidityCallbackFn &validCallback=GroupStateValidityCallbackFn(), const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions(), const kinematics::KinematicsBase::IKCostFn &cost_function=kinematics::KinematicsBase::IKCostFn())
Compute the sequence of joint values that correspond to a straight Cartesian path for a particular li...
const std::vector< const JointModel * > & getActiveJointModels() const
Get the active joints in this group (that have controllable DOF). This does not include mimic joints.
const std::vector< const JointModel * > & getContinuousJointModels() const
Get the array of continuous joints used in this group (may include mimic joints).
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
A link from the robot. Contains the constant transform applied to the link and its geometry.
const std::string & getName() const
The name of this link.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
const Eigen::Isometry3d & getGlobalLinkTransform(const std::string &link_name)
Get the link transform w.r.t. the root link (model frame) of the RobotModel. This is typically the ro...
bool setFromIK(const JointModelGroup *group, const geometry_msgs::msg::Pose &pose, double timeout=0.0, const GroupStateValidityCallbackFn &constraint=GroupStateValidityCallbackFn(), const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions(), const kinematics::KinematicsBase::IKCostFn &cost_function=kinematics::KinematicsBase::IKCostFn())
If the group this state corresponds to is a chain and a solver is available, then the joint values ca...
rclcpp::Logger getLogger()
Core components of MoveIt.
std::function< bool(RobotState *robot_state, const JointModelGroup *joint_group, const double *joint_group_variable_values)> GroupStateValidityCallbackFn
Signature for functions that can verify that if the group joint_group in robot_state is set to joint_...
std::optional< int > hasJointSpaceJump(const std::vector< moveit::core::RobotStatePtr > &waypoints, const moveit::core::JointModelGroup &group, const moveit::core::JumpThreshold &jump_threshold)
Checks if a joint-space path has a jump larger than the given threshold.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
double distance(const urdf::Pose &transform)
A set of options for the kinematics solver.
Struct with options for defining joint-space jump thresholds.
static JumpThreshold relative(double relative_factor)
Detect joint-space jumps relative to the average joint-space displacement along the path.
static JumpThreshold absolute(double revolute, double prismatic)
Detect joint-space jumps greater than the given absolute thresholds.
static JumpThreshold disabled()
Do not define any jump threshold, i.e., disable joint-space jump detection.
Struct for containing max_step for computeCartesianPath.