Apollo源码

news2024/11/20 9:48:50
目录结构介绍
cyber  消息中间件,替换ros作为消息层
data  地图等生成好的数据放在这里(其他数据待补充)
docker 容器相关
docs 文档相关
modules 定位,预测,感知,规划等自动驾驶模块
scripts 脚本
third_party 第三方库
tools 工具目录,几乎为空

Cyber模块

Cyber main函数中先根据命令行信息解析dag参数,然后利用解析的参数,动态的加载对应的模块

输入:命令行数量+命令行内容

输出:加载状态

关联模块:All

mainboard.cc

/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
#include "cyber/common/global_data.h"
#include "cyber/common/log.h"
#include "cyber/init.h"
#include "cyber/mainboard/module_argument.h"
#include "cyber/mainboard/module_controller.h"
#include "cyber/state.h"
using apollo::cyber::mainboard::ModuleArgument;
using apollo::cyber::mainboard::ModuleController;
int main(int argc, char** argv)//命令行参数的数量与内容
{
  //解析参数
  ModuleArgument module_args;
  1.module_args.ParseArgument(argc, argv);//输出解析结果
  //初始化环境
  apollo::cyber::Init(argv[0]); 
  ModuleController controller(module_args);
  //Init中启动LoadAll,若启动失败
  3.if (!controller.Init())
  {
    controller.Clear();
    AERROR << "module start error.";
    return -1;
  }
  //等待关闭
  apollo::cyber::WaitForShutdown();
  //卸载模块
  controller.Clear();
  AINFO << "exit mainboard.";
  return 0;
}

ParseArgument(输出解析信息)

  void ModuleArgument::ParseArgument(const int argc, char* const argv[])
  {
  binary_name_ = std::string(basename(argv[0]));
  //解析命令行参数,根据不同的选项设置相应的变量值,以供程序后续使用(存入dag_conf_list)
  2.GetOptions(argc, argv);
  if (process_group_.empty())
  {
    process_group_ = DEFAULT_process_group_;
  }
  if (sched_name_.empty())
  {
    sched_name_ = DEFAULT_sched_name_;
  }
  //设定process_group和sched_name,若没有则为默认值
  GlobalData::Instance()->SetProcessGroup(process_group_);
  GlobalData::Instance()->SetSchedName(sched_name_);
  AINFO << "binary_name_ is " << binary_name_ << ", process_group_ is "
        << process_group_ << ", has " << dag_conf_list_.size() << " dag conf";
  //从dag_conf_list读取字符串到dag中并打印
  for (std::string& dag : dag_conf_list_)
  {
    AINFO << "dag_conf: " << dag;
  }
}

GetOptions(获取选项设定值)

void ModuleArgument::GetOptions(const int argc, char* const argv[]) {
  opterr = 0;//外部全局变量
  int long_index = 0;
  //定义长短选项,根据输入选择不同操作
  const std::string short_opts = "hd:p:s:";
  static const struct option long_opts[] = {
      {"help", no_argument, nullptr, 'h'},
      {"dag_conf", required_argument, nullptr, 'd'},
      {"process_name", required_argument, nullptr, 'p'},
      {"sched_name", required_argument, nullptr, 's'},
      {NULL, no_argument, nullptr, 0}};
  //命令记录
  std::string cmd("");
  for (int i = 0; i < argc; ++i) {
    cmd += argv[i];
    cmd += " ";
  }
  AINFO << "command: " << cmd;
  if (1 == argc) {
    DisplayUsage();
    exit(0);
  }
  //根据类型执行
  do {
    int opt =getopt_long(argc, argv, short_opts.c_str(), long_opts, &long_index);
    if (opt == -1) {
      break;
    }
    switch (opt) {
      //存储路径
      case 'd':
        dag_conf_list_.emplace_back(std::string(optarg));
        for (int i = optind; i < argc; i++) {
          if (*argv[i] != '-') {
            dag_conf_list_.emplace_back(std::string(argv[i]));
          } else {
            break;
          }
        }
        break;
      case 'p':
        process_group_ = std::string(optarg);
        break;
      case 's':
        sched_name_ = std::string(optarg);
        break;
      case 'h':
        DisplayUsage();
        exit(0);
      default:
        break;
    }
  } while (true);
  if (optind < argc) {
    AINFO << "Found non-option ARGV-element \"" << argv[optind++] << "\"";
    DisplayUsage();
    exit(1);
  }
  if (dag_conf_list_.empty()) {
    AINFO << "-d parameter must be specified";
    DisplayUsage();
    exit(1);
  }
}

LoadAll(加载所有模块)

bool ModuleController::LoadAll()//加载所有模块(生成路径,调用)
{
  //获取根目录
  4.const std::string work_root = common::WorkRoot();
  //获取当前工作目录
  const std::string current_path = common::GetCurrentPath();
  //获取绝对路径
  const std::string dag_root_path = common::GetAbsolutePath(work_root, "dag");
  std::vector<std::string> paths;
  for (auto& dag_conf : args_.GetDAGConfList())
  {
    std::string module_path = "";
    if (dag_conf == common::GetFileName(dag_conf))
    {
    //dag_conf为文件名,则拼接路径
      module_path = common::GetAbsolutePath(dag_root_path, dag_conf);
    } else if (dag_conf[0] == '/')
    {
      //dag_conf为绝对路径
      module_path = dag_conf;
    } else
    {
      //dag_conf为相对路径
      module_path = common::GetAbsolutePath(current_path, dag_conf);
      if (!common::PathExists(module_path))
      {
        module_path = common::GetAbsolutePath(work_root, dag_conf);
      }
    }
    total_component_nums += GetComponentNum(module_path);
    paths.emplace_back(std::move(module_path));
  }
  if (has_timer_component)
  {
    total_component_nums += scheduler::Instance()->TaskPoolSize();
  }
  //将结果转变为全局变量
  common::GlobalData::Instance()->SetComponentNums(total_component_nums);
  for (auto module_path : paths)
  {
    AINFO << "Start initialize dag: " << module_path;
    //加载模块失败
    if (!LoadModule(module_path))
    {
      AERROR << "Failed to load module: " << module_path;
      return false;
    }
  }
  return true;
}

WorkRoot(获取根目录)

inline const std::string WorkRoot()
{
  //检索环境变量CYBER_PATH
  std::string work_root = GetEnv("CYBER_PATH");
  if (work_root.empty())
  {
    work_root = "/apollo/cyber";
  }
  return work_root;
}

Map模块

在这里插入图片描述去年的文件结构如上所示,8.0版本去除了proto部分,所以地图各元素的消息格式暂时未知

Localization模块

Localization模块主要实现车辆的位置(Planning模块)与车辆的姿态、速度信息(Control模块)

输入:IMU与GPS传感器信息

输出:Localization实例

关联模块:Planning+Control

rtk_localization.cc(待补:rtk_localization_component.cc)

void RTKLocalization::GpsCallback(
    const std::shared_ptr<localization::Gps> &gps_msg) {
    //获取延迟
  double time_delay = last_received_timestamp_sec_
                          ? Clock::NowInSeconds() - last_received_timestamp_sec_
                          : last_received_timestamp_sec_;
  //超出时间则提出警告
  if (time_delay > gps_time_delay_tolerance_) {
    std::stringstream ss;
    ss << "GPS message time interval: " << time_delay;
    monitor_logger_.WARN(ss.str());
  }
  //处理错误
  {
    //互斥访问惯性信息
    std::unique_lock<std::mutex> lock(imu_list_mutex_);
    if (imu_list_.empty()) {
      AERROR << "IMU message buffer is empty.";
      if (service_started_) {
        monitor_logger_.ERROR("IMU message buffer is empty.");
      }
      return;
    }
  }
  {
    //互斥访问GPS状态信息
    std::unique_lock<std::mutex> lock(gps_status_list_mutex_);
    if (gps_status_list_.empty()) {
      AERROR << "Gps status message buffer is empty.";
      if (service_started_) {
        monitor_logger_.ERROR("Gps status message buffer is empty.");
      }
      return;
    }
  }
  //发布定位信息
 1. PrepareLocalizationMsg(*gps_msg, &last_localization_result_,&last_localization_status_result_);
  service_started_ = true;
  if (service_started_time == 0.0) {
    service_started_time = Clock::NowInSeconds();
  }
  //监视运行状况
  RunWatchDog(gps_msg->header().timestamp_sec());
  last_received_timestamp_sec_ = Clock::NowInSeconds();
  }

PrepareLocalizationMsg(准备建定位消息)

void RTKLocalization::PrepareLocalizationMsg(const localization::Gps &gps_msg, LocalizationEstimate *localization,LocalizationStatus *localization_status)
{
  //寻找匹配的GPS和IMU消息
  double gps_time_stamp = gps_msg.header().timestamp_sec();
  CorrectedImu imu_msg;
  2.FindMatchingIMU(gps_time_stamp, &imu_msg);
  3.ComposeLocalizationMsg(gps_msg, imu_msg, localization);//组成定位信息
  drivers::gnss::InsStat gps_status;
  FindNearestGpsStatus(gps_time_stamp, &gps_status);//寻找最近的GPS状态
  4.FillLocalizationStatusMsg(gps_status, localization_status);
}

FindMatchingIMU(寻找匹配的IMU)

bool RTKLocalization::FindMatchingIMU(const double gps_timestamp_sec,CorrectedImu *imu_msg) {
  if (imu_msg == nullptr) {
    AERROR << "imu_msg should NOT be nullptr.";
    return false;
  }
  std::unique_lock<std::mutex> lock(imu_list_mutex_);
  auto imu_list = imu_list_;
  lock.unlock();
  if (imu_list.empty()) {
    AERROR << "Cannot find Matching IMU. "<< "IMU message Queue is empty! GPS timestamp[" << gps_timestamp_sec<< "]";
    return false;
  }
  //扫描IMU缓冲区,寻找时间戳更新的消息
  auto imu_it = imu_list.begin();
  for (; imu_it != imu_list.end(); ++imu_it) {
    if ((*imu_it).header().timestamp_sec() - gps_timestamp_sec >std::numeric_limits<double>::min()) {
      break;
    }
  }
  //目标存在
  if (imu_it != imu_list.end()) {
    if (imu_it == imu_list.begin()) {
      AERROR << "IMU queue too short or request too old. "
             << "Oldest timestamp[" << imu_list.front().header().timestamp_sec()
             << "], Newest timestamp["
             << imu_list.back().header().timestamp_sec() << "], GPS timestamp["
             << gps_timestamp_sec << "]";
      *imu_msg = imu_list.front();
    } 
    else {
      //正常情况
      auto imu_it_1 = imu_it;
      imu_it_1--;
      if (!(*imu_it).has_header() || !(*imu_it_1).has_header()) {
        AERROR << "imu1 and imu_it_1 must both have header.";
        return false;
      }
      //插值,同步imu与gps
      if (!InterpolateIMU(*imu_it_1, *imu_it, gps_timestamp_sec, imu_msg)) {
        AERROR << "failed to interpolate IMU";
        return false;
      }
    }
  } 
  else {
    //所有数据时间戳都在请求时间戳之前,则提供最新的IMU数据,不进行外推
    *imu_msg = imu_list.back();
    if (imu_msg == nullptr) {
      AERROR << "Fail to get latest observed imu_msg.";
      return false;
    }
    if (!imu_msg->has_header()) {
      AERROR << "imu_msg must have header.";
      return false;
    }
    if (std::fabs(imu_msg->header().timestamp_sec() - gps_timestamp_sec) > gps_imu_time_diff_threshold_) {
      //报错阈值为20ms
      AERROR << "Cannot find Matching IMU. IMU messages too old. "
             << "Newest timestamp[" << imu_list.back().header().timestamp_sec()
             << "], GPS timestamp[" << gps_timestamp_sec << "]";
    }
  }
  return true;
}

