controls  3.0.0
TrajectoryUtils.h
Go to the documentation of this file.
1 #ifndef TRAJECTORY_UTILS_H
2 #define TRAJECTORY_UTILS_H
3 
4 #include <mav_trajectory_generation/polynomial_optimization_nonlinear.h>
5 #include <mav_trajectory_generation/segment.h>
6 #include <mav_trajectory_generation/trajectory.h>
7 #include <mav_trajectory_generation/vertex.h>
8 
9 #include <Eigen/Core>
10 #include <optional>
11 #include <vector>
12 
13 #include "utils/NodeUtils.h"
14 
16 
35 template <int DerivativeToOptimize>
36 std::optional<Segment::Vector> optimize_path(const std::vector<Eigen::VectorXd>& waypoints,
37  const Eigen::VectorXd& start_vel, double v_max, double a_max) {
38  const int dimension = start_vel.size();
39  constexpr int N = 2 * (DerivativeToOptimize + 1);
40 
41  Vertex::Vector vertices;
42  for (size_t i = 0; i < waypoints.size(); ++i) {
43  Vertex vertex(dimension);
44  if (i == 0) {
45  vertex.makeStartOrEnd(waypoints[i], DerivativeToOptimize);
46  vertex.addConstraint(derivative_order::VELOCITY, start_vel);
47  } else if (i == waypoints.size() - 1) {
48  vertex.makeStartOrEnd(waypoints[i], DerivativeToOptimize);
49  } else {
50  vertex.addConstraint(derivative_order::POSITION, waypoints[i]);
51  }
52  vertices.push_back(vertex);
53  }
54 
55  std::vector<double> segment_times = estimateSegmentTimes(vertices, v_max, a_max);
56 
57  NonlinearOptimizationParameters parameters;
58  PolynomialOptimizationNonLinear<N> opt(dimension, parameters);
59  if (!opt.setupFromVertices(vertices, segment_times, DerivativeToOptimize)) {
60  RCLCPP_WARN(Controller::NodeUtils::get_logger(), "[TRAJ PLANNER] setupFromVertices failed");
61  return std::nullopt;
62  }
63 
64  opt.addMaximumMagnitudeConstraint(derivative_order::VELOCITY, v_max);
65  opt.addMaximumMagnitudeConstraint(derivative_order::ACCELERATION, a_max);
66 
67  int result = opt.optimize();
68  if (result < 0 && result != nlopt::ROUNDOFF_LIMITED) {
69  RCLCPP_WARN(Controller::NodeUtils::get_logger(), "[TRAJ PLANNER] nlopt optimization failed: %s",
70  nlopt::returnValueToString(result).c_str());
71  // TODO: need to fix error handling in mav_trajectory_generation itself
72  // currently it just try catches and reports -1 (nlopt::FAILURE) even if the error is something recoverable like
73  // nlopt::ROUNDOFF_LIMITED (which is the error usually)
74 
75  // do not block return for now
76  // return std::nullopt;
77  }
78 
79  Trajectory trajectory;
80  opt.getTrajectory(&trajectory);
81 
82  if (!trajectory.scaleSegmentTimesToMeetConstraints(v_max, a_max)) {
83  RCLCPP_WARN(Controller::NodeUtils::get_logger(), "[TRAJ PLANNER] scaleSegmentTimesToMeetConstraints failed");
84  return std::nullopt;
85  }
86 
87  Segment::Vector segments;
88  trajectory.getSegments(&segments);
89  return segments;
90 }
91 
102 template <int DerivativeToOptimize>
103 Segment get_constant_segment(const Eigen::VectorXd& value, double duration) {
104  constexpr int N = 2 * (DerivativeToOptimize + 1);
105  const int dimension = value.size();
106 
107  Segment seg(N, dimension);
108  seg.setTime(duration);
109 
110  for (int d = 0; d < dimension; ++d) {
111  Eigen::VectorXd coeffs = Eigen::VectorXd::Zero(N);
112  coeffs(0) = value(d);
113  seg[d].setCoefficients(coeffs);
114  }
115 
116  return seg;
117 }
118 
136 template <int DerivativeToOptimize>
137 std::optional<Trajectory> calculate_trajectory(const std::vector<Eigen::VectorXd>& waypoints,
138  const Eigen::VectorXd& start_vel, double v_max, double a_max,
139  double min_segment_time) {
140  if (waypoints.size() < 2) {
141  return std::nullopt;
142  }
143 
144  const int dimension = start_vel.size();
145  Segment::Vector all_segments;
146 
147  Eigen::VectorXd current_vel = start_vel;
148 
149  size_t i = 0;
150  while (i < waypoints.size() - 1) {
151  if (waypoints[i] == waypoints[i + 1]) {
152  all_segments.push_back(get_constant_segment<DerivativeToOptimize>(waypoints[i], min_segment_time));
153  current_vel = Eigen::VectorXd::Zero(dimension);
154  ++i;
155  } else {
156  std::vector<Eigen::VectorXd> path;
157  path.push_back(waypoints[i]);
158  while (i < waypoints.size() - 1 && waypoints[i] != waypoints[i + 1]) {
159  path.push_back(waypoints[i + 1]);
160  ++i;
161  }
162 
163  auto segments = optimize_path<DerivativeToOptimize>(path, current_vel, v_max, a_max);
164  if (!segments) {
165  return std::nullopt;
166  }
167 
168  all_segments.insert(all_segments.end(), segments->begin(), segments->end());
169  current_vel = Eigen::VectorXd::Zero(dimension);
170  }
171  }
172 
173  if (all_segments.empty()) {
174  return std::nullopt;
175  }
176 
177  Trajectory trajectory;
178  trajectory.setSegments(all_segments);
179  return trajectory;
180 }
181 
187  int start;
188 
190  int size;
191 
193  double v_max;
194 
196  double a_max;
197 };
198 
216 template <int DerivativeToOptimize>
217 std::optional<Trajectory> calculate_trajectory_multidim(const std::vector<Eigen::VectorXd>& waypoints,
218  const Eigen::VectorXd& start_vel,
219  const std::vector<DimensionGroup>& groups,
220  double min_segment_time) {
221  if (waypoints.size() < 2 || groups.empty()) {
222  return std::nullopt;
223  }
224 
225  std::optional<Trajectory> combined;
226 
227  for (const auto& group : groups) {
228  std::vector<Eigen::VectorXd> sub_waypoints;
229  sub_waypoints.reserve(waypoints.size());
230  for (const auto& wp : waypoints) {
231  sub_waypoints.push_back(wp.segment(group.start, group.size));
232  }
233 
234  Eigen::VectorXd sub_vel = start_vel.segment(group.start, group.size);
235 
236  auto traj = calculate_trajectory<DerivativeToOptimize>(sub_waypoints, sub_vel, group.v_max, group.a_max,
237  min_segment_time);
238  if (!traj) {
239  return std::nullopt;
240  }
241 
242  if (!combined) {
243  combined = *traj;
244  } else {
245  Trajectory appended;
246  if (!combined->getTrajectoryWithAppendedDimension(*traj, &appended)) {
247  return std::nullopt;
248  }
249  combined = appended;
250  }
251  }
252 
253  return combined;
254 }
255 
256 } // namespace mav_trajectory_generation
257 
258 #endif // TRAJECTORY_UTILS_H
static rclcpp::Logger get_logger()
Returns the ROS logger associated with the shared node.
Definition: NodeUtils.h:58
Definition: TrajectoryUtils.h:15
std::optional< Trajectory > calculate_trajectory(const std::vector< Eigen::VectorXd > &waypoints, const Eigen::VectorXd &start_vel, double v_max, double a_max, double min_segment_time)
Plans a trajectory through waypoints, inserting constant segments at duplicate points.
Definition: TrajectoryUtils.h:137
std::optional< Trajectory > calculate_trajectory_multidim(const std::vector< Eigen::VectorXd > &waypoints, const Eigen::VectorXd &start_vel, const std::vector< DimensionGroup > &groups, double min_segment_time)
Plans a multi-DOF trajectory by solving each dimension group independently and concatenating the resu...
Definition: TrajectoryUtils.h:217
std::optional< Segment::Vector > optimize_path(const std::vector< Eigen::VectorXd > &waypoints, const Eigen::VectorXd &start_vel, double v_max, double a_max)
Plans a minimum-derivative polynomial path through a sequence of distinct waypoints.
Definition: TrajectoryUtils.h:36
Segment get_constant_segment(const Eigen::VectorXd &value, double duration)
Creates a zero-velocity constant-position polynomial segment.
Definition: TrajectoryUtils.h:103
Describes a contiguous slice of trajectory dimensions sharing a common velocity/acceleration budget.
Definition: TrajectoryUtils.h:185
int size
Number of dimensions in this group.
Definition: TrajectoryUtils.h:190
double a_max
Maximum acceleration magnitude for this group.
Definition: TrajectoryUtils.h:196
int start
Index of the first dimension in this group.
Definition: TrajectoryUtils.h:187
double v_max
Maximum velocity magnitude for this group.
Definition: TrajectoryUtils.h:193