39 #include <rclcpp/logger.hpp>
40 #include <rclcpp/logging.hpp>
42 #include <Eigen/Geometry>
52 static const rclcpp::Logger
LOGGER =
53 rclcpp::get_logger(
"moveit_trajectory_processing.time_optimal_trajectory_generation");
54 constexpr
double DEFAULT_TIMESTEP = 1e-3;
55 constexpr
double EPS = 1e-6;
56 constexpr
double DEFAULT_SCALING_FACTOR = 1.0;
63 :
PathSegment((end - start).norm()), end_(end), start_(start)
70 s = std::max(0.0, std::min(1.0, s));
71 return (1.0 - s) * start_ + s * end_;
76 return (end_ - start_) /
length_;
81 return Eigen::VectorXd::Zero(start_.size());
86 return std::list<double>();
96 Eigen::VectorXd start_;
102 CircularPathSegment(
const Eigen::VectorXd& start,
const Eigen::VectorXd& intersection,
const Eigen::VectorXd& end,
103 double max_deviation)
105 if ((intersection - start).norm() < 0.000001 || (end - intersection).norm() < 0.000001)
109 center_ = intersection;
110 x_ = Eigen::VectorXd::Zero(start.size());
111 y_ = Eigen::VectorXd::Zero(start.size());
115 const Eigen::VectorXd start_direction = (intersection - start).normalized();
116 const Eigen::VectorXd end_direction = (end - intersection).normalized();
117 const double start_dot_end = start_direction.dot(end_direction);
120 if (start_dot_end > 0.999999 || start_dot_end < -0.999999)
124 center_ = intersection;
125 x_ = Eigen::VectorXd::Zero(start.size());
126 y_ = Eigen::VectorXd::Zero(start.size());
130 const double angle = acos(start_dot_end);
131 const double start_distance = (start - intersection).norm();
132 const double end_distance = (end - intersection).norm();
135 double distance = std::min(start_distance, end_distance);
136 distance = std::min(
distance, max_deviation * sin(0.5 * angle) / (1.0 - cos(0.5 * angle)));
138 radius_ =
distance / tan(0.5 * angle);
141 center_ = intersection + (end_direction - start_direction).normalized() * radius_ / cos(0.5 * angle);
142 x_ = (intersection -
distance * start_direction - center_).normalized();
143 y_ = start_direction;
148 const double angle = s / radius_;
149 return center_ + radius_ * (x_ * cos(angle) + y_ * sin(angle));
154 const double angle = s / radius_;
155 return -x_ * sin(angle) + y_ * cos(angle);
160 const double angle = s / radius_;
161 return -1.0 / radius_ * (x_ * cos(angle) + y_ * sin(angle));
166 std::list<double> switching_points;
167 const double dim = x_.size();
168 for (
unsigned int i = 0; i < dim; ++i)
170 double switching_angle = atan2(y_[i], x_[i]);
171 if (switching_angle < 0.0)
173 switching_angle += M_PI;
175 const double switching_point = switching_angle * radius_;
178 switching_points.push_back(switching_point);
181 switching_points.sort();
182 return switching_points;
192 Eigen::VectorXd center_;
197 Path::Path(
const std::list<Eigen::VectorXd>& path,
double max_deviation) : length_(0.0)
201 std::list<Eigen::VectorXd>::const_iterator path_iterator1 = path.begin();
202 std::list<Eigen::VectorXd>::const_iterator path_iterator2 = path_iterator1;
204 std::list<Eigen::VectorXd>::const_iterator path_iterator3;
205 Eigen::VectorXd start_config = *path_iterator1;
206 while (path_iterator2 != path.end())
208 path_iterator3 = path_iterator2;
210 if (max_deviation > 0.0 && path_iterator3 != path.end())
214 0.5 * (*path_iterator2 + *path_iterator3), max_deviation);
215 Eigen::VectorXd end_config = blend_segment->
getConfig(0.0);
216 if ((end_config - start_config).norm() > 0.000001)
218 path_segments_.push_back(std::make_unique<LinearPathSegment>(start_config, end_config));
220 path_segments_.emplace_back(blend_segment);
226 path_segments_.push_back(std::make_unique<LinearPathSegment>(start_config, *path_iterator2));
227 start_config = *path_iterator2;
229 path_iterator1 = path_iterator2;
235 for (std::unique_ptr<PathSegment>& path_segment : path_segments_)
237 path_segment->position_ = length_;
238 std::list<double> local_switching_points = path_segment->getSwitchingPoints();
239 for (std::list<double>::const_iterator point = local_switching_points.begin();
240 point != local_switching_points.end(); ++point)
242 switching_points_.push_back(std::make_pair(length_ + *point,
false));
244 length_ += path_segment->getLength();
245 while (!switching_points_.empty() && switching_points_.back().first >= length_)
246 switching_points_.pop_back();
247 switching_points_.push_back(std::make_pair(length_,
true));
249 switching_points_.pop_back();
252 Path::Path(
const Path& path) : length_(path.length_), switching_points_(path.switching_points_)
254 for (
const std::unique_ptr<PathSegment>& path_segment : path.path_segments_)
256 path_segments_.emplace_back(path_segment->clone());
267 std::list<std::unique_ptr<PathSegment>>::const_iterator it = path_segments_.begin();
268 std::list<std::unique_ptr<PathSegment>>::const_iterator next = it;
270 while (next != path_segments_.end() && s >= (*next)->position_)
275 s -= (*it)->position_;
281 const PathSegment* path_segment = getPathSegment(s);
287 const PathSegment* path_segment = getPathSegment(s);
293 const PathSegment* path_segment = getPathSegment(s);
299 std::list<std::pair<double, bool>>::const_iterator it = switching_points_.begin();
300 while (it != switching_points_.end() && it->first <= s)
304 if (it == switching_points_.end())
306 discontinuity =
true;
309 discontinuity = it->second;
315 return switching_points_;
321 , max_velocity_(max_velocity)
322 , max_acceleration_(max_acceleration)
323 , joint_num_(max_velocity.size())
325 , time_step_(time_step)
326 , cached_time_(std::numeric_limits<double>::max())
331 RCLCPP_ERROR(LOGGER,
"The trajectory is invalid because the time step is 0.");
334 trajectory_.push_back(TrajectoryStep(0.0, 0.0));
335 double after_acceleration = getMinMaxPathAcceleration(0.0, 0.0,
true);
336 while (valid_ && !integrateForward(trajectory_, after_acceleration) && valid_)
338 double before_acceleration;
339 TrajectoryStep switching_point;
340 if (getNextSwitchingPoint(trajectory_.back().path_pos_, switching_point, before_acceleration, after_acceleration))
344 integrateBackward(trajectory_, switching_point.path_pos_, switching_point.path_vel_, before_acceleration);
349 double before_acceleration = getMinMaxPathAcceleration(path_.
getLength(), 0.0,
false);
350 integrateBackward(trajectory_, path_.
getLength(), 0.0, before_acceleration);
356 std::list<TrajectoryStep>::iterator previous = trajectory_.begin();
357 std::list<TrajectoryStep>::iterator it = previous;
360 while (it != trajectory_.end())
363 previous->time_ + (it->path_pos_ - previous->path_pos_) / ((it->path_vel_ + previous->path_vel_) / 2.0);
375 bool Trajectory::getNextSwitchingPoint(
double path_pos, TrajectoryStep& next_switching_point,
376 double& before_acceleration,
double& after_acceleration)
378 TrajectoryStep acceleration_switching_point(path_pos, 0.0);
379 double acceleration_before_acceleration, acceleration_after_acceleration;
380 bool acceleration_reached_end;
383 acceleration_reached_end =
384 getNextAccelerationSwitchingPoint(acceleration_switching_point.path_pos_, acceleration_switching_point,
385 acceleration_before_acceleration, acceleration_after_acceleration);
386 }
while (!acceleration_reached_end &&
387 acceleration_switching_point.path_vel_ > getVelocityMaxPathVelocity(acceleration_switching_point.path_pos_));
389 TrajectoryStep velocity_switching_point(path_pos, 0.0);
390 double velocity_before_acceleration, velocity_after_acceleration;
391 bool velocity_reached_end;
394 velocity_reached_end = getNextVelocitySwitchingPoint(velocity_switching_point.path_pos_, velocity_switching_point,
395 velocity_before_acceleration, velocity_after_acceleration);
397 !velocity_reached_end && velocity_switching_point.path_pos_ <= acceleration_switching_point.path_pos_ &&
398 (velocity_switching_point.path_vel_ > getAccelerationMaxPathVelocity(velocity_switching_point.path_pos_ - EPS) ||
399 velocity_switching_point.path_vel_ > getAccelerationMaxPathVelocity(velocity_switching_point.path_pos_ + EPS)));
401 if (acceleration_reached_end && velocity_reached_end)
405 else if (!acceleration_reached_end &&
406 (velocity_reached_end || acceleration_switching_point.path_pos_ <= velocity_switching_point.path_pos_))
408 next_switching_point = acceleration_switching_point;
409 before_acceleration = acceleration_before_acceleration;
410 after_acceleration = acceleration_after_acceleration;
415 next_switching_point = velocity_switching_point;
416 before_acceleration = velocity_before_acceleration;
417 after_acceleration = velocity_after_acceleration;
422 bool Trajectory::getNextAccelerationSwitchingPoint(
double path_pos, TrajectoryStep& next_switching_point,
423 double& before_acceleration,
double& after_acceleration)
425 double switching_path_pos = path_pos;
426 double switching_path_vel;
432 if (switching_path_pos > path_.
getLength() - EPS)
439 const double before_path_vel = getAccelerationMaxPathVelocity(switching_path_pos - EPS);
440 const double after_path_vel = getAccelerationMaxPathVelocity(switching_path_pos + EPS);
441 switching_path_vel = std::min(before_path_vel, after_path_vel);
442 before_acceleration = getMinMaxPathAcceleration(switching_path_pos - EPS, switching_path_vel,
false);
443 after_acceleration = getMinMaxPathAcceleration(switching_path_pos + EPS, switching_path_vel,
true);
445 if ((before_path_vel > after_path_vel ||
446 getMinMaxPhaseSlope(switching_path_pos - EPS, switching_path_vel,
false) >
447 getAccelerationMaxPathVelocityDeriv(switching_path_pos - 2.0 * EPS)) &&
448 (before_path_vel < after_path_vel || getMinMaxPhaseSlope(switching_path_pos + EPS, switching_path_vel,
true) <
449 getAccelerationMaxPathVelocityDeriv(switching_path_pos + 2.0 * EPS)))
456 switching_path_vel = getAccelerationMaxPathVelocity(switching_path_pos);
457 before_acceleration = 0.0;
458 after_acceleration = 0.0;
460 if (getAccelerationMaxPathVelocityDeriv(switching_path_pos - EPS) < 0.0 &&
461 getAccelerationMaxPathVelocityDeriv(switching_path_pos + EPS) > 0.0)
468 next_switching_point = TrajectoryStep(switching_path_pos, switching_path_vel);
472 bool Trajectory::getNextVelocitySwitchingPoint(
double path_pos, TrajectoryStep& next_switching_point,
473 double& before_acceleration,
double& after_acceleration)
476 path_pos -= DEFAULT_TIMESTEP;
479 path_pos += DEFAULT_TIMESTEP;
481 if (getMinMaxPhaseSlope(path_pos, getVelocityMaxPathVelocity(path_pos),
false) >=
482 getVelocityMaxPathVelocityDeriv(path_pos))
486 }
while ((!start || getMinMaxPhaseSlope(path_pos, getVelocityMaxPathVelocity(path_pos),
false) >
487 getVelocityMaxPathVelocityDeriv(path_pos)) &&
495 double before_path_pos = path_pos - DEFAULT_TIMESTEP;
496 double after_path_pos = path_pos;
497 while (after_path_pos - before_path_pos > EPS)
499 path_pos = (before_path_pos + after_path_pos) / 2.0;
500 if (getMinMaxPhaseSlope(path_pos, getVelocityMaxPathVelocity(path_pos),
false) >
501 getVelocityMaxPathVelocityDeriv(path_pos))
503 before_path_pos = path_pos;
507 after_path_pos = path_pos;
511 before_acceleration = getMinMaxPathAcceleration(before_path_pos, getVelocityMaxPathVelocity(before_path_pos),
false);
512 after_acceleration = getMinMaxPathAcceleration(after_path_pos, getVelocityMaxPathVelocity(after_path_pos),
true);
513 next_switching_point = TrajectoryStep(after_path_pos, getVelocityMaxPathVelocity(after_path_pos));
518 bool Trajectory::integrateForward(std::list<TrajectoryStep>& trajectory,
double acceleration)
520 double path_pos = trajectory.back().path_pos_;
521 double path_vel = trajectory.back().path_vel_;
524 std::list<std::pair<double, bool>>::iterator next_discontinuity = switching_points.begin();
528 while ((next_discontinuity != switching_points.end()) &&
529 (next_discontinuity->first <= path_pos || !next_discontinuity->second))
531 ++next_discontinuity;
534 double old_path_pos = path_pos;
535 double old_path_vel = path_vel;
537 path_vel += time_step_ * acceleration;
538 path_pos += time_step_ * 0.5 * (old_path_vel + path_vel);
540 if (next_discontinuity != switching_points.end() && path_pos > next_discontinuity->first)
544 if (path_pos - next_discontinuity->first < EPS)
548 path_vel = old_path_vel +
549 (next_discontinuity->first - old_path_pos) * (path_vel - old_path_vel) / (path_pos - old_path_pos);
550 path_pos = next_discontinuity->first;
555 trajectory.push_back(TrajectoryStep(path_pos, path_vel));
558 else if (path_vel < 0.0)
561 RCLCPP_ERROR(LOGGER,
"Error while integrating forward: Negative path velocity");
565 if (path_vel > getVelocityMaxPathVelocity(path_pos) &&
566 getMinMaxPhaseSlope(old_path_pos, getVelocityMaxPathVelocity(old_path_pos),
false) <=
567 getVelocityMaxPathVelocityDeriv(old_path_pos))
569 path_vel = getVelocityMaxPathVelocity(path_pos);
572 trajectory.push_back(TrajectoryStep(path_pos, path_vel));
573 acceleration = getMinMaxPathAcceleration(path_pos, path_vel,
true);
575 if (path_vel == 0 && acceleration == 0)
580 RCLCPP_ERROR(LOGGER,
"Error while integrating forward: zero acceleration and velocity. Are any relevant "
581 "acceleration components limited to zero?");
585 if (path_vel > getAccelerationMaxPathVelocity(path_pos) || path_vel > getVelocityMaxPathVelocity(path_pos))
588 TrajectoryStep overshoot = trajectory.back();
589 trajectory.pop_back();
590 double before = trajectory.back().path_pos_;
591 double before_path_vel = trajectory.back().path_vel_;
592 double after = overshoot.path_pos_;
593 double after_path_vel = overshoot.path_vel_;
594 while (after - before > EPS)
596 const double midpoint = 0.5 * (before + after);
597 double midpoint_path_vel = 0.5 * (before_path_vel + after_path_vel);
599 if (midpoint_path_vel > getVelocityMaxPathVelocity(midpoint) &&
600 getMinMaxPhaseSlope(before, getVelocityMaxPathVelocity(before),
false) <=
601 getVelocityMaxPathVelocityDeriv(before))
603 midpoint_path_vel = getVelocityMaxPathVelocity(midpoint);
606 if (midpoint_path_vel > getAccelerationMaxPathVelocity(midpoint) ||
607 midpoint_path_vel > getVelocityMaxPathVelocity(midpoint))
610 after_path_vel = midpoint_path_vel;
615 before_path_vel = midpoint_path_vel;
618 trajectory.push_back(TrajectoryStep(before, before_path_vel));
620 if (getAccelerationMaxPathVelocity(after) < getVelocityMaxPathVelocity(after))
622 if (after > next_discontinuity->first)
626 else if (getMinMaxPhaseSlope(trajectory.back().path_pos_, trajectory.back().path_vel_,
true) >
627 getAccelerationMaxPathVelocityDeriv(trajectory.back().path_pos_))
634 if (getMinMaxPhaseSlope(trajectory.back().path_pos_, trajectory_.back().path_vel_,
false) >
635 getVelocityMaxPathVelocityDeriv(trajectory_.back().path_pos_))
644 void Trajectory::integrateBackward(std::list<TrajectoryStep>& start_trajectory,
double path_pos,
double path_vel,
647 std::list<TrajectoryStep>::iterator start2 = start_trajectory.end();
649 std::list<TrajectoryStep>::iterator start1 = start2;
651 std::list<TrajectoryStep> trajectory;
653 assert(start1->path_pos_ <= path_pos);
655 while (start1 != start_trajectory.begin() || path_pos >= 0.0)
657 if (start1->path_pos_ <= path_pos)
659 trajectory.push_front(TrajectoryStep(path_pos, path_vel));
660 path_vel -= time_step_ * acceleration;
661 path_pos -= time_step_ * 0.5 * (path_vel + trajectory.front().path_vel_);
662 acceleration = getMinMaxPathAcceleration(path_pos, path_vel,
false);
663 slope = (trajectory.front().path_vel_ - path_vel) / (trajectory.front().path_pos_ - path_pos);
668 RCLCPP_ERROR(LOGGER,
"Error while integrating backward: Negative path velocity");
669 end_trajectory_ = trajectory;
681 const double start_slope = (start2->path_vel_ - start1->path_vel_) / (start2->path_pos_ - start1->path_pos_);
682 const double intersection_path_pos =
683 (start1->path_vel_ - path_vel + slope * path_pos - start_slope * start1->path_pos_) / (slope - start_slope);
684 if (std::max(start1->path_pos_, path_pos) - EPS <= intersection_path_pos &&
685 intersection_path_pos <= EPS + std::min(start2->path_pos_, trajectory.front().path_pos_))
687 const double intersection_path_vel =
688 start1->path_vel_ + start_slope * (intersection_path_pos - start1->path_pos_);
689 start_trajectory.erase(start2, start_trajectory.end());
690 start_trajectory.push_back(TrajectoryStep(intersection_path_pos, intersection_path_vel));
691 start_trajectory.splice(start_trajectory.end(), trajectory);
697 RCLCPP_ERROR(LOGGER,
"Error while integrating backward: Did not hit start trajectory");
698 end_trajectory_ = trajectory;
701 double Trajectory::getMinMaxPathAcceleration(
double path_pos,
double path_vel,
bool max)
703 Eigen::VectorXd config_deriv = path_.
getTangent(path_pos);
704 Eigen::VectorXd config_deriv2 = path_.
getCurvature(path_pos);
705 double factor = max ? 1.0 : -1.0;
706 double max_path_acceleration = std::numeric_limits<double>::max();
707 for (
unsigned int i = 0; i < joint_num_; ++i)
709 if (config_deriv[i] != 0.0)
711 max_path_acceleration =
712 std::min(max_path_acceleration, max_acceleration_[i] / std::abs(config_deriv[i]) -
713 factor * config_deriv2[i] * path_vel * path_vel / config_deriv[i]);
716 return factor * max_path_acceleration;
719 double Trajectory::getMinMaxPhaseSlope(
double path_pos,
double path_vel,
bool max)
721 return getMinMaxPathAcceleration(path_pos, path_vel, max) / path_vel;
724 double Trajectory::getAccelerationMaxPathVelocity(
double path_pos)
const
726 double max_path_velocity = std::numeric_limits<double>::infinity();
727 const Eigen::VectorXd config_deriv = path_.
getTangent(path_pos);
728 const Eigen::VectorXd config_deriv2 = path_.
getCurvature(path_pos);
729 for (
unsigned int i = 0; i < joint_num_; ++i)
731 if (config_deriv[i] != 0.0)
733 for (
unsigned int j = i + 1; j < joint_num_; ++j)
735 if (config_deriv[j] != 0.0)
737 double a_ij = config_deriv2[i] / config_deriv[i] - config_deriv2[j] / config_deriv[j];
740 max_path_velocity = std::min(max_path_velocity, sqrt((max_acceleration_[i] / std::abs(config_deriv[i]) +
741 max_acceleration_[j] / std::abs(config_deriv[j])) /
747 else if (config_deriv2[i] != 0.0)
749 max_path_velocity = std::min(max_path_velocity, sqrt(max_acceleration_[i] / std::abs(config_deriv2[i])));
752 return max_path_velocity;
755 double Trajectory::getVelocityMaxPathVelocity(
double path_pos)
const
757 const Eigen::VectorXd tangent = path_.
getTangent(path_pos);
758 double max_path_velocity = std::numeric_limits<double>::max();
759 for (
unsigned int i = 0; i < joint_num_; ++i)
761 max_path_velocity = std::min(max_path_velocity, max_velocity_[i] / std::abs(tangent[i]));
763 return max_path_velocity;
766 double Trajectory::getAccelerationMaxPathVelocityDeriv(
double path_pos)
768 return (getAccelerationMaxPathVelocity(path_pos + EPS) - getAccelerationMaxPathVelocity(path_pos - EPS)) /
772 double Trajectory::getVelocityMaxPathVelocityDeriv(
double path_pos)
774 const Eigen::VectorXd tangent = path_.
getTangent(path_pos);
775 double max_path_velocity = std::numeric_limits<double>::max();
776 unsigned int active_constraint;
777 for (
unsigned int i = 0; i < joint_num_; ++i)
779 const double this_max_path_velocity = max_velocity_[i] / std::abs(tangent[i]);
780 if (this_max_path_velocity < max_path_velocity)
782 max_path_velocity = this_max_path_velocity;
783 active_constraint = i;
786 return -(max_velocity_[active_constraint] * path_.
getCurvature(path_pos)[active_constraint]) /
787 (tangent[active_constraint] * std::abs(tangent[active_constraint]));
797 return trajectory_.back().time_;
800 std::list<Trajectory::TrajectoryStep>::const_iterator Trajectory::getTrajectorySegment(
double time)
const
802 if (time >= trajectory_.back().time_)
804 std::list<TrajectoryStep>::const_iterator last = trajectory_.end();
810 if (time < cached_time_)
812 cached_trajectory_segment_ = trajectory_.begin();
814 while (time >= cached_trajectory_segment_->time_)
816 ++cached_trajectory_segment_;
819 return cached_trajectory_segment_;
825 std::list<TrajectoryStep>::const_iterator it = getTrajectorySegment(time);
826 std::list<TrajectoryStep>::const_iterator previous = it;
829 double time_step = it->time_ - previous->time_;
830 const double acceleration =
831 2.0 * (it->path_pos_ - previous->path_pos_ - time_step * previous->path_vel_) / (time_step * time_step);
833 time_step = time - previous->time_;
834 const double path_pos =
835 previous->path_pos_ + time_step * previous->path_vel_ + 0.5 * time_step * time_step * acceleration;
842 std::list<TrajectoryStep>::const_iterator it = getTrajectorySegment(time);
843 std::list<TrajectoryStep>::const_iterator previous = it;
846 double time_step = it->time_ - previous->time_;
847 const double acceleration =
848 2.0 * (it->path_pos_ - previous->path_pos_ - time_step * previous->path_vel_) / (time_step * time_step);
850 const double path_pos =
851 previous->path_pos_ + time_step * previous->path_vel_ + 0.5 * time_step * time_step * acceleration;
852 const double path_vel = previous->path_vel_ + time_step * acceleration;
859 std::list<TrajectoryStep>::const_iterator it = getTrajectorySegment(time);
860 std::list<TrajectoryStep>::const_iterator previous = it;
863 double time_step = it->time_ - previous->time_;
864 const double acceleration =
865 2.0 * (it->path_pos_ - previous->path_pos_ - time_step * previous->path_vel_) / (time_step * time_step);
867 const double path_pos =
868 previous->path_pos_ + time_step * previous->path_vel_ + 0.5 * time_step * time_step * acceleration;
869 const double path_vel = previous->path_vel_ + time_step * acceleration;
870 Eigen::VectorXd path_acc =
871 (path_.
getTangent(path_pos) * path_vel - path_.
getTangent(previous->path_pos_) * previous->path_vel_);
873 path_acc /= time_step;
878 const double min_angle_change)
879 : path_tolerance_(path_tolerance), resample_dt_(resample_dt), min_angle_change_(min_angle_change)
884 const double max_velocity_scaling_factor,
885 const double max_acceleration_scaling_factor)
const
887 if (trajectory.
empty())
893 RCLCPP_ERROR(LOGGER,
"It looks like the planner did not set the group the plan was computed for");
898 double velocity_scaling_factor = verifyScalingFactor(max_velocity_scaling_factor,
VELOCITY);
899 double acceleration_scaling_factor = verifyScalingFactor(max_acceleration_scaling_factor,
ACCELERATION);
903 const std::vector<std::string>& vars =
group->getVariableNames();
904 std::vector<size_t> active_joint_indices;
905 if (!
group->computeJointVariableIndices(
group->getActiveJointModelNames(), active_joint_indices))
907 RCLCPP_ERROR(LOGGER,
"Failed to get active variable indices.");
910 const size_t num_active_joints = active_joint_indices.size();
911 Eigen::VectorXd max_velocity(num_active_joints);
912 Eigen::VectorXd max_acceleration(num_active_joints);
913 for (
size_t idx = 0; idx < num_active_joints; ++idx)
923 RCLCPP_ERROR(LOGGER,
"Invalid max_velocity %f specified for '%s', must be greater than 0.0",
932 RCLCPP_ERROR_STREAM(LOGGER,
"No velocity limit was defined for joint "
934 <<
"! You have to define velocity limits in the URDF or joint_limits.yaml");
942 RCLCPP_ERROR(LOGGER,
"Invalid max_acceleration %f specified for '%s', must be greater than 0.0",
947 acceleration_scaling_factor;
951 RCLCPP_ERROR_STREAM(LOGGER,
"No acceleration limit was defined for joint "
953 <<
"! You have to define acceleration limits in the URDF or "
954 "joint_limits.yaml");
959 return doTimeParameterizationCalculations(trajectory, max_velocity, max_acceleration);
963 const std::vector<moveit_msgs::msg::JointLimits>&
joint_limits,
964 const double max_velocity_scaling_factor,
965 const double max_acceleration_scaling_factor)
const
967 std::unordered_map<std::string, double> velocity_limits;
968 std::unordered_map<std::string, double> acceleration_limits;
972 if (limit.has_velocity_limits)
974 velocity_limits[limit.joint_name] = limit.max_velocity;
976 if (limit.has_acceleration_limits)
978 acceleration_limits[limit.joint_name] = limit.max_acceleration;
981 return computeTimeStamps(trajectory, velocity_limits, acceleration_limits, max_velocity_scaling_factor,
982 max_acceleration_scaling_factor);
987 const std::unordered_map<std::string, double>& acceleration_limits,
const double max_velocity_scaling_factor,
988 const double max_acceleration_scaling_factor)
const
990 if (trajectory.
empty())
997 RCLCPP_ERROR(LOGGER,
"It looks like the planner did not set the group the plan was computed for");
1002 double velocity_scaling_factor = verifyScalingFactor(max_velocity_scaling_factor,
VELOCITY);
1003 double acceleration_scaling_factor = verifyScalingFactor(max_acceleration_scaling_factor,
ACCELERATION);
1007 const std::vector<std::string>& vars =
group->getVariableNames();
1008 std::vector<size_t> indices;
1009 if (!
group->computeJointVariableIndices(
group->getActiveJointModelNames(), indices))
1011 RCLCPP_ERROR(LOGGER,
"Failed to get active variable indices.");
1014 const size_t num_joints = indices.size();
1016 Eigen::VectorXd max_velocity(num_joints);
1017 Eigen::VectorXd max_acceleration(num_joints);
1018 for (
const auto idx : indices)
1024 bool set_velocity_limit =
false;
1025 auto it = velocity_limits.find(vars[idx]);
1026 if (it != velocity_limits.end())
1028 max_velocity[idx] = it->second * velocity_scaling_factor;
1029 set_velocity_limit =
true;
1037 RCLCPP_ERROR(LOGGER,
"Invalid max_velocity %f specified for '%s', must be greater than 0.0",
1043 set_velocity_limit =
true;
1046 if (!set_velocity_limit)
1048 RCLCPP_ERROR_STREAM(LOGGER,
"No velocity limit was defined for joint "
1049 << vars[idx].c_str()
1050 <<
"! You have to define velocity limits in the URDF or "
1051 "joint_limits.yaml");
1057 bool set_acceleration_limit =
false;
1058 it = acceleration_limits.find(vars[idx]);
1059 if (it != acceleration_limits.end())
1061 max_acceleration[idx] = it->second * acceleration_scaling_factor;
1062 set_acceleration_limit =
true;
1070 RCLCPP_ERROR(LOGGER,
"Invalid max_acceleration %f specified for '%s', must be greater than 0.0",
1075 acceleration_scaling_factor;
1076 set_acceleration_limit =
true;
1078 if (!set_acceleration_limit)
1080 RCLCPP_ERROR_STREAM(LOGGER,
"No acceleration limit was defined for joint "
1081 << vars[idx].c_str()
1082 <<
"! You have to define acceleration limits in the URDF or "
1083 "joint_limits.yaml");
1088 return doTimeParameterizationCalculations(trajectory, max_velocity, max_acceleration);
1092 const double max_velocity_scaling_factor,
const double max_acceleration_scaling_factor)
1101 if (num_waypoints < 2)
1103 RCLCPP_ERROR(LOGGER,
"computeTimeStamps() requires num_waypoints > 1");
1108 default_totg.
computeTimeStamps(trajectory, max_velocity_scaling_factor, max_acceleration_scaling_factor);
1109 double optimal_duration = trajectory.
getDuration();
1110 double new_resample_dt = optimal_duration / (num_waypoints - 1);
1112 resample_totg.
computeTimeStamps(trajectory, max_velocity_scaling_factor, max_acceleration_scaling_factor);
1117 const Eigen::VectorXd& max_velocity,
1118 const Eigen::VectorXd& max_acceleration)
const
1126 RCLCPP_ERROR(LOGGER,
"It looks like the planner did not set the group the plan was computed for");
1130 if (hasMixedJointTypes(
group))
1132 RCLCPP_WARN(LOGGER,
"There is a combination of revolute and prismatic joints in the robot model. TOTG's "
1133 "`path_tolerance` will not function correctly.");
1137 const std::vector<int>& idx =
group->getVariableIndexList();
1138 const unsigned num_joints =
group->getVariableCount();
1142 std::list<Eigen::VectorXd> points;
1143 for (
size_t p = 0; p < num_points; ++p)
1145 moveit::core::RobotStatePtr waypoint = trajectory.
getWayPointPtr(p);
1146 Eigen::VectorXd new_point(num_joints);
1148 bool diverse_point = (p == 0);
1150 for (
size_t j = 0; j < num_joints; ++j)
1152 new_point[j] = waypoint->getVariablePosition(idx[j]);
1154 if (p > 0 && std::fabs(new_point[j] - points.back()[j]) > min_angle_change_)
1156 diverse_point =
true;
1162 points.push_back(new_point);
1166 else if (p == num_points - 1)
1168 points.back() = new_point;
1173 if (points.size() == 1)
1184 Trajectory parameterized(Path(points, path_tolerance_), max_velocity, max_acceleration, DEFAULT_TIMESTEP);
1185 if (!parameterized.isValid())
1187 RCLCPP_ERROR(LOGGER,
"Unable to parameterize trajectory.");
1192 size_t sample_count = std::ceil(parameterized.getDuration() / resample_dt_);
1198 for (
size_t sample = 0; sample <= sample_count; ++sample)
1201 double t = std::min(parameterized.getDuration(), sample * resample_dt_);
1202 Eigen::VectorXd position = parameterized.getPosition(t);
1203 Eigen::VectorXd velocity = parameterized.getVelocity(t);
1204 Eigen::VectorXd acceleration = parameterized.getAcceleration(t);
1206 for (
size_t j = 0; j < num_joints; ++j)
1222 const std::vector<const moveit::core::JointModel*>& joint_models =
group->getActiveJointModels();
1224 bool have_prismatic =
1226 return joint_model->getType() == moveit::core::JointModel::JointType::PRISMATIC;
1229 bool have_revolute =
1231 return joint_model->getType() == moveit::core::JointModel::JointType::REVOLUTE;
1234 return have_prismatic && have_revolute;
1237 double TimeOptimalTrajectoryGeneration::verifyScalingFactor(
const double requested_scaling_factor,
1240 std::string limit_type_str;
1241 double scaling_factor = DEFAULT_SCALING_FACTOR;
1243 const auto limit_type_it =
LIMIT_TYPES.find(limit_type);
1246 limit_type_str = limit_type_it->second +
"_";
1249 if (requested_scaling_factor > 0.0 && requested_scaling_factor <= 1.0)
1251 scaling_factor = requested_scaling_factor;
1255 RCLCPP_WARN(LOGGER,
"Invalid max_%sscaling_factor %f specified, defaulting to %f instead.", limit_type_str.c_str(),
1256 requested_scaling_factor, scaling_factor);
1258 return scaling_factor;
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
Definition of a kinematic model. This class is not thread safe, however multiple instances can be cre...
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a specific variable. Throw an exception of variable is not found.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
void setVariableAcceleration(const std::string &variable, double value)
Set the acceleration of a variable. If an unknown variable name is specified, an exception is thrown.
void zeroVelocities()
Set all velocities to 0.0.
void setVariableVelocity(const std::string &variable, double value)
Set the velocity of a variable. If an unknown variable name is specified, an exception is thrown.
void setVariablePosition(const std::string &variable, double value)
Set the position of a single variable. An exception is thrown if the variable name is not known.
void zeroAccelerations()
Set all accelerations to 0.0.
Maintain a sequence of waypoints and the time durations between these waypoints.
const moveit::core::JointModelGroup * getGroup() const
RobotTrajectory & unwind()
RobotTrajectory & addSuffixWayPoint(const moveit::core::RobotState &state, double dt)
Add a point to the trajectory.
moveit::core::RobotStatePtr & getWayPointPtr(std::size_t index)
std::size_t getWayPointCount() const
RobotTrajectory & clear()
const moveit::core::RobotState & getWayPoint(std::size_t index) const
double getDuration() const
CircularPathSegment * clone() const override
Eigen::VectorXd getConfig(double s) const override
CircularPathSegment(const Eigen::VectorXd &start, const Eigen::VectorXd &intersection, const Eigen::VectorXd &end, double max_deviation)
Eigen::VectorXd getTangent(double s) const override
std::list< double > getSwitchingPoints() const override
Eigen::VectorXd getCurvature(double s) const override
LinearPathSegment * clone() const override
Eigen::VectorXd getTangent(double) const override
Eigen::VectorXd getCurvature(double) const override
Eigen::VectorXd getConfig(double s) const override
LinearPathSegment(const Eigen::VectorXd &start, const Eigen::VectorXd &end)
std::list< double > getSwitchingPoints() const override
virtual Eigen::VectorXd getConfig(double s) const =0
virtual Eigen::VectorXd getCurvature(double s) const =0
virtual Eigen::VectorXd getTangent(double s) const =0
Eigen::VectorXd getTangent(double s) const
std::list< std::pair< double, bool > > getSwitchingPoints() const
Return a list of all switching points as a pair (arc length to switching point, discontinuity)
Eigen::VectorXd getConfig(double s) const
Eigen::VectorXd getCurvature(double s) const
double getNextSwitchingPoint(double s, bool &discontinuity) const
Get the next switching point.
Path(const std::list< Eigen::VectorXd > &path, double max_deviation=0.0)
TimeOptimalTrajectoryGeneration(const double path_tolerance=0.1, const double resample_dt=0.1, const double min_angle_change=0.001)
bool computeTimeStamps(robot_trajectory::RobotTrajectory &trajectory, const double max_velocity_scaling_factor=1.0, const double max_acceleration_scaling_factor=1.0) const override
Compute a trajectory with waypoints spaced equally in time (according to resample_dt_)....
Eigen::VectorXd getAcceleration(double time) const
Return the acceleration vector for a given point in time.
bool isValid() const
Call this method after constructing the object to make sure the trajectory generation succeeded witho...
Eigen::VectorXd getPosition(double time) const
Return the position/configuration vector for a given point in time.
Trajectory(const Path &path, const Eigen::VectorXd &max_velocity, const Eigen::VectorXd &max_acceleration, double time_step=0.001)
Generates a time-optimal trajectory.
double getDuration() const
Returns the optimal duration of the trajectory.
Eigen::VectorXd getVelocity(double time) const
Return the velocity vector for a given point in time.
const rclcpp::Logger LOGGER
double distance(const urdf::Pose &transform)
const std::unordered_map< LimitType, std::string > LIMIT_TYPES
bool totgComputeTimeStamps(const size_t num_waypoints, robot_trajectory::RobotTrajectory &trajectory, const double max_velocity_scaling_factor=1.0, const double max_acceleration_scaling_factor=1.0)
Compute a trajectory with the desired number of waypoints. Resampling the trajectory doesn't change t...
bool acceleration_bounded_