ComposeLocalizationMsg(获取Localization并坐标变换)

void RTKLocalization::ComposeLocalizationMsg(const localization::Gps &gps_msg, const localization::CorrectedImu &imu_msg,LocalizationEstimate *localization) {
  localization->Clear();
  FillLocalizationMsgHeader(localization);
  localization->set_measurement_time(gps_msg.header().timestamp_sec());
  //结合GPS与IMU
  auto mutable_pose = localization->mutable_pose();
  if (gps_msg.has_localization()) {
    const auto &pose = gps_msg.localization();
    if (pose.has_position()) {
      //position为localization的一部分,以下代码可实现world frame -> map frame
      mutable_pose->mutable_position()->set_x(pose.position().x() -map_offset_[0]);
      mutable_pose->mutable_position()->set_y(pose.position().y() -map_offset_[1]);
      mutable_pose->mutable_position()->set_z(pose.position().z() -map_offset_[2]);
    }
    //orientation,四元数转化为航向角
    if (pose.has_orientation()) {
      mutable_pose->mutable_orientation()->CopyFrom(pose.orientation());
      double heading = common::math::QuaternionToHeading(pose.orientation().qw(), pose.orientation().qx(),pose.orientation().qy(), pose.orientation().qz());
      mutable_pose->set_heading(heading);
    }
    //线速度
    if (pose.has_linear_velocity()) {
      mutable_pose->mutable_linear_velocity()->CopyFrom(pose.linear_velocity());
    }
  }
  if (imu_msg.has_imu()) {
    const auto &imu = imu_msg.imu();
    //线加速度
    if (imu.has_linear_acceleration()) {
      if (localization->pose().has_orientation()) {
        //将车辆坐标系中的位置信息转换为地图坐标系中的位置信息
        Vector3d orig(imu.linear_acceleration().x(),imu.linear_acceleration().y(),imu.linear_acceleration().z());
        Vector3d vec = common::math::QuaternionRotate(localization->pose().orientation(), orig);
        mutable_pose->mutable_linear_acceleration()->set_x(vec[0]);
        mutable_pose->mutable_linear_acceleration()->set_y(vec[1]);
        mutable_pose->mutable_linear_acceleration()->set_z(vec[2]);
        //车辆坐标系线加速度
        mutable_pose->mutable_linear_acceleration_vrf()->CopyFrom(imu.linear_acceleration());
      }
      else {
        AERROR << "[PrepareLocalizationMsg]: "<< "fail to convert linear_acceleration";
      }
    }
    //角速度ω
    if (imu.has_angular_velocity()) {
      if (localization->pose().has_orientation()) {
        //convert from vehicle reference to map reference(同上)
        Vector3d orig(imu.angular_velocity().x(), imu.angular_velocity().y(),
                      imu.angular_velocity().z());
        Vector3d vec = common::math::QuaternionRotate(
            localization->pose().orientation(), orig);
        mutable_pose->mutable_angular_velocity()->set_x(vec[0]);
        mutable_pose->mutable_angular_velocity()->set_y(vec[1]);
        mutable_pose->mutable_angular_velocity()->set_z(vec[2]);
        //车辆坐标系角加速度
        mutable_pose->mutable_angular_velocity_vrf()->CopyFrom(
            imu.angular_velocity());
      } else {
        AERROR << "[PrepareLocalizationMsg]: fail to convert angular_velocity";
      }
    }
    //欧拉角
    if (imu.has_euler_angles()) {
      mutable_pose->mutable_euler_angles()->CopyFrom(imu.euler_angles());
    }
  }
}

FillLocalizationStatusMsg(填充Localization中的GNSS状态)

void RTKLocalization::FillLocalizationStatusMsg(const drivers::gnss::InsStat &status,LocalizationStatus *localization_status) {
  apollo::common::Header *header = localization_status->mutable_header();
  double timestamp = apollo::cyber::Clock::NowInSeconds();
  header->set_timestamp_sec(timestamp);
  localization_status->set_measurement_time(status.header().timestamp_sec());
  //检查是否包含位置信息
  if (!status.has_pos_type()) {
    localization_status->set_fusion_status(MeasureState::ERROR);
    localization_status->set_state_message("Error: Current Localization Status Is Missing.");
    return;
  }
  //根据GNSS(GPS)的不同解决方案设置状态
  auto pos_type = static_cast<drivers::gnss::SolutionType>(status.pos_type());
  switch (pos_type) {
    case drivers::gnss::SolutionType::INS_RTKFIXED://差分固定解,亚厘米级精度
      localization_status->set_fusion_status(MeasureState::OK);
      localization_status->set_state_message("");
      break;
    case drivers::gnss::SolutionType::INS_RTKFLOAT://差分浮动解,无法稳定提供差分固定解时的方案
      localization_status->set_fusion_status(MeasureState::WARNNING);
      localization_status->set_state_message("Warning: Current Localization Is Unstable.");
      break;
    default:
      localization_status->set_fusion_status(MeasureState::ERROR);
      localization_status->set_state_message("Error: Current Localization Is Very Unstable.");
      break;
  }
}

Planning模块

Planning模块的作用是根据感知(Prediction)预测的结果,当前的车辆信息和路况规划出一条车辆能够行驶的轨迹,继而交给控制(Control)模块执行

输入:

  1. 预测的障碍物信息(prediction_obstacles)
  2. 车辆底盘(Chassis)信息(车辆的速度,加速度,航向角等信息)
  3. 车辆当前位置(localization_estimate)

输出:规划的路径

关联模块:Control+Localization+Prediction+Routing

planning_component.cc

bool PlanningComponent::Init() {
  //两种模式注册
  injector_ = std::make_shared<DependencyInjector>();
  if (FLAGS_use_navigation_mode) {
    planning_base_ = std::make_unique<NaviPlanning>(injector_);//导航级别路径规划
  } else {
    planning_base_ = std::make_unique<OnLanePlanning>(injector_);//车道级别路径规划
  }
  //配置文件加载
  ACHECK(ComponentBase::GetProtoConfig(&config_))
      << "failed to load planning config file "
      << ComponentBase::ConfigFilePath();
  if (FLAGS_planning_offline_learning ||config_.learning_mode() != PlanningConfig::NO_LEARNING) {
    if (!message_process_.Init(config_, injector_)) {
      AERROR << "failed to init MessageProcess";
      return false;
    }
  }
  planning_base_->Init(config_);
  //订阅Routing模块信息
  routing_reader_ = node_->CreateReader<RoutingResponse>(
      config_.topic_config().routing_response_topic(),
      [this](const std::shared_ptr<RoutingResponse>& routing) {
        AINFO << "Received routing data: run routing callback."
              << routing->header().DebugString();
        std::lock_guard<std::mutex> lock(mutex_);
        routing_.CopyFrom(*routing);
      });
  //读取红绿灯信息
  traffic_light_reader_ = node_->CreateReader<TrafficLightDetection>(
      config_.topic_config().traffic_light_detection_topic(),
      [this](const std::shared_ptr<TrafficLightDetection>& traffic_light) {
        ADEBUG << "Received traffic light data: run traffic light callback.";
        std::lock_guard<std::mutex> lock(mutex_);
        traffic_light_.CopyFrom(*traffic_light);
      });
  //订阅pad消息
  pad_msg_reader_ = node_->CreateReader<PadMessage>(
      config_.topic_config().planning_pad_topic(),
      [this](const std::shared_ptr<PadMessage>& pad_msg) {
        ADEBUG << "Received pad data: run pad callback.";
        std::lock_guard<std::mutex> lock(mutex_);
        pad_msg_.CopyFrom(*pad_msg);
      });
  //订阅Story_telling模块信息
  story_telling_reader_ = node_->CreateReader<Stories>(
      config_.topic_config().story_telling_topic(),
      [this](const std::shared_ptr<Stories>& stories) {
        ADEBUG << "Received story_telling data: run story_telling callback.";
        std::lock_guard<std::mutex> lock(mutex_);
        stories_.CopyFrom(*stories);
      });
  //若使用导航级别路径规划,则读取相对地图
  if (FLAGS_use_navigation_mode) {
    relative_map_reader_ = node_->CreateReader<MapMsg>(
        config_.topic_config().relative_map_topic(),
        [this](const std::shared_ptr<MapMsg>& map_message) {
          ADEBUG << "Received relative map data: run relative map callback.";
          std::lock_guard<std::mutex> lock(mutex_);
          relative_map_.CopyFrom(*map_message);
        });
  }
  //发布规划好的线路
  planning_writer_ = node_->CreateWriter<ADCTrajectory>(config_.topic_config().planning_trajectory_topic());
  //发布重新Routing请求
  rerouting_writer_ = node_->CreateWriter<RoutingRequest>(config_.topic_config().routing_request_topic());
  //发布规划学习数据(?)
  planning_learning_data_writer_ = node_->CreateWriter<PlanningLearningData>(config_.topic_config().planning_learning_data_topic());
  return true;
}
bool PlanningComponent::Proc(
    const std::shared_ptr<prediction::PredictionObstacles>&prediction_obstacles,
    const std::shared_ptr<canbus::Chassis>& chassis,
    const std::shared_ptr<localization::LocalizationEstimate>&localization_estimate) {
  ACHECK(prediction_obstacles != nullptr);
  //检查并执行可能的重新Routing请求
  CheckRerouting();
  //处理融合后输入数据
  local_view_.prediction_obstacles = prediction_obstacles;
  local_view_.chassis = chassis;
  local_view_.localization_estimate = localization_estimate;
  //更新Routing状态,数据放入local_view
  {
    std::lock_guard<std::mutex> lock(mutex_);
    if (!local_view_.routing ||hdmap::PncMap::IsNewRouting(*local_view_.routing, routing_)) {
      local_view_.routing =std::make_shared<routing::RoutingResponse>(routing_);
    }
  }
  {
    std::lock_guard<std::mutex> lock(mutex_);
    local_view_.traffic_light =std::make_shared<TrafficLightDetection>(traffic_light_);
    local_view_.relative_map = std::make_shared<MapMsg>(relative_map_);
  }
  {
    std::lock_guard<std::mutex> lock(mutex_);
    local_view_.pad_msg = std::make_shared<PadMessage>(pad_msg_);
  }
  {
    std::lock_guard<std::mutex> lock(mutex_);
    local_view_.stories = std::make_shared<Stories>(stories_);
  }
  if (!CheckInput()) {
    AERROR << "Input check failed";
    return false;
  }
  //在线训练的数据处理
  if (config_.learning_mode() != PlanningConfig::NO_LEARNING) {
    message_process_.OnChassis(*local_view_.chassis);
    message_process_.OnPrediction(*local_view_.prediction_obstacles);
    message_process_.OnRoutingResponse(*local_view_.routing);
    message_process_.OnStoryTelling(*local_view_.stories);
    message_process_.OnTrafficLightDetection(*local_view_.traffic_light);
    message_process_.OnLocalization(*local_view_.localization_estimate);
  }
  //发布用于RL测试的数据
  if (config_.learning_mode() == PlanningConfig::RL_TEST) {
    PlanningLearningData planning_learning_data;
    LearningDataFrame* learning_data_frame =injector_->learning_based_data()->GetLatestLearningDataFrame();
    if (learning_data_frame) {
      planning_learning_data.mutable_learning_data_frame()
                            ->CopyFrom(*learning_data_frame);
      common::util::FillHeader(node_->Name(), &planning_learning_data);
      planning_learning_data_writer_->Write(planning_learning_data);
    } else {
      AERROR << "fail to generate learning data frame";
      return false;
    }
    return true;
  }
  //执行注册好的Planning,生成线路
  ADCTrajectory adc_trajectory_pb;
  //生成一次路径,将结果存储在adc_trajectory_pb中
  planning_base_->RunOnce(local_view_, &adc_trajectory_pb);
  auto start_time = adc_trajectory_pb.header().timestamp_sec();
  common::util::FillHeader(node_->Name(), &adc_trajectory_pb);
  //根据header时间戳的变化修改轨迹相对时间
  const double dt = start_time - adc_trajectory_pb.header().timestamp_sec();
  for (auto& p : *adc_trajectory_pb.mutable_trajectory_point()) {
    p.set_relative_time(p.relative_time() + dt);
  }
  //发布生成的路径
  planning_writer_->Write(adc_trajectory_pb);
  //加入历史记录
  auto* history = injector_->history();
  history->Add(adc_trajectory_pb);
  return true;
}

