Apollo 11.0
自动驾驶开放平台
move_sequence_predictor.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <algorithm>
20#include <memory>
21
24
25namespace apollo {
26namespace prediction {
27
33
37
39 const ADCTrajectoryContainer* adc_trajectory_container, Obstacle* obstacle,
40 ObstaclesContainer* obstacles_container) {
41 Clear();
42
43 CHECK_NOTNULL(obstacle);
44 CHECK_GT(obstacle->history_size(), 0U);
45
47
48 const Feature& feature = obstacle->latest_feature();
49
50 if (!feature.has_lane() || !feature.lane().has_lane_graph()) {
51 AERROR << "Obstacle [" << obstacle->id() << "] has no lane graph.";
52 return false;
53 }
54
55 std::string lane_id = "";
56 if (feature.lane().has_lane_feature()) {
57 lane_id = feature.lane().lane_feature().lane_id();
58 }
59 int num_lane_sequence = feature.lane().lane_graph().lane_sequence_size();
60 std::vector<bool> enable_lane_sequence(num_lane_sequence, true);
61 Obstacle* ego_vehicle_ptr =
62 obstacles_container->GetObstacle(FLAGS_ego_vehicle_id);
63 FilterLaneSequences(feature, lane_id, ego_vehicle_ptr,
64 adc_trajectory_container, &enable_lane_sequence);
65 for (int i = 0; i < num_lane_sequence; ++i) {
66 const LaneSequence& sequence = feature.lane().lane_graph().lane_sequence(i);
67 if (sequence.lane_segment().empty() ||
68 sequence.lane_segment(0).lane_point().empty()) {
69 ADEBUG << "Empty lane segments.";
70 continue;
71 }
72
73 if (!enable_lane_sequence[i]) {
74 ADEBUG << "Lane sequence [" << ToString(sequence)
75 << "] with probability [" << sequence.probability()
76 << "] is disqualified.";
77 continue;
78 }
79
80 ADEBUG << "Obstacle [" << obstacle->id()
81 << "] will draw a lane sequence trajectory [" << ToString(sequence)
82 << "] with probability [" << sequence.probability() << "].";
83
84 std::vector<TrajectoryPoint> points;
85 auto end_time1 = std::chrono::system_clock::now();
86
87 bool is_about_to_stop = false;
88 double acceleration = 0.0;
89 if (sequence.has_stop_sign()) {
90 double stop_distance =
91 sequence.stop_sign().lane_sequence_s() - sequence.lane_s();
92 is_about_to_stop = SupposedToStop(feature, stop_distance, &acceleration);
93 }
94
95 if (is_about_to_stop) {
97 *obstacle, sequence, FLAGS_prediction_trajectory_time_length,
98 FLAGS_prediction_trajectory_time_resolution, acceleration, &points);
99 } else {
100 DrawMoveSequenceTrajectoryPoints(
101 *obstacle, sequence, FLAGS_prediction_trajectory_time_length,
102 FLAGS_prediction_trajectory_time_resolution, &points);
103 }
104 auto end_time2 = std::chrono::system_clock::now();
105 std::chrono::duration<double> diff = end_time2 - end_time1;
106 ADEBUG << " Time to draw trajectory: " << diff.count() * 1000 << " msec.";
107
108 Trajectory trajectory = GenerateTrajectory(points);
109 trajectory.set_probability(sequence.probability());
110 obstacle->mutable_latest_feature()->add_predicted_trajectory()->CopyFrom(
111 trajectory);
112 }
113 return true;
114}
115
122bool MoveSequencePredictor::DrawMoveSequenceTrajectoryPoints(
123 const Obstacle& obstacle, const LaneSequence& lane_sequence,
124 const double total_time, const double period,
125 std::vector<TrajectoryPoint>* points) {
126 // Sanity check.
127 points->clear();
128 CHECK_NOTNULL(points);
129 const Feature& feature = obstacle.latest_feature();
130 if (!feature.has_position() || !feature.has_velocity() ||
131 !feature.position().has_x() || !feature.position().has_y()) {
132 AERROR << "Obstacle [" << obstacle.id()
133 << " is missing position or velocity";
134 return false;
135 }
136
137 // Fit the lateral and longitudinal polynomials.
138 Eigen::Vector2d position(feature.position().x(), feature.position().y());
139 double time_to_lat_end_state =
140 std::max(FLAGS_default_time_to_lat_end_state,
141 ComputeTimeToLatEndConditionByVelocity(obstacle, lane_sequence));
142
143 double vel_heading = feature.velocity_heading();
144 double feature_v = feature.speed();
145 double feature_a = 0.0;
146 if (FLAGS_enable_lane_sequence_acc && lane_sequence.has_acceleration()) {
147 feature_a = lane_sequence.acceleration();
148 }
149 double lane_heading = lane_sequence.lane_segment(0).lane_point(0).heading();
150 double s0 = 0.0;
151 double ds0 = feature_v * std::cos(vel_heading - lane_heading);
152 double dds0 = feature_a * std::cos(vel_heading - lane_heading);
153 std::pair<double, double> lon_end_vt =
154 ComputeLonEndState({s0, ds0, dds0}, lane_sequence);
155
156 std::array<double, 4> lateral_coeffs;
157 std::array<double, 5> longitudinal_coeffs;
158 GetLateralPolynomial(obstacle, lane_sequence, time_to_lat_end_state,
159 &lateral_coeffs);
160 GetLongitudinalPolynomial(obstacle, lane_sequence, lon_end_vt,
161 &longitudinal_coeffs);
162
163 // Get ready for the for-loop:
164 // project the obstacle's position onto the lane's Frenet coordinates.
165 int lane_segment_index = lane_sequence.adc_lane_segment_idx();
166 std::string lane_id =
167 lane_sequence.lane_segment(lane_segment_index).lane_id();
168 std::shared_ptr<const LaneInfo> lane_info = PredictionMap::LaneById(lane_id);
169 double lane_s = 0.0;
170 double lane_l = 0.0;
171 if (!PredictionMap::GetProjection(position, lane_info, &lane_s, &lane_l)) {
172 AERROR << "Failed in getting lane s and lane l";
173 return false;
174 }
175 double prev_lane_l = lane_l;
176
177 // Draw each trajectory point within the total time of prediction
178 size_t total_num = static_cast<size_t>(total_time / period);
179 for (size_t i = 0; i < total_num; ++i) {
180 double relative_time = static_cast<double>(i) * period;
181 Eigen::Vector2d point;
182 double theta = M_PI;
183
184 lane_l = EvaluateCubicPolynomial(lateral_coeffs, relative_time, 0,
185 time_to_lat_end_state, 0.0);
186 double curr_s =
187 EvaluateQuarticPolynomial(longitudinal_coeffs, relative_time, 0,
188 lon_end_vt.second, lon_end_vt.first);
189 double prev_s = (i > 0) ? EvaluateQuarticPolynomial(
190 longitudinal_coeffs, relative_time - period,
191 0, lon_end_vt.second, lon_end_vt.first)
192 : 0.0;
193 lane_s += std::max(0.0, (curr_s - prev_s));
194 if (curr_s + FLAGS_double_precision < prev_s) {
195 lane_l = prev_lane_l;
196 }
197 if (!PredictionMap::SmoothPointFromLane(lane_id, lane_s, lane_l, &point,
198 &theta)) {
199 AERROR << "Unable to get smooth point from lane [" << lane_id
200 << "] with s [" << lane_s << "] and l [" << lane_l << "]";
201 break;
202 }
203
204 prev_lane_l = lane_l;
205 double lane_speed =
206 EvaluateQuarticPolynomial(longitudinal_coeffs, relative_time, 1,
207 lon_end_vt.second, lon_end_vt.first);
208 double lane_acc =
209 EvaluateQuarticPolynomial(longitudinal_coeffs, relative_time, 2,
210 lon_end_vt.second, lon_end_vt.first);
211
212 TrajectoryPoint trajectory_point;
213 PathPoint path_point;
214 path_point.set_x(point.x());
215 path_point.set_y(point.y());
216 path_point.set_z(0.0);
217 path_point.set_theta(theta);
218 path_point.set_lane_id(lane_id);
219 trajectory_point.mutable_path_point()->CopyFrom(path_point);
220 trajectory_point.set_v(lane_speed);
221 trajectory_point.set_a(lane_acc);
222 trajectory_point.set_relative_time(relative_time);
223 points->emplace_back(std::move(trajectory_point));
224
225 while (lane_s > PredictionMap::LaneById(lane_id)->total_length() &&
226 lane_segment_index + 1 < lane_sequence.lane_segment_size()) {
227 lane_segment_index += 1;
228 lane_s = lane_s - PredictionMap::LaneById(lane_id)->total_length();
229 lane_id = lane_sequence.lane_segment(lane_segment_index).lane_id();
230 }
231 }
232 return true;
233}
234
235std::pair<double, double> MoveSequencePredictor::ComputeLonEndState(
236 const std::array<double, 3>& init_s, const LaneSequence& lane_sequence) {
237 // Get the maximum kappa of the lane.
238 double max_kappa = 0.0;
239 double s_at_max_kappa = 0.0;
240 for (int i = 0; i < lane_sequence.path_point_size(); ++i) {
241 const PathPoint& path_point = lane_sequence.path_point(i);
242 if (path_point.s() < init_s[0] + FLAGS_double_precision) {
243 continue;
244 }
245 if (max_kappa < path_point.kappa()) {
246 max_kappa = path_point.kappa();
247 s_at_max_kappa = path_point.s();
248 }
249 }
250
251 // If the max. curvature is small (almost straight lane),
252 // then predict that the obstacle will keep current speed.
253 double v_init = init_s[1];
254 if (max_kappa < FLAGS_turning_curvature_lower_bound) {
255 return {v_init, FLAGS_prediction_trajectory_time_length};
256 }
257 // (Calculate the speed at the max. curvature point)
259 init_s[1], max_kappa);
260 // If the calculated speed at max. curvature point is higher
261 // than initial speed, don't accelerate, just predict that
262 // the obstacle will maintain current speed.
263 if (v_end + FLAGS_double_precision > v_init) {
264 return {v_init, FLAGS_prediction_trajectory_time_length};
265 }
266 // If the obstacle is already at the max. curvature point,
267 // then predict that it will maintain the current speed.
268 double s_offset = s_at_max_kappa - init_s[0];
269 double t = 2.0 * s_offset / (v_init + v_end);
270 if (t < FLAGS_double_precision) {
271 return {v_init, FLAGS_prediction_trajectory_time_length};
272 }
273 // If the deceleration is too much,
274 // then predict the obstacle follows a reasonable deceleration.
275 double acc = (v_end - v_init) / t;
276 if (acc < FLAGS_vehicle_min_linear_acc) {
277 t = v_init / (-FLAGS_vehicle_min_linear_acc);
278 return {FLAGS_still_obstacle_speed_threshold, t};
279 }
280 // Otherwise, predict that it takes t for the obstacle to arrive at the
281 // max. curvature point with v_end speed.
282 return {v_end, t};
283}
284
285double MoveSequencePredictor::ComputeTimeToLatEndConditionByVelocity(
286 const Obstacle& obstacle, const LaneSequence& lane_sequence) {
287 // Sanity check.
288 CHECK_GT(obstacle.history_size(), 0U);
289 CHECK_GT(lane_sequence.lane_segment_size(), 0);
290 CHECK_GT(lane_sequence.lane_segment(0).lane_point_size(), 0);
291
292 // Get the obstacle's Cartesian v_x, v_y.
293 // Get the lane point's Cartesian angle, relative distance.
294 // Then project the obstacle's velocity onto Frenet coordinate to get
295 // lateral velocity v_l.
296 const Feature& feature = obstacle.latest_feature();
297 const LanePoint& first_lane_point =
298 lane_sequence.lane_segment(0).lane_point(0);
299 double v_x = feature.velocity().x();
300 double v_y = feature.velocity().y();
301 double lane_heading = first_lane_point.heading();
302 double lane_l = first_lane_point.relative_l();
303 double v_l = v_y * std::cos(lane_heading) - v_x * std::sin(lane_heading);
304
305 // If laterally moving too slow or even away from lane center,
306 // then use the default speed
307 // Otherwise, directly calculate the time and return.
308 if (std::fabs(v_l) < FLAGS_default_lateral_approach_speed ||
309 lane_l * v_l < 0.0) {
310 return std::fabs(lane_l / FLAGS_default_lateral_approach_speed);
311 }
312 return std::fabs(lane_l / v_l);
313}
314
315std::vector<double> MoveSequencePredictor::GenerateCandidateTimes() {
316 std::vector<double> candidate_times;
317 double t = FLAGS_time_lower_bound_to_lane_center;
318 double time_gap = FLAGS_sample_time_gap;
319 while (t <= FLAGS_time_upper_bound_to_lane_center) {
320 candidate_times.push_back(t);
321 t += time_gap;
322 }
323 return candidate_times;
324}
325
326double MoveSequencePredictor::CostFunction(const double max_lat_acc,
327 const double time_to_end_state,
328 const double time_to_lane_edge,
329 const double bell_curve_mu) {
330 double cost_of_trajectory =
331 max_lat_acc + FLAGS_cost_function_alpha * time_to_end_state;
332 if (FLAGS_use_bell_curve_for_cost_function) {
333 double bell_curve_weight =
334 1.0 /
335 std::sqrt(2.0 * M_PI * FLAGS_cost_function_sigma *
336 FLAGS_cost_function_sigma) *
337 std::exp(-(time_to_lane_edge - bell_curve_mu) *
338 (time_to_lane_edge - bell_curve_mu) /
339 (2.0 * FLAGS_cost_function_sigma * FLAGS_cost_function_sigma));
340 cost_of_trajectory /= (bell_curve_weight + FLAGS_double_precision);
341 }
342 return cost_of_trajectory;
343}
344
345} // namespace prediction
346} // namespace apollo
bool Predict(const ADCTrajectoryContainer *adc_trajectory_container, Obstacle *obstacle, ObstaclesContainer *obstacles_container) override
Make prediction
Prediction obstacle.
Definition obstacle.h:52
Feature * mutable_latest_feature()
Get a pointer to the latest feature.
Definition obstacle.cc:88
int id() const
Get the obstacle's ID.
Definition obstacle.cc:60
size_t history_size() const
Get the number of historical features.
Definition obstacle.cc:93
void SetPredictorType(const ObstacleConf::PredictorType &predictor_type)
Definition obstacle.cc:1489
const Feature & latest_feature() const
Get the latest feature.
Definition obstacle.cc:78
Obstacle * GetObstacle(const int id)
Get obstacle pointer
static bool SmoothPointFromLane(const std::string &id, const double s, const double l, Eigen::Vector2d *point, double *heading)
Get the smooth point on a lane by a longitudinal coordinate.
static std::shared_ptr< const hdmap::LaneInfo > LaneById(const std::string &id)
Get a shared pointer to a lane by lane ID.
static bool GetProjection(const Eigen::Vector2d &position, const std::shared_ptr< const hdmap::LaneInfo > lane_info, double *s, double *l)
Get the frenet coordinates (s, l) on a lane by a position.
static Trajectory GenerateTrajectory(const std::vector< apollo::common::TrajectoryPoint > &points)
Generate trajectory from trajectory points
Definition predictor.cc:34
ObstacleConf::PredictorType predictor_type_
Definition predictor.h:125
bool SupposedToStop(const Feature &feature, const double stop_distance, double *acceleration)
Determine if an obstacle is supposed to stop within a distance
Definition predictor.cc:125
bool GetLateralPolynomial(const Obstacle &obstacle, const LaneSequence &lane_sequence, const double time_to_end_state, std::array< double, 4 > *coefficients)
bool GetLongitudinalPolynomial(const Obstacle &obstacle, const LaneSequence &lane_sequence, const std::pair< double, double > &lon_end_state, std::array< double, 5 > *coefficients)
void FilterLaneSequences(const Feature &feature, const std::string &lane_id, const Obstacle *ego_vehicle_ptr, const ADCTrajectoryContainer *adc_trajectory_container, std::vector< bool > *enable_lane_sequence)
Filter lane sequences
void DrawConstantAccelerationTrajectory(const Obstacle &obstacle, const LaneSequence &lane_sequence, const double total_time, const double period, const double acceleration, std::vector< apollo::common::TrajectoryPoint > *points)
Draw constant acceleration trajectory points
std::string ToString(const LaneSequence &sequence)
Convert a lane sequence to string
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
Define move sequence predictor
double EvaluateQuarticPolynomial(const std::array< double, 5 > &coeffs, const double t, const uint32_t order, const double end_t, const double end_v)
Evaluate quartic polynomial.
double EvaluateCubicPolynomial(const std::array< double, 4 > &coefs, const double t, const uint32_t order, const double end_t, const double end_v)
Evaluate cubic polynomial.
double AdjustSpeedByCurvature(const double speed, const double curvature)
Adjust a speed value according to a curvature.
class register implement
Definition arena_queue.h:37
optional apollo::common::Point3D velocity
Definition feature.proto:90
optional double velocity_heading
Definition feature.proto:93
optional apollo::common::Point3D position
Definition feature.proto:88
repeated LaneSegment lane_segment