Apollo 11.0
自动驾驶开放平台
st_bounds_decider.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
18
19#include <limits>
20#include <memory>
21
24
25namespace apollo {
26namespace planning {
27
32
33namespace {
34// STBoundPoint contains (t, s_min, s_max)
35using STBoundPoint = std::tuple<double, double, double>;
36// STBound is a vector of STBoundPoints
37using STBound = std::vector<STBoundPoint>;
38// ObsDecSet is a set of decision for new obstacles.
39using ObsDecSet = std::vector<std::pair<std::string, ObjectDecisionType>>;
40} // namespace
41
43 const std::string& config_dir, const std::string& name,
44 const std::shared_ptr<DependencyInjector>& injector) {
45 if (!Decider::Init(config_dir, name, injector)) {
46 return false;
47 }
48 // Load the config this task.
49 return Decider::LoadConfig<STBoundsDeciderConfig>(&config_);
50}
51
52Status STBoundsDecider::Process(Frame* const frame,
53 ReferenceLineInfo* const reference_line_info) {
54 // Initialize the related helper classes.
55 InitSTBoundsDecider(*frame, reference_line_info);
56
57 // Sweep the t-axis, and determine the s-boundaries step by step.
58 STBound regular_st_bound;
59 STBound regular_vt_bound;
60 std::vector<std::pair<double, double>> st_guide_line;
61 Status ret = GenerateRegularSTBound(&regular_st_bound, &regular_vt_bound,
62 &st_guide_line);
63 if (!ret.ok()) {
64 ADEBUG << "Cannot generate a regular ST-boundary.";
65 return Status(ErrorCode::PLANNING_ERROR, ret.error_message());
66 }
67 if (regular_st_bound.empty()) {
68 const std::string msg = "Generated regular ST-boundary is empty.";
69 AERROR << msg;
70 return Status(ErrorCode::PLANNING_ERROR, msg);
71 }
72 StGraphData* st_graph_data = reference_line_info_->mutable_st_graph_data();
73 st_graph_data->SetSTDrivableBoundary(regular_st_bound, regular_vt_bound);
74
75 // Record the ST-Graph for good visualization and easy debugging.
76 auto all_st_boundaries = st_obstacles_processor_.GetAllSTBoundaries();
77 std::vector<STBoundary> st_boundaries;
78 for (const auto& st_boundary : all_st_boundaries) {
79 st_boundaries.push_back(st_boundary.second);
80 }
81 ADEBUG << "Total ST boundaries = " << st_boundaries.size();
82 STGraphDebug* st_graph_debug = reference_line_info->mutable_debug()
83 ->mutable_planning_data()
84 ->add_st_graph();
85 RecordSTGraphDebug(st_boundaries, regular_st_bound, st_guide_line,
86 st_graph_debug);
87
88 return Status::OK();
89}
90
91void STBoundsDecider::InitSTBoundsDecider(
92 const Frame& frame, ReferenceLineInfo* const reference_line_info) {
93 const PathData& path_data = reference_line_info->path_data();
94 PathDecision* path_decision = reference_line_info->path_decision();
95
96 // Map all related obstacles onto ST-Graph.
97 auto time1 = std::chrono::system_clock::now();
98 st_obstacles_processor_.Init(path_data.discretized_path().Length(),
99 config_.total_time(), path_data, path_decision,
100 injector_->history());
101 st_obstacles_processor_.MapObstaclesToSTBoundaries(path_decision);
102 auto time2 = std::chrono::system_clock::now();
103 std::chrono::duration<double> diff = time2 - time1;
104 ADEBUG << "Time for ST Obstacles Processing = " << diff.count() * 1000
105 << " msec.";
106
107 // Initialize Guide-Line and Driving-Limits.
108 static constexpr double desired_speed = 15.0;
109 // If the path_data optimization is guided from a reference path of a
110 // reference trajectory, use its reference speed profile to select the st
111 // bounds in LaneFollow Hybrid Mode
112 if (path_data.is_optimized_towards_trajectory_reference()) {
113 st_guide_line_.Init(desired_speed,
114 injector_->learning_based_data()
115 ->learning_data_adc_future_trajectory_points());
116 } else {
117 st_guide_line_.Init(desired_speed);
118 }
119 static constexpr double max_acc = 2.5;
120 static constexpr double max_dec = 5.0;
121 static constexpr double max_v = desired_speed * 1.5;
122 st_driving_limits_.Init(max_acc, max_dec, max_v,
123 frame.PlanningStartPoint().v());
124}
125
126Status STBoundsDecider::GenerateFallbackSTBound(STBound* const st_bound,
127 STBound* const vt_bound) {
128 // Initialize st-boundary.
129 for (double curr_t = 0.0; curr_t <= config_.total_time();
130 curr_t += kSTBoundsDeciderResolution) {
131 st_bound->emplace_back(curr_t, std::numeric_limits<double>::lowest(),
132 std::numeric_limits<double>::max());
133 vt_bound->emplace_back(curr_t, std::numeric_limits<double>::lowest(),
134 std::numeric_limits<double>::max());
135 }
136
137 // Sweep-line to get detailed ST-boundary.
138 for (size_t i = 0; i < st_bound->size(); ++i) {
139 double t, s_lower, s_upper, lower_obs_v, upper_obs_v;
140 std::tie(t, s_lower, s_upper) = st_bound->at(i);
141 std::tie(t, lower_obs_v, upper_obs_v) = vt_bound->at(i);
142 ADEBUG << "Processing st-boundary at t = " << t;
143
144 // Get Boundary due to driving limits
145 auto driving_limits_bound = st_driving_limits_.GetVehicleDynamicsLimits(t);
146 s_lower = std::fmax(s_lower, driving_limits_bound.first);
147 s_upper = std::fmin(s_upper, driving_limits_bound.second);
148 ADEBUG << "Bounds for s due to driving limits are "
149 << "s_upper = " << s_upper << ", s_lower = " << s_lower;
150
151 // Get Boundary due to obstacles
152 std::vector<std::pair<double, double>> available_s_bounds;
153 std::vector<ObsDecSet> available_obs_decisions;
154 if (!st_obstacles_processor_.GetSBoundsFromDecisions(
155 t, &available_s_bounds, &available_obs_decisions)) {
156 const std::string msg =
157 "Failed to find a proper boundary due to obstacles.";
158 AERROR << msg;
159 return Status(ErrorCode::PLANNING_ERROR, msg);
160 }
161 std::vector<std::pair<STBoundPoint, ObsDecSet>> available_choices;
162 ADEBUG << "Available choices are:";
163 for (int j = 0; j < static_cast<int>(available_s_bounds.size()); ++j) {
164 ADEBUG << " (" << available_s_bounds[j].first << ", "
165 << available_s_bounds[j].second << ")";
166 available_choices.emplace_back(
167 std::make_tuple(0.0, available_s_bounds[j].first,
168 available_s_bounds[j].second),
169 available_obs_decisions[j]);
170 }
171 RemoveInvalidDecisions(driving_limits_bound, &available_choices);
172
173 // Always go for the most conservative option.
174 if (!available_choices.empty()) {
175 // Select the most conservative decision.
176 auto top_choice_s_range = available_choices.front().first;
177 auto top_choice_decision = available_choices.front().second;
178 for (size_t j = 1; j < available_choices.size(); ++j) {
179 if (std::get<1>(available_choices[j].first) <
180 std::get<1>(top_choice_s_range)) {
181 top_choice_s_range = available_choices[j].first;
182 top_choice_decision = available_choices[j].second;
183 }
184 }
185
186 // Set decision for obstacles without decisions.
187 bool is_limited_by_upper_obs = false;
188 bool is_limited_by_lower_obs = false;
189 if (s_lower < std::get<1>(top_choice_s_range)) {
190 s_lower = std::get<1>(top_choice_s_range);
191 is_limited_by_lower_obs = true;
192 }
193 if (s_upper > std::get<2>(top_choice_s_range)) {
194 s_upper = std::get<2>(top_choice_s_range);
195 is_limited_by_upper_obs = true;
196 }
197 st_obstacles_processor_.SetObstacleDecision(top_choice_decision);
198
199 // Update st-guide-line, st-driving-limit info, and v-limits.
200 std::pair<double, double> limiting_speed_info;
201 if (st_obstacles_processor_.GetLimitingSpeedInfo(t,
202 &limiting_speed_info)) {
203 st_driving_limits_.UpdateBlockingInfo(
204 t, s_lower, limiting_speed_info.first, s_upper,
205 limiting_speed_info.second);
206 st_guide_line_.UpdateBlockingInfo(t, s_lower, true);
207 st_guide_line_.UpdateBlockingInfo(t, s_upper, false);
208 if (is_limited_by_lower_obs) {
209 lower_obs_v = limiting_speed_info.first;
210 }
211 if (is_limited_by_upper_obs) {
212 upper_obs_v = limiting_speed_info.second;
213 }
214 }
215 } else {
216 const std::string msg = "No valid st-boundary exists.";
217 AERROR << msg;
218 return Status(ErrorCode::PLANNING_ERROR, msg);
219 }
220
221 // Update into st_bound
222 st_bound->at(i) = std::make_tuple(t, s_lower, s_upper);
223 vt_bound->at(i) = std::make_tuple(t, lower_obs_v, upper_obs_v);
224 }
225
226 return Status::OK();
227}
228
229Status STBoundsDecider::GenerateRegularSTBound(
230 STBound* const st_bound, STBound* const vt_bound,
231 std::vector<std::pair<double, double>>* const st_guide_line) {
232 // Initialize st-boundary.
233 for (double curr_t = 0.0; curr_t <= config_.total_time();
234 curr_t += kSTBoundsDeciderResolution) {
235 st_bound->emplace_back(curr_t, std::numeric_limits<double>::lowest(),
236 std::numeric_limits<double>::max());
237 vt_bound->emplace_back(curr_t, std::numeric_limits<double>::lowest(),
238 std::numeric_limits<double>::max());
239 }
240
241 // Sweep-line to get detailed ST-boundary.
242 for (size_t i = 0; i < st_bound->size(); ++i) {
243 double t, s_lower, s_upper, lower_obs_v, upper_obs_v;
244 std::tie(t, s_lower, s_upper) = st_bound->at(i);
245 std::tie(t, lower_obs_v, upper_obs_v) = vt_bound->at(i);
246 ADEBUG << "Processing st-boundary at t = " << t;
247
248 // Get Boundary due to driving limits
249 auto driving_limits_bound = st_driving_limits_.GetVehicleDynamicsLimits(t);
250 s_lower = std::fmax(s_lower, driving_limits_bound.first);
251 s_upper = std::fmin(s_upper, driving_limits_bound.second);
252 ADEBUG << "Bounds for s due to driving limits are "
253 << "s_upper = " << s_upper << ", s_lower = " << s_lower;
254
255 // Get Boundary due to obstacles
256 std::vector<std::pair<double, double>> available_s_bounds;
257 std::vector<ObsDecSet> available_obs_decisions;
258 if (!st_obstacles_processor_.GetSBoundsFromDecisions(
259 t, &available_s_bounds, &available_obs_decisions)) {
260 const std::string msg =
261 "Failed to find a proper boundary due to obstacles.";
262 AERROR << msg;
263 return Status(ErrorCode::PLANNING_ERROR, msg);
264 }
265 std::vector<std::pair<STBoundPoint, ObsDecSet>> available_choices;
266 ADEBUG << "Available choices are:";
267 for (int j = 0; j < static_cast<int>(available_s_bounds.size()); ++j) {
268 ADEBUG << " (" << available_s_bounds[j].first << ", "
269 << available_s_bounds[j].second << ")";
270 available_choices.emplace_back(
271 std::make_tuple(0.0, available_s_bounds[j].first,
272 available_s_bounds[j].second),
273 available_obs_decisions[j]);
274 }
275 RemoveInvalidDecisions(driving_limits_bound, &available_choices);
276
277 if (!available_choices.empty()) {
278 ADEBUG << "One decision needs to be made among "
279 << available_choices.size() << " choices.";
280 double guide_line_s = st_guide_line_.GetGuideSFromT(t);
281 st_guide_line->emplace_back(t, guide_line_s);
282 RankDecisions(guide_line_s, driving_limits_bound, &available_choices);
283 // Select the top decision.
284 auto top_choice_s_range = available_choices.front().first;
285 bool is_limited_by_upper_obs = false;
286 bool is_limited_by_lower_obs = false;
287 if (s_lower < std::get<1>(top_choice_s_range)) {
288 s_lower = std::get<1>(top_choice_s_range);
289 is_limited_by_lower_obs = true;
290 }
291 if (s_upper > std::get<2>(top_choice_s_range)) {
292 s_upper = std::get<2>(top_choice_s_range);
293 is_limited_by_upper_obs = true;
294 }
295
296 // Set decision for obstacles without decisions.
297 auto top_choice_decision = available_choices.front().second;
298 st_obstacles_processor_.SetObstacleDecision(top_choice_decision);
299
300 // Update st-guide-line, st-driving-limit info, and v-limits.
301 std::pair<double, double> limiting_speed_info;
302 if (st_obstacles_processor_.GetLimitingSpeedInfo(t,
303 &limiting_speed_info)) {
304 st_driving_limits_.UpdateBlockingInfo(
305 t, s_lower, limiting_speed_info.first, s_upper,
306 limiting_speed_info.second);
307 st_guide_line_.UpdateBlockingInfo(t, s_lower, true);
308 st_guide_line_.UpdateBlockingInfo(t, s_upper, false);
309 if (is_limited_by_lower_obs) {
310 lower_obs_v = limiting_speed_info.first;
311 }
312 if (is_limited_by_upper_obs) {
313 upper_obs_v = limiting_speed_info.second;
314 }
315 }
316 } else {
317 const std::string msg = "No valid st-boundary exists.";
318 AERROR << msg;
319 return Status(ErrorCode::PLANNING_ERROR, msg);
320 }
321
322 // Update into st_bound
323 st_bound->at(i) = std::make_tuple(t, s_lower, s_upper);
324 vt_bound->at(i) = std::make_tuple(t, lower_obs_v, upper_obs_v);
325 }
326
327 return Status::OK();
328}
329
330void STBoundsDecider::RemoveInvalidDecisions(
331 std::pair<double, double> driving_limit,
332 std::vector<std::pair<STBoundPoint, ObsDecSet>>* available_choices) {
333 // Remove those choices that don't even fall within driving-limits.
334 size_t i = 0;
335 while (i < available_choices->size()) {
336 double s_lower = 0.0;
337 double s_upper = 0.0;
338 std::tie(std::ignore, s_lower, s_upper) = available_choices->at(i).first;
339 if (s_lower > driving_limit.second || s_upper < driving_limit.first) {
340 // Invalid bound, should be removed.
341 if (i != available_choices->size() - 1) {
342 swap(available_choices->at(i),
343 available_choices->at(available_choices->size() - 1));
344 }
345 available_choices->pop_back();
346 } else {
347 // Valid bound, proceed to the next one.
348 ++i;
349 }
350 }
351}
352
353void STBoundsDecider::RankDecisions(
354 double s_guide_line, std::pair<double, double> driving_limit,
355 std::vector<std::pair<STBoundPoint, ObsDecSet>>* available_choices) {
356 // Perform sorting of the existing decisions.
357 bool has_swaps = true;
358 while (has_swaps) {
359 has_swaps = false;
360 for (int i = 0; i < static_cast<int>(available_choices->size()) - 1; ++i) {
361 double A_s_lower = 0.0;
362 double A_s_upper = 0.0;
363 std::tie(std::ignore, A_s_lower, A_s_upper) =
364 available_choices->at(i).first;
365 double B_s_lower = 0.0;
366 double B_s_upper = 0.0;
367 std::tie(std::ignore, B_s_lower, B_s_upper) =
368 available_choices->at(i + 1).first;
369
370 ADEBUG << " Range ranking: A has s_upper = " << A_s_upper
371 << ", s_lower = " << A_s_lower;
372 ADEBUG << " Range ranking: B has s_upper = " << B_s_upper
373 << ", s_lower = " << B_s_lower;
374
375 // If not both are larger than passable-threshold, should select
376 // the one with larger room.
377 double A_room = std::fmin(driving_limit.second, A_s_upper) -
378 std::fmax(driving_limit.first, A_s_lower);
379 double B_room = std::fmin(driving_limit.second, B_s_upper) -
380 std::fmax(driving_limit.first, B_s_lower);
381 if (A_room < kSTPassableThreshold || B_room < kSTPassableThreshold) {
382 if (A_room < B_room) {
383 swap(available_choices->at(i + 1), available_choices->at(i));
384 has_swaps = true;
385 ADEBUG << "Swapping to favor larger room.";
386 }
387 continue;
388 }
389
390 // Should select the one with overlap to guide-line
391 bool A_contains_guideline =
392 A_s_upper >= s_guide_line && A_s_lower <= s_guide_line;
393 bool B_contains_guideline =
394 B_s_upper >= s_guide_line && B_s_lower <= s_guide_line;
395 if (A_contains_guideline != B_contains_guideline) {
396 if (!A_contains_guideline) {
397 swap(available_choices->at(i + 1), available_choices->at(i));
398 has_swaps = true;
399 ADEBUG << "Swapping to favor overlapping with guide-line.";
400 }
401 continue;
402 }
403 }
404 }
405}
406
407void STBoundsDecider::RecordSTGraphDebug(
408 const std::vector<STBoundary>& st_graph_data, const STBound& st_bound,
409 const std::vector<std::pair<double, double>>& st_guide_line,
410 planning_internal::STGraphDebug* const st_graph_debug) {
411 if (!FLAGS_enable_record_debug || !st_graph_debug) {
412 ADEBUG << "Skip record debug info";
413 return;
414 }
415
416 // Plot ST-obstacle boundaries.
417 for (const auto& boundary : st_graph_data) {
418 auto boundary_debug = st_graph_debug->add_boundary();
419 boundary_debug->set_name(boundary.id());
420 if (boundary.boundary_type() == STBoundary::BoundaryType::YIELD) {
421 boundary_debug->set_type(StGraphBoundaryDebug::ST_BOUNDARY_TYPE_YIELD);
422 ADEBUG << "Obstacle ID = " << boundary.id() << ", decision = YIELD";
423 } else if (boundary.boundary_type() == STBoundary::BoundaryType::OVERTAKE) {
424 boundary_debug->set_type(StGraphBoundaryDebug::ST_BOUNDARY_TYPE_OVERTAKE);
425 ADEBUG << "Obstacle ID = " << boundary.id() << ", decision = OVERTAKE";
426 } else {
427 boundary_debug->set_type(StGraphBoundaryDebug::ST_BOUNDARY_TYPE_UNKNOWN);
428 ADEBUG << "Obstacle ID = " << boundary.id() << ", decision = UNKNOWN";
429 }
430
431 for (const auto& point : boundary.points()) {
432 auto point_debug = boundary_debug->add_point();
433 point_debug->set_t(point.x());
434 point_debug->set_s(point.y());
435 }
436 }
437
438 // Plot the chosen ST boundary.
439 auto boundary_debug = st_graph_debug->add_boundary();
440 boundary_debug->set_name("Generated ST-Boundary");
441 boundary_debug->set_type(
443 for (const auto& st_bound_pt : st_bound) {
444 auto point_debug = boundary_debug->add_point();
445 double t = 0.0;
446 double s_lower = 0.0;
447 std::tie(t, s_lower, std::ignore) = st_bound_pt;
448 point_debug->set_t(t);
449 point_debug->set_s(s_lower);
450 ADEBUG << "(" << t << ", " << s_lower << ")";
451 }
452 for (int i = static_cast<int>(st_bound.size()) - 1; i >= 0; --i) {
453 auto point_debug = boundary_debug->add_point();
454 double t = 0.0;
455 double s_upper = 0.0;
456 std::tie(t, std::ignore, s_upper) = st_bound[i];
457 point_debug->set_t(t);
458 point_debug->set_s(s_upper);
459 ADEBUG << "(" << t << ", " << s_upper << ")";
460 }
461
462 // Plot the used st_guide_line when generating the st_bounds
463 for (const auto& st_points : st_guide_line) {
464 auto* speed_point = st_graph_debug->add_speed_profile();
465 speed_point->set_t(st_points.first);
466 speed_point->set_s(st_points.second);
467 }
468}
469
470} // namespace planning
471} // namespace apollo
A general class to denote the return status of an API call.
Definition status.h:43
bool ok() const
check whether the return status is OK.
Definition status.h:67
const std::string & error_message() const
returns the error message of the status, empty if the status is OK.
Definition status.h:91
static Status OK()
generate a success status.
Definition status.h:60
Frame holds all data for one planning cycle.
Definition frame.h:62
ReferenceLineInfo holds all data for one reference line.
planning_internal::Debug * mutable_debug()
bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector) override
void Init(const double max_acc, const double max_dec, const double max_v, double curr_v)
std::pair< double, double > GetVehicleDynamicsLimits(const double t) const
Given time t, calculate the driving limits in s due to vehicle's dynamics.
void UpdateBlockingInfo(const double t, const double lower_s, const double lower_v, const double upper_s, const double upper_v)
Update the anchoring of the vehicle dynamics limits.
void Init(double desired_v)
void UpdateBlockingInfo(const double t, const double s_block, const bool is_lower_block)
common::Status MapObstaclesToSTBoundaries(PathDecision *const path_decision)
bool GetLimitingSpeedInfo(double t, std::pair< double, double > *const limiting_speed_info)
Provided that decisions for all existing obstacles are made, get the speed limiting info from limitin...
void Init(const double planning_distance, const double planning_time, const PathData &path_data, PathDecision *const path_decision, History *const history)
std::unordered_map< std::string, STBoundary > GetAllSTBoundaries()
void SetObstacleDecision(const std::string &obs_id, const ObjectDecisionType &obs_decision)
Set the decision for a given obstacle.
bool GetSBoundsFromDecisions(double t, std::vector< std::pair< double, double > > *const available_s_bounds, std::vector< std::vector< std::pair< std::string, ObjectDecisionType > > > *const available_obs_decisions)
Given a time t, get the lower and upper s-boundaries.
bool SetSTDrivableBoundary(const std::vector< std::tuple< double, double, double > > &s_boundary, const std::vector< std::tuple< double, double, double > > &v_obs_info)
std::shared_ptr< DependencyInjector > injector_
Definition task.h:59
ReferenceLineInfo * reference_line_info_
Definition task.h:58
virtual bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector)
Definition task.cc:40
Planning module main class.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
float diff(Image< float > *I, int x1, int y1, int x2, int y2)
Dissimilarity measure between pixels
constexpr double kSTPassableThreshold
constexpr double kSTBoundsDeciderResolution
class register implement
Definition arena_queue.h:37
: data with map info and obstacle info