#
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 调用内部协程机制去响应方法函数,无线程切换等上下文操作, 相比较线程更快;