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

Posted frank909

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自动驾驶 Apollo 源码分析系列,系统监控篇:简析Monitor模块工作机制相关的知识,希望对你有一定的参考价值。

前面的文章分析了 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 变量实现。

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 监控硬件、进程、模块、资源几大类。

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

以上是关于自动驾驶 Apollo 源码分析系列,系统监控篇:简析Monitor模块工作机制的主要内容,如果未能解决你的问题,请参考以下文章

自动驾驶 Apollo 源码分析系列,系统监控篇:Monitor模块如何监控硬件

自动驾驶 Apollo 源码分析系列,系统监控篇:Monitor模块如何监控通信中 channel 的时延?

自动驾驶 Apollo 源码分析系列,系统监控篇:Monitor模块如何监控通信中 channel 的时延?

自动驾驶 Apollo 源码分析系列,系统监控篇:Monitor模块如何监控通信中 channel 的时延?

自动驾驶 Apollo 源码分析系列,系统监控篇:Monitor模块如何监控通信中 channel 的时延?

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