接下来继续分析GetWaypointIndex函数
GetWaypointIndex函数
SearchForwardWaypointIndex函数
int LaneFollowMap::SearchForwardWaypointIndex(
int start, const hdmap::LaneWaypoint& waypoint) const {
int i = std::max(start, 0);
while (i < static_cast<int>(route_indices_.size()) &&
!hdmap::RouteSegments::WithinLaneSegment(route_indices_[i].segment,
waypoint)) {
++i;
}
return i;
}route_indices_:的类型是std::vector<RouteIndex>
struct RouteIndex {
apollo::hdmap::LaneSegment segment;
std::array<int, 3> index;
};
上面图示的route_indices_
route_indices_[0].segment = lane0
route_indices_[0].index = {roadsegment0, passage0, lane0}
route_indices_[1].segment = lane1
route_indices_[1].index = {roadsegment1, passage0, lane1}
route_indices_[2].segment = lane2
route_indices_[2].index = {roadsegment1, passage1, lane2}
route_indices_[3].segment = lane3
route_indices_[3].index = {roadsegment1, passage1, lane3}
route_indices_[4].segment = lane4
route_indices_[4].index = {roadsegment1, passage2, lane4}
route_indices_[5].segment = lane5
route_indices_[5].index = {roadsegment2, passage0, lane5}SearchForwardWaypointIndex函数的第一个参数表示的是,当前自车位置在全局路线上的匹配点在route_indices_中的索引,初始化时为-1.第二个参数是我们通过上一篇planning模块(1)-参考线的生成 中介绍的GetNearestPointFromRouting函数获取到的自车位置在全局路线上所对应的waypoint数据 ,SearchForwardWaypointIndex函数的作用就是从前往后搜索route_indices_看自车位置在全局路线上所对应的waypoint是否能和route_indices_中的哪个元素匹配上,然后返回其索引.
SearchBackwardWaypointIndex函数
是从后向前遍历route_indices_搜索,主要是为了容错
if (forward_index == adc_route_index_ ||
forward_index == adc_route_index_ + 1) {
return forward_index;
}如果搜索到的索引在当前adc_route_index_索引附近,说明搜索到的forward_index是合理的,就直接返回forward_index
如果不是在当前adc_route_index_索引附近,并且如果向后搜索到的索引在当前adc_route_index_附近那就返回backward_index更合适,如果向后搜索不到,那就只能返回离当前自车位置比较远的索引forward_index.
UpdateNextRoutingWaypointIndex函数
std::vector<WaypointIndex> routing_waypoint_index_;
struct WaypointIndex {
apollo::hdmap::LaneWaypoint waypoint;
int index;
WaypointIndex(const apollo::hdmap::LaneWaypoint &waypoint, int index)
: waypoint(waypoint), index(index) {}
};routing_waypoint_index_:表示的是算路请求指令中传入的waypoint在route_indices_中的索引等相关信息,routing_waypoint_index_是在UpdatePlanningCommand构建的
modules/planning/pnc_map/lane_follow_map/lane_follow_map.cc
routing_waypoint_index_.clear();
const auto& request_waypoints = routing.routing_request().waypoint();
if (request_waypoints.empty()) {
AERROR << "Invalid routing: no request waypoints.";
return false;
}
int i = 0;
for (size_t j = 0; j < route_indices_.size(); ++j) {
while (i < request_waypoints.size() &&
hdmap::RouteSegments::WithinLaneSegment(route_indices_[j].segment,
request_waypoints.Get(i))) {
routing_waypoint_index_.emplace_back(
hdmap::LaneWaypoint(route_indices_[j].segment.lane,
request_waypoints.Get(i).s()),
j);
++i;
}
}next_routing_waypoint_index_:表示下一个自车要开到的waypoint的索引
while (next_routing_waypoint_index_ != 0 &&
next_routing_waypoint_index_ < routing_waypoint_index_.size() &&
routing_waypoint_index_[next_routing_waypoint_index_].index >
cur_index) {
--next_routing_waypoint_index_;
}如果当前next_routing_waypoint_index_所指向的waypoint在route_indices_索引大于当前自车在route_indices_匹配到的索引,说明在倒车所以next_routing_waypoint_index_要减小
while (next_routing_waypoint_index_ != 0 &&
next_routing_waypoint_index_ < routing_waypoint_index_.size() &&
routing_waypoint_index_[next_routing_waypoint_index_].index ==
cur_index &&
adc_waypoint_.s <
routing_waypoint_index_[next_routing_waypoint_index_].waypoint.s) {
--next_routing_waypoint_index_;发现当前自车waypoint匹配到的索引和当前next_routing_waypoint_index_的索引在一个车道上,并且自车的纵向距离小于当前next_routing_waypoint_index_所表示的waypoint的纵向距离说明也是在倒车next_routing_waypoint_index_要减小
while (next_routing_waypoint_index_ < routing_waypoint_index_.size() &&
routing_waypoint_index_[next_routing_waypoint_index_].index <
cur_index) {
++next_routing_waypoint_index_;
}
while (next_routing_waypoint_index_ < routing_waypoint_index_.size() &&
cur_index ==
routing_waypoint_index_[next_routing_waypoint_index_].index &&
adc_waypoint_.s >=
routing_waypoint_index_[next_routing_waypoint_index_].waypoint.s) {
++next_routing_waypoint_index_;
}上面逻辑类似,是在前行所以next_routing_waypoint_index_要增加
UpdateRoutingRange函数
void LaneFollowMap::UpdateRoutingRange(int adc_index) {
// Track routing range.
range_lane_ids_.clear();
range_start_ = std::max(0, adc_index - 1);
range_end_ = range_start_;
while (range_end_ < static_cast<int>(route_indices_.size())) {
const auto& lane_id = route_indices_[range_end_].segment.lane->id().id();
if (range_lane_ids_.count(lane_id) != 0) {
break;
}
range_lane_ids_.insert(lane_id);
++range_end_;
}
}传入的参数是当前自车waypoint的索引,根据当前自车waypoint的索引,把还没走到的lane_id存入range_lane_ids_,range_lane_ids_中, 走过的的车道就被删掉了.
if (next_routing_waypoint_index_ == routing_waypoint_index_.size() - 1) {
stop_for_destination_ = true;
}当next_routing_waypoint_index_ == routing_waypoint_index_.size() - 1
证明下一个要到达的waypoint是终点了.
到此UpdateVehicleState函数就分析完了.
GetNeighborPassages函数
std::vector<int> LaneFollowMap::GetNeighborPassages(
const routing::RoadSegment& road, int start_passage)road:当前自车位置匹配点所在的roadsegment索引
start_passage:当前自车位置匹配点所在的roadsegment中的所在passage索引


需要注意一下roadsegment中passage的change_lane_type和ExtractBasicPassages函数中passage的change_lane_type不同
上面图示蓝色部分是passage的change_lane_type的构建方式,图标中是roadsegment中的change_lane_type的构建方式
roadsegment0 passage0 node0 FORWARD
roadsegment1 passage0 node1 LEFT
roadsegment1 passage1 node2 node3 RIGHT
roadsegment1 passage2 node4 FORWARD
roadsegment2 passage0 node5 FORWARDGetNeighborPassages函数主要是针对换道的情况,如果当前自车位置在全局路线上所匹配到的位置是上图的node0,那么因为它在roadsegment中的passage的change_lane_type是FORWARD类型所以会直接返回node0所在passage的索引
如果当前自车位置在全局路线上所匹配到的位置是上图的node1,那么因为它在roadsegment中的passage的change_lane_type不是FORWARD就会继续执行下面的逻辑.
如果当前next_routing_waypoint_index_所表示的waypoint也与自车位置在全局路线上所匹配到的位置在同一个车道,同样直接返回当前自车所在passage的索引
如果change_lane_type是routing::LEFT或routing::RIGHT,那就会从map拓扑图中获取到所有当前车道的左右换道邻边的id存入neighbor_lanes中
然后在当前roadsegment中遍历所有passage中的车道,看是否有与neighbor_lanes中匹配的车道,如果存在就把匹配的车道所在的passage id存起来返回.
比如:如果当前自车位置在全局路线上所匹配到的位置是上图的node1那么它所在的passage的change_lane_type是routing::LEFT,那么就会在map的拓扑图中获取到所有它的左侧换道邻边存入neighbor_lanes中,然后在当前roadsegment1中的passage中去查找neighbor_lanes中是否有id相同的车道,比如node2,那么就会把node2所在的passage1的索引存入result中返回,这里返回的result是包含自车所在passage的,如果有符合条件的换道passage,result中也会包含.
这就是GetNeighborPassages函数所做的事情
auto drive_passages = GetNeighborPassages(road, passage_index);
AINFO << "Neighbor passages: " << drive_passages.size();
for (const int index : drive_passages) {
const auto& passage = road.passage(index);
hdmap::RouteSegments segments;
if (!PassageToSegments(passage, &segments)) {
ADEBUG << "Failed to convert passage to lane segments.";
continue;
}
假如车的当前位置如上图,在即将换道的位置,那么通过GetNeighborPassages获取到drive_passages就是roadsegment1的passage0和roadsegment1的passage1
然后遍历drive_passages分别执行下面逻辑
PassageToSegments(passage, &segments)const PointENU nearest_point =
index == passage_index
? adc_waypoint_.lane->GetSmoothPoint(adc_waypoint_.s)
: PointFactory::ToPointENU(adc_state_);GetSmoothPoint函数
还记得一条lane是由很多个点组成的吧,GetSmoothPoint的函数就是根据当前自车所对应的waypoint的纵向距离得到在车道上point的坐标
如果index是当前自车所在匹配的passage,那nearest_point就通过GetSmoothPoint去找平滑点,否则就使用当前来自location模块的自车位置坐标
segments.GetProjection(nearest_point, &sl, &segment_waypoint)获取到最近点在当前passage的所有车道中横向距离最小的位置作为waypoint位置
只有当前遍历的index不是自车所在的passage时CanDriveFrom函数才会被调用,也就意味着只有存在换道的情况时CanDriveFrom函数才会被调用.
CanDriveFrom函数
if (index != passage_index) {
if (!segments.CanDriveFrom(adc_waypoint_)) {
ADEBUG << "You cannot drive from current waypoint to passage: "
<< index;
continue;
}
}还记得吗adc_waypoint_是我们通过planning模块(1)-参考线的生成 GetNearestPointFromRouting函数获取到的.
if (IsWaypointOnSegment(waypoint)) {
return true;
}根据上面图示,当前自车的adc_waypoint_是在node1上,如果index是roadsegment1的passage1,IsWaypointOnSegment(waypoint)是false.
auto point = waypoint.lane->GetSmoothPoint(waypoint.s);
...
LaneWaypoint segment_waypoint;
common::SLPoint route_sl;
bool has_projection = GetProjection(point, &route_sl, &segment_waypoint);
if (!has_projection) {
AERROR << "No projection from waypoint: " << waypoint.DebugString();
return false;
}
static constexpr double kMaxLaneWidth = 10.0;
if (std::fabs(route_sl.l()) > 2 * kMaxLaneWidth) {
return false;
}当index是roadsegment1的passage1时会继续向下执行
根据自车waypoint的纵向距离获取平滑点, 然后通过平滑点获取在roadsegment1的passage1上横向距离最小的投影点waypoint,如果横向距离大于20m认为无法变道
double waypoint_heading = waypoint.lane->Heading(waypoint.s);
double segment_heading = segment_waypoint.lane->Heading(segment_waypoint.s);
double heading_diff =
common::math::AngleDiff(waypoint_heading, segment_heading);
if (std::fabs(heading_diff) > M_PI / 2) {
ADEBUG << "Angle diff too large:" << heading_diff;
return false;
}如果当前自车所在车道与目标车道(变道过去的那条车道)的车道方向角度差大于180,则认为无法变道.
double waypoint_left_width = 0.0;
double waypoint_right_width = 0.0;
waypoint.lane->GetWidth(waypoint.s, &waypoint_left_width,
&waypoint_right_width);
double segment_left_width = 0.0;
double segment_right_width = 0.0;
segment_waypoint.lane->GetWidth(segment_waypoint.s, &segment_left_width,
&segment_right_width);获取自车所在车道的左右空间宽度,获取目标车道左右空间宽度 比如:1.75m

这个空间的宽度是从base_map.txt中的left_sample和right_sample获取到的

auto segment_projected_point =
segment_waypoint.lane->GetSmoothPoint(segment_waypoint.s);
double dist = common::util::DistanceXY(point, segment_projected_point);
const double kLaneSeparationDistance = 0.3;
if (route_sl.l() < 0) { // waypoint at right side
if (dist >
waypoint_left_width + segment_right_width + kLaneSeparationDistance) {
AERROR << "waypoint is too far to reach: " << dist;
return false;
}
} else { // waypoint at left side
if (dist >
waypoint_right_width + segment_left_width + kLaneSeparationDistance) {
AERROR << "waypoint is too far to reach: " << dist;
return false;
}
}获取目标车道自车投影点的平滑点,然后计算自车所在车道上的平滑点,与目标车道投影点之间的距离,如下图红色线

route_sl.l() < 0表示自车在目标车道右侧,否则自车在目标车道左侧
如果自车在目标车道右侧,那么如果dist大于当前车道的左侧空间加上目标车道的右侧空间则无法变道
如果自车在目标车道左侧,那么如果dist大于当前车道的右侧空间加上目标车道的左侧空间则无法变道
这样CanDriveFrom函数就分析完了.