1. 程式人生 > >Apollo程式碼解析:4. control模組

Apollo程式碼解析:4. control模組

0. 簡介:

閱讀本章之前預設已經閱讀了:

首先來看看整體的邏輯圖:

這裡寫圖片描述

由此可知planning和control是整個Apollo的核心,由於個人喜好的原因先看control模組。

開啟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_;
};