前言
本文是针对Apollo 8.0中的Monitor进行阐述,旨在通过其架构和业务逻辑来掌握Monitor。
Monitor总体介绍
架构图
Apollo官网给出的模块关系图
![](https://img-blog.csdnimg.cn/img_convert/6a4d6455cc2bd86cbd8d3136fba81df3.png)
由此可见,Monitor模块定期检测架构中被监控软、硬模块的状态信息,计算出当前系统的整体的健康状态,及时反馈给下游模块(Guardian)。
PS: 个人感觉HMI和Monitor的Data Lines应该是双向的
Monitor给HMI定期输出最终系统状态
Monitor通过HMI拿到当前的HMI状态
分类图
每一个模块都有一个单独的xxxMonitor类来监控。种类较多,文章下面逐一剖析。
![](https://img-blog.csdnimg.cn/img_convert/af74f712ddf745b12d539b30a5fe290d.png)
类图
下图可简单表示Monitor重要类之间的关系
![](https://img-blog.csdnimg.cn/img_convert/f7688b3e232029a3261edef7ebc984a5.png)
Monitor子模块介绍
Monitor
是整个监控的入口模块,Cyber框架的应用模块之一,最终被编译成libmonitor.so被mainboard启动。
继承了Cyber框架的定时组件,所以内部逻辑相当简单,持有若干个xxxMonitor的指针
Init
初始化Monitor Manager、xxxMonitor实例
Proc
串行调度各模块监控的任务,最后产出监控结果
一次监控检测任务顺序
EsdCanMonitor-->SocketCanMonitor-->GpsMonitor-->LocalizationMonitor-->CameraMonitor-->ProcessMonitor-->ModuleMonitor-->LatencyMonitor-->ChannelMonitor-->ResourceMonitor-->SummaryMonitor-->(FunctionalSafetyMonitor)
Monitor Manager
此类被声明为单例模式,被*Monitor调用
主要作用
被Monitor类调用
StartFrame、EndFrame成员函数来开始&&结束一次监控任务。
StartFrame
创建人机交互模块的reader,并获取最新的状态,如果获取不到,直接停止本次监控任务(这也是为什么要同时启动人机交互模块)
Channel: hmi_status_topic, /apollo/hmi/status
消息: modules/common_msgs/dreamview_msgs/hmi_status.proto: HMIStatus
判断上次的运行方式与本次的运行方式(HMIStatus.current_mode)是否改变,
改变
记录当前运行方式
获取当前运行方式的配置(apollo::dreamview::HMIMode)
初始化系统状态中各组件状态字段
没改变
清理历史上其他模块的结果
更新自动驾驶标识字段并返回true
EndFrame: 调用log_buffer_对象来发布消息
监控结果channel: /apollo/monitor
消息类型: modules/common_msgs/monitor_msgs/monitor_log.proto: MonitorMessage
被xxxMonitor类调用
CreateReader、CreateWriter成员模板函数来创建不同类型的reader和writer
reader被缓存在Monitor Manager内部
Getters
GetStatus : 获取当前系统整体的状态(SystemStatus: status_)
SystemStatus: modules/common_msgs/monitor_msgs/system_status.proto
IsInAutonomousMode: 判断当前是否为自动驾驶模式
如果当前是离线模式(use_sim_time被设置true) 为false
创建底盘的reader,如果创建不成功,为false
Channel: chassis_topic, /apollo/canbus/chassis
消息: modules/common_msgs/chassis_msgs/chassis.proto: Chassis
通过底盘reader获取最新的底盘状态,如果Chassis消息中的头部模块名字被标记为SimControl, 为false (因为仿真不需要安全检查)
判断消息是否过期,过期为否
消息时间 + FLAGS_system_status_lifetime_seconds(default: 30s) < 当前时间即为过时
判断底盘消息中的驾驶模式是否为自动驾驶模式,直接返回
GetHMIMode: 获取人机交互模块的配置
其内部的node成员是Monitor继承TimerComponet而来的。
RecurrentRunner
是所有xxxMonitor的父类,其内部有两个主要的方法
Tick
根据xxxMonitor的监控周期来调用RunOnce方法
RunOnce
此方法为纯虚函数,xxxMonitor实现自己的监控逻辑。
软件模块
Camera Monitor
消息来源:
CameraCompent : modules/drivers/camera (未移植)
Channel name(实际上应该与modules/drivers/camera/conf/camera*.pb.txt中channel name一致)
FLAGS_image_long_topic
Default: /apollo/sensor/camera/traffic/image_long
FLAGS_camera_image_long_topic
Default: /apollo/sensor/camera/image_long
FLAGS_camera_image_short_topic
Default: /apollo/sensor/camera/image_short
FLAGS_camera_front_6mm_topic
Default: /apollo/sensor/camera/front_6mm/image
FLAGS_camera_front_6mm_2_topic
Default: /apollo/sensor/camera/front_6mm_2/image
FLAGS_camera_front_12mm_topic
Default: /apollo/sensor/camera/front_12mm/image
消息
类型: apollo::drivers::Image
定义: modules/common_msgs/sensor_msgs/sensor_image.proto
模块用途
摄像头是否存在且只能存在一个
监控检测逻辑
串行判断所有摄像头的Channel,记录下frame_id,如果检测到当前摄像头存在且已经有摄像头存在即报错
最终一个都没有检测到即报错,否则报正常
如何开启
在modules/dreamview/conf/hmi_modes下的配置文件中monitored_components模块里面指定FLAGS_camera_component_name的名字
Channel Monitor
模块用途
监控modules/dreamview/conf/hmi_modes下配置文件中monitored_components里面指定channel数据是否有效(为空或者缺失字段)、时延、发送频率等指标
监控检测逻辑
获取当前的HMImode
如果被监控组件配置中有channel字段,则计算更新频率
创建相对应的reader并且获取最新的message
reader创建不成功时,直接下发UNKNOWN状态
最新message为空时,直接下发FATAL状态
检查reader中的channel延迟情况, 不符合预期则下发FATAL状态
reader->GetDelaySec()
检查message中是否缺失字段,不符合预期则下发ERROR状态
被监控字段定义: modules/dreamview/proto/hmi_mode.proto: ChannelMonitorConfig.mandatory_fields 目前并没有被使用
检查更新频率是否在预期范围内,不符合预期则下发WARN状态
内部持有LatencyMonitor的指针,并通过GetFrequency来计算更新频率
如果以上全部符合预期,下发OK状态
如何开启
modules/dreamview/conf/hmi_modes下配置文件中monitored_components里面指定channel字段即自动开启。
Functional Satety Monitor
模块用途
此模块在Summay Monitor之后执行,会根据汇总的结果来确定是否要采取一定的措施,比如说紧急停车
开启方法
FLAGS_enable_functional_safety, 默认是开启的
监控检测逻辑
确定当前是否安全,如果安全,则跳过本次监控
如果当前是非自动驾驶模式,则认为是安全的
检查HMI Modules、Monitored Component的状态,如果没有任何的ERROR或者FATAL,则认为是安全的
判断请求停车是否被触发过,触发过则跳过本次监控
判断是否有安全模式触发时间,如果没有,设置新的安全模式触发时间,跳过本次监控
判断在safety_mode_seconds_before_estop(10s)时间内有没有采取任何措施,如果没有,则设置紧急停车状态位
安全模式触发时间 + safety_mode_seconds_before_estop < 当前时间,即认为没有采取任何措施
Latency Monitor
模块用途
计算所有模块时延,本身并不下发状态码,统计的数据下发到指定channel中去
为ChannelMonitor提供channel更新频率数据
消息来源
哪个模块需要被监控时延,需要模块自己创建LatencyRecorder实例
时延记录输入
Channel: latency_recording_topic /apollo/common/latency_records
消息: modules/common/latency_recorder/proto/latency_record.proto: LatencyRecordMap
统计输出
Channel: latency_reporting_topic /apollo/common/latency_reports
消息:modules/common/latency_recorder/proto/latency_record.proto: LatencyReport
监控检测逻辑
创建输入时延记录channel的reader,并设置最大取消息数量(30条)
获取多条LatencyRecordMap消息,记录并计算频率保存在成员变量里,以供查询
如果满足时延报告周期,则对外发布消息
当前时间-上次报告时间 > 报告周期
如果开启
自动开启,只要有模块把延时上报,监控模块就会有统计报告
Localization Monitor
模块用途
主要用来监控定位数据,最后根据订阅来的状态码来更新最终的状态
消息来源
modules/localization
输入Channel
localization_msf_status: /apollo/localization/msf_status
消息
modules/common_msgs/localization_msgs/localization.proto: LocalizationStatus
监控检测逻辑
检查定位模块是否被监控,如果没被监控,跳过
创建reader并获取最新message
如果最新message为空则下发ERROR状态
透传定位状态码到组件状态码并下发,对应关系
MeasureState::OK : ComponentStatus::OK
MeasureState::WARNNING : ComponentStatus::WARN
MeasureState::ERROR : ComponentStatus::WARN
MeasureState::CRITICAL_ERROR: ComponentStatus::ERROR
MeasureState::FATAL_ERROR: ComponentStatus::FATAL
Module Monitor
模块用途
这是通过Cyber框架中Node服务发现手段来检测被监控模块是否还存在
监控检测逻辑
对于每一个被监控的模块,用NodeManager去查看是否有模块Node,如果在启动时配置的Node任意一个不存在,则下发FATAL状态码
NodeManager即为cyber::service_discovery::NodeManager,可以找到所有存在的Node节点,一个正常运行的模块至少存在一个Node节点
Process Monitor
模块用途
这是通过当前所有正在运行的进程,检测预期进程是否还存在
监控检测逻辑
通过所有正在运行的进程(/proc/<PID>/cmdline)来获取所有的命令字符串
分别检查HMI Modules、Monitored Components、 other components中的所有启动关键字是否在存活进程列表中,如果有一个不存在,则下发FATAL
Recorder Monitor
模块用途
监控SmartRecorder模块的状态,最后根据SmartRecorder模块的状态来下发状态
输入
Channel: recorder_status_topic
消息: modules/common_msgs/monitor_msgs/smart_recorder_status.proto: SmartRecorderStatus
监控检测逻辑
检查SmartComponent组件是否被监控,如果没有则跳过
创建reader并且获取最新的message
如果没有最新message,则下发error
直接映射透传最新message中的recording_state
RecordingState::RECORDING: ComponentStatus::OK
RecordingState::TERMINATING: ComponentStatus::WARN
RecordingState::STOPPED: ComponentStatus::OK
Summary Monitor
模块用途
这个模块是整个监控体系中最重要的,xxxMonitor都调用此模块来修改Monitor Manager中的SystemStatus,内部具有优先级的判断。另外,本身也有一些汇总状态升级的逻辑。
组件状态优先级: FATAL > ERROR > WARN > OK > UNKNOWN
监控监测逻辑
将SystemStatus中的组件状态(Process、Module、Channel、Resource、Other)汇总到最严重的级别
序列化SystemStatus,并判断是否达到监控结果广播周期,如果判断到周期后,则广播
判断系统状态hash值和上一次是否一致
当前时间 - 上次广播时间 > 系统状态广播间隔(system_status_publish_interval: 1s)
硬件模块
Esdcan Monitor
模块用途
用来监控ESD-CAN设备的,看设备是否在线
如何开启
编译之前需要加上USE_ESD_CAN编译参数,现在默认不开启
监控检测任务
获取Canbus组件,如果没有获取不到,则跳过
根据can_id创建一个handle,然后通过canIoctl来获取设备状态,如果一切正常,说明设备在线,下发OK,反之不在,下发ERROR
GPS Monitor
模块用途
用来监控GPS的状态
输入
Channel: gnss_best_pose_topic
消息: modules/common_msgs/sensor_msgs/gnss_best_pose.proto: GnssBestPose
监控监测逻辑
获取GPS组件,如果获取不到,跳过本次监控
创建reader并且获取最新的message
根据最新message的SolutionType来确定组件状态
SolutionType::NARROW_INT: ComponentStatus::OK
SolutionType::SINGLE: ComponentStatus::WARN
Default: ComponentStatus::ERROR
Resource Monitor
模块用途
根据预设的阈值来监控服务器的资源,
如何开启
modules/dreamview/conf/hmi_modes下配置monitored_modules只要有resource相关配置就会开启
监控检测逻辑
获取被监控的组件,逐一检查是否配置resource字段,如果没有配置,跳过
对于有资源阈值的别监控组件,逐一检查硬件资源,有任何不符合预期即下发ERROR和WARN
检查磁盘空间
检查CPU使用率
检查内存使用率
检查磁盘负载
SocketCan Monitor
模块用途
用来监控Socket Can设备,与Edscan Monitor类似
监控检测逻辑
根据名字获取相关的组件,获取不到即跳过本次监控
打开Socket CAN的handler
设置Message Filter, 失败即返回ERROR
允许CAN的响应
利用ioctl和bind来测试设备是否正常运转,出错返回ERROR