Apollo 11.0
自动驾驶开放平台
open_space_trajectory_optimizer.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2019 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
22
23#include <iomanip>
24#include <utility>
25
26namespace apollo {
27namespace planning {
28
32
35 : config_(config) {
36 // Load config
37 AINFO << config_.DebugString();
38 // Initialize hybrid astar class pointer
39 warm_start_.reset(new HybridAStar(config.planner_open_space_config()));
40
41 // Initialize dual variable warm start class pointer
42 dual_variable_warm_start_.reset(
44
45 // Initialize distance approach trajectory smootherclass pointer
46 distance_approach_.reset(
48
49 // Initialize iterative anchoring smoother config class pointer
50 iterative_anchoring_smoother_.reset(
52}
53
55 const std::vector<common::TrajectoryPoint>& stitching_trajectory,
56 const std::vector<double>& end_pose, const std::vector<double>& XYbounds,
57 double rotate_angle, const Vec2d& translate_origin,
58 const Eigen::MatrixXi& obstacles_edges_num,
59 const Eigen::MatrixXd& obstacles_A, const Eigen::MatrixXd& obstacles_b,
60 const std::vector<std::vector<Vec2d>>& obstacles_vertices_vec,
61 double* time_latency) {
62 if (XYbounds.empty() || end_pose.empty() || obstacles_edges_num.cols() == 0 ||
63 obstacles_A.cols() == 0 || obstacles_b.cols() == 0) {
64 ADEBUG << "OpenSpaceTrajectoryOptimizer input data not ready";
65 AERROR << XYbounds.empty() << end_pose.empty() << obstacles_edges_num.cols()
66 << obstacles_A.cols() << obstacles_b.cols();
67 return Status(ErrorCode::PLANNING_ERROR,
68 "OpenSpaceTrajectoryOptimizer input data not ready");
69 }
70 CHECK(!stitching_trajectory.empty());
71 // Generate Stop trajectory if init point close to destination
72 if (IsInitPointNearDestination(stitching_trajectory.back(), end_pose,
73 rotate_angle, translate_origin)) {
74 AINFO << "Planning init point is close to destination, skip new "
75 "trajectory generation";
76 return Status(ErrorCode::OK,
77 "Planning init point is close to destination, skip new "
78 "trajectory generation");
79 }
80
81 const auto start_timestamp = std::chrono::system_clock::now();
82
83 // Initiate initial states
84 stitching_trajectory_ = stitching_trajectory;
85
86 // Init trajectory point is the stitching point from last trajectory
87 const common::TrajectoryPoint trajectory_stitching_point =
88 stitching_trajectory.back();
89
90 // init x, y, z would be rotated.
91 double init_x = trajectory_stitching_point.path_point().x();
92 double init_y = trajectory_stitching_point.path_point().y();
93 double init_phi = trajectory_stitching_point.path_point().theta();
94 AINFO << "origin_point: (" << std::setprecision(9) << translate_origin.x()
95 << "," << translate_origin.y() << ")";
96 AINFO << "origin_heading:" << std::setprecision(9) << rotate_angle << ",";
97 AINFO << "init_point: ( " << std::setprecision(9) << init_x << "," << init_y
98 << ")";
99 AINFO << "end_pose: (" << std::setprecision(9) << end_pose[0] << "," << end_pose[1]
100 << ")";
101
102 // Rotate and scale the state
103 PathPointNormalizing(rotate_angle, translate_origin, &init_x, &init_y,
104 &init_phi);
105
106 // Result container for warm start (initial velocity is assumed to be 0 for
107 // now)
108 HybridAStartResult result;
109
110 if (warm_start_->Plan(init_x, init_y, init_phi, end_pose[0], end_pose[1],
111 end_pose[2], XYbounds, obstacles_vertices_vec,
112 &result)) {
113 AINFO << "State warm start problem solved successfully!";
114 } else {
115 AERROR << "State warm start problem failed to solve";
116 return Status(ErrorCode::PLANNING_ERROR,
117 "State warm start problem failed to solve");
118 }
119
120 // Containers for distance approach trajectory smoothing problem
121 Eigen::MatrixXd xWS;
122 Eigen::MatrixXd uWS;
123 Eigen::MatrixXd state_result_ds;
124 Eigen::MatrixXd control_result_ds;
125 Eigen::MatrixXd time_result_ds;
126 Eigen::MatrixXd l_warm_up;
127 Eigen::MatrixXd n_warm_up;
128 Eigen::MatrixXd dual_l_result_ds;
129 Eigen::MatrixXd dual_n_result_ds;
130
131 if (FLAGS_enable_parallel_trajectory_smoothing) {
132 std::vector<HybridAStartResult> partition_trajectories;
133 if (!warm_start_->TrajectoryPartition(result, &partition_trajectories)) {
134 return Status(ErrorCode::PLANNING_ERROR, "Hybrid Astar partition failed");
135 }
136 size_t size = partition_trajectories.size();
137 std::vector<Eigen::MatrixXd> xWS_vec;
138 std::vector<Eigen::MatrixXd> uWS_vec;
139 std::vector<Eigen::MatrixXd> state_result_ds_vec;
140 std::vector<Eigen::MatrixXd> control_result_ds_vec;
141 std::vector<Eigen::MatrixXd> time_result_ds_vec;
142 std::vector<Eigen::MatrixXd> l_warm_up_vec;
143 std::vector<Eigen::MatrixXd> n_warm_up_vec;
144 std::vector<Eigen::MatrixXd> dual_l_result_ds_vec;
145 std::vector<Eigen::MatrixXd> dual_n_result_ds_vec;
146 xWS_vec.resize(size);
147 uWS_vec.resize(size);
148 state_result_ds_vec.resize(size);
149 control_result_ds_vec.resize(size);
150 time_result_ds_vec.resize(size);
151 l_warm_up_vec.resize(size);
152 n_warm_up_vec.resize(size);
153 dual_l_result_ds_vec.resize(size);
154 dual_n_result_ds_vec.resize(size);
155
156 // In for loop
157 ADEBUG << "Trajectories size in smoother is " << size;
158 for (size_t i = 0; i < size; ++i) {
159 LoadHybridAstarResultInEigen(&partition_trajectories[i], &xWS_vec[i],
160 &uWS_vec[i]);
161 Eigen::MatrixXd last_time_u(2, 1);
162 double init_v = 0.0;
163 // Stitching point control and velocity is set for first piece of
164 // trajectories. In the next ones, control and velocity are assumed to be
165 // zero as the next trajectories always start from vehicle static state
166 if (i == 0) {
167 const double init_steer = trajectory_stitching_point.steer();
168 const double init_a = trajectory_stitching_point.a();
169 last_time_u << init_steer, init_a;
170 init_v = trajectory_stitching_point.v();
171 } else {
172 last_time_u << 0.0, 0.0;
173 init_v = 0.0;
174 }
175 // TODO(Jinyun): Further testing
176 const auto smoother_start_timestamp = std::chrono::system_clock::now();
177 if (FLAGS_use_iterative_anchoring_smoother) {
178 AINFO << "use iterative anchoring smoother";
179 if (!GenerateDecoupledTraj(
180 xWS_vec[i], last_time_u(1, 0), init_v, obstacles_vertices_vec,
181 &state_result_ds_vec[i], &control_result_ds_vec[i],
182 &time_result_ds_vec[i])) {
183 AERROR << "Smoother fail at " << i << "th trajectory";
184 AERROR << i << "th trajectory size is " << xWS_vec[i].cols();
185 return Status(
186 ErrorCode::PLANNING_ERROR,
187 "iterative anchoring smoothing problem failed to solve");
188 }
189 } else {
190 const double start_system_timestamp =
191 std::chrono::duration<double>(
192 std::chrono::system_clock::now().time_since_epoch())
193 .count();
194 AINFO << "use distance approach parallel smoother";
195 if (!GenerateDistanceApproachTraj(
196 xWS_vec[i], uWS_vec[i], XYbounds, obstacles_edges_num,
197 obstacles_A, obstacles_b, obstacles_vertices_vec, last_time_u,
198 init_v, &state_result_ds_vec[i], &control_result_ds_vec[i],
199 &time_result_ds_vec[i], &l_warm_up_vec[i], &n_warm_up_vec[i],
200 &dual_l_result_ds_vec[i], &dual_n_result_ds_vec[i])) {
201 AERROR << "Smoother fail at " << i
202 << "th trajectory with index starts from 0";
203 AERROR << i << "th trajectory size is " << xWS_vec[i].cols();
204 AERROR << "State matrix: " << xWS_vec[i];
205 AERROR << "Control matrix: " << uWS_vec[i];
206 return Status(ErrorCode::PLANNING_ERROR,
207 "distance approach smoothing problem failed to solve");
208 }
209 const auto end_system_timestamp =
210 std::chrono::duration<double>(
211 std::chrono::system_clock::now().time_since_epoch())
212 .count();
213 const auto time_diff_ms =
214 (end_system_timestamp - start_system_timestamp) * 1000;
215 ADEBUG << "total planning time spend: " << time_diff_ms << " ms.";
216 ADEBUG << i << "th trajectory size is " << xWS_vec[i].cols();
217 ADEBUG << "average time spend: " << time_diff_ms / xWS_vec[i].cols()
218 << " ms per point.";
219 ADEBUG << "average time spend after smooth: "
220 << time_diff_ms / state_result_ds_vec[i].cols()
221 << " ms per point.";
222 ADEBUG << i << "th smoothed trajectory size is "
223 << state_result_ds_vec[i].cols();
224 }
225 const auto smoother_end_timestamp = std::chrono::system_clock::now();
226 std::chrono::duration<double> smoother_diff =
227 smoother_end_timestamp - smoother_start_timestamp;
228 AINFO << "Open space trajectory smoothing total time: "
229 << smoother_diff.count() * 1000.0 << " ms at the " << i
230 << "th trajectory.";
231 AINFO << "The " << i << "th trajectory pre-smoothing size is "
232 << xWS_vec[i].cols() << "; post-smoothing size is "
233 << state_result_ds_vec[i].cols();
234 }
235
236 // Retrive the trajectory in one piece
237 CombineTrajectories(xWS_vec, uWS_vec, state_result_ds_vec,
238 control_result_ds_vec, time_result_ds_vec,
239 l_warm_up_vec, n_warm_up_vec, dual_l_result_ds_vec,
240 dual_n_result_ds_vec, &xWS, &uWS, &state_result_ds,
241 &control_result_ds, &time_result_ds, &l_warm_up,
242 &n_warm_up, &dual_l_result_ds, &dual_n_result_ds);
243
244 } else {
245 AINFO << "use distance approach smoother";
246 LoadHybridAstarResultInEigen(&result, &xWS, &uWS);
247
248 const double init_steer = trajectory_stitching_point.steer();
249 const double init_a = trajectory_stitching_point.a();
250 Eigen::MatrixXd last_time_u(2, 1);
251 last_time_u << init_steer, init_a;
252
253 const double init_v = trajectory_stitching_point.v();
254 FLAGS_use_iterative_anchoring_smoother = false;
255 if (!GenerateDistanceApproachTraj(
256 xWS, uWS, XYbounds, obstacles_edges_num, obstacles_A, obstacles_b,
257 obstacles_vertices_vec, last_time_u, init_v, &state_result_ds,
258 &control_result_ds, &time_result_ds, &l_warm_up, &n_warm_up,
259 &dual_l_result_ds, &dual_n_result_ds)) {
260 return Status(ErrorCode::PLANNING_ERROR,
261 "distance approach smoothing problem failed to solve");
262 }
263 }
264
265 // record debug info
266 if (FLAGS_enable_record_debug) {
267 open_space_debug_.Clear();
268 RecordDebugInfo(trajectory_stitching_point, translate_origin, rotate_angle,
269 end_pose, xWS, uWS, l_warm_up, n_warm_up, dual_l_result_ds,
270 dual_n_result_ds, state_result_ds, control_result_ds,
271 time_result_ds, XYbounds, obstacles_vertices_vec);
272 }
273
274 // rescale the states to the world frame
275 size_t state_size = state_result_ds.cols();
276 for (size_t i = 0; i < state_size; ++i) {
277 PathPointDeNormalizing(rotate_angle, translate_origin,
278 &(state_result_ds(0, i)), &(state_result_ds(1, i)),
279 &(state_result_ds(2, i)));
280 }
281
282 LoadTrajectory(state_result_ds, control_result_ds, time_result_ds);
283
284 const auto end_timestamp = std::chrono::system_clock::now();
285 std::chrono::duration<double> diff = end_timestamp - start_timestamp;
286 ADEBUG << "open space trajectory smoother total time: "
287 << diff.count() * 1000.0 << " ms.";
288 *time_latency = diff.count() * 1000.0;
289
290 return Status::OK();
291}
292
294 const common::TrajectoryPoint& trajectory_stitching_point,
295 const Vec2d& translate_origin, const double rotate_angle,
296 const std::vector<double>& end_pose, const Eigen::MatrixXd& xWS,
297 const Eigen::MatrixXd& uWS, const Eigen::MatrixXd& l_warm_up,
298 const Eigen::MatrixXd& n_warm_up, const Eigen::MatrixXd& dual_l_result_ds,
299 const Eigen::MatrixXd& dual_n_result_ds,
300 const Eigen::MatrixXd& state_result_ds,
301 const Eigen::MatrixXd& control_result_ds,
302 const Eigen::MatrixXd& time_result_ds, const std::vector<double>& XYbounds,
303 const std::vector<std::vector<Vec2d>>& obstacles_vertices_vec) {
304 // load information about trajectory stitching point
305
306 open_space_debug_.mutable_trajectory_stitching_point()->CopyFrom(
307 trajectory_stitching_point);
308 // load translation origin and heading angle
309 auto* roi_shift_point = open_space_debug_.mutable_roi_shift_point();
310 // pathpoint
311 roi_shift_point->mutable_path_point()->set_x(translate_origin.x());
312 roi_shift_point->mutable_path_point()->set_y(translate_origin.y());
313 roi_shift_point->mutable_path_point()->set_theta(rotate_angle);
314
315 // load end_pose into debug
316 auto* end_point = open_space_debug_.mutable_end_point();
317 end_point->mutable_path_point()->set_x(end_pose[0]);
318 end_point->mutable_path_point()->set_y(end_pose[1]);
319 end_point->mutable_path_point()->set_theta(end_pose[2]);
320 end_point->set_v(end_pose[3]);
321
322 // load warm start trajectory
323 size_t horizon = xWS.cols() - 1;
324 auto* warm_start_trajectory =
325 open_space_debug_.mutable_warm_start_trajectory();
326 for (size_t i = 0; i < horizon; ++i) {
327 auto* warm_start_point = warm_start_trajectory->add_vehicle_motion_point();
328 warm_start_point->mutable_trajectory_point()->mutable_path_point()->set_x(
329 xWS(0, i));
330 warm_start_point->mutable_trajectory_point()->mutable_path_point()->set_y(
331 xWS(1, i));
332 warm_start_point->mutable_trajectory_point()
333 ->mutable_path_point()
334 ->set_theta(xWS(2, i));
335 warm_start_point->mutable_trajectory_point()->set_v(xWS(3, i));
336 warm_start_point->set_steer(uWS(0, i));
337 warm_start_point->mutable_trajectory_point()->set_a(uWS(1, i));
338 }
339 auto* warm_start_point = warm_start_trajectory->add_vehicle_motion_point();
340 warm_start_point->mutable_trajectory_point()->mutable_path_point()->set_x(
341 xWS(0, horizon));
342 warm_start_point->mutable_trajectory_point()->mutable_path_point()->set_y(
343 xWS(1, horizon));
344 warm_start_point->mutable_trajectory_point()->mutable_path_point()->set_theta(
345 xWS(2, horizon));
346 warm_start_point->mutable_trajectory_point()->set_v(xWS(3, horizon));
347
348 // load warm start dual variables
349 size_t l_warm_up_rows = l_warm_up.rows();
350 for (size_t i = 0; i < horizon; ++i) {
351 for (size_t j = 0; j < l_warm_up_rows; j++) {
352 open_space_debug_.add_warm_start_dual_lambda(l_warm_up(j, i));
353 }
354 }
355 size_t n_warm_up_rows = n_warm_up.rows();
356 for (size_t i = 0; i < horizon; ++i) {
357 for (size_t j = 0; j < n_warm_up_rows; j++) {
358 open_space_debug_.add_warm_start_dual_miu(n_warm_up(j, i));
359 }
360 }
361
362 // load optimized dual variables
363 size_t dual_l_result_ds_rows = dual_l_result_ds.rows();
364 for (size_t i = 0; i < horizon; ++i) {
365 for (size_t j = 0; j < dual_l_result_ds_rows; j++) {
366 open_space_debug_.add_optimized_dual_lambda(dual_l_result_ds(j, i));
367 }
368 }
369 size_t dual_n_result_ds_rows = dual_n_result_ds.rows();
370 for (size_t i = 0; i < horizon; ++i) {
371 for (size_t j = 0; j < dual_n_result_ds_rows; j++) {
372 open_space_debug_.add_optimized_dual_miu(dual_n_result_ds(j, i));
373 }
374 }
375
376 double relative_time = 0;
377
378 // load smoothed trajectory
379 horizon = state_result_ds.cols() - 1;
380 auto* smoothed_trajectory = open_space_debug_.mutable_smoothed_trajectory();
381 for (size_t i = 0; i < horizon; ++i) {
382 auto* smoothed_point = smoothed_trajectory->add_vehicle_motion_point();
383 smoothed_point->mutable_trajectory_point()->mutable_path_point()->set_x(
384 state_result_ds(0, i));
385 smoothed_point->mutable_trajectory_point()->mutable_path_point()->set_y(
386 state_result_ds(1, i));
387 smoothed_point->mutable_trajectory_point()->mutable_path_point()->set_theta(
388 state_result_ds(2, i));
389 smoothed_point->mutable_trajectory_point()->set_v(state_result_ds(3, i));
390 smoothed_point->set_steer(control_result_ds(0, i));
391 smoothed_point->mutable_trajectory_point()->set_a(control_result_ds(1, i));
392 relative_time += time_result_ds(0, i);
393 smoothed_point->mutable_trajectory_point()->set_relative_time(
394 relative_time);
395 }
396 auto* smoothed_point = smoothed_trajectory->add_vehicle_motion_point();
397 smoothed_point->mutable_trajectory_point()->mutable_path_point()->set_x(
398 state_result_ds(0, horizon));
399 smoothed_point->mutable_trajectory_point()->mutable_path_point()->set_y(
400 state_result_ds(1, horizon));
401 smoothed_point->mutable_trajectory_point()->mutable_path_point()->set_theta(
402 state_result_ds(2, horizon));
403 smoothed_point->mutable_trajectory_point()->set_v(
404 state_result_ds(3, horizon));
405
406 // load xy boundary (xmin, xmax, ymin, ymax)
407 open_space_debug_.add_xy_boundary(XYbounds[0]);
408 open_space_debug_.add_xy_boundary(XYbounds[1]);
409 open_space_debug_.add_xy_boundary(XYbounds[2]);
410 open_space_debug_.add_xy_boundary(XYbounds[3]);
411
412 // load obstacles
413 for (const auto& obstacle_vertices : obstacles_vertices_vec) {
414 auto* obstacle_ptr = open_space_debug_.add_obstacles();
415 for (const auto& vertex : obstacle_vertices) {
416 obstacle_ptr->add_vertices_x_coords(vertex.x());
417 obstacle_ptr->add_vertices_y_coords(vertex.y());
418 }
419 }
420}
421
423 planning_internal::OpenSpaceDebug* open_space_debug) {
424 open_space_debug->MergeFrom(open_space_debug_);
425}
426
427bool OpenSpaceTrajectoryOptimizer::IsInitPointNearDestination(
428 const common::TrajectoryPoint& planning_init_point,
429 const std::vector<double>& end_pose, double rotate_angle,
430 const Vec2d& translate_origin) {
431 CHECK_EQ(end_pose.size(), 4U);
432 Vec2d end_pose_to_world_frame = Vec2d(end_pose[0], end_pose[1]);
433
434 end_pose_to_world_frame.SelfRotate(rotate_angle);
435 end_pose_to_world_frame += translate_origin;
436
437 const common::PathPoint path_point = planning_init_point.path_point();
438 double distance_to_init_point =
439 std::sqrt((path_point.x() - end_pose_to_world_frame.x()) *
440 (path_point.x() - end_pose_to_world_frame.x()) +
441 (path_point.y() - end_pose_to_world_frame.y()) *
442 (path_point.y() - end_pose_to_world_frame.y()));
443
444 if (distance_to_init_point <
446 return true;
447 }
448 return false;
449}
450
451void OpenSpaceTrajectoryOptimizer::PathPointNormalizing(
452 double rotate_angle, const Vec2d& translate_origin, double* x, double* y,
453 double* phi) {
454 *x -= translate_origin.x();
455 *y -= translate_origin.y();
456 double tmp_x = *x;
457 *x = (*x) * std::cos(-rotate_angle) - (*y) * std::sin(-rotate_angle);
458 *y = tmp_x * std::sin(-rotate_angle) + (*y) * std::cos(-rotate_angle);
459 *phi = common::math::NormalizeAngle(*phi - rotate_angle);
460}
461
462void OpenSpaceTrajectoryOptimizer::PathPointDeNormalizing(
463 double rotate_angle, const Vec2d& translate_origin, double* x, double* y,
464 double* phi) {
465 double tmp_x = *x;
466 *x = (*x) * std::cos(rotate_angle) - (*y) * std::sin(rotate_angle);
467 *y = tmp_x * std::sin(rotate_angle) + (*y) * std::cos(rotate_angle);
468 *x += translate_origin.x();
469 *y += translate_origin.y();
470 *phi = common::math::NormalizeAngle(*phi + rotate_angle);
471}
472
473void OpenSpaceTrajectoryOptimizer::LoadTrajectory(
474 const Eigen::MatrixXd& state_result, const Eigen::MatrixXd& control_result,
475 const Eigen::MatrixXd& time_result) {
476 optimized_trajectory_.clear();
477
478 // Optimizer doesn't take end condition control state into consideration for
479 // now
480 size_t states_size = state_result.cols();
481 size_t times_size = time_result.cols();
482 size_t controls_size = control_result.cols();
483 CHECK_EQ(states_size, times_size + 1);
484 CHECK_EQ(states_size, controls_size + 1);
485 double relative_time = 0.0;
486 double relative_s = 0.0;
487 Vec2d last_path_point(state_result(0, 0), state_result(1, 0));
488 for (size_t i = 0; i < states_size; ++i) {
489 common::TrajectoryPoint point;
490 point.mutable_path_point()->set_x(state_result(0, i));
491 point.mutable_path_point()->set_y(state_result(1, i));
492 point.mutable_path_point()->set_theta(state_result(2, i));
493 point.set_v(state_result(3, i));
494 Vec2d cur_path_point(state_result(0, i), state_result(1, i));
495 relative_s += cur_path_point.DistanceTo(last_path_point);
496 point.mutable_path_point()->set_s(relative_s);
497 // TODO(Jinyun): Evaluate how to set end states control input
498 if (i == controls_size) {
499 point.set_steer(0.0);
500 point.set_a(0.0);
501 } else {
502 point.set_steer(control_result(0, i));
503 point.set_a(control_result(1, i));
504 }
505
506 if (i == 0) {
507 point.set_relative_time(relative_time);
508 } else {
509 relative_time += time_result(0, i - 1);
510 point.set_relative_time(relative_time);
511 }
512
513 optimized_trajectory_.emplace_back(point);
514 last_path_point = cur_path_point;
515 }
516}
517
518void OpenSpaceTrajectoryOptimizer::UseWarmStartAsResult(
519 const Eigen::MatrixXd& xWS, const Eigen::MatrixXd& uWS,
520 const Eigen::MatrixXd& l_warm_up, const Eigen::MatrixXd& n_warm_up,
521 Eigen::MatrixXd* state_result_ds, Eigen::MatrixXd* control_result_ds,
522 Eigen::MatrixXd* time_result_ds, Eigen::MatrixXd* dual_l_result_ds,
523 Eigen::MatrixXd* dual_n_result_ds) {
524 AERROR << "Use warm start as trajectory output";
525
526 *state_result_ds = xWS;
527 *control_result_ds = uWS;
528 *dual_l_result_ds = l_warm_up;
529 *dual_n_result_ds = n_warm_up;
530
531 size_t time_result_horizon = xWS.cols() - 1;
532 *time_result_ds = Eigen::MatrixXd::Constant(
533 1, time_result_horizon, config_.planner_open_space_config().delta_t());
534}
535
536bool OpenSpaceTrajectoryOptimizer::GenerateDistanceApproachTraj(
537 const Eigen::MatrixXd& xWS, const Eigen::MatrixXd& uWS,
538 const std::vector<double>& XYbounds,
539 const Eigen::MatrixXi& obstacles_edges_num,
540 const Eigen::MatrixXd& obstacles_A, const Eigen::MatrixXd& obstacles_b,
541 const std::vector<std::vector<Vec2d>>& obstacles_vertices_vec,
542 const Eigen::MatrixXd& last_time_u, const double init_v,
543 Eigen::MatrixXd* state_result_ds, Eigen::MatrixXd* control_result_ds,
544 Eigen::MatrixXd* time_result_ds, Eigen::MatrixXd* l_warm_up,
545 Eigen::MatrixXd* n_warm_up, Eigen::MatrixXd* dual_l_result_ds,
546 Eigen::MatrixXd* dual_n_result_ds) {
547 size_t horizon = xWS.cols() - 1;
548 Eigen::MatrixXd x0(4, 1);
549 x0 << xWS(0, 0), xWS(1, 0), xWS(2, 0), init_v;
550
551 Eigen::MatrixXd xF(4, 1);
552 xF << xWS(0, horizon), xWS(1, horizon), xWS(2, horizon), xWS(3, horizon);
553
554 // load vehicle configuration
555 const common::VehicleParam& vehicle_param_ =
557 double front_to_center = vehicle_param_.front_edge_to_center();
558 double back_to_center = vehicle_param_.back_edge_to_center();
559 double left_to_center = vehicle_param_.left_edge_to_center();
560 double right_to_center = vehicle_param_.right_edge_to_center();
561 Eigen::MatrixXd ego(4, 1);
562 ego << front_to_center, right_to_center, back_to_center, left_to_center;
563
564 // Get obstacle num
565 size_t obstacles_num = obstacles_vertices_vec.size();
566
567 // Get timestep delta t
568 double ts = config_.planner_open_space_config().delta_t();
569
570 // slack_warm_up, temp usage
571 Eigen::MatrixXd s_warm_up = Eigen::MatrixXd::Zero(obstacles_num, horizon + 1);
572
573 // Dual variable warm start for distance approach problem
574 if (FLAGS_use_dual_variable_warm_start) {
575 if (dual_variable_warm_start_->Solve(
576 horizon, ts, ego, obstacles_num, obstacles_edges_num, obstacles_A,
577 obstacles_b, xWS, l_warm_up, n_warm_up, &s_warm_up)) {
578 ADEBUG << "Dual variable problem solved successfully!";
579 } else {
580 AERROR << "Dual variable problem failed to solve";
581 return false;
582 }
583 } else {
584 *l_warm_up =
585 0.5 * Eigen::MatrixXd::Ones(obstacles_edges_num.sum(), horizon + 1);
586 *n_warm_up = 0.5 * Eigen::MatrixXd::Ones(4 * obstacles_num, horizon + 1);
587 }
588
589 // Distance approach trajectory smoothing
590 if (distance_approach_->Solve(
591 x0, xF, last_time_u, horizon, ts, ego, xWS, uWS, *l_warm_up,
592 *n_warm_up, s_warm_up, XYbounds, obstacles_num, obstacles_edges_num,
593 obstacles_A, obstacles_b, state_result_ds, control_result_ds,
594 time_result_ds, dual_l_result_ds, dual_n_result_ds)) {
595 ADEBUG << "Distance approach problem solved successfully!";
596 } else {
597 AERROR << "Distance approach problem failed to solve";
598 if (FLAGS_enable_smoother_failsafe) {
599 UseWarmStartAsResult(xWS, uWS, *l_warm_up, *n_warm_up, state_result_ds,
600 control_result_ds, time_result_ds, dual_l_result_ds,
601 dual_n_result_ds);
602 } else {
603 return false;
604 }
605 }
606 return true;
607}
608
609// TODO(Jinyun): deprecate the use of Eigen in trajectory smoothing
610void OpenSpaceTrajectoryOptimizer::LoadHybridAstarResultInEigen(
611 HybridAStartResult* result, Eigen::MatrixXd* xWS, Eigen::MatrixXd* uWS) {
612 // load Warm Start result(horizon is timestep number minus one)
613 size_t horizon = result->x.size() - 1;
614 xWS->resize(4, horizon + 1);
615 uWS->resize(2, horizon);
616 Eigen::VectorXd x = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(
617 result->x.data(), horizon + 1);
618 Eigen::VectorXd y = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(
619 result->y.data(), horizon + 1);
620 Eigen::VectorXd phi = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(
621 result->phi.data(), horizon + 1);
622 Eigen::VectorXd v = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(
623 result->v.data(), horizon + 1);
624 Eigen::VectorXd steer = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(
625 result->steer.data(), horizon);
626 Eigen::VectorXd a =
627 Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(result->a.data(), horizon);
628 xWS->row(0) = std::move(x);
629 xWS->row(1) = std::move(y);
630 xWS->row(2) = std::move(phi);
631 xWS->row(3) = std::move(v);
632 uWS->row(0) = std::move(steer);
633 uWS->row(1) = std::move(a);
634}
635
636void OpenSpaceTrajectoryOptimizer::CombineTrajectories(
637 const std::vector<Eigen::MatrixXd>& xWS_vec,
638 const std::vector<Eigen::MatrixXd>& uWS_vec,
639 const std::vector<Eigen::MatrixXd>& state_result_ds_vec,
640 const std::vector<Eigen::MatrixXd>& control_result_ds_vec,
641 const std::vector<Eigen::MatrixXd>& time_result_ds_vec,
642 const std::vector<Eigen::MatrixXd>& l_warm_up_vec,
643 const std::vector<Eigen::MatrixXd>& n_warm_up_vec,
644 const std::vector<Eigen::MatrixXd>& dual_l_result_ds_vec,
645 const std::vector<Eigen::MatrixXd>& dual_n_result_ds_vec,
646 Eigen::MatrixXd* xWS, Eigen::MatrixXd* uWS,
647 Eigen::MatrixXd* state_result_ds, Eigen::MatrixXd* control_result_ds,
648 Eigen::MatrixXd* time_result_ds, Eigen::MatrixXd* l_warm_up,
649 Eigen::MatrixXd* n_warm_up, Eigen::MatrixXd* dual_l_result_ds,
650 Eigen::MatrixXd* dual_n_result_ds) {
651 // Repeated midway state point are not added
652 size_t warm_start_state_size = 0;
653 for (const auto& warm_start_state : xWS_vec) {
654 warm_start_state_size += warm_start_state.cols();
655 }
656 warm_start_state_size -= xWS_vec.size() - 1;
657
658 size_t warm_start_control_size = 0;
659 for (const auto& warm_start_control : uWS_vec) {
660 warm_start_control_size += warm_start_control.cols();
661 }
662
663 // Repeated midway state point are not added
664 size_t smoothed_state_size = 0;
665 for (const auto& smoothed_state : state_result_ds_vec) {
666 smoothed_state_size += smoothed_state.cols();
667 }
668 smoothed_state_size -= state_result_ds_vec.size() - 1;
669
670 size_t smoothed_control_size = 0;
671 for (const auto& smoothed_control : control_result_ds_vec) {
672 smoothed_control_size += smoothed_control.cols();
673 }
674
675 size_t time_size = 0;
676 for (const auto& smoothed_time : time_result_ds_vec) {
677 time_size += smoothed_time.cols();
678 }
679
680 size_t l_warm_start_size = 0;
681 for (const auto& l_warm_start : l_warm_up_vec) {
682 l_warm_start_size += l_warm_start.cols();
683 }
684
685 size_t n_warm_start_size = 0;
686 for (const auto& n_warm_start : n_warm_up_vec) {
687 n_warm_start_size += n_warm_start.cols();
688 }
689
690 size_t l_smoothed_size = 0;
691 for (const auto& l_smoothed : dual_l_result_ds_vec) {
692 l_smoothed_size += l_smoothed.cols();
693 }
694
695 size_t n_smoothed_size = 0;
696 for (const auto& n_smoothed : dual_n_result_ds_vec) {
697 n_smoothed_size += n_smoothed.cols();
698 }
699
700 Eigen::MatrixXd xWS_ =
701 Eigen::MatrixXd::Zero(xWS_vec[0].rows(), warm_start_state_size);
702 Eigen::MatrixXd uWS_ =
703 Eigen::MatrixXd::Zero(uWS_vec[0].rows(), warm_start_control_size);
704 Eigen::MatrixXd state_result_ds_ =
705 Eigen::MatrixXd::Zero(state_result_ds_vec[0].rows(), smoothed_state_size);
706 Eigen::MatrixXd control_result_ds_ = Eigen::MatrixXd::Zero(
707 control_result_ds_vec[0].rows(), smoothed_control_size);
708 Eigen::MatrixXd time_result_ds_ =
709 Eigen::MatrixXd::Zero(time_result_ds_vec[0].rows(), time_size);
710 Eigen::MatrixXd l_warm_up_ =
711 Eigen::MatrixXd::Zero(l_warm_up_vec[0].rows(), l_warm_start_size);
712 Eigen::MatrixXd n_warm_up_ =
713 Eigen::MatrixXd::Zero(n_warm_up_vec[0].rows(), n_warm_start_size);
714 Eigen::MatrixXd dual_l_result_ds_ =
715 Eigen::MatrixXd::Zero(dual_l_result_ds_vec[0].rows(), l_smoothed_size);
716 Eigen::MatrixXd dual_n_result_ds_ =
717 Eigen::MatrixXd::Zero(dual_n_result_ds_vec[0].rows(), n_smoothed_size);
718
719 size_t traj_size = xWS_vec.size();
720
721 uint64_t counter = 0;
722 for (size_t i = 0; i < traj_size; ++i) {
723 // leave out the last repeated point so set column minus one
724 uint64_t warm_start_state_cols = xWS_vec[i].cols() - 1;
725 for (size_t j = 0; j < warm_start_state_cols; ++j) {
726 xWS_.col(counter) = xWS_vec[i].col(j);
727 ++counter;
728 }
729 }
730 xWS_.col(counter) = xWS_vec.back().col(xWS_vec.back().cols() - 1);
731 ++counter;
732 CHECK_EQ(counter, warm_start_state_size);
733
734 counter = 0;
735 for (size_t i = 0; i < traj_size; ++i) {
736 // leave out the last repeated point so set column minus one
737 uint64_t warm_start_control_cols = uWS_vec[i].cols();
738 for (size_t j = 0; j < warm_start_control_cols; ++j) {
739 uWS_.col(counter) = uWS_vec[i].col(j);
740 ++counter;
741 }
742 }
743 CHECK_EQ(counter, warm_start_control_size);
744
745 counter = 0;
746 for (size_t i = 0; i < traj_size; ++i) {
747 // leave out the last repeated point so set column minus one
748 uint64_t smoothed_state_cols = state_result_ds_vec[i].cols() - 1;
749 for (size_t j = 0; j < smoothed_state_cols; ++j) {
750 state_result_ds_.col(counter) = state_result_ds_vec[i].col(j);
751 ++counter;
752 }
753 }
754 state_result_ds_.col(counter) =
755 state_result_ds_vec.back().col(state_result_ds_vec.back().cols() - 1);
756 ++counter;
757 CHECK_EQ(counter, smoothed_state_size);
758
759 counter = 0;
760 for (size_t i = 0; i < traj_size; ++i) {
761 // leave out the last repeated point so set column minus one
762 uint64_t smoothed_control_cols = control_result_ds_vec[i].cols();
763 for (size_t j = 0; j < smoothed_control_cols; ++j) {
764 control_result_ds_.col(counter) = control_result_ds_vec[i].col(j);
765 ++counter;
766 }
767 }
768 CHECK_EQ(counter, smoothed_control_size);
769
770 counter = 0;
771 for (size_t i = 0; i < traj_size; ++i) {
772 // leave out the last repeated point so set column minus one
773 uint64_t time_cols = time_result_ds_vec[i].cols();
774 for (size_t j = 0; j < time_cols; ++j) {
775 time_result_ds_.col(counter) = time_result_ds_vec[i].col(j);
776 ++counter;
777 }
778 }
779 CHECK_EQ(counter, time_size);
780
781 counter = 0;
782 for (size_t i = 0; i < traj_size; ++i) {
783 // leave out the last repeated point so set column minus one
784 uint64_t l_warm_up_cols = l_warm_up_vec[i].cols();
785 for (size_t j = 0; j < l_warm_up_cols; ++j) {
786 l_warm_up_.col(counter) = l_warm_up_vec[i].col(j);
787 ++counter;
788 }
789 }
790 CHECK_EQ(counter, l_warm_start_size);
791
792 counter = 0;
793 for (size_t i = 0; i < traj_size; ++i) {
794 // leave out the last repeated point so set column minus one
795 uint64_t n_warm_up_cols = n_warm_up_vec[i].cols();
796 for (size_t j = 0; j < n_warm_up_cols; ++j) {
797 n_warm_up_.col(counter) = n_warm_up_vec[i].col(j);
798 ++counter;
799 }
800 }
801 CHECK_EQ(counter, n_warm_start_size);
802
803 counter = 0;
804 for (size_t i = 0; i < traj_size; ++i) {
805 // leave out the last repeated point so set column minus one
806 uint64_t dual_l_result_ds_cols = dual_l_result_ds_vec[i].cols();
807 for (size_t j = 0; j < dual_l_result_ds_cols; ++j) {
808 dual_l_result_ds_.col(counter) = dual_l_result_ds_vec[i].col(j);
809 ++counter;
810 }
811 }
812 CHECK_EQ(counter, l_smoothed_size);
813
814 counter = 0;
815 for (size_t i = 0; i < traj_size; ++i) {
816 // leave out the last repeated point so set column minus one
817 uint64_t dual_n_result_ds_cols = dual_n_result_ds_vec[i].cols();
818 for (size_t j = 0; j < dual_n_result_ds_cols; ++j) {
819 dual_n_result_ds_.col(counter) = dual_n_result_ds_vec[i].col(j);
820 ++counter;
821 }
822 }
823 CHECK_EQ(counter, n_smoothed_size);
824
825 *xWS = std::move(xWS_);
826 *uWS = std::move(uWS_);
827 *state_result_ds = std::move(state_result_ds_);
828 *control_result_ds = std::move(control_result_ds_);
829 *time_result_ds = std::move(time_result_ds_);
830 *l_warm_up = std::move(l_warm_up_);
831 *n_warm_up = std::move(n_warm_up_);
832 *dual_l_result_ds = std::move(dual_l_result_ds_);
833 *dual_n_result_ds = std::move(dual_n_result_ds_);
834}
835
836bool OpenSpaceTrajectoryOptimizer::GenerateDecoupledTraj(
837 const Eigen::MatrixXd& xWS, const double init_a, const double init_v,
838 const std::vector<std::vector<Vec2d>>& obstacles_vertices_vec,
839 Eigen::MatrixXd* state_result_dc, Eigen::MatrixXd* control_result_dc,
840 Eigen::MatrixXd* time_result_dc) {
841 DiscretizedTrajectory smoothed_trajectory;
842 if (!iterative_anchoring_smoother_->Smooth(
843 xWS, init_a, init_v, obstacles_vertices_vec, &smoothed_trajectory)) {
844 return false;
845 }
846
847 LoadResult(smoothed_trajectory, state_result_dc, control_result_dc,
848 time_result_dc);
849 return true;
850}
851
852// TODO(Jinyun): tmp interface, will refactor
853void OpenSpaceTrajectoryOptimizer::LoadResult(
854 const DiscretizedTrajectory& discretized_trajectory,
855 Eigen::MatrixXd* state_result_dc, Eigen::MatrixXd* control_result_dc,
856 Eigen::MatrixXd* time_result_dc) {
857 const size_t points_size = discretized_trajectory.size();
858 CHECK_GT(points_size, 1U);
859 *state_result_dc = Eigen::MatrixXd::Zero(4, points_size);
860 *control_result_dc = Eigen::MatrixXd::Zero(2, points_size - 1);
861 *time_result_dc = Eigen::MatrixXd::Zero(1, points_size - 1);
862
863 auto& state_result = *state_result_dc;
864 for (size_t i = 0; i < points_size; ++i) {
865 state_result(0, i) = discretized_trajectory[i].path_point().x();
866 state_result(1, i) = discretized_trajectory[i].path_point().y();
867 state_result(2, i) = discretized_trajectory[i].path_point().theta();
868 state_result(3, i) = discretized_trajectory[i].v();
869 }
870
871 auto& control_result = *control_result_dc;
872 auto& time_result = *time_result_dc;
873 const double wheel_base = common::VehicleConfigHelper::Instance()
874 ->GetConfig()
875 .vehicle_param()
876 .wheel_base();
877 for (size_t i = 0; i + 1 < points_size; ++i) {
878 control_result(0, i) =
879 std::atan(discretized_trajectory[i].path_point().kappa() * wheel_base);
880 control_result(1, i) = discretized_trajectory[i].a();
881 time_result(0, i) = discretized_trajectory[i + 1].relative_time() -
882 discretized_trajectory[i].relative_time();
883 }
884}
885
886} // namespace planning
887} // namespace apollo
A general class to denote the return status of an API call.
Definition status.h:43
static Status OK()
generate a success status.
Definition status.h:60
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
void SelfRotate(const double angle)
rotate the vector itself by angle.
Definition vec2d.cc:70
double y() const
Getter for y component
Definition vec2d.h:57
double x() const
Getter for x component
Definition vec2d.h:54
common::Status Plan(const std::vector< common::TrajectoryPoint > &stitching_trajectory, const std::vector< double > &end_pose, const std::vector< double > &XYbounds, double rotate_angle, const common::math::Vec2d &translate_origin, const Eigen::MatrixXi &obstacles_edges_num, const Eigen::MatrixXd &obstacles_A, const Eigen::MatrixXd &obstacles_b, const std::vector< std::vector< common::math::Vec2d > > &obstacles_vertices_vec, double *time_latency)
OpenSpaceTrajectoryOptimizer(const OpenSpaceTrajectoryOptimizerConfig &config)
void UpdateDebugInfo(::apollo::planning_internal::OpenSpaceDebug *open_space_debug)
void RecordDebugInfo(const common::TrajectoryPoint &trajectory_stitching_point, const common::math::Vec2d &translate_origin, const double rotate_angle, const std::vector< double > &end_pose, const Eigen::MatrixXd &xWS, const Eigen::MatrixXd &uWs, const Eigen::MatrixXd &l_warm_up, const Eigen::MatrixXd &n_warm_up, const Eigen::MatrixXd &dual_l_result_ds, const Eigen::MatrixXd &dual_n_result_ds, const Eigen::MatrixXd &state_result_ds, const Eigen::MatrixXd &control_result_ds, const Eigen::MatrixXd &time_result_ds, const std::vector< double > &XYbounds, const std::vector< std::vector< common::math::Vec2d > > &obstacles_vertices_vec)
Planning module main class.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
double NormalizeAngle(const double angle)
Normalize angle to [-PI, PI).
Definition math_utils.cc:53
class register implement
Definition arena_queue.h:37
optional VehicleParam vehicle_param