Apollo 11.0
自动驾驶开放平台
spiral_reference_line_smoother.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17/*
18 * spiral_reference_line_smoother.cc
19 */
20
22
23#include <algorithm>
24#include <utility>
25
26#include <coin/IpIpoptApplication.hpp>
27#include <coin/IpSolveStatistics.hpp>
28
32
33namespace apollo {
34namespace planning {
35
39
41 const ReferenceLine& raw_reference_line,
42 ReferenceLine* const smoothed_reference_line) {
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;
49
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));
56
57 const double delta_s = length / num_of_pieces;
58 double s = 0.0;
59
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)) {
63 ReferencePoint rlp = raw_reference_line.GetReferencePoint(s);
64 raw_point2d.emplace_back(rlp.x(), rlp.y());
65 }
66
67 Smooth(raw_point2d, &opt_theta, &opt_kappa, &opt_dkappa, &opt_s, &opt_x,
68 &opt_y);
69 } else {
70 size_t start_index = 0;
71 for (const auto& anchor_point : anchor_points_) {
72 if (anchor_point.enforced) {
73 start_index++;
74 } else {
75 break;
76 }
77 }
78
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());
84 }
85 } else {
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());
91 }
92
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());
106 } else {
107 raw_point2d.emplace_back(p.path_point.x(), p.path_point.y());
108 }
109 }
110
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();
115 fixed_start_theta_ =
116 common::math::NormalizeAngle(start_anchor_point.path_point.theta());
117 fixed_start_kappa_ = start_anchor_point.path_point.kappa();
118 fixed_start_dkappa_ = start_anchor_point.path_point.dkappa();
119
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();
123
124 Smooth(raw_point2d, &opt_theta, &opt_kappa, &opt_dkappa, &opt_s, &opt_x,
125 &opt_y);
126
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());
136
137 std::for_each(opt_x.begin(), opt_x.end(),
138 [this](double& x) { x += zero_x_; });
139
140 std::for_each(opt_y.begin(), opt_y.end(),
141 [this](double& y) { y += zero_y_; });
142 }
143 }
144
145 std::vector<common::PathPoint> smoothed_point2d =
146 Interpolate(opt_theta, opt_kappa, opt_dkappa, opt_s, opt_x, opt_y,
148
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();
154
155 common::SLPoint ref_sl_point;
156 if (!raw_reference_line.XYToSL(p, &ref_sl_point)) {
157 return false;
158 }
159 if (ref_sl_point.s() < 0 ||
160 ref_sl_point.s() > raw_reference_line.Length()) {
161 continue;
162 }
163
164 ReferencePoint rlp = raw_reference_line.GetReferencePoint(ref_sl_point.s());
165 ref_points.emplace_back(
167 heading, rlp.lane_waypoints()),
168 kappa, dkappa));
169 }
170
172 if (ref_points.size() < 2) {
173 AERROR << "Fail to generate smoothed reference line.";
174 return false;
175 }
176 *smoothed_reference_line = ReferenceLine(ref_points);
177 return true;
178}
179
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);
186
188
189 ptop->set_default_max_point_deviation(config_.spiral().max_deviation());
190 ptop->set_element_weight_curve_length(config_.spiral().weight_curve_length());
191 ptop->set_element_weight_kappa(config_.spiral().weight_kappa());
192 ptop->set_element_weight_dkappa(config_.spiral().weight_dkappa());
193
194 Ipopt::SmartPtr<Ipopt::TNLP> problem = ptop;
195
196 // Create an instance of the IpoptApplication
197 Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory();
198
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());
204
205 Ipopt::ApplicationReturnStatus status = app->Initialize();
206 if (status != Ipopt::Solve_Succeeded) {
207 ADEBUG << "*** Error during initialization!";
208 return -1;
209 }
210
211 status = app->OptimizeTNLP(problem);
212
213 if (status == Ipopt::Solve_Succeeded ||
214 status == Ipopt::Solved_To_Acceptable_Level) {
215 // Retrieve some statistics about the solve
216 Ipopt::Index iter_count = app->Statistics()->IterationCount();
217 ADEBUG << "*** The problem solved in " << iter_count << " iterations!";
218
219 Ipopt::Number final_obj = app->Statistics()->FinalObjective();
220 ADEBUG << "*** The final value of the objective function is " << final_obj
221 << '.';
222 } else {
223 ADEBUG << "Return status: " << int(status);
224 }
225
226 ptop->get_optimization_results(ptr_theta, ptr_kappa, ptr_dkappa, ptr_s, ptr_x,
227 ptr_y);
228
229 if (!(status == Ipopt::Solve_Succeeded) &&
230 !(status == Ipopt::Solved_To_Acceptable_Level)) {
231 return -1;
232 }
233 return app->Statistics()->IterationCount();
234}
235
236bool SpiralReferenceLineSmoother::Smooth(std::vector<Eigen::Vector2d> point2d,
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);
244
246
247 ptop->set_default_max_point_deviation(config_.spiral().max_deviation());
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_);
251 }
252
253 ptop->set_end_point_position(fixed_end_x_, fixed_end_y_);
254 ptop->set_element_weight_curve_length(config_.spiral().weight_curve_length());
255 ptop->set_element_weight_kappa(config_.spiral().weight_kappa());
256 ptop->set_element_weight_dkappa(config_.spiral().weight_dkappa());
257
258 Ipopt::SmartPtr<Ipopt::TNLP> problem = ptop;
259
260 // Create an instance of the IpoptApplication
261 Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory();
262
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());
271
272 Ipopt::ApplicationReturnStatus status = app->Initialize();
273 if (status != Ipopt::Solve_Succeeded) {
274 ADEBUG << "*** Error during initialization!";
275 return false;
276 }
277
278 status = app->OptimizeTNLP(problem);
279
280 if (status == Ipopt::Solve_Succeeded ||
281 status == Ipopt::Solved_To_Acceptable_Level) {
282 // Retrieve some statistics about the solve
283 Ipopt::Index iter_count = app->Statistics()->IterationCount();
284 ADEBUG << "*** The problem solved in " << iter_count << " iterations!";
285
286 Ipopt::Number final_obj = app->Statistics()->FinalObjective();
287 ADEBUG << "*** The final value of the objective function is " << final_obj
288 << '.';
289 } else {
290 ADEBUG << "Return status: " << int(status);
291 }
292
293 ptop->get_optimization_results(ptr_theta, ptr_kappa, ptr_dkappa, ptr_s, ptr_x,
294 ptr_y);
295
296 return status == Ipopt::Solve_Succeeded ||
297 status == Ipopt::Solved_To_Acceptable_Level;
298}
299
300std::vector<common::PathPoint> SpiralReferenceLineSmoother::Interpolate(
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;
307 common::PathPoint first_point =
308 to_path_point(x.front(), y.front(), start_s, theta.front(), kappa.front(),
309 dkappa.front());
310 smoothed_point2d.push_back(first_point);
311
312 for (size_t i = 0; i + 1 < theta.size(); ++i) {
313 double start_x = x[i];
314 double start_y = y[i];
315
316 auto path_point_seg = Interpolate(
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);
319
320 smoothed_point2d.insert(smoothed_point2d.end(), path_point_seg.begin(),
321 path_point_seg.end());
322
323 start_s = smoothed_point2d.back().s();
324 }
325 return smoothed_point2d;
326}
327
328std::vector<common::PathPoint> SpiralReferenceLineSmoother::Interpolate(
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;
334
335 const auto angle_diff = common::math::AngleDiff(theta0, theta1);
336
337 QuinticSpiralPath spiral_curve(theta0, kappa0, dkappa0, theta0 + angle_diff,
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);
346
347 const double theta =
348 common::math::NormalizeAngle(spiral_curve.Evaluate(0, inter_s));
349 const double kappa = spiral_curve.Evaluate(1, inter_s);
350 const double dkappa = spiral_curve.Evaluate(2, inter_s);
351
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));
355 }
356 return path_points;
357}
358
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;
363 point.set_x(x);
364 point.set_y(y);
365 point.set_s(s);
366 point.set_theta(theta);
367 point.set_kappa(kappa);
368 point.set_dkappa(dkappa);
369 return point;
370}
371
373 const std::vector<AnchorPoint>& anchor_points) {
374 anchor_points_ = std::move(anchor_points);
375
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();
379
380 std::for_each(anchor_points_.begin(), anchor_points_.end(),
381 [this](AnchorPoint& p) {
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_);
386 });
387}
388
389} // namespace planning
390} // namespace apollo
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
double y() const
Getter for y component
Definition vec2d.h:57
double x() const
Getter for x component
Definition vec2d.h:54
const std::vector< LaneWaypoint > & lane_waypoints() const
Definition path.h:121
Describe a quintic spiral path Map (theta0, kappa0, dkappa0) --— delta_s --—> (theta1,...
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.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
double AngleDiff(const double from, const double to)
Calculate the difference between angle from and to
Definition math_utils.cc:61
double NormalizeAngle(const double angle)
Normalize angle to [-PI, PI).
Definition math_utils.cc:53
class register implement
Definition arena_queue.h:37