Control模块

Control模块的作用是根据规划(Planning)模块生成的轨迹,计算出汽车的油门,刹车和方向盘信号,控制汽车按照规定的轨迹行驶

输入:车辆底盘(Chassis)信息, 位置信息(LocalizationEstimate), Planning模块规划的轨迹(ADCTrajectory)

输出:油门、刹车、方向盘控制(ControlCommand)

关联模块:Planning+Localization

control_component.cc

bool ControlComponent::Init() {
  //订阅Chassis信息
  cyber::ReaderConfig chassis_reader_config;
  chassis_reader_config.channel_name = FLAGS_chassis_topic;
  chassis_reader_config.pending_queue_size = FLAGS_chassis_pending_queue_size;
  chassis_reader_ =node_->CreateReader<Chassis>(chassis_reader_config, nullptr);
  ACHECK(chassis_reader_ != nullptr);
  //订阅Planning信息
  cyber::ReaderConfig planning_reader_config;
  planning_reader_config.channel_name = FLAGS_planning_trajectory_topic;
  planning_reader_config.pending_queue_size = FLAGS_planning_pending_queue_size;
  trajectory_reader_ =node_->CreateReader<ADCTrajectory>(planning_reader_config, nullptr);
  ACHECK(trajectory_reader_ != nullptr);
  //订阅Localization信息
  cyber::ReaderConfig localization_reader_config;
  localization_reader_config.channel_name = FLAGS_localization_topic;
  localization_reader_config.pending_queue_size =
      FLAGS_localization_pending_queue_size;
  localization_reader_ = node_->CreateReader<LocalizationEstimate>(localization_reader_config, nullptr);
  ACHECK(localization_reader_ != nullptr);
}
bool ControlComponent::Proc() {
  //读取各模块数据
  const auto start_time = Clock::Now();
  chassis_reader_->Observe();
  const auto &chassis_msg = chassis_reader_->GetLatestObserved();
  if (chassis_msg == nullptr) {
    AERROR << "Chassis msg is not ready!";
    return false;
  }
  OnChassis(chassis_msg);
  trajectory_reader_->Observe();
  const auto &trajectory_msg = trajectory_reader_->GetLatestObserved();
  if (trajectory_msg == nullptr) {
    AERROR << "planning msg is not ready!";
    return false;
  }
  //为什么判断???
  if (latest_trajectory_.header().sequence_num() !=trajectory_msg->header().sequence_num()) {
    OnPlanning(trajectory_msg);
  }
  localization_reader_->Observe();
  const auto &localization_msg = localization_reader_->GetLatestObserved();
  if (localization_msg == nullptr) {
    AERROR << "localization msg is not ready!";
    return false;
  }
  OnLocalization(localization_msg);
  pad_msg_reader_->Observe();
  const auto &pad_msg = pad_msg_reader_->GetLatestObserved();
  if (pad_msg != nullptr) {
    OnPad(pad_msg);
  }
/*TODO(SHU):避免冗余拷贝
  {  
    std::lock_guard<std::mutex> lock(mutex_);
    local_view_.mutable_chassis()->CopyFrom(latest_chassis_);
    local_view_.mutable_trajectory()->CopyFrom(latest_trajectory_);
    local_view_.mutable_localization()->CopyFrom(latest_localization_);
    if (pad_msg != nullptr) {
      local_view_.mutable_pad_msg()->CopyFrom(pad_msg_);
    }
  }
  //若使用Control子模块
  if (FLAGS_use_control_submodules) {
    local_view_.mutable_header()->set_lidar_timestamp(local_view_.trajectory().header().lidar_timestamp());
    local_view_.mutable_header()->set_camera_timestamp(local_view_.trajectory().header().camera_timestamp());
    local_view_.mutable_header()->set_radar_timestamp(local_view_.trajectory().header().radar_timestamp());
    common::util::FillHeader(FLAGS_control_local_view_topic, &local_view_);
    const auto end_time = Clock::Now();
    //测量延迟
    static apollo::common::LatencyRecorder latency_recorder(FLAGS_control_local_view_topic);
    latency_recorder.AppendLatencyRecord(local_view_.trajectory().header().lidar_timestamp(), start_time,end_time);
    local_view_writer_->Write(local_view_);
    return true;
  }
  //处理pad_msg
  if (pad_msg != nullptr) {
    ADEBUG << "pad_msg: " << pad_msg_.ShortDebugString();
    if (pad_msg_.action() == DrivingAction::RESET) {
      AINFO << "Control received RESET action!";
      estop_ = false;
      estop_reason_.clear();
    }
    pad_received_ = true;
  }
  //结束测试
  if (control_conf_.is_control_test_mode() &&control_conf_.control_test_duration() > 0 &&
      (start_time - init_time_).ToSecond() >control_conf_.control_test_duration()) {
    AERROR << "Control finished testing. exit";
    return false;
  }*/
  //生成控制命令
  ControlCommand control_command;
  Status status;
  if (local_view_.chassis().driving_mode() == apollo::canbus::Chassis::COMPLETE_AUTO_DRIVE) {
    1.status = ProduceControlCommand(&control_command);
  } else {
    //重置车辆控制状态
    ResetAndProduceZeroControlCommand(&control_command);
  }
  AERROR_IF(!status.ok()) << "Failed to produce control command:" << status.error_message();
  if (pad_received_) {
    control_command.mutable_pad_msg()->CopyFrom(pad_msg_);
    pad_received_ = false;
  }
  //在Control框架下发布紧急制动原因并设置头部信息
  if (estop_) {
    control_command.mutable_header()->mutable_status()->set_msg(estop_reason_);
  }
  control_command.mutable_header()->set_lidar_timestamp(local_view_.trajectory().header().lidar_timestamp());
  control_command.mutable_header()->set_camera_timestamp(local_view_.trajectory().header().camera_timestamp());
  control_command.mutable_header()->set_radar_timestamp(local_view_.trajectory().header().radar_timestamp());
  common::util::FillHeader(node_->Name(), &control_command);
  ADEBUG << control_command.ShortDebugString();
  //测试模式下不发布控制命令
  if (control_conf_.is_control_test_mode()) {
    ADEBUG << "Skip publish control command in test mode";
    return true;
  }
  //计算时间开销(ms为单位)
  const auto end_time = Clock::Now();
  const double time_diff_ms = (end_time - start_time).ToSecond() * 1e3;
  ADEBUG << "total control time spend: " << time_diff_ms << " ms.";
  control_command.mutable_latency_stats()->set_total_time_ms(time_diff_ms);
  control_command.mutable_latency_stats()->set_total_time_exceeded(time_diff_ms > control_conf_.control_period() * 1e3);
  ADEBUG << "control cycle time is: " << time_diff_ms << " ms.";
  status.Save(control_command.mutable_header()->mutable_status());
  //测量延迟
  if (local_view_.trajectory().header().has_lidar_timestamp()) {
    static apollo::common::LatencyRecorder latency_recorder(FLAGS_control_command_topic);
    latency_recorder.AppendLatencyRecord(local_view_.trajectory().header().lidar_timestamp(), start_time, end_time);
  }
  //发布控制命令
  control_cmd_writer_->Write(control_command);
  return true;
}

ProduceControlCommand(计算控制参数并执行)

