欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

百度apollo - Apollo代码解析:4. control模块

程序员文章站 2022-04-16 10:08:12
...

0. 简介:

阅读本章之前默认已经阅读了:

PS: 代码注释github:https://github.com/DinnerHowe/apollo_read

首先来看看整体的逻辑图:

百度apollo - Apollo代码解析:4. control模块

由此可知planning和control是整个Apollo的核心,由于个人喜好的原因先看control模块。

打开control模块:

百度apollo - Apollo代码解析:4. control模块

可见整个模块是由main.cc开始的,直接看代码:


#include "modules/common/apollo_app.h"
#include "modules/control/common/control_gflags.h"
#include "modules/control/control.h"

APOLLO_MAIN(apollo::control::Control);

程序用了一个宏APOLLO_MAIN来实现的,该宏传入的是control类,APOLLO_MAIN的实现在modules/common/apollo_app.h中实现的,直接看程序:


//宏定义
#define APOLLO_MAIN(APP)
  int main(int argc, char **argv) {
    google::InitGoogleLogging(argv[0]);
    google::ParseCommandLineFlags(&argc, &argv, true);
    signal(SIGINT, apollo::common::apollo_app_sigint_handler);
    APP apollo_app_;
    ros::init(argc, argv, apollo_app_.Name());
    apollo_app_.Spin();
    return 0;
  }

其中:

  • google::InitGoogleLogging:是google glog的初始化函数,作用是初始化glog
  • google::ParseCommandLineFlags:是google gflags的初始化函数,作用是解析命令行参数,一般都放在 main 函数中开始位置。
  • APP apollo_app_:是实例化函数,实例化control类。
  • ros::init(argc, argv, apollo_app_.Name()):注册节点,这是程序开始的地方,apollo_app_.Name()将以gflags命令行参数形式传入node name,在c++中命令行参数就是字符串,因此apollo_app_.Name()可以看作一个全局的字符串变量。
  • apollo_app_.Spin():在apollo_app.cc中实现,control初始化Control::Init,开始函数Control::Start在这运行。个人认为整个程序最tricky的地方就是这了,和ROScallback函数实现开始不一样,Apollo把程序开始放到了spin()中。

在看apollo_app_.Spin()这个函数之前,先要了解一下在Apollo被广泛引用的apollo::common::Status类该函数载modules/common/status/status.h定义:

class Status {
 public:
  /**
   * @brief Create a success status.
   */
  Status() : code_(ErrorCode::OK), msg_() {}
  ~Status() = default;

  /**
   * @brief Create a status with the specified error code and msg as a
   * human-readable string containing more detailed information.
   * @param code the error code.
   * @param msg the message associated with the error.
   */
  //重载构造函数Status()
  Status(ErrorCode code, const std::string &msg) : code_(code), msg_(msg) {}
  /**
   * @brief Create a status with the specified error code and empty msg
   * @param code the error code.
   */
//重载Status()+防止隐式调用(一个参数的`构造函数`(或者除了第一个参数外其余参数都有默认值的`多参构造函数`))
  explicit Status(ErrorCode code) : code_(code), msg_("") {} 

  /**
   * @brief generate a success status.
   * @returns a success status
   */
  static Status OK() { return Status(); }

  /**
   * @brief check whether the return status is OK.
   * @returns true if the code is ErrorCode::OK
   *          false otherwise
   */
   //默认true, 因为初始化列表:Status() : "code_(ErrorCode::OK)", msg_() {}
  bool ok() const { return code_ == ErrorCode::OK; } 

  /**
   * @brief get the error code
   * @returns the error code
   */
  ErrorCode code() const { return code_; }

  /**
   * @brief defines the logic of testing if two Status are equal
   */
   //重载运算符`==`
  bool operator==(const Status &rh) const { 
    return (this->code_ == rh.code_) && (this->msg_ == rh.msg_);
  }

  /**
   * @brief defines the logic of testing if two Status are unequal
   */
   //重载运算符`!=`
  bool operator!=(const Status &rh) const { return !(*this == rh); }

  /**
   * @brief returns the error message of the status, empty if the status is OK.
   * @returns the error message
   */
  const std::string &error_message() const { return msg_; }

  /**
   * @brief returns a string representation in a readable format.
   * @returns the string "OK" if success.
   *          the internal error message otherwise.
   */
  std::string ToString() const {
    if (ok()) {
      return "OK";
    }
    return ErrorCode_Name(code_) + ": " + msg_;
  }

  /**
   * @brief save the error_code and error message to protobuf
   * @param the Status protobuf that will store the message.
   */
  void Save(StatusPb *status_pb) {
    if (!status_pb) {
      return;
    }
    status_pb->set_error_code(code_);
    if (!msg_.empty()) {
      status_pb->set_msg(msg_);
    }
  }

 private:
  ErrorCode code_;
  std::string msg_;
};