Apollo 11.0
自动驾驶开放平台
trajectory_stitcher.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
22
23#include <algorithm>
24
25#include "absl/strings/str_cat.h"
26
27#include "cyber/common/log.h"
34
35namespace apollo {
36namespace planning {
37
42
43TrajectoryPoint TrajectoryStitcher::ComputeTrajectoryPointFromVehicleState(
44 const double planning_cycle_time, const VehicleState& vehicle_state) {
45 TrajectoryPoint point;
46 point.mutable_path_point()->set_s(0.0);
47 point.mutable_path_point()->set_x(vehicle_state.x());
48 point.mutable_path_point()->set_y(vehicle_state.y());
49 point.mutable_path_point()->set_z(vehicle_state.z());
50 point.mutable_path_point()->set_theta(vehicle_state.heading());
51 point.mutable_path_point()->set_kappa(vehicle_state.kappa());
52 point.set_v(vehicle_state.linear_velocity());
53 point.set_a(vehicle_state.linear_acceleration());
54 point.set_relative_time(planning_cycle_time);
55 return point;
56}
57
58std::vector<TrajectoryPoint>
60 const double planning_cycle_time, const VehicleState& vehicle_state) {
61 TrajectoryPoint reinit_point;
62 static constexpr double kEpsilon_v = 0.1;
63 static constexpr double kEpsilon_a = 0.4;
64 // TODO(Jinyun/Yu): adjust kEpsilon if corrected IMU acceleration provided
65 if (std::abs(vehicle_state.linear_velocity()) < kEpsilon_v &&
66 std::abs(vehicle_state.linear_acceleration()) < kEpsilon_a) {
67 reinit_point = ComputeTrajectoryPointFromVehicleState(planning_cycle_time,
68 vehicle_state);
69 } else {
70 VehicleState predicted_vehicle_state;
71 predicted_vehicle_state =
72 VehicleModel::Predict(planning_cycle_time, vehicle_state);
73 reinit_point = ComputeTrajectoryPointFromVehicleState(
74 planning_cycle_time, predicted_vehicle_state);
75 }
76
77 return std::vector<TrajectoryPoint>(1, reinit_point);
78}
79
80// only used in navigation mode
82 const double x_diff, const double y_diff, const double theta_diff,
83 PublishableTrajectory* prev_trajectory) {
84 if (!prev_trajectory) {
85 return;
86 }
87
88 // R^-1
89 double cos_theta = std::cos(theta_diff);
90 double sin_theta = -std::sin(theta_diff);
91
92 // -R^-1 * t
93 auto tx = -(cos_theta * x_diff - sin_theta * y_diff);
94 auto ty = -(sin_theta * x_diff + cos_theta * y_diff);
95
96 std::for_each(prev_trajectory->begin(), prev_trajectory->end(),
97 [&cos_theta, &sin_theta, &tx, &ty,
98 &theta_diff](common::TrajectoryPoint& p) {
99 auto x = p.path_point().x();
100 auto y = p.path_point().y();
101 auto theta = p.path_point().theta();
102
103 auto x_new = cos_theta * x - sin_theta * y + tx;
104 auto y_new = sin_theta * x + cos_theta * y + ty;
105 auto theta_new =
106 common::math::NormalizeAngle(theta - theta_diff);
107
108 p.mutable_path_point()->set_x(x_new);
109 p.mutable_path_point()->set_y(y_new);
110 p.mutable_path_point()->set_theta(theta_new);
111 });
112}
113
114/* Planning from current vehicle state if:
115 1. the auto-driving mode is off
116 (or) 2. we don't have the trajectory from last planning cycle
117 (or) 3. the position deviation from actual and target is too high
118*/
120 const canbus::Chassis& vehicle_chassis, const VehicleState& vehicle_state,
121 const double current_timestamp, const double planning_cycle_time,
122 const size_t preserved_points_num, const bool replan_by_offset,
123 const PublishableTrajectory* prev_trajectory, std::string* replan_reason,
124 const control::ControlInteractiveMsg& control_interactive_msg) {
125 // 1.check replan not by offset
126 size_t time_matched_index = 0;
127 if (need_replan_by_necessary_check(vehicle_state, current_timestamp,
128 prev_trajectory, replan_reason,
129 &time_matched_index)) {
130 return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
131 }
132
133 // 2. check replan by GEAR switch
134 if (vehicle_chassis.has_gear_location()) {
135 static canbus::Chassis::GearPosition gear_pos =
137 if (gear_pos == canbus::Chassis::GEAR_NEUTRAL &&
138 vehicle_chassis.gear_location() == canbus::Chassis::GEAR_DRIVE) {
139 gear_pos = vehicle_chassis.gear_location();
140 const std::string msg =
141 "gear change from n to d, replan to avoid large station error";
142 AERROR << msg;
143 *replan_reason = msg;
144 return ComputeReinitStitchingTrajectory(planning_cycle_time,
145 vehicle_state);
146 }
147 gear_pos = vehicle_chassis.gear_location();
148 }
149
150 auto time_matched_point = prev_trajectory->TrajectoryPointAt(
151 static_cast<uint32_t>(time_matched_index));
152
153 // 3.check replan by control_interactive_msg
154 if (need_replan_by_control_interactive(current_timestamp, replan_reason,
155 control_interactive_msg)) {
157 planning_cycle_time, vehicle_state, time_matched_point,
158 control_interactive_msg);
159 }
160
161 size_t position_matched_index = prev_trajectory->QueryNearestPointWithBuffer(
162 {vehicle_state.x(), vehicle_state.y()}, 1.0e-6);
163
164 auto frenet_sd = ComputePositionProjection(
165 vehicle_state.x(), vehicle_state.y(),
166 prev_trajectory->TrajectoryPointAt(
167 static_cast<uint32_t>(position_matched_index)));
168
169 // 4.check replan by offset
170 if (replan_by_offset) {
171 if (vehicle_chassis.has_parking_brake()) {
172 static bool parking_brake = true;
173 if (parking_brake && !vehicle_chassis.parking_brake()) {
174 parking_brake = vehicle_chassis.parking_brake();
175 const std::string msg =
176 "parking brake off, ego move, replan to avoid large station error";
177 AERROR << msg;
178 *replan_reason = msg;
179 return ComputeReinitStitchingTrajectory(planning_cycle_time,
180 vehicle_state);
181 }
182 parking_brake = vehicle_chassis.parking_brake();
183 }
184
185 auto lon_diff = time_matched_point.path_point().s() - frenet_sd.first;
186 auto lat_diff = frenet_sd.second;
187 double time_diff =
188 time_matched_point.relative_time() -
189 prev_trajectory
190 ->TrajectoryPointAt(static_cast<uint32_t>(position_matched_index))
191 .relative_time();
192
193 ADEBUG << "Control lateral diff: " << lat_diff
194 << ", longitudinal diff: " << lon_diff
195 << ", time diff: " << time_diff;
196
197 if (std::fabs(lat_diff) > FLAGS_replan_lateral_distance_threshold) {
198 const std::string msg = absl::StrCat(
199 "the distance between matched point and actual position is too "
200 "large. Replan is triggered. lat_diff = ",
201 lat_diff);
202 AERROR << msg;
203 *replan_reason = msg;
204 return ComputeReinitStitchingTrajectory(planning_cycle_time,
205 vehicle_state);
206 }
207
208 if (std::fabs(lon_diff) > FLAGS_replan_longitudinal_distance_threshold) {
209 const std::string msg = absl::StrCat(
210 "the distance between matched point and actual position is too "
211 "large. Replan is triggered. lon_diff = ",
212 lon_diff);
213 AERROR << msg;
214 *replan_reason = msg;
215 return ComputeReinitStitchingTrajectory(planning_cycle_time,
216 vehicle_state);
217 }
218
219 if (std::fabs(time_diff) > FLAGS_replan_time_threshold) {
220 const std::string msg = absl::StrCat(
221 "the difference between time matched point relative time and "
222 "actual position corresponding relative time is too "
223 "large. Replan is triggered. time_diff = ",
224 time_diff);
225 AERROR << msg;
226 *replan_reason = msg;
227 return ComputeReinitStitchingTrajectory(planning_cycle_time,
228 vehicle_state);
229 }
230 } else {
231 ADEBUG << "replan according to certain amount of "
232 << "lat、lon and time offset is disabled";
233 }
234
235 // 4.stitching_trajectory
236 double forward_rel_time =
237 current_timestamp - prev_trajectory->header_time() + planning_cycle_time;
238
239 size_t forward_time_index =
240 prev_trajectory->QueryLowerBoundPoint(forward_rel_time);
241
242 ADEBUG << "Position matched index:\t" << position_matched_index;
243 ADEBUG << "Time matched index:\t" << time_matched_index;
244
245 auto matched_index = std::min(time_matched_index, position_matched_index);
246
247 std::vector<TrajectoryPoint> stitching_trajectory(
248 prev_trajectory->begin() +
249 std::max(0, static_cast<int>(matched_index - preserved_points_num)),
250 prev_trajectory->begin() + forward_time_index + 1);
251 ADEBUG << "stitching_trajectory size: " << stitching_trajectory.size();
252
253 const double zero_s = stitching_trajectory.back().path_point().s();
254 for (auto& tp : stitching_trajectory) {
255 if (!tp.has_path_point()) {
256 *replan_reason = "replan for previous trajectory missed path point";
257 return ComputeReinitStitchingTrajectory(planning_cycle_time,
258 vehicle_state);
259 }
260 tp.set_relative_time(tp.relative_time() + prev_trajectory->header_time() -
261 current_timestamp);
262 tp.mutable_path_point()->set_s(tp.path_point().s() - zero_s);
263 }
264 return stitching_trajectory;
265}
266
267std::pair<double, double> TrajectoryStitcher::ComputePositionProjection(
268 const double x, const double y, const TrajectoryPoint& p) {
269 Vec2d v(x - p.path_point().x(), y - p.path_point().y());
270 Vec2d n(std::cos(p.path_point().theta()), std::sin(p.path_point().theta()));
271
272 std::pair<double, double> frenet_sd;
273 frenet_sd.first = v.InnerProd(n) + p.path_point().s();
274 frenet_sd.second = v.CrossProd(n);
275 return frenet_sd;
276}
277
279 const common::VehicleState& vehicle_state, const double current_timestamp,
280 const PublishableTrajectory* prev_trajectory, std::string* replan_reason,
281 size_t* time_matched_index) {
282 if (!FLAGS_enable_trajectory_stitcher) {
283 *replan_reason = "stitch is disabled by gflag.";
284 return true;
285 }
286 if (!prev_trajectory) {
287 *replan_reason = "replan for no previous trajectory.";
288 return true;
289 }
290
291 if (vehicle_state.driving_mode() != canbus::Chassis::COMPLETE_AUTO_DRIVE) {
292 *replan_reason = "replan for manual mode.";
293 return true;
294 }
295
296 size_t prev_trajectory_size = prev_trajectory->NumOfPoints();
297
298 if (prev_trajectory_size == 0) {
299 ADEBUG << "Projected trajectory at time [" << prev_trajectory->header_time()
300 << "] size is zero! Previous planning not exist or failed. Use "
301 "origin car status instead.";
302 *replan_reason = "replan for empty previous trajectory.";
303 return true;
304 }
305
306 const double veh_rel_time =
307 current_timestamp - prev_trajectory->header_time();
308
309 *time_matched_index = prev_trajectory->QueryLowerBoundPoint(veh_rel_time);
310
311 if (*time_matched_index == 0 &&
312 veh_rel_time < prev_trajectory->StartPoint().relative_time()) {
313 AWARN << "current time smaller than the previous trajectory's first time";
314 *replan_reason =
315 "replan for current time smaller than the previous trajectory's first "
316 "time.";
317 return true;
318 }
319
320 if (*time_matched_index + 1 >= prev_trajectory_size) {
321 AWARN << "current time beyond the previous trajectory's last time";
322 *replan_reason =
323 "replan for current time beyond the previous trajectory's last time";
324 return true;
325 }
326
327 auto time_matched_point = prev_trajectory->TrajectoryPointAt(
328 static_cast<uint32_t>(*time_matched_index));
329
330 if (!time_matched_point.has_path_point()) {
331 *replan_reason = "replan for previous trajectory missed path point";
332 return true;
333 }
334 return false;
335}
336
338 const double current_timestamp, std::string* replan_reason,
339 const control::ControlInteractiveMsg& control_interactive_msg) {
340 const double rel_time =
341 current_timestamp - control_interactive_msg.header().timestamp_sec();
342 if (rel_time > 0.5) {
343 AINFO << "control_interactive_msg time out, skip replay by control "
344 "interactive";
345 return false;
346 }
347 if (control_interactive_msg.has_replan_request() &&
348 control_interactive_msg.replan_request() == true) {
349 *replan_reason = "replan for control_interactive_msg, " +
350 control_interactive_msg.replan_request_reason();
351 return true;
352 }
353 return false;
354}
355
356std::vector<common::TrajectoryPoint>
358 const double planning_cycle_time, const common::VehicleState& vehicle_state,
359 const common::TrajectoryPoint& time_match_point,
360 const control::ControlInteractiveMsg& control_interactive_msg) {
361 if (control_interactive_msg.replan_req_reason_code() ==
363 control_interactive_msg.replan_req_reason_code() ==
365 AINFO << "control_interactive_msg replan, all replan";
366 return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
367 } else {
368 AINFO << "control_interactive_msg replan, speed replan";
369 VehicleState vehicle_state_tmp = vehicle_state;
370 vehicle_state_tmp.set_x(time_match_point.path_point().x());
371 vehicle_state_tmp.set_y(time_match_point.path_point().y());
372 vehicle_state_tmp.set_z(time_match_point.path_point().z());
373 vehicle_state_tmp.set_heading(time_match_point.path_point().theta());
374 vehicle_state_tmp.set_kappa(time_match_point.path_point().kappa());
375 return ComputeReinitStitchingTrajectory(planning_cycle_time,
376 vehicle_state_tmp);
377 }
378}
379
380} // namespace planning
381} // namespace apollo
Defines the templated Angle class.
static VehicleState Predict(const double predicted_time_horizon, const VehicleState &cur_vehicle_state)
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
void set_x(const double x)
Setter for x component
Definition vec2d.h:60
size_t QueryNearestPointWithBuffer(const common::math::Vec2d &position, const double buffer) const
const common::TrajectoryPoint & TrajectoryPointAt(const size_t index) const
virtual size_t QueryLowerBoundPoint(const double relative_time, const double epsilon=1.0e-5) const
static std::vector< common::TrajectoryPoint > ComputeStitchingTrajectory(const canbus::Chassis &vehicle_chassis, const common::VehicleState &vehicle_state, const double current_timestamp, const double planning_cycle_time, const size_t preserved_points_num, const bool replan_by_offset, const PublishableTrajectory *prev_trajectory, std::string *replan_reason, const control::ControlInteractiveMsg &control_interactive_msg)
static std::vector< common::TrajectoryPoint > ComputeControlInteractiveStitchingTrajectory(const double planning_cycle_time, const common::VehicleState &vehicle_state, const common::TrajectoryPoint &time_match_point, const control::ControlInteractiveMsg &control_interactive_msg)
static bool need_replan_by_necessary_check(const common::VehicleState &vehicle_state, const double current_timestamp, const PublishableTrajectory *prev_trajectory, std::string *replan_reason, size_t *time_matched_index)
static std::vector< common::TrajectoryPoint > ComputeReinitStitchingTrajectory(const double planning_cycle_time, const common::VehicleState &vehicle_state)
static void TransformLastPublishedTrajectory(const double x_diff, const double y_diff, const double theta_diff, PublishableTrajectory *prev_trajectory)
static bool need_replan_by_control_interactive(const double current_timestamp, std::string *replan_reason, const control::ControlInteractiveMsg &control_interactive_msg)
Planning module main class.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
#define AWARN
Definition log.h:43
Some util functions.
class register implement
Definition arena_queue.h:37
Contains a number of helper functions related to quaternions.
optional GearPosition gear_location
optional bool parking_brake
Definition chassis.proto:94
optional double timestamp_sec
Definition header.proto:9
optional apollo::canbus::Chassis::DrivingMode driving_mode
optional ReplanRequestReasonCode replan_req_reason_code