第九部分:Monitor模块详解
免责声明
本文档仅供学习和技术研究使用,内容基于 Apollo 开源项目的公开资料和代码分析整理而成。文档中的技术实现细节、架构设计等内容可能随 Apollo 项目更新而变化。使用本文档所述技术方案时,请以 Apollo 官方最新文档为准。
声明事项:
- 本文档不构成任何商业使用建议
- 涉及自动驾驶技术的应用需遵守当地法律法规
- 作者不对因使用本文档内容产生的任何后果承担责任
- Apollo 为百度公司注册商标,本文档为非官方技术解析
1. Monitor模块概述
1.1 模块定位
Monitor模块是Apollo自动驾驶系统的健康监控中枢,负责实时监控所有模块、进程、通道和系统资源的状态,并在异常时触发Guardian安全模式。
核心职责:
- 监控所有关键进程运行状态
- 监控CyberRT消息通道更新频率
- 监控系统资源(CPU/内存/磁盘)
- 监控硬件设备(GPS/CAN/传感器)
- 汇总状态并触发安全模式
- 向HMI提供系统健康信息
关键特性:
- 12个监控器并行运行
- 1.5秒检测周期
- 层级状态汇总: UNKNOWN < OK < WARN < ERROR < FATAL
- 主动触发Guardian: 通过设置safety_mode_trigger_time
- 实时HMI反馈: 向Dreamview提供状态信息
2. 系统架构设计
2.1 整体架构
┌──────────────────────────────────────────────────────────┐
│ Monitor Component │
│ (100Hz TimerComponent) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ MonitorManager (Singleton) │ │
│ │ - SystemStatus管理 │ │
│ │ - HMIMode配置 │ │
│ │ - Reader/Writer工厂 │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ 12个RecurrentRunner (各自独立周期): │ │
│ │ │ │
│ │ 1. ProcessMonitor (1.5s) - 进程状态 │ │
│ │ 2. ModuleMonitor (1.5s) - 模块状态 │ │
│ │ 3. ChannelMonitor (5s) - 消息通道 │ │
│ │ 4. LatencyMonitor (5s) - 消息延迟 │ │
│ │ 5. ResourceMonitor (5s) - 系统资源 │ │
│ │ 6. GpsMonitor (2s) - GPS硬件 │ │
│ │ 7. LocalizationMonitor (2s) - 定位质量 │ │
│ │ 8. CameraMonitor (2s) - 相机状态 │ │
│ │ 9. EsdCanMonitor (1s) - ESD CAN卡 │ │
│ │ 10. SocketCanMonitor (1s) - Socket CAN │ │
│ │ 11. SummaryMonitor (1s) - 状态汇总 │ │
│ │ 12. FunctionalSafetyMonitor - 功能安全检查 │ │
│ └────────────────────────────────────────────────────┘ │
└──────────────────────────┬───────────────────────────────┘
│ SystemStatus (10Hz)
↓
┌─────────────────┐
│ Guardian │ ← 触发安全模式
└─────────────────┘
↓
┌─────────────────┐
│ Dreamview │ ← 显示系统状态
└─────────────────┘
2.2 RecurrentRunner基类
所有监控器继承自RecurrentRunner:
cpp
class RecurrentRunner {
public:
RecurrentRunner(const std::string &name, const double interval);
// 每次Monitor::Proc()调用时执行
void Tick(const double current_time) {
if (current_time >= next_round_) {
RunOnce(current_time); // 到达间隔时间则执行
next_round_ = current_time + interval_;
round_count_++;
}
}
// 子类实现具体监控逻辑
virtual void RunOnce(const double current_time) = 0;
private:
std::string name_;
double interval_; // 执行间隔(秒)
double next_round_; // 下次执行时间
unsigned int round_count_;
};
执行频率示例:
Monitor Proc() @ 100Hz (每10ms)
t=0ms: 所有Runner初始化
t=10ms: Tick() - 未到时间,跳过
...
t=1000ms: ProcessMonitor::RunOnce() (1.5s间隔,首次执行)
EsdCanMonitor::RunOnce() (1s间隔)
SummaryMonitor::RunOnce() (1s间隔)
t=2000ms: GpsMonitor::RunOnce() (2s间隔)
t=5000ms: ChannelMonitor::RunOnce() (5s间隔)
ResourceMonitor::RunOnce() (5s间隔)
3. 核心监控器详解
3.1 监控器列表
| 监控器 | 检测周期 | 监控内容 | 失败影响 |
|---|---|---|---|
| ProcessMonitor | 1.5s | 进程是否存在 | FATAL → Guardian |
| ModuleMonitor | 1.5s | Cyber模块状态 | FATAL → Guardian |
| ChannelMonitor | 5s | 消息更新频率 | ERROR/WARN |
| LatencyMonitor | 5s | 消息端到端延迟 | WARN |
| ResourceMonitor | 5s | CPU/内存/磁盘 | WARN/ERROR |
| GpsMonitor | 2s | GPS信号质量 | WARN/ERROR |
| LocalizationMonitor | 2s | 定位精度 | ERROR |
| CameraMonitor | 2s | 相机帧率 | WARN |
| EsdCanMonitor | 1s | ESD CAN卡状态 | FATAL |
| SocketCanMonitor | 1s | Socket CAN状态 | FATAL |
| SummaryMonitor | 1s | 汇总所有状态 | - |
| FunctionalSafetyMonitor | 1s | 功能安全检查 | 触发Guardian |
3.2 状态级别
cpp
enum Status {
UNKNOWN = 0; // 未知(初始状态)
OK = 1; // 正常
WARN = 2; // 警告(可继续运行)
ERROR = 3; // 错误(功能受限)
FATAL = 4; // 致命(必须停止)
}
状态升级规则:
UNKNOWN → OK → WARN → ERROR → FATAL
↑ ↑ ↑ ↑
正常 轻微异常 严重异常 崩溃
4. 进程监控机制
4.1 ProcessMonitor实现
cpp
class ProcessMonitor : public RecurrentRunner {
public:
ProcessMonitor()
: RecurrentRunner("ProcessMonitor", 1.5) {} // 1.5秒周期
void RunOnce(const double current_time) override {
// 1. 获取所有运行中的进程
std::vector<std::string> running_processes;
for (const auto& cmd_file : cyber::common::Glob("/proc/*/cmdline")) {
std::string cmd_string;
if (cyber::common::GetContent(cmd_file, &cmd_string)) {
std::replace(cmd_string.begin(), cmd_string.end(), '\0', ' ');
running_processes.push_back(cmd_string);
}
}
// 2. 检查HMI模块进程
auto* hmi_modules = MonitorManager::Instance()
->GetStatus()->mutable_hmi_modules();
for (const auto& iter : mode.modules()) {
const std::string& module_name = iter.first;
const auto& config = iter.second.process_monitor_config();
UpdateStatus(running_processes, config,
&hmi_modules->at(module_name));
}
// 3. 检查其他组件进程
// (类似逻辑检查monitored_components, other_components等)
}
private:
static void UpdateStatus(
const std::vector<std::string>& running_processes,
const ProcessMonitorConfig& config,
ComponentStatus* status) {
// 遍历所有运行进程,查找匹配的进程
for (const std::string& command : running_processes) {
bool all_keywords_matched = true;
// 检查所有关键字是否都在命令行中
for (const std::string& keyword : config.command_keywords()) {
if (command.find(keyword) == std::string::npos) {
all_keywords_matched = false;
break;
}
}
if (all_keywords_matched) {
// 找到匹配进程,状态设为OK
SummaryMonitor::EscalateStatus(ComponentStatus::OK,
command, status);
return;
}
}
// 未找到进程,状态设为FATAL
SummaryMonitor::EscalateStatus(ComponentStatus::FATAL,
"Process not found", status);
}
};
4.2 进程匹配机制
配置示例 (HMI Mode):
yaml
modules:
planning:
process_monitor_config:
command_keywords:
- "mainboard"
- "planning"
匹配过程:
bash
# 系统运行的进程:
/apollo/bazel-bin/cyber/mainboard -d modules/planning/dag/planning.dag
# 提取的命令行字符串:
"/apollo/bazel-bin/cyber/mainboard -d modules/planning/dag/planning.dag"
# 检查关键字:
- "mainboard" ✓ (存在)
- "planning" ✓ (存在)
# 结果: 匹配成功,Planning进程正常运行
失败示例:
Planning进程崩溃后:
- 遍历所有/proc/*/cmdline
- 找不到同时包含"mainboard"和"planning"的进程
- 设置 hmi_modules["planning"].status = FATAL
- SummaryMonitor汇总后触发safety_mode
5. 通道监控机制
5.1 ChannelMonitor实现
cpp
class ChannelMonitor : public RecurrentRunner {
public:
explicit ChannelMonitor(
const std::shared_ptr<LatencyMonitor>& latency_monitor)
: RecurrentRunner("ChannelMonitor", 5.0), // 5秒周期
latency_monitor_(latency_monitor) {}
void RunOnce(const double current_time) override {
auto manager = MonitorManager::Instance();
const auto& mode = manager->GetHMIMode();
auto* components = manager->GetStatus()->mutable_components();
// 检查每个组件的通道状态
for (const auto& iter : mode.monitored_components()) {
const std::string& name = iter.first;
if (!iter.second.has_channel()) continue;
const auto& config = iter.second.channel();
auto* status = components->at(name).mutable_channel_status();
// 从LatencyMonitor获取频率
bool update_freq = false;
double freq = 0.0;
if (config.has_name()) {
const auto freq_opt = latency_monitor_->GetFrequency(config.name());
if (freq_opt) {
update_freq = true;
freq = *freq_opt;
}
}
UpdateStatus(config, status, update_freq, freq);
}
}
private:
static void UpdateStatus(
const ChannelMonitorConfig& config,
ComponentStatus* status,
const bool update_freq,
const double freq) {
if (!update_freq) {
// 无法获取频率,标记为WARN
status->set_status(ComponentStatus::WARN);
status->set_message("Channel frequency not available");
return;
}
// 检查频率是否在正常范围内
if (freq < config.min_frequency_allowed()) {
// 频率过低
status->set_status(ComponentStatus::WARN);
status->set_message(absl::StrCat("Frequency too low: ", freq,
" < ", config.min_frequency_allowed()));
} else {
// 频率正常
status->set_status(ComponentStatus::OK);
status->set_message(absl::StrCat("Frequency: ", freq, " Hz"));
}
}
std::shared_ptr<LatencyMonitor> latency_monitor_;
};
5.2 频率检测
LatencyMonitor计算频率:
cpp
// LatencyMonitor内部维护消息时间戳队列
std::map<std::string, std::deque<double>> message_timestamps_;
void OnMessage(const std::string& channel, double timestamp) {
auto& timestamps = message_timestamps_[channel];
timestamps.push_back(timestamp);
// 保留最近10秒的时间戳
while (!timestamps.empty() &&
timestamp - timestamps.front() > 10.0) {
timestamps.pop_front();
}
}
std::optional<double> GetFrequency(const std::string& channel) {
if (!message_timestamps_.count(channel)) return {};
const auto& timestamps = message_timestamps_[channel];
if (timestamps.size() < 2) return {};
// 频率 = 消息数 / 时间跨度
double time_span = timestamps.back() - timestamps.front();
if (time_span < 0.1) return {};
return (timestamps.size() - 1) / time_span;
}
配置示例:
yaml
monitored_components:
perception:
channel:
name: "/apollo/perception/obstacles"
min_frequency_allowed: 8.0 # 最低8Hz
6. 资源监控机制
6.1 ResourceMonitor实现
cpp
class ResourceMonitor : public RecurrentRunner {
public:
ResourceMonitor()
: RecurrentRunner("ResourceMonitor", 5.0) {} // 5秒周期
void RunOnce(const double current_time) override {
const auto& mode = MonitorManager::Instance()->GetHMIMode();
auto* components = MonitorManager::Instance()
->GetStatus()->mutable_global_components();
// 检查各项资源
for (const auto& iter : mode.global_components()) {
const std::string& name = iter.first;
if (!iter.second.has_resource()) continue;
const auto& config = iter.second.resource();
auto* status = components->at(name).mutable_resource_status();
UpdateStatus(config, status);
}
}
private:
static void UpdateStatus(
const ResourceMonitorConfig& config,
ComponentStatus* status) {
// 1. 检查磁盘空间
CheckDiskSpace(config, status);
// 2. 检查CPU使用率
CheckCPUUsage(config, status);
// 3. 检查内存使用率
CheckMemoryUsage(config, status);
// 4. 检查磁盘I/O负载
CheckDiskLoads(config, status);
}
static void CheckDiskSpace(
const ResourceMonitorConfig& config,
ComponentStatus* status) {
for (const auto& disk_config : config.disks()) {
struct statvfs stat;
if (statvfs(disk_config.path().c_str(), &stat) != 0) {
SummaryMonitor::EscalateStatus(
ComponentStatus::ERROR,
"Failed to get disk space: " + disk_config.path(),
status);
continue;
}
// 计算可用空间百分比
const double available_percentage =
static_cast<double>(stat.f_bavail) / stat.f_blocks * 100;
// 检查是否低于阈值
if (available_percentage <
disk_config.min_available_gb() /
(stat.f_blocks * stat.f_frsize / 1e9) * 100) {
SummaryMonitor::EscalateStatus(
ComponentStatus::WARN,
absl::StrCat("Low disk space: ",
disk_config.path(), " ",
available_percentage, "%"),
status);
}
}
}
static void CheckCPUUsage(
const ResourceMonitorConfig& config,
ComponentStatus* status) {
if (!config.has_cpu_usage()) return;
// 读取/proc/stat获取CPU使用率
static unsigned long long prev_total = 0, prev_idle = 0;
std::ifstream stat_file("/proc/stat");
std::string line;
std::getline(stat_file, line);
unsigned long long user, nice, system, idle;
sscanf(line.c_str(), "cpu %llu %llu %llu %llu",
&user, &nice, &system, &idle);
unsigned long long total = user + nice + system + idle;
double cpu_usage = 100.0 * (1.0 -
static_cast<double>(idle - prev_idle) / (total - prev_total));
prev_total = total;
prev_idle = idle;
// 检查CPU使用率
if (cpu_usage > config.cpu_usage().high_usage_percentage()) {
SummaryMonitor::EscalateStatus(
ComponentStatus::WARN,
absl::StrCat("High CPU usage: ", cpu_usage, "%"),
status);
}
}
static void CheckMemoryUsage(
const ResourceMonitorConfig& config,
ComponentStatus* status) {
if (!config.has_memory_usage()) return;
// 读取/proc/meminfo
std::ifstream meminfo("/proc/meminfo");
std::string line;
unsigned long long total_mem = 0, available_mem = 0;
while (std::getline(meminfo, line)) {
if (line.find("MemTotal:") == 0) {
sscanf(line.c_str(), "MemTotal: %llu kB", &total_mem);
} else if (line.find("MemAvailable:") == 0) {
sscanf(line.c_str(), "MemAvailable: %llu kB", &available_mem);
}
}
double used_percentage =
100.0 * (1.0 - static_cast<double>(available_mem) / total_mem);
if (used_percentage >
config.memory_usage().high_usage_percentage()) {
SummaryMonitor::EscalateStatus(
ComponentStatus::WARN,
absl::StrCat("High memory usage: ", used_percentage, "%"),
status);
}
}
};
6.2 资源阈值配置
yaml
global_components:
resource:
resource:
# 磁盘空间
disks:
- path: "/apollo"
min_available_gb: 10.0 # 最少10GB
- path: "/apollo/data"
min_available_gb: 50.0 # 最少50GB(录制数据)
# CPU使用率
cpu_usage:
high_usage_percentage: 90.0 # CPU>90%警告
# 内存使用率
memory_usage:
high_usage_percentage: 85.0 # 内存>85%警告
7. 状态汇总与决策
7.1 SummaryMonitor
SummaryMonitor负责汇总所有监控器的状态,并决定是否触发Guardian安全模式。
cpp
class SummaryMonitor : public RecurrentRunner {
public:
SummaryMonitor()
: RecurrentRunner("SummaryMonitor", 1.0) {} // 1秒周期
void RunOnce(const double current_time) override {
auto manager = MonitorManager::Instance();
auto* status = manager->GetStatus();
// 汇总所有组件状态
ComponentStatus::Status worst_status = ComponentStatus::OK;
std::string worst_message;
// 1. 检查HMI模块
for (const auto& iter : status->hmi_modules()) {
if (iter.second.status() > worst_status) {
worst_status = iter.second.status();
worst_message = iter.first + ": " + iter.second.message();
}
}
// 2. 检查监控组件
for (const auto& iter : status->components()) {
UpdateWorstStatus(iter.second, &worst_status, &worst_message);
}
// 3. 检查全局组件
for (const auto& iter : status->global_components()) {
UpdateWorstStatus(iter.second, &worst_status, &worst_message);
}
// 4. 决定是否触发安全模式
if (worst_status >= ComponentStatus::ERROR) {
// 有ERROR或FATAL状态,触发安全模式
status->set_safety_mode_trigger_time(current_time);
status->set_passenger_msg(
"系统异常: " + worst_message + ", 正在安全停车");
// 如果是FATAL,需要紧急停车
if (worst_status == ComponentStatus::FATAL) {
status->set_require_emergency_stop(true);
}
} else {
// 清除安全模式触发时间
status->clear_safety_mode_trigger_time();
status->clear_require_emergency_stop();
}
}
private:
static void UpdateWorstStatus(
const Component& component,
ComponentStatus::Status* worst_status,
std::string* worst_message) {
// 检查各个子状态
const ComponentStatus* statuses[] = {
&component.summary(),
&component.process_status(),
&component.channel_status(),
&component.resource_status()
};
for (const auto* status : statuses) {
if (status->status() > *worst_status) {
*worst_status = status->status();
*worst_message = status->message();
}
}
}
public:
// 状态升级辅助函数
static void EscalateStatus(
const ComponentStatus::Status new_status,
const std::string& message,
ComponentStatus* status) {
// 只有新状态更严重时才升级
if (new_status > status->status()) {
status->set_status(new_status);
status->set_message(message);
}
}
};
7.2 FunctionalSafetyMonitor
功能安全监控器基于汇总状态做最终决策:
cpp
class FunctionalSafetyMonitor : public RecurrentRunner {
public:
FunctionalSafetyMonitor()
: RecurrentRunner("FunctionalSafetyMonitor", 1.0) {}
void RunOnce(const double current_time) override {
auto* status = MonitorManager::Instance()->GetStatus();
// 检查是否在自动驾驶模式
if (!MonitorManager::Instance()->IsInAutonomousMode()) {
return; // 非自动驾驶模式,不触发
}
// 检查是否有致命错误
bool has_fatal_error = false;
for (const auto& iter : status->hmi_modules()) {
if (iter.second.status() == ComponentStatus::FATAL) {
has_fatal_error = true;
break;
}
}
if (has_fatal_error &&
!status->has_safety_mode_trigger_time()) {
// 有致命错误但未触发安全模式,立即触发
status->set_safety_mode_trigger_time(current_time);
status->set_require_emergency_stop(true);
status->set_passenger_msg("检测到致命错误,紧急停车");
}
}
};
8. 配置与部署
8.1 DAG配置
protobuf
# modules/monitor/dag/monitor.dag
module_config {
module_library : "modules/monitor/libmonitor_component.so"
timer_components {
class_name : "Monitor"
config {
name: "monitor"
interval: 10 # 10ms = 100Hz
}
}
}
8.2 HMI Mode配置
yaml
# modules/dreamview/conf/hmi_modes/default.pb.txt
modules:
planning:
process_monitor_config:
command_keywords:
- "mainboard"
- "planning"
control:
process_monitor_config:
command_keywords:
- "mainboard"
- "control"
monitored_components:
perception:
channel:
name: "/apollo/perception/obstacles"
min_frequency_allowed: 8.0
process:
command_keywords:
- "perception"
global_components:
resource:
resource:
disks:
- path: "/apollo"
min_available_gb: 10.0
cpu_usage:
high_usage_percentage: 90.0
memory_usage:
high_usage_percentage: 85.0
9. 实际应用场景
9.1 Planning崩溃检测
t=0s: Planning正常运行
t=10s: Planning因bug崩溃,进程退出
t=11.5s: ProcessMonitor::RunOnce() (1.5s周期)
扫描/proc/*/cmdline
未找到包含"mainboard"+"planning"的进程
设置 hmi_modules["planning"].status = FATAL
t=12s: SummaryMonitor::RunOnce() (1s周期)
检测到Planning状态=FATAL
设置 safety_mode_trigger_time = 12.0
设置 require_emergency_stop = true
t=12.01s: Guardian收到SystemStatus
检测到 has_safety_mode_trigger_time()
触发安全模式,执行紧急停车
9.2 磁盘空间不足
t=0s: 磁盘可用空间: 15GB
t=300s: 用户启动数据录制
t=600s: 磁盘可用空间: 8GB
t=605s: ResourceMonitor::RunOnce() (5s周期)
检测到 /apollo/data 可用空间 < 10GB
设置 global_components["resource"].status = WARN
t=606s: SummaryMonitor::RunOnce()
汇总状态: WARN (不触发安全模式)
设置 passenger_msg = "磁盘空间不足,请清理数据"
t=607s: Dreamview显示警告
HMI: "⚠️ 磁盘空间不足: 8GB < 10GB"
10. 调试与故障排查
10.1 查看SystemStatus
bash
# 实时监控SystemStatus
cyber_monitor -c /apollo/monitor/system_status
# 查看字段:
# - hmi_modules: 各模块状态
# - components: 组件状态
# - global_components: 全局组件状态
# - safety_mode_trigger_time: 是否触发安全模式
# - passenger_msg: 给乘客的消息
10.2 常见问题
问题: 模块状态一直是FATAL
bash
# 检查进程是否运行
ps aux | grep planning
# 检查关键字配置
# 确保process_monitor_config.command_keywords正确
# 查看Monitor日志
cat /apollo/data/log/monitor.INFO
问题: CPU使用率警告
bash
# 查看CPU占用
top
# 调整阈值
# 编辑HMI mode配置,提高cpu_usage.high_usage_percentage
参考资料与引用
官方资源
-
Apollo 官方 GitHub 仓库
https://github.com/ApolloAuto/apollo
- Apollo 开源项目主仓库,包含完整源代码
-
Apollo 官方文档
- 官方技术文档和开发指南
-
Apollo 开发者社区
https://apollo.baidu.com/community
- 官方开发者论坛和技术交流平台
技术规范与标准
-
ISO 26262 - 道路车辆功能安全标准
-
ISO 21448 (SOTIF) - 预期功能安全标准
学术论文与技术资源
-
CenterPoint: Center-based 3D Object Detection and Tracking
Yin, T., Zhou, X., & Krähenbühl, P. (2021)
-
BEVFormer: Learning Bird's-Eye-View Representation from Multi-Camera Images
Li, Z., et al. (2022)
-
OpenDRIVE 地图标准
开源工具与库
-
Bazel 构建系统
-
Fast-DDS (eProsima)
https://www.eprosima.com/index.php/products-all/eprosima-fast-dds
-
PROJ 坐标转换库
-
TensorRT 开发指南
-
PCL 点云库文档
-
IPOPT 优化求解器
说明
本文档内容整理自上述官方资料、开源代码以及相关技术文档。所有代码示例和技术细节均基于 Apollo 9.0/10.0 版本。如需获取最新信息,请访问 Apollo 官方网站和 GitHub 仓库。
版权说明
Apollo® 是百度公司的注册商标。本文档为基于开源项目的非官方技术研究文档,仅供学习参考使用。