前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自动驾驶 Apollo 源码分析系列,系统监控篇(一):简析Monitor模块工作机制

自动驾驶 Apollo 源码分析系列,系统监控篇(一):简析Monitor模块工作机制

作者头像
Frank909
发布2022-05-10 14:51:54
1.1K0
发布2022-05-10 14:51:54
举报
文章被收录于专栏:Frank909Frank909

前面的文章分析了 Apollo 6.0 中的 Guardian 模块,引发了我对 Monitor 模块的好奇心。 ​

在这里插入图片描述
在这里插入图片描述

我们可以看到 Guardian 除了接收 Control 模块的信息外,还要接收来自 Monitor 发过来的信息,事实上 Guardian 根据 Monitor 传输的 system status 信息判断是否需要紧急停车。 ​

本篇文章的目的就是为了搞清楚 Monitor 的主要工作流程。 ​

Monitor 的职责

根据 Apollo 官方开发者文档提示,Monitor 模块主要作用有 2 大类:

  1. 硬件状态检测
  2. 软件模块状态监控

每个大类下面又细分了许多小类,如下图所示:

在这里插入图片描述
在这里插入图片描述

可以看到 Monitor 需要监控的东西非常多,涉及到传感器,也涉及到了系统物理资源,而软件层面的进程、模块、时延、消息通道也需要监控。 ​

接下来我们具体到代码层面分析。 ​

Monitor 工作流程

Monitor 的代码路径在 modules/monitor 目录下。 ​

在这里插入图片描述
在这里插入图片描述

按照定义,我们可以发现,Monitor 就是一个普通的定时器组件,单独继承了 Init 和 Proc 两个模板方法。成员变量也只有一个 RecurrentRunner 的 vector。 ​

我们先分析 Init 方法。 ​

Monitor 的 Init() 初始化

在 monitor.cc 中有 init 方法实现,代码也很简单。 ​

在这里插入图片描述
在这里插入图片描述

我们看到,初始化一个 MonitorManager 实例,并且创建不同类型的 xxxMonitor,并依次将它们压入 runners 这个 vector 容器当中。 ​

需要特别处理的是 FunctionalSafetyMonitor,只有 FLAGS_enable_functional_safety 为真时,它才会被添加进去。 ​

Monitor 的 Proc() 方法

Proc() 中代码非常简短。 ​

在这里插入图片描述
在这里插入图片描述

通过 MonitorManager 的 StartFrame 为起始,EndFrame 为结束,代表一次监控任务操作。在每一次监控周期当中触发 runners_ 中不同的 xxxMonitor 的 Tick() 方法就完事了。 ​

所以,真正起监控作用的还是 xxxMonitor。 ​

根据官方文档的提示,Monitor 运行时,先扫描不同的子 Monitor,然后通过 SummaryMonitor 做整体状态的监控报告,产生 4 类状态:

  • Fatal
  • Error
  • Warn
  • OK
  • Unkown

另外,刚刚提到过 FunctionalSafetyMonitor 也是值得关注的。 ​

所以,如果想搞懂 Monitor 这个子系统的基础工作流程,我们只需要关注下面几个类:

  • MonitorManager
  • RecurrentRunner
  • SummaryMonitor
  • FunctionalSafetyMonitor

MonitorManager

先看定义:

在这里插入图片描述
在这里插入图片描述

核心关注点有 3 个:

  1. SystemStatus 变量,之前分析 Guardian 模块中有注意到,Monitor 发送它的状态,里面有是否需要紧急停车的请求;
  2. in_autonomous_driving 变量,用来判断是否在自动驾驶模式,这个很重要,因为有些异常如果是人工驾驶状态是可以忽略的;
  3. MonitorManager 采用单例模式,这样保证获取到的实例是同一个。

MonitorManager 我不想过多分析,我关注的是 SystemStatus 变量。 ​

它是在 proto 文件中定义的,编译后会产生 .h 文件,路径是 modules/monitor/proto/system_status.proto。我也其中找到了我想要关注的东西。 ​

在这里插入图片描述
在这里插入图片描述

SystemStatus 中有 2 个 map,一个是保存不同组件的状态,另外一个是为了给 HMI 传输故障状态。 ​

SystemStatus 还有一个 passenger_msg,用来向乘客传递一些信息,这些信息可以通过声光形式提示乘客。 ​

SystemStatus 有一个变量 require_emergency_stop,如果经 Monitor 判断需要紧急停车时,它就会置为 true,然后传递给 Guardian。它正是本文需要分析的目标之一。 ​

在这里插入图片描述
在这里插入图片描述

startframe 主要作用是读取 HMI 的状态,并保持同步。 ​

在这里插入图片描述
在这里插入图片描述

endframe 只需要打印 logs。 ​

RecurrentRunner

前面分析,Monitor 中实际干活的是各类 xxxMonitor,它们都是 RecurrentRunner 的子类,按照单词字面意思就知道都是周期性任务执行器。 ​

在这里插入图片描述
在这里插入图片描述

