前面的文章有分析,Monitor 模块监控的内容分为 Hardware 和 Software 两位。
本篇分析硬件监控部分。
首先,可以观察一下 Apollo 官方文档给出的硬件连接图。
跟自动驾驶本身相关的无非是传感器和底盘。
当前 Monitor 系统支持的硬件类监控有 4 个:
ESD CAN 是一种 CanCard,在 Apollo 中通过 PCIe 接口连接到 6108 工控机上面,在 Apollo 1.0 版本的官方文档就有介绍过 ESD CAN 型号是 ESD CAN-PCIe/402-1。 它长这个样子:
ESD CAN 接收到的信号有 2 类:
我在前面的文章中有写过,各类 xxxMonitor 其实是 RecurrentRunner 子类。
EsdMonitor 也是如此,它和 CameraMonitor 一样也是 RecurrentRunner 子类。
EsdCanMonitor 在初始化的时候设置了自己的模块名字和周期执行间隔,这里时间间隔是 3 秒,也就是 EsdCan 每 3 秒被监控 1 次。
我们也可以看到 EsdCanMonitor 的核心方法其实是 EsdCanTest。
在 EsdCanTest 中检测到的结果,最后会通过 SummaryMonitor.EscalateStatus 方法提升自身状态等级。
当然,如果 ESD CAN 根本不存在,那么就返回 ERROR 错误类型。
EsdCanTest 内部创建了 NT_HANDLE 类型变量 handle,并基于它进行测试。
应该是借助于 EsdCan 厂商自带的驱动测试函数。上面代码很简单,通过调用 3 个函数进行了 5 类测试。
然后根据测试的结果返回。
测试的可能结果还挺多的,就不一一列出了。
NTCAN_SUCCESS:
NTCAN_RX_TIMEOUT:
NTCAN_TX_TIMEOUT:
NTCAN_TX_ERROR:
NTCAN_CONTR_OFF_BUS:
NTCAN_CONTR_BUSY:
...
然后 EsdCan 的监控的基本逻辑就没有了,它的工作更多借助于厂商的驱动测试API完成。
GpsMonitor 的代码更简单。
监控周期也是每隔 3 秒一次。
主要逻辑是接收 GnssBestPose 这个 Topic,获取它的状态,结果有 3 种:
GnssBestPose 和 SolutionType 的定义都来自 GNSS 驱动,路径在。
modules/drivers/gnss/proto/gnss_best_pose.proto
Socket CAN 是个什么东西呢?
我们知道 Socket,也知道在汽车行业中广泛通过 CAN 协议传输,那么 Socket CAN 是什么呢?
它是在 Linux 环境下基于 Socket 机制实现 CAN 协议的一套机制。
Apollo 中也支持对它的监控。
可以看到核心方法是 SocketCanTest。
通过 socket 方法得到一个 handler。
注意 socket() 中的参考,PF_CAN 有别于我们常使用的 TCP 类 Socket 开发。
socket(AF_INET,SOCK_STREAM,0)
这说明 SocketCAN 和普通的 TCP/IP 是不一样的。
SocketCanTest() 中通过 SocketCanHandlerTest 执行操作。
检测的逻辑也非常简单:
ResourceMonitor 监控的对象是那些通用的物理资源,当前包含 CPU、内存、磁盘。
上面代码显示并没有多特别之处,下面是这的实现。
ResourceMonitor 每隔 5 秒监控 1 次,它需要从 HMI 中获取受监控的配置项目。
在代码检测磁盘空间是通过 boost::filesystem 中的 space() 方法。
得到的结果需要和 config 中规定的阈值进行判断,产生 ERROR 和 WARN 两种结果。
实际执行的是 GetSystemCPUUsage 或者 GetCPUUsage 方法。
核心逻辑无非就是通过代码执行命令行脚本 /proc/stat
。这个命令包含了系统内核中很多信息,就如 CPU 信息。比如,我在我的 WIN11 系统中的 WSL 中查看 /proc/stat 信息,出现下面的结果 :
cpu 状态有很多信息,每一列有独特的意义。
cpu 统计时间的单位是 jiffies。 大家可能在想,代码如何拿到 /proc/stat 信息的呢?
因为在 Linux 中,万物皆文件。只要通过 ifstream 读取那个路径,然后 getLine 一行一行解析就好了。 然后,如果要统计单个进程 PID 的CPU 信息,则需要通过 /proc/pid/stat 命令。
有 4 种时间
最终的 CPU 时长:
cputime = utime+stime+cutime+cstime
CPU 使用率公式:
usage = (time - pretime)/monitor_time
就是在一次监控周期内,两次 cputime 统计值的差占监控时间的比例。
CPU 状态是否报警取决于结果和配置中预设的值的比较。
检查内存使用情况的逻辑和 CPU 差不多。
如果没有进程 DAG 则检测 SystemMemoryUsage 否则就通过 pid 一个个获取单个进程的内存信息。
通过命令行 /proc/meminfo 获取内存信息。
得到总共的内存,和当前使用的内存,然后求比例。 单个进程使用的内存信息通过 /proc/pid/statm 命令求得。
内存使用率公式:
usage = usedMem/TotalMem
计算已使用了的内存在整个内存容量的占比。
字面意思是检测磁盘负载。
需要通过 GetSystemDiskload 获取各个设备的负载值,然后和配置中的阈值做比较,最终得到 Error 或者 WARN 状态。
借助的是 /proc/diskstats 命令,这个命令可以查看磁盘的相关信息。
第2列也就是 ram0、loop0、sda 之类是 devicename。 第12列是 I/O 耗费的时间,单位是 ms。
磁盘负债的比例计算公式是:
usage = (当前I/O时间 - 上一次I/O时间)/监控间隔时长