Status ControlComponent::ProduceControlCommand(ControlCommand *control_command) {
  Status status = CheckInput(&local_view_);
  //检查数据,错误则紧急停车,转换为手动控制
  if (!status.ok()) {
    AERROR_EVERY(100) << "Control input data failed: " << status.error_message();
    control_command->mutable_engage_advice()->set_advice(apollo::common::EngageAdvice::DISALLOW_ENGAGE);
    control_command->mutable_engage_advice()->set_reason(status.error_message());
    estop_ = true;
    estop_reason_ = status.error_message();
  } else {
    //检查时间戳,超时
    Status status_ts = CheckTimestamp(local_view_);
    if (!status_ts.ok()) {
      AERROR << "Input messages timeout";
      //如果没有接收到新的数据,则清空轨迹信息,停止自动控制
      trajectory_reader_->ClearData();
      status = status_ts;
      if (local_view_.chassis().driving_mode() !=apollo::canbus::Chassis::COMPLETE_AUTO_DRIVE) {
        control_command->mutable_engage_advice()->set_advice(apollo::common::EngageAdvice::DISALLOW_ENGAGE);
        control_command->mutable_engage_advice()->set_reason(status.error_message());
      }
    } else {
      control_command->mutable_engage_advice()->set_advice(apollo::common::EngageAdvice::READY_TO_ENGAGE);
    }
  }
  //检查紧急制动
  estop_ = control_conf_.enable_persistent_estop()
               ? estop_ || local_view_.trajectory().estop().is_estop()
               : local_view_.trajectory().estop().is_estop();
  if (local_view_.trajectory().estop().is_estop()) {
    estop_ = true;
    estop_reason_ = "estop from planning : ";
    estop_reason_ += local_view_.trajectory().estop().reason();
  }
  if (local_view_.trajectory().trajectory_point().empty()) {
    AWARN_EVERY(100) << "planning has no trajectory point. ";
    estop_ = true;
    estop_reason_ = "estop for empty planning trajectory, planning headers: " + local_view_.trajectory().header().ShortDebugString();
  }
  //车辆处于驾驶档且速度为负值,则触发
  if (FLAGS_enable_gear_drive_negative_speed_protection) {
    const double kEpsilon = 0.001;
    auto first_trajectory_point = local_view_.trajectory().trajectory_point(0);
    if (local_view_.chassis().gear_location() == Chassis::GEAR_DRIVE &&first_trajectory_point.v() < -1 * kEpsilon) {
      estop_ = true;
      estop_reason_ = "estop for negative speed when gear_drive";
    }
  }
  //手动驾驶状态
  if (!estop_) {
    if (local_view_.chassis().driving_mode() == Chassis::COMPLETE_MANUAL) {
      controller_agent_.Reset();
      AINFO_EVERY(100) << "Reset Controllers in Manual Mode";
    }
    auto debug = control_command->mutable_debug()->mutable_input_debug();
    debug->mutable_localization_header()->CopyFrom(local_view_.localization().header());
    debug->mutable_canbus_header()->CopyFrom(local_view_.chassis().header());
    debug->mutable_trajectory_header()->CopyFrom(local_view_.trajectory().header());
    if (local_view_.trajectory().is_replan()) {
      latest_replan_trajectory_header_ = local_view_.trajectory().header();
    }
    //重新规划时记录头部文件
    if (latest_replan_trajectory_header_.has_sequence_num()) {
      debug->mutable_latest_replan_trajectory_header()->CopyFrom(
          latest_replan_trajectory_header_);
    }
    //控制器代理(核心部分),利用传入的Localization、chassis、trajectory信息计算控制参数
    Status status_compute = controller_agent_.ComputeControlCommand(&local_view_.localization(), &local_view_.chassis(),&local_view_.trajectory(), control_command);
    if (!status_compute.ok()) {
      AERROR << "Control main function failed"
             << " with localization: "
             << local_view_.localization().ShortDebugString()
             << " with chassis: " << local_view_.chassis().ShortDebugString()
             << " with trajectory: "
             << local_view_.trajectory().ShortDebugString()
             << " with cmd: " << control_command->ShortDebugString()
             << " status:" << status_compute.error_message();
      estop_ = true;
      estop_reason_ = status_compute.error_message();
      status = status_compute;
    }
  }
  //如果Planning模块触发了紧急制动,则不会执行Control命令
  if (estop_) {
    AWARN_EVERY(100) << "Estop triggered! No control core method executed!";
    control_command->set_speed(0);
    control_command->set_throttle(0);
    control_command->set_brake(control_conf_.soft_estop_brake());
    control_command->set_gear_location(Chassis::GEAR_DRIVE);
  }
  //将signal信息(Planning?)复制到Control模块
  if (local_view_.trajectory().decision().has_vehicle_signal()) {
    control_command->mutable_signal()->CopyFrom(local_view_.trajectory().decision().vehicle_signal());
  }
  return status;
}

pad_msg主要包括以下两种功能:

  1. 发送消息给Canbus模块,来控制driving_mode,Control模块根据当前driving_mode的状态来判断是否启动自动驾驶(pad_msg由Planning模块订阅并发布)
  2. 通过reset来清空estop_的状态(estop_其中一个产生条件为路径为空,起源于Planning模块)

Perception模块

Perception模块利用各种传感器数据中获取的有关环境信息,使得车辆能够理解、感知其周围的事物

输入:雷达与图像数据,车辆的速度与角速度

输出:具有航向、速度和分类信息的3D障碍物轨迹以及交通信号灯检测和识别的输出

关联模块:Prediction+Localization

Prediction模块

Prediction模块主要研究并预测感知模块(Perception)检测到的所有障碍物的行为,预测接收障碍物数据以及基本感知信息,包括位置、航向、速度、加速度,然后生成具有这些障碍物概率的预测轨迹

输入:感知模块的障碍物信息(Perception),定位模块的定位信息(Localization),规划模块的前一个计算周期的规划轨迹(Planning)

输出:具有预测轨迹的障碍物,障碍物标注有预测轨迹及其优先级

关联模块:Perception+Localization+Planning*

prediction_component.cc

void PredictionComponent::OfflineProcessFeatureProtoFile(const std::string& features_proto_file_name) {
  //读取障碍物容器指针
  auto obstacles_container_ptr = container_manager_->GetContainer<ObstaclesContainer>(AdapterConfig::PERCEPTION_OBSTACLES);
  obstacles_container_ptr->Clear();
  //将特征加入障碍物容器(Perception)
  Features features;
  apollo::cyber::common::GetProtoFromBinaryFile(features_proto_file_name,&features);
  for (const Feature& feature : features.feature()) {
    obstacles_container_ptr->InsertFeatureProto(feature);
    Obstacle* obstacle_ptr = obstacles_container_ptr->GetObstacle(feature.id());
    if (!obstacle_ptr) {
      continue;
    }
    //评估障碍物?
    1.evaluator_manager_->EvaluateObstacle(obstacle_ptr, obstacles_container_ptr);
  }
}
bool PredictionComponent::Init() {
  component_start_time_ = Clock::NowInSeconds();
  container_manager_ = std::make_shared<ContainerManager>();
  evaluator_manager_.reset(new EvaluatorManager());
  predictor_manager_.reset(new PredictorManager());
  scenario_manager_.reset(new ScenarioManager());
  PredictionConf prediction_conf;
  //未能加载配置文件
  if (!ComponentBase::GetProtoConfig(&prediction_conf)) {
    AERROR << "Unable to load prediction conf file: " << ComponentBase::ConfigFilePath();
    return false;
  }
  ADEBUG << "Prediction config file is loaded into: " << prediction_conf.ShortDebugString();
  if (!MessageProcess::Init(container_manager_.get(), evaluator_manager_.get(), predictor_manager_.get(), prediction_conf)) {
    return false;
  }
  //订阅各模块信息
  planning_reader_ = node_->CreateReader<ADCTrajectory>(prediction_conf.topic_conf().planning_trajectory_topic(), nullptr);
  localization_reader_ = node_->CreateReader<localization::LocalizationEstimate>(prediction_conf.topic_conf().localization_topic(), nullptr);
  storytelling_reader_ = node_->CreateReader<storytelling::Stories>(prediction_conf.topic_conf().storytelling_topic(), nullptr);
  prediction_writer_ = node_->CreateWriter<PredictionObstacles>(prediction_conf.topic_conf().prediction_topic());
  container_writer_ = node_->CreateWriter<SubmoduleOutput>(prediction_conf.topic_conf().container_topic_name());
  adc_container_writer_ = node_->CreateWriter<ADCTrajectoryContainer>(prediction_conf.topic_conf().adccontainer_topic_name());
  perception_obstacles_writer_ = node_->CreateWriter<PerceptionObstacles>(prediction_conf.topic_conf().perception_obstacles_topic_name());
  return true;
}
bool PredictionComponent::Proc(const std::shared_ptr<PerceptionObstacles>& perception_obstacles) {
  if (FLAGS_use_lego) {
    //将各模块内容处理后,放入容器供其他部分使用
    3.return ContainerSubmoduleProcess(perception_obstacles);
  }
  //涉及更多的数据处理和后续任务,发布预测的障碍物信息
  4.return PredictionEndToEndProc(perception_obstacles);
}

EvaluateObstacle(根据障碍物选择评估器)

void EvaluatorManager::EvaluateObstacle(const ADCTrajectoryContainer* adc_trajectory_container,
    Obstacle* obstacle,ObstaclesContainer* obstacles_container,std::vector<Obstacle*> dynamic_env) {
  Evaluator* evaluator = nullptr;
  //根据障碍物的类型选择不同的评估器(evaluators)
  switch (obstacle->type()) {
    case PerceptionObstacle::VEHICLE: {
      //警告却不是慢行(潜在危险)
      if (obstacle->IsCaution() && !obstacle->IsSlow()) {
        if (obstacle->IsInteractiveObstacle()) {
          evaluator = GetEvaluator(interaction_evaluator_);
        } else if (obstacle->IsNearJunction()) {
          evaluator = GetEvaluator(vehicle_in_junction_caution_evaluator_);
        } else if (obstacle->IsOnLane()) {
          evaluator = GetEvaluator(vehicle_on_lane_caution_evaluator_);
        } else {
          evaluator = GetEvaluator(vehicle_default_caution_evaluator_);
        }
        CHECK_NOTNULL(evaluator);
        //评估并退出
        if (evaluator->GetName() == "JOINTLY_PREDICTION_PLANNING_EVALUATOR") {
          2.if (evaluator->Evaluate(adc_trajectory_container,obstacle, obstacles_container)) {
            break;
          } else {
            AERROR << "Obstacle: " << obstacle->id() << " interaction evaluator failed," << " downgrade to normal level!";
          }
        } else {
          if (evaluator->Evaluate(obstacle, obstacles_container)) {
            break;
          } else {
            AERROR << "Obstacle: " << obstacle->id() << " caution evaluator failed, downgrade to normal level!";
          }
        }
      }
      //障碍物不属于警告类别或警告评估失败
      if (obstacle->HasJunctionFeatureWithExits() &&!obstacle->IsCloseToJunctionExit()) {
        //障碍物在交叉路口里
        evaluator = GetEvaluator(vehicle_in_junction_evaluator_);
      } else if (obstacle->IsOnLane()) {
        evaluator = GetEvaluator(vehicle_on_lane_evaluator_);
      } else {
        //不再评估并退出
        ADEBUG << "Obstacle: " << obstacle->id() << " is neither on lane, nor in junction. Skip evaluating.";
        break;
      }
      CHECK_NOTNULL(evaluator);
      if (evaluator->GetName() == "LANE_SCANNING_EVALUATOR") {
        evaluator->Evaluate(obstacle, obstacles_container, dynamic_env);
      } else {
        evaluator->Evaluate(obstacle, obstacles_container);
      }
      break;
    }
    case PerceptionObstacle::BICYCLE: {
      if (obstacle->IsOnLane()) {
        evaluator = GetEvaluator(cyclist_on_lane_evaluator_);
        CHECK_NOTNULL(evaluator);
        evaluator->Evaluate(obstacle, obstacles_container);
      }
      break;
    }
    case PerceptionObstacle::PEDESTRIAN: {
      //若处于离线模式或者优先级为CAUTION,则进行评估
      if (FLAGS_prediction_offline_mode == PredictionConstants::kDumpDataForLearning ||
          obstacle->latest_feature().priority().priority() == ObstaclePriority::CAUTION) {
        evaluator = GetEvaluator(pedestrian_evaluator_);
        CHECK_NOTNULL(evaluator);
        evaluator->Evaluate(obstacle, obstacles_container);
        break;
      }
    }
    default: {
      if (obstacle->IsOnLane()) {
        evaluator = GetEvaluator(default_on_lane_evaluator_);
        CHECK_NOTNULL(evaluator);
        evaluator->Evaluate(obstacle, obstacles_container);
      }
      break;
    }
  }
}

