26#include <coin/IpIpoptApplication.hpp>
27#include <coin/IpSolveStatistics.hpp>
43 std::vector<double> opt_x;
44 std::vector<double> opt_y;
45 std::vector<double> opt_theta;
46 std::vector<double> opt_kappa;
47 std::vector<double> opt_dkappa;
48 std::vector<double> opt_s;
50 if (anchor_points_.empty()) {
51 const double piecewise_length =
config_.spiral().piecewise_length();
52 const double length = raw_reference_line.
Length();
53 ADEBUG <<
"Length = " << length;
54 uint32_t num_of_pieces =
55 std::max(1u,
static_cast<uint32_t
>(length / piecewise_length));
57 const double delta_s = length / num_of_pieces;
60 std::vector<Eigen::Vector2d> raw_point2d;
61 for (std::uint32_t i = 0; i <= num_of_pieces;
62 ++i, s = std::fmin(s + delta_s, length)) {
64 raw_point2d.emplace_back(rlp.
x(), rlp.
y());
67 Smooth(raw_point2d, &opt_theta, &opt_kappa, &opt_dkappa, &opt_s, &opt_x,
70 size_t start_index = 0;
71 for (
const auto& anchor_point : anchor_points_) {
72 if (anchor_point.enforced) {
79 std::vector<Eigen::Vector2d> raw_point2d;
80 if (start_index == 0) {
81 for (
const auto& anchor_point : anchor_points_) {
82 raw_point2d.emplace_back(anchor_point.path_point.x(),
83 anchor_point.path_point.y());
86 std::vector<double> overhead_s;
87 for (
size_t i = 0; i + 1 < start_index; ++i) {
88 const auto& p0 = anchor_points_[i];
89 const auto& p1 = anchor_points_[i + 1];
90 overhead_s.push_back(p1.path_point.s() - p0.path_point.s());
93 std::vector<double> overhead_theta;
94 std::vector<double> overhead_kappa;
95 std::vector<double> overhead_dkappa;
96 std::vector<double> overhead_x;
97 std::vector<double> overhead_y;
98 for (
size_t i = 0; i < anchor_points_.size(); ++i) {
99 const auto& p = anchor_points_[i];
100 if (i + 1 < start_index) {
101 overhead_theta.push_back(p.path_point.theta());
102 overhead_kappa.push_back(p.path_point.kappa());
103 overhead_dkappa.push_back(p.path_point.dkappa());
104 overhead_x.push_back(p.path_point.x());
105 overhead_y.push_back(p.path_point.y());
107 raw_point2d.emplace_back(p.path_point.x(), p.path_point.y());
111 const auto& start_anchor_point = anchor_points_[start_index - 1];
112 fixed_start_point_ =
true;
113 fixed_start_x_ = start_anchor_point.path_point.x();
114 fixed_start_y_ = start_anchor_point.path_point.y();
117 fixed_start_kappa_ = start_anchor_point.path_point.kappa();
118 fixed_start_dkappa_ = start_anchor_point.path_point.dkappa();
120 const auto& end_anchor_point = anchor_points_.back();
121 fixed_end_x_ = end_anchor_point.path_point.x();
122 fixed_end_y_ = end_anchor_point.path_point.y();
124 Smooth(raw_point2d, &opt_theta, &opt_kappa, &opt_dkappa, &opt_s, &opt_x,
127 opt_theta.insert(opt_theta.begin(), overhead_theta.begin(),
128 overhead_theta.end());
129 opt_kappa.insert(opt_kappa.begin(), overhead_kappa.begin(),
130 overhead_kappa.end());
131 opt_dkappa.insert(opt_dkappa.begin(), overhead_dkappa.begin(),
132 overhead_dkappa.end());
133 opt_s.insert(opt_s.begin(), overhead_s.begin(), overhead_s.end());
134 opt_x.insert(opt_x.begin(), overhead_x.begin(), overhead_x.end());
135 opt_y.insert(opt_y.begin(), overhead_y.begin(), overhead_y.end());
137 std::for_each(opt_x.begin(), opt_x.end(),
138 [
this](
double& x) { x += zero_x_; });
140 std::for_each(opt_y.begin(), opt_y.end(),
141 [
this](
double& y) { y += zero_y_; });
145 std::vector<common::PathPoint> smoothed_point2d =
146 Interpolate(opt_theta, opt_kappa, opt_dkappa, opt_s, opt_x, opt_y,
149 std::vector<ReferencePoint> ref_points;
150 for (
const auto& p : smoothed_point2d) {
151 const double heading = p.theta();
152 const double kappa = p.kappa();
153 const double dkappa = p.dkappa();
156 if (!raw_reference_line.
XYToSL(p, &ref_sl_point)) {
159 if (ref_sl_point.
s() < 0 ||
160 ref_sl_point.
s() > raw_reference_line.
Length()) {
165 ref_points.emplace_back(
172 if (ref_points.size() < 2) {
173 AERROR <<
"Fail to generate smoothed reference line.";
181 std::vector<Eigen::Vector2d> point2d, std::vector<double>* ptr_theta,
182 std::vector<double>* ptr_kappa, std::vector<double>* ptr_dkappa,
183 std::vector<double>* ptr_s, std::vector<double>* ptr_x,
184 std::vector<double>* ptr_y)
const {
185 CHECK_GT(point2d.size(), 1U);
194 Ipopt::SmartPtr<Ipopt::TNLP> problem = ptop;
197 Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory();
199 app->Options()->SetStringValue(
"hessian_approximation",
"limited-memory");
200 app->Options()->SetIntegerValue(
"max_iter",
config_.spiral().max_iteration());
201 app->Options()->SetNumericValue(
"tol",
config_.spiral().opt_tol());
202 app->Options()->SetNumericValue(
"acceptable_tol",
203 config_.spiral().opt_acceptable_tol());
205 Ipopt::ApplicationReturnStatus status = app->Initialize();
206 if (status != Ipopt::Solve_Succeeded) {
207 ADEBUG <<
"*** Error during initialization!";
211 status = app->OptimizeTNLP(problem);
213 if (status == Ipopt::Solve_Succeeded ||
214 status == Ipopt::Solved_To_Acceptable_Level) {
216 Ipopt::Index iter_count = app->Statistics()->IterationCount();
217 ADEBUG <<
"*** The problem solved in " << iter_count <<
" iterations!";
219 Ipopt::Number final_obj = app->Statistics()->FinalObjective();
220 ADEBUG <<
"*** The final value of the objective function is " << final_obj
223 ADEBUG <<
"Return status: " << int(status);
229 if (!(status == Ipopt::Solve_Succeeded) &&
230 !(status == Ipopt::Solved_To_Acceptable_Level)) {
233 return app->Statistics()->IterationCount();
237 std::vector<double>* ptr_theta,
238 std::vector<double>* ptr_kappa,
239 std::vector<double>* ptr_dkappa,
240 std::vector<double>* ptr_s,
241 std::vector<double>* ptr_x,
242 std::vector<double>* ptr_y)
const {
243 CHECK_GT(point2d.size(), 1U);
248 if (fixed_start_point_) {
249 ptop->
set_start_point(fixed_start_x_, fixed_start_y_, fixed_start_theta_,
250 fixed_start_kappa_, fixed_start_dkappa_);
258 Ipopt::SmartPtr<Ipopt::TNLP> problem = ptop;
261 Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory();
263 app->Options()->SetStringValue(
"hessian_approximation",
"limited-memory");
264 app->Options()->SetIntegerValue(
"print_level", 0);
265 app->Options()->SetIntegerValue(
"max_iter",
config_.spiral().max_iteration());
266 app->Options()->SetIntegerValue(
"acceptable_iter",
267 config_.spiral().opt_acceptable_iteration());
268 app->Options()->SetNumericValue(
"tol",
config_.spiral().opt_tol());
269 app->Options()->SetNumericValue(
"acceptable_tol",
270 config_.spiral().opt_acceptable_tol());
272 Ipopt::ApplicationReturnStatus status = app->Initialize();
273 if (status != Ipopt::Solve_Succeeded) {
274 ADEBUG <<
"*** Error during initialization!";
278 status = app->OptimizeTNLP(problem);
280 if (status == Ipopt::Solve_Succeeded ||
281 status == Ipopt::Solved_To_Acceptable_Level) {
283 Ipopt::Index iter_count = app->Statistics()->IterationCount();
284 ADEBUG <<
"*** The problem solved in " << iter_count <<
" iterations!";
286 Ipopt::Number final_obj = app->Statistics()->FinalObjective();
287 ADEBUG <<
"*** The final value of the objective function is " << final_obj
290 ADEBUG <<
"Return status: " << int(status);
296 return status == Ipopt::Solve_Succeeded ||
297 status == Ipopt::Solved_To_Acceptable_Level;
301 const std::vector<double>& theta,
const std::vector<double>& kappa,
302 const std::vector<double>& dkappa,
const std::vector<double>& s,
303 const std::vector<double>& x,
const std::vector<double>& y,
304 const double resolution)
const {
305 std::vector<common::PathPoint> smoothed_point2d;
306 double start_s = 0.0;
308 to_path_point(x.front(), y.front(), start_s, theta.front(), kappa.front(),
310 smoothed_point2d.push_back(first_point);
312 for (
size_t i = 0; i + 1 < theta.size(); ++i) {
313 double start_x = x[i];
314 double start_y = y[i];
317 start_x, start_y, start_s, theta[i], kappa[i], dkappa[i], theta[i + 1],
318 kappa[i + 1], dkappa[i + 1], s[i], resolution);
320 smoothed_point2d.insert(smoothed_point2d.end(), path_point_seg.begin(),
321 path_point_seg.end());
323 start_s = smoothed_point2d.back().s();
325 return smoothed_point2d;
329 const double start_x,
const double start_y,
const double start_s,
330 const double theta0,
const double kappa0,
const double dkappa0,
331 const double theta1,
const double kappa1,
const double dkappa1,
332 const double delta_s,
const double resolution)
const {
333 std::vector<common::PathPoint> path_points;
338 kappa1, dkappa1, delta_s);
339 size_t num_of_points =
340 static_cast<size_t>(std::ceil(delta_s / resolution) + 1);
341 for (
size_t i = 1; i <= num_of_points; ++i) {
342 const double inter_s =
343 delta_s /
static_cast<double>(num_of_points) *
static_cast<double>(i);
344 const double dx = spiral_curve.ComputeCartesianDeviationX<10>(inter_s);
345 const double dy = spiral_curve.ComputeCartesianDeviationY<10>(inter_s);
349 const double kappa = spiral_curve.Evaluate(1, inter_s);
350 const double dkappa = spiral_curve.Evaluate(2, inter_s);
352 auto path_point = to_path_point(start_x + dx, start_y + dy,
353 start_s + inter_s, theta, kappa, dkappa);
354 path_points.push_back(std::move(path_point));
359common::PathPoint SpiralReferenceLineSmoother::to_path_point(
360 const double x,
const double y,
const double s,
const double theta,
361 const double kappa,
const double dkappa)
const {
362 common::PathPoint point;
366 point.set_theta(theta);
367 point.set_kappa(kappa);
368 point.set_dkappa(dkappa);
373 const std::vector<AnchorPoint>& anchor_points) {
374 anchor_points_ = std::move(anchor_points);
376 CHECK_GT(anchor_points_.size(), 1U);
377 zero_x_ = anchor_points_.front().path_point.x();
378 zero_y_ = anchor_points_.front().path_point.y();
380 std::for_each(anchor_points_.begin(), anchor_points_.end(),
382 auto curr_x = p.path_point.x();
383 auto curr_y = p.path_point.y();
384 p.path_point.set_x(curr_x - zero_x_);
385 p.path_point.set_y(curr_y - zero_y_);
Implements a class of 2-dimensional vectors.
double y() const
Getter for y component
double x() const
Getter for x component
const std::vector< LaneWaypoint > & lane_waypoints() const
Describe a quintic spiral path Map (theta0, kappa0, dkappa0) --— delta_s --—> (theta1,...
ReferenceLineSmootherConfig config_
ReferencePoint GetReferencePoint(const double s) const
bool XYToSL(const common::math::Vec2d &xy_point, common::SLPoint *const sl_point, double warm_start_s=-1.0) const
Transvert Cartesian coordinates to Frenet.
static void RemoveDuplicates(std::vector< ReferencePoint > *points)
void set_start_point(const double x, const double y, const double theta, const double kappa, const double dkappa)
void set_element_weight_curve_length(const double weight_curve_length)
void set_element_weight_kappa(const double weight_kappa)
void set_default_max_point_deviation(const double point_max_deviation)
void get_optimization_results(std::vector< double > *ptr_theta, std::vector< double > *ptr_kappa, std::vector< double > *ptr_dkappa, std::vector< double > *ptr_s, std::vector< double > *ptr_x, std::vector< double > *ptr_y) const
void set_element_weight_dkappa(const double weight_dkappa)
void set_end_point_position(const double x, const double y)
std::vector< common::PathPoint > Interpolate(const std::vector< double > &theta, const std::vector< double > &kappa, const std::vector< double > &dkappa, const std::vector< double > &s, const std::vector< double > &x, const std::vector< double > &y, const double resolution) const
int SmoothStandAlone(std::vector< Eigen::Vector2d > point2d, std::vector< double > *ptr_theta, std::vector< double > *ptr_kappa, std::vector< double > *ptr_dkappa, std::vector< double > *ptr_s, std::vector< double > *ptr_x, std::vector< double > *ptr_y) const
bool Smooth(const ReferenceLine &raw_reference_line, ReferenceLine *const smoothed_reference_line) override
Smooth a given reference line
SpiralReferenceLineSmoother(const ReferenceLineSmootherConfig &config)
void SetAnchorPoints(const std::vector< AnchorPoint > &) override
Smoothing constraints
Planning module main class.
double AngleDiff(const double from, const double to)
Calculate the difference between angle from and to
double NormalizeAngle(const double angle)
Normalize angle to [-PI, PI).
optional double resolution