Apollo 11.0
自动驾驶开放平台
open_space_trajectory_provider.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 <memory>
24#include <string>
25
26#include "modules/common/vehicle_state/proto/vehicle_state.pb.h"
27
28#include "cyber/task/task.h"
33
34namespace apollo {
35namespace planning {
36
42
44 const std::string& config_dir, const std::string& name,
45 const std::shared_ptr<DependencyInjector>& injector) {
46 if (!Task::Init(config_dir, name, injector)) {
47 return false;
48 }
49 // Load the config this task.
50 if (!Task::LoadConfig<OpenSpaceTrajectoryProviderConfig>(&config_)) {
51 return false;
52 }
53 straight_trajectory_length_ = config_.open_space_straight_trajectory_length();
54 open_space_trajectory_optimizer_.reset(new OpenSpaceTrajectoryOptimizer(
56 return true;
57}
58
64
67 is_generation_thread_stop_.store(true);
68 if (thread_init_flag_) {
69 task_future_.get();
70 }
71 trajectory_updated_.store(false);
72 trajectory_error_.store(false);
73 trajectory_skipped_.store(false);
74 optimizer_thread_counter = 0;
75 last_trajctory_point.Clear();
76 }
77}
78
81 is_generation_thread_stop_.store(true);
82 if (thread_init_flag_) {
83 task_future_.get();
84 }
85 is_generation_thread_stop_.store(false);
86 thread_init_flag_ = false;
87 trajectory_updated_.store(false);
88 trajectory_error_.store(false);
89 trajectory_skipped_.store(false);
90 optimizer_thread_counter = 0;
91 is_planned_ = false;
92 }
93}
94
95Status OpenSpaceTrajectoryProvider::Process() {
96 ADEBUG << "trajectory provider";
97 auto trajectory_data =
99
100 // generate stop trajectory at park_and_go check_stage
101 if (injector_->planning_context()
102 ->mutable_planning_status()
103 ->mutable_park_and_go()
104 ->in_check_stage()) {
105 ADEBUG << "ParkAndGo Stage Check.";
106 GenerateStopTrajectory(trajectory_data);
107 return Status::OK();
108 }
109
110 // when in zone cover stage, should change end pose
111 if (FLAGS_change_end_pose) {
112 AINFO << "Restart OpenSpaceTrajectoryProvider!";
113 FLAGS_calculate_next_trajectory = true;
114 Restart();
115 }
116
117 // Start thread when getting in Process() for the first time
118 if (config_.enable_open_space_planner_thread() && !thread_init_flag_) {
119 task_future_ = cyber::Async(
120 &OpenSpaceTrajectoryProvider::GenerateTrajectoryThread, this);
121 thread_init_flag_ = true;
122 }
123 bool need_replan = false;
124 // Get stitching trajectory from last frame
125 const common::VehicleState vehicle_state = frame_->vehicle_state();
126 auto* previous_frame = injector_->frame_history()->Latest();
127 // Use complete raw trajectory from last frame for stitching purpose
128 std::vector<TrajectoryPoint> stitching_trajectory;
129 bool is_stop_due_to_fallback = false;
130 if (previous_frame &&
131 IsVehicleStopDueToFallBack(
132 previous_frame->open_space_info().fallback_flag(), vehicle_state)) {
133 is_stop_due_to_fallback = true;
134 }
135 if (!is_planned_ || is_stop_due_to_fallback) {
136 AINFO << "need to fallback: is_planned" << is_planned_
137 << "is_stop_due_to_fallback" << is_stop_due_to_fallback;
138 const double planning_cycle_time =
139 1.0 / static_cast<double>(FLAGS_planning_loop_rate);
141 planning_cycle_time, vehicle_state);
142 if (FLAGS_calculate_next_trajectory &&
143 last_trajctory_point.has_path_point() && !is_stop_due_to_fallback) {
144 last_trajctory_point.mutable_path_point()->set_s(0.0);
145 last_trajctory_point.set_v(0.1);
146 last_trajctory_point.set_relative_time(0.1);
147 stitching_trajectory =
148 std::vector<TrajectoryPoint>(1, last_trajctory_point);
149 }
150 for (auto& trajectorypoint : stitching_trajectory) {
151 AINFO << "stitching_trajectory: " << trajectorypoint.DebugString();
152 }
153 need_replan = true;
154 injector_->planning_context()
155 ->mutable_planning_status()
156 ->mutable_open_space()
157 ->set_position_init(false);
159 }
160 // Get open_space_info from current frame
161 const auto& open_space_info = frame_->open_space_info();
162
163 if (config_.enable_open_space_planner_thread()) {
164 ADEBUG << "Open space plan in multi-threads mode";
165
166 if (is_generation_thread_stop_) {
167 GenerateStopTrajectory(trajectory_data);
168 return Status(ErrorCode::OK, "Parking finished");
169 }
170
171 if (need_replan) {
172 std::vector<double> temp_target =
174 if (open_space_info.target_parking_spot_id() != "") {
175 double angle = open_space_info.open_space_end_pose()[2];
176 temp_target[0] = straight_trajectory_length_ * cos(angle) +
177 open_space_info.open_space_end_pose()[0];
178 temp_target[1] = straight_trajectory_length_ * sin(angle) +
179 open_space_info.open_space_end_pose()[1];
180 }
181 std::lock_guard<std::mutex> lock(open_space_mutex_);
182 thread_data_.stitching_trajectory = stitching_trajectory;
183 thread_data_.end_pose = temp_target;
184 thread_data_.rotate_angle = open_space_info.origin_heading();
185 thread_data_.translate_origin = open_space_info.origin_point();
186 thread_data_.obstacles_edges_num = open_space_info.obstacles_edges_num();
187 thread_data_.obstacles_A = open_space_info.obstacles_A();
188 thread_data_.obstacles_b = open_space_info.obstacles_b();
189 thread_data_.obstacles_vertices_vec =
190 open_space_info.obstacles_vertices_vec();
191 thread_data_.XYbounds = open_space_info.ROI_xy_boundary();
192 data_ready_.store(true);
193 is_planned_ = true;
194 } else {
195 std::lock_guard<std::mutex> lock(open_space_mutex_);
196 data_ready_.store(false);
197 }
198
199 // Check vehicle state
200 if (IsVehicleNearDestination(
201 vehicle_state, open_space_info.open_space_end_pose(),
202 open_space_info.origin_heading(), open_space_info.origin_point())) {
203 GenerateStopTrajectory(trajectory_data);
204 // is_generation_thread_stop_.store(true);
205 AINFO << "Vehicle is near to destination";
206 return Status(ErrorCode::OK, "Vehicle is near to destination");
207 }
208
209 // Check if trajectory updated
210 if (trajectory_updated_) {
211 std::lock_guard<std::mutex> lock(open_space_mutex_);
212 LoadResult(trajectory_data);
213 if (FLAGS_enable_record_debug) {
214 // call merge debug ptr, open_space_trajectory_optimizer_
215 auto* ptr_debug = frame_->mutable_open_space_info()->mutable_debug();
216 open_space_trajectory_optimizer_->UpdateDebugInfo(
217 ptr_debug->mutable_planning_data()->mutable_open_space());
218
219 // sync debug instance
221 }
222 AINFO << "Trajectory Update" << trajectory_data->size();
223 data_ready_.store(false);
224 trajectory_updated_.store(false);
225 return Status::OK();
226 }
227
228 if (trajectory_error_) {
229 AINFO << "error";
230 ++optimizer_thread_counter;
231 std::lock_guard<std::mutex> lock(open_space_mutex_);
232 trajectory_error_.store(false);
233 // TODO(Jinyun) Use other fallback mechanism when last iteration smoothing
234 // result has out of bound pathpoint which is not allowed for next
235 // iteration hybrid astar algorithm which requires start position to be
236 // strictly in bound
237 if (optimizer_thread_counter > 1000) {
238 return Status(ErrorCode::PLANNING_ERROR,
239 "open_space_optimizer failed too many times");
240 }
241 }
242
243 if (previous_frame &&
244 previous_frame->open_space_info().open_space_provider_success() &&
245 !need_replan) {
246 ReuseLastFrameResult(previous_frame, trajectory_data);
247 if (FLAGS_enable_record_debug) {
248 // copy previous debug to current frame
249 ReuseLastFrameDebug(previous_frame);
250 }
251 // reuse last frame debug when use last frame traj
252 AINFO << "ReuseLastFrameResult";
253 return Status(ErrorCode::OK,
254 "Waiting for open_space_trajectory_optimizer in "
255 "open_space_trajectory_provider");
256 } else {
257 AINFO << "Stop due to computation not finished";
258 if (previous_frame && !previous_frame->open_space_info()
259 .stitched_trajectory_result()
260 .empty()) {
261 *(trajectory_data) =
262 previous_frame->open_space_info().stitched_trajectory_result();
263 } else {
264 GenerateStopTrajectory(trajectory_data);
265 }
266 return Status(ErrorCode::OK, "Stop due to computation not finished");
267 }
268 } else {
269 const auto& end_pose = open_space_info.open_space_end_pose();
270 const auto& rotate_angle = open_space_info.origin_heading();
271 const auto& translate_origin = open_space_info.origin_point();
272 const auto& obstacles_edges_num = open_space_info.obstacles_edges_num();
273 const auto& obstacles_A = open_space_info.obstacles_A();
274 const auto& obstacles_b = open_space_info.obstacles_b();
275 const auto& obstacles_vertices_vec =
276 open_space_info.obstacles_vertices_vec();
277 const auto& XYbounds = open_space_info.ROI_xy_boundary();
278
279 // Check vehicle state
280 if (IsVehicleNearDestination(vehicle_state, end_pose, rotate_angle,
281 translate_origin)) {
282 GenerateStopTrajectory(trajectory_data);
283 return Status(ErrorCode::OK, "Vehicle is near to destination");
284 }
285
286 // Generate Trajectory;
287 double time_latency;
288 Status status = open_space_trajectory_optimizer_->Plan(
289 stitching_trajectory, end_pose, XYbounds, rotate_angle,
290 translate_origin, obstacles_edges_num, obstacles_A, obstacles_b,
291 obstacles_vertices_vec, &time_latency);
293
294 // If status is OK, update vehicle trajectory;
295 if (status == Status::OK()) {
296 LoadResult(trajectory_data);
297 return status;
298 } else {
299 return status;
300 }
301 }
302 return Status(ErrorCode::PLANNING_ERROR);
303}
304
305void OpenSpaceTrajectoryProvider::GenerateTrajectoryThread() {
306 while (!is_generation_thread_stop_) {
307 if (!trajectory_updated_ && data_ready_) {
308 OpenSpaceTrajectoryThreadData thread_data;
309 {
310 std::lock_guard<std::mutex> lock(open_space_mutex_);
311 thread_data = thread_data_;
312 }
313 double time_latency;
314 Status status = open_space_trajectory_optimizer_->Plan(
315 thread_data.stitching_trajectory, thread_data.end_pose,
316 thread_data.XYbounds, thread_data.rotate_angle,
317 thread_data.translate_origin, thread_data.obstacles_edges_num,
318 thread_data.obstacles_A, thread_data.obstacles_b,
319 thread_data.obstacles_vertices_vec, &time_latency);
321 if (status == Status::OK()) {
322 std::lock_guard<std::mutex> lock(open_space_mutex_);
323 trajectory_updated_.store(true);
324 } else {
325 if (status.ok()) {
326 std::lock_guard<std::mutex> lock(open_space_mutex_);
327 trajectory_skipped_.store(true);
328 } else {
329 std::lock_guard<std::mutex> lock(open_space_mutex_);
330 trajectory_error_.store(true);
331 }
332 }
333 }
334 }
335}
336
337bool OpenSpaceTrajectoryProvider::IsVehicleNearDestination(
338 const common::VehicleState& vehicle_state,
339 const std::vector<double>& end_pose, double rotate_angle,
340 const Vec2d& translate_origin) {
341 CHECK_EQ(end_pose.size(), 4U);
342 Vec2d end_pose_to_world_frame = Vec2d(end_pose[0], end_pose[1]);
343
344 end_pose_to_world_frame.SelfRotate(rotate_angle);
345 end_pose_to_world_frame += translate_origin;
346
347 double end_theta_to_world_frame = end_pose[2];
348 end_theta_to_world_frame += rotate_angle;
349 const double max_adc_stop_speed = common::VehicleConfigHelper::Instance()
350 ->GetConfig()
351 .vehicle_param()
352 .max_abs_speed_when_stopped();
353 if (std::fabs(vehicle_state.linear_velocity()) > max_adc_stop_speed) {
354 return false;
355 }
356 double distance_to_vehicle =
357 std::sqrt((vehicle_state.x() - end_pose_to_world_frame.x()) *
358 (vehicle_state.x() - end_pose_to_world_frame.x()) +
359 (vehicle_state.y() - end_pose_to_world_frame.y()) *
360 (vehicle_state.y() - end_pose_to_world_frame.y()));
361
362 double theta_to_vehicle = std::abs(common::math::AngleDiff(
363 vehicle_state.heading(), end_theta_to_world_frame));
364 ADEBUG << "theta_to_vehicle" << theta_to_vehicle << "end_theta_to_world_frame"
365 << end_theta_to_world_frame << "rotate_angle" << rotate_angle;
366 ADEBUG << "near_destination_threshold"
369 .near_destination_threshold(); // which config file
370 ADEBUG << "is_near_destination_theta_threshold"
374 if (distance_to_vehicle < config_.open_space_trajectory_optimizer_config()
377 theta_to_vehicle < config_.open_space_trajectory_optimizer_config()
380 ADEBUG << "vehicle reach end_pose";
383 return true;
384 }
385 return false;
386}
387
388bool OpenSpaceTrajectoryProvider::IsVehicleStopDueToFallBack(
389 const bool is_on_fallback, const common::VehicleState& vehicle_state) {
390 if (!is_on_fallback) {
391 return false;
392 }
393 static constexpr double kEpsilon = 1.0e-1;
394 const double adc_speed = vehicle_state.linear_velocity();
395 if (std::abs(adc_speed) < kEpsilon) {
396 AINFO << "ADC stops due to fallback trajectory";
397 return true;
398 }
399 AINFO << "set fallback but adc not stop" << adc_speed;
400 return false;
401}
402
403void OpenSpaceTrajectoryProvider::GenerateStopTrajectory(
404 DiscretizedTrajectory* const trajectory_data) {
405 double relative_time = 0.0;
406 // TODO(Jinyun) Move to conf
407 static constexpr int stop_trajectory_length = 10;
408 static constexpr double relative_stop_time = 0.1;
409 static constexpr double vEpsilon = 0.00001;
410 double standstill_acceleration =
411 frame_->vehicle_state().linear_velocity() >= -vEpsilon
414 trajectory_data->clear();
415 for (size_t i = 0; i < stop_trajectory_length; i++) {
416 TrajectoryPoint point;
417 point.mutable_path_point()->set_x(frame_->vehicle_state().x());
418 point.mutable_path_point()->set_y(frame_->vehicle_state().y());
419 point.mutable_path_point()->set_theta(frame_->vehicle_state().heading());
420 point.mutable_path_point()->set_s(0.0);
421 point.mutable_path_point()->set_kappa(0.0);
422 point.set_relative_time(relative_time);
423 point.set_v(0.0);
424 point.set_a(standstill_acceleration);
425 trajectory_data->emplace_back(point);
426 relative_time += relative_stop_time;
427 }
428}
429
430void OpenSpaceTrajectoryProvider::LoadResult(
431 DiscretizedTrajectory* const trajectory_data) {
432 // Load unstitched two trajectories into frame for debug
433 trajectory_data->clear();
434 auto optimizer_trajectory_ptr =
436 auto stitching_trajectory_ptr =
438 open_space_trajectory_optimizer_->GetOptimizedTrajectory(
439 optimizer_trajectory_ptr);
440 open_space_trajectory_optimizer_->GetStitchingTrajectory(
441 stitching_trajectory_ptr);
442 // Stitch two trajectories and load back to trajectory_data from frame
443 size_t optimizer_trajectory_size = optimizer_trajectory_ptr->size();
444 double stitching_point_relative_time =
445 stitching_trajectory_ptr->back().relative_time();
446 double stitching_point_relative_s =
447 stitching_trajectory_ptr->back().path_point().s();
448 for (size_t i = 0; i < optimizer_trajectory_size; ++i) {
449 optimizer_trajectory_ptr->at(i).set_relative_time(
450 optimizer_trajectory_ptr->at(i).relative_time() +
451 stitching_point_relative_time);
452 optimizer_trajectory_ptr->at(i).mutable_path_point()->set_s(
453 optimizer_trajectory_ptr->at(i).path_point().s() +
454 stitching_point_relative_s);
455 }
456
458 double distance = straight_trajectory_length_;
459 double v = 0.3;
460 double t = distance / v * 2;
461 double a = v / t;
462 double start_x = optimizer_trajectory_ptr->back().path_point().x();
463 double start_y = optimizer_trajectory_ptr->back().path_point().y();
464 double start_time = optimizer_trajectory_ptr->back().relative_time();
465 std::vector<double> end_pose =
467 double unit_x = -cos(optimizer_trajectory_ptr->back().path_point().theta());
468 double unit_y = -sin(optimizer_trajectory_ptr->back().path_point().theta());
469 for (size_t i = 1; i <= t / 0.1; i++) {
470 double x = 0, y = 0, v_now = 0, a_now = 0;
471 v_now = v - a * i * 0.1;
472 a_now = -a;
473 double scale = (v + v_now) / 2 * i * 0.1;
474 x = scale * unit_x;
475 y = scale * unit_y;
476 ADEBUG << start_x + x << ", " << start_y + y << ", "
477 << start_time + 0.1 * i << ", " << v_now << ", " << a_now;
478 TrajectoryPoint point;
479 point.mutable_path_point()->set_x(start_x + x);
480 point.mutable_path_point()->set_y(start_y + y);
481 point.mutable_path_point()->set_theta(
482 optimizer_trajectory_ptr->back().path_point().theta());
483 point.mutable_path_point()->set_s(0.0);
484 point.mutable_path_point()->set_kappa(0.0);
485 point.set_relative_time(start_time + 0.1 * i);
486 point.set_v(-v_now);
487 point.set_a(a_now);
488 optimizer_trajectory_ptr->push_back(point);
489 }
490 }
491 *(trajectory_data) = *(optimizer_trajectory_ptr);
492
493 // Last point in stitching trajectory is already in optimized trajectory, so
494 // it is deleted
497 ->pop_back();
498 trajectory_data->PrependTrajectoryPoints(
501}
502
503void OpenSpaceTrajectoryProvider::ReuseLastFrameResult(
504 const Frame* last_frame, DiscretizedTrajectory* const trajectory_data) {
505 *(trajectory_data) =
506 last_frame->open_space_info().stitched_trajectory_result();
508}
509
510void OpenSpaceTrajectoryProvider::ReuseLastFrameDebug(const Frame* last_frame) {
511 // reuse last frame's instance
513 ptr_debug->mutable_planning_data()->mutable_open_space()->MergeFrom(
514 last_frame->open_space_info()
515 .debug_instance()
516 .planning_data()
517 .open_space());
518}
519
520} // namespace planning
521} // 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
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
a singleton clock that can be used to get the current timestamp.
Definition clock.h:39
const OpenSpaceInfo & open_space_info() const
Definition frame.h:167
const common::VehicleState & vehicle_state() const
Definition frame.cc:83
OpenSpaceInfo * mutable_open_space_info()
Definition frame.h:169
void set_destination_reached(const bool flag)
apollo::planning_internal::Debug * mutable_debug_instance()
const std::vector< common::TrajectoryPoint > & stitching_trajectory_data() const
const std::vector< double > & open_space_end_pose() const
const std::string target_parking_spot_id() const
std::vector< common::TrajectoryPoint > * mutable_stitching_trajectory_data()
void set_time_latency(double time_latency)
void set_open_space_provider_success(const bool flag)
void set_openspace_planning_finish(const bool flag)
DiscretizedTrajectory * mutable_optimizer_trajectory_data()
DiscretizedTrajectory * mutable_stitched_trajectory_result()
apollo::planning_internal::Debug * mutable_debug()
bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector) override
std::shared_ptr< DependencyInjector > injector_
Definition task.h:59
virtual bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector)
Definition task.cc:40
static std::vector< common::TrajectoryPoint > ComputeReinitStitchingTrajectory(const double planning_cycle_time, const common::VehicleState &vehicle_state)
Planning module main class.
#define ADEBUG
Definition log.h:41
#define AINFO
Definition log.h:42
float cos(Angle16 a)
Definition angle.cc:42
float sin(Angle16 a)
Definition angle.cc:25
double AngleDiff(const double from, const double to)
Calculate the difference between angle from and to
Definition math_utils.cc:61
class register implement
Definition arena_queue.h:37
optional OpenSpaceTrajectoryOptimizerConfig open_space_trajectory_optimizer_config
std::vector< common::TrajectoryPoint > stitching_trajectory
std::vector< std::vector< common::math::Vec2d > > obstacles_vertices_vec