PedestrianInteractionEvaluator::Evaluate(使用深度学习模型进行预测和评估)

bool PedestrianInteractionEvaluator::Evaluate(Obstacle* obstacle_ptr, ObstaclesContainer* obstacles_container) {
  //检查健全性(初始化)
  CHECK_NOTNULL(obstacle_ptr);
  obstacle_ptr->SetEvaluatorType(evaluator_type_);
  int id = obstacle_ptr->id();
  if (!obstacle_ptr->latest_feature().IsInitialized()) {
    AERROR << "Obstacle [" << id << "] has no latest feature.";
    return false;
  }
  Feature* latest_feature_ptr = obstacle_ptr->mutable_latest_feature();
  CHECK_NOTNULL(latest_feature_ptr);
  //提取障碍物的特征信息并根据不同模式处理
  //-离线模式, 在本地保存以供训练
  //-在线模式, 通过训练模型进行评估
  std::vector<double> feature_values;
  ExtractFeatures(obstacle_ptr, &feature_values);
  if (FLAGS_prediction_offline_mode == PredictionConstants::kDumpDataForLearning) {
    FeatureOutput::InsertDataForLearning(*latest_feature_ptr, feature_values, "pedestrian", nullptr);
    ADEBUG << "Saving extracted features for learning locally.";
    return true;
  }
  static constexpr double kShortTermPredictionTimeResolution = 0.4;
  static constexpr int kShortTermPredictionPointNum = 5;
  static constexpr int kHiddenStateUpdateCycle = 4;
  //Step 1 Get social embedding
  torch::Tensor social_pooling = GetSocialPooling();
  std::vector<torch::jit::IValue> social_embedding_inputs;
  social_embedding_inputs.push_back(std::move(social_pooling.to(device_)));
  torch::Tensor social_embedding =
      torch_social_embedding_.forward(social_embedding_inputs)
          .toTensor()
          .to(torch::kCPU);

  // Step 2 Get position embedding
  double pos_x = feature_values[2];
  double pos_y = feature_values[3];
  double rel_x = 0.0;
  double rel_y = 0.0;
  if (obstacle_ptr->history_size() > kHiddenStateUpdateCycle - 1) {
    rel_x = obstacle_ptr->latest_feature().position().x() - obstacle_ptr->feature(3).position().x();
    rel_y = obstacle_ptr->latest_feature().position().y() - obstacle_ptr->feature(3).position().y();
  }
  torch::Tensor torch_position = torch::zeros({1, 2});
  torch_position[0][0] = rel_x;
  torch_position[0][1] = rel_y;
  std::vector<torch::jit::IValue> position_embedding_inputs;
  position_embedding_inputs.push_back(std::move(torch_position.to(device_)));
  torch::Tensor position_embedding = torch_position_embedding_.forward(position_embedding_inputs).toTensor().to(torch::kCPU);
  // Step 3 Conduct single LSTM and update hidden states
  torch::Tensor lstm_input =
      torch::zeros({1, 2 * (kEmbeddingSize + kHiddenSize)});
  for (int i = 0; i < kEmbeddingSize; ++i) {
    lstm_input[0][i] = position_embedding[0][i];
  }
  if (obstacle_id_lstm_state_map_.find(id) == obstacle_id_lstm_state_map_.end()) {
    obstacle_id_lstm_state_map_[id].ht = torch::zeros({1, 1, kHiddenSize});
    obstacle_id_lstm_state_map_[id].ct = torch::zeros({1, 1, kHiddenSize});
    obstacle_id_lstm_state_map_[id].timestamp = obstacle_ptr->timestamp();
    obstacle_id_lstm_state_map_[id].frame_count = 0;
  }
  torch::Tensor curr_ht = obstacle_id_lstm_state_map_[id].ht;
  torch::Tensor curr_ct = obstacle_id_lstm_state_map_[id].ct;
  int curr_frame_count = obstacle_id_lstm_state_map_[id].frame_count;
  if (curr_frame_count == kHiddenStateUpdateCycle - 1) {
    for (int i = 0; i < kHiddenSize; ++i) {
      lstm_input[0][kEmbeddingSize + i] = curr_ht[0][0][i];
      lstm_input[0][kEmbeddingSize + kHiddenSize + i] = curr_ct[0][0][i];
    }
    std::vector<torch::jit::IValue> lstm_inputs;
    lstm_inputs.push_back(std::move(lstm_input.to(device_)));
    auto lstm_out_tuple = torch_single_lstm_.forward(lstm_inputs).toTuple();
    auto ht = lstm_out_tuple->elements()[0].toTensor();
    auto ct = lstm_out_tuple->elements()[1].toTensor();
    obstacle_id_lstm_state_map_[id].ht = ht.clone();
    obstacle_id_lstm_state_map_[id].ct = ct.clone();
  }
  obstacle_id_lstm_state_map_[id].frame_count = (curr_frame_count + 1) % kHiddenStateUpdateCycle;
  //Step 4 for-loop get a trajectory
  //Set the starting trajectory point
  Trajectory* trajectory = latest_feature_ptr->add_predicted_trajectory();
  trajectory->set_probability(1.0);
  TrajectoryPoint* start_point = trajectory->add_trajectory_point();
  start_point->mutable_path_point()->set_x(pos_x);
  start_point->mutable_path_point()->set_y(pos_y);
  start_point->mutable_path_point()->set_theta(latest_feature_ptr->theta());
  start_point->set_v(latest_feature_ptr->speed());
  start_point->set_relative_time(0.0);
  for (int i = 1; i <= kShortTermPredictionPointNum; ++i) {
    double prev_x = trajectory->trajectory_point(i - 1).path_point().x();
    double prev_y = trajectory->trajectory_point(i - 1).path_point().y();
    ACHECK(obstacle_id_lstm_state_map_.find(id) !=
           obstacle_id_lstm_state_map_.end());
    torch::Tensor torch_position = torch::zeros({1, 2});
    double curr_rel_x = rel_x;
    double curr_rel_y = rel_y;
    if (i > 1) {
      curr_rel_x =
          prev_x - trajectory->trajectory_point(i - 2).path_point().x();
      curr_rel_y =
          prev_y - trajectory->trajectory_point(i - 2).path_point().y();
    }
    torch_position[0][0] = curr_rel_x;
    torch_position[0][1] = curr_rel_y;
    std::vector<torch::jit::IValue> position_embedding_inputs;
    position_embedding_inputs.push_back(std::move(torch_position.to(device_)));
    torch::Tensor position_embedding = torch_position_embedding_.forward(position_embedding_inputs).toTensor().to(torch::kCPU);
    torch::Tensor lstm_input = torch::zeros({1, kEmbeddingSize + 2 * kHiddenSize});
    for (int i = 0; i < kEmbeddingSize; ++i) {
      lstm_input[0][i] = position_embedding[0][i];
    }
    auto ht = obstacle_id_lstm_state_map_[id].ht.clone();
    auto ct = obstacle_id_lstm_state_map_[id].ct.clone();
    for (int i = 0; i < kHiddenSize; ++i) {
      lstm_input[0][kEmbeddingSize + i] = ht[0][0][i];
      lstm_input[0][kEmbeddingSize + kHiddenSize + i] = ct[0][0][i];
    }
    std::vector<torch::jit::IValue> lstm_inputs;
    lstm_inputs.push_back(std::move(lstm_input.to(device_)));
    auto lstm_out_tuple = torch_single_lstm_.forward(lstm_inputs).toTuple();
    ht = lstm_out_tuple->elements()[0].toTensor();
    ct = lstm_out_tuple->elements()[1].toTensor();
    std::vector<torch::jit::IValue> prediction_inputs;
    prediction_inputs.push_back(ht[0]);
    auto pred_out_tensor = torch_prediction_layer_.forward(prediction_inputs).toTensor().to(torch::kCPU);
    auto pred_out = pred_out_tensor.accessor<float, 2>();
    TrajectoryPoint* point = trajectory->add_trajectory_point();
    double curr_x = prev_x + static_cast<double>(pred_out[0][0]);
    double curr_y = prev_y + static_cast<double>(pred_out[0][1]);
    point->mutable_path_point()->set_x(curr_x);
    point->mutable_path_point()->set_y(curr_y);
    point->set_v(latest_feature_ptr->speed());
    point->mutable_path_point()->set_theta(latest_feature_ptr->velocity_heading());
    point->set_relative_time(kShortTermPredictionTimeResolution * static_cast<double>(i));
  }
  return true;
}

ContainerSubmoduleProcess(处理各模块信息并更新发布)

bool PredictionComponent::ContainerSubmoduleProcess(const std::shared_ptr<PerceptionObstacles>& perception_obstacles) {
  constexpr static size_t kHistorySize = 10;
  const auto frame_start_time = Clock::Now();
  //读取Localization信息,并且调用OnLocalization更新
  localization_reader_->Observe();
  auto ptr_localization_msg = localization_reader_->GetLatestObserved();
  if (ptr_localization_msg == nullptr) {
    AERROR << "Prediction: cannot receive any localization message.";
    return false;
  }
  MessageProcess::OnLocalization(container_manager_.get(),*ptr_localization_msg);
  //读取Planning上一时刻的信息
  planning_reader_->Observe();
  auto ptr_trajectory_msg = planning_reader_->GetLatestObserved();
  if (ptr_trajectory_msg != nullptr) {
    MessageProcess::OnPlanning(container_manager_.get(), *ptr_trajectory_msg);
  }
  //同上
  storytelling_reader_->Observe();
  auto ptr_storytelling_msg = storytelling_reader_->GetLatestObserved();
  if (ptr_storytelling_msg != nullptr) {
    MessageProcess::OnStoryTelling(container_manager_.get(),*ptr_storytelling_msg);
  }
  =====================================================================================================================
  MessageProcess::ContainerProcess(container_manager_, *perception_obstacles,scenario_manager_.get());
  auto obstacles_container_ptr = container_manager_->GetContainer<ObstaclesContainer>(AdapterConfig::PERCEPTION_OBSTACLES);
  CHECK_NOTNULL(obstacles_container_ptr);
  auto adc_trajectory_container_ptr = container_manager_->GetContainer<ADCTrajectoryContainer>(AdapterConfig::PLANNING_TRAJECTORY);
  CHECK_NOTNULL(adc_trajectory_container_ptr);
  //获取子模块输出
  SubmoduleOutput submodule_output = obstacles_container_ptr->GetSubmoduleOutput(kHistorySize,frame_start_time);
  submodule_output.set_curr_scenario(scenario_manager_->scenario());
  container_writer_->Write(submodule_output);
  adc_container_writer_->Write(*adc_trajectory_container_ptr);
  perception_obstacles_writer_->Write(*perception_obstacles);
  return true;
}

