35using STBoundPoint = std::tuple<double, double, double>;
37using STBound = std::vector<STBoundPoint>;
39using ObsDecSet = std::vector<std::pair<std::string, ObjectDecisionType>>;
43 const std::string& config_dir,
const std::string& name,
44 const std::shared_ptr<DependencyInjector>& injector) {
49 return Decider::LoadConfig<STBoundsDeciderConfig>(&config_);
55 InitSTBoundsDecider(*frame, reference_line_info);
58 STBound regular_st_bound;
59 STBound regular_vt_bound;
60 std::vector<std::pair<double, double>> st_guide_line;
61 Status ret = GenerateRegularSTBound(®ular_st_bound, ®ular_vt_bound,
64 ADEBUG <<
"Cannot generate a regular ST-boundary.";
67 if (regular_st_bound.empty()) {
68 const std::string msg =
"Generated regular ST-boundary is empty.";
70 return Status(ErrorCode::PLANNING_ERROR, msg);
77 std::vector<STBoundary> st_boundaries;
78 for (
const auto& st_boundary : all_st_boundaries) {
79 st_boundaries.push_back(st_boundary.second);
81 ADEBUG <<
"Total ST boundaries = " << st_boundaries.size();
82 STGraphDebug* st_graph_debug = reference_line_info->
mutable_debug()
83 ->mutable_planning_data()
85 RecordSTGraphDebug(st_boundaries, regular_st_bound, st_guide_line,
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();
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,
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
108 static constexpr double desired_speed = 15.0;
112 if (path_data.is_optimized_towards_trajectory_reference()) {
113 st_guide_line_.
Init(desired_speed,
115 ->learning_data_adc_future_trajectory_points());
117 st_guide_line_.
Init(desired_speed);
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());
126Status STBoundsDecider::GenerateFallbackSTBound(STBound*
const st_bound,
127 STBound*
const vt_bound) {
129 for (
double curr_t = 0.0; curr_t <= config_.
total_time();
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());
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;
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;
152 std::vector<std::pair<double, double>> available_s_bounds;
153 std::vector<ObsDecSet> available_obs_decisions;
155 t, &available_s_bounds, &available_obs_decisions)) {
156 const std::string msg =
157 "Failed to find a proper boundary due to obstacles.";
159 return Status(ErrorCode::PLANNING_ERROR, msg);
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]);
171 RemoveInvalidDecisions(driving_limits_bound, &available_choices);
174 if (!available_choices.empty()) {
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;
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;
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;
200 std::pair<double, double> limiting_speed_info;
202 &limiting_speed_info)) {
204 t, s_lower, limiting_speed_info.first, s_upper,
205 limiting_speed_info.second);
208 if (is_limited_by_lower_obs) {
209 lower_obs_v = limiting_speed_info.first;
211 if (is_limited_by_upper_obs) {
212 upper_obs_v = limiting_speed_info.second;
216 const std::string msg =
"No valid st-boundary exists.";
218 return Status(ErrorCode::PLANNING_ERROR, msg);
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);
229Status STBoundsDecider::GenerateRegularSTBound(
230 STBound*
const st_bound, STBound*
const vt_bound,
231 std::vector<std::pair<double, double>>*
const st_guide_line) {
233 for (
double curr_t = 0.0; curr_t <= config_.
total_time();
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());
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;
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;
256 std::vector<std::pair<double, double>> available_s_bounds;
257 std::vector<ObsDecSet> available_obs_decisions;
259 t, &available_s_bounds, &available_obs_decisions)) {
260 const std::string msg =
261 "Failed to find a proper boundary due to obstacles.";
263 return Status(ErrorCode::PLANNING_ERROR, msg);
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]);
275 RemoveInvalidDecisions(driving_limits_bound, &available_choices);
277 if (!available_choices.empty()) {
278 ADEBUG <<
"One decision needs to be made among "
279 << available_choices.size() <<
" choices.";
281 st_guide_line->emplace_back(t, guide_line_s);
282 RankDecisions(guide_line_s, driving_limits_bound, &available_choices);
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;
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;
297 auto top_choice_decision = available_choices.front().second;
301 std::pair<double, double> limiting_speed_info;
303 &limiting_speed_info)) {
305 t, s_lower, limiting_speed_info.first, s_upper,
306 limiting_speed_info.second);
309 if (is_limited_by_lower_obs) {
310 lower_obs_v = limiting_speed_info.first;
312 if (is_limited_by_upper_obs) {
313 upper_obs_v = limiting_speed_info.second;
317 const std::string msg =
"No valid st-boundary exists.";
319 return Status(ErrorCode::PLANNING_ERROR, msg);
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);
330void STBoundsDecider::RemoveInvalidDecisions(
331 std::pair<double, double> driving_limit,
332 std::vector<std::pair<STBoundPoint, ObsDecSet>>* available_choices) {
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) {
341 if (i != available_choices->size() - 1) {
342 swap(available_choices->at(i),
343 available_choices->at(available_choices->size() - 1));
345 available_choices->pop_back();
353void STBoundsDecider::RankDecisions(
354 double s_guide_line, std::pair<double, double> driving_limit,
355 std::vector<std::pair<STBoundPoint, ObsDecSet>>* available_choices) {
357 bool has_swaps =
true;
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;
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;
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);
382 if (A_room < B_room) {
383 swap(available_choices->at(i + 1), available_choices->at(i));
385 ADEBUG <<
"Swapping to favor larger room.";
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));
399 ADEBUG <<
"Swapping to favor overlapping with guide-line.";
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";
417 for (
const auto& boundary : st_graph_data) {
418 auto boundary_debug = st_graph_debug->add_boundary();
419 boundary_debug->set_name(boundary.id());
422 ADEBUG <<
"Obstacle ID = " << boundary.id() <<
", decision = YIELD";
425 ADEBUG <<
"Obstacle ID = " << boundary.id() <<
", decision = OVERTAKE";
428 ADEBUG <<
"Obstacle ID = " << boundary.id() <<
", decision = UNKNOWN";
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());
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();
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 <<
")";
452 for (
int i =
static_cast<int>(st_bound.size()) - 1; i >= 0; --i) {
453 auto point_debug = boundary_debug->add_point();
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 <<
")";
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);
A general class to denote the return status of an API call.
bool ok() const
check whether the return status is OK.
const std::string & error_message() const
returns the error message of the status, empty if the status is OK.
static Status OK()
generate a success status.
Frame holds all data for one planning cycle.
ReferenceLineInfo holds all data for one reference line.
StGraphData * mutable_st_graph_data()
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)
double GetGuideSFromT(double t)
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_
ReferenceLineInfo * reference_line_info_
virtual bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector)
Planning module main class.
float diff(Image< float > *I, int x1, int y1, int x2, int y2)
Dissimilarity measure between pixels
constexpr double kSTPassableThreshold
constexpr double kSTBoundsDeciderResolution
: data with map info and obstacle info
optional double total_time
@ ST_BOUNDARY_TYPE_OVERTAKE
@ ST_BOUNDARY_TYPE_UNKNOWN
@ ST_BOUNDARY_TYPE_DRIVABLE_REGION