既然是周期性执行器,那么肯定有每次执行间隔时长,这个是 interval_ 变量指定,它指定了 Tick() 方法被定义触发,Tick() 会调用 RunOnce() 方法。 ​

在这里插入图片描述
在这里插入图片描述

因为 Monitor 执行频率很高,为了减轻 CPU 负担,也根据各个模块的定时需求,Tick 不是每次都会被触发。在一个监控周期内,它只执行一次。 ​

真正干活的是 RunOnce() 方法,但它需要在 RecurrentRunner 的子类中实现。 ​

我们先分析 SummaryMonitor。 ​

SummaryMonitor
在这里插入图片描述
在这里插入图片描述

​SummaryMonitor 对整个系统状态负责,核心方法是 EscalateStatus,它需要综合其他 Monitor 的监控信息然后根据情况决定整体系统的 status 定义。

在这里插入图片描述
在这里插入图片描述

按照定义,status 的权重 FATAL > ERROR > WARN > OK > UNKNOW,高的权重可以覆盖低权重。 ​

前面一节讲过,RecurrentRunner 的子类会覆写 RunOnce 方法。

在这里插入图片描述
在这里插入图片描述

其它的 RecurrentRunner 不需要每次在 Tick() 方法中触发 RunOnce() 方法,但 SummaryMonitor 需要,因为它的职责是在每一个Tick中更新各个componentstatus。 ​

在这里插入图片描述
在这里插入图片描述

然后,在合适的时机定期广播出来,代码也简单。 ​

FunctionalSafetyMonitor

快接近目的地了,FunctionalSafetyMonitor 负责安全相关,它将触发紧急停车信号。 ​

在这里插入图片描述
在这里插入图片描述

注释写得很明白,这个 Monitor 有 2 个目的:

  1. 通知驾驶员采取行动
  2. 触发 Guardian 模块,如果预期的安全措施没有发生

在这里插入图片描述
在这里插入图片描述

代码逻辑也非常简单,整理成流程图是这样的: ​

在这里插入图片描述
在这里插入图片描述

整个处理过程经历了 4 个判断。 ​

第 1 个判断

通过 checksafety() 方法检测系统是否安全,如果安全的话就清除紧急停车相关的标志,如果不安全则进入后续的流程。 ​

第 2 个判断

通过 require_emergency_stop() 方法申请紧急停车,如果系统已经申请过了,那么就返回,如果系统还没有申请过紧急停车,则进入后续流程。 ​

第 3 个判断

判断是否已经设置了安全模式触发时间,如果没有则设置安全时间然后返回,如果设置了的话则进入后续流程。 ​

第 4 个判断

如果前面检测到了系统设置的安全模式触发时间,那么就需要判断它是否超时了。 ​

如果安全模式触发后,在规定时间内系统没有响应,那么就申请紧急停车,通过设置 system_status 变量实现。 ​

代码语言:javascript
复制
system_status->set_require_emergency_stop(true);

最终,紧急停车命令就产生了。当然,我们还需要关注之前的安全判断逻辑。 ​

CheckSafety()
在这里插入图片描述
在这里插入图片描述

核心逻辑有 3 点:

  1. 只对自动驾驶状态下的安全监控负责
  2. 检测 HMI 中配置的各个 modules 状态
  3. 检测受监控的其他 components 模块状态

在这里插入图片描述
在这里插入图片描述

前面讲过,ComponentStatus 有 5 个状态,判断的依据是 ERROR 和 FATAL 是不安全的,其它的是安全的。 ​

并且,FunctionalSafetyMonitor 的安全判断也是基于其他监控模块自身上报的状态,它也是从系统整体角度出发的。 ​

其他受监控的模块如何上报自己的状态呢? ​

答案是通过自身 updatestatus 方法和 SummaryManager.EscalateStatus() 方法。 比如,我们观察 CameraMonitor 代码。

在这里插入图片描述
在这里插入图片描述

RunOnce() 方法中调用了 UpdateStatus(),然后调用了 SummaryMonitor.EscalateStatus(),最终完成了本 Monitor 的状态更新。 ​

Monitor 的骨架和安全监控机制

有了前面的基础分析,我们现在可以绘制 Monitor 模块的骨架了。

上面是基础的静态结构,当然,动态行为我们也不难得到。

总结

  1. 相对 Guardian 模块,Monitor 模块复杂一点,但也比较简单。
  2. Monitor 模块核心类是 Monitor、MonitorManager、SummaryMonitor、FunctionalSafetyMonitor,它们能形成一个完整的监控逻辑。
  3. Monitor 监控硬件、进程、模块、资源几大类。

本文完,后续的文章依次介绍单个模块如何进行状态监控。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Monitor 的职责
  • Monitor 工作流程
    • Monitor 的 Init() 初始化
      • Monitor 的 Proc() 方法
        • MonitorManager
          • RecurrentRunner
            • SummaryMonitor
              • FunctionalSafetyMonitor
                • 第 1 个判断
                • 第 2 个判断
                • 第 3 个判断
                • 第 4 个判断
                • CheckSafety()
            • Monitor 的骨架和安全监控机制
            • 总结
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档