PredictionEndToEndProc

bool PredictionComponent::PredictionEndToEndProc(const std::shared_ptr<PerceptionObstacles>& perception_obstacles) {
  //测试模式
  if (FLAGS_prediction_test_mode && (Clock::NowInSeconds() - component_start_time_ > FLAGS_prediction_test_duration)) {
    ADEBUG << "Prediction finished running in test mode";
  }
  //检查相对地图(实时)
  if (FLAGS_use_navigation_mode && !PredictionMap::Ready()) {
    AERROR << "Relative map is empty.";
    return false;
  }
  frame_start_time_ = Clock::NowInSeconds();
  auto end_time1 = std::chrono::system_clock::now();
  //读取Localization信息并更新
  localization_reader_->Observe();
  auto ptr_localization_msg = localization_reader_->GetLatestObserved();
  if (ptr_localization_msg == nullptr) {
    AERROR << "Prediction: cannot receive any localization message.";
    return false;
  }
  MessageProcess::OnLocalization(container_manager_.get(),*ptr_localization_msg);
  auto end_time2 = std::chrono::system_clock::now();
  std::chrono::duration<double> diff = end_time2 - end_time1;
  ADEBUG << "Time for updating PoseContainer: " << diff.count() * 1000 << " msec.";
  //读取Storytelling消息并更新
  storytelling_reader_->Observe();
  auto ptr_storytelling_msg = storytelling_reader_->GetLatestObserved();
  if (ptr_storytelling_msg != nullptr) {
    MessageProcess::OnStoryTelling(container_manager_.get(),*ptr_storytelling_msg);
  }
  planning_reader_->Observe();
  auto ptr_trajectory_msg = planning_reader_->GetLatestObserved();
  if (ptr_trajectory_msg != nullptr) {
    MessageProcess::OnPlanning(container_manager_.get(), *ptr_trajectory_msg);
  }
  auto end_time3 = std::chrono::system_clock::now();
  diff = end_time3 - end_time2;
  ADEBUG << "Time for updating ADCTrajectoryContainer: " << diff.count() * 1000 << " msec.";
  =====================================================================================================================
  //获取所有perception_obstacles,并调用OnPerception进行处理
  auto perception_msg = *perception_obstacles;
  PredictionObstacles prediction_obstacles;
  //将Perception模块内容转换为Prediction模块可用的格式
  MessageProcess::OnPerception(perception_msg, container_manager_, evaluator_manager_.get(),predictor_manager_.get(), scenario_manager_.get(), &prediction_obstacles);
  auto end_time4 = std::chrono::system_clock::now();
  diff = end_time4 - end_time3;
  ADEBUG << "Time for updating PerceptionContainer: " << diff.count() * 1000 << " msec.";
  //对预测的障碍物信息进行后续处理
  prediction_obstacles.set_start_timestamp(frame_start_time_);
  prediction_obstacles.set_end_timestamp(Clock::NowInSeconds());
  prediction_obstacles.mutable_header()->set_lidar_timestamp(perception_msg.header().lidar_timestamp());
  prediction_obstacles.mutable_header()->set_camera_timestamp(perception_msg.header().camera_timestamp());
  prediction_obstacles.mutable_header()->set_radar_timestamp(perception_msg.header().radar_timestamp());
  prediction_obstacles.set_perception_error_code(perception_msg.error_code());
  //循环遍历所有trajectory_point,检查合法性(预测的轨迹可能存在问题)
  if (FLAGS_prediction_test_mode) {
    for (auto const& prediction_obstacle :
         prediction_obstacles.prediction_obstacle()) {
      for (auto const& trajectory : prediction_obstacle.trajectory()) {
        for (auto const& trajectory_point : trajectory.trajectory_point()) {
          if (!ValidationChecker::ValidTrajectoryPoint(trajectory_point)) {
            AERROR << "Invalid trajectory point [" << trajectory_point.ShortDebugString() << "]";
            break;
          }
        }
      }
    }
  }
  auto end_time5 = std::chrono::system_clock::now();
  diff = end_time5 - end_time1;
  ADEBUG << "End to end time elapsed: " << diff.count() * 1000 << " msec.";
  //发布prediction_obstacles
  common::util::FillHeader(node_->Name(), &prediction_obstacles);
  prediction_writer_->Write(prediction_obstacles);
  return true;
}

容器存储来自订阅通道的输入数据
评估器对任何给定的障碍分别预测路径和速度
预测器生成障碍物的预测轨迹

Routing模块

Routing模块主要关注起点到终点的长期路径,需要根据起点到终点之间的道路,选择一条最优路径

输入:地图数据(Map)和路由请求(routing_request)

输出:规划的路径

关联模块:Map

routing_component.cc

#include "modules/routing/routing_component.h"
#include <utility>
#include "modules/common/adapters/adapter_gflags.h"
#include "modules/routing/common/routing_gflags.h"
DECLARE_string(flagfile);
namespace apollo {
namespace routing {
bool RoutingComponent::Init() {
  //加载配置文件
  RoutingConfig routing_conf;
  ACHECK(cyber::ComponentBase::GetProtoConfig(&routing_conf))
      << "Unable to load routing conf file: "
      << cyber::ComponentBase::ConfigFilePath();
  AINFO << "Config file: " << cyber::ComponentBase::ConfigFilePath() << " is loaded.";
  //配置QOS,
  apollo::cyber::proto::RoleAttributes attr;
  attr.set_channel_name(routing_conf.topic_config().routing_response_topic());
  auto qos = attr.mutable_qos_profile();
  //保持最新历史
  qos->set_history(apollo::cyber::proto::QosHistoryPolicy::HISTORY_KEEP_LAST);
  //要求可靠传输
  qos->set_reliability(apollo::cyber::proto::QosReliabilityPolicy::RELIABILITY_RELIABLE);
  //消息在本例持久化(断线依旧可用)
  qos->set_durability(apollo::cyber::proto::QosDurabilityPolicy::DURABILITY_TRANSIENT_LOCAL);
  //创建消息发布
  response_writer_ = node_->CreateWriter<RoutingResponse>(attr);
  apollo::cyber::proto::RoleAttributes attr_history;
  attr_history.set_channel_name(routing_conf.topic_config().routing_response_history_topic());
  auto qos_history = attr_history.mutable_qos_profile();
  qos_history->set_history(apollo::cyber::proto::QosHistoryPolicy::HISTORY_KEEP_LAST);
  qos_history->set_reliability(apollo::cyber::proto::QosReliabilityPolicy::RELIABILITY_RELIABLE);
  qos_history->set_durability(apollo::cyber::proto::QosDurabilityPolicy::DURABILITY_TRANSIENT_LOCAL);
  response_history_writer_ = node_->CreateWriter<RoutingResponse>(attr_history);
  //创建定时器,按间隔更新时间戳
  std::weak_ptr<RoutingComponent> self = std::dynamic_pointer_cast<RoutingComponent>(shared_from_this());
  timer_.reset(new ::apollo::cyber::Timer(
      FLAGS_routing_response_history_interval_ms,
      [self, this]() {
        auto ptr = self.lock();
        if (ptr) {
          std::lock_guard<std::mutex> guard(this->mutex_);
          if (this->response_ != nullptr) {
            auto timestamp = apollo::cyber::Clock::NowInSeconds();
            response_->mutable_header()->set_timestamp_sec(timestamp);
            //记录历史
            this->response_history_writer_->Write(*response_);
          }
        }
      },
      false));
  timer_->Start();
  //初始化并启动
  1.return routing_.Init().ok() && routing_.Start().ok();
}
//收到路由请求时触发
bool RoutingComponent::Proc(const std::shared_ptr<RoutingRequest>& request) {
  auto response = std::make_shared<RoutingResponse>();
  //处理Routing请求
  2.if (!routing_.Process(request, response.get())) {
    return false;
  }
  //填充头部并发布响应(协作)
  common::util::FillHeader(node_->Name(), response.get());
  response_writer_->Write(response);
  {
    std::lock_guard<std::mutex> guard(mutex_);
    response_ = std::move(response);
  }
  return true;
}
}
}

routing.cc

#include "modules/routing/routing.h"
#include <limits>
#include <unordered_map>
#include "modules/common/util/point_factory.h"
#include "modules/map/hdmap/hdmap_common.h"
#include "modules/routing/common/routing_gflags.h"
namespace apollo {
namespace routing {
using apollo::common::ErrorCode;
using apollo::common::PointENU;
using apollo::hdmap::ParkingSpaceInfoConstPtr;
apollo::common::Status Routing::Init() {
  //读取地图文件(RoutingMap主要由点和边组成)
  const auto routing_map_file = apollo::hdmap::RoutingMapFile();
  AINFO << "Use routing topology graph path: " << routing_map_file;
  navigator_ptr_.reset(new Navigator(routing_map_file));
  //加载BaseMap
  hdmap_ = apollo::hdmap::HDMapUtil::BaseMapPtr();
  ACHECK(hdmap_) << "Failed to load map file:" << apollo::hdmap::BaseMapFile();
  return apollo::common::Status::OK();
}
apollo::common::Status Routing::Start() {
  if (!navigator_ptr_->IsReady()) {
    AERROR << "Navigator is not ready!";
    return apollo::common::Status(ErrorCode::ROUTING_ERROR,"Navigator not ready");
  }
  //发布Routing状态
  AINFO << "Routing service is ready.";
  monitor_logger_buffer_.INFO("Routing started");
  return apollo::common::Status::OK();
}
bool Routing::Process(const std::shared_ptr<RoutingRequest>& routing_request,RoutingResponse* const routing_response) {
  CHECK_NOTNULL(routing_response);
  AINFO << "Get new routing request:" << routing_request->DebugString();
  //对车道信息进行填充(寻找最近车道)
  1.const auto& fixed_requests = FillLaneInfoIfMissing(*routing_request);
  double min_routing_length = std::numeric_limits<double>::max();
  //从所有额外路径中挑选最优的
  for (const auto& fixed_request : fixed_requests) {
    RoutingResponse routing_response_temp;
    if (navigator_ptr_->SearchRoute(fixed_request, &routing_response_temp)) {
      const double routing_length = routing_response_temp.measurement().distance();
      if (routing_length < min_routing_length) {
        routing_response->CopyFrom(routing_response_temp);
        min_routing_length = routing_length;
      }
    }
    //对停车信息进行填充
    FillParkingID(routing_response);
  }
  //寻找到合适路径,停车位置规划完毕
  if (min_routing_length < std::numeric_limits<double>::max() && SupplementParkingRequest(routing_response)) {
    monitor_logger_buffer_.INFO("Routing success!");
    return true;
  }
  AERROR << "Failed to search route with navigator.";
  monitor_logger_buffer_.WARN("Routing failed! " + routing_response->status().msg());
  return false;
}
}
}

