Apollo 11.0
自动驾驶开放平台
stage_precise_parking.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2023 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 <string>
24#include <vector>
25
27
28namespace apollo {
29namespace planning {
30
32
34 const StagePipeline &config,
35 const std::shared_ptr<DependencyInjector> &injector,
36 const std::string &config_dir,
37 void *context) {
38 CHECK_NOTNULL(context);
39 bool ret = Stage::Init(config, injector, config_dir, context);
40 if (!ret) {
41 AERROR << Name() << "init failed!";
42 return false;
43 }
44 precise_parking_context_ = GetContextAs<PreciseParkingContext>();
45 return ret;
46}
47
49 auto *mutable_open_space_info = frame->mutable_open_space_info();
50
51 GetOpenspaceRoi(frame);
53 StageResult result = ExecuteTaskOnOpenSpace(frame);
54 if (result.HasError()) {
55 AERROR << "StagePreceseParking planning error";
57 }
58
59 if (frame->open_space_info().destination_reached()) {
60 AINFO << "StagePreceseParking destination reached";
61 return FinishStage(frame);
62 }
63
65}
66
67StageResult StagePreciseParking::FinishStage(Frame *frame) {
68 next_stage_ = "ARRIVE_PARKING_SPOT";
75}
76
77bool StagePreciseParking::GetOpenspaceRoi(Frame *frame) {
78 const auto &hdmap = hdmap::HDMapUtil::BaseMapPtr();
79 // const auto &junction
80 // =
81 // hdmap->GetJunctionById(hdmap::MakeMapId(precise_parking_context_->precise_parking_command.junction_id()));
82 common::PointENU point;
83 std::vector<hdmap::AreaInfoConstPtr> areas;
84 point.set_x(precise_parking_context_->precise_parking_command.parking_spot_pose().x());
85 point.set_y(precise_parking_context_->precise_parking_command.parking_spot_pose().y());
86 if (hdmap::HDMapUtil::BaseMapPtr()->GetAreas(point, 1e-1, &areas) < 0) {
87 AERROR << "can not find any junction near parking spot";
88 return false;
89 };
90 const auto &area_polygon = areas.front()->polygon();
91
92 double ego_x = injector_->ego_info()->vehicle_state().x();
93 double ego_y = injector_->ego_info()->vehicle_state().y();
94 Vec2d ego_pos(ego_x, ego_y);
95
96 auto points = area_polygon.points();
98 std::reverse(points.begin(), points.end());
99 AINFO << "Junction polygon is anticlockwise";
100
101 SetOrigin(points, ego_pos, frame);
102
103 // get target pose
104 GetEndPose(frame);
105
106 // get roi boundary
107 std::vector<std::vector<common::math::Vec2d>> roi_parking_boundary;
108 std::vector<common::math::Vec2d> parking_point;
109 for (const auto point : points) {
110 parking_point.emplace_back(point.x(), point.y());
111 parking_point.back() -= frame->open_space_info().origin_point();
112 parking_point.back().SelfRotate(-frame->open_space_info().origin_heading());
113 }
114 parking_point.push_back(parking_point.front());
115
116 for (int i = 0; i < parking_point.size() - 1; ++i) {
117 roi_parking_boundary.emplace_back(std::vector<Vec2d>{parking_point.at(i), parking_point.at(i + 1)});
118 }
119
120 // Fuse line segments into convex contraints
121 if (!FuseLineSegments(roi_parking_boundary)) {
122 AERROR << "FuseLineSegments failed in parking ROI";
123 return false;
124 }
125
126 // Get xy boundary
127 auto xminmax = std::minmax_element(
128 parking_point.begin(), parking_point.end(), [](const Vec2d &a, const Vec2d &b) { return a.x() < b.x(); });
129 auto yminmax = std::minmax_element(
130 parking_point.begin(), parking_point.end(), [](const Vec2d &a, const Vec2d &b) { return a.y() < b.y(); });
131 std::vector<double> ROI_xy_boundary{
132 xminmax.first->x(), xminmax.second->x(), yminmax.first->y(), yminmax.second->y()};
133 auto *xy_boundary = frame->mutable_open_space_info()->mutable_ROI_xy_boundary();
134 xy_boundary->assign(ROI_xy_boundary.begin(), ROI_xy_boundary.end());
135
136 ego_pos -= frame->open_space_info().origin_point();
137 ego_pos.SelfRotate(-frame->open_space_info().origin_heading());
138 if (ego_pos.x() < ROI_xy_boundary[0] || ego_pos.x() > ROI_xy_boundary[1] || ego_pos.y() < ROI_xy_boundary[2]
139 || ego_pos.y() > ROI_xy_boundary[3]) {
140 AERROR << "vehicle outside of xy boundary of parking ROI";
141 return false;
142 }
143 if (!FormulateBoundaryConstraints(roi_parking_boundary, frame)) {
144 const std::string msg = "Fail to formulate boundary constraints";
145 AERROR << msg;
146 return false;
147 }
148 return true;
149}
150
151void StagePreciseParking::SetOrigin(const std::vector<Vec2d> &points, const Vec2d &ego_pos, Frame *frame) {
152 auto *previous_frame = injector_->frame_history()->Latest();
153 if (previous_frame->open_space_info().origin_point().x() != 0
154 && previous_frame->open_space_info().origin_point().y() != 0
155 && previous_frame->open_space_info().origin_heading() != 0) {
156 frame->mutable_open_space_info()->set_origin_heading(previous_frame->open_space_info().origin_heading());
157 frame->mutable_open_space_info()->mutable_origin_point()->set_x(
158 previous_frame->open_space_info().origin_point().x());
159 frame->mutable_open_space_info()->mutable_origin_point()->set_y(
160 previous_frame->open_space_info().origin_point().y());
161 } else {
162 double distance = std::numeric_limits<double>::max();
163 int min_index = 0;
164 for (int index = 0; index < points.size(); index++) {
165 const auto &point = points[index];
166 if ((point - ego_pos).Length() < distance) {
167 distance = (point - ego_pos).Length();
168 min_index = index;
169 }
170 }
171 double angle = 0;
172 if (min_index == points.size() - 1) {
173 angle = (points[0] - points[min_index]).Angle();
174 } else {
175 angle = (points[min_index + 1] - points[min_index]).Angle();
176 }
177 frame->mutable_open_space_info()->set_origin_heading(angle);
178 frame->mutable_open_space_info()->mutable_origin_point()->set_x(points[min_index].x());
179 frame->mutable_open_space_info()->mutable_origin_point()->set_y(points[min_index].y());
180 }
181}
182
183void StagePreciseParking::GetEndPose(Frame *frame) {
184 auto parking_spot_pose = precise_parking_context_->precise_parking_command.parking_spot_pose();
185 Vec2d end_pt = Vec2d(parking_spot_pose.x(), parking_spot_pose.y());
186 Vec2d vec = precise_parking_context_->precise_parking_command.parking_inwards()
187 ? precise_parking_context_->scenario_config.precise_trajectory_length()
188 * Vec2d(std::cos(parking_spot_pose.heading()), std::sin(parking_spot_pose.heading())) * -1.0
189 : precise_parking_context_->scenario_config.precise_trajectory_length()
190 * Vec2d(std::cos(parking_spot_pose.heading()), std::sin(parking_spot_pose.heading()));
191 end_pt += vec;
192 const auto &origin_point = frame->open_space_info().origin_point();
193 const auto &origin_heading = frame->open_space_info().origin_heading();
194 end_pt -= origin_point;
195 end_pt.SelfRotate(-origin_heading);
196
197 auto *end_pose = frame->mutable_open_space_info()->mutable_open_space_end_pose();
198 end_pose->push_back(end_pt.x());
199 end_pose->push_back(end_pt.y());
200 end_pose->push_back(parking_spot_pose.heading() - origin_heading);
201 end_pose->push_back(0.0);
202}
203
204bool StagePreciseParking::FuseLineSegments(std::vector<std::vector<common::math::Vec2d>> &line_segments_vec) {
205 static constexpr double kEpsilon = 1.0e-8;
206 auto cur_segment = line_segments_vec.begin();
207 while (cur_segment != line_segments_vec.end() - 1) {
208 auto next_segment = cur_segment + 1;
209 auto cur_last_point = cur_segment->back();
210 auto next_first_point = next_segment->front();
211 // Check if they are the same points
212 if (cur_last_point.DistanceTo(next_first_point) > kEpsilon) {
213 ++cur_segment;
214 continue;
215 }
216 if (cur_segment->size() < 2 || next_segment->size() < 2) {
217 AERROR << "Single point line_segments vec not expected";
218 return false;
219 }
220 size_t cur_segments_size = cur_segment->size();
221 auto cur_second_to_last_point = cur_segment->at(cur_segments_size - 2);
222 auto next_second_point = next_segment->at(1);
223 if (common::math::CrossProd(cur_second_to_last_point, cur_last_point, next_second_point) < 0.0) {
224 cur_segment->push_back(next_second_point);
225 next_segment->erase(next_segment->begin(), next_segment->begin() + 2);
226 if (next_segment->empty()) {
227 line_segments_vec.erase(next_segment);
228 }
229 } else {
230 ++cur_segment;
231 }
232 }
233 return true;
234}
235
236bool StagePreciseParking::FormulateBoundaryConstraints(
237 const std::vector<std::vector<common::math::Vec2d>> &roi_parking_boundary,
238 Frame *const frame) {
239 // Gather vertice needed by warm start and distance approach
240 if (!LoadObstacleInVertices(roi_parking_boundary, frame)) {
241 AERROR << "fail at LoadObstacleInVertices()";
242 return false;
243 }
244 // Transform vertices into the form of Ax>b
245 if (!OpenSpaceRoiUtil::LoadObstacleInHyperPlanes(frame->mutable_open_space_info())) {
246 AERROR << "fail at LoadObstacleInHyperPlanes()";
247 return false;
248 }
249 return true;
250}
251
252bool StagePreciseParking::LoadObstacleInVertices(
253 const std::vector<std::vector<common::math::Vec2d>> &roi_parking_boundary,
254 Frame *const frame) {
255 auto *mutable_open_space_info = frame->mutable_open_space_info();
256 const auto &open_space_info = frame->open_space_info();
257 auto *obstacles_vertices_vec = mutable_open_space_info->mutable_obstacles_vertices_vec();
258 auto *obstacles_edges_num_vec = mutable_open_space_info->mutable_obstacles_edges_num();
259
260 // load vertices for parking boundary (not need to repeat the first
261 // vertice to get close hull)
262 size_t parking_boundaries_num = roi_parking_boundary.size();
263 size_t perception_obstacles_num = 0;
264
265 for (size_t i = 0; i < parking_boundaries_num; ++i) {
266 obstacles_vertices_vec->push_back(roi_parking_boundary[i]);
267 }
268
269 Eigen::MatrixXi parking_boundaries_obstacles_edges_num(parking_boundaries_num, 1);
270 for (size_t i = 0; i < parking_boundaries_num; i++) {
271 if (roi_parking_boundary[i].size() <= 1U) {
272 AERROR << "Roi parking boundary is invalid: " << roi_parking_boundary[i].size();
273 return false;
274 }
275 parking_boundaries_obstacles_edges_num(i, 0) = static_cast<int>(roi_parking_boundary[i].size()) - 1;
276 }
277
278 AINFO << precise_parking_context_->scenario_config.enable_perception_obstacles();
279 if (precise_parking_context_->scenario_config.enable_perception_obstacles()) {
280 if (perception_obstacles_num == 0) {
281 ADEBUG << "no obstacle given by perception";
282 }
283 // load vertices for perception obstacles(repeat the first vertice at the
284 // last to form closed convex hull)
285 const auto &origin_point = open_space_info.origin_point();
286 const auto &origin_heading = open_space_info.origin_heading();
287 ThreadSafeIndexedObstacles *obstacles_by_frame = frame->GetObstacleList();
288 AINFO << obstacles_by_frame->Items().size();
289 for (const auto &obstacle : obstacles_by_frame->Items()) {
290 if (OpenSpaceRoiUtil::FilterOutObstacle(100, *frame, frame->open_space_info().ROI_xy_boundary(), *obstacle)) {
291 AINFO << "obstacle is filtered out";
292 continue;
293 }
294 ++perception_obstacles_num;
295
296 std::vector<Vec2d> vertices_ccw;
297 if (precise_parking_context_->scenario_config.expand_polygon_of_obstacle_by_distance()) {
298 common::math::Polygon2d original_polygon = obstacle->PerceptionPolygon();
299 original_polygon.ExpandByDistance(
300 precise_parking_context_->scenario_config.perception_obstacle_buffer());
301 original_polygon.CalculateVertices(-1.0 * origin_point);
302 vertices_ccw = original_polygon.GetAllVertices();
303 } else {
304 Box2d original_box = obstacle->PerceptionBoundingBox();
305 original_box.Shift(-1.0 * origin_point);
306 original_box.LongitudinalExtend(precise_parking_context_->scenario_config.perception_obstacle_buffer());
307 original_box.LateralExtend(precise_parking_context_->scenario_config.perception_obstacle_buffer());
308 vertices_ccw = original_box.GetAllCorners();
309 }
310
311 // TODO(Jinyun): Check correctness of ExpandByDistance() in polygon
312 // Polygon2d buffered_box(original_box);
313 // buffered_box = buffered_box.ExpandByDistance(
314 // config_.perception_obstacle_buffer());
315 // TODO(Runxin): Rotate from origin instead
316 // original_box.RotateFromCenter(-1.0 * origin_heading);
317
318 std::vector<Vec2d> vertices_cw;
319 while (!vertices_ccw.empty()) {
320 auto current_corner_pt = vertices_ccw.back();
321 current_corner_pt.SelfRotate(-1.0 * origin_heading);
322 vertices_cw.push_back(current_corner_pt);
323 vertices_ccw.pop_back();
324 }
325 // As the perception obstacle is a closed convex set, the first vertice
326 // is repeated at the end of the vector to help transform all four edges
327 // to inequality constraint
328 vertices_cw.push_back(vertices_cw.front());
329 AINFO << "obstacle vertices: " << vertices_cw.size();
330 obstacles_vertices_vec->push_back(vertices_cw);
331 }
332
333 // obstacle boundary box is used, thus the edges are set to be 4
334 Eigen::MatrixXi perception_obstacles_edges_num = 4 * Eigen::MatrixXi::Ones(perception_obstacles_num, 1);
335
336 obstacles_edges_num_vec->resize(
337 parking_boundaries_obstacles_edges_num.rows() + perception_obstacles_edges_num.rows(), 1);
338 *(obstacles_edges_num_vec) << parking_boundaries_obstacles_edges_num, perception_obstacles_edges_num;
339
340 } else {
341 obstacles_edges_num_vec->resize(parking_boundaries_obstacles_edges_num.rows(), 1);
342 *(obstacles_edges_num_vec) << parking_boundaries_obstacles_edges_num;
343 }
344
345 mutable_open_space_info->set_obstacles_num(parking_boundaries_num + perception_obstacles_num);
346 return true;
347}
348
349} // namespace planning
350} // namespace apollo
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
static const HDMap * BaseMapPtr()
Frame holds all data for one planning cycle.
Definition frame.h:62
const OpenSpaceInfo & open_space_info() const
Definition frame.h:167
OpenSpaceInfo * mutable_open_space_info()
Definition frame.h:169
void set_is_on_open_space_trajectory(const bool flag)
DiscretizedTrajectory * mutable_path_planning_trajectory_result()
DiscretizedTrajectory * mutable_interpolated_trajectory_result()
DiscretizedTrajectory * mutable_optimizer_trajectory_data()
TrajGearPair * mutable_chosen_partitioned_trajectory()
std::vector< TrajGearPair > * mutable_partitioned_trajectories()
static bool AdjustPointsOrderToClockwise(std::vector< Vec2d > *polygon)
static bool LoadObstacleInHyperPlanes(OpenSpaceInfo *const open_space_info)
brief Transform the vertice presentation of the obstacles into linear inequality as Ax>b
static bool FilterOutObstacle(const double filtering_distance, const Frame &frame, const std::vector< double > &xy_boundary, const Obstacle &obstacle)
is obstacle can be filterd out, filtered by distance and roi XY bound
StageResult Process(const common::TrajectoryPoint &planning_init_point, Frame *frame) override
Each stage does its business logic inside Process function.
bool Init(const StagePipeline &config, const std::shared_ptr< DependencyInjector > &injector, const std::string &config_dir, void *context)
const StageResult & SetStageStatus(const StageStatusType &stage_status)
Set the stage status.
bool HasError() const
Check if StageResult contains error.
std::string next_stage_
Definition stage.h:89
StageResult ExecuteTaskOnOpenSpace(Frame *frame)
Definition stage.cc:206
virtual bool Init(const StagePipeline &config, const std::shared_ptr< DependencyInjector > &injector, const std::string &config_dir, void *context)
Definition stage.cc:43
std::shared_ptr< DependencyInjector > injector_
Definition stage.h:91
const std::string & Name() const
Definition stage.cc:99
Planning module main class.
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
double CrossProd(const Vec2d &start_point, const Vec2d &end_point_1, const Vec2d &end_point_2)
Cross product between two 2-D vectors from the common start point, and end at two other points.
Definition math_utils.cc:28
ThreadSafeIndexedList< std::string, Obstacle > ThreadSafeIndexedObstacles
Definition obstacle.h:294
class register implement
Definition arena_queue.h:37
apollo::external_command::PreciseParkingCommand precise_parking_command