Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the wp-statistics domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /www/wwwroot/robotattractor/wp-includes/functions.php on line 6114

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the jetpack domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /www/wwwroot/robotattractor/wp-includes/functions.php on line 6114

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the updraftplus domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /www/wwwroot/robotattractor/wp-includes/functions.php on line 6114
Apollo中的PnC功能详解 – 机器人家园

1 UpdateRoutingResponse函数

  PncMap::UpdateRoutingResponse函数只被reference_line_provider中的CreateReferenceLine函数调用。它的作用是:当有新的Routing结果到来时,用最新的Routing结果初始化PncMap中的一些变量。具体来说,首先遍历Routing结果中我们最关心的数据,即将要行驶的路线。把路线上所有的lane(的id)存放到all_lane_ids_中(注意它被定义成防止出现重复元素的std::unordered_set类型)。变量all_lane_ids_很简单,就是待行驶的路线上所有lane(的id)。

bool PncMap::UpdateRoutingResponse(const routing::RoutingResponse &routing) {
  range_lane_ids_.clear();
  route_indices_.clear();
  all_lane_ids_.clear();
  for (int road_index = 0; road_index < routing.road_size(); ++road_index) {
    const auto &road_segment = routing.road(road_index);
    for (int passage_index = 0; passage_index < road_segment.passage_size(); ++passage_index) {
      const auto &passage = road_segment.passage(passage_index);
      for (int lane_index = 0; lane_index < passage.segment_size(); ++lane_index) {
        all_lane_ids_.insert(passage.segment(lane_index).id());
        route_indices_.emplace_back();
        route_indices_.back().segment = ToLaneSegment(passage.segment(lane_index));
        route_indices_.back().index = {road_index, passage_index, lane_index};
      }
    }
  }

  range_start_ = 0;
  range_end_ = 0;
  adc_route_index_ = -1;
  next_routing_waypoint_index_ = 0;
  UpdateRoutingRange(adc_route_index_);

  routing_waypoint_index_.clear();
  const auto &request_waypoints = routing.routing_request().waypoint();
  int i = 0;
  for (size_t j = 0; j < route_indices_.size(); ++j) {
    while (i < request_waypoints.size() &&
           RouteSegments::WithinLaneSegment(route_indices_[j].segment,
                                            request_waypoints.Get(i))) {
      routing_waypoint_index_.emplace_back(
          LaneWaypoint(route_indices_[j].segment.lane, request_waypoints.Get(i).s()), j);
      ++i;
    }
  }
  routing_ = routing;
  adc_waypoint_ = LaneWaypoint();
  stop_for_destination_ = false;
  return true;
}

  接下来初始化route_indices_变量。这个route_indices_就没那么简单了,它在后面还经常用到。route_indices_元素的index字段存放了lane、passage、road三部分的索引。lane、passage、road三个东西就像套娃,从小到大。

  struct RouteIndex {
    LaneSegment segment;
    std::array index;
  };
  std::vector route_indices_;

2 UpdateRoutingRange函数

  PncMap::UpdateRoutingRange函数的作用是得到剩余Routing路线上包含的lane。剩余Routing路线指的是从自车当前时刻实际位置所在lane的编号(或索引)开始,一直到终点。当然如果自车还未开始运动,那得到的就是整条Routing路线包含的lane。随着自车运动,剩余的routing路线会不断缩短,所以包含的lane也会不断减少。找到的结果存储在range_lane_ids_中。
  其中,在实现上值得注意的是range_lane_ids_这个变量,它不是普通的std::vector,而是std::unordered_set。使用unordered_set而不用vector肯定有原因。unordered_set的特点是其中的元素不会有重复的。所以,range_lane_ids_中能够保证不会有重复的lane。采用unordered_set的另一个目的是防止出现环路(loop),在遍历lane时如果发现它已经在range_lane_ids_中了就立即break退出,不会添加两次。

3 PassageToSegments函数

  顾名思义,PncMap::PassageToSegments函数的作用是根据Routing路由结果中的一段routing::Passage得到一个RouteSegmentsPassage中有若干LaneSegment(proto中的类型),而得到的RouteSegments中也有若干LaneSegmentpath.h中定义的结构体),没有错误的情况下它们的数量也应该是相等的。根据Passage中每个LaneSegment的id,借助高精地图的GetLaneById接口函数拿到了对应的同id的lane的指针。因此,RouteSegments相比routing::Passage不只是单薄的id了,而是包含lane在高精地图中的指针,通过指针可以拿到丰富的lane上的信息,比如左右边界、中心线等等。

bool PncMap::PassageToSegments(routing::Passage passage, RouteSegments *segments) const {
  CHECK_NOTNULL(segments);
  segments->clear();
  for (const auto &lane : passage.segment()) {
    auto lane_ptr = hdmap_->GetLaneById(hdmap::MakeMapId(lane.id()));
    if (!lane_ptr) {
      AERROR << "Failed to find lane: " << lane.id();
      return false;
    }
    segments->emplace_back(lane_ptr, std::max(0.0, lane.start_s()),
                           std::min(lane_ptr->total_length(), lane.end_s()));
  }
  return !segments->empty();
}

  Passage是路由结果中最重要的一个数据结构了,它的定义在routing.proto中,如下。可见,Passage就是若干(收尾相接)的LaneSegment。不用猜,一个LaneSegment就对应一个高精地图中的lane。

message LaneSegment {
  optional string id = 1;
  optional double start_s = 2;
  optional double end_s = 3;
}
message Passage {
  repeated LaneSegment segment = 1;
  optional bool can_exit = 2;
  optional ChangeLaneType change_lane_type = 3 [default = FORWARD];
}

5 GetNearestPointFromRouting函数

  PncMap::GetNearestPointFromRouting函数的作用是找到自车当前在哪条lane上,以及在这条lane上的具体位置(也就是$s$)。首先,根据自车的当前位姿$(x、y、θ)$调用高精地图的GetLanesWithHeading函数寻找一定范围(10米)内的所有lane。这些lane不一定在Routing的路线上,所以要挑选出同时出现在range_lane_ids_中的那些lane,存放到valid_lanes变量中。然后再根据距离找到最近的一条lane,这就是我们想要的结果。

  在实现上使用了一个高级的库函数std::copy_if,但是这行代码的功能很简单,就是在lanes中找出在range_lane_ids_中的那些lane,将其都存到valid_lanes变量中。

std::copy_if(lanes.begin(), lanes.end(), std::back_inserter(valid_lanes),
               [&](LaneInfoConstPtr ptr) {
                 return range_lane_ids_.count(ptr->lane().id().id()) > 0;
               });

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注