FillLaneInfoIfMissing(寻找距离请求点最近的车道)

std::vector<RoutingRequest> Routing::FillLaneInfoIfMissing(const RoutingRequest& routing_request) {
  std::vector<RoutingRequest> fixed_requests;
  std::unordered_map<int, std::vector<LaneWaypoint>>additional_lane_waypoint_map;
  RoutingRequest fixed_request(routing_request);
  for (int i = 0; i < routing_request.waypoint_size(); ++i) {
    LaneWaypoint lane_waypoint(routing_request.waypoint(i));
    if (lane_waypoint.has_id()) {
      continue;
    }
    //填充缺少的车道信息
    const auto point =common::util::PointFactory::ToPointENU(lane_waypoint.pose());//将pose信息转换为坐标点
    std::vector<std::shared_ptr<const hdmap::LaneInfo>> lanes;
    //在没有找到车道时扩大半径,寻找最近的车道
    constexpr double kRadius = 0.3;
    for (int i = 0; i < 20; ++i) {
      hdmap_->GetLanes(point, kRadius + i * kRadius, &lanes);
      if (lanes.size() > 0) {
        break;
      }
    }
    if (lanes.empty()) {
      AERROR << "Failed to find nearest lane from map at position: " << point.DebugString();
      return fixed_requests;//返回空的Vector
    }
    for (size_t j = 0; j < lanes.size(); ++j) {
      double s = 0.0;
      double l = 0.0;
      lanes[j]->GetProjection({point.x(), point.y()}, &s, &l);
      if (j == 0) {
        auto waypoint_info = fixed_request.mutable_waypoint(i);
        waypoint_info->set_id(lanes[j]->id().id());
        waypoint_info->set_s(s);
      } else {
        //额外的备选车道
        LaneWaypoint new_lane_waypoint(lane_waypoint);
        new_lane_waypoint.set_id(lanes[j]->id().id());
        new_lane_waypoint.set_s(s);
        additional_lane_waypoint_map[i].push_back(new_lane_waypoint);
      }
    }
  }
  //第一个处理后的路由请求
  fixed_requests.push_back(fixed_request);
  //由于车道重叠生成额外路由请求
  for (const auto& m : additional_lane_waypoint_map) {
    size_t cur_size = fixed_requests.size();
    for (size_t i = 0; i < cur_size; ++i) {
      //使用index迭代的同时push_back
      for (const auto& lane_waypoint : m.second) {
        RoutingRequest new_request(fixed_requests[i]);
        auto waypoint_info = new_request.mutable_waypoint(m.first);
        waypoint_info->set_id(lane_waypoint.id());
        waypoint_info->set_s(lane_waypoint.s());
        fixed_requests.push_back(new_request);
      }
    }
  }//在主要路由请求的基础上,将备选车道转换为额外路由请求,应对车道重叠的情况(为路径规划器提供更多选择)
  for (const auto& fixed_request : fixed_requests) {
    ADEBUG << "Fixed routing request:" << fixed_request.DebugString();
  }
  return fixed_requests;
}

Canbus模块

Canbus模块可以利用订阅的信息,向车辆控制系统传递命令以达到控制底盘(Chassis)的目的,同时可以实时进行车辆数据的接受与发送

输入:控制命令(Control Command)+保护命令(Guardian Command)

输出:汽车底盘信息(Chassis)

关联模块:Control+Guardian

canbus_component.cc

void CanbusComponent::Clear() {
  vehicle_object_->Stop();
  AINFO << "Cleanup Canbus component";
}
bool CanbusComponent::Init() {
  //加载配置文件
  if (!GetProtoConfig(&canbus_conf_)) {
    AERROR << "Unable to load canbus conf file: " << ConfigFilePath();
    return false;
  }
  AINFO << "The canbus conf file is loaded: " << FLAGS_canbus_conf_file;
  ADEBUG << "Canbus_conf:" << canbus_conf_.ShortDebugString();
  //加载车辆工厂库
  if (!apollo::cyber::common::PathExists(FLAGS_load_vehicle_library)) {
    AERROR << FLAGS_load_vehicle_library << " No such vehicle library";
    return false;
  }
  AINFO << "Load the vehicle factory library: " << FLAGS_load_vehicle_library;
  //创建车辆对象
  ClassLoader loader(FLAGS_load_vehicle_library);
  auto vehicle_object = loader.CreateClassObj<AbstractVehicleFactory>(FLAGS_load_vehicle_class_name);
  if (!vehicle_object) {
    AERROR << "Failed to create the vehicle factory: " << FLAGS_load_vehicle_class_name;
    return false;
  }
  vehicle_object_ = vehicle_object;
  if (vehicle_object_ == nullptr) {
    AERROR << "Failed to create vehicle factory pointer.";
  }
  AINFO << "Successfully create vehicle factory: " << FLAGS_load_vehicle_class_name;
  //初始化车辆对象并传入配置信息
  if (!vehicle_object_->Init(&canbus_conf_)) {
    AERROR << "Fail to init vehicle factory.";
    return false;
  }
  AINFO << "Vehicle factory is successfully initialized.";
  //配置消息订阅器(guardian+control)
  cyber::ReaderConfig guardian_cmd_reader_config;
  guardian_cmd_reader_config.channel_name = FLAGS_guardian_topic;
  guardian_cmd_reader_config.pending_queue_size = FLAGS_guardian_cmd_pending_queue_size;
  cyber::ReaderConfig control_cmd_reader_config;
  control_cmd_reader_config.channel_name = FLAGS_control_command_topic;
  control_cmd_reader_config.pending_queue_size = FLAGS_control_cmd_pending_queue_size;
  if (FLAGS_receive_guardian) {
    guardian_cmd_reader_ = node_->CreateReader<GuardianCommand>(
        guardian_cmd_reader_config,[this](const std::shared_ptr<GuardianCommand> &cmd) {
          ADEBUG << "Received guardian data: run canbus callback.";
          OnGuardianCommand(*cmd);
        });
  } else {
    control_command_reader_ = node_->CreateReader<ControlCommand>(
        control_cmd_reader_config,[this](const std::shared_ptr<ControlCommand> &cmd) {
          ADEBUG << "Received control data: run canbus callback.";
          1.OnControlCommand(*cmd);
        });
  }
  //创建Chassis写入器
  chassis_writer_ = node_->CreateWriter<Chassis>(FLAGS_chassis_topic);
  //启动Canbus相关组件
  if (!vehicle_object_->Start()) {
    AERROR << "Fail to start canclient, cansender, canreceiver, canclient, "
              "vehicle controller.";//缺少判断?
  }
  AINFO << "Start canclient cansender, canreceiver, canclient, vehicle "
           "controller successfully.";
  monitor_logger_buffer_.INFO("Canbus is started.");
  return true;
}
bool CanbusComponent::Proc() {
  2.PublishChassis();
  if (FLAGS_enable_chassis_detail_pub) {
    vehicle_object_->PublishChassisDetail();
  }
  //表明正在运行
  vehicle_object_->UpdateHeartbeat();
  return true;
}
common::Status CanbusComponent::OnError(const std::string &error_msg) {
  monitor_logger_buffer_.ERROR(error_msg);
  return ::apollo::common::Status(ErrorCode::CANBUS_ERROR, error_msg); 
}

OnControlCommand(执行车辆控制命令)

void CanbusComponent::OnControlCommand(const ControlCommand &control_command) {
  int64_t current_timestamp = Time::Now().ToMicrosecond();
  //如果命令的到达速度超过了系统的处理能力,可以选择忽略
  if (current_timestamp - last_timestamp_ < FLAGS_min_cmd_interval * 1000) {
    ADEBUG << "Control command comes too soon. Ignore.\n Required "
              "FLAGS_min_cmd_interval["
           << FLAGS_min_cmd_interval << "], actual time interval[" << current_timestamp - last_timestamp_ << "].";
    return;
  }
  //记录新的时间戳
  last_timestamp_ = current_timestamp;
  //计算延迟
  ADEBUG << "Control_sequence_number:" << control_command.header().sequence_num() << ", Time_of_delay:"
         << current_timestamp - static_cast<int64_t>(control_command.header().timestamp_sec() *1e6) << " micro seconds";
  //将命令传递给底层的车辆控制系统
  vehicle_object_->UpdateCommand(&control_command);
}

PublishChassis(发布底盘信息)

void CanbusComponent::PublishChassis() {
  Chassis chassis = vehicle_object_->publish_chassis();
  //填充头部信息
  common::util::FillHeader(node_->Name(), &chassis);
  chassis_writer_->Write(chassis);
  ADEBUG << chassis.ShortDebugString();
}

Guardian模块

Guardian模块通过监测车辆的状态来识别潜在的风险,采取适当的措施来保障车辆运行的安全

输入:底盘(Chassis),control_cmd以及system_status信息

输出:保护指令(guardian_cmd_)

关联模块:Canbus+Control

guardian_component.cc

bool GuardianComponent::Init() {
  if (!GetProtoConfig(&guardian_conf_)) {
    AERROR << "Unable to load canbus conf file: " << ConfigFilePath();
    return false;
  }
  //订阅chassis,control_cmd以及system_status信息
  chassis_reader_ = node_->CreateReader<Chassis>(FLAGS_chassis_topic, [this](const std::shared_ptr<Chassis>& chassis) {
        ADEBUG << "Received chassis data: run chassis callback.";
        std::lock_guard<std::mutex> lock(mutex_);
        chassis_.CopyFrom(*chassis);
      });
  control_cmd_reader_ = node_->CreateReader<ControlCommand>(FLAGS_control_command_topic,[this](const std::shared_ptr<ControlCommand>& cmd) {
        ADEBUG << "Received control data: run control callback.";
        std::lock_guard<std::mutex> lock(mutex_);
        control_cmd_.CopyFrom(*cmd);
      });
  system_status_reader_ = node_->CreateReader<SystemStatus>(FLAGS_system_status_topic,[this](const std::shared_ptr<SystemStatus>& status) {
        ADEBUG << "Received system status data: run system status callback.";
        std::lock_guard<std::mutex> lock(mutex_);
        last_status_received_s_ = Time::Now().ToSecond();
        system_status_.CopyFrom(*status);
      });
  //guardian消息发布
  guardian_writer_ = node_->CreateWriter<GuardianCommand>(FLAGS_guardian_topic);
  return true;
}
bool GuardianComponent::Proc() {
  constexpr double kSecondsTillTimeout(2.5);
  bool safety_mode_triggered = false;
  //满足条件时进入安全模式
  if (guardian_conf_.guardian_enable()) {
    std::lock_guard<std::mutex> lock(mutex_);
    if (Time::Now().ToSecond() - last_status_received_s_ > kSecondsTillTimeout) {
      safety_mode_triggered = true;
    }
    safety_mode_triggered = safety_mode_triggered || system_status_.has_safety_mode_trigger_time();
  }
  //依据状态触发安全模式或继续传递控制命令
  if (safety_mode_triggered) {
    ADEBUG << "Safety mode triggered, enable safety mode";
    1.TriggerSafetyMode();
  } else {
    ADEBUG << "Safety mode not triggered, bypass control command";
    PassThroughControlCommand();
  }
  //填充头部信息并发布命令
  common::util::FillHeader(node_->Name(), &guardian_cmd_);
  guardian_writer_->Write(guardian_cmd_);
  return true;
}

