Skip to content

#

modules/guardian/guardian_component.h

namespace apollo {
namespace guardian {

class GuardianComponent : public apollo::cyber::TimerComponent {
 public:
  bool Init() override;
  bool Proc() override;

 private:
  void PassThroughControlCommand();
  void TriggerSafetyMode();

  apollo::guardian::GuardianConf guardian_conf_;
  apollo::canbus::Chassis chassis_;
  apollo::monitor::SystemStatus system_status_;
  apollo::control::ControlCommand control_cmd_;
  apollo::guardian::GuardianCommand guardian_cmd_;

  double last_status_received_s_{};

  std::shared_ptr<apollo::cyber::Reader<apollo::canbus::Chassis>>
      chassis_reader_;
  std::shared_ptr<apollo::cyber::Reader<apollo::control::ControlCommand>>
      control_cmd_reader_;
  std::shared_ptr<apollo::cyber::Reader<apollo::monitor::SystemStatus>>
      system_status_reader_;
  std::shared_ptr<apollo::cyber::Writer<apollo::guardian::GuardianCommand>>
      guardian_writer_;

  std::mutex mutex_;
};

CYBER_REGISTER_COMPONENT(GuardianComponent)

}  // namespace guardian
}  // namespace apollo

组件结构#

组件定义#

  • 继承 apollo::cyber::TimerComponent 组件 , 重写 Init 和 Proc 方法;
  • Init 是组件初始化时被调用;
  • Proc 是定时器要调用的方法;
CYBER_REGISTER_COMPONENT(GuardianComponent)

// 宏展开内容
namespace { 
    struct ProxyType2 { 
        ProxyType2() { 
            apollo::cyber::class_loader::utility::RegisterClass<GuardianComponent, apollo::cyber::ComponentBase>( "GuardianComponent", "apollo::cyber::ComponentBase");
        }
    };
    static ProxyType2 g_register_class_2; 
}
  • ProxyType2 类名为宏展开生成的,不同组件是不重复的,并创建对应静态实例 g_register_class_2;
  • 并通过 RegisterClass 方法 注册到class_factory中,(cyber/class_loader/utility/class_loader_utility.h)
  • class_loader_utility有对应的动态库加载操作,在加载动态库的同时,静态变量g_register_class_2将构造初始化,同时class_factory 也会有改组件注册的信息;
class TimerComponent : public ComponentBase {
 public:
  TimerComponent();
  ~TimerComponent() override;

  /**
   * @brief init the component by protobuf object.
   *
   * @param config which is define in 'cyber/proto/component_conf.proto'
   *
   * @return returns true if successful, otherwise returns false
   */
  bool Initialize(const TimerComponentConfig& config) override;
  void Clear() override;
  bool Process();
  uint64_t GetInterval() const;

   private:
  /**
   * @brief The Proc logic of the component, which called by the CyberRT frame.
   *
   * @return returns true if successful, otherwise returns false
   */
  virtual bool Proc() = 0;

  uint64_t interval_ = 0;
  std::unique_ptr<Timer> timer_;
};

//
bool TimerComponent::Initialize(const TimerComponentConfig& config) {
  if (!config.has_name() || !config.has_interval()) {
    AERROR << "Missing required field in config file.";
    return false;
  }
  node_.reset(new Node(config.name()));
  LoadConfigFiles(config);
  if (!Init()) {
    return false;
  }

  std::shared_ptr<TimerComponent> self =
      std::dynamic_pointer_cast<TimerComponent>(shared_from_this());
  auto func = [self]() { self->Process(); };
  timer_.reset(new Timer(config.interval(), func, false));
  timer_->Start();
  return true;
}
  • cyber组件在初始化时,会 传配置数据 调用Initialize方法初始化TimerComponent基类所需数据对象(timer定时器等),并会调用Init方法初始化子类实例;
  • 通过Lambda将 self->Process() 函数封装传给定时器,由定时器来触发调用;

  • 定时器采用单调时钟进程触发(steady_clock::now()),单调时钟为系统开机所经过的时间;

void TimingWheel::TickFunc() {
  Rate rate(TIMER_RESOLUTION_MS * 1000000);  // ms to ns
  while (running_) {
    Tick();
    // AINFO_EVERY(1000) << "Tick " << TickCount();
    tick_count_++;
    rate.Sleep();
    {
      std::lock_guard<std::mutex> lock(current_work_wheel_index_mutex_);
      current_work_wheel_index_ =
          GetWorkWheelIndex(current_work_wheel_index_ + 1);
    }
    if (current_work_wheel_index_ == 0) {
      {
        std::lock_guard<std::mutex> lock(current_assistant_wheel_index_mutex_);
        current_assistant_wheel_index_ =
            GetAssistantWheelIndex(current_assistant_wheel_index_ + 1);
      }
      Cascade(current_assistant_wheel_index_);
    }
  }
}
void TimingWheel::Tick() {
  auto& bucket = work_wheel_[current_work_wheel_index_];
  {
    std::lock_guard<std::mutex> lock(bucket.mutex());
    auto ite = bucket.task_list().begin();
    while (ite != bucket.task_list().end()) {
      auto task = ite->lock();
      if (task) {
        ADEBUG << "index: " << current_work_wheel_index_
               << " timer id: " << task->timer_id_;
        auto* callback =
            reinterpret_cast<std::function<void()>*>(&(task->callback));
        cyber::Async([this, callback] {
          if (this->running_) {
            (*callback)();
          }
        });
      }
      ite = bucket.task_list().erase(ite);
    }
  }
}
  • cyber 会创建一个1ms周期定时触发器 (timing_wheel),通过 rate.Sleep() 来减小时间的抖动,里面会记录上一次的执行开始时间和结束时间,计算出需要sleep的时间;如果超过了会直接执行;
  • sleep 后会 计算本周器需要触发的任务TimerBucket (TimerTask list),并在Tick()执行 , 通过cyber::Async 将 callback 进行异步执行,不阻塞该定时器触发线程;
  • cyber::Async 调用内部协程机制去响应方法函数,无线程切换等上下文操作, 相比较线程更快;