TriggerSafetyMode(触发安全模式)

void GuardianComponent::TriggerSafetyMode() {
  AINFO << "Safety state triggered, with system safety mode trigger time : " << system_status_.safety_mode_trigger_time();
  std::lock_guard<std::mutex> lock(mutex_);
  bool sensor_malfunction = false, obstacle_detected = false;
  //检查超声波传感器
  if (!chassis_.surround().sonar_enabled() || chassis_.surround().sonar_fault()) {
    AINFO << "Ultrasonic sensor not enabled for faulted, will do emergency stop!";
    sensor_malfunction = true;
  } else {
    //当障碍物过近或传感器故障
    for (int i = 0; i < chassis_.surround().sonar_range_size(); ++i) {
      if ((chassis_.surround().sonar_range(i) > 0.0 &&
           chassis_.surround().sonar_range(i) < 2.5) ||
          chassis_.surround().sonar_range(i) > 30) {
        AINFO << "Object detected or ultrasonic sensor fault output, will do emergency stop!";
        obstacle_detected = true;
      }
    }
  }
  //设置安全模式下控制命令
  guardian_cmd_.mutable_control_command()->set_throttle(0.0);
  guardian_cmd_.mutable_control_command()->set_steering_target(0.0);
  guardian_cmd_.mutable_control_command()->set_steering_rate(25.0);
  guardian_cmd_.mutable_control_command()->set_is_in_safe_mode(true);
  //***TODO(QiL) : Remove this one once hardware re-alignment is done.(重新校准)
  sensor_malfunction = false;
  obstacle_detected = false;
  AINFO << "Temporarily ignore the ultrasonic sensor output during hardware re-alignment!";
  //根据情况采取制动
  if (system_status_.require_emergency_stop() || sensor_malfunction || obstacle_detected) {
    AINFO << "Emergency stop triggered! with system status from monitor as : "
          << system_status_.require_emergency_stop();
    guardian_cmd_.mutable_control_command()->set_brake(guardian_conf_.guardian_cmd_emergency_stop_percentage());
  } else {
    AINFO << "Soft stop triggered! with system status from monitor as : "
          << system_status_.require_emergency_stop();
    guardian_cmd_.mutable_control_command()->set_brake(guardian_conf_.guardian_cmd_soft_stop_percentage());
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1081424.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

工学云打卡签到自动实现关于异地时定位的问题解决|蘑菇钉

工学云打卡助手&#xff0c;能解决你在异地时每天不间断签到的问题&#xff0c;仔细看图哦 1.自动签到 2.自定义打卡地区 3.生成日周月报与总结自动发表 4.支持随机通用内容 5.支持打卡结果推送 你是否曾经因为缺乏自律而无法坚持学习目标&#xff1f;是否曾经因为无法衡量…

WorkPlus一站式解决方案,助力企业构建统一门户系统

在信息爆炸的时代&#xff0c;企业管理面临着海量的数据和各类业务应用的复杂性。如何实现信息的井然有序、高效管理&#xff0c;成为企业发展的关键。WorkPlus作为领先的品牌&#xff0c;致力于打造统一门户系统&#xff0c;为企业提供全方位的服务和解决方案。本文将以知乎的…

Java实现B树

1.介绍 B树是一种自平衡的搜索树数据结构&#xff0c;常用于数据库和文件系统中的索引结构。它具有以下好处和功能&#xff1a; 高效的查找操作&#xff1a;B树的特点是每个节点可以存储多个关键字&#xff0c;并且保持有序。通过在节点上进行二分查找&#xff0c;可以快速定位…

使用PyTorch处理多维特征输入的完美指南

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

WorkPlus私有部署即时通信助力企业信息安全与高效协作

在当今快速发展的商业环境中&#xff0c;高效的内部沟通对企业的成功至关重要。然而&#xff0c;在保障信息安全的同时&#xff0c;如何实现高效的协作和沟通一直是企业所面临的挑战。传统的公共即时通信平台&#xff0c;尽管提供了便利的沟通工具&#xff0c;但其数据存储和控…

python- excel 创建/写入/删sheet+花式遍历

文章目录 前言python- excel 创建/写入/删sheet花式遍历1. excel 创建2. 写入excel3. 创建写入excel demo实战4. 删除sheet5. excel 花式遍历 demo实战5.1. 获取 A1的值5.2. 获取指定列的切片数据&#xff0c;获取 B1到B5的值5.3. 循环整个excel的这个sheet5.4. 遍历指定行&…

VR全景云端看车,让你享受不一样的购车体验

这个“黄金周”可谓是热闹非凡&#xff0c;不仅房企大降价&#xff0c;部分车企也在“黄金周”发力&#xff0c;降价优惠促销量&#xff0c;那么你准备买车了吗&#xff1f;买车也是一个大件&#xff0c;需要多家店去走动比对价位&#xff0c;难免会挑花了眼&#xff0c;其实我…

中国SaaS行业等待“渡劫时刻”

期待、追捧、失望、质疑&#xff0c;中国SaaS行业激荡十几年&#xff0c;尝遍了市场浮沉&#xff0c;如今潮水褪去&#xff0c;SaaS企业们到了见真章的时刻。 一开始&#xff0c;SaaS行业被人们寄予厚望。互联网的蓬勃发展&#xff0c;数字化转型的历史进程&#xff0c;似乎都…

快讯|Tubi 有 Rabbit AI 啦

在每月一期的 Tubi 快讯中&#xff0c;你将全面及时地获取 Tubi 最新发展动态&#xff0c;欢迎星标关注【比图科技】微信公众号&#xff0c;一起成长变强&#xff01; Tubi 推出 Rabbit AI 帮助用户找到喜欢的视频内容 Tubi 于今年九月底推出了 Rabbit AI&#xff0c;这是一项…

基于 gin框架搭建入门项目

go mod init gin-ranking go: creating new go.mod: module gin-ranking go: to add module requirements and sums:go mod tidy下载gin框架 cmd窗口中执行命令&#xff1a; go get -u github.com/gin-gonic/ginpackage mainimport ("github.com/gin-gonic/gin"&qu…

圭亚那奥罗拉金矿配电工程中AM5SE系列微机保护装置

安科瑞 崔丽洁 摘要&#xff1a;目前&#xff0c;微机保护装置广泛应用于电力系统中&#xff0c;该类装置能够有效监测电力系统的运行状况&#xff0c;并实时记录电力系统出现故障的位置及性质&#xff0c;从而为故障的快速处理提供有效的参考信息。本文介绍的AM5SE系列微机保…

android:can not find libdevapi.so

一、为什么会出现这样的报错&#xff1f; 引用了一些第三方的sdk的so库之后通常都会遇到这样的错误&#xff0c;&#xff08;“nativeLibraryDirectories”[/data/app/com.lukouapp-1/lib/arm64, /vendor/lib64, /system/lib64]]] couldnt find "libxxxx.so"&#x…

zookeeper节点数据类型介绍及集群搭建

一、zookeeper介绍 zookeeper官网&#xff1a;Apache ZooKeeper zookeeper是一个分布式协调框架&#xff0c;保证的是CP&#xff0c;即一致性和分区容错性&#xff1b;zookeeper是一个分布式文件存储系统&#xff0c;文件节点可以存储数据&#xff0c;监听子文件节点等可以实…

绥化市中心广场焕发新活力:OLED透明拼接屏的奇观展示

OLED透明拼接屏技术在绥化城市的应用引起了广泛关注。 绥化市位于中国东北地区&#xff0c;是黑龙江省的一个重要城市。 该市拥有悠久的历史&#xff0c;历经多个朝代的兴衰。绥化的历史背景赋予了这座城市独特的文化底蕴和魅力。 绥化市内有许多著名景点&#xff0c;其中最…

day

#include <iostream> using namespace std; class Per {//算术运算符friend const Per operator(const Per &k1,const Per &k2);friend const Per operator-(const Per &k1,const Per &k2);friend const Per operator*(const Per &k1,const Per &…

vue项目npm intall时发生版本冲突的解决办法

在日常使用命令npm install / npm install XX下载依赖的操作中&#xff0c;我经常会遇到无法解析依赖树的问题&#xff08;依赖冲突&#xff09; 当遇到这种情况的时候&#xff0c;可以通过以下命令完成依赖安装&#xff1a; npm install --legacy-peer-deps npm install xxx…

国产化即时通讯平台WorkPlus,助力企业实现自主可控的沟通与协作

作为在线沟通与协作的重要工具&#xff0c;即时通讯平台在企业中扮演着不可或缺的角色。然而&#xff0c;为了保护企业的核心数据和机密信息&#xff0c;越来越多的企业开始转向国产化的即时通讯平台。在这一背景下&#xff0c;国内软件品牌WorkPlus应运而生&#xff0c;为企业…

基于 chinese-roberta-wwm-ext 微调训练中文命名实体识别任务

一、模型和数据集介绍 1.1 预训练模型 chinese-roberta-wwm-ext 是基于 RoBERTa 架构下开发&#xff0c;其中 wwm 代表 Whole Word Masking&#xff0c;即对整个词进行掩码处理&#xff0c;通过这种方式&#xff0c;模型能够更好地理解上下文和语义关联&#xff0c;提高中文文…

mongodb简介、安装、搭建复制集

一、 简介 NoSQL数据库四大家族&#xff1a;列存储 Hbase&#xff0c;键值(Key-Value)存储 Redis&#xff0c;图像存储 Neo4j&#xff0c;基于分布式文档存储的数据库MongoDb。 MongoDB 和关系型数据库对比 关系型数据库MongoDBdatabase&#xff08;库&#xff09;database&…

.net也能写内存挂

最近在研究.net的内存挂。 写了很久的c,发现c#写出来的东西实在太香。 折腾c#外挂已经有很长时间了。都是用socket和c配合。 这个模式其实蛮成功的&#xff0c;用rpc调用的方式加上c#的天生await 非常好写逻辑 类似这样 最近想换个口味。注入托管dll到非托管进程 这样做只…